You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

分组加权方差计算问题:Python代码返回全NaN的解决求助

问题:分组计算加权方差时结果全为NaN

我需要按name字段对数据集进行groupby分组,获取每组的加权方差,但编写的代码运行后结果全为NaN:

import numpy as np
from statsmodels.stats.weightstats import DescrStatsW
import pandas as pd


data = {
        
"name": ['dick', 'sam', 'sam', 'sam','susan', 'susan', 'john', 'john', 'john'],
"last_name": ['lim', 'tan', 'tan', 'lim', 'wee', 'lim', 'low', 'tan', 'tan'],
"id": ['S','F', 'S','F', 'F', 'S', 'S','F', 'F',],
"loc": ['E','W', 'N','S', 'N', 'S', 'E','N', 'N'],
"sex": ['M','M', 'F','F', 'F','F', 'M','F', np.nan],
"age": [9999,20, 20,20, 20, 20, 20,40, np.nan],
'wt': [90, 10, 10, 10, 10, 10, 10, 10, 10]
}


df = pd.DataFrame(data)

wm =lambda x: DescrStatsW(df["age"], weights=df["wt"], ddof=0).var

df_gpby = df.groupby(["name"], dropna=True).agg({"age": wm}).reset_index()

print(df_gpby) 

期望输出

nameage
dicknan
john44.72
sam0.00
susan0.00

加权方差公式(中文)

加权方差的计算公式为:
加权方差 = Σ[权重i × (观测值i - 加权均值)²] / Σ权重i
(注:此处采用自由度为0的计算方式,即除以总权重而非总权重减1)


解决方案

问题根源

原代码中的lambda函数错误地使用了全局的df["age"]和df["wt"],而非当前分组的子集数据。在groupby的agg操作中,传入的x是当前分组的age列,但代码没有关联对应分组的wt列,导致计算逻辑错误,最终返回全NaN。

修改后的代码

直接使用groupby.apply处理整个分组,同时获取每组的age和wt数据:

import numpy as np
from statsmodels.stats.weightstats import DescrStatsW
import pandas as pd

data = {
    "name": ['dick', 'sam', 'sam', 'sam','susan', 'susan', 'john', 'john', 'john'],
    "last_name": ['lim', 'tan', 'tan', 'lim', 'wee', 'lim', 'low', 'tan', 'tan'],
    "id": ['S','F', 'S','F', 'F', 'S', 'S','F', 'F',],
    "loc": ['E','W', 'N','S', 'N', 'S', 'E','N', 'N'],
    "sex": ['M','M', 'F','F', 'F','F', 'M','F', np.nan],
    "age": [9999,20, 20,20, 20, 20, 20,40, np.nan],
    'wt': [90, 10, 10, 10, 10, 10, 10, 10, 10]
}

df = pd.DataFrame(data)

def weighted_variance(group):
    # 过滤当前分组中age或wt为NaN的行
    filtered = group.dropna(subset=['age', 'wt'])
    if len(filtered) < 2:
        return np.nan
    return DescrStatsW(filtered['age'], weights=filtered['wt'], ddof=0).var

df_gpby = df.groupby("name", dropna=True).apply(weighted_variance).reset_index(name='age')
# 保留两位小数匹配期望输出
df_gpby['age'] = df_gpby['age'].round(2)
print(df_gpby)

输出结果

name    age
0   dick    NaN
1   john  44.72
2    sam   0.00
3  susan   0.00

代码说明

  1. 定义weighted_variance函数,接收整个分组数据,先过滤掉age或wt为空的行;
  2. 如果分组过滤后有效数据不足2个,返回NaN(比如dick只有一条数据,无法计算方差);
  3. 使用DescrStatsW计算当前分组的加权方差,指定ddof=0匹配期望的计算逻辑;
  4. 通过groupby.apply将函数应用到每个分组,最后重置索引并格式化小数位数。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 13:35:58