Distância geográfica / geoespacial entre 2 listas de pontos lat / lon (coordenadas)

Eu tenho 2 listas ( list1 , list2 ) com latitude / longitudes de vários locais. Uma lista ( list2 ) tem nomes de localidade que list1 não possui.

Eu quero uma localidade aproximada para cada ponto na lista1 também. Então eu quero pegar um ponto na list1 , tentar procurar o ponto mais próximo na list2 e pegar aquela localidade. Eu repito para cada ponto na list1 . Ele também quer a distância (em metros) e o índice do ponto (em list1 ) para que eu possa construir algumas regras de negócios em torno dele – essencialmente, são dois novos cols que devem ser adicionados à list1 ( near_dist , indx ).

Estou usando a function gdist , mas não consigo fazer isso funcionar com inputs de frameworks de dados.

Exemplo de listas de input:

 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 a distância geográfica entre dois pontos com coordenadas de latitude / longitude, você pode usar várias fórmulas. A geosphere pacote tem o distCosine , distHaversine , distVincentySphere e distVincentyEllipsoid para calcular a distância. Destes, o distVincentyEllipsoid é considerado o mais preciso, mas computacionalmente mais intensivo que os outros.

Com uma dessas funções, você pode criar uma matriz de distância. Com base nessa matriz, você pode atribuir nomes de locality base na distância mais curta com a which.min e a distância correspondente com min (veja a última parte da resposta):

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

isto dá:

 > 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 

Outra possibilidade é atribuir a locality base nos valores médios de longitude e latitude da locality s na lista 2:

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

ou com 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)] ] 

isto dá:

 > 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 você pode ver, isso leva na maioria (7 de 10) ocasiões para outra locality designada.


Você pode adicionar a distância com:

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

ou outra abordagem com max.col (que é altamente provável mais 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)] ] 

o 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