pct_change结果全为nan主因是数据非数值型或首行无前值;需检查dtype、清洗异常字符、确保索引单调,periods设偏移量而非步长,groupby后首行恒为nan。

为什么 pct_change 算出来全是 NaN
最常见的情况:第一行永远是 NaN,因为没前一个值可比;但如果整列都是 NaN,大概率是数据类型不对——pct_change 只对数值型有效。
- 检查
dtype:df['col'].dtype不是float64或int64?先用pd.to_numeric(df['col'], errors='coerce')转一遍 - 含空字符串、逗号分隔数字(如
"1,234")、单位符号(如"100%")都会导致转成object类型,必须清洗 - 时间序列中若索引非单调递增(比如重复日期、乱序),
pct_change仍会计算,但结果可能不符合业务逻辑——建议先sort_index()
pct_change 的 periods 参数到底怎么用
默认 periods=1 是和上一行比,但实际中常要“同比”“环比”或跨多期比较,这时 periods 就不是“步长”而是“偏移量”。
-
periods=12在月度数据里才是年同比,前提是索引按月对齐且无缺失;如果中间缺了某个月,结果会错位 -
periods=-1是和下一行比(向前看),适合预测场景,但容易被忽略:它会让最后一行变NaN,而不是第一行 - 配合
freq(如freq='M')能自动对齐周期,但仅适用于DatetimeIndex,普通整数索引不认这个参数
和手动写 (x - x.shift(1)) / x.shift(1) 有啥区别
表面看等价,但底层处理空值逻辑不同:前者在分母为 0 或 NaN 时统一返回 NaN;后者如果 x.shift(1) 是 0,会触发 RuntimeWarning 并产生 inf 或 -inf,后续统计可能出错。
- 想保留
inf?别用pct_change,老老实实手算并用np.where控制分母 - 性能上,
pct_change是 C 实现的,比链式shift快 20%~30%,尤其在百万行以上数据时明显 - 注意:
pct_change不支持axis=1时的fill_method,横向计算缺失值填充得自己先fillna
在 groupby 后用 pct_change 的坑
直接 df.groupby('cat')['val'].pct_change() 看似合理,但每组首行一定是 NaN——这不是 bug,是设计:它不会跨组回溯,也不会自动用组内前值填充。
- 如果需要“组内连续编号”效果,先加序号列:
df['seq'] = df.groupby('cat').cumcount() + 1,再按seq排序确保顺序 - 遇到组内只有 1 行的数据,
pct_change返回NaN,无法避免;若需标记,可用transform('size')先过滤 - 多级分组(如
groupby(['a', 'b']))下,pct_change默认按层级顺序逐级展开,不是先合并在算,这点和agg不同
真正麻烦的是时间不对齐的分组数据:比如每个用户登录时间不规律,直接 pct_change 算出的“7日变化”可能跨了 15 天。这时候得先 resample 或 asfreq 对齐频率,再算变化——但这一步很多人直接跳过。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











