按ID和P分组,筛选L=1行上下各一行L=0数据的实现方法
需求说明
原始DataFrame如下:
| ID | P | L | Score |
|---|---|---|---|
| 1 | 1 | 0 | 5 |
| 1 | 1 | 1 | |
| 1 | 1 | 0 | 7 |
| 1 | 2 | 0 | 10 |
| 1 | 2 | 1 | |
| 1 | 2 | 0 | 8 |
| 1 | 2 | 1 | 5 |
| 1 | 2 | 0 | 7 |
| 1 | 2 | 1 | |
| 1 | 2 | 1 | |
| 1 | 2 | 0 | 8 |
| 2 | 1 | 0 | 9 |
| 2 | 1 | 0 | 9 |
| 2 | 1 | 0 | 10 |
| 2 | 1 | 1 | |
| 2 | 1 | 0 | 7 |
| 2 | 1 | 1 |
需求:按ID和P分组,筛选出每个L=1的行上方紧邻的一行L=0数据,以及下方紧邻的一行L=0数据;若存在连续多个L=1的行,取这组连续行整体的上方紧邻L=0行和下方紧邻L=0行。
实现方案
步骤说明
通过分组标记连续L=1的区块,定位每个区块的前后紧邻L=0行,最后去重得到目标结果。
代码实现
import pandas as pd # 构造原始DataFrame df = pd.DataFrame({ 'ID': [1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2], 'P': [1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1], 'L': [0,1,0,0,1,0,1,0,1,1,0,0,0,0,1,0,1], 'Score': [5,'',7,10,'',8,5,7,'','',8,9,9,10,'',7,''] }) def process_group(g): # 标记L=1的行 g['is_L1'] = g['L'] == 1 # 用反向标记的累计和区分连续L1的区块 g['block'] = (~g['is_L1']).cumsum() # 获取所有包含L1的区块编号 l1_blocks = g[g['is_L1']]['block'].unique() target_indices = [] for block in l1_blocks: block_rows = g[g['block'] == block] # 取区块前一行(存在且L=0) prev_idx = block_rows.index[0] - 1 if prev_idx >= g.index[0] and g.loc[prev_idx, 'L'] == 0: target_indices.append(prev_idx) # 取区块后一行(存在且L=0) next_idx = block_rows.index[-1] + 1 if next_idx <= g.index[-1] and g.loc[next_idx, 'L'] == 0: target_indices.append(next_idx) return g.loc[target_indices].drop(columns=['is_L1', 'block']) # 分组处理并去重 result = df.groupby(['ID', 'P'], group_keys=False).apply(process_group) result = result.drop_duplicates() print(result)
输出结果
运行后得到的目标行如下:
| ID | P | L | Score |
|---|---|---|---|
| 1 | 1 | 0 | 5 |
| 1 | 1 | 0 | 7 |
| 1 | 2 | 0 | 10 |
| 1 | 2 | 0 | 8 |
| 1 | 2 | 0 | 7 |
| 1 | 2 | 0 | 8 |
| 2 | 1 | 0 | 10 |
| 2 | 1 | 0 | 7 |
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

