
本文介绍如何使用 Pandas 的 shift() 和布尔索引,精准筛选出“前一行某列值为指定值”的所有当前行,适用于日志分析、状态转移检测等场景。
本文介绍如何使用 pandas 的 `shift()` 和布尔索引,精准筛选出“前一行某列值为指定值”的所有当前行,适用于日志分析、状态转移检测等场景。
在数据分析中,常需根据前一行的状态来提取当前行数据——例如:当某行为状态标记 typeId == 6(表示“操作结束”),我们希望立即捕获其后的第一行(即“后续动作”或“响应记录”);又或者,在时序数据中识别“触发-响应”成对结构。这类需求无法通过常规条件过滤实现,而 pandas.Series.shift() 正是解决该问题的核心工具。
shift() 方法可将序列整体向下(或向上)平移指定步数,默认 periods=1 表示下移一行:原第 0 行值变为 NaN,原第 1 行值移到第 0 行位置,依此类推。因此,df['typeId'].shift() 得到的是“每一行所对应的前一行的 typeId 值”。随后用 .eq(6) 判断该前值是否等于 6,生成布尔序列,再用于布尔索引即可完成筛选。
以下为完整示例代码:
import pandas as pd
# 构造示例 DataFrame(注意:原始问题中 index 存在重复(两个 16),此处按实际顺序修正为唯一索引)
df = pd.DataFrame({
'typeId': [2, 3, 1, 1, 1, 1, 1, 3, 6, 1, 3, 6, 1, 1, 1, 1]
}, index=[1, 2, 3, 4, 5, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
# 关键逻辑:筛选「前一行 typeId == 6」的当前行
mask = df['typeId'].shift().eq(6)
result = df[mask].copy()
print(result)输出结果:
typeId 10 1 13 1
⚠️ 注意事项:
- 索引对齐性:shift() 保持原始索引不变。若原始 DataFrame 索引不连续(如含 16 跳跃),结果中的行仍保留原始索引(如上例中 10 和 13),而非位置序号。如需按自然顺序重排索引,可追加 .reset_index(drop=True)。
- 首行处理:因第一行无“前一行”,shift() 默认填充 NaN,故 .eq(6) 结果恒为 False,首行永不被选中——这符合语义预期。
- 多行匹配扩展:若需获取“6 之后的连续 N 行”,可结合 cumsum() 与分组逻辑实现,但基础场景中 shift() + 布尔索引已足够简洁高效。
- 性能提示:该方案全程向量化,无需 for 循环或 apply(),即使处理百万级数据也保持高性能。
总结而言,df[col].shift().eq(value) 是 Pandas 中表达“当前行满足前一行条件”的标准范式,兼具可读性、健壮性与执行效率,应作为数据工程师和分析师的必备技能之一。










