【问题标题】: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()

得到它:

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

我没有找到办法。

【问题讨论】:

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


【解决方案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()
    • 我已经尝试不重做您的代码。而是以您自己的方法选择需要更改的单件,以便您更好地理解它。让我知道这是否有帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 2021-11-03
    • 2013-03-12
    相关资源
    最近更新 更多