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

如何在Python中按年份对Series缩尾处理?遇NaN问题求助

解决分组Winsorize后新列全为NaN的问题

我之前也碰到过一模一样的问题!核心原因是 scipy.stats.mstats.winsorize 返回的是numpy数组/掩码数组,而非带索引的pandas Series,直接用 groupby.apply 时,pandas无法将这些数组和原DataFrame的行一一对应,最终导致新列被填充为NaN。

下面是两种可靠的解决方案,能完美对齐Stata的缩尾结果:

方法1:用transform替代apply(最简单)

transform 会自动将每个组的处理结果映射回原DataFrame的对应行,天生适配这种逐行生成结果的场景:

from scipy.stats.mstats import winsorize
import pandas as pd

# 对分组后的roe列执行缩尾,结果直接映射回原DataFrame
t['roe_w'] = t.groupby('year')['roe'].transform(lambda x: winsorize(x, limits=[0.01, 0.01]))

方法2:自定义函数返回带索引的Series(更灵活)

如果需要保留原数据中的缺失值,或者做额外处理,可以写一个自定义函数,将winsorize的结果包装成带原索引的Series:

def winsorize_series(s):
    # 对当前组的roe执行缩尾处理
    winsorized_vals = winsorize(s, limits=[0.01, 0.01])
    # 返回带原索引的Series,确保能和原DataFrame的行精准对齐
    return pd.Series(winsorized_vals, index=s.index)

t['roe_w'] = t.groupby('year')['roe'].apply(winsorize_series)

为什么原写法会失败?

你直接执行 groupby('year').roe.apply(winsorize,...) 时,返回的结果是按组聚合的数组(每个年份对应一个数组),而非逐行的数值。pandas无法将这些数组拆解成原DataFrame的每行值,因此新列只能填充为NaN。

处理含缺失值的场景

如果你的数据里有NaN,可以调整函数来保留原缺失值,同时对非缺失值执行缩尾:

def winsorize_with_nan(s):
    # 标记非缺失值的位置
    non_nan_mask = s.notna()
    # 仅对非缺失值执行缩尾
    winsorized = winsorize(s[non_nan_mask], limits=[0.01, 0.01])
    # 创建结果Series,保留原数据的缺失值
    result = s.copy()
    result[non_nan_mask] = winsorized
    return result

t['roe_w'] = t.groupby('year')['roe'].apply(winsorize_with_nan)

用上述方法处理后,你就能得到和Stata完全对齐的缩尾结果,同时新列不会再出现NaN了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:30:15