2015-07-28 24 views
24

Ho 2 elenchi (list1, list2) con latitudine/longitudine di varie posizioni. Un elenco (list2) ha nomi di località che non ha list1.Distanza geografica/geospaziale tra 2 elenchi di punti lat/lon (coordinate)

Desidero una località approssimativa per ogni punto in list1. Quindi voglio prendere un punto in list1, provare a cercare il punto più vicino in list2 e prendere quella località. Ripeto per ogni punto in list1. Vogliono anche la distanza (in metri) e l'indice del punto (in list1) in modo che io possa costruire alcune regole commerciali intorno ad esso - essenzialmente queste sono 2 nuove colonne che dovrebbero essere aggiunte a list1 (near_dist, indx).

Sto usando la funzione gdist, ma non riesco a farlo funzionare con gli input del frame dati.

liste di input Esempio:

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

risposta

37

Per calcolare la distanza geografica tra i due punti con coordinate di latitudine/longitudine, è possibile utilizzare diversi formula di. Il pacchetto geosphere ha il distCosine, distHaversine, distVincentySphere e distVincentyEllipsoid per il calcolo della distanza. Di questi, lo distVincentyEllipsoid è considerato il più accurato, ma è computazionalmente più intenso degli altri.

Con una di queste funzioni, è possibile creare una matrice di distanze. Sulla base di tale matrice è possibile assegnare locality nomi in base alla distanza più breve con which.min e la distanza corrispondente min (si veda per questo l'ultima parte della risposta) come questo:

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

questo 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 

Un'altra possibilità è quella di assegnare il locality sulla base dei valori di longitudine e latitudine medi delle locality s in 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)] ] 

questo dà:

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

Come si può vedere, questo porta nella maggior parte (7 su 10) occasioni a un altro assegnato locality.


È possibile aggiungere la distanza con:

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

o un altro approccio con max.col (che è altamente probabile più veloce):

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

il risultato:

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