web-dev-qa-db-fra.com

R - Recherche du point voisin le plus proche et du nombre de voisins dans un rayon donné, coordonnées lat-long

J'essaie de comprendre à quel point certains points sont isolés dans mon ensemble de données. J'utilise deux méthodes pour déterminer l'isolement, la distance du plus proche voisin et le nombre de sites voisins dans un rayon donné. Toutes mes coordonnées sont en latitude et longitude

Voici à quoi ressemblent mes données:

    pond            lat         long        area    canopy  avg.depth   neighbor    n.lat   n.long  n.distance  n.area  n.canopy    n.depth n.avg.depth radius1500
    A10             41.95928    -72.14605   1500    66      60.61538462                                 
    AA006           41.96431    -72.121     250     0       57.77777778                                 
    Blacksmith      41.95508    -72.123803  361     77      71.3125                                 
    Borrow.Pit.1    41.95601    -72.15419   0       0       41.44444444                                 
    Borrow.Pit.2    41.95571    -72.15413   0       0       37.7                                    
    Borrow.Pit.3    41.95546    -72.15375   0       0       29.22222222                                 
    Boulder         41.918223   -72.14978   1392    98      43.53333333                                 

Je veux mettre le nom de l'étang voisin le plus proche dans la colonne voisine, son lat et long en n.lat et n.long, la distance entre les deux étangs en n.distance, et la zone, la canopée et la profondeur moyenne en chacune des colonnes appropriées.

Deuxièmement, je veux mettre le nombre d'étangs à moins de 1500m de l'étang cible dans radius1500.

Quelqu'un connaît-il une fonction ou un package qui m'aidera à calculer les distances/nombres que je veux? Si c'est un problème, il ne sera pas difficile d'entrer les autres données dont j'ai besoin, mais le nom et la distance du voisin le plus proche, ainsi que le nombre d'étangs à moins de 1500 mètres, sont ce pour quoi j'ai vraiment besoin d'aide.

Je vous remercie.

23
user2934942

La meilleure option consiste à utiliser les bibliothèques sp et rgeos, qui vous permettent de construire des classes spatiales et d'effectuer un géotraitement.

library(sp)
library(rgeos)

Lisez les données et transformez-les en objets spatiaux:

mydata <- read.delim('d:/temp/testfile.txt', header=T)

sp.mydata <- mydata
coordinates(sp.mydata) <- ~long+lat

class(sp.mydata)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"

Maintenant, calculez les distances par paires entre les points

d <- gDistance(sp.mydata, byid=T)

Trouver la deuxième distance la plus courte (la distance la plus proche est du point par rapport à lui-même, utilisez donc la deuxième plus courte)

min.d <- apply(d, 1, function(x) order(x, decreasing=F)[2])

Construire un nouveau bloc de données avec les variables souhaitées

newdata <- cbind(mydata, mydata[min.d,], apply(d, 1, function(x) sort(x, decreasing=F)[2]))

colnames(newdata) <- c(colnames(mydata), 'neighbor', 'n.lat', 'n.long', 'n.area', 'n.canopy', 'n.avg.depth', 'distance')

newdata
            pond      lat      long area canopy avg.depth     neighbor    n.lat    n.long n.area n.canopy n.avg.depth
6            A10 41.95928 -72.14605 1500     66  60.61538 Borrow.Pit.3 41.95546 -72.15375      0        0    29.22222
3          AA006 41.96431 -72.12100  250      0  57.77778   Blacksmith 41.95508 -72.12380    361       77    71.31250
2     Blacksmith 41.95508 -72.12380  361     77  71.31250        AA006 41.96431 -72.12100    250        0    57.77778
5   Borrow.Pit.1 41.95601 -72.15419    0      0  41.44444 Borrow.Pit.2 41.95571 -72.15413      0        0    37.70000
4   Borrow.Pit.2 41.95571 -72.15413    0      0  37.70000 Borrow.Pit.1 41.95601 -72.15419      0        0    41.44444
5.1 Borrow.Pit.3 41.95546 -72.15375    0      0  29.22222 Borrow.Pit.2 41.95571 -72.15413      0        0    37.70000
6.1      Boulder 41.91822 -72.14978 1392     98  43.53333 Borrow.Pit.3 41.95546 -72.15375      0        0    29.22222
        distance
6   0.0085954872
3   0.0096462277
2   0.0096462277
5   0.0003059412
4   0.0003059412
5.1 0.0004548626
6.1 0.0374480316

Edit: si les coordonnées sont en degrés et que vous souhaitez calculer la distance en kilomètres, utilisez le package geosphere

library(geosphere)

d <- distm(sp.mydata)

# rest is the same

Cela devrait fournir de meilleurs résultats, si les points sont dispersés à travers le globe et les coordonnées sont en degrés

35
Zbynek

La solution proposée par @Zbynek est plutôt sympa mais si vous cherchez une distance entre deux voisins en km comme je le suis, je vous propose cette solution.

   earth.dist<-function(lat1,long1,lat2,long2){

           rad <- pi/180
           a1 <- lat1 * rad
           a2 <- long1 * rad
           b1 <- lat2 * rad
           b2 <- long2 * rad
           dlat <- b1-a1
           dlon<- b2-a2
           a <- (sin(dlat/2))^2 +cos(a1)*cos(b1)*(sin(dlon/2))^2
           c <- 2*atan2(sqrt(a),sqrt(1-a))
           R <- 6378.145
           dist <- R *c
           return(dist)
           }


    Dist <- matrix(0,ncol=length(mydata),nrow=length(mydata.sp))

  for (i in 1:length(mydata)){
      for(j in 1:length(mydata.sp)){
          Dist[i,j] <- earth.dist(mydata$lat[i],mydata$long[i],mydata.sp$lat[j],mydata.sp$long[j])
 }}



     DDD <- matrix(0, ncol=5,nrow=ncol(Dist))   ### RECTIFY the nb of col by the number of variable you want

   for(i in 1:ncol(Dist)){
       sub<- sort(Dist[,i])[2]
       DDD[i,1] <- names(sub) 
       DDD[i,2] <- sub
       DDD[i,3] <- rownames(Dist)[i]
       sub_neig_atr <- Coord[Coord$ID==names(sub),]
       DDD[i,4] <- sub_neig_atr$area
       DDD[i,5] <- sub_neig_atr$canopy
       ### Your can add any variable you want here 

   }

    DDD <- as.data.frame(DDD)

    names(DDD)<-c("neigboor_ID","distance","pond","n.area","n.canopy")
   data <- merge(mydata,DDD, by="pond")

Vous finissez par obtenir une distance en km si vos coordonnées sont longues et latentes.

Des suggestions pour l'améliorer?

1
Nico Coallier