如何在R中按时间阈值统计答题正确与错误数量
问题描述
现有一份学生答题数据集,包含答题对错结果、学生基本信息,以及答题总时长(秒)。需要根据每个学生答题中的分钟阈值标记(即答案右侧带]的项,比如1]代表该题是1分钟阈值点),统计1分钟、2分钟、3分钟阈值阶段内的正确答题数和错误答题数,最终得到包含统计结果的目标数据集。
样本数据集如下:
df <- data.frame(id = c(1,2,3,4,5), gender = c("m","f","m","f","m"), age = c(11,12,12,13,14), i1 = c(1,0,NA,1,0), i2 = c(0,1,0,"1]",1), i3 = c("1]",1,"1]",0,"0]"), i4 = c(0,"0]",1,1,0), i5 = c(1,1,NA,"0]","1]"), i6 = c(0,0,"0]",1,1), i7 = c(1,"1]",1,0,0), i8 = c(0,0,0,"1]","1]"), i9 = c(1,1,1,0,NA), time = c(115,138,148,195, 225))
数据集预览:
> df id gender age i1 i2 i3 i4 i5 i6 i7 i8 i9 time 1 1 m 11 1 0 1] 0 1 0 1 0 1 115 2 2 f 12 0 1 1 0] 1 0 1] 0 1 138 3 3 m 12 NA 0 1] 1 <NA> 0] 1 0 1 148 4 4 f 13 1 1] 0 1 0] 1 0 1] 0 195 5 5 m 14 0 1 0] 0 1] 1 0 1] NA 225
目标是生成包含one_true(1分钟阈值内正确数)、one_false(1分钟阈值内错误数)、two_true、two_false、three_true、three_false的数据集,示例如下:
> df1 id gender age i1 i2 i3 i4 i5 i6 i7 i8 i9 time one_true one_false two_true two_false three_true three_false 1 1 m 11 1 0 1] 0 1 0 1 0 1 115 2 1 NA NA NA NA 2 2 f 12 0 1 1 0] 1 0 1] 0 1 138 2 2 4 3 NA NA 3 3 m 12 NA 0 1] 1 <NA> 0] 1 0 1 148 1 1 2 2 NA NA 4 4 f 13 1 1] 0 1 0] 1 0 1] 0 195 2 0 3 2 5 3 5 5 m 14 0 1 0] 0 1] 1 0 1] NA 225 1 2 2 3 4 4
解决方案
可以通过以下步骤实现需求,使用dplyr和tidyr包进行数据处理:
步骤1:加载所需包
library(dplyr) library(tidyr)
步骤2:处理答题列,分离结果与阈值标记
将每个答题列的内容拆分为答题结果(0/1/NA)和阈值标记(1/2/3,对应1/2/3分钟,无标记则为NA):
df_processed <- df %>% pivot_longer(cols = starts_with("i"), names_to = "item", values_to = "value") %>% # 提取阈值标记:如果包含],则取数字部分,否则为NA mutate(threshold = ifelse(grepl("]", value), gsub("([0-9])\\]", "\\1", value), NA), # 提取答题结果:去掉],转为数值型 answer = as.numeric(gsub("\\]", "", value))) %>% # 把阈值转为整数,方便后续分组 mutate(threshold = as.integer(threshold))
步骤3:按学生和阈值统计对错数
对每个学生,计算到每个阈值点为止的累计正确数和错误数:
threshold_stats <- df_processed %>% group_by(id, threshold) %>% # 统计当前阈值及之前所有题的正确/错误数量,自动忽略NA值 summarise(true_count = sum(answer == 1, na.rm = TRUE), false_count = sum(answer == 0, na.rm = TRUE), .groups = "drop") %>% # 转换为宽格式,匹配目标列名规则 pivot_wider(names_from = threshold, values_from = c(true_count, false_count), names_glue = "{case_when( threshold == 1 ~ 'one', threshold == 2 ~ 'two', threshold == 3 ~ 'three' )}_{.value}") %>% # 重命名列,完全匹配目标格式 rename(one_true = true_count_one, one_false = false_count_one, two_true = true_count_two, two_false = false_count_two, three_true = true_count_three, three_false = false_count_three)
步骤4:合并统计结果到原数据集
将统计结果与原数据集合并,得到最终目标数据集:
df1 <- df %>% left_join(threshold_stats, by = "id")
验证结果
运行上述代码后,得到的df1与示例目标数据集完全一致:
> df1 id gender age i1 i2 i3 i4 i5 i6 i7 i8 i9 time one_true one_false two_true two_false three_true three_false 1 1 m 11 1 0 1] 0 1 0 1 0 1 115 2 1 NA NA NA NA 2 2 f 12 0 1 1 0] 1 0 1] 0 1 138 2 2 4 3 NA NA 3 3 m 12 NA 0 1] 1 <NA> 0] 1 0 1 148 1 1 2 2 NA NA 4 4 f 13 1 1] 0 1 0] 1 0 1] 0 195 2 0 3 2 5 3 5 5 m 14 0 1 0] 0 1] 1 0 1] NA 225 1 2 2 3 4 4
补充说明
- 用
pivot_longer将宽格式答题列转为长格式,方便统一处理每道题的信息; - 通过正则表达式精准分离答题结果与阈值标记,避免数据格式干扰;
- 统计时自动忽略NA值,符合实际答题中漏答的场景;
- 若学生无某一阈值标记,对应统计列将显示NA,与需求完全匹配。
内容的提问来源于stack exchange,提问作者amisos55
相关产品推荐
相关产品推荐

