You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Pandas中正确计算分组样本合并均值与标准差的方法

正确计算分组后的合并均值与标准差

你提到的直接用groupby.agg({'Mean':'mean', 'Dev':'mean'})确实是数学错误的,因为每个子样本的大小(n)不同,均值需要加权平均,而标准差(方差)不能直接取平均,得结合每个子样本的方差、均值与合并均值的偏差来计算。

一、数学原理

1. 合并均值(CombinedMean)

合并均值是所有子样本的加权算术平均,权重为每个子样本的样本量n
$$\text{CombinedMean} = \frac{\sum(n_i \times \text{Mean}_i)}{\sum(n_i)}$$

2. 合并标准差(CombinedDev)

标准差的计算需要先算合并方差,步骤如下:

  • 计算每个子样本的方差:$\text{Var}_i = \text{Dev}_i^2$(假设你的Dev是标准差,如果是方差则跳过这一步)
  • 计算组内平方和:$\sum(n_i \times \text{Var}_i)$
  • 计算组间平方和:$\sum(n_i \times (\text{Mean}_i - \text{CombinedMean})^2)$
  • 合并方差:$\text{CombinedVar} = \frac{\text{组内平方和} + \text{组间平方和}}{\sum(n_i)}$(如果是样本标准差则分母用$\sum(n_i) - k$,$k$是分组内子样本的数量;你的示例结果用的是总体标准差,分母是总样本量)
  • 合并标准差:$\text{CombinedDev} = \sqrt{\text{CombinedVar}}$

二、Pandas实现方案

我们可以用groupby.apply()来实现自定义的分组计算,这样能同时处理均值和标准差的正确计算:

import pandas as pd
import numpy as np

# 构造示例数据
df = pd.DataFrame({
    'Start': ['abc', 'abc', 'abc', 'abc', 'ijk', 'ijk', 'ijk'],
    'End': ['x', 'x', 'y', 'y', 'x', 'x', 'z'],
    'n': [54, 45, 14, 16, 25, 25, 7],
    'Mean': [47, 42, 50, 30, 20, 20, 10],
    'Dev': [5, 4, 10, 20, 5, 5, 2]
})

def calculate_combined_stats(group):
    total_n = group['n'].sum()
    # 计算合并均值
    combined_mean = (group['n'] * group['Mean']).sum() / total_n
    # 计算合并方差(匹配示例的总体标准差逻辑)
    var_i = group['Dev'] ** 2
    within_ss = (group['n'] * var_i).sum()
    between_ss = (group['n'] * (group['Mean'] - combined_mean) ** 2).sum()
    combined_var = (within_ss + between_ss) / total_n
    combined_dev = np.sqrt(combined_var)
    # 整理结果并保留一位小数
    return pd.Series({
        'N': total_n,
        'CombinedMean': round(combined_mean, 1),
        'CombinedDev': round(combined_dev, 1)
    })

# 按Start和End分组计算
result = df.groupby(['Start', 'End']).apply(calculate_combined_stats).reset_index()
print(result)

运行这段代码后,输出结果和你期望的完全一致:

Start End   N  CombinedMean  CombinedDev
0   abc   x  99           44.7          5.2
1   abc   y  30           39.3         19.0
2   ijk   x  50           20.0          5.0
3   ijk   z   7           10.0          2.0

补充说明

  • 如果你的Dev样本标准差(而非总体标准差),那么合并方差的分母应该用total_n - len(group)(即总样本量减去分组内子样本的数量),这样计算出来的是无偏的样本合并标准差。
  • apply()而不是agg()是因为我们需要先计算合并均值,再用它来计算合并方差,这是一个有依赖的步骤,agg()无法直接处理这种顺序关联的计算。

内容的提问来源于stack exchange,提问作者TylerNG

火山引擎 最新活动