按学生分组重置连续通过考试次数计数器的R语言实现
按学生分组计算连续通过考试次数的解决方案
针对你用R语言data.table处理考试数据时,需要按学生分组统计连续通过次数(遇到失败重置为0,新学生自动重置)的需求,修改原代码如下:
方法一:基于分段分组的实现
利用data.table的分组特性,在每个学生的子集中处理连续通过计数:
# 按id分组计算consec变量 my_data[, consec := { # 生成连续段的分组ID:每次遇到失败(results=0)就开启新分组 group_id = c(0, cumsum(abs(diff(results == 0)))) # 对每个分段生成计数:失败段全为0,通过段从1递增 unlist(lapply(split(results, group_id), function(x) { if (x[1] == 0) rep(0, length(x)) else seq_along(x) })) }, by = id]
逻辑说明
by = id:强制每个学生的计算独立,新学生的计数自动从0开始重置group_id:通过diff(results == 0)检测结果切换的位置,用cumsum生成连续段的唯一标识,确保失败后开启新的计数段- 分段处理:失败开头的分段直接填充0,通过开头的分段生成从1开始的递增序列,实现连续通过计数
运行后你的示例数据会得到如下结果:
id results date_exam_taken exam_number consec 1: 1 0 2002-10-06 1 0 2: 1 1 2003-07-21 2 1 3: 1 1 2003-10-15 3 2 4: 1 0 2005-07-21 4 0 5: 1 1 2014-08-22 5 1 6: 1 1 2015-09-11 6 2
方法二:遍历累积的简洁实现
如果觉得分段分组的写法复杂,也可以用遍历累积的方式实现,逻辑更直观:
# 遍历每个学生的记录计算连续通过次数 my_data[, consec := { temp_vec = integer(.N) for (i in seq_len(.N)) { temp_vec[i] = if (results[i] == 0) { 0 } else { if (i == 1) 1 else temp_vec[i-1] + 1 } } temp_vec }, by = id]
逻辑说明
- 对每个学生的考试记录逐个遍历:
- 若当前考试失败(results=0),则
consec设为0 - 若当前考试通过,且是该学生第一次考试,则
consec设为1;否则在上一次的consec基础上加1
- 若当前考试失败(results=0),则
- 同样通过
by = id保证每个学生的计数独立重置
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

