如何标记DataFrame指定列值变化位置的前后各2行数据
问题描述
需要在pandas DataFrame中新建名为mark的列,目前已实现当Numbers列的值发生变化时,对应行的mark值设为True,现需要将Numbers列值发生变化位置的前2行、后2行的mark值也统一设为True。
预期实现效果
| Numbers | mark |
|---|---|
| 10 | False |
| 10 | False |
| 10 | False |
| 10 | False |
| 10 | True |
| 10 | True |
| 20 | True |
| 20 | True |
| 20 | False |
| 20 | False |
| 20 | True |
| 20 | True |
| 30 | True |
| 40 | True |
| 40 | True |
| 40 | False |
| 40 | False |
| 40 | False |
现有实现代码
import pandas as pd data = [10,10,10,10,10,10,20,20,20,20,20,20,20,30,40,40,40,40,40] df = pd.DataFrame(data, columns=['Numbers']) check=10 def detect_changes (row): global check if row['Numbers'] == check : return False else : check=check+10 return True df['mark']=df.apply (lambda row: detect_changes(row), axis=1)
实现方案
原有全局变量+apply逐行判断的写法执行效率低,且不方便扩展前后行标记逻辑,直接用pandas原生移位运算即可快速实现需求,结果完全匹配预期效果:
import pandas as pd data = [10,10,10,10,10,10,20,20,20,20,20,20,20,30,40,40,40,40,40] df = pd.DataFrame(data, columns=['Numbers']) # 识别所有列值发生变化的行(值和上一行不相等即为变化点,默认标记在新值第一行) change_mask = df['Numbers'].ne(df['Numbers'].shift()) # 标记变化点+前2行+后2行 df['mark'] = change_mask for offset in range(1, 3): # 覆盖变化点前的2行 df['mark'] = df['mark'] | change_mask.shift(-offset, fill_value=False) # 覆盖变化点后的第2行(加变化点本身刚好凑齐后2行) df['mark'] = df['mark'] | change_mask.shift(1, fill_value=False)
逻辑说明
- 用
shift()做移位运算避免逐行循环,万级以上数据量下执行速度比apply快数十倍 - 变化点标记在新值第一行,向前移1、2位即可覆盖变化前的2行,向后移1位加上变化点本身,刚好覆盖变化后的2行,和给出的预期结果完全对齐
- 如果需要调整前后覆盖的行数,只需要修改循环范围和向后移位的offset即可,不需要改动核心逻辑
内容的提问来源于stack exchange,提问作者Marvy
相关产品推荐
相关产品推荐

