基于项目的总和

时间:2019-08-23 19:26:42

标签: python pandas numpy

我正在尝试建立一个时间段,在这种情况下,假设是30天,在此期间,每个ID和Project的金额都会被添加。

基本上,30天总和的开始日期必须是在开始日期之前首次看到ID和项目的时间。然后,如果在30天之内再次看到相同的ID和项目,则应将其与前一个一起添加。 30天后,如果出现相同的ID和项目,则应再启动一个SUM(),并再使用30天。

经过大量的质量检查和协助,我遇到了一个我无法解决的错误-我将不胜感激任何人的时间,并请您提供解决方案。

输入数据帧为:

ID  Project Amount  Start Date
2345    251 3       3/20/17
3456    251 50      4/10/17
1234    203 75      4/12/17
1234    203 100     4/13/17
2345    251 4       4/16/17
3456    251 125     4/28/17
3456    251 300     4/28/17
3456    251 50      3/22/18
3456    251 100     3/23/18
1234    203 1       5/29/18
1234    203 2       5/29/18
1234    203 29.65   5/29/18
3456    251 43.75   6/5/18

预期输出:

ID  Project Period  Amount
1234    203 0       175
1234    203 9       32.65
2345    251 0       7
3456    251 0       475
3456    251 7       150
3456    251 9       43.75

实际输出:

ID  Project Period  Amount
1234    203 0       175
1234    203 9       32.65
2345    251 0       7
3456    251 0       50
3456    251 5       425
3456    251 7       150
3456    251 9       43.75

如您所见,425和50由于某种原因未加在一起。实际应该显示475,分别是4/10/17的50,4/28/17的125和4/28/17的300。

我也尝试过通过Project也进行“ sort_values”操作,但这没有用。再次感谢任何帮助,谢谢!

1 个答案:

答案 0 :(得分:1)

您基本上正在看一个孤岛问题。对于具有相同IDProject的行,一个“岛”跨越30天。 Start Date在此期间落入的任何行都被分组到同一岛。否则,他们将开始一个新的“岛屿”。

def summarize(x):
    date = x['Start Date'].iloc[0]
    islands = [date]
    gap = pd.Timedelta(days=30)

    for d in x['Start Date'].iloc[1:]:
        date = d if (d - date) > gap else date
        islands.append(date)

    return x.groupby(islands).agg({
        'Amount': 'sum'
    })

df.sort_values('Start Date').groupby(['ID', 'Project']).apply(summarize)

输出:

                         Amount
ID   Project                   
1234 201     2018-07-16  100.00
     203     2017-04-13  200.00
             2018-05-29   81.65
             2018-07-01  645.34
2345 203     2018-08-13   95.12
             2019-04-12   10.00
     251     2017-04-11    7.00
3456 251     2018-03-23  150.00
             2018-06-05   43.75