無向線のクラスタリング


16

私は、方向に関係なく線をクラスター化する効率的な方法を探しています。つまり、ニューヨークとロサンゼルスを結ぶ線は、ロサンゼルスとニューヨークを結ぶ他の方向の線と同じクラスター内にある必要があります。開始点/終了点の位置は類似している必要があります(つまり、サンディエゴからロングアイランドまではLA-NYと同じクラスター内にあるはずですが、サンフランシスコからボストンまではおそらくそうではありません)。中間点はありません。入力データは次の例のようになります。

ここに画像の説明を入力してください (日本語版ウィキペディアGFDLまたはCC-BY-SA-3.0の Cassiopeia sweetによる、Wikimedia Commons経由)

以前に行を事前に並べ替えてみました。たとえば、すべてを西から東に走らせるようにしましたが、これは北から南に走る線やその他の方向の線の問題を解決しません。

この問題に対処するアルゴリズムを知っていますか?私は探していましたが、無向セグメントの平均方向を計算するアルゴリズムに加えて、リモートで役立つものは見つかりませんでしたので、間違った検索用語を使用する必要があります。


1
両端の座標を計算し、STR(set([x1、y1、x2、y2]))を使用して文字列フィールドに入力します。このフィールドを要約して一意の値を見つけることができます
-FelixIP

回答:


10

私があなたを正しく理解していれば、方向に関係なくほぼ同じラインをクラスター化したいと思います。

これがうまくいくと思うアイデアです。

  1. 始点と終点で線を分割します

  2. ポイントをクラスター化し、クラスターIDを取得します

  3. クラスターIDの同じ組み合わせを持つ行を見つけます。それらはクラスターです

これはPostGIS(もちろん:-))バージョン2.3で可能になります。

ST_ClusterDBSCAN関数はテストしていませんが、機能するはずです。

このような行テーブルがある場合:

CREATE TABLE the_lines
(
   geom geometry(linestring),
   id integer primary key
)

そして、始点と終点が最大10 km離れたクラスターを作成します。また、クラスターになるには少なくとも2つのポイントが必要です。その場合、クエリは次のようになります。

WITH point_id AS
   (SELECT (ST_DumpPoints(geom)).geom, id FROM the_lines),
point_clusters as
   (SELECT ST_ClusterDBSCAN(geom, 10000, 2) cluster_id, id line_id FROM point_id) 
SELECT array_agg(a.line_id), a.cluster_id, b.cluster_id 
FROM point_clusters a 
     INNER JOIN point_clusters b 
     ON a.line_id = b.line_id AND a.cluster_id < b.cluster_id
GROUP BY a.cluster_id, b.cluster_id

参加するとa.cluster_id<b.cluster_id、方向に関係なく同等のクラスターIDを取得できます。


ニックラス、ありがとう!クラスタリング中に異なる単位(角度や距離)を混在させることを強制しないため、このアプローチが気に入っています。
暗闇

5

本当に出発地や目的地を考慮せずに、方向だけでクラスター化したいですか?もしそうなら、いくつかの非常に簡単な方法があります。おそらく最も簡単なのは、各線の方位を計算し、それを2倍にして、円上の点としてプロットすることです。前後のベアリングは180度異なるため、2倍にした後は360度異なり、まったく同じ場所にプロットされます。ここで、任意の方法を使用して、平面内のポイントをクラスター化します。

以下にR、4つのクラスターのそれぞれに応じて色分けされた線を表示する出力を使用した、実際の例を示します。もちろん、GISを使用してベアリングを計算することになるでしょう。簡単にするために、ユークリッドベアリングを使用しました。

図

cluster.undirected <- function(x, ...) {
  #
  # Compute the bearing and double it.
  #
  theta <- atan2(x[, 4] - x[, 2], x[, 3] - x[, 1]) * 2
  #
  # Convert to a point on the unit circle.
  #
  z <- cbind(cos(theta), sin(theta))
  #
  # Cluster those points.
  #
  kmeans(z, ...)
}
#
# Create some data.
#
n <- 100
set.seed(17)
pts <- matrix(rnorm(4*n, c(-2,0,2,0), sd=1), ncol=4, byrow=TRUE)
colnames(pts) <- c("x.O", "y.O", "x.D", "y.D")
#
# Plot them.
#
plot(rbind(pts[1:n,1:2], pts[1:n,3:4]), pch=19, col="Gray", xlab="X", ylab="Y")
#
# Plot the clustering solution.
#
n.centers <- 4
s <- cluster.undirected(pts, centers=n.centers)
colors <- hsv(seq(1/6, 5/6, length.out=n.centers), 0.8, 0.6, 0.25)
invisible(sapply(1:n, function(i) 
  lines(pts[i, c(1,3)], pts[i, c(2,4)], col=colors[s$cluster[i]], lwd=2))
)

ありがとうございました!出発地と目的地(O&D)も重要です。「開始点/終了点の位置は似ているべきだ」とほのめかそうとしましたが、どちらがOでどちらがDであるかは気にしません。 KMeansを実行する前に、単位円の値をポイント座標にスケーリングする方法を理解できます。
暗闇

