การคำนวณระยะห่าง {น้อยที่สุด} ระหว่างรูปหลายเหลี่ยมใน R


9

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

require(sp)
require(ggplot2)
require(mapdata)
require(gridExtra)
require(scales)
require(rgeos)
require(spatstat)

# Create the coordinates for 3 squares
ls.coords <- list()
ls.coords <- list()
ls.coords[[1]] <- c(15.7, 42.3, # a list of coordinates
                    16.7, 42.3,
                    16.7, 41.6,
                    15.7, 41.6,
                    15.7, 42.3)

ls.coords[[2]] <- ls.coords[[1]]+0.5 # use simple offset

ls.coords[[3]] <- c(13.8, 45.4, # a list of coordinates
                    15.6, 45.4,
                    15.6, 43.7,
                    13.8, 43.7,
                    13.8, 45.4)

# Prepare lists to receive the sp objects and data frames
ls.polys <- list()
ls.sp.polys <- list()

for (ii in seq_along(ls.coords)) {
   crs.args <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
   my.rows <- length(ls.coords[[ii]])/2
   # create matrix of pairs
   my.coords <- matrix(ls.coords[[ii]],nrow = my.rows,ncol = 2,byrow = TRUE)
   # now build sp objects from scratch...
   poly = Polygon(my.coords)
   # layer by layer...
   polys = Polygons(list(poly),1)
   spolys = SpatialPolygons(list(polys))
   # projection is important
   proj4string(spolys) <- crs.args
   # Now save sp objects for later use
   ls.sp.polys[[ii]] <- spolys
   # Then create data frames for ggplot()
   poly.df <- fortify(spolys)
   poly.df$id <- ii
   ls.polys[[ii]] <- poly.df
}

# Convert the list of polygons to a list of owins
w <- lapply(ls.sp.polys, as.owin)
# Calculate the centroids and get the output to a matrix
centroid <- lapply(w, centroid.owin)
centroid <- lapply(centroid, rbind)
centroid <- lapply(centroid, function(x) rbind(unlist(x)))
centroid <- do.call('rbind', centroid)

# Create a new df and use fortify for ggplot
centroid_df <- fortify(as.data.frame(centroid))
# Add a group column
centroid_df$V3 <- rownames(centroid_df)

ggplot(data = italy, aes(x = long, y = lat, group = group)) +
  geom_polygon(fill = "grey50") +
  # Constrain the scale to 'zoom in'
  coord_cartesian(xlim = c(13, 19), ylim = c(41, 46)) +
  geom_polygon(data = ls.polys[[1]], aes(x = long, y = lat, group = group), fill = alpha("red", 0.3)) +
  geom_polygon(data = ls.polys[[2]], aes(x = long, y = lat, group = group), fill = alpha("green", 0.3)) +
  geom_polygon(data = ls.polys[[3]], aes(x = long, y = lat, group = group), fill = alpha("lightblue", 0.8)) + 
  coord_equal() +
  # Plot the centroids
  geom_point(data=centroid_points, aes(x = V1, y = V2, group = V3))

# Calculate the centroid distances using spDists {sp}
centroid_dists <- spDists(x=centroid, y=centroid, longlat=TRUE)

centroid_dists

       [,1]      [,2]     [,3]
[1,]   0.00000  69.16756 313.2383
[2,]  69.16756   0.00000 283.7120
[3,] 313.23834 283.71202   0.0000

# Calculate the coefficient of variation as a measure of polygon dispersion 
cv <- sd(centroid_dist)/mean(centroid_dist)
[1] 0.9835782

พล็อตรูปสามเหลี่ยมและเซนทรอยด์ของพวกมัน

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

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

สิ่งที่ฉันต้องการได้รับคือการป้อนข้อมูลเกี่ยวกับวิธีการอื่น เช่นฉันจะคำนวณระยะห่างระหว่างรูปหลายเหลี่ยมได้อย่างไรหรือด้วยฟังก์ชันใด

ฉันทดสอบเพื่อแปลง SpatialPolygon dataframe ด้านบนเป็น PointPatterns (ppp) {spatstat}เพื่อให้สามารถเรียกใช้nndist() {spatstat}เพื่อคำนวณระยะทางระหว่างจุดทั้งหมด แต่ตั้งแต่ผมกำลังจัดการกับพื้นที่ขนาดใหญ่มาก (รูปหลายเหลี่ยมหลายคนและขนาดใหญ่), เมทริกซ์ที่ได้รับอย่างมากและอิ่มไม่แน่ใจว่าจะยังคงได้รับการระยะทางที่น้อยที่สุดระหว่างรูปหลายเหลี่ยม

ฉันได้ดูฟังก์ชันgDistance {rgeos}นี้ด้วย แต่ฉันคิดว่ามันใช้ได้กับข้อมูลที่คาดการณ์เท่านั้นซึ่งอาจเป็นปัญหาสำหรับฉันเนื่องจากพื้นที่ของฉันสามารถข้ามได้หลายEPSG areasอย่าง crossdist {spatstat}ปัญหาเดียวกันจะเกิดขึ้นสำหรับฟังก์ชั่น


