【问题标题】:Groupby sum and difference of rows in a pandas dataframe熊猫数据框中行的分组总和和差异
【发布时间】:2021-08-04 05:39:18
【问题描述】:

我有一个数据框:

df = pd.DataFrame({ 
    'Metric': ['Total Assets', 'Total Promo', 'Total Assets', 'Total Int'],
    'Product': ['AA', 'AA', 'BB', 'AA'],
    'Risk': ['High', 'High','Low', 'High'],
    '202101': [ 130, 200, 190, 210], 
    '202102': [ 130, 200, 190, 210],
    '202103': [ 130, 200, 190, 210],})

我想对ProductRisk 进行分组,并对Total AssetsTotal Promo 中的条目求和,然后从Total Int 中的条目中减去结果。我可以将所有行与Total Int 乘以-1 并对结果求和。但我想知道是否有直接的方法。

df.groupby(['Product', 'Risk']).sum()

实际数据集很大,将某些行乘以 -1 会引入复杂性

输出如下:

df = pd.DataFrame({ 
    'Product': ['AA', 'BB'],
    'Risk': ['High', 'Low'],
    '202101': [ 120, 190], 
    '202102': [ 120, 190],
    '202103': [ 120, 190],})

【问题讨论】:

  • 我认为将要减去的值乘以 -1 是一种有效且明确的解决方案

标签: pandas pandas-groupby


【解决方案1】:

您可以将 Total Int 行乘以 -1:

df.loc[df['Metric'] == 'Total Int', df.select_dtypes('number').columns] *= -1

# OR

df.loc[df['Metric'] == 'Total Int', df.filter(regex=r'\d{6}').columns] *= -1
>>> df.groupby(['Product', 'Risk']).sum()
              202101  202102  202103
Product Risk
AA      High     120     120     120
BB      Low      190     190     190

【讨论】:

  • 虽然我认为这可能是最好的解决方案,但这被 OP 明确拒绝;) (实际数据集很大,将某些行乘以 -1 会引入复杂性)
  • 尽管如此,如果不是最有效的话,可能是最简单、最明确的!
  • 感谢@mozway 和 corralien。列的名称采用 yyyymm 格式。我按问题编辑。我如何将 df.filter 操作与这些列名一起使用
  • 我更新了我的答案。使用select_dtypes('number')
  • like="2021"regex="\d{6}"
【解决方案2】:

在您的实际数据集中,您是否有任何只有一行的组?如果所有组都多于一行,则以下解决方案将起作用,因此diff() 不会返回nan。这是你的第二行输出不在那里,但我想你的组在你的大数据集中有不止一行。

IIUC,创建一个系列s 区分这两个组,并在sumgroupby 之后取diff

 import pandas as pd
import numpy as np

df = pd.DataFrame({ 
    'Metric': ['Total Assets', 'Total Promo', 'Total Assets', 'Total Int'],
    'Product': ['AA', 'AA', 'BB', 'AA'],
    'Risk': ['High', 'High','Low', 'High'],
    'Col1': [ 130, 200, 190, 210], 
    'Col2': [ 130, 200, 190, 210],
    'Col3': [ 130, 200, 190, 210],})

s = np.where(df['Metric'].isin(['Total Assets', 'Total Promo']), 'B', 'A')

cols = ['Product', 'Risk']
(df.groupby(cols + [s]).sum()
   .groupby(cols).diff()
   .dropna().reset_index().drop('level_2', axis=1))

Out[1]: 
  Product  Risk   Col1   Col2   Col3
0      AA  High  120.0  120.0  120.0

【讨论】:

    【解决方案3】:

    这个解决方案怎么样?

    (df.
     melt(['Metric', 'Product', 'Risk']).
     pivot(index=['Product', 'Risk', 'variable'], columns= 'Metric', values = 'value').
     assign(Total = lambda df: df['Total Assets'].fillna(0)+df['Total Promo'].fillna(0) - df['Total Int'].fillna(0)).
     drop(columns = ['Total Assets', 'Total Promo', 'Total Int']).
     reset_index().
     pivot(index=['Product', 'Risk'], columns= 'variable', values = 'Total')
     )
    

    【讨论】:

      猜你喜欢
      • 2017-12-30
      • 2015-10-09
      • 2020-04-21
      • 2017-02-06
      • 1970-01-01
      • 2014-07-11
      • 2018-04-25
      • 2016-11-08
      • 2019-04-07
      相关资源
      最近更新 更多