具有多索引的 Pandas 数据透视表小计

Posted

技术标签:

【中文标题】具有多索引的 Pandas 数据透视表小计【英文标题】:Pandas pivot table subtotals with multi-index 【发布时间】:2020-10-17 16:31:45 【问题描述】:

我正在尝试使用 Excel 样式的小计创建一个简单的数据透视表,但是我找不到使用 Pandas 的方法。我已经尝试过 Wes 在另一个与小计相关的问题中建议的解决方案,但这并没有给出预期的结果。下面是重现它的步骤:

创建示例数据:

sample_data = 'customer': ['A', 'A', 'A', 'B', 'B', 'B', 'A', 'A', 'A', 'B', 'B', 'B'], 'product': ['astro','ball','car','astro','ball', 'car', 'astro', 'ball', 'car','astro','ball','car'],
'week': [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2],
'qty': [10, 15, 20, 40, 20, 34, 300, 20, 304, 23, 45, 23]

df = pd.DataFrame(sample_data)

创建带有边距的数据透视表(它只有总计,没有客户(A,B)的小计)

piv = df.pivot_table(index=['customer','product'],columns='week',values='qty',margins=True,aggfunc=np.sum)

    week           1    2   All
customer    product         
A   astro         10    300 310
    ball          15    20  35
    car           20    304 324
B   astro         40    23  63
    ball          20    45  65
    car           34    23  57
All              139    715 854

然后,我尝试了Wes Mckiney在另一个线程中提到的方法,使用stack函数:

piv2 = df.pivot_table(index='customer',columns=['week','product'],values='qty',margins=True,aggfunc=np.sum)

piv2.stack('product')

结果具有我想要的格式,但带有“全部”的行没有总和:

    week               1    2   All
customer    product         
A                    NaN    NaN    669.0
        astro       10.0    300.0   NaN
        ball        15.0    20.0    NaN
        car         20.0    304.0   NaN
B                    NaN    NaN    185.0
        astro        40.0   23.0    NaN
        ball         20.0   45.0    NaN
        car         34.0    23.0    NaN
All                  NaN    NaN     854.0
        astro        50.0   323.0   NaN
        ball         35.0   65.0    NaN
        car         54.0    327.0   NaN

如何使它像在 Excel 中一样工作,示例如下?所有小计和总计工作?我错过了什么?编 excel sample

只是指出,我可以在每次迭代时使用客户的 For 循环过滤并稍后连接,但我希望可能有更直接的解决方案,谢谢

【问题讨论】:

【参考方案1】:

您可以一步完成,但由于字母排序,您必须对索引名称保持战略性:

piv = df.pivot_table(index=['customer','product'],
                     columns='week',
                     values='qty',
                     margins=True,
                     margins_name='Total',
                     aggfunc=np.sum)

(pd.concat([piv, 
            piv.query('customer != "Total"')
               .sum(level=0)
               .assign(product='total')
               .set_index('product', append=True)])
   .sort_index())

输出:

week                1    2  Total
customer product                 
A        astro     10  300    310
         ball      15   20     35
         car       20  304    324
         total     45  624    669
B        astro     40   23     63
         ball      20   45     65
         car       34   23     57
         total     94   91    185
Total             139  715    854

【讨论】:

嗨,Scott,简单而优雅的解决方案,它在我的真实数据框中工作得很好。你能推荐一些材料,让我更多地了解你为找出解决方案所采取的步骤吗?非常感谢 你好,克莱顿。我从回答 Stack Overflow 上的问题中学到了这些步骤。但是,www.dunderdata.com 有一些很棒的培训信息。 @ScottBoston 如何访问一个值,例如 [B, Total] (output=63) 中的值? @elsadek 使用元组。 df.loc[('B','total'), :] @ScottBoston 谢谢,刚刚发现在多索引数据帧中使用元组。【参考方案2】:

@Scott Boston 的回答完美而优雅。作为参考,如果您只对客户和pd.concat() 进行分组,结果是我们得到以下结果。

piv = df.pivot_table(index=['customer','product'],columns='week',values='qty',margins=True,aggfunc=np.sum)
piv3 =  df.pivot_table(index=['customer'],columns='week',values='qty',margins=True,aggfunc=np.sum)
piv4 = pd.concat([piv, piv3], axis=0)

piv4
week    1   2   All
(A, astro)  10  300 310
(A, ball)   15  20  35
(A, car)    20  304 324
(B, astro)  40  23  63
(B, ball)   20  45  65
(B, car)    34  23  57
(All, ) 139 715 854
A   45  624 669
B   94  91  185
All 139 715 854

【讨论】:

这也是我很高兴刚刚了解到的另一种可能性。谢谢

以上是关于具有多索引的 Pandas 数据透视表小计的主要内容,如果未能解决你的问题,请参考以下文章

Pandas 数据透视表行小计

Pandas Pivot Table - 重新组织多索引的顺序

多索引数据框到带有新列的数据透视表

对多索引数据透视表 pandas 进行排序

Pandas 数据透视表和小计

结合 pandas 数据透视表多索引标题 - 一个时间戳,一个字符串