You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NHS出勤数据分析技术咨询:分组统计实现及代码优化建议

NHS出勤数据分析技术咨询:分组统计实现及代码优化建议

Hey there!首先得给你点个赞——你已经完成了数据清理的关键一步,而且尝试用循环实现分组统计的思路完全在线!不过确实,Pandas的groupby正是为这类分组统计场景量身打造的,不仅能让代码更简洁,还能让后续的分析扩展轻松太多。咱们一步步来拆解优化,同时解决你所有的疑问:


一、先点评你当前的代码与思路

你的循环代码逻辑是对的:通过逐行判断工作日/周末,再累加各原因的计数。但有两个小问题需要注意:

  1. 效率问题:iterrows()是Pandas里逐行循环的方法,在数据量较大时速度会很慢(Pandas原生方法是C实现的,比Python逐行循环快几个数量级);
  2. 灵活性问题:你硬编码了原因列表,如果后续新增出勤原因列,代码就需要手动修改,不够鲁棒;
  3. 重复判断:每次循环都要写!= '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比循环更好?

  1. 效率拉满:Pandas原生方法是C语言实现的,比iterrows()逐行循环快几十到上百倍(尤其是大数据集);
  2. 扩展性强:新增分析维度(比如按月份、地区分组)时,只需修改groupby的参数,不需要重构整个循环;
  3. 可读性高:代码逻辑和你的分析目标完全对应,后续维护或调整时一眼就能看懂。

四、后续分析的简化思路

现在你已经用groupby搭建了基础框架,后续如果要加新的分析(比如按月份+周末统计原因),只需要在groupby里传入多个列即可:

# 示例:按月份+是否周末分组统计
month_weekend_stats = NHSdata.groupby(['Month', 'Is_Weekend'])[reason_columns].sum()

备注:内容来源于stack exchange,提问作者HEB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 18:23:14