在R语言中如何生成包含所有适用类别的长格式数据集?
解决方案
首先,你生成所有科目与成绩组合的代码是正确的,问题出在后续的循环处理上——每次循环都会覆盖does_not_work,最终只保留最后一次迭代的结果,而且这种多列转长的方式效率较低。下面提供两种符合需求的实现方式:
方式一:生成所有同成绩的分类组合(匹配用户示例输出)
如果需要每个学生对应所有与自己成绩相同的分类(无论分类中的科目组合是否包含该学生的科目),可以通过交叉连接实现:
library(tidyverse) # 你的原始数据集 test <- tibble(student_id = c(1), subject = c("math"), grade_num = c(95), grade = c("a")) # 生成所有科目组合(你的代码,保留不变) all_subjects <- c("math", "science", "english") i = 1 all_subject_combos <- c() while(i <= length(all_subjects)) { if(i > 1) { some_combos <- combn(all_subjects, i, FUN = function(x) paste(x, collapse = "_"), simplify = TRUE) all_subject_combos <- append(all_subject_combos, some_combos) } i <- i +1 } all_grades <- c("A", "B", "C", "D", "F") all_subjects_and_grades <- expand.grid(all_subject_combos, all_grades) subjects_and_grades_combos <- all_subjects_and_grades %>% unite("names", c(Var1, Var2)) %>% mutate(names = tolower(paste0("n_", str_replace_all(names, "\\|", "_")))) %>% pull(names) # 把分类组合转为表格,并提取成绩部分用于匹配 category_tbl <- tibble(category = subjects_and_grades_combos) %>% mutate(grade = str_extract(category, "[a-z]$")) # 提取分类末尾的成绩(小写) # 交叉连接:每个学生匹配所有同成绩的分类 result <- test %>% mutate(grade = tolower(grade)) %>% # 统一成绩大小写 cross_join(category_tbl, by = "grade") %>% # 按成绩匹配所有分类 select(student_id, subject, grade_num, grade, category) # 查看结果 result
运行后会得到每个学生对应所有同成绩的分类行,和你提供的示例输出结构一致。
方式二:仅匹配包含学生科目+同成绩的分类
如果需要分类中的科目组合必须包含该学生的科目(比如学生学math,只保留包含math的分类+同成绩),只需在交叉连接后添加筛选:
result <- test %>% mutate(grade = tolower(grade)) %>% cross_join(category_tbl, by = "grade") %>% filter(str_detect(category, subject)) %>% # 筛选包含学生科目的分类 select(student_id, subject, grade_num, grade, category) result
为什么你的循环代码不生效?
你之前的循环每次都会重新赋值does_not_work,导致之前迭代生成的列被覆盖,最终只保留最后一次循环的列。如果一定要用循环生成多列再转长,可以这样修改,但效率不如上面的方法:
# 初始化结果为原始数据 does_not_work <- test # 循环添加列 i = 1 while(i <= length(subjects_and_grades_combos)) { col_name <- paste0("subject_grade_grouping_", i) does_not_work <- does_not_work %>% mutate(!!col_name := case_when( # 这里可以根据需求调整匹配条件,比如同成绩+包含科目 str_detect(subjects_and_grades_combos[i], tolower(subject)) & str_detect(subjects_and_grades_combos[i], tolower(grade)) ~ subjects_and_grades_combos[i] )) i <- i +1 } # 转长格式 long_result <- does_not_work %>% pivot_longer(cols = starts_with("subject_grade_grouping_"), names_to = "temp", values_to = "category") %>% drop_na(category) %>% # 去掉无匹配的分类 select(-temp) long_result
内容的提问来源于stack exchange,提问作者J.Sabree
相关产品推荐
相关产品推荐

