การทำคลัสเตอร์สายที่ไม่ได้บอกทิศทาง


16

ฉันกำลังมองหาวิธีที่มีประสิทธิภาพในการจัดกลุ่มบรรทัดที่เป็นอิสระจากทิศทางของพวกเขา นั่นหมายความว่าเส้นแบ่งระหว่างนิวยอร์กกับลอสแองเจลิสควรอยู่ในกลุ่มเดียวกันกับแนวในทิศทางอื่นระหว่างลอสแองเจลิสและนิวยอร์ก จุดเริ่มต้น / จุดสิ้นสุดควรมีลักษณะใกล้เคียงกัน (เช่นซานดิเอโกไปลองไอส์แลนด์ควรอยู่ในกลุ่มเดียวกันกับ LA-NY แต่อาจไม่ใช่ซานฟรานซิสโกถึงบอสตัน) และไม่มีจุดกึ่งกลาง ข้อมูลอินพุตจะคล้ายกับตัวอย่างนี้:

ป้อนคำอธิบายรูปภาพที่นี่ (โดย Cassiopeia หวานที่วิกิพีเดียภาษาญี่ปุ่นGFDLหรือCC-BY-SA-3.0ผ่านวิกิมีเดียคอมมอนส์)

ก่อนหน้านี้ฉันพยายามเรียงลำดับบรรทัดล่วงหน้าเช่นทำให้พวกเขาวิ่งจากตะวันตกไปตะวันออก แต่นี่ไม่ได้แก้ปัญหาสำหรับสายที่วิ่งจากเหนือจรดใต้และอื่น ๆ

คุณรู้อัลกอริธึมที่เกี่ยวข้องกับปัญหานี้หรือไม่? ฉันกำลังมองหา แต่นอกเหนือจากอัลกอริทึมในการคำนวณทิศทางเฉลี่ยของกลุ่มที่ไม่ได้ทำเส้นทางฉันไม่พบสิ่งใดที่เป็นประโยชน์จากระยะไกลดังนั้นฉันจึงต้องใช้คำค้นหาที่ไม่ถูกต้อง


1
ฉันจะคำนวณพิกัดปลายทั้งสองและใช้ STR (set ([x1, y1, x2, y2])) เพื่อเติมฟิลด์สตริง คุณสามารถสรุปฟิลด์นี้เพื่อค้นหาค่าที่ไม่ซ้ำกัน
FelixIP

คำตอบ:


10

หากฉันเข้าใจคุณถูกต้องคุณต้องการจัดกลุ่มบรรทัดที่มีความเหมือนกันโดยไม่เกี่ยวข้องกับทิศทาง

นี่คือความคิดที่ฉันคิดว่าสามารถใช้ได้

  1. แยกบรรทัดในจุดเริ่มต้นและจุดสิ้นสุด

  2. ทำคลัสเตอร์คะแนนและรับ ID คลัสเตอร์

  3. ค้นหาบรรทัดที่มีการรวมกันของรหัสคลัสเตอร์เดียวกัน นั่นคือคลัสเตอร์

สิ่งนี้ควรเป็นไปได้ใน PostGIS (แน่นอน :-)) เวอร์ชัน 2.3

ฉันไม่ได้ทดสอบฟังก์ชัน ST_ClusterDBSCAN แต่ควรใช้งานได้

หากคุณมีตารางเส้นแบบนี้:

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

และคุณต้องการสร้างคลัสเตอร์ที่จุดเริ่มต้นและจุดสิ้นสุดอยู่ห่างกันสูงสุด 10 กม. และจะต้องมีอย่างน้อย 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 คลัสเตอร์ที่เปรียบเทียบได้โดยไม่ขึ้นกับทิศทาง


ขอบคุณ Nicklas! ฉันชอบวิธีการนี้เพราะมันไม่ได้บังคับให้ฉันผสมหน่วยต่าง ๆ (เช่นมุมและระยะทาง) ขณะทำการรวมกลุ่ม
underdark

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
underdark

ฉันสงสัยว่าคุณอาจมีสิ่งนั้นอยู่ในใจ นั่นเป็นเหตุผลที่ฉันแนะนำให้ทำแผนที่ครึ่งทิศทางกับพิกัด (จุด) คุณสามารถปรับขนาดจุดเหล่านั้น (คิดว่าพิกัดเชิงขั้ว) โดยตัวแปรตัวที่สองและ / หรือแนะนำพิกัดเพิ่มเติมสำหรับจุดกำเนิดหรือปลายทาง โดยไม่ทราบว่าจุดประสงค์สูงสุดของการจัดกลุ่มเป็นเรื่องยากที่จะให้คำแนะนำเพิ่มเติมเนื่องจากขนาดที่สัมพันธ์กันของพิกัดเพิ่มเติม (เทียบกับพิกัดวงกลม) จะเป็นตัวกำหนดวิธีการแก้ปัญหาการจัดกลุ่ม ทางออกก็คือการใช้ประโยชน์จากHough เปลี่ยน
whuber

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

ณ จุดนี้คุณอาจใช้เทคนิคการจัดกลุ่มใด ๆ ตามเมทริกซ์ระยะทาง


ตัวอย่างเช่นฉันคำนวณระยะทางจากจุดหนึ่งถึงจุดทั้งหมด 190 จุดบนแผนที่สำหรับ 20 เมืองในสหรัฐอเมริกาที่มีประชากรมากที่สุดและขอแปดกลุ่มโดยใช้วิธีการลำดับชั้น (สำหรับความเรียบง่ายฉันใช้การคำนวณระยะทางแบบยุคลิดและใช้วิธีการเริ่มต้นในซอฟต์แวร์ที่ฉันใช้: ในทางปฏิบัติคุณจะต้องเลือกระยะทางที่เหมาะสมและวิธีการจัดกลุ่มสำหรับปัญหาของคุณ) นี่คือวิธีแก้ปัญหาด้วยกลุ่มที่ระบุโดยสีของแต่ละส่วนของเส้น (สีได้รับการสุ่มให้กับกลุ่ม)

รูป

นี่คือ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 ขนาดใหญ่ไหม
underdark

ใช่เพราะมีส่วนของเส้นตรงnเส้นจึงมีการคำนวณระยะทาง n (n-1) / 2 แต่ไม่มีปัญหาโดยธรรมชาติ: อัลกอริธึมการจัดกลุ่มทั้งหมดจำเป็นต้องค้นหาระยะทางหรือความแตกต่างระหว่างจุด (หรือระหว่างจุดและจุดศูนย์กลางคลัสเตอร์) นี่เป็นปัญหาทั่วไปที่อัลกอริทึมจำนวนมากทำงานกับฟังก์ชันระยะทางที่กำหนดเอง
whuber
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.