diff() 默认按相邻行计算差值,跨行差值需设 periods 参数,其本质是位置偏移(row[i] - row[i-periods]),不跳过中间行、不处理缺失值对齐、不感知时间间隔,groupby 后须在分组列上直接调用 diff() 实现组内计算。

直接说结论:diff() 方法本身不跨行计算,它默认只对相邻行做差;所谓“跨行差值”,本质是调整 periods 参数控制步长,而不是跳过中间行手动索引。
为什么 diff(periods=2) 不等于 “跳过第1行、用第3行减第1行”?
它确实是——diff(periods=2) 就是当前行减去向上数第2行的值(即 row[i] - row[i-2]),不是“隔一行取值再相减”的逻辑转换。Pandas 的 diff() 严格按偏移量计算,和手写 df['col'].iloc[i] - df['col'].iloc[i-2] 等价,但更安全(自动对齐索引、保留 NaN)。
常见误判场景:
- 误以为
diff(periods=2)会跳过缺失值重新对齐 → 实际它只看位置偏移,不管中间值是否为 NaN - 在非单调或重复索引上使用,结果与预期行序不符 →
diff()基于整数位置(.iloc语义),不是标签位置(.loc) - 对
groupby后对象直接调diff()却没指定axis或分组内计算 → 默认按列算,容易出错
diff() 在时间序列中怎么处理非等距时间间隔?
它完全不感知时间信息:即使你的索引是 DatetimeIndex,df['value'].diff(periods=1) 仍是第n个时间点减第n−1个时间点,不管这两个时间点之间隔了多久。想按真实时间差(如“7天前的值”)做差,必须先用 resample() 或 asof() 对齐,再做减法。
立即学习“Python免费学习笔记(深入)”;
例如,要计算“每个时间点与其前一个工作日收盘价之差”,不能靠 diff(),得用:
df['prev_bday'] = df.index.to_series().apply(lambda x: x - pd.offsets.BDay(1)) df['value_diff_bday'] = df['value'] - df.reindex(df['prev_bday']).values
否则 diff(periods=1) 只认行序,遇到周末空缺就直接拿周五减周一(如果数据里有周一),结果错位。
如何在 groupby 后正确做跨行差值?
必须明确作用域:是组内跨行,还是组间跨行?绝大多数情况你要的是前者,那就必须把 diff() 放在 groupby().apply() 或直接链式调用,且避免在聚合后误操作。
- ✅ 正确:
df.groupby('category')['sales'].diff(periods=3)—— 每组内各自算,第4行减第1行 - ❌ 错误:
df.groupby('category').diff(periods=3)—— 这是对整个分组后的 DataFrame 按列 diff,行为不可控 - ⚠️ 注意顺序:若需先排序再差分(比如按日期),必须显式
sort_values(),因为groupby不保证组内顺序
性能提示:对大分组,diff() 比 shift() + 减法略快,但若需复杂偏移(如动态 periods),就得用 rolling().apply() 配合自定义函数。
真正容易被忽略的一点:当 periods 大于组内行数时,对应结果全为 NaN,且不会报错或警告——你需要自己检查 groupby().size() 是否普遍大于所需 periods,否则分析结果里会静默丢失大量有效差值。


















