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
之外还有很多简单的解决方案,使用循环等等。
但我会对 tidyverse
或 data.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
假设我有一个 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
之外还有很多简单的解决方案,使用循环等等。
但我会对 tidyverse
或 data.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