使用dplyr编写条件更新分组计数器函数的问题求助
按ID分组的计数器更新问题
数据集
my_data = structure(list(id = c("A", "A", "A", "A", "A", "B", "B", "B", "B"), result = c("AAA", "BBB", "CCC", "AAA", "CCC", "DDD", "BBB", "BBB", "DDD")), class = "data.frame", row.names = c(NA, -9L))
需求规则
针对每个唯一ID,按以下逻辑更新计数器变量:
- 当
result为AAA时,计数器重置为0 - 当
result为BBB时,计数器 = 当前计数器 + 1 - 当
result为CCC时,计数器 = 当前计数器 + 2 - 当
result为DDD时,计数器 = 当前计数器 - 1
尝试的错误代码
library(dplyr) my_data %>% group_by(id) %>% mutate(counter = ifelse(result == "AAA", 0, ifelse(result == "BBB", 1, ifelse(result == "CCC", 2, ifelse(result == "DDD", -1, ifelse(result == 1, cumsum(result), 0))))))
错误输出结果
# A tibble: 9 x 3 # Groups: id [2] id result counter <chr> <chr> <dbl> 1 A AAA 0 2 A BBB 1 3 A CCC 2 4 A AAA 0 5 A CCC 2 6 B DDD -1 7 B BBB 1 8 B BBB 1 9 B DDD -1
预期输出
id result counter 1 A AAA 0 2 A BBB 1 3 A CCC 3 4 A AAA 0 5 A CCC 2 6 B DDD -1 7 B BBB 0 8 B BBB 1 9 B DDD 0
问题分析
你的代码只返回了单次操作的增量值,没有实现基于前一次计数器结果的累积计算,且尝试对字符型的result直接使用cumsum是无效的。要实现带重置的累积逻辑,需要先映射增量值,再按重置点分割分组后累加。
正确解法
方法1:dplyr分组累积
library(dplyr) my_data %>% group_by(id) %>% # 映射每个result对应的增量值 mutate(incr = case_match( result, "AAA" ~ 0, "BBB" ~ 1, "CCC" ~ 2, "DDD" ~ -1 ), # 生成重置分组:每次出现AAA就开启新分组 reset_group = cumsum(result == "AAA")) %>% # 按id和重置分组,计算累积和 group_by(id, reset_group, .add = TRUE) %>% mutate(counter = cumsum(incr)) %>% # 清理中间列 select(-incr, -reset_group) %>% ungroup()
方法2:purrr逐行计算
如果需要更灵活的逐行逻辑,用accumulate手动处理每一步的计数器更新:
library(dplyr) library(purrr) my_data %>% group_by(id) %>% mutate(counter = accumulate(result, .init = 0, function(prev, curr) { case_match( curr, "AAA" ~ 0, "BBB" ~ prev + 1, "CCC" ~ prev + 2, "DDD" ~ prev - 1 ) }) %>% tail(-1)) %>% # 移除初始的0值 ungroup()
以上两种方法均能得到符合预期的输出结果。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

