You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于data.table统计学生考试科目数:处理双强度科目计数问题

解决data.table中考虑“双强度”修读规则的学生修读科目统计问题

我刚好处理过类似的场景,咱们一步步来搞定这个问题。首先得明确核心需求:原来的num_subjects是直接数非NA的列数,但双强度科目会用两个成绩列(比如Physics_1和Physics_2)来标识——这时候不管这两个列有没有成绩,只要属于同一门科目的双强度修读,都只能算1门,而不是2门。

先模拟一份测试数据

咱们先造个符合场景的data.table,方便后续演示:

library(data.table)
# 模拟数据:StudentID是学生ID,Math/English是普通科目,Physics/Biology是双强度科目(带_1/_2后缀)
dt <- data.table(
  StudentID = c(1, 2, 3),
  Math = c(85, NA, 90),
  Physics_1 = c(78, 82, NA),
  Physics_2 = c(81, 85, NA),
  English = c(92, 88, 79),
  Biology_1 = c(NA, 75, 80),
  Biology_2 = c(NA, 77, NA)
)

方法一:行级处理(适合小数据集)

这种方法直接在原表上操作,对每行数据按科目组统计:

# 第一步:提取科目组名称(去掉双强度科目的后缀,比如把Physics_1/Physics_2统一为Physics)
subject_groups <- gsub("_\\d+$", "", names(dt)[-1]) # 排除StudentID列,用正则去掉末尾的_1/_2

# 第二步:对每行计算正确的科目数
dt[, num_subjects_corrected := sapply(.SD, function(row) {
  # 把当前行的成绩按科目组分组
  grouped_scores <- split(row, subject_groups)
  # 统计每个组里是否至少有一个非NA成绩,然后求和
  sum(sapply(grouped_scores, function(group) any(!is.na(group))))
}), .SDcols = -"StudentID"]

方法二:转长格式聚合(适合大数据集,更高效)

如果你的数据集很大,行级循环效率不高,推荐用melt+dcast的方式:

# 1. 把宽表转长表,方便按科目组聚合
dt_long <- melt(dt, id.vars = "StudentID", variable.name = "Subject", value.name = "Score")

# 2. 给每个科目分配对应的科目组
dt_long[, Subject_Group := gsub("_\\d+$", "", Subject)]

# 3. 按学生+科目组,标记该学生是否修读了这门科目(只要有一个成绩就算)
dt_long[, has_enrolled := any(!is.na(Score)), by = .(StudentID, Subject_Group)]

# 4. 转回宽表,统计每个学生的修读科目数
dt_corrected <- dcast(dt_long, StudentID ~ ., fun.aggregate = sum, value.var = "has_enrolled")
setnames(dt_corrected, ".", "num_subjects_corrected")

# 5. 把统计结果合并回原表
dt <- dt[dt_corrected, on = "StudentID"]

自定义规则适配

如果你的双强度科目不是用_1/_2标识的(比如列名带_Double后缀),只需要调整正则表达式就行。比如如果是Physics_Double这种格式,就把gsub("_\\d+$", "", ...)改成gsub("_Double$", "", ...),根据实际的命名规则灵活调整。

运行完上面的代码,你就能得到修正后的num_subjects_corrected字段,准确统计每个学生实际修读的科目数啦!

内容的提问来源于stack exchange,提问作者newruser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:12:46