用 dplyr 和 rle 总结连续失败

Summarize consecutive failures with dplyr and rle

我正在尝试构建一个客户流失模型,其中包含每个客户的最大连续用户体验失败次数和遇到的问题。这是我的简化数据和所需的输出:

library(dplyr)
df <- data.frame(customerId = c(1,2,2,3,3,3), date = c('2015-01-01','2015-02-01','2015-02-02', '2015-03-01','2015-03-02','2015-03-03'),isFailure = c(0,0,1,0,1,1))
> df
  customerId       date isFailure
1          1 2015-01-01         0
2          2 2015-02-01         0
3          2 2015-02-02         1
4          3 2015-03-01         0
5          3 2015-03-02         1
6          3 2015-03-03         1

期望的结果:

> desired.df
  customerId maxConsecutiveFailures
1          1                      0
2          2                      1
3          3                      2

我有点不知所措,搜索其他 rle 问题对我没有帮助 - 这就是我 "expecting" 类似的解决方案:

df %>% 
  group_by(customerId) %>%
  summarise(maxConsecutiveFailures = 
    max(rle(isFailure[isFailure == 1])$lengths))

我们按 'customerId' 分组并使用 do 在 'isFailure' 列上执行 rle。为 values (lengths[values]) 提取 'TRUE' 的 lengths,并创建具有 if/else 条件的 'Max' 列到 return 0 对于那些没有任何 1 值的人。

 df %>%
    group_by(customerId) %>%
    do({tmp <- with(rle(.$isFailure==1), lengths[values])
     data.frame(customerId= .$customerId, Max=if(length(tmp)==0) 0 
                    else max(tmp)) }) %>% 
     slice(1L)
#   customerId Max
#1          1   0
#2          2   1
#3          3   2

这是我的尝试,仅使用标准 dplyr 函数:

df %>% 
  # grouping key(s):
  group_by(customerId) %>%
  # check if there is any value change
  # if yes, a new sequence id is generated through cumsum
  mutate(last_one = lag(isFailure, 1, default = 100), 
         not_eq = last_one != isFailure, 
         seq = cumsum(not_eq)) %>% 
  # the following is just to find the largest sequence
  count(customerId, isFailure, seq) %>% 
  group_by(customerId, isFailure) %>% 
  summarise(max_consecutive_event = max(n))

输出:

# A tibble: 5 x 3
# Groups:   customerId [3]
  customerId isFailure max_consecutive_event
       <dbl>     <dbl>                 <int>
1          1         0                     1
2          2         0                     1
3          2         1                     1
4          3         0                     1
5          3         1                     2

isFailure 值的最终过滤器将产生想要的结果(不过需要添加回 0 失败计数客户)。

该脚本可以采用 isFailure 列的任何值,并计算具有相同值的最大连续天数。