R语言长表转宽表求助:将分组成绩数据转换为指定格式
解决R语言中长格式转指定宽格式的问题
看起来你需要把包含group和grade的长格式数据,转换成以所有可能的grade值为行、各个group为列、值对应频数的宽格式表格。我来帮你一步步解决这个问题:
首先先确认你的原始数据:
df <- data.frame( group = c(2, 2, 2, 1, 1, 0, 0, 1, 1, 0, 1, 0), grade = c(2, 4, 3, 1, 3, 2, 5, 1, 1, 2, 3, 1) )
方法一:使用基础R实现
这种方法不需要额外安装包,适合喜欢原生R语法的用户:
- 首先生成所有需要的grade值(从你的目标输出看是1到8):
all_grades <- data.frame(grade = 1:8)
- 统计
group和grade的交叉频数:
freq_table <- table(df$grade, df$group) # 转换为数据框方便后续处理 freq_df <- as.data.frame.matrix(freq_table) # 把行名转为grade列 freq_df$grade <- as.integer(rownames(freq_df)) rownames(freq_df) <- NULL
- 合并全grade数据集和频数表,填充缺失值为0:
result <- merge(all_grades, freq_df, by = "grade", all.x = TRUE) # 把NA替换为0 result[is.na(result)] <- 0 # 调整列名和顺序,符合你的目标格式 colnames(result) <- c("grade", "group0", "group1", "group2") result <- result[, c("group0", "group1", "group2")]
运行后得到的result就是你想要的格式:
print(result) # group0 group1 group2 # 1 1 3 0 # 2 2 0 1 # 3 0 2 1 # 4 0 0 1 # 5 1 0 0 # 6 0 0 0 # 7 0 0 0 # 8 0 0 0
方法二:使用tidyverse工具(更直观)
如果你习惯使用dplyr和tidyr,可以用更简洁的语法:
首先安装并加载包(如果没安装的话):
install.packages("tidyverse") library(tidyverse)
然后执行以下步骤:
result <- df %>% # 统计每个group和grade的频数 count(group, grade) %>% # 转换为宽格式,缺失组合填充0 pivot_wider(names_from = group, values_from = n, values_fill = 0) %>% # 生成所有需要的grade值(1到8),并合并填充 right_join(tibble(grade = 1:8), by = "grade") %>% # 替换NA为0,调整列名和顺序 mutate(across(c(`0`, `1`, `2`), ~replace_na(., 0))) %>% rename(group0 = `0`, group1 = `1`, group2 = `2`) %>% select(group0, group1, group2) %>% # 把NA的grade行也保留并填充0 replace(is.na(.), 0)
运行后得到的结果和基础R方法一致,完全符合你的需求。
为什么之前的方法没成功?
你尝试的subset、tapply、table其实都是正确的方向,但可能缺少了覆盖所有grade值(包括未出现的)和填充缺失值为0这两步。比如table()只会统计出现过的grade值,而你的目标输出需要包含1到8所有grade,所以必须手动生成全grade列表并合并。
内容的提问来源于stack exchange,提问作者OvergrownCode
相关产品推荐
相关产品推荐

