使用 dplyr 时使用 rle 按运行分组
Use rle to group by runs when using dplyr
在 R 中,我想在根据变量 x
的 运行 分组后总结我的数据(也就是每组数据对应于连续的数据子集x
值相同)。例如,考虑以下数据框,我想计算 x
的每个 运行 中的平均 y
值:
(dat <- data.frame(x=c(1, 1, 1, 2, 2, 1, 2), y=1:7))
# x y
# 1 1 1
# 2 1 2
# 3 1 3
# 4 2 4
# 5 2 5
# 6 1 6
# 7 2 7
在这个例子中,x
变量有 运行 个长度为 3,然后是 2,然后是 1,最后是 1,在这四个中取值 1、2、1 和 2 运行秒。 y
在这些组中的对应均值是 2、4.5、6 和 7。
使用 tapply
在基数 R 中很容易执行此分组操作,将 dat$y
作为数据传递,使用 rle
从中计算 运行 数字dat$x
,并传递所需的汇总函数:
tapply(dat$y, with(rle(dat$x), rep(seq_along(lengths), lengths)), mean)
# 1 2 3 4
# 2.0 4.5 6.0 7.0
我想我可以直接将这个逻辑转移到 dplyr,但我的尝试到目前为止都以错误告终:
library(dplyr)
# First attempt
dat %>%
group_by(with(rle(x), rep(seq_along(lengths), lengths))) %>%
summarize(mean(y))
# Error: cannot coerce type 'closure' to vector of type 'integer'
# Attempt 2 -- maybe "with" is the problem?
dat %>%
group_by(rep(seq_along(rle(x)$lengths), rle(x)$lengths)) %>%
summarize(mean(y))
# Error: invalid subscript type 'closure'
为了完整起见,我可以使用 cumsum
、head
和 tail
自己重新实现 rle
运行 id 来解决这个问题,但是它使分组代码更难阅读并且需要重新发明轮子:
dat %>%
group_by(run=cumsum(c(1, head(x, -1) != tail(x, -1)))) %>%
summarize(mean(y))
# run mean(y)
# (dbl) (dbl)
# 1 1 2.0
# 2 2 4.5
# 3 3 6.0
# 4 4 7.0
是什么导致我的基于 rle
的分组代码在 dplyr
中失败,有什么解决方案可以让我在按 [=43= 分组时继续使用 rle
] id?
如果您显式创建分组变量 g
它或多或少会起作用:
> dat %>% transform(g=with(rle(dat$x),{ rep(seq_along(lengths), lengths)}))%>%
group_by(g) %>% summarize(mean(y))
Source: local data frame [4 x 2]
g mean(y)
(int) (dbl)
1 1 2.0
2 2 4.5
3 3 6.0
4 4 7.0
我在这里使用 transform
因为 mutate
会抛出错误。
一个选项似乎是使用 {}
,如:
dat %>%
group_by(yy = {yy = rle(x); rep(seq_along(yy$lengths), yy$lengths)}) %>%
summarize(mean(y))
#Source: local data frame [4 x 2]
#
# yy mean(y)
# (int) (dbl)
#1 1 2.0
#2 2 4.5
#3 3 6.0
#4 4 7.0
如果未来的 dplyr 版本也有等同于 data.table 的 rleid
功能就好了。
我注意到使用 data.frame
或 tbl_df
输入时会出现此问题,但在使用 tbl_dt
或 data.table
输入时不会:
dat %>%
tbl_df %>%
group_by(yy = with(rle(x), rep(seq_along(lengths), lengths))) %>%
summarize(mean(y))
Error: cannot coerce type 'closure' to vector of type 'integer'
dat %>%
tbl_dt %>%
group_by(yy = with(rle(x), rep(seq_along(lengths), lengths))) %>%
summarize(mean(y))
Source: local data table [4 x 2]
yy mean(y)
(int) (dbl)
1 1 2.0
2 2 4.5
3 3 6.0
4 4 7.0
我在 dplyr 的 github 页面上将其报告为 issue。
在 R 中,我想在根据变量 x
的 运行 分组后总结我的数据(也就是每组数据对应于连续的数据子集x
值相同)。例如,考虑以下数据框,我想计算 x
的每个 运行 中的平均 y
值:
(dat <- data.frame(x=c(1, 1, 1, 2, 2, 1, 2), y=1:7))
# x y
# 1 1 1
# 2 1 2
# 3 1 3
# 4 2 4
# 5 2 5
# 6 1 6
# 7 2 7
在这个例子中,x
变量有 运行 个长度为 3,然后是 2,然后是 1,最后是 1,在这四个中取值 1、2、1 和 2 运行秒。 y
在这些组中的对应均值是 2、4.5、6 和 7。
使用 tapply
在基数 R 中很容易执行此分组操作,将 dat$y
作为数据传递,使用 rle
从中计算 运行 数字dat$x
,并传递所需的汇总函数:
tapply(dat$y, with(rle(dat$x), rep(seq_along(lengths), lengths)), mean)
# 1 2 3 4
# 2.0 4.5 6.0 7.0
我想我可以直接将这个逻辑转移到 dplyr,但我的尝试到目前为止都以错误告终:
library(dplyr)
# First attempt
dat %>%
group_by(with(rle(x), rep(seq_along(lengths), lengths))) %>%
summarize(mean(y))
# Error: cannot coerce type 'closure' to vector of type 'integer'
# Attempt 2 -- maybe "with" is the problem?
dat %>%
group_by(rep(seq_along(rle(x)$lengths), rle(x)$lengths)) %>%
summarize(mean(y))
# Error: invalid subscript type 'closure'
为了完整起见,我可以使用 cumsum
、head
和 tail
自己重新实现 rle
运行 id 来解决这个问题,但是它使分组代码更难阅读并且需要重新发明轮子:
dat %>%
group_by(run=cumsum(c(1, head(x, -1) != tail(x, -1)))) %>%
summarize(mean(y))
# run mean(y)
# (dbl) (dbl)
# 1 1 2.0
# 2 2 4.5
# 3 3 6.0
# 4 4 7.0
是什么导致我的基于 rle
的分组代码在 dplyr
中失败,有什么解决方案可以让我在按 [=43= 分组时继续使用 rle
] id?
如果您显式创建分组变量 g
它或多或少会起作用:
> dat %>% transform(g=with(rle(dat$x),{ rep(seq_along(lengths), lengths)}))%>%
group_by(g) %>% summarize(mean(y))
Source: local data frame [4 x 2]
g mean(y)
(int) (dbl)
1 1 2.0
2 2 4.5
3 3 6.0
4 4 7.0
我在这里使用 transform
因为 mutate
会抛出错误。
一个选项似乎是使用 {}
,如:
dat %>%
group_by(yy = {yy = rle(x); rep(seq_along(yy$lengths), yy$lengths)}) %>%
summarize(mean(y))
#Source: local data frame [4 x 2]
#
# yy mean(y)
# (int) (dbl)
#1 1 2.0
#2 2 4.5
#3 3 6.0
#4 4 7.0
如果未来的 dplyr 版本也有等同于 data.table 的 rleid
功能就好了。
我注意到使用 data.frame
或 tbl_df
输入时会出现此问题,但在使用 tbl_dt
或 data.table
输入时不会:
dat %>%
tbl_df %>%
group_by(yy = with(rle(x), rep(seq_along(lengths), lengths))) %>%
summarize(mean(y))
Error: cannot coerce type 'closure' to vector of type 'integer'
dat %>%
tbl_dt %>%
group_by(yy = with(rle(x), rep(seq_along(lengths), lengths))) %>%
summarize(mean(y))
Source: local data table [4 x 2]
yy mean(y)
(int) (dbl)
1 1 2.0
2 2 4.5
3 3 6.0
4 4 7.0
我在 dplyr 的 github 页面上将其报告为 issue。