วิธีการวัดความคล้ายคลึงกันของวัตถุ SpatialLines


9

ฉันสร้างสองSpatialLinesวัตถุใน รูปR:

วัตถุเหล่านี้ถูกสร้างขึ้นด้วยวิธีนี้:

library(sp)
xy <- cbind(x,y)
xy.sp = sp::SpatialPoints(xy)
spl1 <- sp::SpatialLines(list(Lines(Line(xy.sp), ID="a")))

ทีนี้ฉันอยากสรุปว่านี่คือเส้นตรงที่หมุนแล้วพลิกและความแตกต่างระหว่างพวกเขาเท่ากับ 0 (รูปร่างที่เท่ากัน)

ในการทำเช่นนั้นเราสามารถใช้maptoolsแพ็คเกจและหมุนบรรทัดที่ 1 เช่น:

spl180 <- maptools::elide(spl1, rotate=180)

แต่ละบรรทัดที่หมุนแล้วจะต้องตรวจสอบเทียบกับบรรทัดที่ 2 โดยใช้rgeosแพ็คเกจเช่น:

hdist <- rgeos::gDistance(spl180, spl2, byid=FALSE, hausdorff=TRUE)

อย่างไรก็ตามนี่เป็นวิธีการคำนวณที่มีราคาแพงมากในการจับคู่SpatialLinesวัตถุโดยเฉพาะอย่างยิ่งหากจำนวนวัตถุมีค่าประมาณ 1,000

มีวิธีที่ฉลาดในการทำงานนี้หรือไม่?

ป.ล. นอกจากนี้วิธีการที่อธิบายไว้ข้างต้นไม่รับประกันการหมุนและการพลิกที่เป็นไปได้ทั้งหมด

P.S2 หากบรรทัดที่ 1 ถูกย่อส่วนด้วย # 2 ความแตกต่างระหว่างบรรทัด # 1 และ # 2 จะต้องเท่ากับ 0

UPDATE:

ป้อนคำอธิบายรูปภาพที่นี่

คำตอบ:


9

วิธีที่มีประสิทธิภาพวัตถุประสงค์ทั่วไปอย่างแท้จริงใด ๆ จะสร้างมาตรฐานการเป็นตัวแทนของรูปร่างเพื่อที่พวกเขาจะไม่เปลี่ยนแปลงตามการหมุนการแปลการสะท้อนหรือการเปลี่ยนแปลงเล็กน้อยในการเป็นตัวแทนภายใน

วิธีหนึ่งในการทำเช่นนี้คือรายการรูปร่างที่เชื่อมต่อกันเป็นลำดับสลับของความยาวขอบและมุม (เซ็นชื่อ) เริ่มต้นจากปลายด้านหนึ่ง (รูปร่างควรเป็น "สะอาด" ในแง่ของการไม่มีขอบที่มีความยาวเป็นศูนย์หรือมุมตรง) ในการทำให้ค่าคงที่นี้อยู่ภายใต้การสะท้อนให้ลบมุมทั้งหมดหากไม่เป็นศูนย์แรกที่เป็นค่าลบ

(เนื่องจากรูปหลายเหลี่ยมที่เชื่อมต่อกันของnจุดยอดจะมีขอบn -1 คั่นด้วยมุมn -2 ฉันพบว่ามันสะดวกในRโค้ดด้านล่างเพื่อใช้โครงสร้างข้อมูลประกอบด้วยสองอาร์เรย์หนึ่งสำหรับความยาวขอบ$lengthsและอีกอันสำหรับ angles,. $anglesส่วนของเส้นจะไม่มีมุมเลยดังนั้นมันสำคัญที่จะต้องจัดการกับอาร์เรย์ที่มีความยาวเป็นศูนย์ในโครงสร้างข้อมูลดังกล่าว)

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

ในการทำให้ค่าคงที่ภายใต้การพลิกกลับของการวางแนวพื้นฐานให้เลือกการแทนคำที่เก่าที่สุดระหว่าง lexicographically และการกลับรายการ

หากต้องการจัดการ polylines หลายส่วนให้จัดเรียงส่วนประกอบตามลำดับพจนานุกรม

