2016-12-01 7 views
2

나는 여러 가지 해답을 이미 살펴 봤지만 문제에 적용하지 못했습니다. 참조 :별도의 df에서 위치 간 거리를 계산하는 방법 R

Calculating the distance between points in different data frames

Calculating number of points within a certain radius

find locations within certain lat/lon distance in r

find number of points within a radius in R using lon and lat coordinates

Identify points within specified distance in R

내가 DF locstop 있습니다. 각 stop에 대해 loc까지 거리를 찾고 싶습니다.

내 위치

loc <- data.frame(station = c('Baker Street','Bank'), 
        lat = c(51.522236,51.5134047), 
        lng = c(-0.157080, -0.08905843), 
        postcode = c('NW1','EC3V') 
       ) 

내 내가 이런 걸 원하는 최종 결과

stop <- data.frame(station = c('Angel','Barbican','Barons Court','Bayswater'), 
        lat = c(51.53253,51.520865,51.490281,51.51224), 
        lng = c(-0.10579,-0.097758,-0.214340,-0.187569), 
        postcode = c('EC1V','EC1A', 'W14', 'W2')) 

를 중지 :

df <- data.frame(loc = c('Baker Street','Bank','Baker Street','Bank','Baker Street','Bank','Baker Street','Bank'), 
       stop = c('Angel','Barbican','Barons Court','Bayswater','Angel','Barbican','Barons Court','Bayswater'), 
       dist = c('x','x','x','x','x','x','x','x'), 
       lat = c(51.53253,51.520865,51.490281,51.51224,51.53253,51.520865,51.490281,51.51224), 
       lng = c(-0.10579,-0.097758,-0.214340,-0.187569,-0.10579,-0.097758,-0.214340,-0.187569), 
       postcode = c('EC1V','EC1A', 'W14', 'W2','EC1V','EC1A', 'W14', 'W2') 
       ) 

내 데이터 세트가 상대적으로 큰을 내가 찾고 있어요 이 문제를 해결하는 효율적인 방법입니다.

달성 방법에 대한 아이디어가 있으십니까?

+0

질문을 올바르게 읽지는 못했지만 loc 데이터 프레임의 각 지점에서 중지 데이터 프레임의 각 지점 사이의 거리를 찾으려고합니까? – Awhstin

+0

@Awhstin 예 ... 정확하게 'stop'에서 'loc'까지의 각 거리 – Davis

+1

