Yönlendirilmemiş satırları kümeleme


16

Çizgileri yönlerinden bağımsız olarak kümelemenin etkili bir yolunu arıyorum. Bu, New York ve Los Angeles arasındaki bir hattın, Los Angeles ve New York arasındaki diğer yöndeki bir satırla aynı kümede olması gerektiği anlamına gelir. Başlangıç ​​/ bitiş noktası konumları benzer olmalıdır (örn. San Diego'dan Long Island'a LA-NY ile aynı kümede olmalı, ancak muhtemelen San Francisco'dan Boston'a değil) ve ara noktalar yoktur. Girdi verileri bu örneğe benzer:

resim açıklamasını buraya girin ( Vikipedi Commons aracılığıyla Japon Wikipedia GFDL veya CC-BY-SA-3.0'da Cassiopeia sweet tarafından )

Daha önce hatları önceden sıralamaya çalıştım, örneğin hepsini batıdan doğuya doğru çalıştırmak için, ama bu kuzeyden güneye ve diğer yollardan geçen hatlar için sorunu çözmez.

Bu sorunla ilgili herhangi bir algoritma biliyor musunuz? Aradım ama yönlendirilmemiş segmentlerin ortalama yönünü hesaplamak için Algoritmanın yanı sıra uzaktan yararlı bir şey bulamadım, bu yüzden yanlış arama terimlerini kullanmalıyım.


1
Her iki uç koordinatlarını hesaplar ve string alanını doldurmak için STR (set ([x1, y1, x2, y2])) kullanırdım. Benzersiz değerler bulmak için bu alanı özetleyebilirsiniz
FelixIP

Yanıtlar:


10

Seni doğru anlarsam, yönüne bakılmaksızın yaklaşık aynı çizgileri kümelemek istersiniz.

İşte işe yarayabileceğini düşündüğüm bir fikir.

  1. çizgileri başlangıç ​​ve bitiş noktalarına bölme

  2. Noktaları kümele ve küme kimliği al

  3. Aynı küme kimliği kombinasyonuna sahip satırları bulun. Bunlar bir küme

Bu PostGIS (tabii ki :-)) sürüm 2.3'te mümkün olmalıdır

ST_ClusterDBSCAN işlevini test etmedim, ancak işi yapmalı.

Böyle bir çizgi tablonuz varsa:

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

Ve başlangıç ​​ve bitiş noktalarının en fazla 10 km olduğu bir küme oluşturmak istiyorsunuz. Ve bir küme olabilmek için en az 2 puan olmalıdır, o zaman sorgu şöyle olabilir:

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

Bir araya gelerek a.cluster_id<b.cluster_idyönten bağımsız karşılaştırılabilir küme kimliği elde edersiniz.


Teşekkürler Nicklas! Bu yaklaşımı seviyorum çünkü kümelenirken farklı birimleri (yani açıları ve mesafeleri) karıştırmaya zorlamıyor.
underdark

5

Menşei veya varış noktası dikkate alınmaksızın, yalnızca yön ile kümelenmeyi gerçekten istiyor musunuz? Eğer öyleyse, bazı çok basit yollar var. Belki de en kolayı, her hattın yönünü hesaplamak, iki katına çıkarmak ve bir daire üzerinde bir nokta olarak çizmektir. İleri-geri rulmanlar 180 derece farklılık gösterdiğinden, iki katına çıktıktan sonra 360 derece farklılık gösterir ve bu nedenle tamamen aynı yere çizilir. Şimdi istediğiniz noktaları kullanarak düzlemdeki noktaları kümeleyin.

İşte Rçıktısı dört kümenin her birine göre renklendirilmiş çizgileri gösteren çalışan bir örnek . Tabii ki yatakları hesaplamak için muhtemelen bir CBS kullanırsınız - Basitlik için Öklid yatakları kullandım.

şekil

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))
)

Teşekkür ederim! Kökeni ve varış yeri (O&D) de önemlidir. "Başlangıç ​​/ bitiş noktası konumları benzer olmalıdır" ile ipucu vermeye çalıştım ama hangisinin O ve hangisinin D olduğu umurumda değil. Yine de, açıklamanız beni aradığım çözüme yaklaştırabilir. KMeanları çalıştırmadan önce birim daire değerlerinin nokta koordinatlarına nasıl ölçekleneceğini anlayabilir.
underdark

Bunu aklınızda tutabileceğinden şüphelendim. Bu yüzden yarı yönleri bir çift koordinat (nokta) ile eşleştirmeyi önerdim. Bu noktaları (kutupsal koordinatları düşünün) ikinci bir değişkenle ölçeklendirebilir ve / veya başlangıç ​​noktaları veya hedefler için ek koordinatlar ekleyebilirsiniz. Kümelenmenin nihai amacını bilmeden, daha fazla tavsiye vermek zordur çünkü ek koordinatların göreceli boyutları (daire koordinatlarına kıyasla) kümeleme çözümlerini belirleyecektir. Başka bir çözüm Hough dönüşümünü kullanmaktır .
whuber

4

Soruyu açıklığa kavuşturmanız, her iki köken de yakın ve her iki hedef de yakın olduğunda herhangi bir iki başlangıç ​​noktası (OD) çiftinin "kapalı" olarak değerlendirilmesi gerektiği için , kümelemenin gerçek satır segmentlerine dayalı olmasını istediğinizi gösterir. , hangi noktanın başlangıç ​​noktası veya hedef olarak kabul edildiğine bakılmaksızın .

Bu formülasyon, zaten iki nokta arasındaki mesafe d hissine sahip olduğunuzu gösterir : uçak uçarken mesafe, haritadaki mesafe, gidiş-dönüş seyahat süresi veya O ve D olduğunda değişmeyen başka bir metrik olabilir. açık. Tek komplikasyon, segmentlerin benzersiz temsillere sahip olmamasıdır: sıralanmamış çiftlere {O, D} karşılık gelir , ancak (O, D) veya (D, O) sıralı çiftler olarak temsil edilmelidir . Bu nedenle, toplamları veya kareleri gibi d (O1, O2) ve d (D1, D2) mesafelerinin simetrik bir kombinasyonu olmak için sıralı iki çift (O1, D1) ve (O2, D2) arasındaki mesafeyi alabiliriz. karelerinin toplamının kökü. Bu kombinasyonu şu şekilde yazalım:

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

Sıralanmamış çiftler arasındaki mesafeyi iki olası mesafeden daha küçük olacak şekilde tanımlamanız yeterlidir:

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

Bu noktada, bir mesafe matrisine dayalı herhangi bir kümeleme tekniği uygulayabilirsiniz.


Örnek olarak, en kalabalık ABD kentlerinden 20'si için haritadaki 190 noktadan noktaya mesafelerin tümünü hesapladım ve hiyerarşik bir yöntem kullanarak sekiz küme istedim. (Basitlik için Öklid uzaklık hesaplamaları kullandım ve kullandığım yazılımda varsayılan yöntemleri uyguladım: pratikte sorununuz için uygun mesafeleri ve kümeleme yöntemlerini seçmek isteyeceksiniz). İşte çözüm, her çizgi parçasının rengiyle gösterilen kümeler. (Renkler rastgele kümelere atandı.)

şekil

İşte Rbu örneği üreten kod. Girdisi şehirler için "Boylam" ve "Enlem" alanlarına sahip bir metin dosyasıdır. (Şekildeki şehirleri etiketlemek için "Anahtar" alanı da içerir.)

#
# 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)

Teşekkürler! Çift mesafe hesaplaması büyük OD veri kümeleri için bir sorun teşkil edecek mi?
underdark

Evet, çünkü n çizgi segmentlerinde n (n-1) / 2 mesafe hesaplaması vardır. Ancak doğal bir sorun yoktur: tüm kümeleme algoritmalarının noktalar (veya noktalar ve küme merkezleri arasında) arasındaki mesafeleri veya farklılıkları bulması gerekir. Bu, birçok algoritmanın özel bir mesafe işleviyle çalıştığı yaygın bir sorundur.
whuber
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.