R语言中summarise与summarise_at/across加权均值结果不一致问题
问题:多列加权均值计算结果不一致的原因及正确方法
数据集
a <- data.frame(cat = c("a","b","b","c","a","c"), num1 = c(-2,1,2,4,3,2), num2 = c(-2,3,1,5,3,2), weight = c(3.12,2,14,1.12,1,12))
需求
计算所有含“num”字段的加权均值(实际数据集有大量此类字段)。
方法1:逐个指定列计算
a %>% summarise(num1 = weighted.mean(num1, weight, na.rm=T), num2 = weighted.mean(num2, weight, na.rm=T))
结果:
| num1 | num2 |
|---|---|
| 1.661853 | 1.394705 |
方法2:批量处理列的错误写法
写法1
a %>% summarise(across(contains("num"), ~weighted.mean(.x, na.rm=T)))
写法2
a %>% summarise_at(.vars=vars(contains("num")), function(x, weight) weighted.mean(x, weight))
结果:
| num1 | num2 |
|---|---|
| 1.666667 | 2 |
疑问
为何两种方法结果不同?应该信任哪一种?
解答
结果不同的核心原因是批量处理的写法没有正确传递weight权重参数:
- 方法1的写法是正确的:
weighted.mean(num1, weight, na.rm=T)明确指定了权重列weight,计算的是真正的加权均值,这个结果是可信的。 - 方法2的两种写法都存在参数缺失问题:
across的写法里,~weighted.mean(.x, na.rm=T)只传了待计算列.x和na.rm,没传权重参数w,此时weighted.mean会默认用等权重计算(也就是普通算术平均)。比如num1的算术平均是(-2+1+2+4+3+2)/6 = 1.666667,和你得到的错误结果完全匹配。summarise_at的写法里,你定义的function(x, weight)需要接收weight参数,但summarise_at默认只会把待处理列x传给自定义函数,不会自动传递weight,导致权重参数缺失,同样退化为算术平均。
正确的批量处理写法
想要批量计算加权均值,必须在批量处理的函数里明确引用权重列:
推荐(tidyverse新版本语法:across)
a %>% summarise(across(contains("num"), ~weighted.mean(.x, w = weight, na.rm=T)))
旧版本语法(summarise_at)
a %>% summarise_at(.vars=vars(contains("num")), ~weighted.mean(.x, w = weight, na.rm=T))
或者直接指定权重列的完整引用:
a %>% summarise_at(.vars=vars(contains("num")), function(x) weighted.mean(x, w = a$weight, na.rm=T))
修正后的批量写法会得到和方法1完全一致的结果,应该信任方法1以及修正后的批量处理结果。
内容的提问来源于stack exchange,提问作者Carmen Tello
相关产品推荐
相关产品推荐

