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

如何用R的dplyr按学生分组计算科目差值(单记录填NA)

学生科目差值计算解决方案

原始数据集

quux <- structure(list(STUDENT = c(1L, 1L, 2L, 2L, 3L, 3L, 4L), CLASS = c("A", "B", "A", "B", "A", "B", "A"), ENG = c(9L, 2L, 7L, 5L, 8L, 0L, 1L), MATH = c(2L, 10L, 0L, 3L, 4L, 1L, 3L), HIST = c(8L, 1L, 0L, 1L, 6L, 6L, 2L)), class = "data.frame", row.names = c(NA, -7L))

对应的表格展示:

STUDENTCLASSENGMATHHIST
1A928
1B2101
2A700
2B531
3A846
3B016
4A132

需求

对每个STUDENT,分别计算:

  • ENG.DIF = ENG[CLASS='B'] - ENG[CLASS='A']
  • MATH.DIF = MATH[CLASS='B'] - MATH[CLASS='A']
  • HIST.DIF = HIST[CLASS='B'] - HIST[CLASS='A']
    若学生仅有一条记录,则对应差值填充为NA。

尝试的错误代码

DAT1 %>% group_by(STUDENT) %>% mutate(ENG.DIF = ENG[CLASS =='B'] - ENG[CLASS == 'A']

(注:代码存在语法缺失,且未处理单条记录场景、未覆盖所有科目计算)

解决方案

提供两种可行实现方式:

方法一:宽表转换后计算

先将长表转成宽表,让每个学生的A、B班成绩分列,再直接计算差值:

library(tidyr)
library(dplyr)

quux %>%
  pivot_wider(
    id_cols = STUDENT,
    names_from = CLASS,
    values_from = c(ENG, MATH, HIST),
    names_glue = "{.value}_{CLASS}"
  ) %>%
  mutate(
    ENG.DIF = ENG_B - ENG_A,
    MATH.DIF = MATH_B - MATH_A,
    HIST.DIF = HIST_B - HIST_A
  ) %>%
  select(STUDENT, ENG.DIF, MATH.DIF, HIST.DIF)

方法二:分组直接汇总计算

通过分组后判断记录数量,仅对有两条记录的学生计算差值:

library(dplyr)

quux %>%
  group_by(STUDENT) %>%
  summarize(
    ENG.DIF = ifelse(n() == 2, ENG[CLASS == "B"] - ENG[CLASS == "A"], NA),
    MATH.DIF = ifelse(n() == 2, MATH[CLASS == "B"] - MATH[CLASS == "A"], NA),
    HIST.DIF = ifelse(n() == 2, HIST[CLASS == "B"] - HIST[CLASS == "A"], NA)
  )

两种方法均可得到期望结果:

# A tibble: 4 × 4
  STUDENT ENG.DIF MATH.DIF HIST.DIF
    <int>   <int>    <int>    <int>
1       1      -7        8       -9
2       2      -2        3        1
3       3      -8       -3        0
4       4      NA       NA       NA

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:13:19