我有一个包含学生成绩和科目的长数据集。我想保留一个长数据集,但我想添加一个列,告诉我学生在人文课程(英语和历史)和STEM课程(生物和数学)中有多少个F。我还想为D、C、B和A添加相同的列。
我知道我可以明确地说明这一点,但在未来,他们可能会有其他科目(如增加化学到STEM)或完全不同的类别,如外语,所以我希望它是可扩展的。
我知道如何得到所有的列组合,我知道如何手动处理每个部分--但我不知道如何组合这两个。任何帮助都将不胜感激!
#Sample data
library(tidyverse)
student_grades <- tibble(student_id = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5),
subject = c(rep(c("english", "biology", "math", "history"), 4), NA, "biology"),
grade = c(1, 2, 3, 4, 5, 4, 3, 2, 2, 4, 1, 1, 1, 1, 2, 3, 3, 4))
#All combinations of grades and subjects
all_subject_combos <- c("eng|his", "bio|math")
all_grades <- c("F", "D", "C",
"B", "A")
subjects_and_letter_grades <- expand.grid(all_subject_combos, all_grades)
all_combos <- subjects_and_letter_grades %>%
unite("names", c(Var1, Var2)) %>%
mutate(names = str_replace_all(names, "\\|", "_")) %>%
pull(names)
#Manual generation of numbers of Fs by subject
#This is what I want the results to look like, but with all other letter grades
student_grades %>%
group_by(student_id) %>%
mutate(eng_his_F = sum((case_when(
str_detect(subject, "eng|his") & grade == 1 ~ 1,
TRUE ~ 0)), na.rm = TRUE),
bio_math_F = sum((case_when(
str_detect(subject, "bio|math") & grade == 1 ~ 1,
TRUE ~ 0)), na.rm = TRUE)) %>%
ungroup()
理想情况下,这将是可伸缩的,为任何数量的主题组合,并不会要求我写了同样的代码,为D,C,B和A。
2条答案
按热度按时间lmvvr0a81#
我们可以用
map
循环all_combos
向量,然后在每个list
中,按"student_id"进行分组(也可以在循环外执行此操作,并创建一个对象在此处使用此操作),通过计算创建与循环同名的新列(!!
),并对case_when
的输出的sum
使用:=
运算符,然后将数据与原始数据绑定w80xi6nr2#
这里有另一种方法来看待它。我使用一个小的Map表(subject_to_field)来Map主题到它的领域(英语-〉人文学科,数学-〉STEM等)。我认为这可能有助于可伸缩性。当主题被添加或删除时,你需要维护这个表。
left_join然后将字段与student_grades tibble组合在一起。
添加“grade 2”列并不是必需的,但可以提高可读性。最后,我们需要做的是执行适当的分组和计数。在这种方法中,对于学生没有出现的成绩,您不会得到零计数。
它将给予以下输出: