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

Cla*_*ria 4 python pivot-table pandas pandas-groupby

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

创建样本数据:

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)
Run Code Online (Sandbox Code Playgroud)

创建带有边距的数据透视表(它只有总计,没有客户 (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
Run Code Online (Sandbox Code Playgroud)

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

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

piv2.stack('product')
Run Code Online (Sandbox Code Playgroud)

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

    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
Run Code Online (Sandbox Code Playgroud)

如何使其像在 Excel 中一样工作,示例如下?所有小计和总计都有效吗?我缺少什么?ed excel 样本

只是为了指出,我可以使用客户在每次迭代中进行的 For 循环过滤并稍后连接来使其工作,但我希望可能有一个更直接的解决方案,谢谢

Sco*_*ton 7

您可以一步完成,但由于按字母顺序排序,您必须对索引名称采取策略:

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())
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)