【问题标题】:Pandas groupby get filtered sum over total sumPandas groupby 在总和上获得过滤总和
【发布时间】:2020-02-25 15:37:18
【问题描述】:

我有以下数据框:

df = pd.DataFrame([[1, 2, True], [1, 4, False], [2, 6, False], [2, 8, True]], columns=["Group", "Value", "C"])

   Group  Value      C
0      1      2   True
1      1      4  False
2      2      6  False
3      2      8   True

而且我希望每个组都知道 C 等于 true 的值的总和与值的总和之间的总和。因此,例如对于第 1 组,我们有 2 / (2+4)

我已经通过一些广泛的搜索来达到以下阶段:

df.groupby('Group').agg(lambda x: x.loc[x.C == True, 'Value'].sum() / x.Value.sum())

          Value         C
Group                    
1      0.333333  0.333333
2      0.571429  0.571429

但是(正如预期的那样)我得到两列,我只想得到一个。我的理想结果是:

       Ratio        
Group                    
1      0.333333  
2      0.571429  

我当然可以在 groupby 之后进行一些修改并得到我想要的,但由于我是 Python 新手,我想知道我是否在这里遗漏了一些基本的东西。

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    我相信您可以在 groupby.transform() 上使用除法和 sum 并在过滤后使用 .assign() 进行分配,以便在 ythe 索引上对齐:

    df[df['C']].assign(Ratio=df['Value']/df.groupby('Group')['Value'].transform('sum'))
    

    如果每组超过 1 个 True,请使用:

    m=(df.groupby(['Group','C'],as_index=False,sort=False)['Value'].sum()
      .query('C==True').assign(Sum=df.groupby(['Group'])['Value'].transform('sum')))
    m[['Group']].assign(Ratio=m['Value']/m['Sum'])
    

       Group     Ratio
    0      1  0.333333
    3      2  0.571429
    

    【讨论】:

      【解决方案2】:

      您可以除以所有行的聚合过滤行,然后将Series转换为一列DataFrame

      filt = df.loc[df['C']].groupby('Group')['Value'].sum()
      tot = df.groupby('Group')['Value'].sum()
      df1 = filt.div(tot, fill_value=0).to_frame('ratio')
      print (df1)
                ratio
      Group          
      1      0.333333
      2      0.571429
      

      您的解决方案可以通过将 .agg 将所有列更改为 GroupBy.apply 以返回 Series 来实现,但如果数据量大/许多独特的组应该很慢:

      df = (df.groupby('Group')
              .apply(lambda x: x.loc[x.C, 'Value'].sum() / x.Value.sum())
              .to_frame('ratio'))
      print (df)
                ratio
      Group          
      1      0.333333
      2      0.571429
      

      解决方案也适用于仅False 组:

      df = pd.DataFrame([[0, 2, False], [1, 2, True], [1, 4, False], 
                         [2, 6, False], [2, 8, True]], columns=["Group", "Value", "C"])
      
      
      df1 = (df.groupby('Group')
              .apply(lambda x: x.loc[x.C, 'Value'].sum() / x.Value.sum())
              .to_frame('ratio'))
      print (df1)
                ratio
      Group          
      0      0.000000
      1      0.333333
      2      0.571429
      
      filt = df.loc[df['C']].groupby('Group')['Value'].sum()
      tot = df.groupby('Group')['Value'].sum()
      
      print (df1)
                ratio
      Group          
      0      0.000000
      1      0.333333
      2      0.571429
      

      【讨论】:

        【解决方案3】:

        你可以使用apply:

        result = df.groupby('Group').apply(lambda x: pd.Series({'ratio' : (x.Value * x.C).sum() / x.Value.sum()}))
        print(result)
        

        输出

                  ratio
        Group          
        1      0.333333
        2      0.571429
        

        【讨论】:

          猜你喜欢
          • 2017-10-20
          • 2018-03-07
          • 1970-01-01
          • 2019-06-08
          • 2014-05-04
          • 1970-01-01
          • 2019-08-11
          相关资源
          最近更新 更多