按data.frame分组对指定因子水平的val值求和的实现方法
分组筛选求和解决方案
需求说明
现有如下结构的data.frame:
fac1 fac2 fac3 val 1 Apple Fresh Red 2 2 Apple Old Red 3 3 Apple Hazard Red 1 4 Banana Fresh Yellow 4 5 Banana Old Yellow 5 6 Banana Hazard Yellow 1 7 Berry Fresh Purple 1 8 Berry Old Purple 1 9 Berry Hazard Purple 3
需要按fac1的每个因子水平,筛选fac2等于**字符型值"Fresh"或"Old"**的行,对val列求和,同时保留fac3列,生成如下结构的结果:
fac1 fac3 sum.freshold 1 Apple Red 5 2 Banana Yellow 9 3 Berry Purple 2
示例数据代码
mydf <- data.frame(fac1 = c(rep("Apple", 3), rep("Banana", 3), rep("Berry", 3)), fac2 = rep(c("Fresh", "Old", "Hazard"), 3), fac3 = c(rep("Red", 3), rep("Yellow", 3), rep("Purple", 3)), val = c(2,3,1,4,5,1,1,1,3), stringsAsFactors = T)
无效代码问题分析
你尝试的tapply代码无法得到目标结果,原因有两点:
- 函数内部使用了全局的
mydf$fac2,但tapply传入的x是分组后的val子集,索引和原数据不匹配,导致筛选逻辑错误; tapply返回的是向量,无法直接生成包含fac1、fac3和求和列的data.frame。
# 无效代码 tapply(mydf$val, mydf$fac1, function(x) {x[mydf$fac2 == "Fresh"] + x[mydf$fac2 == "Old"]})
可行解决方案
方法1:使用dplyr包(语法直观)
library(dplyr) result <- mydf %>% # 筛选fac2为Fresh或Old的行 filter(fac2 %in% c("Fresh", "Old")) %>% # 按fac1和fac3分组(每个fac1对应唯一fac3,确保结果保留fac3) group_by(fac1, fac3) %>% # 求和并重命名列 summarise(sum.freshold = sum(val), .groups = "drop")
方法2:使用Base R(无需额外包)
# 第一步:筛选符合条件的行 filtered_df <- mydf[mydf$fac2 %in% c("Fresh", "Old"), ] # 第二步:按fac1和fac3分组求和 result <- aggregate(val ~ fac1 + fac3, data = filtered_df, FUN = sum) # 第三步:重命名求和列 colnames(result)[3] <- "sum.freshold"
方法3:使用data.table包(大数据场景高效)
library(data.table) # 转换为data.table格式 setDT(mydf) # 筛选+分组求和 result <- mydf[fac2 %in% c("Fresh", "Old"), .(sum.freshold = sum(val)), by = .(fac1, fac3)]
内容的提问来源于stack exchange,提问作者Joschi Nin
相关产品推荐
相关产品推荐

