在R中按条件统计分组内前序无点击次数(遇点击重置计数)
按ID分组统计无点击次数并在点击时重置计数
给定数据集:
df <- structure(list(ID = c(1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L), clicks = c(0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L)), class = "data.frame", row.names = c(NA, -13L))
需求是按ID分组,统计每个ID下当前行及之前的连续无点击次数(遇到点击时重置计数,点击行的计数为0)。
你尝试的代码:
df %>% as_tibble() %>% mutate(click_reverse = ifelse(clicks==0, 1, 0)) %>% group_by(ID) %>% mutate(noclicks_count = ifelse(click_reverse==1, cumsum(click_reverse),0))
问题在于cumsum(click_reverse)是对整个ID组的累计,不会在点击后重置,所以ID=2中点击后的无点击次数会延续之前的累计值,不符合预期。
正确实现方法
我们需要先按ID和点击事件分割的子分组来计算,也就是在每个ID内,每当出现点击(clicks=1)时,就开启一个新的子分组,再在子分组内累计无点击次数。
代码如下:
library(dplyr) df %>% as_tibble() %>% mutate(click_reverse = ifelse(clicks == 0, 1, 0)) %>% group_by(ID) %>% # 生成子分组标识:每遇到一次点击,开启新的子分组 mutate(click_group = cumsum(clicks)) %>% group_by(ID, click_group) %>% # 在子分组内累计无点击次数,点击行强制设为0 mutate(noclicks_count = ifelse(clicks == 1, 0, cumsum(click_reverse))) %>% ungroup() %>% # 可选:移除中间变量click_group select(-click_group)
运行后得到的结果与你的理想输出完全一致:
# A tibble: 13 × 4 ID clicks click_reverse noclicks_count <int> <int> <dbl> <dbl> 1 1 0 1 1 2 1 0 1 2 3 1 1 0 0 4 2 0 1 1 5 2 1 0 0 6 2 0 1 1 7 2 0 1 2 8 3 0 1 1 9 3 0 1 2 10 3 0 1 3 11 4 1 0 0 12 4 0 1 1 13 4 0 1 2
逻辑说明
click_group = cumsum(clicks):在每个ID内,每遇到一次点击(clicks=1),累计值加1,以此把每个ID分割成"点击前的无点击段"、"点击后新的无点击段"等独立子分组。- 按
ID和click_group二级分组后,cumsum(click_reverse)只会在当前子分组内累计,实现了点击后的计数重置。 - 通过
ifelse(clicks == 1, 0, ...)确保点击行的计数固定为0。
内容的提问来源于stack exchange,提问作者tippy
相关产品推荐
相关产品推荐

