簡體   English   中英

如何讓熊貓根據數據框中的特定值調整我的公式?

[英]How can I get pandas to adjust my formula based on a specific value in a dataframe?

我有一個如下所示的pandas數據框:

Emp_ID | Weekly_Hours | Hire_Date | Termination_Date | Salary_Paid    | Multiplier | Hourly_Pay

A1     | 35           | 01/01/1990 | 06/04/2020      | 5000           | 0.229961   | 32.85
B2     | 35           | 02/01/2020 | NaN             | 10000          | 0.229961   | 65.70
C3     | 30           | 23/03/2020 | NaN             | 5800           | 0.229961   | 44.46

乘數是所有員工的靜態數字,計算為 7 / 30.44。 每小時工資的計算方法是將月工資乘以乘數,再除以每周合同工時。

現在我的挑戰是讓 Pandas 識別 Termination Date 字段中的日期,並調整計算。 例如,第一條記錄需要更新,以顯示該員工在 2020 年 6 月 4 日辭職后,實際上在 4 個工作日內通過工資單支付了 5000 美元,而不是整月。 因此,預期的時薪數字為 (5000 / 4 * 7 / 35) = 250。

我可以很容易地編寫計算代碼; 我的努力是在所有四月畢業生(對任何其他月份不感興趣)的新列中添加一列來反映工作日(上例中的 4 天)。 到目前為止我已經嘗試過了。

df['T_Mth_Workdays'] = np.where(df['Termination_Date'].notnull(), np.busday_count('2020-04-01', df['Termination_Date']), 0)

但是,上述方法返回一個錯誤,指出:

iterator operand 0 dtype could not be cast from dtype(' m8 [ns] ') to dtype(' m8 [d] ')

我應該在這里補充一點,我必須手動將日期更改為 datetime[ns64] 格式。

任何指點,感激地收到。 謝謝!

您的np.where函數調用的問題在於它試圖將整個系列df["Termination_Date"]作為參數傳遞給np.busday_count count 函數失敗,因為它要求參數采用np.datetime64[D]格式(即,僅指定到當天的值),並且系列無法輕松轉換為這種格式。

一種解決方案是編寫自定義功能,只有調用np.busday_count不是元素NaT S,變換的那些到datetime64[D]之前調用類型np.busday_count 然后,您可以apply自定義函數應用於df["Termination_Date"]系列,如下所示:

#!/usr/bin/env python3

import numpy as np
import pandas as pd

DATE_FORMAT = "%d-%m-%Y"

# Reproduce raw data
raw_data = [
    ["A1", 35, "01/01/1990", "06/04/2020", 5000, 0.229961, 32.85],
    ["B2", 35, "02/01/2020", None, 10000, 0.229961, 65.70],
    ["C3", 35, "23/03/2020", "NAT", 5800, 0.229961, 44.46],
]

# Convert raw dates to ISO format, then np.datetime64
def parse_raw_dates(s):
    try:
        spl = s.split("/")
        ds = "%s-%s-%s" %(spl[2], spl[1], spl[0]) 
    except:
        ds = "NAT"
    return np.datetime64(ds)
for line in raw_data:
    line[2] = parse_raw_dates(line[2])

# Create dataframe
df = pd.DataFrame(
    data = raw_data,
    columns = [
        "Emp_ID", "Weekly_Hours", "Hire_Date", "Termination_Date",
        "Salary_Paid", "Multiplier", "Hourly_Pay"],
)

# Create special conversion function
def myfunc(d):
    d = d.to_numpy().astype('datetime64[D]')
    if np.isnat(d):
        return 0
    else:
        return np.busday_count('2020-04-01', d)
df['T_Mth_Workdays'] = df["Termination_Date"].apply(myfunc)

def format_date(d):
    d = d.to_numpy().astype('datetime64[D]')
    if np.isnat(d):
        return ""
    else:
        return pd.to_datetime(d).strftime(DATE_FORMAT)
df["Hire_Date"] = df["Hire_Date"].apply(format_date)
df["Termination_Date"] = df["Termination_Date"].apply(format_date)

在這里發布我的方法,以防將來對其他人有所幫助。 首先是創建數據框的代碼:

d = {'Emp_ID': ['A1', 'B2', 'C3'], 'Weekly Hours': ['35', '35', '30'], 'Hire_Date': ['01/01/1990', '02/01/2020', '23/03/2020'], 
     'Termination_Date': ['06/04/2020', np.nan, np.nan], 'Salary_Paid': [5000, 10000, 5800]}
df = pd.DataFrame(data=d)

df

第一步是將日期轉換為更有用的格式——這是pd.to_datetime()派上用場的地方——需要的調整是指定格式。

df['Hire_Date'] = pd.to_datetime(df['Hire_Date'], format='%d/%m/%Y')
df['Termination_Date'] = pd.to_datetime(df['Termination_Date'], format='%d/%m/%Y')

這具有預期的效果; 從而正確表示日期,並選擇四月作為員工 A1 的正確終止月份。

我現在(稍微)調整了 Ken 用於計算 4 月份工作日的自定義解決方案:

def workday_calc(d):
    d = d.to_numpy().astype('datetime64[D]')
    if np.isnat(d):
        return 30.44
    else:
        d = d.astype(str)
        d = dt.datetime.strptime(d, '%Y-%m-%d')
        e = (d + dt.timedelta(1)).strftime('%Y-%m-%d')
        return np.busday_count('2020-04-01', e, weekmask=[1,1,1,1,1,0,0])

我在查看np.busday_count()上的numpy 文檔時發現了錯誤。 有兩個有用的指針需要注意: 在函數的第一行中必須使用datetime64[D] - 您不能使用pd.to_datetime() 這是因為datetime64[D]格式是能夠調用np.isnat()函數的先決條件。

但是,在我們處理數據幀中的NaT那一刻,我們需要切換回字符串格式,這是datetime.strptime()函數所需要的。 使用datetime.strptime()特性,我們告訴 Python 日期是 a) 以 ISO 格式表示,我們需要將其保留為字符串。 datetime.strptime()np.busday_count()的優點是它們都是為處理字符串而構建的。

此外, np.busday_count()不包括結束日期,因此我使用timedelta()將結束日期加一,以便計算中間的所有日期。 考慮到您要執行的操作,這可能合適也可能不合適,但我想要包含 4 月份工作的天數。 因此,在這種情況下,該員工在 4 月份工作了 4 個工作日。

然后我們只需應用自定義函數並創建一個新列。

df['Days_Worked_April'] = df['Termination_Date'].apply(workday_calc)

我現在可以使用新創建的列來推導我的乘數 - 使用相同的舊方法。 其余的很簡單,但為了完整起見,我在下面包含了代碼和結果。

df['Multiplier'] = df.apply(lambda x: 7 / x['Days_Worked_April'], axis=1)
df['Hourly_Pay_Calc'] = round((df.apply(lambda x: x['Salary_Paid'] * x['Multiplier'] / x['Weekly Hours'], axis=1)), 2)

輸出:

Emp_ID  Weekly Hours    Hire_Date   Termination_Date    Salary_Paid Days_Worked_April   Multiplier  Hourly_Pay_Calc
0   A1  35.0    1990-01-01  2020-04-06  5000    4.00    1.750000    250.00
1   B2  35.0    2020-01-02  NaT 10000   30.44   0.229961    65.70
2   C3  30.0    2020-03-23  NaT 5800    30.44   0.229961    44.46

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM