Phân cụm các dòng không mong muốn


16

Tôi đang tìm kiếm một cách hiệu quả để phân cụm các dòng độc lập với hướng của chúng. Điều đó có nghĩa là một đường giữa New York và Los Angeles phải nằm trong cùng một cụm với một đường theo hướng khác giữa Los Angeles và New York. Các vị trí điểm bắt đầu / điểm cuối phải tương tự nhau (ví dụ: San Diego đến Long Island phải nằm trong cùng một cụm với LA-NY nhưng có lẽ không phải là San Francisco đến Boston) và không có điểm trung gian. Dữ liệu đầu vào sẽ tương tự như ví dụ này:

nhập mô tả hình ảnh ở đây (Tác giả Cassiopeia ngọt ngào tại Wikipedia tiếng Nhật GFDL hoặc CC-BY-SA-3.0 , qua Wikimedia Commons)

Trước đây tôi đã cố gắng sắp xếp các dòng trước, ví dụ để làm cho tất cả chúng chạy từ tây sang đông, nhưng điều này không giải quyết được vấn đề cho các dòng chạy từ bắc xuống nam và cách khác.

Bạn có biết bất kỳ thuật toán xử lý vấn đề này? Tôi đã tìm kiếm nhưng ngoài Thuật toán để tính hướng trung bình của các phân đoạn không mong muốn, tôi không tìm thấy bất cứ điều gì hữu ích từ xa, vì vậy tôi phải sử dụng các thuật ngữ tìm kiếm sai.


1
Tôi sẽ tính toán cả hai tọa độ đầu và sử dụng STR (set ([x1, y1, x2, y2])) để điền vào trường chuỗi. Bạn có thể tóm tắt trường này để tìm các giá trị duy nhất
FelixIP

Câu trả lời:


10

Nếu tôi hiểu bạn đúng, bạn muốn phân cụm các dòng giống nhau mà không liên quan đến hướng.

Đây là một ý tưởng mà tôi nghĩ có thể làm việc.

  1. chia các dòng ở điểm bắt đầu và điểm kết thúc

  2. Phân cụm các điểm và nhận id cụm

  3. Tìm các dòng có cùng sự kết hợp của id cụm. Đó là một cụm

Điều này có thể có trong PostGIS (tất nhiên :-)) phiên bản 2.3

Tôi đã không kiểm tra hàm ST_ClusterDBSCAN, nhưng nó sẽ hoạt động.

Nếu bạn có một bảng dòng như thế này:

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

Và bạn muốn tạo cụm nơi điểm bắt đầu và điểm kết thúc cách nhau tối đa 10 km. Và phải có ít nhất 2 điểm để trở thành một cụm thì truy vấn có thể giống như:

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

Bằng cách tham gia với a.cluster_id<b.cluster_idbạn có được id cụm so sánh độc lập với hướng.


Cảm ơn Nicklas! Tôi thích cách tiếp cận này vì nó không buộc tôi phải trộn các đơn vị khác nhau (nghĩa là góc và khoảng cách) trong khi phân cụm.
underdark

5

Bạn có thực sự muốn phân cụm chỉ theo hướng, mà không có bất kỳ xem xét về nguồn gốc hoặc đích đến? Nếu vậy, có một số cách rất đơn giản. Có lẽ cách dễ nhất là tính toán độ chịu lực của mỗi dòng, nhân đôi số đó và vẽ nó như một điểm trên một vòng tròn. Vì vòng bi tiến - lùi khác nhau 180 độ, chúng khác nhau 360 độ sau khi nhân đôi và do đó vẽ đồ thị tại cùng một vị trí. Bây giờ phân cụm các điểm trong mặt phẳng bằng bất kỳ phương pháp nào bạn thích.

Dưới đây là một ví dụ hoạt động R, với đầu ra của nó hiển thị các dòng được tô màu theo từng cụm trong bốn cụm. Tất nhiên bạn có thể sẽ sử dụng một hệ thống GIS để tính toán các vòng bi - Tôi đã sử dụng vòng bi Euclide để đơn giản.

Nhân vật

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

Cảm ơn bạn! Nguồn gốc và đích đến (O & D) cũng quan trọng. Đã thử gợi ý về nó với "vị trí điểm bắt đầu / điểm kết thúc tương tự nhau" nhưng tôi không quan tâm đó là O và D. Tuy nhiên, tôi nghĩ rằng lời giải thích của bạn có thể đưa tôi đến gần hơn với giải pháp mà tôi đang tìm kiếm, nếu tôi có thể tìm ra cách chia tỷ lệ các giá trị vòng tròn đơn vị thành tọa độ điểm trước khi chạy KMeans.
underdark

Tôi nghi ngờ bạn có thể có suy nghĩ đó. Đó là lý do tại sao tôi đề xuất ánh xạ các hướng bán tới một cặp tọa độ (điểm). Bạn có thể chia tỷ lệ các điểm đó (nghĩ tọa độ cực) bằng một biến thứ hai và / hoặc giới thiệu tọa độ bổ sung cho nguồn gốc hoặc đích. Không biết mục đích cuối cùng của việc phân cụm, thật khó để cung cấp thêm lời khuyên vì kích thước tương đối của tọa độ bổ sung (so với tọa độ vòng tròn) sẽ xác định các giải pháp phân cụm. Một giải pháp khác là khai thác biến đổi Hough .
whuber

4

Việc làm rõ câu hỏi của bạn cho biết bạn muốn phân cụm dựa trên các phân đoạn dòng thực tế , theo nghĩa là bất kỳ hai cặp điểm gốc (OD) nào cũng được coi là "đóng" khi cả hai nguồn gốc đều đóng và cả hai đích đều đóng , bất kể điểm nào được coi là điểm gốc hoặc điểm đến .

Công thức này cho thấy bạn đã có cảm giác về khoảng cách d giữa hai điểm: đó có thể là khoảng cách khi máy bay bay, khoảng cách trên bản đồ, thời gian di chuyển khứ hồi hoặc bất kỳ số liệu nào khác không thay đổi khi O và D chuyển. Sự phức tạp duy nhất là các phân đoạn không có các biểu diễn duy nhất: chúng tương ứng với các cặp không có thứ tự {O, D} nhưng phải được biểu diễn dưới dạng các cặp theo thứ tự , (O, D) hoặc (D, O). Do đó, chúng ta có thể lấy khoảng cách giữa hai cặp theo thứ tự (O1, D1) và (O2, D2) là một số kết hợp đối xứng của khoảng cách d (O1, O2) và d (D1, D2), chẳng hạn như tổng của chúng hoặc hình vuông gốc của tổng bình phương của họ. Hãy viết kết hợp này là

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

Chỉ cần xác định khoảng cách giữa các cặp không có thứ tự là nhỏ hơn trong hai khoảng cách có thể:

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

Tại thời điểm này, bạn có thể áp dụng bất kỳ kỹ thuật phân cụm dựa trên ma trận khoảng cách.


Lấy ví dụ, tôi đã tính toán tất cả 190 khoảng cách điểm-điểm trên bản đồ cho 20 thành phố đông dân nhất Hoa Kỳ và yêu cầu tám cụm sử dụng phương pháp phân cấp. (Để đơn giản, tôi đã sử dụng các tính toán khoảng cách Euclide và áp dụng các phương thức mặc định trong phần mềm tôi đang sử dụng: trong thực tế, bạn sẽ muốn chọn khoảng cách phù hợp và phương pháp phân cụm cho vấn đề của mình). Đây là giải pháp, với các cụm được chỉ định bởi màu của từng đoạn. (Màu sắc được phân ngẫu nhiên vào các cụm.)

Nhân vật

Đây là Rmã đã tạo ra ví dụ này. Đầu vào của nó là một tệp văn bản với các trường "Kinh độ" và "Vĩ độ" cho các thành phố. (Để gắn nhãn các thành phố trong hình, nó cũng bao gồm trường "Khóa".)

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

Cảm ơn! Tính toán khoảng cách theo cặp sẽ là một vấn đề đối với các bộ dữ liệu OD lớn?
underdark

Có, bởi vì với n phân đoạn dòng có tính toán khoảng cách n (n-1) / 2. Nhưng không có vấn đề cố hữu: tất cả các thuật toán phân cụm cần tìm khoảng cách hoặc điểm khác biệt giữa các điểm (hoặc giữa các điểm và trung tâm cụm). Đây là một vấn đề phổ biến đến mức nhiều thuật toán hoạt động với hàm khoảng cách tùy chỉnh.
whuber
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.