【问题标题】:Find weekly leaves aggregate for each partner before a specific date查找每个合作伙伴在特定日期之前的每周休假总数
【发布时间】:2022-08-18 02:26:57
【问题描述】:

我有一个包含休假开始日期和结束日期、休假持续时间和最后工作日期 (LWD) 的合作伙伴休假数据集。我需要找到每个合作伙伴从 LWD 获得的四个星期的休假总和,并按 LWD 的每周间隔分组。第 1 周可被视为距 LWD 7 天,第 2 周为接下来的 7 天,依此类推。

编辑:目的是找出每个合伙人在他们离开公司之前的最后四个星期内的休假次数

下面的数据集示例,日期为 dd/mm/yyyy 格式

我正在寻找一个结果,例如:

我知道会有一个groupby,然后是datetime.timedelta(days = 7),以便从 LWD 获取日期,但对最终结果感到困惑。任何帮助表示赞赏。请注意,每周总和不是累积的,仅适用于特定一周的跨度

import pandas as pd
df = pd.DataFrame({\'EID\':[75161,75162,75162,75162,75162,75166,75166,75166,75169,75170],
                   \'START_DATE\':[\'30/08/21\',\'01/10/21\',\'18/06/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/06/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)
df[\'END_DATE\'] = pd.to_datetime(df[\'END_DATE\'], infer_datetime_format=True)
df[\'LWD\'] = pd.to_datetime(df[\'LWD\'], infer_datetime_format=True)
  • 对不起,但你的解释不是很有帮助。您能否详细说明所需的计算以及列标题逻辑。
  • 目的是找出每个合伙人在离开公司前的最后 4 周内每一周的休假次数
  • 那么,按周显示总和还是仅显示总数重要吗?
  • LWD 前 7 天的总叶片数, LWD 前 7 至 14 天的总叶片数, LWD 前 21 至 14 天的总叶片数, LWD 前 21 至 28 天的总叶片数

标签: python python-3.x pandas


【解决方案1】:

关于您的示例,首先要注意的是,您需要在将日期列转换为 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) 

【讨论】:

  • 感谢您分享方法。最后,实际上在“for r in range...”之后的行中,它显示 TypeError 为“TypeError:列表索引必须是整数或切片,而不是 numpy.float64”。我尝试在 groupby 阶段后将 EID、DURATION 转换为整数,但错误仍然存​​在。
  • 如果我将 DURATION 四舍五入到最接近的整数,然后将其转换为整数,它会给我一个索引错误,如上一条评论中提到的同一行中的“IndexError: list index out of range”。我在这里想念什么?
  • 请将以 TraceBack 开头的完整错误消息发布到您的问题中。
  • IndexError Traceback(最近一次调用最后)/var/folders/d4/wzhp8dts0nx745lfh2rtpkp00000gp/T/ipykernel_57158/2691307073.py in <module> 1 error_type, error, tb = sys.exc_info() ----> 2 filename, lineno, func_name, line = traceback.extract_tb(tb)[-1] IndexError: list index out of range
  • 您如何断定此错误消息与for r in range..... 指令有关?
猜你喜欢
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 2020-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
相关资源
最近更新 更多