【问题标题】:Calculate the attendance from a CSV file generated using a biometric device从使用生物识别设备生成的 CSV 文件计算出勤率
【发布时间】:2020-07-16 17:13:51
【问题描述】:

首先,我是 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,第二列是登录/注销时间。

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

输出

基本:
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,对于每一天,使用timedelta函数计算第一次登录时间和最后一次注销时间之间的时间差(肯定会有多个条目) >日期时间模块

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

问题

这似乎是一个非常简单明了的任务,然而……

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

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

再次重申,我是编程新手,所以请告诉我我解决这个问题的逻辑是否合理,或者我应该尝试不同的方法。

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

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

【问题讨论】:

  • 可以使用熊猫吗?您可能会查找 set() 和 zip(),它们是列表列表的强大工具
  • 您如何区分登录和注销时间,因为您似乎只有一个时间变量。还是同一天最早登录第二次注销?
  • 在没有人回答你的问题时我在手机上稍后我会提供一个智能熊猫解决方案
  • 嗨萨米尔。您说,“我一直在尝试合并列表列表……”。请在帖子开头显示该代码。对我来说,作为一名读者,最重要的是问题代码。谢谢。
  • 如果你提供一个 reallistic 数据集,重现和测试会容易得多。数据集是否也可能包含不一致的值(一天中登录/注销次数奇数),如果发生应该怎么办?

标签: python csv calculation biometrics


【解决方案1】:

我猜你只是在寻找一种将列表列表转换为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']}

【讨论】:

    【解决方案2】:

    您可以在下面找到员工 (ID:13) 的一个示例输出,我的脚本创建的文件名为 ID-13 2020-04-05.txt 的出席情况

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

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

    示例输出文件: ID-13 2020-04-05.txt 的出席情况

    员工 ID - 13

    日期持续时间
    02/03/2020 8:39:0
    03/03/2020 8:37:0

    我的代码/熊猫解决方案:

    #!/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()
    

    【讨论】:

      猜你喜欢
      • 2017-07-04
      • 1970-01-01
      • 2014-07-22
      • 2017-01-12
      • 2018-12-19
      • 1970-01-01
      • 2023-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多