R语言DataFrame按学期分组统计X变量各数值出现次数
解决方案:按学期统计X列各数值出现次数
这里有几种实用的方法能帮你实现需求,完美避开把Semester列计入统计的问题,还能得到你想要的输出格式:
方法1:使用tidyverse工具(dplyr + tidyr)
这种方法通过数据重塑和分组统计,逻辑清晰且代码简洁:
library(dplyr) library(tidyr) # 处理数据并生成结果 result <- df %>% # 将所有X开头的列转为长格式,自动排除Semester列 pivot_longer(cols = starts_with("X"), names_to = "variable", values_to = "value") %>% # 移除缺失值,只统计有效数值 drop_na(value) %>% # 按学期和数值分组,计算出现次数 count(Semester, value) %>% # 转回宽格式,给列名加上n_前缀,缺失数值补0 pivot_wider(names_from = value, values_from = n, names_prefix = "n_", values_fill = 0) %>% # 按学期排序,并调整列顺序匹配示例输出 arrange(Semester) %>% select(Semester, n_7, n_6, n_5, n_4, n_3, n_2, n_1) # 查看结果 print(result)
步骤说明:
pivot_longer:把X1-X7的宽格式数据转为长格式,直接过滤掉了Semester列,只保留需要统计的变量。drop_na:剔除值为NA的行,避免干扰计数结果。count:完成分组计数,统计每个学期中每个数值的出现次数。pivot_wider:将长格式数据转回你需要的宽格式,values_fill=0保证没有出现过的数值显示为0,不会遗漏。- 最后通过
arrange和select调整顺序,完全匹配你给出的示例输出结构。
方法2:使用base R的by()函数(适配你最初的尝试)
如果你更习惯用base R,可以修改你原来的by()函数逻辑,明确指定只处理X列:
# 定义自定义统计函数 count_x_values <- function(sub_df) { # 筛选所有以X开头的列,提取数据并转为向量 x_data <- unlist(sub_df[, grepl("^X", colnames(sub_df))]) # 移除缺失值 x_data <- x_data[!is.na(x_data)] # 统计1-7每个数值的出现次数(强制包含所有1-7的级别,缺失的数值计数为0) value_counts <- table(factor(x_data, levels = 1:7)) # 整理成目标格式的数据框 data.frame( Semester = unique(sub_df$Semester), n_7 = value_counts["7"], n_6 = value_counts["6"], n_5 = value_counts["5"], n_4 = value_counts["4"], n_3 = value_counts["3"], n_2 = value_counts["2"], n_1 = value_counts["1"], stringsAsFactors = FALSE ) } # 按Semester分组处理,并合并结果 result_base <- do.call(rbind, by(df, df$Semester, count_x_values)) # 查看结果 print(result_base)
步骤说明:
grepl("^X", colnames(sub_df)):精准筛选出所有X开头的列,彻底排除Semester列的干扰。factor(x_data, levels = 1:7):确保统计时覆盖1到7的所有数值,即使某个数值在该学期没有出现,也会返回0而不是忽略。do.call(rbind, ...):把by()返回的多个子数据框合并成一个完整的结果数据框。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

