бързи, правилни изчисления на разстоянието

Имам голяма рамка от данни (> 8 милиона реда) с наблюдения на хора и различни сайтове. Интересувам се да разгледам близостта на тези сайтове до няколко ключови места (1 местоположение през 2014 г. и 2 местоположения през 2015 г.).

За да минимизирам броя на изчисленията (и да ускоря нещата), използвах dplyr, за да свия всички известни местоположения само до един представителен сайт за всяка година и след това се опитах да използвам функцията distGeo, за да изчисля разстоянието, когато годината съвпада .

dist <- df %>% 
  mutate(year = year(ts)) %>% #ts is the time stamp for each observation
  select(site, lat, lon, year) %>% 
  group_by(site, lat, lon, year) %>% 
  summarise(n=n()) %>% #if I stop after summarise, the data frame has been reduced to 93 observations
  mutate(dist1 = ifelse(year == "2014",
                        distGeo(c(-64.343043, 45.897932), #coordinates for key location in 2014
                                df[,c("lon", "lat")])/1000, 
                         NA_real_)) #I have a similar lines for the two key locations in 2015

Самото изпълнение на тази част отнема ~30 минути, а резултатът е разстояние от 740,1656 км за всеки обект от 2014 г. Как мога да поправя този код, за да осигуря правилното разстояние и в идеалния случай да ускоря изчисленията?

РЕДАКТИРАНЕ:

Както е предложено по-долу, ето решението:

dist <- df %>% 
  mutate(year = year(ts)) %>%
  select(site, lat, lon, year) %>% 
  group_by(site, lat, lon, year) %>% 
  summarise(n=n()) %>% 
  mutate(dist1 = ifelse(year == "2014",
                     pmap_dbl(list(lon, lat),
                              ~distVincentyEllipsoid(c(-64.343043, 45.897932), 
                                                     c(.x, .y))/1000), 
                     NA_real_)

person tnt    schedule 25.01.2019    source източник


Отговори (1)


Можете да използвате purrr::pmap, за да направите това доста бързо (тъй като distGeo не е векторизирано)...

library(tidyverse) #for dplyr and purrr
library(geosphere) #for distGeo

df <- data.frame(lat = 90*runif(100), lon = 90*runif(100)) #dummy data

dist <- df %>% 
  mutate(dist1 = pmap_dbl(list(lon, lat),     #pmap_dbl ensures output is vector of numbers
                          ~distGeo(c(-64.343043, 45.897932), 
                                   c(.x, .y)) / 1000))

Ще трябва да промените това, за да включите годината и други променливи, които съм пренебрегнал.

Проблемът с вашия код беше използването на термина df[...] вътре в конвейер dplyr, който започва с df. Най-добре е просто да работите с голи имена на променливи, както по-горе.

person Andrew Gustar    schedule 25.01.2019
comment
Благодаря @Andrew Gustar. Можете ли да обясните малко по-подробно какво имате предвид под distGeo не е векторизирано? Правил съм нещо подобно в миналото и не съм имал същия проблем. - person tnt; 25.01.2019
comment
@tnt Първите два аргумента на distGeo са 2-вектори (long, lat) (или, мисля, n*2 матрици), така че не можете просто да ги замените с вектори и да очаквате функцията да произведе векторен изход, както можете с много R функции. Вместо това имате нужда от нещо като pmap или mapply, за да итерирате през двата вектора за ширина и дължина едновременно. - person Andrew Gustar; 26.01.2019