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

时间:2018-09-11 20:08:55

标签: python-3.x pandas pivot-table subtotal

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

我创建了我的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

enter image description here

要做小计,我开始求和CONTINENT级别

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

enter image description here

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

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

得到了: enter image description here

我如何像第一个表格一样将值分隔成多个级别?

我没有找到一种方法。

3 个答案:

答案 0 :(得分:3)

使用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

答案 1 :(得分:2)

您想改成这样

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

答案 2 :(得分: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