быстрый и правильный расчет расстояния

У меня есть большой фрейм данных (> 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
Спасибо @Эндрю Густар. Можете ли вы объяснить немного подробнее, что вы подразумеваете под distGeo не векторизованным? Я делал что-то подобное в прошлом, и у меня не было такой же проблемы. - person tnt; 25.01.2019
comment
@tnt Первые два аргумента distGeo являются 2-векторами (долгота, широта) (или, я думаю, матрицами n * 2), поэтому вы не можете просто заменить их векторами и ожидать, что функция выдаст векторный вывод, как вы можете со многими функциями R. Вместо этого вам нужно что-то вроде pmap или mapply для одновременного перебора двух векторов широты и долготы. - person Andrew Gustar; 26.01.2019