私はあなたがそれを念頭に置いているかもしれないと疑った。そのため、半方向を一対の座標(ポイント)にマッピングすることを提案しました。これらのポイントを2番目の変数でスケーリング(極座標を考える)したり、出発地または目的地に追加の座標を導入したりできます。クラスタリングの最終的な目的がわからなければ、追加の座標の相対的なサイズ(円座標と比較)がクラスタリングソリューションを決定するため、より多くのアドバイスを提供することは困難です。別の解決策は、ハフ変換を活用することです。
whuber

4

質問の明確化は、両方の起点が近く、両方の終点が近い場合、任意の2つの起点と終点(OD)のペアが「近い」と見なされるという意味で、実際の線分に基づいてクラスタリングを行うことを示しています、どのポイントが起点または終点とみなされるか関係なく

この定式化は、2つのポイント間の距離dの感覚をすでに持っていることを示唆します:飛行機の飛行距離、地図上の距離、往復旅行時間、またはOとDが変化しても変化しないその他のメトリック切り替えました。彼らはに対応する:唯一の合併症は、セグメントが一意の表現を持っていないということである非順序対{O、D}が、として表現されなければならない順序付きペアのいずれか(O、D)又は(D、O)。したがって、2つの順序付けられたペア(O1、D1)と(O2、D2)の間の距離を、距離d(O1、O2)とd(D1、D2)の対称的な組み合わせ(それらの合計や二乗など)とすることができます。平方和のルート。この組み合わせを

distance((O1,D1), (O2,D2)) = f(d(O1,O2), d(D1,D2)).

順序付けられていないペア間の距離を、2つの可能な距離の小さい方に単純に定義します。

distance({O1,D1}, {O2,D2}) = min(f(d(O1,O2)), d(D1,D2)), f(d(O1,D2), d(D1,O2))).

この時点で、距離行列に基づいたクラスタリング手法を適用できます。


例として、20の最も人口の多い米国の都市の地図上の190のポイントツーポイント距離をすべて計算し、階層的な方法を使用して8つのクラスターを要求しました。(簡単にするために、ユークリッド距離計算を使用し、使用しているソフトウェアのデフォルトの方法を適用しました。実際には、問題に適した距離とクラスタリング方法を選択します)。以下は、各ラインセグメントの色で示されるクラスターを使用したソリューションです。(色はクラスターにランダムに割り当てられました。)

図

Rこの例を作成したコードを次に示します。入力は、都市の「経度」フィールドと「緯度」フィールドを持つテキストファイルです。(図の都市にラベルを付けるために、「キー」フィールドも含まれています。)

#
# Obtain an array of point pairs.
#
X <- read.csv("F:/Research/R/Projects/US_cities.txt", stringsAsFactors=FALSE)
pts <- cbind(X$Longitude, X$Latitude)

# -- This emulates arbitrary choices of origin and destination in each pair
XX <- t(combn(nrow(X), 2, function(i) c(pts[i[1],], pts[i[2],])))
k <- runif(nrow(XX)) < 1/2
XX <- rbind(XX[k, ], XX[!k, c(3,4,1,2)])
#
# Construct 4-D points for clustering.
# This is the combined array of O-D and D-O pairs, one per row.
#
Pairs <- rbind(XX, XX[, c(3,4,1,2)])
#
# Compute a distance matrix for the combined array.
#
D <- dist(Pairs)
#
# Select the smaller of each pair of possible distances and construct a new
# distance matrix for the original {O,D} pairs.
#
m <- attr(D, "Size")
delta <- matrix(NA, m, m)
delta[lower.tri(delta)] <- D
f <- matrix(NA, m/2, m/2)
block <- 1:(m/2)
f <- pmin(delta[block, block], delta[block+m/2, block])
D <- structure(f[lower.tri(f)], Size=nrow(f), Diag=FALSE, Upper=FALSE, 
               method="Euclidean", call=attr(D, "call"), class="dist")
#
# Cluster according to these distances.
#
H <- hclust(D)
n.groups <- 8
members <- cutree(H, k=2*n.groups)
#
# Display the clusters with colors.
#
plot(c(-131, -66), c(28, 44), xlab="Longitude", ylab="Latitude", type="n")
g <- max(members)
colors <- hsv(seq(1/6, 5/6, length.out=g), seq(1, 0.25, length.out=g), 0.6, 0.45)
colors <- colors[sample.int(g)]
invisible(sapply(1:nrow(Pairs), function(i) 
  lines(Pairs[i, c(1,3)], Pairs[i, c(2,4)], col=colors[members[i]], lwd=1))
)
#
# Show the points for reference
#
positions <- round(apply(t(pts) - colMeans(pts), 2, 
                         function(x) atan2(x[2], x[1])) / (pi/2)) %% 4
positions <- c(4, 3, 2, 1)[positions+1]
points(pts, pch=19, col="Gray", xlab="X", ylab="Y")
text(pts, labels=X$Key, pos=positions, cex=0.6)

ありがとう!ペアワイズ距離の計算は、大規模なODデータセットの問題になりますか?
暗闇

はい、n本の線分ではn(n-1)/ 2の距離計算があるためです。しかし、固有の問題はありません。すべてのクラスタリングアルゴリズムは、ポイント間(またはポイントとクラスター中心間)の距離または非類似度を見つける必要があります。これは非常に一般的な問題であり、多くのアルゴリズムがカスタム距離関数で機能します。
whuber
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.