【问题标题】:How to sum values under GroupBy and consecutive date conditions?如何对 GroupBy 和连续日期条件下的值求和?
【发布时间】:2021-06-19 05:57:07
【问题描述】:

给定表:

ID LINE SITE DATE UNITS TOTAL
1 X AAA 02-May-2017 12 30
2 X AAA 03-May-2017 10 22
3 X AAA 04-May-2017 22 40
4 Z AAA 20-MAY-2017 15 44
5 Z AAA 21-May-2017 8 30
6 Z BBB 22-May-2017 10 32
7 Z BBB 23-May-2017 25 52
8 K CCC 02-Jun-2017 6 22
9 K CCC 03-Jun-2017 4 33
10 K CCC 12-Aug-2017 11 44
11 K CCC 13-Aug-2017 19 40
12 K CCC 14-Aug-2017 30 40

对于每一行,如果 ID、LINE 、SITE 等于前一行(天)需要计算如下(最后一天)和(最后 3 天): 请注意,需要确保 ID、LINE、SITE 列的“groupby”下的日期是连续的

ID LINE SITE DATE UNITS TOTAL Last day Last 3 days
1 X AAA 02-May-2017 12 30 0 0
2 X AAA 03-May-2017 10 22 12/30 12/30
3 X AAA 04-May-2017 22 40 10/22 (10+12)/(30+22)
4 Z AAA 20-MAY-2017 15 44 0 0
5 Z AAA 21-May-2017 8 30 15/44 15/44
6 Z BBB 22-May-2017 10 32 0 0
7 Z BBB 23-May-2017 25 52 10/32 10/32
8 K CCC 02-Jun-2017 6 22 0 0
9 K CCC 03-Jun-2017 4 33 6/22 6/22
10 K CCC 12-Aug-2017 11 44 4/33 0
11 K CCC 13-Aug-2017 19 40 11/44 (11/44)
12 K CCC 14-Aug-2017 30 40 19/40 (11+19/44+40)

【问题讨论】:

    标签: pandas date pandas-groupby shift cumsum


    【解决方案1】:

    在这种情况下,我通常使用 groupby 进行 for 循环:

    import pandas as pd
    import numpy as np
    
    #copied your table
    table = pd.read_csv('/home/fm/Desktop/stackover.csv')
    table.set_index('ID', inplace = True)
    table[['Last day','Last 3 days']] = np.nan
    
    for i,r in table.groupby(['LINE' ,'SITE']):
        #First subset non sequential dates
        limits_interval = pd.to_datetime(r['DATE']).diff() != '1 days'
        #First element is a false positive, as its impossible to calculate past days from first day
        limits_interval.iloc[0]=False
    
        ids_subset = r.index[limits_interval].to_list()
        ids_subset.append(r.index[-1]+1) #to consider all values
        id_start = 0
    
        for id_end in ids_subset:    
            r_sub = r.loc[id_start:id_end-1, :].copy()
            id_start = id_end 
    
            #move all values one day off, if the database is as in your example (1 line per day) wont have problems
            r_shifted = r_sub.shift(1)
    
            r_sub['Last day']=r_shifted['UNITS']/r_shifted['TOTAL']
    
            aux_units_cumsum = r_shifted['UNITS'].cumsum()
            aux_total_cumsum = r_shifted['TOTAL'].cumsum()
    
            r_sub['Last 3 days'] = aux_units_cumsum/aux_total_cumsum
    
            r_sub.fillna(0, inplace = True)
    
            table.loc[r_sub.index,:]=r_sub.copy()
    

    你可以创建一个函数并在 groupby 中应用,它会更干净:Apply function to pandas groupby。它会更优雅。 希望能帮到你,祝你好运

    【讨论】:

    • 嗨,非常感谢。它工作得很好。问题是(正如你提到的)一天并不是所有组都连续的。在我给出的示例中(更新),如果您查看“LINE=K,SITE=CCC 等”日期有差距。
    • 嗨,不客气。 OBS:-如果天是连续的,则应用于日期时间对象的 diff() 函数返回“1 天”。 -我需要附加 r.index[-1]+1 以考虑所有行,+1 补偿 r_sub 分配中的 -1 -.copy() 方法避免熊猫返回视图
    • 还有一件事......我如何将此案例延长到 7 天或“n”天?这个想法是回顾 3,7, n 天并进行计算,即使在 7 天内有一天或两天的间隔。
    • 我认为 rolling 和 timedelta 可能会解决它,但我不知道如何!?
    • limits_interval = pd.to_datetime(r['DATE']).diff() >n n 是 n 天的变量。但我不确定我是否理解你的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    相关资源
    最近更新 更多