2015-07-28 36 views
24

Mam 2 listy (list1, list2) o szerokości/długości geograficznej różnych lokalizacji. Jedna lista (list2) ma nazwy miejscowości, których nie ma list1.Odległość geograficzna/geoprzestrzenna między 2 listami punktów/rzędów (współrzędnych)

Chcę również przybliżoną lokalizację dla każdego punktu na liście1. Więc chcę wziąć punkt w list1, spróbuj wyszukać najbliższy punkt w list2 i zabrać tę miejscowość. Powtarzam dla każdego punktu w list1. Potrzebna jest również odległość (w metrach) i indeks punktu (w list1), więc mogę utworzyć pewne reguły biznesowe wokół niego - zasadniczo są to 2 nowe parametry, które należy dodać do list1 (near_dist, indx).

Używam funkcji gdist, ale nie mogę tego zrobić, aby działała z wejściami ramki danych.

listy Przykład wejściowe:

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

Odpowiedz

37

Aby obliczyć odległość geograficzną pomiędzy dwoma punktami o współrzędnych szerokość/długość geograficzna, można zastosować kilka formuła tych. Opakowanie geosphere ma do obliczania odległości odległość distCosine, ,. Spośród nich, distVincentyEllipsoid jest uważany za najbardziej dokładny, ale jest bardziej intensywny obliczeniowo niż pozostałe.

Za pomocą jednej z tych funkcji można utworzyć matrycę odległości. Na podstawie tej macierzy można następnie przypisać locality nazwy na podstawie najkrótszej odległości z which.min i odpowiedniej odległości z min (patrz na tej ostatniej części odpowiedzi) jak poniżej:

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

to daje:

> 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 

Inną możliwością jest przypisanie locality na podstawie średnich długości i szerokości geograficznej wartościami locality sw 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)]) 

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

to daje:

> 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 

Jak widać, prowadzi to w większości (7 z 10) okazjach do innego przypisanego locality.


Możesz dodać dystans:

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

lub innego podejścia z max.col (co jest wysoce prawdopodobne szybciej):

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

wynik:

> 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