Применение функции по расчёту рабочих дней (5 дневка) в датафрейме между двумя столбцами с датами
Пытаюсь решить простецкую задачку, но никак не получается. Исходные данные Имеется датафрейм, состоящий из столбцов Работа-дата начала-дата завершения- и. Цель сформировать дополнительный столбец с числом рабочих дней (5-дневка) внутри диапазона (дата начала - дата завершения)
Сам датафрейм
index,Work,Start_date,End_date
0,Каталог изделия,2022-12-15 00:00:00,2023-02-15 00:00:00
1,Регламент СО,2022-10-01 00:00:00,2023-04-30 00:00:00
2,Лопатка,2023-02-01 00:00:00,2023-03-15 00:00:00
3,Ротор,2023-03-01 00:00:00,2023-05-31 00:00:00
4,Комплект Запчастей,2023-03-01 00:00:00,2023-04-30 00:00:00
Расчёт вне датафрейма на двух переменных удалось реализовать по найденному алгоритму:
import pandas as pd
from datetime import date
start_date = date.fromisoformat('2023-01-06')
end_date = date.fromisoformat('2023-01-11')
def clean_dates(df):
dates = pd.date_range(start_date, end_date, freq='D')
res = 1+len(dates\[(dates.date\>=start_date)&(dates.date\<end_date)&(dates.weekday\<5)\])
Попытка адаптировать его под датафрейм не увенчалась успехом:
def clean_dates(df, x):
dates = pd.date_range(x df["Start_date"], x df["End_date"], freq='D')
res = 1+len(dates[(dates.date>=x df["Start_date"])&(dates.date<x df["End_date"])&(dates.weekday<5)])
return(df, x)
df["cwd"] = df.apply(clean_dates, axis=1)
в итоге пришлось колхозить:
df["range"] = df.apply(lambda x: 21*len(pd.date_range(start=x["Start_date"], end=x["End_date"], freq="M")
.date.tolist()), axis=1) #determination of work days (21 - average work days per month)
Ответы (1 шт):
Во-первых, среднее количество рабочих дней здесь не подойдет - это как средняя температура по больнице, для точных подсчетов не годится. Во-вторых, есть готовые средства pandas, позволяющие считать рабочие дни (другое дело, что, например, российские праздники там вряд ли учитываются. я бы предложил сделать так:
res = df.copy()
res['days'] = [pd.bdate_range(start, end) for start, end in zip(res['Start_date'], res['End_date'])]
# ^^^ обратите внимание на bdate_range - в отличие от date_range
# здесь учитываются "бизнес-дни"
res = res.explode("days")
res = res.groupby("Work")["days"].count()
df = df.join(res.drop(columns="days"), on="Work")
получим df:
Work Start_date End_date days
index
0 Каталог изделия 2022-12-15 00:00:00 2023-02-15 00:00:00 45
1 Регламент СО 2022-10-01 00:00:00 2023-04-30 00:00:00 150
2 Лопатка 2023-02-01 00:00:00 2023-03-15 00:00:00 31
3 Ротор 2023-03-01 00:00:00 2023-05-31 00:00:00 66
4 Комплект Запчастей 2023-03-01 00:00:00 2023-04-30 00:00:00 43