1
คุณจะพิจารณาการใช้postgres/postgisเพิ่มเติมจากR? ฉันได้ใช้ขั้นตอนการทำงานที่ผมดำเนินการส่วนใหญ่ของการทำงานของฉันในส่วนแต่การจัดเก็บข้อมูลในฐานข้อมูลที่ผมเข้าถึงโดยใช้R sqldfสิ่งนี้ช่วยให้คุณสามารถใช้postgisฟังก์ชั่นทั้งหมด (ซึ่งระยะห่างระหว่างรูปหลายเหลี่ยมเป็นแบบตรง)
djq

@djq: ขอบคุณสำหรับการแสดงความคิดเห็น ใช่ฉันจะไปแน่นอน :) ฉันเริ่มสร้างฐานข้อมูลในpostgresแต่หยุดเมื่อฉันไม่รู้ (ไม่ได้ดู) วิธีการเชื่อมต่อเวิร์กโฟลว์ / geostats ระหว่างฐานข้อมูลและR...
jO

คำตอบ:


9

คุณสามารถทำการวิเคราะห์นี้ในแพ็คเกจ "spdep" ในฟังก์ชั่นเพื่อนบ้านที่เกี่ยวข้องหากคุณใช้ "longlat = TRUE" ฟังก์ชั่นจะคำนวณระยะทางวงกลมที่ดีและส่งกลับกิโลเมตรเป็นหน่วยระยะทาง ในตัวอย่างด้านล่างคุณสามารถบีบบังคับวัตถุรายการระยะทางที่เกิด ("dist.list") กับเมทริกซ์หรือ data.frame อย่างไรก็ตามมันค่อนข้างมีประสิทธิภาพในการคำนวณสถิติสรุปโดยใช้ lapply

require(sp)
require(spdep)

# Create SpatialPolygonsDataFrame for 3 squares
poly1 <- Polygons(list(Polygon(matrix(c(15.7,42.3,16.7,42.3,16.7,41.6,15.7,41.6,15.7,42.3), 
                   nrow=5, ncol=2, byrow=TRUE))),"1")     
poly2 <- Polygons(list(Polygon(matrix(c(15.7,42.3,16.7,42.3,16.7,41.6,15.7,41.6,15.7,42.3)+0.5, 
                   nrow=5, ncol=2, byrow=TRUE))),"2")     
poly3 <- Polygons(list(Polygon(matrix(c(13.8, 45.4, 15.6, 45.4,15.6, 43.7,13.8, 43.7,13.8, 45.4), 
                   nrow=5, ncol=2, byrow=TRUE))),"3")                      
spolys = SpatialPolygons(list(poly1,poly2,poly3),1:3)
 spolys <- SpatialPolygonsDataFrame(spolys, data.frame(ID=sapply(slot(spolys, "polygons"), 
                                    function(x) slot(x, "ID"))) )   
   proj4string(spolys) <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"

# Centroid coordinates (not used but provided for example) 
coords <- coordinates(spolys)

# Create K Nearest Neighbor list
skNN.nb <- knn2nb(knearneigh(coordinates(spolys), longlat=TRUE), 
                  row.names=spolys@data$ID)

# Calculate maximum distance for all linkages 
maxDist <- max(unlist(nbdists(skNN.nb, coordinates(spolys), longlat=TRUE)))

# Create spdep distance object
sDist <- dnearneigh(coordinates(spolys), 0, maxDist^2, row.names=spolys@data$ID)
  summary(sDist, coordinates(spolys), longlat=TRUE)

# Plot neighbor linkages                  
plot(spolys, border="grey") 
  plot(sDist, coordinates(spolys), add=TRUE)  

# Create neighbor distance list 
( dist.list <- nbdists(sDist, coordinates(spolys), longlat=TRUE) )

# Minimum distance 
( dist.min <- lapply(dist.list, FUN=min) )

# Distance coefficient of variation    
( dist.cv <- lapply(dist.list, FUN=function(x) { sd(x) / mean(x) } ) )

ขอบคุณสำหรับการแสดงความคิดเห็นและข้อมูลเชิงลึกในspdebแพ็คเกจ เพื่อความกระจ่าง, วิธีนี้ให้ผลลัพธ์เหมือนในตัวอย่างใช่ไหม?
jO

ในกรณีที่คุณไม่เห็นความคิดเห็นข้างต้นของฉัน
jO

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

ตำรวจขนาดใหญ่และฟอร์มที่แย่สำหรับ SE แต่ตอนนี้ฉันไม่สามารถทำงานได้เต็มที่ การค้นหาคำตอบสำหรับคำถามนี้ดูเหมือนว่าจะบ่งบอกว่าฟังก์ชั่น gDistance จากห้องสมุด rgeos จะทำในสิ่งที่ OP ต้องการ: ค้นหาระยะทางที่สั้นที่สุดระหว่างขอบ ถ้าหากฉันรีบไปพบกับเส้นตายที่กำหนดฉันได้ตีความผิด OP หรือ Jeffrey Evans ขอโทษอย่างจริงใจ
csfowler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.