tidyverse中仅能用pivot_wider()实现特定行值的汇总计算吗?
问题与解决方案
我需要对整洁格式的测试结果数据汇总计算索引值,要求按group分组,对特定var值对应的result做加权求和(如b值/2 + d值/3)。习惯用group_by()和summarise()结合result[var=='A']的子集方式实现,但该方法无法正常运行,目前仅能通过pivot_wider()实现需求。
可复现代码
示例数据与错误尝试
library(tidyverse) # 示例数据 df <- data.frame(group = c('foo', 'foo', 'foo', 'foo','bar', 'bar', 'bar', 'bar'), var = c('a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'), result = c(1, 6, 9, 3, 5, 0, 2, 9)) # 此方法无法运行,按错误提示改用reframe()也不行 index <- df %>% group_by(group) %>% summarise(var = 'index', result = result[var=='b']/2 + result[var=='d']/3) #> 警告:在dplyr 1.1.0版本中,summarise()每组返回多于(或少于)1行的用法已被弃用。 #> ℹ 请改用reframe()。 #> ℹ 从summarise()切换到reframe()时,请注意reframe()始终返回未分组的数据框,请相应调整。 #> 调用lifecycle::last_lifecycle_warnings()查看警告产生位置。 #> `summarise()`已按'group'分组输出,可使用`.groups`参数覆盖此设置。
可行的pivot_wider方法
# 使用pivot_wider可以实现,这是唯一的方法吗? index <- df %>% filter(var %in% c('b', 'd')) %>% pivot_wider(names_from = var, values_from = result) %>% mutate(index = b/2 + d/3) %>% pivot_longer(cols = c('b', 'd', 'index'), names_to = 'var', values_to = 'result')
替代方法:无需pivot_wider的group_by+summarise写法
其实不用转宽表也能实现,核心是确保每组中提取的b和d对应的值是单个标量,避免返回多值。
方法1:先筛选目标var再加权求和
index <- df %>% filter(var %in% c("b", "d")) %>% group_by(group) %>% summarise( var = "index", result = sum(if_else(var == "b", result/2, result/3)) ) # 如果需要保留原b、d的数据,再和原数据合并即可 final_df <- bind_rows(df, index)
方法2:直接提取每组的b和d值
因为每组中b和d各出现一次,所以可以用first()确保拿到单个值:
index <- df %>% group_by(group) %>% summarise( var = "index", result = first(result[var == "b"])/2 + first(result[var == "d"])/3 ) # 合并原数据得到完整结果 final_df <- bind_rows(df, index)
这两种方法都能直接用group_by()+summarise()完成索引计算,不需要来回转置宽表/长表。
内容的提问来源于stack exchange,提问作者Libbie SELC
相关产品推荐
相关产品推荐

