繁体   English   中英

根据使用生物识别设备生成的 CSV 文件计算出勤率

[英]Calculate the attendance from a CSV file generated using a biometric device

首先,我是 Python 的完整初学者,这是我第一次为个人项目编写脚本,所以请在回答时保持温和。

输入

我有一个未排序的 CSV 文件,其中包含给定月份所有员工的登录时间,如下所示:

13,03/02/2020 09:43
12,03/02/2020 10:26
10,03/02/2020 12:12
13,03/02/2020 18:22
12,03/02/2020 18:23
13,03/03/2020 09:51
12,03/03/2020 10:38
10,03/03/2020 12:02
13,03/03/2020 18:28
12,03/03/2020 18:29

其中第一列是员工 ID,第二列是登录/注销时间。

我想知道从文件中读取登录时间并计算的最佳/最有效方法:

Output

基本的:
1. 员工在办公室呆了多少天
2.员工每天的总工作时间

Employee ID - xxxx

Date        Duration  
DD/MM/YY    hh:mm:ss
DD/MM/YY    hh:mm:ss
DD/MM/YY    hh:mm:ss

Total No. of Working Days in this month: 

先进的:
计算哪些日子是星期天,并将这些日子添加到他们目前的出勤率中
更高级:
与某个地区的在线 google 日历进行比较,以查找该地区该月的假期并将这些假期添加到他们的出勤中

我的逻辑:

  1. 阅读 CSV 文件并提取登录时间并将其保存在排序列表中。 这将创建一个列表列表,如下所示:
[['10', '03/02/2020 12:12'],['10', '03/03/2020 12:02'], ['10', '03/06/2020 15:12'], ['10', '03/07/2020 16:18'], ['10', '03/08/2020 11:04'], ['10', '03/08/2020 11:05'], ['10', '03/09/2020 11:27'], ['10', '03/10/2020 17:06'], ['10', '03/11/2020 22:13'], ['10', '03/12/2020 11:13'], ['10', '03/13/2020 11:57'], ['10', '03/14/2020 11:29'], ['10', '03/16/2020 10:32'], ['10', '03/17/2020 17:37'], ['10', '03/18/2020 12:24'], ['10', '03/19/2020 15:38'], ['10', '03/19/2020 15:45'], ['10', '03/20/2020 15:26']]
  1. 将此列表转换为排序字典,以便将员工的所有登录时间一起保存在列表中。 看起来像:
{'10':['03/02/2020 12:12','03/02/2020 15:38','03/08/2020 11:05'],  
'12':['03/03/2020 11:27','03/03/2020 12:02','03/03/2020 18:29'],  
'13':['03/16/2020 10:32','03/16/2020 11:57','03/16/2020 19:04']}

等等...

...其中,字典的“键”是员工 ID,“值”是按日期排序的所有登录/注销时间的列表

  1. 对于每个员工ID,对于每一天,使用datetime模块的timedelta函数计算第一次登录时间和最后一次注销时间的时间差(肯定会有多个条目)

  2. 创建一个 excel 文件,看起来像上面显示的预期 output

问题

似乎是一个非常简单明了的任务,但...

我一直试图将列表列表合并到一个正确的字典中,其中员工 ID 作为键,所有登录时间的列表作为值。 试图用谷歌搜索一个可能的解决方案让我找到了https://thispointer.com/python-how-to-convert-a-list-to-dictionary/ 但这对我的问题没有帮助,因为我试图从同一个列表中提取非常具体的信息。

在 stackoverflow 上找不到类似的东西,所以我发布了一个新问题。

同样,我是编程新手,所以请让我知道我解决这个问题的逻辑是否有意义,或者我应该尝试不同的方法。

PS:我看过 pandas 但似乎没有必要从头开始学习这样一个简单的任务。
此外,下一步,计算时差可能比我想象的要困难,因此非常欢迎任何帮助。
另外,我不是要求为我编写代码。 我想学习这门美丽的语言,这样我就可以变得更好,并轻而易举地创建这样的脚本。

如果您做到了这一点,感谢您抽出宝贵的时间:您让世界变得更美好:)

我猜你只是在寻找一种将列表列表转换为dict的方法,试试这个:

