рассчитать расстояние и время между точками вдоль пути движения животных - PullRequest
0 голосов
/ 04 января 2019

У меня есть большой набор данных (> 9 миллионов строк) времени и местоположения, когда отдельные животные были обнаружены на станциях. Я хотел бы рассчитать расстояние между каждой станцией вдоль пути каждого животного, когда оно путешествует между станциями, а также время, необходимое для перемещения между станциями. А затем я хотел бы суммировать общее расстояние и время по всем участкам пути.

Для каждого человека в этом наборе данных данные организованы с каждым разом, когда они были обнаружены в стационарных точках. Если человек находился в стационарной точке в течение длительного последовательного периода времени, то существует несколько записей (каждые ~ 30 с) для этого периода времени.

Я могу суммировать данные ниже, чтобы получить 1 строку за каждый раз, когда человек находился на станции (см. Ниже). Однако выходной сигнал не распознается, когда человек путешествует на одну и ту же станцию ​​более одного раза.

1007 * Е.Г. *

id <- c("A", "A", "A", "A", "A", "A", "A", "A", "B", "B")
site <- c("a", "a", "b", "a", "c", "c", "c", "d", "a", "b")
time <- seq(1:10)
lat <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2)
lon <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2)

df <- data.frame(id, site, time, lat, lon)

df %>% group_by(id, site, lat, lon) %>%
  summarize(timeStart = min(time), 
            timeEnd = max(time))

# A tibble: 6 x 6
# Groups:   id, site, lat [?]
  id    site    lat   lon timeStart timeEnd
  <fct> <fct> <dbl> <dbl>     <dbl>   <dbl>
1 A     a         1     1         1       4
2 A     b         2     2         3       3
3 A     c         3     3         5       7
4 A     d         4     4         8       8
5 B     a         1     1         9       9
6 B     b         2     2        10      10

I подход, позволяющий сгруппировать данные таким образом, чтобы множественные посещения одной и той же станции (с промежуточными поездками на другие станции) распознавались как отдельный «этап» поездки.

Затем мне нужно вычислить расстояние по большому кругу между каждой станцией, а также разницу во времени между timeEnd (1-я станция) и timeStart (2-я станция).

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Во-первых, функция data.table rleid используется для создания группирующей переменной: для каждого отдельного пользователя каждое изменение сайта представляет новую группу. Внутри каждой группы рассчитайте желаемую статистику:

library(data.table)
library(geosphere)
setDT(df)
df2 <- df[ , .(id = id[1],
               site = site[1],
               lat = lat[1],
               lon = lon[1],
               first_time = min(time),
               last_time = max(time)),
           by = .(id_site = rleid(id, site))]

Затем для каждого отдельного человека вычисляется последовательное расстояние большого круга между последовательными участками с помощью geosphere::distHaversine. Чтобы избежать проблем, когда у людей есть только одна или две записи *, добавлены некоторые проверки:

df2[ , dist := if(.N == 1){
  0 } else if(.N == 2){
    c(0, distHaversine(c(lon[1], lat[1]), c(lon[2], lat[2])))
  } else c(0, distHaversine(as.matrix(.SD[ , .(lon, lat)]))), by = id]

#    id_site id site lat lon first_time last_time     dist
# 1:       1  A    a   1   1          1         2      0.0
# 2:       2  A    b   2   2          3         3 157401.6
# 3:       3  A    a   1   1          4         4 157401.6
# 4:       4  A    c   3   3          5         7 314755.2
# 5:       5  A    d   4   4          8         8 157281.8
# 6:       6  B    a   1   1          9         9      0.0
# 7:       7  B    b   2   2         10        10 157401.6
# 8:       8  C    a   1   1         11        11      0.0

Таким образом, для каждого человека расстояние рассчитывается только один раз для нового сайта . Это контрастирует с другим ответом, где вычисления расстояния выполняются между каждый временной шаг (кажется, многие из них).


* Попробуйте, например, distHaversine(cbind(1, 1)) (distGeo(cbind(1, 1))) или distHaversine(cbind(c(1, 1), c(1, 2))) (distGeo(cbind(c(1, 1), c(1, 2))))


Данные

Я добавил человека с одной записью в качестве контрольного примера.

id <- c("A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "C")
site <- c("a", "a", "b", "a", "c", "c", "c", "d", "a", "b", "a")
time <- seq(1:11)
lat <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2, 1)
lon <- c(1, 1, 2, 1, 3, 3, 3, 4, 1, 2, 1)

df <- data.frame(id, site, time, lat, lon)
0 голосов
/ 04 января 2019

Возможно, это не ваше полное решение, но это хорошее начало. Это позволит найти расстояние и разницу во времени между каждой строкой данных и установить значения NA, когда идентификатор изменяется между строками.

df <- data.frame(id, site, time, lat, lon)

library(geosphere)
library(dplyr)

#sort data by id and time
df<-df[order(df$id, df$time), ]
#find distance between each point in column
# Note longitude is the first column
df$distance<-c(NA, distGeo(df[,c("lon", "lat")]))
#find delta time between each row for each id
df<-df %>% group_by(id) %>% mutate(dtime=case_when(site != lag(site) ~ time-lag(time),
                                               TRUE ~ NA_integer_))
#remove distances where there was no delta time (row pairs with different ids)
df$distance[is.na(df$dtime)]<-NA

#id summary
df%>% summarize(disttraveled=sum(distance, na.rm=TRUE), totaltime=sum(dtime, na.rm=TRUE))
...