首页 文章

使用dplyr时,使用rle按运行分组

提问于
浏览
12

在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'

为了完整性,我可以使用 cumsumheadtail 来重新实现 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

是什么导致我的基于_1825158的分组代码在 dplyr 中失败,是否有任何解决方案使我能够在按运行ID分组时继续使用 rle

2 回答

  • 8

    一个选项似乎是使用 {} ,如:

    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.frametbl_df 输入时会出现此问题,但使用 tbl_dtdata.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 .

  • 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 会抛出错误 .

相关问题