如何使用pandas iterrows与列定位计算出勤人员首次末次访问周间隔
高性价比实现方案(无需逐行遍历)
为什么之前的iterrows方案容易跑不通
逐行遍历本身在数据量稍大时效率极低,且经常因为行内类型混杂、空值判断不准出现逻辑错误;Pandas生态下完全可以用向量化运算替代循环,计算速度能提升1~2个数量级。
分步可运行代码
1. 提前拆分数据结构,避免计算错位
你的DataFrame结构为:第1列是姓名,后续53列是周度出勤值(1=出勤,空值=缺勤),先把两类数据拆分,避免把姓名列混进数值计算里:
import pandas as pd import numpy as np # 定位列位置 name_column = df.columns[0] weekly_columns = df.columns[1:] # 单独取出周度出勤矩阵 weekly_attendance = df[weekly_columns]
2. 先筛选符合条件的人员(总出勤≥2次)
直接用空值判断统计总出勤数,比逐行sum空值的效率高很多:
# 统计每个人的总出勤次数(非空即算出勤) total_attend_count = weekly_attendance.notna().sum(axis=1) # 筛选出符合出勤次数要求的行索引 valid_user_index = total_attend_count[total_attend_count >= 2].index # 提取符合条件的子表 valid_user_attend = weekly_attendance.loc[valid_user_index]
3. 向量化计算首/末次出勤位置,直接得到时间跨度
利用布尔矩阵的索引定位,完全跳过循环:
# 把出勤数据转成布尔矩阵:True=当周出勤,False=未出勤 attend_boolean = valid_user_attend.notna().to_numpy() # 计算每行第一次出现True的位置(也就是首次出勤的列索引) first_attend_idx = np.argmax(attend_boolean, axis=1) # 计算每行最后一次出现True的位置(从矩阵右侧反向找最大值) last_attend_idx = attend_boolean.shape[1] - np.argmax(attend_boolean[:, ::-1], axis=1) - 1 # 计算时间跨度:末次索引 - 首次索引 week_span = last_attend_idx - first_attend_idx
4. 组装最终结果表
final_result = pd.DataFrame({ "人员姓名": df.loc[valid_user_index, name_column].values, "总出勤次数": total_attend_count.loc[valid_user_index].values, "首次出勤周": first_attend_idx + 1, # 因为索引从0开始,对应周数要+1 "末次出勤周": last_attend_idx +1, "周度时间跨度": week_span })
结果验证:对应你提到的索引1433的示例,该人员在第1周、第46周出勤
- 第1周对应列索引0,第46周对应列索引45
- 计算得到的时间跨度 = 45 - 0 =45,和你手动计算的结果完全匹配
常见避坑提醒
- 提前确认周度列的顺序是按周1到周53从左到右排列的,列顺序混乱会直接导致索引定位错误
- 不要把姓名列纳入周度计算矩阵,否则非空判断会把姓名当成有效出勤,导致总出勤次数统计错误
内容的提问来源于stack exchange,提问作者Glenn
相关产品推荐
相关产品推荐