from collections import defaultdict
import pprint
l = [['10', '03/02/2020 12:12'],['10', '03/03/2020 12:02'], ['10', '03/06/2020 15:12'], ['10', '03/07/2020 16:18'], ['10', '03/08/2020 11:04'], ['10', '03/08/2020 11:05'], ['10', '03/09/2020 11:27'], ['10', '03/10/2020 17:06'], ['10', '03/11/2020 22:13'], ['10', '03/12/2020 11:13'], ['10', '03/13/2020 11:57'], ['10', '03/14/2020 11:29'], ['10', '03/16/2020 10:32'], ['10', '03/17/2020 17:37'], ['10', '03/18/2020 12:24'], ['10', '03/19/2020 15:38'], ['10', '03/19/2020 15:45'], ['10', '03/20/2020 15:26'], ['11', '03/19/2020 15:45'], ['11', '03/20/2020 15:26'], ['12', '03/19/2020 15:45'], ['12', '03/20/2020 15:26']]
datesByEmployee = defaultdict(list)
for ll in l:
    datesByEmployee[ll[0]].append(ll[1])
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(dict(datesByEmployee))

这给了你:

{   '10': [   '03/02/2020 12:12',
          '03/03/2020 12:02',
          [...]],
'11': ['03/19/2020 15:45', '03/20/2020 15:26'],
'12': ['03/19/2020 15:45', '03/20/2020 15:26']}

在下面您可以找到一个示例 output 用于员工(ID:13),我的脚本创建的文件称为ID-13 的出勤 2020-04-05.txt

到目前为止,请注意我的脚本的两个导入限制
1)它创建.txt文件而不是.xlsx
2)它只取最短的白天时间,然后从当天的最长时间中减去它。

限制 2 还意味着,当某人在某一天(即 3 月 2 日)登录并在第二天的 3 月 3 日注销时,在输出文件的持续时间列中,您会发现“今天没有注销”。 此外,如果一个人每天多次登录和注销,即休息,这些时间将被忽略。
但是,这将是单独的问题,这是您要解决的任务的一部分

示例输出文件: ID-13 2020-04-05.txt 的出勤率

员工编号 - 13

日期持续时间
2020 年 2 月 3 日 8:39:0
2020 年 3 月 3 日 8:37:0

我的代码/pandas 解决方案:

#!/usr/bin/env python3
import pandas as pd
from pathlib import Path
import numpy as np
import datetime
from math import floor

def time_to_delat(t):
    """Convert datetime.time object with hour and minute to datetime.timedelta object"""
    dt = datetime.timedelta(hours=t.hour, minutes=t.minute)
    return dt
def trans_form_tostring(dt):
    hours = dt.seconds//3600
    minutes = (dt.seconds//60)%60
    seconds = dt.seconds%60
    return f"{hours}:{minutes}:{seconds}"

def main():
    # set path to csv
    path_to_csv = Path("C:/Test/tmp_csv.csv")
    # set names for the columns
    header = ['ID','Datetime']
    # read the csv as pandas dataframe
    df = pd.read_csv(path_to_csv, names = header,parse_dates=True)
    # Convert the column 'Date' to a datetime object
    df['Datetime'] = pd.to_datetime(df['Datetime'])
    df['Date'] = df['Datetime'].dt.date
    df['Time'] = df['Datetime'].dt.time

    for ID in df.ID.unique():
        # Iterate over every unique ID of employee and Filter for a single ID
        one_employee = df[df['ID']==ID].sort_values(by='Date')
        # Get the earliest start time of a day and the latest time of a day
        start_per_day = one_employee.groupby('Date')['Time'].min()
        end_per_day = one_employee.groupby('Date')['Time'].max()
        # Convert array of datetime.time objects to array of datetime.timedelta objects
        start_per_day_dt = np.array([time_to_delat(x) for x in start_per_day])
        end_per_day_dt = np.array([time_to_delat(x) for x in end_per_day])
        # get the duration for a single day
        delta_per_day = [trans_form_tostring(x) for x in (end_per_day_dt - start_per_day_dt)]
        # Create an empty list dates for the attendance
        attended_days = []
        for i,working_day in enumerate(one_employee.Date.unique()):
            if delta_per_day[i] == "0:0:0":
                delta_per_day[i] = "No Logout for this day"
            day = working_day.strftime("%d/%m/%Y")
            attended_days.append(f"{day}\t{delta_per_day[i]}")
        create_excel_output(ID,attended_days,Path("C:/Test"))

def create_excel_output(ID, dates,outpath=None):
    protocol_file = f"Attendance of ID-{ID} {datetime.date.today()}.txt"
    if outpath is not None:
        protocol_file = outpath / f"Attendance of ID-{ID} {datetime.date.today()}.txt"
    employee = f"Employee ID - {ID}"
    with open(protocol_file,'w') as txt:
        txt.write(employee+"\n\n")
        txt.write("Date\tDuration\n")
        for line in dates:
            txt.write(line)
            txt.write("\n")

if __name__ == '__main__':
    main()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM