如何移除Pandas DataFrame中连续4个0值的行
解决连续4个月0值行的移除问题
你的原代码存在两个关键问题:
- 使用
rolling(window=4)时未指定聚合逻辑,生成的是Rolling对象而非有效判断条件,导致后续的Total_rolling无法正确识别连续0值; - 用
shift标记移除行的逻辑只能覆盖部分行,没法把连续4个0的所有行都标记出来。
下面提供两种可靠的实现方案:
方案一:基于连续分组统计(直观易懂)
# 第一步:必须按ID和年月排序,保证时间序列连续性 df_next = df_next.sort_values(['ID', 'Year_Month']) # 标记Total是否为0 df_next['is_zero'] = df_next['Total'] == 0 # 为每个连续的0序列分配唯一分组ID(非0行分组ID为0) df_next['zero_group'] = df_next.groupby('ID')['is_zero'].apply( lambda x: x.cumsum() - x.cumsum().where(~x).ffill().fillna(0) ) # 计算每个0分组的长度,标记需要移除的行 group_len = df_next.groupby(['ID', 'zero_group'])['is_zero'].transform('sum') df_next['to_remove'] = df_next['is_zero'] & (group_len >= 4) # 过滤并清理辅助列 df_filtered = df_next[~df_next['to_remove']].drop(['is_zero', 'zero_group', 'to_remove'], axis=1)
逻辑说明
- 排序是核心前提:如果每个ID的行不是按时间顺序排列,连续值的判断完全失效;
zero_group通过累加标记,把连续的0归为同一分组,方便统计长度;- 最后只过滤掉那些属于长度≥4的0分组的所有行。
方案二:基于Rolling窗口(更简洁)
# 先排序 df_next = df_next.sort_values(['ID', 'Year_Month']) # 用滚动窗口判断当前位置是否是连续4个0的最后一个位置 df_next['consec_zero'] = df_next.groupby('ID')['Total'].rolling(4, min_periods=4).apply( lambda x: (x == 0).all() ).reset_index(0, drop=True) # 向前填充3次,把连续4个0的前3行也标记为需要移除 df_next['consec_zero'] = df_next.groupby('ID')['consec_zero'].ffill(limit=3).fillna(False) # 过滤数据 df_filtered = df_next[~df_next['consec_zero']].drop('consec_zero', axis=1)
逻辑说明
rolling(4, min_periods=4)确保只有当窗口内有完整4个数据时才计算;- 窗口内全为0时返回1,否则返回NaN;
ffill(limit=3)把连续4个0的前3行也标记为True,这样整个连续序列都会被过滤;- 最后过滤掉标记为True的行即可。
验证方法
可以随机抽取存在连续0值的ID验证结果:
# 取一个有连续0的ID test_id = df_next[df_next['Total'] == 0]['ID'].sample(1).iloc[0] # 查看过滤后的数据 print(df_filtered[df_filtered['ID'] == test_id])
内容的提问来源于stack exchange,提问作者TheMaffGuy
相关产品推荐
相关产品推荐

