代码如下,复制后保存为扩展名为py的文件即可。
- 如未安装pandas包,请使用pip install pandas进行安装。
- 代码请结合附件,在python环境下使用。
- 确保附件保存在C盘根目录下,否则请将代码中的路径改为正确的路径。
由于代码注释已经很详细了,所以我这里就不再解释了。
处理流程如下:
- 先处理系统错误(空值/数据类型等问题)。
- 然后处理逻辑错误(漏打卡,多打卡等问题)。
- 根据逻辑计算。
- 输出结果。
----------------------------
import pandas as pd
df = pd.read_excel(r'C:\考勤记录模板.xlsx')
# 预览数据
print(df.head(10))
# 查看空值
print(df.isnull().sum())
# 删除空值
df.dropna(subset='时间', inplace=True)
print(df.isnull().sum())
# 修改日期格式
df['日期'] = df['日期'].apply(
lambda x: pd.to_datetime('1900-1-1')
+ pd.DateOffset(x))
df['时间'] = pd.to_datetime(
df['时间'], format='%H:%M:%S')
print(df.head(20))
# 添加打卡次数,以便检查多打卡或漏打卡的情况。
df['打卡次数'] = df.groupby(['工号', '日期'])['时间'].rank()
print(df.head(20))
df_times = df.groupby(['工号', '日期'])['打卡次数'].agg(
['min', 'max'])
df_times = df_times.reset_index()
print(df_times.head())
df_new = pd.merge(df, df_times, on=['工号', '日期'])
print(df_new.head())
# 多打卡的位置介乎最小值和最大值之间,因此将两者与打卡次数相减,必然大于0
df_new['多打卡'] = (df_new['打卡次数'] - df_new['min']) * (df_new['max'] - df_new['打卡次数'])
df_new = df_new[df_new['多打卡'] == 0]
print(df_new.head(10))
# 漏打卡的最大值和最小值相同,相减得0
df_new['打卡次数差'] = df_new['max'] - df_new['min']
df_new['漏打卡'] = df_new['打卡次数差'].apply(lambda x: '是' if x == 0 else '否')
print(df_new.head(10))
# 漏打卡没法算迟到,补卡后再处理
'''
基于以上表格,给我算出每个人,每天的迟到,早退,加班时长。
具体逻辑如下:
迟到:时间大于8:35:01算迟到
早退:时间小于16:29:59算早退;周六11:30:00之前算早退.
加班时长:工作日:16:30:00后算加班,未达到17:30:00不算加班,17:30:00后满半小时都算加班;
周六:12:30:00以后算加班,周日:8:35:01后算加班
'''
df_new['星期'] = df_new['日期'].dt.strftime('%a')
print(df_new.head(10))
# 判断迟到/早退/加班。
def get_work_type(df_time, df_weekday, is_mark=True):
start_time = pd.to_datetime('1900-01-01 8:35:01')
work_type = None
work_time = pd.Timedelta(0)
if df_weekday == 'Sat':
end_time = pd.to_datetime('1900-01-01 11:30:00')
ot_start_time = pd.to_datetime('1900-01-01 12:30:00')
elif df_weekday == 'Sun':
end_time = pd.to_datetime('1900-01-01 8:35:01')
ot_start_time = pd.to_datetime('1900-01-01 8:35:01')
else:
end_time = pd.to_datetime('1900-01-01 16:30:00')
ot_start_time = pd.to_datetime('1900-01-01 18:00:00')
# 打卡时间介乎下班和上班之间
if start_time < df_time < end_time:
# 打卡时间接近上班则算迟早,否则算早退
if df_time - start_time <= end_time - df_time:
work_type = '迟到'
work_time = df_time - start_time
else:
work_type = '早退'
work_time = end_time - df_time
# 如果下班时间大于加班起始时间
elif df_time > ot_start_time:
work_type = '加班'
work_time = df_time - ot_start_time
# 根据传入值选择输出时间或者标签。
if is_mark:
return work_type
else:
return work_time
# 生成类型和时长
df_new['类型'] = df_new.apply(
lambda x: get_work_type(x['时间'], x['星期']), axis=1)
df_new[df_new['类型'].notnull()]
df_new['时长'] = df_new.apply(
lambda x: get_work_type(x['时间'], x['星期'], False), axis=1)
df_new[df_new['类型'].notnull()]
columns = ['工号', '姓名', '部门', '日期', '时间', '漏打卡', '类型', '时长']
print(df_new.columns)
df_result = df_new[columns]
df_result.to_excel(r'C:\考勤记录.xlsx', '处理结果', index=False)
----------------------------