tidyverse 中的累积聚合

Cumulative aggregates within tidyverse

假设我有一个 tibble(或 data.table),它由两列组成:

a <- tibble(id = rep(c("A", "B"), each = 6), val = c(1, 0, 0, 1 ,0,1,0,0,0,1,1,1))

此外,我有一个名为 myfun 的函数,它接受任意长度的数字向量作为输入,returns 接受单个数字。例如,您可以将 myfun 视为标准偏差。

现在我想为我的 tibble 创建第三列(称为结果),其中包含应用于 val 累积和分组的 myfun 的输出关于 id。 例如,结果的第一个条目应包含 mfun(val[1])。 第二个条目应包含 myfun(val[1:2]),依此类推。 我想实现一个累积版本的 myfun。

当然,在 tidyverse 之外还有很多简单的解决方案,使用循环等等。 但我会对 tidyversedata.table 框架内的解决方案感兴趣。

感谢任何帮助。

你可以这样做:

library(tidyverse)

a %>% 
  group_by(id) %>% 
  mutate(y = map_dbl(seq_along(val),~sd(val[1:.x]))) %>%
  ungroup

# # A tibble: 12 x 3
#       id   val         y
#    <chr> <dbl>     <dbl>
#  1     A     1        NA
#  2     A     0 0.7071068
#  3     A     0 0.5773503
#  4     A     1 0.5773503
#  5     A     0 0.5477226
#  6     A     1 0.5477226
#  7     B     0        NA
#  8     B     0 0.0000000
#  9     B     0 0.0000000
# 10     B     1 0.5000000
# 11     B     1 0.5477226
# 12     B     1 0.5477226

说明

我们首先使用 tidyverse 链进行分组,然后我们使用 mutate,而不是 summarize,因为我们希望保留相同的未聚合行。

函数map_dbl在这里用于循环最终索引的向量。 seq_along(val) 将是 1:6 两个组在这里。

使用 map 系列的函数,我们可以使用 ~ 表示法,这将假定函数的第一个参数命名为 .x.

循环遍历这些索引,我们首先计算 sd(val[1:1])sd(val[1])NA,然后是 sd(val[1:2]) 等等...

map_dbl returns 设计了一个 doubles 的向量,它们被堆叠在 y 列中。

可以使用具有动态宽度 (vector containing width) 的 zoo::rollapplyr。要为每个组准备动态宽度,可以使用 1:n()seq(n())

让我们使用 OP 提供的数据将其应用于函数 sd :

library(dplyr)
library(zoo)

a %>% group_by(id) %>%
  mutate(y = rollapplyr(val, 1:n(), sd ))

#   # Groups: id [2]
#   id      val      y
#   <chr> <dbl>  <dbl>
#  1 A      1.00 NA    
#  2 A      0     0.707
#  3 A      0     0.577
#  4 A      1.00  0.577
#  5 A      0     0.548
#  6 A      1.00  0.548
#  7 B      0    NA    
#  8 B      0     0    
#  9 B      0     0    
# 10 B      1.00  0.500
# 11 B      1.00  0.548
# 12 B      1.00  0.548