2015-07-28 3 views
24

У меня есть 2 списка (list1, list2) с широтой/долготами разных мест. Один список (list2) имеет названия местностей, которых нет у list1.Географическое/геопространственное расстояние между 2 списками точек lat/lon (координаты)

Я хочу приблизительную локальность для каждой точки в списке1. Поэтому я хочу взять точку в list1, попробуйте найти ближайшую точку в list2 и возьмите эту местность. Повторяю для каждой точки в list1. Он также хочет расстояние (в метрах) и индекс точки (в list1), поэтому я могу создать вокруг него некоторые бизнес-правила - по существу это два новых столбца, которые должны быть добавлены к list1 (, indx).

Я использую функцию gdist, но я не могу заставить ее работать с вводом данных.

Пример входных списки:

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

ответ

37

Чтобы вычислить географическое расстояние между двумя точками с координатами широты/долготы, можно использовать несколько формулы-х. В пакете geosphere есть distCosine, distHaversine, distVincentySphere и distVincentyEllipsoid для расчета расстояния. Из них distVincentyEllipsoid считается наиболее точным, но более вычислительно более интенсивным, чем другие.

С помощью одной из этих функций вы можете сделать матрицу расстояний. На основе этой матрицы можно затем присвоить locality имен на основе кратчайшего расстояния с which.min и соответствующим расстоянием с min (см для этой последней части ответа), как это:

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

это дает:

> 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 

Другая возможность состоит в том, чтобы назначить locality на основе средней долготы и широты значений locality с в 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)]) 

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

это дает:

> 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 

Как вы можете видеть, это приводит в большинстве (7 из 10) случаев на другой назначенный locality.


Вы можете добавить расстояние с:

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

или другой подход с max.col (что весьма вероятно, быстрее):

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

результат:

> 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