如何用Pandas筛选DataFrame中start与end标记间的行(含标记行)
筛选每组start到end之间的行(含首尾)
针对你给出的DataFrame,这里提供两种可行的解决方案,实现按record_id分组后,保留每组内start到end标记之间的所有行(包含start和end行):
方法一:利用累积和标记区间
这种方法通过数值标记和分组累积和快速定位目标区间,效率较高:
import pandas as pd import numpy as np # 构建示例数据 data = {'record_id' : [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3], 'some_data': ['semper', 'lectus', 'turpis', 'proin', 'justo', 'vitae', 'luctus', 'magna', 'non', 'vestibulum', 'nulla', 'erat', 'nisl', 'orci', 'curae', 'nam', 'aliquet', 'aliquam', 'cum', 'convallis'], 'boundaries': [np.NaN, 'start', np.NaN, np.NaN, 'end', np.NaN, np.NaN, np.NaN, 'start', np.NaN, np.NaN, 'end', np.NaN, np.NaN, np.NaN, 'start', np.NaN, 'end', np.NaN, np.NaN]} df = pd.DataFrame(data) # 1. 给start和end赋值标记值,其余补0 df['marker'] = df['boundaries'].map({'start': 1, 'end': -1}).fillna(0) # 2. 按record_id分组计算累积和,start后累积和为1,遇到end后变为0 df['in_range'] = df.groupby('record_id')['marker'].cumsum() # 3. 保留累积和>=1的行,同时单独标记end行(因为end行的累积和为0) df['in_range'] = df['in_range'].astype(bool) | (df['boundaries'] == 'end') # 4. 筛选结果并移除辅助列 result = df[df['in_range']].drop(columns=['marker', 'in_range']) print(result)
方法二:直接定位start/end索引标记区间
这种方法逻辑更直观,适合理解区间标记的过程:
import pandas as pd import numpy as np # 构建示例数据(同上) data = {'record_id' : [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3], 'some_data': ['semper', 'lectus', 'turpis', 'proin', 'justo', 'vitae', 'luctus', 'magna', 'non', 'vestibulum', 'nulla', 'erat', 'nisl', 'orci', 'curae', 'nam', 'aliquet', 'aliquam', 'cum', 'convallis'], 'boundaries': [np.NaN, 'start', np.NaN, np.NaN, 'end', np.NaN, np.NaN, np.NaN, 'start', np.NaN, np.NaN, 'end', np.NaN, np.NaN, np.NaN, 'start', np.NaN, 'end', np.NaN, np.NaN]} df = pd.DataFrame(data) # 定义分组处理函数:标记每组内start到end的区间 def mark_target_interval(group): # 获取当前组内start和end的索引 start_indices = group[group['boundaries'] == 'start'].index end_indices = group[group['boundaries'] == 'end'].index # 创建全False的掩码 mask = pd.Series(False, index=group.index) # 遍历每一组start-end对,标记区间内的行 for s_idx, e_idx in zip(start_indices, end_indices): mask.loc[s_idx:e_idx] = True return mask # 按record_id分组应用函数,生成标记列 df['in_range'] = df.groupby('record_id').apply(mark_target_interval).reset_index(level=0, drop=True) # 筛选结果并移除辅助列 result = df[df['in_range']].drop(columns='in_range') print(result)
两种方法最终都会得到如下结果:
record_id some_data boundaries 1 1 lectus start 2 1 turpis NaN 3 1 proin NaN 4 1 justo end 8 2 non start 9 2 vestibulum NaN 10 2 nulla NaN 11 2 erat end 15 3 nam start 16 3 aliquet NaN 17 3 aliquam end
内容的提问来源于stack exchange,提问作者mrgou
相关产品推荐
相关产品推荐