ในการค้นหาคลาสสมมูลภายใต้การแปลงแบบยุคลิดจากนั้น

  • สร้างการรับรองมาตรฐานของรูปร่าง

  • ทำการเรียงลำดับพจนานุกรมของการรับรองมาตรฐาน

  • ส่งผ่านลำดับที่เรียงลำดับเพื่อระบุลำดับของการแทนเท่ากัน

เวลาในการคำนวณเป็นสัดส่วนกับ O (n * log (n) * N) โดยที่nคือจำนวนของคุณสมบัติและNเป็นจำนวนจุดยอดที่ใหญ่ที่สุดในคุณลักษณะใด ๆ สิ่งนี้มีประสิทธิภาพ

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


ตัวอย่าง

รูปมือซ้ายแสดงห้า polylines บวกอีก 15 ที่ได้จากการแปลแบบสุ่มการหมุนการสะท้อนและการพลิกกลับของการวางแนวภายใน (ซึ่งมองไม่เห็น) มือขวาร่างสีตามชนชั้นสมดุลแบบยุคลิดของพวกเขา: ตัวเลขทั้งหมดของสีทั่วไปเป็นสมภาค; สีที่ต่างกันจะไม่สอดคล้องกัน

รูป

Rรหัสดังต่อไปนี้ เมื่ออินพุตถูกอัพเดตเป็น 500 รูปร่าง, 500 พิเศษ (สอดคล้องกัน) รูปร่างโดยมีค่าเฉลี่ย 100 จุดต่อรูปร่าง, เวลาดำเนินการของเครื่องนี้คือ 3 วินาที

รหัสนี้ไม่สมบูรณ์:เนื่องจากRไม่มีการเรียงลำดับพจนานุกรมดั้งเดิมและฉันไม่รู้สึกเหมือนการเขียนรหัสตั้งแต่เริ่มต้นฉันจึงทำการเรียงลำดับในพิกัดแรกของแต่ละรูปร่างมาตรฐาน นั่นจะเป็นสิ่งที่ดีสำหรับรูปร่างแบบสุ่มที่สร้างขึ้นที่นี่ แต่สำหรับงานผลิตควรใช้การเรียงลำดับพจนานุกรมแบบเต็ม ฟังก์ชั่นorder.shapeจะเป็นเพียงสิ่งเดียวที่ได้รับผลกระทบจากการเปลี่ยนแปลงนี้ อินพุตของมันคือรายการของรูปร่างที่ได้มาตรฐานsและเอาต์พุตของมันคือลำดับของดัชนีsที่จะเรียงลำดับ

