R语言:如何按列名数值范围对数据框列求和?
按列名数值范围对行值分组求和的实现方法
原始数据框
# 构造示例数据框 df <- structure(list( V1 = c(2008L, 2011L, 2013L, 2014L, 2015L, 2016L, 2017L, 2018L, 2019L, 2020L, 2021L, 2022L), `11` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L), `14` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L), `15` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `17` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L), `19` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L), `20` = c(1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L), `21` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L), `22` = c(0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L), `24` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L), `26` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L), `28` = c(0L, 0L, 0L, 0L, 0L, 1L, 2L, 0L, 0L, 0L, 0L, 0L), `29` = c(0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `3` = c(0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L), `31` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L), `32` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L), `35` = c(0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L), `37` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L), `39` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L), `47` = c(0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `5` = c(0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `51` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L), `54` = c(0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L), `55` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L), `6` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L), `63` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L), `66` = c(0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `7` = c(0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 2L, 3L, 1L), `9` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L), `91` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L) ), class = "data.frame", row.names = c(NA, -12L))
需求说明
需要按列名的数值范围(0-10、11-20…91-100)对每一行的列值分组求和,得到指定的汇总结果。
问题分析
你之前尝试的代码xtabs(values~., transform(cbind(df[1],stack(df[-1])), ind = sub('.','',ind)))是按列名的第二位数字截取处理,不符合数值范围分组的逻辑,因此无法得到正确结果。
解决方案
方法1:使用tidyverse工具(dplyr + tidyr)
通过长格式转换、分组求和再转回宽格式,逻辑清晰易读:
library(dplyr) library(tidyr) # 1. 将宽格式数据转为长格式 df_long <- df %>% pivot_longer(-V1, names_to = "col_num", values_to = "value") %>% mutate(col_num = as.integer(col_num)) # 列名转为数值型 # 2. 定义分组区间和对应标签 breaks <- seq(0, 100, by = 10) labels <- paste0(breaks[-length(breaks)], "-", breaks[-1]) # 3. 按年份和区间分组求和,再转回宽格式 result <- df_long %>% mutate(group = cut(col_num, breaks = breaks, labels = labels, include.lowest = TRUE)) %>% group_by(V1, group) %>% summarise(total = sum(value), .groups = "drop") %>% pivot_wider(names_from = group, values_from = total, values_fill = 0) # 查看结果 print(result, row.names = FALSE)
方法2:使用base R实现
无需加载额外包,通过基础函数完成操作:
# 1. 提取数值列名并转为整数 col_nums <- as.integer(colnames(df)[-1]) # 2. 定义分组区间和标签 breaks <- seq(0, 100, 10) labels <- paste0(breaks[-length(breaks)], "-", breaks[-1]) # 3. 对每一行按区间分组求和 row_sums <- t(apply(df[, -1], 1, function(row) { tapply(row, cut(col_nums, breaks = breaks, labels = labels, include.lowest = TRUE), sum) })) # 4. 组合年份列与求和结果 result_base <- cbind(df[, "V1", drop = FALSE], row_sums) colnames(result_base) <- c("V1", labels) # 查看结果 print(result_base)
两种方法都能生成符合预期的分组求和结果。
内容的提问来源于stack exchange,提问作者KubaH
相关产品推荐
相关产品推荐

