簡體   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