Pandas DataFrame二进制序列转态识别:代码原理与优化问询
原代码运行原理
你的代码按CLI_CD分组处理每个客户的独立序列,核心逻辑拆解如下:
- 定位连续6个0的窗口:
df['TARGET'].rolling(6).sum().eq(0)- 对
TARGET列做窗口大小为6的向前滚动求和,当窗口内所有值都是0时,求和结果为0,此时返回True。这一步会标记出连续6个0窗口的最后一行。
- 对
- 映射到目标行:
.shift(-6)- 将上一步得到的
True向前移位6位,把连续6个0窗口的起始前一行(即需要标记的行)对应过来。比如第7-12行全为0,rolling(6).sum()会在第12行返回True,shift(-6)会把这个True放到第6行的位置。
- 将上一步得到的
- 筛选当前行是1的情况:
& df['TARGET'].eq(1)- 只有当目标行的
TARGET值为1时,OUTPUT列才会标记为True,精准匹配你“当前行是1,且之后连续6行都是0”的需求。
- 只有当目标行的
原代码的合理性与优化方案
合理性验证
- 分组逻辑正确:按
CLI_CD分组避免了不同客户的行互相干扰,符合业务场景。 - 需求匹配准确:通过滚动求和+移位操作,完美实现了“标记最后一个满足后续6行全0的1所在行”的要求。
优化实现(更直观高效)
原代码的向前窗口+移位写法稍显绕,可改为更直观的向后窗口写法,同时保留Pandas向量化操作的性能优势:
def verify(df): # 检查当前行之后的1-6行是否全为0:shift(-1)取到下一行,rolling(6)覆盖后续6行,min_periods=6确保必须有完整6行 has_6_zeros_after = df['TARGET'].shift(-1).rolling(6, min_periods=6).sum().eq(0) # 同时满足当前行TARGET为1 df['OUTPUT'] = df['TARGET'].eq(1) & has_6_zeros_after return df df = df.groupby('CLI_CD').apply(verify)
性能提升建议
如果数据集规模较大,可直接用groupby结合原生滚动操作替代自定义函数,减少额外开销:
df['OUTPUT'] = df.groupby('CLI_CD').apply( lambda x: x['TARGET'].eq(1) & x['TARGET'].shift(-1).rolling(6, min_periods=6).sum().eq(0) ).reset_index(level=0, drop=True)
边界情况处理说明
- 组内末尾行:如果某行是组内倒数第6行及以后,后续不足6行,
has_6_zeros_after会返回False,符合需求(无连续6行0的条件不成立)。 - 连续1的场景:比如第5、6行都是1,后续7-12行全为0——此时只有第6行的
OUTPUT会标记为True,因为它是最后一个满足后续6行全0的1,完全匹配你的要求。
内容的提问来源于stack exchange,提问作者Renata Lins
相关产品推荐
相关产品推荐

