Эффективное агрегирование своевременных данных в R с помощью dplyr - PullRequest
2 голосов
/ 03 августа 2020

У меня есть такие данные:

set.seed(2020)
df_time = data.frame(Time = as.Date(1:100), value = round(runif(100, min = 0, 100)))
head(df_time)
          Time value
1   1970-01-02    65
2   1970-01-03    39
3   1970-01-04    62
4   1970-01-05    48
5   1970-01-06    14
6   1970-01-07     7
7   1970-01-08    13
8   1970-01-09    39
9   1970-01-10     0
10  1970-01-11    62

И это:

df = data.frame(from= as.Date(c(3,6, 20)),to= as.Date(c(8,7, 24)),)
head(df)

Моя цель - изменить фрейм данных df таким образом, чтобы он складывал сумму значения между двумя заданными датами (исключая дату начала и включая дату до), т.е.

        from         to sum_value
1 1970-01-04 1970-01-09       121
2 1970-01-07 1970-01-08        13
3 1970-01-21 1970-01-25       204

В настоящий момент я делаю это с помощью al oop, но это занимает слишком много времени для суммы данные у меня есть. Кто-нибудь знает лучшее решение (например, с dplyr)?

1 Ответ

3 голосов
/ 03 августа 2020

Вы можете использовать rowwise() в этом случае, чтобы указать dplyr для оценки df строка за строкой:

df %>% 
  rowwise() %>% 
  mutate(sum_value = df_time %>% 
           filter(Time > from, Time <= to) %>% 
           pull(value) %>% 
           sum()) %>% 
  ungroup() # ungroup is used to restore default behaviour of dplyr

#> # A tibble: 3 x 3
#>   from       to         sum_value
#>   <date>     <date>         <dbl>
#> 1 1970-01-04 1970-01-09       121
#> 2 1970-01-07 1970-01-08        13
#> 3 1970-01-21 1970-01-25       204

Вот как я поступил бы, так как считаю код простым для понимания. Но, насколько я понимаю, в основном он все еще находится под капотом oop.

Другой и потенциально более быстрый подход может заключаться в использовании data.table. Я не так хорошо знаком с синтаксисом, поэтому может быть способ получше, но это работает:

library(data.table)
# convert to data.table
df_time <- setDT(df_time)
df <- setDT(df)

# duplicate Time column since foverlaps needs two of them
df_time <- df_time[, Time2 := Time]
# Since from day should not be included
df <- df[, from := from + 1]
  
setkey(df, from, to)
res <- foverlaps(df_time, df, by.x = c("Time", "Time2"), by.y = c("from", "to"), type = "within")
res <- res[, .(value = sum(value)), keyby = .(from, to)]
res[, from := from - 1]
#>          from         to value
#> 1:       <NA>       <NA>  4622
#> 2: 1970-01-04 1970-01-09   121
#> 3: 1970-01-07 1970-01-08    13
#> 4: 1970-01-21 1970-01-25   204
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...