簡體   English   中英

將 function 應用到 dataframe 行使用結果用於下一行輸入

[英]Apply function to dataframe row use result for next row input

我正在嘗試創建一個基本的調度系統。 這是我到目前為止所擁有的:

我有一個 pandas dataframe job_data看起來像這樣:

廁所 工作 開始 期間
1 J1 2022-08-16 07:30:00 17
1 J2 2022-08-16 07:30:00 5
2 J3 2022-08-16 07:30:00 21
2 J4 2022-08-16 07:30:00 12

它包含 wc(工作中心)、工作、工作的開始日期和持續時間(以小時為單位)。

我創建了一個 function add_hours ,它采用以下 arguments:開始(日期時間),小時數(整數)。

它根據開始時間和持續時間計算作業完成的時間。

add_hours的代碼是:

def is_in_open_hours(dt):
    return (
        dt.weekday() in business_hours["weekdays"]
        and dt.date() not in holidays
        and business_hours["from"].hour <= dt.time().hour < business_hours["to"].hour
    )


def get_next_open_datetime(dt):
    while True:
        dt = dt + timedelta(days=1)
        if dt.weekday() in business_hours["weekdays"] and dt.date() not in holidays:
            dt = datetime.combine(dt.date(), business_hours["from"])
            return dt


def add_hours(dt, hours):
    while hours != 0:
        if is_in_open_hours(dt):
            dt = dt + timedelta(hours=1)
            hours = hours - 1
        else:
            dt = get_next_open_datetime(dt)
    return dt

計算結束列的代碼是:

df["end"] = df.apply(lambda x: add_hours(x.start, x.duration), axis=1)

function 的結果是結束列:

廁所 工作 開始 期間 結尾
1 J1 2022-08-16 07:30:00 17 2022-08-17 14:00:00
1 J2 2022-08-16 07:30:00 5 2022-08-17 10:00:00
2 J3 2022-08-16 07:30:00 21 2022-08-18 08:00:00
2 J4 2022-08-16 07:30:00 12 2022-08-18 08:00:00

問題是,我需要第二行中的開始日期時間是前一行的結束日期時間,而不是它們都使用相同的開始日期。 我還需要為每個 wc 重新開始這個過程。

所以所需的 output 將是:

廁所 工作 開始 期間 結尾
1 J1 2022-08-16 07:30:00 17 2022-08-17 14:00:00
1 J2 2022-08-17 14:00:00 5 2022-08-17 19:00:00
2 J3 2022-08-16 07:30:00 21 2022-08-18 08:00:00
2 J4 2022-08-18 08:00:00 10 2022-08-18 18:00:00

您可以使用Timedeltagroupby操作。

由於您沒有提供您的自定義 function,我將在這里應用一個簡單的持續時間添加:

df['start'] = pd.to_datetime(df['start'])

t = pd.to_timedelta(df['duration'], unit='h')
g = t.groupby(df['wc'])

df['start'] = df['start'].add(g.apply(lambda x: x.cumsum().shift(fill_value=pd.Timedelta('0'))))

df['end'] = df['start'].add(t)

Output:

   wc job               start  duration                 end
0   1  J1 2022-08-16 07:30:00        17 2022-08-17 00:30:00
1   1  J2 2022-08-17 00:30:00         5 2022-08-17 05:30:00
2   2  J3 2022-08-16 07:30:00        21 2022-08-17 04:30:00
3   2  J4 2022-08-17 04:30:00        12 2022-08-17 16:30:00

我展示了一種替代方法,您只需要第first start date ,然后根據工作持續時間引導列表。


# import required modules
import io
import pandas as pd
from datetime import datetime
from datetime import timedelta

# make a dataframe
# note: only the first start date is required
x = '''
wc  job start   duration    end
1   J1  2022-08-16 07:30:00 17  2022-08-17 14:00:00
1   J2  2022-08-16 07:30:00 5   2022-08-17 10:00:00
2   J3  2022-08-16 07:30:00 21  2022-08-18 08:00:00
2   J4  2022-08-16 07:30:00 12  2022-08-18 08:00:00
'''
data = io.StringIO(x)

df = pd.read_csv(data, sep='\t')

# construct start and end lists
start = datetime.strptime(df['start'][0], '%Y-%m-%d %H:%M:%S')
start_list = [start]
end_list = []
for x in df['duration']:
    time_change = timedelta(hours=float(x))
    new_time = start_list[-1] + time_change
    start_list.append(new_time)
    end_list.append(new_time)

start_list.pop(-1)

# add to dataframe
df['start'] = start_list
df['end'] = end_list

# finished
df


結果是這樣的:

在此處輸入圖像描述

我不確定您的數據集的大小,但如果它不是太大,您可以使用以下優雅的解決方案(這將需要很長時間才能運行,因為您正在復制計算)

df['cum_duration'] = df.groupby('wc').duration.transform(sum)
df['end'] = df.apply(lambda x: add_hours(x.start, x.cum_duration), axis=1)

如果 OP 提供business_hours df,我可以嘗試驗證此解決方案

暫無
暫無

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

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