R中替代嵌套for循环实现分组连续FALSE计数的方案
R中高效实现分组数据集的连续FALSE统计转换
示例原始数据
先构造一份符合需求的示例数据,方便验证转换逻辑:
library(dplyr) library(purrr) df <- tibble( group = rep(c("A", "B"), each = 5), id = 1:10, flag = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE) )
核心转换代码
这里用dplyr做分组,purrr::reduce实现无嵌套循环的高效计算,完全符合规则要求:
df_transformed <- df %>% group_by(group) %>% mutate( new_col = reduce( rev(tail(flag, -1)), ~ if (.y) 0 else .x + 1, .init = 0 ) %>% rev() %>% c(., 0) ) %>% ungroup()
逻辑解释
- 分组处理:
group_by(group)确保每个分组独立计算,互不干扰 - 取后续行序列:
tail(flag, -1)提取每个分组中当前行的下一行到最后一行的flag值 - 反向累计计算:
- 反转序列后用
reduce从后往前遍历:如果当前flag是TRUE,直接重置为0;如果是FALSE,就在前一个结果基础上加1(统计连续数量) .init=0对应分组最后一行的new_col固定为0
- 反转序列后用
- 恢复顺序并补全:反转累计结果回到原行顺序,最后补0作为分组最后一行的数值
转换结果
运行代码后得到的目标数据集:
print(df_transformed) #> # A tibble: 10 × 4 #> group id flag new_col #> <chr> <int> <lgl> <dbl> #> 1 A 1 FALSE 1 #> 2 A 2 FALSE 0 #> 3 A 3 TRUE 2 #> 4 A 4 FALSE 1 #> 5 A 5 FALSE 0 #> 6 B 6 TRUE 3 #> 7 B 7 FALSE 2 #> 8 B 8 FALSE 1 #> 9 B 9 FALSE 0 #> 10 B 10 TRUE 0
可以看到完全符合规则:
- 分组首行根据下一行开始的连续
FALSE数填充(如A组首行下一行是FALSE,连续1个后遇TRUE,填1) - 下一行是
TRUE的行直接填0(如A组第二行) - 每个分组最后一行固定填0
大数据场景优化(data.table版本)
如果你的数据集很大,用data.table会更高效:
library(data.table) setDT(df) df_transformed <- df[, { tail_flag <- tail(flag, -1) new_col_part <- reduce(rev(tail_flag), ~if(.y) 0 else .x+1, .init=0) %>% rev() new_col <- c(new_col_part, 0) .(id, flag, new_col) }, by = group]
内容的提问来源于stack exchange,提问作者PS08
相关产品推荐
相关产品推荐

