R'de çokgenler arasındaki {minimum} mesafeyi hesaplama


9

Tür dağılımlarının yüzey alanını hesapladım (şekil dosyalarından çokgenleri birleştirmek), ancak bu alan oldukça uzak çokgenlerden oluşabileceğinden, bir miktar dağılım ölçüsünü hesaplamak istiyorum. Şimdiye kadar yaptığım, her çokgenin centroidlerini geri almak, aralarındaki mesafeyi hesaplamak ve bunları aşağıdaki kukla örnekte olduğu gibi varyasyon katsayısını hesaplamak için kullanmaktır;

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

Üç çokgen ve bunların sentroidlerinin çizimi

resim açıklamasını buraya girin

Bu yaklaşımın çok yararlı olup olmadığından emin değilim, çünkü birçok durumda, çokgenler (yukarıdaki örnekte mavi olan gibi) geri kalanlara kıyasla oldukça büyüktür, böylece mesafeyi daha da arttırır. Örneğin, Avustralya'nın sentroidi Papau ile batılı yatılılarla neredeyse aynı mesafeye sahiptir.

Almak istediğim alternatif yaklaşımlar hakkında bazı bilgiler. Örneğin, çokgenler arasındaki mesafeyi nasıl veya hangi fonksiyonla hesaplayabilirim?

Tüm noktalar arasındaki mesafeyi hesaplamak {spatstat}için çalıştırmak nndist() {spatstat}için yukarıdaki SpatialPolygon veri çerçevesini PointPatterns (ppp) dönüştürmek için test ettim . Ama oldukça geniş alanlarla (çokgenler ve büyük olanlar) uğraştığım için, matris büyükleşiyor ve çokgenler arasındaki minimum mesafeye nasıl devam edeceğinden emin değilim .

Bu işleve de baktım gDistance {rgeos}, ancak alanlarmın birkaçını geçebileceği için sadece benim için sorun olabilecek tahmini veriler üzerinde çalıştığını düşünüyorum EPSG areas. Aynı sorun fonksiyon için de ortaya çıkacaktır crossdist {spatstat}.


1
Buna postgres/postgisek olarak kullanmayı düşünür müsünüz R? İşimin çoğunu gerçekleştirdiğim R, ancak verileri kullanarak eriştiğim bir veritabanında sakladığım bir iş akışı kullandım sqldf. Bu, tüm postgisişlevleri (çokgenler arasındaki mesafenin doğrudan olduğu) kullanmanızı sağlar
djq

@djq: Yorum yaptığınız için teşekkürler. Evet, kesinlikle bir gitmek istiyorum :) Bir veritabanı inşa etmeye başladı postgresama ben veritabanı ile iş akışı / geostats arasında nasıl bağlanacağını bilmiyordum (bakmadı)R
JO.

Yanıtlar:


9

Bu analizi "spdep" paketinde yapabilirsiniz. İlgili komşu işlevlerde, "longlat = TRUE" kullanırsanız, işlev büyük daire mesafesini hesaplar ve kilometreyi mesafe birimi olarak döndürür. Aşağıdaki örnekte, sonuçta elde edilen mesafe listesi nesnesini ("dist.list") bir matrise veya data.frame'e zorlayabilirsiniz, ancak lapply kullanarak özet istatistikleri hesaplamak oldukça etkilidir.

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

Yorum yaptığınız için teşekkür ederiz spdeb. Sadece açıklamak gerekirse, bu yaklaşım benim örneğimle aynı çıktıyı veriyor, değil mi?
JO.

Yukarıdaki
yorumumu görememeniz

Yanıt, sentroidler arasındaki mesafeleri hesaplamak için yararlı bir kod sağlamasına rağmen, OP'nin merkezi noktasıyla ilgilenmez, bu da çokgen sınırlarının en yakın iki noktası arasındaki mesafeyi nasıl bulacağınızdır.
csfowler

Büyük bir polis ve SE için kötü bir form, ama şu anda tam çalışmayı yapamıyorum. Bu soruya bir cevap arayışım, kütüphane rgeolarından gelen gDistance fonksiyonunun OP'nin amaçladığı şeyi yapacağını gösteriyor: kenarlar arasındaki en kısa mesafeyi bulun. Sıkı bir süre için acele ederken OP veya Jeffrey Evans'ı özür dilerim.
csfowler
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.