聚集无向线


16

我正在寻找一种有效的方法来对线进行聚类,而与线的方向无关。这意味着,纽约和洛杉矶之间的路线应与洛杉矶和纽约之间的另一方向的路线位于同一群集中。起点/终点位置应相似(即,圣地亚哥到长岛的位置应与LA-NY在同一群集中,但旧金山和波士顿可能不在同一位置),并且没有中间点。输入数据将类似于此示例:

在此处输入图片说明 (通过维基百科,通过日本维基百科GFDLCC-BY-SA-3.0的仙后座甜蜜)

我以前曾尝试过预先对线进行排序,例如使它们全部从西向东延伸,但是这并不能解决从北向南或以其他方式延伸的线的问题。

您知道有什么算法可以解决这个问题吗?我一直在寻找,但是除了算法来计算无向片段的平均方向外,我还没有发现任何有用的远程帮助,因此我必须使用错误的搜索词。


1
我会计算两端坐标,并使用STR(set([x1,y1,x2,y2]))填充字符串字段。您可以汇总此字段以找到唯一的值
FelixIP

Answers:


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

您是否真的要仅按方向进行聚类,而不考虑出发地或目的地?如果是这样,有一些非常简单的方法。也许最简单的方法是计算每条线的方位角,将其加倍,并将其绘制为圆上的点。由于前后轴承相差180度,因此加倍后它们之间相差360度,因此在完全相同的位置绘制。现在,使用您喜欢的任何方法在平面上将点聚类。

这是中的一个工作示例R,其输出显示了根据四个聚类中的每个聚类线的颜色。当然,您可能会使用GIS来计算方位角-为简单起见,我使用了Euclidean方位角。

数字

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之前弄清楚如何将单位圆的值缩放到点坐标。
天黑

我怀疑您可能会想到这一点。这就是为什么我建议将半方向映射到一对坐标(点)的原因。您可以通过第二个变量缩放这些点(考虑极坐标)和/或为起点或终点引入其他坐标。在不了解聚类的最终目的的情况下,很难提供更多建议,因为附加坐标的相对大小(与圆坐标相比)将决定聚类的解决方案。另一个解决方案是利用霍夫变换
ub

4

您对问题的澄清表明您希望基于实际的线段进行聚类,从某种意义上说,当两个起点或终点都接近时,任何两个起点-终点(OD)对都应被视为“终点”。 ,无论哪个点被认为是始发地或目的地

这种表述表明您已经了解了两点之间的距离d:可能是飞机飞行的距离,地图上的距离,往返旅行时间,或者当O和D为切换。唯一的麻烦是,这些段没有唯一的表示形式:它们对应于无序对{O,D},但必须表示为有序对,即(O,D)或(D,O)。因此,我们可以将两个有序对(O1,D1)和(O2,D2)之间的距离作为距离d(O1,O2)和d(D1,D2)的对称组合,例如它们的和或平方其平方和的根。让我们将此组合写为

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

只需将无序对之间的距离定义为两个可能的距离中的较小者:

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

此时,您可以应用基于距离矩阵的任何聚类技术。


例如,我计算了美国20个人口最多的城市在地图上的所有190个点对点距离,并使用分层方法请求了八个聚类。(为简单起见,我使用了欧式距离计算,并在我使用的软件中应用了默认方法:在实践中,您将要为问题选择适当的距离和聚类方法)。这是解决方案,其中群集由每个线段的颜色指示。(将颜色随机分配给群集。)

数字

这是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个距离计算。但是没有内在的问题:所有聚类算法都需要找出点之间(或点与聚类中心之间)的距离或相异性。这是一个常见的问题,许多算法都使用自定义距离函数。
ub
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.