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

如何用Pandas数据集计算员工在岗时长与缺勤时长?

解决方案:Pandas处理打卡数据计算在岗/缺勤时长

先指出你原代码里的几个问题:

  • df.iteritems()是遍历列的方法,不是遍历行,遍历行应该用df.iterrows(),但更推荐用Pandas的向量化操作替代手动遍历
  • 条件判断逻辑错误:if (df['Addr'] == 'Main Entry-In' or 'Prod. Entry-In') 会始终返回True,因为'Prod. Entry-In'是真值,正确写法是判断Addr是否包含Entry/Exit关键词
  • 语法错误:entries.['Time']多了个点,应该是entries['Time']

下面是高效的向量化解决方案,无需手动逐行遍历:

步骤1:数据预处理

先合并日期时间为可计算的datetime类型,标记打卡类型,并按用户和时间排序(这是时间计算的基础,确保打卡顺序正确):

import pandas as pd

# 假设数据已读取到df中
df['Datetime'] = pd.to_datetime(df['Date'] + ' ' + df['Time'], format='%Y.%m.%d %H:%M')

# 标记打卡类型:Entry/Exit
df['CheckType'] = df['Addr'].apply(lambda x: 'Entry' if 'Entry In' in x else 'Exit' if 'Exit' in x else 'Unknown')

# 按用户ID和时间排序,保证打卡顺序正确
df = df.sort_values(by=['User ID', 'Datetime']).reset_index(drop=True)

步骤2:计算在岗时长(Present Time)

同一用户的Exit时间减去对应的Entry时间,通过分组偏移行来配对:

# 分组后获取下一条记录的时间和打卡类型
df['Next_Datetime'] = df.groupby('User ID')['Datetime'].shift(-1)
df['Next_CheckType'] = df.groupby('User ID')['CheckType'].shift(-1)

# 仅当当前是Entry且下一条是Exit时,计算在岗时长
df['present_time'] = df.apply(
    lambda row: (row['Next_Datetime'] - row['Datetime']) if row['CheckType'] == 'Entry' and row['Next_CheckType'] == 'Exit' else pd.NaT,
    axis=1
)

步骤3:计算缺勤时长(Absence Time)

下一次Entry时间减去上一次Exit时间:

# 分组后获取上一条记录的时间和打卡类型
df['Prev_Datetime'] = df.groupby('User ID')['Datetime'].shift(1)
df['Prev_CheckType'] = df.groupby('User ID')['CheckType'].shift(1)

# 仅当当前是Entry且上一条是Exit时,计算缺勤时长
df['absence_time'] = df.apply(
    lambda row: (row['Datetime'] - row['Prev_Datetime']) if row['CheckType'] == 'Entry' and row['Prev_CheckType'] == 'Exit' else pd.NaT,
    axis=1
)

步骤4:处理异常打卡(连续打卡/漏打卡)

过滤连续打卡(同一类型连续出现)

# 标记连续相同类型的打卡为异常
df['Is_Abnormal'] = df.groupby('User ID')['CheckType'].apply(lambda x: x == x.shift())

# 过滤掉连续异常的打卡(保留第一个连续项)
df = df[~df['Is_Abnormal']].reset_index(drop=True)

处理漏打卡(Entry/Exit不配对)

可以统计每个用户的Entry和Exit数量,标记不匹配的记录:

# 统计每个用户的Entry/Exit数量
check_counts = df.groupby(['User ID', 'CheckType']).size().unstack(fill_value=0)

# 找出Entry和Exit数量不等的用户
unmatched_users = check_counts[check_counts['Entry'] != check_counts['Exit']].index

# 标记这些用户的最后一条记录为漏打卡
df['Is_Missing'] = df.apply(
    lambda row: True if row['User ID'] in unmatched_users and row.name == df[df['User ID'] == row['User ID']].index[-1] else False,
    axis=1
)

最终结果整理

保留需要的列,或按用户汇总结果:

# 选择需要的列展示
result = df[['User ID', 'User Name', 'Datetime', 'CheckType', 'present_time', 'absence_time', 'Is_Abnormal', 'Is_Missing']]
print(result)

关键说明

  • 用向量化操作替代手动遍历,效率远高于逐行循环(Pandas的核心优势就是向量化)
  • 必须先按用户和时间排序,否则时间差计算会完全错误
  • 异常处理规则可根据业务调整,比如连续打卡的时间阈值(比如10分钟内连续打卡算异常)、漏打卡的补全规则(比如默认补全当天22:00为下班时间)

内容的提问来源于stack exchange,提问作者Nikobitan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:40:42