如何用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))
对应的表格展示:
| STUDENT | CLASS | ENG | MATH | HIST |
|---|---|---|---|---|
| 1 | A | 9 | 2 | 8 |
| 1 | B | 2 | 10 | 1 |
| 2 | A | 7 | 0 | 0 |
| 2 | B | 5 | 3 | 1 |
| 3 | A | 8 | 4 | 6 |
| 3 | B | 0 | 1 | 6 |
| 4 | A | 1 | 3 | 2 |
需求
对每个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
相关产品推荐
相关产品推荐

