data.frame中一个变量的滚动总和,由另一个变量定义

时间:2020-08-17 08:32:39

标签: r dplyr rolling-computation

我正在尝试以累积方式汇总data.frame中的值。

我有这个:

df <- data.frame(
  a = rep(1:2, each = 5),
  b = 1:10,
  step_window = c(2,3,1,2,4, 1,2,3,2,1)
)

我正在尝试汇总b组中a的值。诀窍是,我想要b值的总和,该值与step_window给定的当前行之后的行数相对应。

这是我正在寻找的输出:

data.frame(
    a = rep(1:2, each = 5),
    step_window = c(2,3,1,2,4, 
                    1,2,3,2,1),
    b = 1:10,
    sum_b_step_window = c(3, 9, 3, 9, 5,
                          6, 15, 27, 19, 10)
  ) 

我尝试使用RcppRoll来执行此操作,但出现错误Expecting a single value

df %>% 
  group_by(a) %>% 
  mutate(sum_b_step_window = RcppRoll::roll_sum(x = b, n = step_window))

4 个答案:

答案 0 :(得分:2)

我不确定在任何滚动功能中是否都可能具有可变的窗口大小。这是使用map2_dbl的一种方法:

library(dplyr)
df %>% 
  group_by(a) %>% 
  mutate(sum_b_step_window = purrr::map2_dbl(row_number(), step_window, 
                             ~sum(b[.x:(.x + .y - 1)], na.rm = TRUE)))

#      a     b step_window sum_b_step_window
#   <int> <int>       <dbl>             <dbl>
# 1     1     1           2                 3
# 2     1     2           3                 9
# 3     1     3           1                 3
# 4     1     4           2                 9
# 5     1     5           4                 5
# 6     2     6           1                 6
# 7     2     7           2                15
# 8     2     8           3                27
# 9     2     9           2                19
#10     2    10           1                10

答案 1 :(得分:2)

1)滚动应用

Zoo中的

rollapply支持向量宽度。 partial=TRUE说,如果宽度超过了末尾,则仅使用数据中的值。 (另一种可能性是使用fill=NA代替,在这种情况下,如果没有足够的数据,它将用NA填充)。 align="left"指定每一步的当前值是求和范围的左端。

library(dplyr)
library(zoo)

df %>%
  group_by(a) %>%
  mutate(sum = rollapply(b, step_window, sum, partial = TRUE, align = "left")) %>%
  ungroup

2)SQL

这也可以在SQL中完成,方法是在指示的条件下将df与其自身连接起来,然后对条件匹配的所有行的每一行求和。

library(sqldf)

sqldf("select A.*, sum(B.b) as sum
  from df A 
  left join df B on B.rowid between A.rowid and A.rowid + A.step_window - 1
    and A.a = B.a
  group by A.rowid")

答案 2 :(得分:1)

这是软件包slider的解决方案。

library(dplyr)
library(slider)

df %>%
    group_by(a) %>% 
    mutate(sum_b_step_window = hop_vec(b, row_number(), step_window+row_number()-1, sum)) %>% 
    ungroup() 

在不同的窗口大小上都很灵活。

输出:

# A tibble: 10 x 4
       a     b step_window sum_b_step_window
   <int> <int>       <dbl>             <int>
 1     1     1           2                 3
 2     1     2           3                 9
 3     1     3           1                 3
 4     1     4           2                 9
 5     1     5           4                 5
 6     2     6           1                 6
 7     2     7           2                15
 8     2     8           3                27
 9     2     9           2                19
10     2    10           1                10

slider是几个月前的tidyverse软件包,专门用于滑动窗口功能。在这里查看更多信息:pagevignette

hopslider的引擎。通过这种解决方案,我们可以触发不同的.start.stop根据b组对a的值求和。

对于_vec,您要让hop返回一个向量:在这种情况下为双精度。

row_number()是一种dplyr函数,可让您返回每个组的行号,从而使您可以沿行滑动。

答案 3 :(得分:1)

data.table使用累积和的解决方案

setDT(df)
df[, sum_b_step_window := {
  cs <- c(0,cumsum(b))
  cs[pmin(.N+1, 1:.N+step_window)]-cs[pmax(1, (1:.N))]
},by = a]