Distancia geográfica / geoespacial entre 2 listas de puntos lat / lon (coordenadas)

Tengo 2 listas ( list1 , list2 ) con latitud / longitudes de varias ubicaciones. Una lista ( list2 ) tiene nombres de localidad que list1 no tiene.

También quiero una localidad aproximada para cada punto en la lista1. Así que quiero tomar un punto en la list1 , tratar de buscar el punto más cercano en list2 y tomar esa localidad. Repito para cada punto de la list1 . También quiere la distancia (en metros) y el índice del punto (en list1 ) para que pueda construir algunas reglas de negocio a su alrededor, esencialmente estos son 2 nuevos cols que deberían agregarse a list1 ( near_dist , indx ).

Estoy usando la función gdist , pero no puedo hacer que funcione con las entradas de marcos de datos.

Ejemplo de listas de entrada:

 list1 <- data.frame(longitude = c(80.15998, 72.89125, 77.65032, 77.60599, 72.88120, 76.65460, 72.88232, 77.49186, 72.82228, 72.88871), latitude = c(12.90524, 19.08120, 12.97238, 12.90927, 19.08225, 12.81447, 19.08241, 13.00984, 18.99347, 19.07990)) list2 <- data.frame(longitude = c(72.89537, 77.65094, 73.95325, 72.96746, 77.65058, 77.66715, 77.64214, 77.58415, 77.76180, 76.65460), latitude = c(19.07726, 13.03902, 18.50330, 19.16764, 12.90871, 13.01693, 13.00954, 12.92079, 13.02212, 12.81447), locality = c("A", "A", "B", "B", "C", "C", "C", "D", "D", "E")) 

Para calcular la distancia geográfica entre dos puntos con coordenadas de latitud / longitud, puede usar varias fórmulas. El paquete geosphere tiene distCosine , distHaversine , distVincentySphere y distVincentyEllipsoid para calcular la distancia. De estos, distVincentyEllipsoid se considera el más preciso, pero es computacionalmente más intensivo que los otros.

Con una de estas funciones, puede hacer una matriz de distancia. En base a esa matriz, puede asignar nombres de locality función de la distancia más corta con la which.min y la distancia correspondiente con min (vea para esto la última parte de la respuesta) de la siguiente manera:

 library(geosphere) # create distance matrix mat < - distm(list1[,c('longitude','latitude')], list2[,c('longitude','latitude')], fun=distVincentyEllipsoid) # assign the name to the point in list1 based on shortest distance in the matrix list1$locality <- list2$locality[max.col(-mat)] 

esto da:

 > list1 longitude latitude locality 1 80.15998 12.90524 D 2 72.89125 19.08120 A 3 77.65032 12.97238 C 4 77.60599 12.90927 D 5 72.88120 19.08225 A 6 76.65460 12.81447 E 7 72.88232 19.08241 A 8 77.49186 13.00984 D 9 72.82228 18.99347 A 10 72.88871 19.07990 A 

Otra posibilidad es asignar la locality función de los valores promedio de longitud y latitud de la locality s en list2 :

 library(dplyr) list2a < - list2 %>% group_by(locality) %>% summarise_each(funs(mean)) %>% ungroup() mat2 < - distm(list1[,c('longitude','latitude')], list2a[,c('longitude','latitude')], fun=distVincentyEllipsoid) list1 <- list1 %>% mutate(locality2 = list2a$locality[max.col(-mat2)]) 

o con data.table :

 library(data.table) list2a < - setDT(list2)[,lapply(.SD, mean), by=locality] mat2 <- distm(setDT(list1)[,.(longitude,latitude)], list2a[,.(longitude,latitude)], fun=distVincentyEllipsoid) list1[, locality2 := list2a$locality[max.col(-mat2)] ] 

esto da:

 > list1 longitude latitude locality locality2 1 80.15998 12.90524 DD 2 72.89125 19.08120 AB 3 77.65032 12.97238 CC 4 77.60599 12.90927 DC 5 72.88120 19.08225 AB 6 76.65460 12.81447 EE 7 72.88232 19.08241 AB 8 77.49186 13.00984 DC 9 72.82228 18.99347 AB 10 72.88871 19.07990 AB 

Como puede ver, esto lleva en la mayoría (7 de cada 10) ocasiones a otra locality asignada.


Puedes agregar la distancia con:

 list1$near_dist < - apply(mat2, 1, min) 

u otro enfoque con max.col (que es altamente probable más rápido):

 list1$near_dist < - mat2[matrix(c(1:10, max.col(-mat2)), ncol = 2)] # or using dplyr list1 <- list1 %>% mutate(near_dist = mat2[matrix(c(1:10, max.col(-mat2)), ncol = 2)]) # or using data.table (if not already a data.table, convert it with 'setDT(list1)' ) list1[, near_dist := mat2[matrix(c(1:10, max.col(-mat2)), ncol = 2)] ] 

el resultado:

 > list1 longitude latitude locality locality2 near_dist 1: 80.15998 12.90524 DD 269966.8970 2: 72.89125 19.08120 AB 65820.2047 3: 77.65032 12.97238 CC 739.1885 4: 77.60599 12.90927 DC 9209.8165 5: 72.88120 19.08225 AB 66832.7223 6: 76.65460 12.81447 EE 0.0000 7: 72.88232 19.08241 AB 66732.3127 8: 77.49186 13.00984 DC 17855.3083 9: 72.82228 18.99347 AB 69456.3382 10: 72.88871 19.07990 AB 66004.9900