关于您的示例,首先要注意的是,您需要在将日期列转换为 pd.datetime 类型的语句中包含 dayfirst=True 参数。如下所示:
df['START_DATE'] = pd.to_datetime(df['START_DATE'], infer_datetime_format=True, dayfirst=True)
df['END_DATE'] = pd.to_datetime(df['END_DATE'], infer_datetime_format=True, dayfirst=True)
df['LWD'] = pd.to_datetime(df['LWD'], infer_datetime_format=True, dayfirst=True)
进行更改后,您的日期字段应报告一致且正确的日期条目,如下所示:
df = pd.DataFrame({'EID':[75161,75162,75162,75162,75162,75166,75166,75166,75169,75170],
'START_DATE':['30/08/21','01/10/21','18/10/21','12/11/21','14/06/21','22/04/21','22/07/21','23/08/21','24/08/21','25/10/21'],
'END_DATE':['30/08/21','01/10/21','18/10/21','12/11/21','14/06/21','23/04/21','23/07/21','23/08/21','26/08/21','25/10/21'],
'LWD':['30/08/21','13/11/21','13/11/21','13/11/21','13/11/21','13/10/21','13/10/21','13/10/21','13/10/21','13/11/21'],
'DURATION':[1,1,1,1,1,2,2,1,3,1]
})
df['START_DATE'] = pd.to_datetime(df['START_DATE'], infer_datetime_format=True, dayfirst=True)
df['END_DATE'] = pd.to_datetime(df['END_DATE'], infer_datetime_format=True, dayfirst=True)
df['LWD'] = pd.to_datetime(df['LWD'], infer_datetime_format=True, dayfirst=True)
注意:我更改了您的一些数据,通过让单个 ID 的休假日期超过感兴趣的期间来增加示例的复杂性。
我的数据框看起来像:
EID START_DATE END_DATE LWD DURATION
0 75161 2021-08-30 2021-08-30 2021-08-30 1
1 75162 2021-10-01 2021-10-01 2021-11-13 1
2 75162 2021-10-18 2021-10-18 2021-11-13 1
3 75162 2021-11-12 2021-11-12 2021-11-13 1
4 75162 2021-06-14 2021-06-14 2021-11-13 1
5 75166 2021-04-22 2021-04-23 2021-10-13 2
6 75166 2021-07-22 2021-07-23 2021-10-13 2
7 75166 2021-08-23 2021-08-23 2021-10-13 1
8 75169 2021-08-24 2021-08-26 2021-10-13 3
9 75170 2021-10-25 2021-10-25 2021-11-13 1
现在第一步是添加一个列,显示 LWD 之前的几周休假,如下所示:
#define function to calculate timedelta in weeks between two columns
def week_diff(x: pd.datetime, y:pd.datetime) -> int:
end = x.dt.to_period('W').view(dtype='int64')
start = y.dt.to_period('W').view(dtype='int64')
return end-start
df['wks_delta'] = week_diff(df['LWD'], df['START_DATE'])
结果是:
EID START_DATE END_DATE LWD DURATION wks_delta
0 75161 2021-08-30 2021-08-30 2021-08-30 1 0
1 75162 2021-10-01 2021-10-01 2021-11-13 1 6
2 75162 2021-10-18 2021-10-18 2021-11-13 1 3
3 75162 2021-11-12 2021-11-12 2021-11-13 1 0
4 75162 2021-06-14 2021-06-14 2021-11-13 1 21
5 75166 2021-04-22 2021-04-23 2021-10-13 2 25
6 75166 2021-07-22 2021-07-23 2021-10-13 2 12
7 75166 2021-08-23 2021-08-23 2021-10-13 1 7
8 75169 2021-08-24 2021-08-26 2021-10-13 3 7
9 75170 2021-10-25 2021-10-25 2021-11-13 1 2
我们可以使用以下方法过滤此数据帧和 groupby("EID", 'wks_delta'):
df = df[df['wks_delta'] <= 4]
df1 = df.groupby(['EID', 'wks_delta']).sum()
df1.reset_index(inplace=True)
导致:
EID wks_delta DURATION
0 75161 0 1
1 75162 0 1
2 75162 3 1
3 75170 2 1
通过应用以下内容:
def computeLeavePeriods(prds: list, df: pd.DataFrame) -> pd.DataFrame:
row_index = list(df["EID"].unique())
rows = len(row_index)
cols = len(prds)
rslt = [[0]*cols for i in range(rows)]
for r in range(df.shape[0]):
rslt[row_index.index(df.iloc[r]['EID'])][df.iloc[r]['wks_delta']] += df.iloc[r]['DURATION']
return pd.DataFrame(data= rslt, columns=prds, index=row_index)
computeLeavePeriods(['1-LWD', '2-LWD', '3-LWD', '4-LWD'], df1)
我们得到最终结果:
1-LWD 2-LWD 3-LWD 4-LWD
75161 1 0 0 0
75162 1 0 0 1
75170 0 0 1 0
要处理浮动的 Duration 值,您可以修改 computeLeavePeriods 函数,如下所示:
def computeLeavePeriods(prds: list, df: pd.DataFrame) -> pd.DataFrame:
row_index = list(df["EID"].unique())
rows = len(row_index)
cols = len(prds)
rslt = [[0]*cols for i in range(rows)]
for r in range(df.shape[0]):
rslt[row_index.index(df.iloc[r]['EID'])][int(df.iloc[r]['wks_delta'])] += df.iloc[r]['DURATION']
return pd.DataFrame(data= rslt, columns=prds, index=row_index)