#
# Create random shapes.
#
n.shapes <- 5      # Unique shapes, up to congruence
n.shapes.new <- 15 # Additional congruent shapes to generate
p.mean <- 5        # Expected number of vertices per shape
set.seed(17)       # Create a reproducible starting point
shape.random <- function(n) matrix(rnorm(2*n), nrow=2, ncol=n)
shapes <- lapply(2+rpois(n.shapes, p.mean-2), shape.random)
#
# Randomly move them around.
#
move.random <- function(xy) {
  a <- runif(1, 0, 2*pi)
  reflection <- sign(runif(1, -1, 1))
  translation <- runif(2, -8, 8)
  m <- matrix(c(cos(a), sin(a), -sin(a), cos(a)), 2, 2) %*%
    matrix(c(reflection, 0, 0, 1), 2, 2)
  m <- m %*% xy + translation
  if (runif(1, -1, 0) < 0) m <- m[ ,dim(m)[2]:1]
  return (m)
}
i <- sample(length(shapes), n.shapes.new, replace=TRUE)
shapes <- c(shapes, lapply(i, function(j) move.random(shapes[[j]])))
#
# Plot the shapes.
#
range.shapes <- c(min(sapply(shapes, min)), max(sapply(shapes, max)))
palette(gray.colors(length(shapes)))
par(mfrow=c(1,2))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(shapes), function(i) lines(t(shapes[[i]]), col=i, lwd=2)))
#
# Standardize the shape description.
#
standardize <- function(xy) {
  n <- dim(xy)[2]
  vectors <- xy[ ,-1, drop=FALSE] - xy[ ,-n, drop=FALSE]
  lengths <- sqrt(colSums(vectors^2))
  if (which.min(lengths - rev(lengths))*2 < n) {
    lengths <- rev(lengths)
    vectors <- vectors[, (n-1):1]
  }
  if (n > 2) {
    vectors <- vectors / rbind(lengths, lengths)
    perps <- rbind(-vectors[2, ], vectors[1, ])
    angles <- sapply(1:(n-2), function(i) {
      cosine <- sum(vectors[, i+1] * vectors[, i])
      sine <- sum(perps[, i+1] * vectors[, i])
      atan2(sine, cosine)
    })
    i <- min(which(angles != 0))
    angles <- sign(angles[i]) * angles
  } else angles <- numeric(0)
  list(lengths=lengths, angles=angles)
}
shapes.std <- lapply(shapes, standardize)
#
# Sort lexicographically.  (Not implemented: see the text.)
#
order.shape <- function(s) {
  order(sapply(s, function(s) s$lengths[1]))
}
i <- order.shape(shapes.std)
#
# Group.
#
equal.shape <- function(s.0, s.1) {
  same.length <- function(a,b) abs(a-b) <= (a+b) * 1e-8
  same.angle <- function(a,b) min(abs(a-b), abs(a-b)-2*pi) < 1e-11
  r <- function(u) {
    a <- u$angles
    if (length(a) > 0) {
      a <- rev(u$angles)
      i <- min(which(a != 0))
      a <- sign(a[i]) * a
    }
    list(lengths=rev(u$lengths), angles=a)
  }
  e <- function(u, v) {
    if (length(u$lengths) != length(v$lengths)) return (FALSE)
    all(mapply(same.length, u$lengths, v$lengths)) &&
      all(mapply(same.angle, u$angles, v$angles))
    }
  e(s.0, s.1) || e(r(s.0), s.1)
}
g <- rep(1, length(shapes.std))
for (j in 2:length(i)) {
  i.0 <- i[j-1]
  i.1 <- i[j]
  if (equal.shape(shapes.std[[i.0]], shapes.std[[i.1]])) 
    g[j] <- g[j-1] else g[j] <- g[j-1]+1
}
palette(rainbow(max(g)))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(i), function(j) lines(t(shapes[[i[j]]]), col=g[j], lwd=2)))

เมื่อหนึ่งรวมถึง dilations พล (หรือ "isotheties") ในกลุ่มของการเปลี่ยนแปลงที่สมดุลเรียนที่มีการเรียนการสอดคล้องกันของรูปทรงเรขาคณิตที่เลียนแบบ ภาวะแทรกซ้อนนี้ได้รับการจัดการอย่างง่ายดาย: สร้างมาตรฐาน polylines ทั้งหมดให้มีความยาวรวมของหน่วยตัวอย่าง
whuber

ขอบคุณมาก ๆ. เพียงคำถามเดียว: รูปร่างควรจะแสดงเป็น SpatialLines หรือ SpatialPolygons?
Klausos Klausos

รูปหลายเหลี่ยมสร้างภาวะแทรกซ้อนอื่น: ขอบเขตของพวกเขาไม่มีปลายทางแน่นอน มีหลายวิธีในการจัดการเช่นการกำหนดมาตรฐานการเริ่มต้นที่ (พูด) จุดสุดยอดที่เรียงลำดับแรกตามลำดับ xy lexicographic และดำเนินการในทิศทางทวนเข็มนาฬิการอบรูปหลายเหลี่ยม (ทอพอโลยีรูปหลายเหลี่ยมที่เชื่อมต่อ "สะอาด" จะมีจุดสุดยอดเพียงจุดเดียว) ไม่ว่ารูปร่างนั้นจะถือว่าเป็นรูปหลายเหลี่ยมหรือรูปหลายเหลี่ยมก็ตาม ตั้งใจที่จะเป็นรูปหลายเหลี่ยมหรือรูปหลายเหลี่ยม
whuber

ขออภัยสำหรับคำถามง่ายๆ แต่ฉันควรขอให้เข้าใจตัวอย่างของคุณ วัตถุรูปร่างของคุณมีความยาว $ และ $ มุม อย่างไรก็ตามหากฉันเรียกใช้รหัสนี้กับข้อมูล xy ของฉัน (เช่น [1,] 3093.5 -2987.8 [2,] 3072.7 -2991.0 เป็นต้น) จะไม่ประมาณมุมหรือวาดรูปร่าง ถ้าฉันเรียกใช้พล็อต (รูปร่าง [[1]]) ดังนั้นฉันจะเห็นโพลีไลน์ของฉันได้อย่างชัดเจน ดังนั้นฉันควรบันทึก polylines ใน R เพื่อให้สามารถทดสอบโค้ดของคุณในข้อมูลของฉันได้อย่างไร
Klausos Klausos

