在R中按组计算排除当前观测值的标准差
计算分组标准差时排除当前观测值的简便方法
当然有简便方法啦!用dplyr就能轻松实现,甚至有两种思路可以选——一种直观易懂适合小数据,另一种向量化操作适合大数据场景,我给你一步步拆解:
首先先把你的示例数据定义好:
df <- data.frame( country = c(rep("A",3), rep("B",3)), weight = c(10,11,12,20,25,30) )
方法一:直观逐行排除(适合小数据集)
这个方法直接针对每一行,排除当前观测后计算标准差,逻辑非常清晰:
library(dplyr) library(purrr) df_processed <- df %>% group_by(country) %>% mutate(standarddeviation = map_dbl(row_number(), ~sd(weight[-.]))) %>% ungroup()
代码解释:
group_by(country):先按国家分组,确保我们只在同一个国家的范围内计算map_dbl(row_number(), ~sd(weight[-.])):对组内每一行的行号,执行「去掉当前行的weight,计算标准差」的操作,map_dbl保证返回的是数值型向量,刚好能作为新列添加ungroup():最后取消分组,回到普通数据框格式
运行后你会得到完全符合预期的结果:
# A tibble: 6 × 3 country weight standarddeviation <chr> <dbl> <dbl> 1 A 10 0.707 2 A 11 1 3 A 12 0.707 4 B 20 3.54 5 B 25 7.07 6 B 30 3.54
方法二:数学公式推导(适合大数据集)
如果你的数据集很大,逐行操作效率会偏低,这时候可以用方差的数学公式来推导,全程向量化操作,速度快很多:
df_processed <- df %>% group_by(country) %>% mutate( n = n(), sum_w = sum(weight), sum_w2 = sum(weight^2), # 计算排除当前值的方差 var_excl = (sum_w2 - weight^2 - (sum_w - weight)^2/(n-1))/(n-2), # 开根号得到标准差 standarddeviation = sqrt(var_excl) ) %>% # 去掉中间计算的辅助列 select(-n, -sum_w, -sum_w2, -var_excl) %>% ungroup()
原理说明:
我们利用方差的计算公式:样本方差 = $\frac{\sum x^2 - \frac{(\sum x)^2}{n}}{n-1}$。当排除当前观测值$x_i$后,新的总和是$\sum x - x_i$,新的平方和是$\sum x^2 - x_i^2$,新的样本量是$n-1$,代入公式就能得到排除当前值的方差,再开根号就是标准差啦。
这个方法和第一种方法结果完全一致,但速度会快很多,适合处理十万行以上的大数据集。
内容的提问来源于stack exchange,提问作者wwl
相关产品推荐
相关产品推荐

