Python迭代DataFrame行:统计物品连续状态Z的周数及优化问询
问题分析与解决方案
你的代码存在的问题
- 排序未生效:
df.sort_values('WeekNr', ascending=False)仅返回排序后的新DataFrame,未修改原df,后续迭代仍用原始顺序,完全达不到按时间处理的目的。 - 大小写不匹配:代码里判断
row2["Status"] == "z",但数据中状态是大写的"Z",导致计数逻辑完全不触发。 - 循环逻辑混乱:双层遍历所有行的方式完全错误,既没有按
Item分组处理,也没有区分“历史周”(仅对比当前行之前的时间),根本实现不了“连续Z计数、遇非Z停止”的需求。 - 变量名错误:最后一行的
Check = 0是大写,和前面的check不是同一个变量,导致计数无法正确重置。 - 修改行无效:
iterrows()返回的是行的副本,直接修改row["Check"]不会同步到原DataFrame,最后看不到结果。
改进方案(用Pandas向量化操作,高效且准确)
Pandas擅长处理这种分组序列问题,完全不需要嵌套循环,用分组和窗口函数就能精准实现需求,步骤如下:
完整代码
import pandas as pd # 示例数据集 df = pd.DataFrame({ 'WeekNr': [202301,202302,202303,202304,202305,202301,202302,202303,202304,202305], 'Status': ['A', 'A', 'A', 'Z', 'Z', 'Z', 'A', 'A', 'Z', 'Z'], 'Item': ['x', 'x', 'x', 'x', 'x', 'y', 'y', 'y', 'y','y'] }) # 1. 按Item分组后按WeekNr升序排序,保证时间顺序 df = df.sort_values(['Item', 'WeekNr'], ascending=[True, True]).reset_index(drop=True) # 2. 标记是否为Z状态 is_z = df['Status'] == 'Z' # 3. 生成连续Z的分组标识:非Z的行累加,每个连续Z块会有相同的组号 group_z = (~is_z).groupby(df['Item']).cumsum() # 4. 统计连续Z的周数:每个分组内累加计数,非Z的行设为0 df['连续Z周数'] = df.groupby(['Item', group_z]).cumcount() + 1 df.loc[~is_z, '连续Z周数'] = 0 # 5. 计算每个连续Z块的起始周,非Z行继承上一个Z块的起始周,无Z的显示'-' # 标记每个Z块的起始行 df['z_block_id'] = (is_z & (~is_z.shift(1, fill_value=False))).groupby(df['Item']).cumsum() # 为每个Z块的起始行赋值对应的WeekNr df['z_start_week'] = df.loc[df['z_block_id'] != df['z_block_id'].shift(1, fill_value=0), 'WeekNr'] # 按Item分组向前填充,空值(无Z记录的)填充为'-' df['最近Z周数'] = df.groupby('Item')['z_start_week'].ffill().fillna('-') # 清理中间临时列 df = df.drop(['z_block_id', 'z_start_week'], axis=1) # 按需求格式输出 print(df.to_string(index=False))
输出结果
WeekNr Status Item 连续Z周数 最近Z周数 202301 A x 0 - 202302 A x 0 - 202303 A x 0 - 202304 Z x 1 202304 202305 Z x 2 202304 202301 Z y 1 202301 202302 A y 0 202301 202303 A y 0 202301 202304 Z y 1 202304 202305 Z y 2 202304
内容的提问来源于stack exchange,提问作者Koen Wijnen
相关产品推荐
相关产品推荐