ฉันเริ่มต้นด้วยโครงสร้างข้อมูลเดียวกับที่คุณทำ: อาร์เรย์ของ (x, y) พิกัด อาร์เรย์ของฉันใส่พิกัดเหล่านั้นลงในคอลัมน์ (ราวกับว่าคุณใช้rbind(x,y)แทนcbind(x,y)) นั่นคือทั้งหมดที่คุณต้องการ: spห้องสมุดไม่ได้ใช้ หากคุณต้องการที่จะทำตามสิ่งที่จะทำในรายละเอียดผมขอแนะนำให้คุณเริ่มต้นด้วยการพูดn.shapes <- 2, และn.shapes.new <- 3 p.mean <- 1จากนั้นshapes, shapes.stdฯลฯ ทั้งหมดพอขนาดเล็กที่จะตรวจสอบได้อย่างง่ายดาย วิธีที่สง่างามและ "ถูกต้อง" - ในการจัดการกับสิ่งเหล่านี้ทั้งหมดคือการสร้างคลาสของคุณสมบัติที่เป็นมาตรฐาน
whuber

1

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

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

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

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


ขอบคุณมาก. คุณช่วยอธิบายวิธีการตรวจสอบว่าความยาวของการส่องสว่างทั้งสองนั้นไม่ใช่อัตราส่วนจำนวนเต็มได้หรือไม่? นอกจากนี้ฉันขอขอบคุณมากถ้าคุณสามารถให้ตัวอย่างของการตรวจสอบ "ถ้าพื้นที่กล่องขอบเขตหรือพื้นที่ตัวถังนูนอยู่ในอัตราส่วนที่ดี"
Klausos Klausos

ตัวอย่างเช่นถ้าฉันแยกกล่อง จำกัด ขอบเขตจากข้อมูลอวกาศฉันเพิ่งได้รับสองคะแนน: spl <- sp :: SpatialLines (รายการ (เส้น (เส้น (เส้น (xy.sp), ID = i))) b <- bbox ( spl)
Klausos Klausos

ขยายการโพสต์หลัก
lynxlynxlynx

"ถ้าคุณได้จำนวนเต็มหรือใกล้พอคุณสามารถอนุมานได้ว่าอาจมีการปรับมาตราส่วน" ผู้ใช้ใช้งานระดับ 1.4 หรือไม่?
Germán Carrillo

แน่นอน แต่การสันนิษฐานของฉันชัดเจนโดยเฉพาะการแก้ไขในภายหลัง ฉันจินตนาการว่ากำลังซูมภาพในสไตล์เว็บแม็พซึ่งมีข้อ จำกัด อย่างมาก
lynxlynxlynx

1

วิธีที่ดีในการเปรียบเทียบ polylines เหล่านี้จะขึ้นอยู่กับการเป็นตัวแทนของลำดับ (ระยะทาง, มุมเลี้ยว) ที่แต่ละจุดยอด: สำหรับเส้นที่ประกอบด้วยคะแนนP1, P2, ..., PN, ลำดับดังกล่าวจะเป็น:

(ระยะทาง (P1P2), มุม (P1, P2, P3), ระยะทาง (P2P3), ... , มุม (P (N-2), P (N-1), PN), ระยะทาง (P (N-1) ) PN))

ตามความต้องการของคุณสองบรรทัดจะเท่ากับถ้าหากลำดับที่สอดคล้องกันเท่ากัน (โมดูโลสั่งทิศทางและมุม) การเปรียบเทียบลำดับหมายเลขนั้นเป็นเรื่องเล็กน้อย

ด้วยการคำนวณลำดับ polyline แต่ละครั้งเพียงครั้งเดียวและตามที่แนะนำโดย lynxlynxlynx การทดสอบความคล้ายคลึงกันของลำดับเฉพาะสำหรับ polyline ที่มีลักษณะเล็ก ๆ น้อย ๆ เช่นเดียวกัน (ความยาวจำนวนจุดยอด ... ) การคำนวณควรเร็วมาก!


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

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