【问题标题】:Cumulative sum of first occurence of consecutive True values in a group in PandasPandas 组中第一次出现连续真值的累积和
【发布时间】:2021-11-02 03:44:21
【问题描述】:

我有一个 Pandas 数据框列 A、B、C 和 D。我希望所需列如下:

按 ['A','B','C'] 分组,我希望所需列显示 FIRST CONSECUTIVE True 值的累积总和在 D 列中。

A B C D Desired Column
100 AAA 001 False 0
100 AAA 001 False 0
200 BBB 055 True 1
200 BBB 055 True 2
200 BBB 055 True 3
200 BBB 055 False 3
200 BBB 055 True 3
300 CCC 099 False 0
300 CCC 099 True 0

False 值停止组中的累积总和,并且不考虑 False 之后的任何 True 值。

我想用这张表来计算一个汇总表:

A B C Max(Desired Column)
100 AAA 001 0
200 BBB 055 3
300 CCC 099 0

感谢您的帮助!

【问题讨论】:

    标签: python pandas dataframe pandas-groupby cumulative-sum


    【解决方案1】:

    我在您的示例数据中添加了一个组,以包括该组以不连续的True 开头,后跟False 的情况。

    df.expanding.min()cummin 相同,但min_periods 控制在多少行之后开始累积。 bfill 在每个组的第一行中相应地填充 nan 值。

    df['actual'] = (df.groupby(['A','B','C']).D
                      .apply(lambda x: x.expanding(min_periods=2)
                                        .min()
                                        .bfill()
                                        .cumsum())
                      .astype('int'))
    
    assert df.actual.equals(df.Desired), 'different results, try again'
    df
    

    输出

          A    B    C      D  Desired  actual
    0   100  AAA    1  False        0       0
    1   100  AAA    1  False        0       0
    2   200  BBB   55   True        1       1
    3   200  BBB   55   True        2       2
    4   200  BBB   55   True        3       3
    5   200  BBB   55  False        3       3
    6   200  BBB   55   True        3       3
    7   300  CCC   99  False        0       0
    8   300  CCC   99   True        0       0
    9   400  DDD  199   True        0       0
    10  400  DDD  199  False        0       0
    

    准备示例数据框

    import pandas as pd
    import io
    
    t = '''
    A,B,C,D,Desired
    100,AAA,1,False,0
    100,AAA,1,False,0
    200,BBB,55,True,1
    200,BBB,55,True,2
    200,BBB,55,True,3
    200,BBB,55,False,3
    200,BBB,55,True,3
    300,CCC,99,False,0
    300,CCC,99,True,0
    400,DDD,199,True,0
    400,DDD,199,False,0
    '''
    
    df = pd.read_csv(io.StringIO(t))
    df
    

    输出

          A    B    C      D  Desired
    0   100  AAA    1  False        0
    1   100  AAA    1  False        0
    2   200  BBB   55   True        1
    3   200  BBB   55   True        2
    4   200  BBB   55   True        3
    5   200  BBB   55  False        3
    6   200  BBB   55   True        3
    7   300  CCC   99  False        0
    8   300  CCC   99   True        0
    9   400  DDD  199   True        0
    10  400  DDD  199  False        0
    

    获取每个组的最大行数

    df.groupby(['A','B','C']).actual.max().reset_index()
    

    输出

         A    B    C  actual
    0  100  AAA    1       0
    1  200  BBB   55       3
    2  300  CCC   99       0
    3  400  DDD  199       0
    

    【讨论】:

    • 很好的扩展演示。但是,如果在第一个序列之后还有另一个单独的 True 序列,这也会增加计数。所以你可能仍然需要cummin 将第一个False 之后的所有内容标记为False
    • 它只计算True,直到第一个False(就像cummin),不管组中的值是什么。如果展开的窗口包含一个False,那么min 总体上是False。为了确保我测试了它,添加了True 行到组BBB。一个缺点是min 将针对相同的值计算多次。复杂度是~O(n^2) vs O(n)cummin
    • 知道了。很酷的解决方案。 +1
    【解决方案2】:

    您可以使用cumminFalse之后的所有值标记为False,然后计算cumsum

    df['Desired Column'] = df.groupby(['A', 'B', 'C']).D.transform(lambda x: x.cummin().cumsum())
    
    df
         A    B   C      D  Desired Column
    0  100  AAA   1  False               0
    1  100  AAA   1  False               0
    2  200  BBB  55   True               1
    3  200  BBB  55   True               2
    4  200  BBB  55   True               3
    5  200  BBB  55  False               3
    6  200  BBB  55   True               3
    7  300  CCC  99  False               0
    8  300  CCC  99   True               0
    

    如果你只需要聚合列,那么你可以找到第一个Falseargmin的索引:

    df.groupby(['A', 'B', 'C'], as_index=False).D.agg(
      lambda x: len(x) if x.all() else x.argmin()
    )
    
         A    B   C  D
    0  100  AAA   1  0
    1  200  BBB  55  3
    2  300  CCC  99  0
    

    【讨论】:

    • 这种情况下cummin可以换成cumprod吗?
    • 是的,我也有同样的想法,但是cumprod,然后我看到了你的答案。直到关于cummin :)
    • 我认为这是意料之中的。在这种情况下,第一个连续的 True 将只有一个 True 值,因此它应该将 sum 设置为 1。@MichaelSzczesny
    • @MichaelSzczesny IMO,一个 True 值仍然可以被视为长度为 1 的序列。但是我们可以等待OP的澄清。
    • 正是我需要的,非常感谢!
    猜你喜欢
    • 2014-05-11
    • 1970-01-01
    • 2019-01-07
    • 2019-11-09
    • 1970-01-01
    • 2021-06-15
    • 2018-05-30
    • 2018-09-02
    • 2019-02-15
    相关资源
    最近更新 更多