直接用df.select_dtypes(include='number').apply(lambda x: pd.series({'skew': skew(x.dropna(), nan_policy='omit'), 'kurtosis': kurtosis(x.dropna(), nan_policy='omit')}))一次性计算所有数值列的偏度和峰度,自动处理nan、排除非数值列,并规避pandas内置方法在nan_policy和excess kurtosis上的不一致问题。

直接用 scipy.stats 的 skew() 和 kurtosis(),配合 pandas.DataFrame.select_dtypes() 筛出数值列——这是最稳、最快、最不易出错的方式。
怎么一次性算完所有数值列的偏度和峰度?
别手动遍历列名,也别写 for 循环套 scipy 函数。直接利用 pandas 的 apply() 配合向量化函数:
from scipy.stats import skew, kurtosis
numeric_cols = df.select_dtypes(include='number').columns
result = df[numeric_cols].apply(lambda x: pd.Series({
'skew': skew(x.dropna(), nan_policy='omit'),
'kurtosis': kurtosis(x.dropna(), nan_policy='omit')
}))
关键点:
-
select_dtypes(include='number')自动排除 object / category 列,比写df.dtypes != 'object'更准 -
nan_policy='omit'必须显式指定,否则含NaN时skew()默认报错ValueError: Input contains NaN -
x.dropna()再套一层更保险,尤其当列里混有inf或空字符串转成的NaN
为什么不能直接用 df.skew() 和 df.kurtosis()?
pandas 自带的 skew() 和 kurtosis() 方法看似省事,但实际有坑:
- 它们默认按
axis=0计算,看起来没问题,但底层调用的是scipy,而 pandas 0.25+ 后对nan_policy的处理不透明,某些版本会静默跳过NaN,导致结果和手动用scipy不一致 -
df.kurtosis()计算的是 *excess kurtosis*(峰度减 3),而scipy.stats.kurtosis()默认也是 excess,但如果你误用fisher=False参数,就和 pandas 结果对不上 - 没有统一控制
nan_policy的入口,调试时容易困惑
遇到 RuntimeWarning: invalid value encountered in double_scalars 怎么办?
这个警告通常出现在某列方差为 0(全相同值)或只有 1~2 个有效样本时,skew() 和 kurtosis() 内部除零。解决方法:
- 加
try/except捕获,返回np.nan或占位符,比如:skew(x, nan_policy='omit') if x.nunique() > 1 else np.nan - 提前过滤掉低方差列:
df[numeric_cols].nunique() > 2,避免无意义计算 - 注意
kurtosis()要求至少 4 个非空值才合理,少于 4 个时结果不可信,建议加样本量检查:len(x.dropna()) → 设为 <code>np.nan
偏度和峰度本身对样本量敏感,尤其是峰度;列中哪怕一个异常值都可能让结果剧烈波动。别只看数字大小,一定要结合直方图或 df[col].describe() 一起看——这才是真正能用的结果。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











