diff()默认按行序机械差分,不识别时间索引;需先sort_index()确保升序,再用asfreq()/reindex()对齐频率后差分;periods=1为默认,freq参数仅pandas 2.0+支持。

diff() 函数默认对行做一阶差分,但容易误以为是“时间差”
它不看 datetime 索引,只按 DataFrame 行序机械相减。如果你的索引是乱序的日期(比如从数据库导出未排序),diff() 会用第2行减第1行,而不是用“2023-01-02”的值减“2023-01-01”的值。
实操建议:
- 差分前先用
sort_index()确保时间索引升序 - 如果想按真实时间间隔差分(比如跳过周末、只算交易日),得先用
asfreq()或reindex()对齐频率,再diff() -
df['value'].diff(periods=1)和df['value'].diff()效果一样;periods=2才是隔一行相减
用 freq 参数做时间对齐差分,但 pandas 2.0+ 才支持
旧版本(pandas freq 会报 TypeError: diff() got an unexpected keyword argument 'freq'。这个参数不是用来指定“差多少天”,而是让 pandas 先按给定频率重采样(如 'D' 表示每日),再做行间差分。
实操建议:
- pandas ≥ 2.0 可写
df['value'].diff(freq='D'),它会自动填充缺失日期、插值(默认线性),再差分 - 低版本得手动做:
df.asfreq('D').interpolate().diff(),注意interpolate()默认只处理数值列 -
freq='M'不代表“月度差分”,而是转成月末频率后差分;若原始数据含月中数据,会丢失精度
多级索引下 diff() 默认只对最内层生效
比如你有 MultiIndex:(stock_id, date),调用 df.groupby('stock_id')['price'].diff() 是对每个股票单独差分;但直接 df['price'].diff() 会跨股票计算——把上一只股票最后一天当成下一只股票第一天的前值。
实操建议:
- 时间序列差分几乎总是需要按实体分组,优先用
groupby(...).diff() - 如果索引是
(date, stock_id),且 date 是外层,diff(level=0)才是对日期层差分(需确保 date 已排序) -
diff()的axis参数对 Series 无效,只对 DataFrame 有意义(axis=0是默认,axis=1是列间差分,极少用于时序)
差分后首行变 NaN,fillna() 不能随便补
差分必然损失一个观测值,首行(或每组首行)是 NaN。有人用 fillna(0) 或 ffill(),结果让模型误学“突变归零”或“趋势延续”。
实操建议:
- 建模前保留
NaN,让算法(如 ARIMA、LSTM)自己处理缺失——多数库会自动 drop - 若必须填充,用
df['value'].diff().bfill()比ffill()更合理(因为差分值代表变化量,首期变化无定义,用二期反推更稳) - 注意
diff().dropna()会删整行,若其他列有值会被连带丢弃;应只对目标列操作后再合并
差分本身很简单,难的是差分前的数据对齐和差分后的 NaN 处理——这两步错一点,模型就学偏了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











