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

如何在Pandas中按列对含NaN的数据缩尾并保留数据结构

实现按列缩尾并保留原数据结构的解决方案

你遇到的问题其实可以通过两种简洁的方式解决,核心思路是对每列单独计算非NaN值的分位数,再对该列的非NaN值进行缩尾,同时保留原有的NaN和行结构。下面是具体的实现方法:

方法一:使用Pandas原生函数(推荐,无需额外依赖)

Pandas的clip()方法可以直接实现缩尾逻辑,配合quantile()计算分位数时跳过NaN,完美满足你的需求:

# 计算每列的1%和99%分位数(自动跳过NaN)
quantiles = df.quantile([0.01, 0.99], skipna=True)

# 对每列执行缩尾操作:将低于1%分位数的值替换为1%分位数,高于99%分位数的替换为99%分位数
# axis=1表示按列匹配分位数,原数据中的NaN会被保留
wins_pandas = df.clip(lower=quantiles.loc[0.01], upper=quantiles.loc[0.99], axis=1)

验证缩尾效果:

wins_pandas.quantile([0, 0.01, 0.5, 0.99, 1], skipna=True)

此时你会看到:

  • 每列的最小值(0分位数)等于1%分位数
  • 每列的最大值(1分位数)等于99%分位数
  • 原数据中的NaN位置完全保留,行数和原DataFrame一致

方法二:正确使用Scipy的winsorize

你之前使用的scipy.stats.mstats.winsorize其实本身就支持忽略NaN并保留原数组长度,可能是你对结果的验证存在误解。调整函数实现如下:

from scipy.stats.mstats import winsorize

def winsorize_single_col(s):
    # mstats.winsorize会自动忽略NaN,返回的数组中原有NaN位置保持不变
    return winsorize(s, limits=[0.01, 0.01])

# 按列应用函数,保留原数据结构
wins_scipy = df.apply(winsorize_single_col, axis=0)

验证后你会发现,缩尾后的非NaN值已经被正确处理,NaN位置完全保留,不会丢失任何行。

为什么你之前的方法看起来“结果错误”?

你提到“其余列结果错误(99分位数与最大值应一致)”,这其实是缩尾后的正常现象:缩尾操作就是把超过99%分位数的所有值替换为99%分位数,因此缩尾后的最大值必然等于99%分位数。而你用df.quantile()查看结果时,函数会自动跳过NaN计算分位数,所以这个结果是完全正确的。

而删除所有含NaN行的方法会丢失大量数据,这两种方法都完美避免了这个问题,同时保证了缩尾效果的准确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:25:30