shift()按索引位置线性偏移,正数下移、负数上移并补nan,不支持循环;需用np.roll()或iloc实现循环偏移,groupby().shift()可安全分组滞后,时序分析中应区分位置偏移与时间偏移。

shift() 函数的基本用法和常见误用
直接对 shift() 传入正数(如 df['col'].shift(1))会把数据往下错一位,空出的顶部填 NaN;传负数(如 df['col'].shift(-2))则往上错两位,底部补 NaN。很多人以为它能自动“循环移位”,但其实不会——shift() 是纯线性偏移,不带 wrap 或 modulo 行为。
- 默认
axis=0,即按行方向偏移;若想按列偏移(极少见),需显式指定axis=1 -
shift()返回新 Series/DataFrame,原数据不变;要就地修改得赋值回去,比如df['new_col'] = df['col'].shift(2) - 如果列含
datetime类型,shift()不会按时间间隔移动(那是resample()或asfreq()的事),它只按索引位置数偏移
如何实现真正的周期性循环偏移(如“首尾相连”)
当需要类似数组 roll 的效果(例如把最后一行挪到第一行),shift() 本身做不到,得组合 iloc 或 np.roll()。Pandas 没有内置 roll() 方法,但可以用 np.roll() 配合 pd.Series 构造:
import numpy as np df['col_rolled'] = pd.Series(np.roll(df['col'], shift=1), index=df.index)
注意:用 np.roll() 后必须显式恢复原始 index,否则会丢失对齐;若原索引非整数(如 DatetimeIndex),直接用 iloc 更稳妥:
df['col_rolled'] = df['col'].iloc[np.roll(np.arange(len(df)), 1)].values- 避免用
df['col'].values直接 roll 后塞回 DataFrame——这会丢掉 index 对齐,引发后续 merge 或计算错位 - 对多列批量 roll,建议用
df.iloc[np.roll(np.arange(len(df)), k)]整体切片,比逐列操作更安全
结合 groupby 做分组内周期偏移
在面板数据或用户行为分析中,常需“每个用户独立做 shift”或“每个设备单独 roll”。此时不能先 shift() 再 groupby,而必须在 groupby().apply() 里调用:
df['lagged_by_group'] = df.groupby('user_id')['value'].shift(1)
这句是正确的;但下面这句会出错:
# ❌ 错误:先 shift 再 groupby,跨组污染
df['bad'] = df['value'].shift(1).groupby(df['user_id']).transform('first')
-
groupby(...).shift()是推荐写法,内部自动按组对齐,缺失值只出现在每组开头 - 若需组内循环偏移(如每组最后一条挪到该组第一条),仍得用
groupby().apply()+np.roll(),且必须确保 apply 函数返回与输入等长的序列 - 性能上,
groupby().shift()比apply(lambda x: x.shift())快得多,后者触发 Python 循环,应避免
时序对齐场景下 shift 的陷阱
处理时间序列时,用 shift(1) 做滞后特征很常见,但容易忽略索引类型的影响。如果 DataFrame 索引是 DatetimeIndex 且不规则(如交易日缺失),shift(1) 移动的是“第 n 行”,不是“前一天”。结果可能把周五的值移到了周一位置,中间跳过周六日——这未必是你想要的“滞后一天”。
- 真正按时间偏移要用
df.asfreq('D').shift(1)或df.resample('D').first().shift(1),但会引入更多NaN - 更稳健的做法是用
df['value'].shift(1).reindex(df.index, method='ffill')补缺,但需明确业务逻辑是否允许前向填充 - 检查偏移后数据对齐最简单的方法:打印
df.index[:5]和df['shifted'].index[:5],确认二者一致
周期性偏移的“周期”到底指行序还是时间间隔,得先厘清业务语义;代码只是工具,错位往往发生在定义没想清楚的时候。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











