分组加权方差计算问题: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)
期望输出
| name | age |
|---|---|
| dick | nan |
| john | 44.72 |
| sam | 0.00 |
| susan | 0.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
代码说明
- 定义
weighted_variance函数,接收整个分组数据,先过滤掉age或wt为空的行; - 如果分组过滤后有效数据不足2个,返回NaN(比如dick只有一条数据,无法计算方差);
- 使用
DescrStatsW计算当前分组的加权方差,指定ddof=0匹配期望的计算逻辑; - 通过
groupby.apply将函数应用到每个分组,最后重置索引并格式化小数位数。
内容的提问来源于stack exchange,提问作者stranger12309
相关产品推荐
相关产品推荐

