名前

ST_ClusterDBSCAN — 入力ジオメトリごとにDBSCANアルゴリズムを使ってクラスタ番号を返すウィンドウ関数です。

概要

integer ST_ClusterDBSCAN(geometry winset geom, float8 eps, integer minpoints);

説明

2次元Density-based spatial clustering of applications with noise (DBSCAN)アルゴリズムを使って、入力ジオメトリ毎にクラスタ番号を返すウィンドウ関数です。ST_ClusterKMeansと違い、クラスタ数の指定は不要ですが、代わりに、クラスタを決定するために、期待する距離(eps)と密度(minpoints)のパラメータを使います。

入力ジオメトリは、次のいずれかの場合にはクラスタに追加されます:

  • 「核」ジオメトリという、入力ジオメトリ (自分を含む)のうち少なくともminpoints個がepsで指定した距離の範囲内にあるもの。または

  • 「境界」ジオメトリという、核ジオメトリからepsで指定した距離の範囲内にあるものです。

境界ジオメトリは、複数のクラスタの核ジオメトリのeps距離内に存在する場合があることに注意して下さい。どちらに割り当てても正しいので、境界ジオメトリは有効なクラスタの一つに任意に割り当てられます。この状況では、正しいクラスタがminpointsジオメトリより少ないジオメトリで生成される可能性があります。境界ジオメトリの割当の決定性を確実にする (その結果、ST_ClusterDBSCANの呼び出しで同じ結果が生成される)には、ウィンドウ定義内でORDER BY節を使います。あいまいなクラスタ割当は他のDBSCAN実装とは異なるかも知れません。

[注記]

どのクラスタとの結合の基準に合わないジオメトリは、NULLのクラスタ番号が割り当てられます。

Availability: 2.3.0

このメソッドは曲線ストリングと曲線に対応しています。

Cluster polygons within 50 units of each other, requiring at least two polygons per cluster. The isolated polygon is reported as noise.

Code
WITH input(name, geom) AS (
  VALUES
    ('A1', ST_MakeEnvelope(0, 0, 10, 10)),
    ('A2', ST_MakeEnvelope(30, 0, 40, 10)),
    ('B1', ST_MakeEnvelope(100, 0, 110, 10)),
    ('B2', ST_MakeEnvelope(130, 0, 140, 10)),
    ('noise', ST_MakeEnvelope(250, 0, 260, 10))
), clustered AS (
  SELECT name,
         geom,
         ST_ClusterDBSCAN(geom, eps => 50, minpoints => 2)
           OVER (ORDER BY name) AS cid
  FROM input
)
SELECT COALESCE(cid::text, 'noise') AS cluster,
       string_agg(name, ',' ORDER BY name) AS members,
       ST_Collect(geom ORDER BY name) AS cluster_geom
FROM clustered
GROUP BY cid
ORDER BY cid NULLS LAST;
出力:
0 | A1,A2 | MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((30 0,30 10,40 10,40 0,30 0)))
1 | B1,B2 | MULTIPOLYGON(((100 0,100 10,110 10,110 0,100 0)),((130 0,130 10,140 10,140 0,130 0)))
noise | noise | MULTIPOLYGON(((250 0,250 10,260 10,260 0,250 0)))
Figure
Geometry figure for visual-st-clusterdbscan-01

同じクラスタ番号の区画をジオメトリコレクションに合併する例。

Code
SELECT cid, ST_Collect(geom) AS cluster_geom, array_agg(parcel_id) AS ids_in_cluster FROM (
    SELECT parcel_id, ST_ClusterDBSCAN(geom, eps => 0.5, minpoints => 5) over () AS cid, geom
    FROM parcels) sq
GROUP BY cid;