부수적으로, 저는 [어제 질문에 답변했습니다] (http://stackoverflow.com/a/40898595/496488) 'circle'을'circle'으로,'stop'을'dat'으로 대체하고 각 데이터 프레임에서 유지하고자하는 열을 계속 전달할 경우 여기에서 작동합니다. (질문은 중복되지 않지만 답변은 비슷합니다.) – eipi10

답변

4

이렇게하면 expand.gridmerge 일부 창의적인 변수 이름 바꾸기가 사용됩니다. 작은 사람이긴하지만 작업이 벡터화되기 때문에 꽤 효율적입니다.

library(dplyr) 
df <- expand.grid(station = loc$station, stop = stop$station) %>% 
    merge(loc, by = 'station') %>% 
    rename(loc = station, lat1 = lat, lng1 = lng, station = stop) %>% 
    select(-postcode) %>% 
    merge(stop, by = 'station') %>% 
    rename(stop = station, lat2 = lat, lng2 = lng) 
#   stop   loc  lat1  lng1  lat2  lng2 postcode 
# 1  Angel Baker Street 51.52224 -0.15708000 51.53253 -0.105790  EC1V 
# 2  Angel   Bank 51.51340 -0.08905843 51.53253 -0.105790  EC1V 
# 3  Barbican Baker Street 51.52224 -0.15708000 51.52087 -0.097758  EC1A 
# 4  Barbican   Bank 51.51340 -0.08905843 51.52087 -0.097758  EC1A 
# 5 Barons Court Baker Street 51.52224 -0.15708000 51.49028 -0.214340  W14 
# 6 Barons Court   Bank 51.51340 -0.08905843 51.49028 -0.214340  W14 
# 7 Bayswater Baker Street 51.52224 -0.15708000 51.51224 -0.187569  W2 
# 8 Bayswater   Bank 51.51340 -0.08905843 51.51224 -0.187569  W2 

우리는 다음 Haversine formula를 사용하여 거리를 계산하기 위해 (야곱에서 영감) geosphere::distHaversine()를 사용할 수 있습니다.

df$dist_meters <- geosphere::distHaversine(select(df, lng1, lat1), 
              select(df, lng2, lat2)) 
df %>% 
    select(stop, loc, dist_meters) 
#   stop   loc dist_meters 
# 1  Angel Baker Street 3732.422 
# 2  Angel   Bank 2423.989 
# 3  Barbican Baker Street 4111.786 
# 4  Barbican   Bank 1026.091 
# 5 Barons Court Baker Street 5328.649 
# 6 Barons Court   Bank 9054.998 
# 7 Bayswater Baker Street 2387.231 
# 8 Bayswater   Bank 6825.897 

그리고 경우에

는 하버 사인 공식은 호기심 작동하는 당신의 방법

latrad1 <- df$lat1 * pi/180 
latrad2 <- df$lat2 * pi/180 
dlat <- df$dlat * pi/180 
dlng <- df$dlng * pi/180 
a <- sin(dlat/2)^2 + sin(dlng/2)^2 * cos(latrad1) * cos(latrad2) 
dist_rad <- 2 * atan2(sqrt(a), sqrt(1-a)) 
df %>% 
    mutate(dist_meters_byhand = dist_rad * 6378137) %>% 
    select(stop, loc, dist_meters_geosphere = dist_meters, dist_meters_byhand) 
#   stop   loc dist_meters_geosphere dist_meters_byhand 
# 1  Angel Baker Street    3732.422   3732.422 
# 2  Angel   Bank    2423.989   2423.989 
# 3  Barbican Baker Street    4111.786   4111.786 
# 4  Barbican   Bank    1026.091   1026.091 
# 5 Barons Court Baker Street    5328.649   5328.649 
# 6 Barons Court   Bank    9054.998   9054.998 
# 7 Bayswater Baker Street    2387.231   2387.231 
# 8 Bayswater   Bank    6825.897   6825.897 
+0

답변 해 주셔서 감사합니다. 매우 도움이됩니다. 서로 가깝게 간주되는 것은 무엇입니까? 동일한 국가 (예 : 영국) 내의 데이터 요소에 사용할 수 있나요, 아니면 거리에 대해 구형 좌표가 필요합니까? 또한 귀하의 답변에서 측정 된 거리는 어느 단위입니까? – Davis

+1

필자는 Jacob이 제안한대로 geosphere 패키지를 사용하여 결과를 미터로 변경했습니다. 도움을 주신 덕분에 –

0

다른 방법 벤의 @ 있지만 여기만큼 똑똑 (또는 아마 빨리) 안 :

library(geosphere) 

master_df <- data.frame() 

for (i in 1:nrow(loc)){ 
    this_loc <- loc[i, 1] 
    temp_df <- cbind(stop, 
        data.frame(loc = this_loc, 
        dist = distm(as.matrix(stop[, 2:3]), c(loc[i, 2], loc[i, 3])))) 
    master_df <- rbind(master_df, temp_df) 
} 

geosphere 패키지는 기본적으로 haversine을 사용하는데 정확도가 필요한 경우 유용 할 수 있습니다.

+0

. 나는 당신의 접근 방식을 시도 할 때 고유 한 거리 즉 dist를 얻지 못한다는 것을 알아 챘다. '천사'와 '베이커 거리'는 dist와 동일합니다. '엔젤'을'은행'으로? – Davis

+0

참! 사소한 멍청이가 고쳐졌습니다 ... – Jacob