NHS出勤数据分析技术咨询:分组统计实现及代码优化建议
NHS出勤数据分析技术咨询:分组统计实现及代码优化建议
Hey there!首先得给你点个赞——你已经完成了数据清理的关键一步,而且尝试用循环实现分组统计的思路完全在线!不过确实,Pandas的groupby正是为这类分组统计场景量身打造的,不仅能让代码更简洁,还能让后续的分析扩展轻松太多。咱们一步步来拆解优化,同时解决你所有的疑问:
一、先点评你当前的代码与思路
你的循环代码逻辑是对的:通过逐行判断工作日/周末,再累加各原因的计数。但有两个小问题需要注意:
- 效率问题:
iterrows()是Pandas里逐行循环的方法,在数据量较大时速度会很慢(Pandas原生方法是C实现的,比Python逐行循环快几个数量级); - 灵活性问题:你硬编码了原因列表,如果后续新增出勤原因列,代码就需要手动修改,不够鲁棒;
- 重复判断:每次循环都要写
!= 'Undisclosed',可以统一处理。
二、核心优化方向:用Pandas GroupBy替代循环
groupby的核心是拆分-应用-合并:先把数据按指定规则(比如工作日/周末、时段)拆成小分组,再对每个分组做统计,最后合并结果。完全适配你所有的分析需求,而且代码量会大幅减少!
先做通用数据预处理:统一排除Undisclosed
首先解决你提到的「通用排除Undisclosed」需求——我们可以写一个简单的函数,或者直接在数据清理阶段把Undisclosed替换为Pandas的空值pd.NA,这样后续统计时会自动忽略这些值:
import pandas as pd # 1. 通用排除Undisclosed的函数(可复用) def exclude_undisclosed(df, target_columns=None): """ 将指定列中的'Undisclosed'替换为pd.NA,方便后续统计自动排除 若target_columns为None,则处理所有列 """ if target_columns is None: target_columns = df.columns df[target_columns] = df[target_columns].replace('Undisclosed', pd.NA) return df # 2. 动态获取所有出勤原因列(假设除了Weekday、Hour等元数据列,其余都是原因列) reason_columns = [col for col in NHSdata.columns if col not in ['Weekday', 'Hour', '其他非原因列']] # 3. 应用函数清理数据 NHSdata = exclude_undisclosed(NHSdata, reason_columns)
分析1:工作日vs周末最常见出勤原因
用groupby替代你的循环代码,逻辑更清晰,扩展性更强:
# 先新增一列标记是否为周末(比写两个or条件更简洁) NHSdata['Is_Weekend'] = NHSdata['Weekday'].isin(['Saturday', 'Sunday']) # 分组统计:按是否周末,对所有原因列求和(自动忽略pd.NA即Undisclosed) weekday_weekend_stats = NHSdata.groupby('Is_Weekend')[reason_columns].sum() # 转置结果,让原因作为行,更直观对比 weekday_weekend_stats = weekday_weekend_stats.T weekday_weekend_stats.columns = ['工作日总次数', '周末总次数'] # 找出每组的最常见原因 most_common_weekday = weekday_weekend_stats['工作日总次数'].idxmax() most_common_weekend = weekday_weekend_stats['周末总次数'].idxmax() print(f"工作日最常见出勤原因:{most_common_weekday}") print(f"周末最常见出勤原因:{most_common_weekend}")
分析2:全周最常见的出勤小时
这个需求用groupby或者value_counts都能轻松实现:
# 方法1:用groupby统计每个小时的出勤总记录数 hour_counts = NHSdata.groupby('Hour').size() most_common_hour = hour_counts.idxmax() # 方法2:用value_counts直接统计(更简洁) # most_common_hour = NHSdata['Hour'].value_counts().idxmax() print(f"全周最常见的出勤小时:{most_common_hour}点")
分析3:日间/夜间最常见出勤原因
先新增一列标记时段,再用groupby统计即可:
# 定义函数判断时段:8am-7pm(8-19点)为日间,其余为夜间 def get_time_period(hour): return '日间(8:00-19:00)' if 8 <= hour <= 19 else '夜间(20:00-7:00)' # 新增时段列 NHSdata['Time_Period'] = NHSdata['Hour'].apply(get_time_period) # 分组统计各时段的原因总次数 time_period_stats = NHSdata.groupby('Time_Period')[reason_columns].sum().T # 找出各时段最常见原因 most_common_daytime = time_period_stats['日间(8:00-19:00)'].idxmax() most_common_nighttime = time_period_stats['夜间(20:00-7:00)'].idxmax() print(f"日间最常见出勤原因:{most_common_daytime}") print(f"夜间最常见出勤原因:{most_common_nighttime}")
三、为什么用GroupBy比循环更好?
- 效率拉满:Pandas原生方法是C语言实现的,比
iterrows()逐行循环快几十到上百倍(尤其是大数据集); - 扩展性强:新增分析维度(比如按月份、地区分组)时,只需修改
groupby的参数,不需要重构整个循环; - 可读性高:代码逻辑和你的分析目标完全对应,后续维护或调整时一眼就能看懂。
四、后续分析的简化思路
现在你已经用groupby搭建了基础框架,后续如果要加新的分析(比如按月份+周末统计原因),只需要在groupby里传入多个列即可:
# 示例:按月份+是否周末分组统计 month_weekend_stats = NHSdata.groupby(['Month', 'Is_Weekend'])[reason_columns].sum()
备注:内容来源于stack exchange,提问作者HEB
相关产品推荐
相关产品推荐

