数据透视表中每个级别的小计

Posted

技术标签:

【中文标题】数据透视表中每个级别的小计【英文标题】:Subtotal for each level in Pivot table 【发布时间】:2019-02-16 09:47:06 【问题描述】:

我正在尝试创建一个数据透视表,除了一般总计之外,每个行级别之间还有一个小计。

我创建了我的 df。

import pandas as pd
df = pd.DataFrame(
    np.array([['SOUTH AMERICA', 'BRAZIL', 'SP', 500],
             ['SOUTH AMERICA', 'BRAZIL', 'RJ', 200],
             ['SOUTH AMERICA', 'BRAZIL', 'MG', 150],
             ['SOUTH AMERICA', 'ARGENTINA', 'BA', 180],
             ['SOUTH AMERICA', 'ARGENTINA', 'CO', 300],
             ['EUROPE', 'SPAIN', 'MA', 400],
             ['EUROPE', 'SPAIN', 'BA', 110],
             ['EUROPE', 'FRANCE', 'PA', 320],
             ['EUROPE', 'FRANCE', 'CA', 100],
             ['EUROPE', 'FRANCE', 'LY', 80]], dtype=object),
    columns=["CONTINENT", "COUNTRY","LOCATION","POPULATION"]
)

之后我创建了如下所示的数据透视表

table = pd.pivot_table(df, values=['POPULATION'], index=['CONTINENT', 'COUNTRY', 'LOCATION'], fill_value=0, aggfunc=np.sum, dropna=True)
table

为了做小计,我开始总结 CONTINENT 级别

tab_tots = table.groupby(level='CONTINENT').sum()
tab_tots.index = [tab_tots.index, ['Total'] * len(tab_tots)]

并与我的第一个枢轴连接以获得小计。

pd.concat([table, tab_tots]).sort_index()

得到它:

我怎样才能像第一个表一样获得按级别分隔的值?

我没有找到办法。

【问题讨论】:

看看这个 SO 帖子***.com/a/52209189/6361531。 【参考方案1】:

使用margins=True,并且需要更改您的pivot indexcolumns 的一点点。

newdf=pd.pivot_table(df, index=['CONTINENT'],values=['POPULATION'], columns=[ 'COUNTRY', 'LOCATION'], aggfunc=np.sum, dropna=True,margins=True)
newdf.drop('All').stack([1,2])
Out[132]: 
                                  POPULATION
CONTINENT     COUNTRY   LOCATION            
EUROPE        All                     1010.0
              FRANCE    CA             100.0
                        LY              80.0
                        PA             320.0
              SPAIN     BA             110.0
                        MA             400.0
SOUTH AMERICA ARGENTINA BA             180.0
                        CO             300.0
              All                     1330.0
              BRAZIL    MG             150.0
                        RJ             200.0
                        SP             500.0

【讨论】:

【参考方案2】:

IIUC:

contotal = table.groupby(level=0).sum().assign(COUNTRY='TOTAL', LOCATION='').set_index(['COUNTRY','LOCATION'], append=True)
coutotal = table.groupby(level=[0,1]).sum().assign(LOCATION='TOTAL').set_index(['LOCATION'], append=True)

df_out = (pd.concat([table,contotal,coutotal]).sort_index())
df_out

输出:

                                  POPULATION
CONTINENT     COUNTRY   LOCATION            
EUROPE        FRANCE    CA               100
                        LY                80
                        PA               320
                        TOTAL            500
              SPAIN     BA               110
                        MA               400
                        TOTAL            510
              TOTAL                     1010
SOUTH AMERICA ARGENTINA BA               180
                        CO               300
                        TOTAL            480
              BRAZIL    MG               150
                        RJ               200
                        SP               500
                        TOTAL            850
              TOTAL                     1330

【讨论】:

所有其他方式都可以进行一些自定义。但对我来说这是最客观和正确的答案,完美的谢谢你!【参考方案3】:

你想做这样的事情

tab_tots.index = [tab_tots.index, ['Total'] * len(tab_tots), [''] * len(tab_tots)]

这给出了我认为你追求的以下内容

In [277]: pd.concat([table, tab_tots]).sort_index()
Out[277]:
                                  POPULATION
CONTINENT     COUNTRY   LOCATION
EUROPE        FRANCE    CA               100
                        LY                80
                        PA               320
              SPAIN     BA               110
                        MA               400
              Total                     1010
SOUTH AMERICA ARGENTINA BA               180
                        CO               300
              BRAZIL    MG               150
                        RJ               200
                        SP               500
              Total                     1330

请注意,虽然这解决了您的问题,但它在风格上并不是好的编程。您的总和级别的逻辑不一致。

这对于 UI 界面来说是有意义的,但如果您正在使用数据,也许使用它会更好

tab_tots.index = [tab_tots.index, ['All'] * len(tab_tots), ['All'] * len(tab_tots)]

这遵循 SQL 表逻辑,会给你

In [289]: pd.concat([table, tab_tots]).sort_index()
Out[289]:
                                  POPULATION
CONTINENT     COUNTRY   LOCATION
EUROPE        All       All             1010
              FRANCE    CA               100
                        LY                80
                        PA               320
              SPAIN     BA               110
                        MA               400
SOUTH AMERICA ARGENTINA BA               180
                        CO               300
              All       All             1330
              BRAZIL    MG               150
                        RJ               200
                        SP               500

【讨论】:

非常感谢亚历山大!但是,如果我也想要 COUNTRY 的小计,我该怎么做呢? tab_tots = table.groupby(level=['CONTINENT', 'COUNTRY']).sum() 我已经尝试不重做您的代码。而是以您自己的方法选择需要更改的单件,以便您更好地理解它。让我知道这是否有帮助

以上是关于数据透视表中每个级别的小计的主要内容,如果未能解决你的问题,请参考以下文章

熊猫数据透视表中的小计

您可以对数据透视表中的行和/或列进行小计吗?

如何使用 vba 从具有多个数据字段的 excel 数据透视表中删除小计

Excel 数据透视表:将小计乘以标量

排除元素的 Excel 数据透视表小计

使用数据透视表(熊猫)中的小计行时保留索引部分(不同的列)