在R中,我希望在根据变量x
的运行对数据进行分组后对其进行汇总(也就是说,每组数据对应于连续x
值的数据子集相同)。例如,请考虑以下数据框,我想在y
的每次运行中计算平均x
值:
(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
使用dat$y
作为数据,使用rle
计算dat$x
的运行编号,可以很容易地在基准R中执行此分组操作,并传递所需的汇总函数:
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'
为了完整起见,我可以使用rle
,cumsum
和head
重新实现tail
运行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
中失败的原因是什么,是否有任何解决方案可以让我在按运行ID分组时继续使用rle
?
答案 0 :(得分:9)
一个选项似乎是使用{}
,如:
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。
答案 1 :(得分:2)
如果明确创建分组变量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
会抛出错误。