さまざまな場所の緯度/経度を含む2つのリスト(list1
、list2
)があります。 1つのリスト(list2
)には、list1
にはない地域名があります。
List1のすべてのポイントについてもおおよその局所性が必要です。だから、list1
でポイントを取り、list2
で最も近いポイントを探して、その場所を取りたいと思います。 list1
のすべてのポイントについて繰り返します。また、距離(メートル)とポイントのインデックス(list1
)が必要なので、ビジネスルールを構築できます。基本的に、これらはlist1
( near_dist
、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"))
緯度/経度座標を使用して2つのポイント間の地理的距離を計算するには、いくつかの式を使用できます。パッケージgeosphere
には、距離を計算するためのdistCosine
、distHaversine
、distVincentySphere
、およびdistVincentyEllipsoid
があります。これらのうち、distVincentyEllipsoid
は最も正確なものと見なされますが、他のものよりも計算量が多くなります。
これらの関数のいずれかを使用すると、距離行列を作成できます。その行列に基づいて、which.min
を使用した最短距離とlocality
を使用した対応する距離に基づいて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
別の可能性は、list2
のlocality
sの平均経度と緯度の値に基づいてlocality
を割り当てることです。
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
ご覧のとおり、ほとんどの場合(10のうち7)、別の割り当てられた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
Mark Needhamのブログ でデータフレームをたどってこの機能を実行する必要がある場合に、この方法を簡単にするこのソリューションに対するMartin Harringaの功績
library(dplyr)
df %>%
rowwise() %>%
mutate(newcolumn_distance = distHaversine(c(df$long1, df$lat1),
c(df$long2, df$lat2)))
実世界のデータセットからの大規模なサンプルでdistmとdistHaversineの2つの関数を別々に使用してテストしましたが、distHaversineはdistm関数よりもはるかに高速に出力されるようです。 2つは2つの形式で同じ機能にすぎないと思っていたので驚きました。