如何在Pandas DataFrame中为连续三行重复值添加新列
Pandas添加标记列:连续三行ID相同标记Yes/No
问题背景
现有如下Pandas DataFrame:
import pandas as pd df = pd.DataFrame({'ID': ['p1305', 'p1305', 'p1305', 'p1307', 'p1307', 'p1307', 'p1301', 'p1301', 'p1301', 'p1340', 'p1340', 'p1340','P569','P987','P569']})
需求:添加一列y,当ID列连续三行值相同时,对应行的y值为Yes,否则为No。
尝试的代码:
# 创建大小为3的滚动窗口 rolling = df['ID'].rolling(3) # 自定义函数检查窗口内值是否全部相同 df['y'] = rolling.apply(lambda x: 'Yes' if all(x == x[0]) else 'No')
触发错误:
DataError: No numeric types to aggregate
期望输出:
ID y 0 p1305 Yes 1 p1305 Yes 2 p1305 Yes 3 p1307 Yes 4 p1307 Yes 5 p1307 Yes 6 p1301 Yes 7 p1301 Yes 8 p1301 Yes 9 p1340 Yes 10 P1340 Yes 11 P1340 Yes 12 P569 No 13 P987 No 14 P569 No
解决方案
错误原因
rolling.apply()默认要求聚合操作返回数值类型,但你的lambda返回字符串Yes/No,且非数值列的滚动操作容易触发类型校验错误。
方法一:基于连续分组标记(推荐,匹配期望输出)
通过标记连续相同ID的分组,统计每组行数,只要组内行数≥3,就标记该组所有行为Yes:
# 标记连续相同ID的分组 df['group'] = (df['ID'] != df['ID'].shift()).cumsum() # 统计每个分组的行数 df['count'] = df.groupby('group')['ID'].transform('count') # 根据行数设置y列 df['y'] = df['count'].map(lambda x: 'Yes' if x >=3 else 'No') # 清理中间列(可选) df.drop(['group', 'count'], axis=1, inplace=True)
方法二:基于滚动窗口校验
如果需要严格校验当前行所在的3行窗口内值是否全部相同,可以用rolling.nunique()返回数值结果,再转换为Yes/No:
# 计算每个3行窗口内ID的唯一值数量(min_periods=1允许窗口不足3行) window_unique = df['ID'].rolling(3, min_periods=1).nunique() # 唯一值为1时说明窗口内值全相同,标记Yes df['y'] = window_unique.map(lambda x: 'Yes' if x ==1 else 'No')
两种方法对比:
- 方法一:针对整个连续相同的ID组,只要组内出现≥3次,所有行都标记Yes,完全匹配你的期望输出。
- 方法二:针对每个滚动窗口,仅当窗口内3个值全相同时才标记Yes(前两行窗口不足3,但如果和后续值相同也会标记Yes)。
内容的提问来源于stack exchange,提问作者ARJ
相关产品推荐
相关产品推荐

