【问题标题】:Pandas Pivot tables row subtotalsPandas 数据透视表行小计
【发布时间】:2013-03-12 07:05:13
【问题描述】:

我正在使用 Pandas 0.10.1

考虑到这个数据框:

Date       State   City    SalesToday  SalesMTD  SalesYTD
20130320     stA    ctA            20       400      1000
20130320     stA    ctB            30       500      1100
20130320     stB    ctC            10       500       900
20130320     stB    ctD            40       200      1300
20130320     stC    ctF            30       300       800

如何按州对小计进行分组?

State   City  SalesToday  SalesMTD  SalesYTD
  stA    ALL          50       900      2100
  stA    ctA          20       400      1000
  stA    ctB          30       500      1100

我尝试使用数据透视表,但我只能在列中使用小计

table = pivot_table(df, values=['SalesToday', 'SalesMTD','SalesYTD'],\
                     rows=['State','City'], aggfunc=np.sum, margins=True)

我可以通过数据透视表在 excel 上实现这一点。

【问题讨论】:

    标签: python pandas pivot-table


    【解决方案1】:

    您可以通过在 State 列上使用 groupby() 来获取汇总值。

    让我们先做一些示例数据:

    import pandas as pd
    import StringIO
    
    incsv = StringIO.StringIO("""Date,State,City,SalesToday,SalesMTD,SalesYTD
    20130320,stA,ctA,20,400,1000
    20130320,stA,ctB,30,500,1100
    20130320,stB,ctC,10,500,900
    20130320,stB,ctD,40,200,1300
    20130320,stC,ctF,30,300,800""")
    
    df = pd.read_csv(incsv, index_col=['Date'], parse_dates=True)
    

    然后应用 groupby 函数并添加一个列 City:

    dfsum = df.groupby('State', as_index=False).sum()
    dfsum['City'] = 'All'
    
    print dfsum
    
      State  SalesToday  SalesMTD  SalesYTD City
    0   stA          50       900      2100  All
    1   stB          50       700      2200  All
    2   stC          30       300       800  All
    

    我们可以使用 append 将原始数据附加到求和的 df 中:

    dfsum.append(df).set_index(['State','City']).sort_index()
    
    print dfsum
    
                SalesMTD  SalesToday  SalesYTD
    State City                                
    stA   All        900          50      2100
          ctA        400          20      1000
          ctB        500          30      1100
    stB   All        700          50      2200
          ctC        500          10       900
          ctD        200          40      1300
    stC   All        300          30       800
          ctF        300          30       800
    

    我添加了 set_index 和 sort_index 以使其看起来更像您的示例输出,它并不是获得结果所必需的。

    【讨论】:

    • 另一个替代函数是 concat(),它允许我通过设置参数 ignore_index 来更好地控制索引。 pd.concat([x, y], ignore_index=True)。 This article 还提到 concat() 与 pandas.append() 相比效率更高。
    【解决方案2】:

    如果您没有将州和城市都放在行中,您将获得单独的边距。重塑并获得您想要的表格:

    In [10]: table = pivot_table(df, values=['SalesToday', 'SalesMTD','SalesYTD'],\
                         rows=['State'], cols=['City'], aggfunc=np.sum, margins=True)
    
    
    In [11]: table.stack('City')
    Out[11]: 
                SalesMTD  SalesToday  SalesYTD
    State City                                
    stA   All        900          50      2100
          ctA        400          20      1000
          ctB        500          30      1100
    stB   All        700          50      2200
          ctC        500          10       900
          ctD        200          40      1300
    stC   All        300          30       800
          ctF        300          30       800
    All   All       1900         130      5100
          ctA        400          20      1000
          ctB        500          30      1100
          ctC        500          10       900
          ctD        200          40      1300
          ctF        300          30       800
    

    我承认这并不完全明显。

    【讨论】:

    • 如果我们有 values=,如果列是从 columns=... 创建的,这将有效。将只有一个“All”列。
    • @wes-mckinney 对于 0.25.1 版的 pandas,rows 不是参数。我指定了一个 3 列索引,但输出只返回总计,而不是索引列的小计。
    【解决方案3】:

    这个怎么样?

    table = pd.pivot_table(data, index=['State'],columns = ['City'],values=['SalesToday', 'SalesMTD','SalesYTD'],\
                          aggfunc=np.sum, margins=True)
    

    【讨论】:

      【解决方案4】:

      我认为这个小计示例代码是你想要的(类似于 excel 小计)

      我假设您希望按列 A、B、C、D 分组,而不是计算 E 的列值

      main_df.groupby(['A', 'B', 'C']).apply(lambda sub_df: sub_df\
             .pivot_table(index=['D'], values=['E'], aggfunc='count', margins=True)
      

      输出:

      A B C  D  E
             a  1 
      a a a  b  2
             c  2
           all  5
             a  3 
      b b a  b  2
             c  2
           all  7
             a  3 
      b b b  b  6
             c  2
             d  3
           all 14
      

      【讨论】:

      • 以防万一有人过来尝试但省略了margins=True参数:需要获取添加了all的行。
      • @Parfait 在您的示例中是否可以包含总计?
      • @Clickinaway ...这不是我的答案,我只是帮助编辑。但根据pivot_table 规范,您可以获得行小计和列总计。
      • @Parfait 我目前在这方面失败了,整个上午都在看其他 SE 帖子。我的帖子在这里stackoverflow.com/questions/53266032/…
      • 我知道我们不应该感谢别人或赞扬 SO,但这纯粹是天才。这解决了我的问题。谢谢!
      【解决方案5】:
      table = pd.pivot_table(df, index=['A'], values=['B', 'C'], columns=['D', 'E'], fill_value='0', aggfunc=np.sum/'count'/etc., margins=True, margins_name='Total')
      
      print(table)
      

      【讨论】:

        猜你喜欢
        • 2021-11-03
        • 2017-05-13
        • 2019-04-07
        • 2020-05-02
        • 2018-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多