You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于阶段排序过滤分组数据:寻求无循环实现方案

问题:高效过滤ID阶段回退前的数据

数据记录了各ID在指定日期所处的Stage,理想状态下每个ID应向Stage 4定向推进(无需经过所有阶段),但有时会回退至之前的阶段(包括同一阶段)。数据已按ID内的日期降序排序:

import pandas as pd

df = pd.DataFrame(
    {
        "ID": ["A","A","A","B","B","B","B","B","B","C","C","C","C","C","C"],
        "Stage":[4,2,1,4,3,4,3,2,1,4,3,2,1,2,1],
        "Date":['2022-09-18','2022-09-17','2022-09-16','2022-09-20','2022-09-19','2022-09-18','2022-09-17','2022-09-16','2022-09-15',
                '2022-09-20','2022-09-19','2022-09-18','2022-09-17','2022-09-16','2022-09-15']
    }
)
print(df)

需求:删除每个ID在最近一次阶段回退之前的所有行,得到目标过滤结果。请问是否存在无需使用for循环的简洁方法实现从df到df_filtered的转换?


解决方案:纯向量化实现

完全可以用Pandas的分组和窗口函数实现,不需要for循环,步骤如下:

  1. 标记回退行为:对每个ID,比较当前Stage与下一条记录的Stage(数据是日期降序,下一条对应更早的日期),如果当前Stage < 下一条Stage,说明发生了回退(因为理想是向Stage4推进,数值越大阶段越靠后,更早日期的Stage更大意味着从高阶段回退到低阶段)。
  2. 定位最近一次回退的起始点:对每个ID的回退标记从后往前(最早日期到最新日期)累积,找到最后一次回退的位置,保留该位置及之后的所有行(即最新日期方向的行)。

具体代码:

# 1. 按ID分组,标记回退行为
df['is_backward'] = df.groupby('ID')['Stage'].apply(lambda x: x < x.shift(1)).fillna(False)

# 2. 按ID分组,计算需要保留的行标记
df['keep_flag'] = df.groupby('ID')['is_backward'].transform(lambda x: x[::-1].cumsum() > 0)

# 3. 过滤数据:保留回退起始点之后的行,同时保留无回退记录的ID的所有行
df_filtered = df[df['keep_flag'] | (~df.groupby('ID')['is_backward'].transform('any'))].drop(columns=['is_backward', 'keep_flag'])

print(df_filtered)

结果说明

运行后得到的df_filtered会精准保留每个ID最近一次回退及之后的所有行:

  • ID A:所有行都在回退序列内,完整保留
  • ID B:保留从2022-09-20到2022-09-17的记录(最近一次回退的起始点)
  • ID C:保留从2022-09-20到2022-09-15的记录(包含最后一次回退及后续行为)

内容的提问来源于stack exchange,提问作者freesoup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 23:35:22