使用数据透视表(熊猫)中的小计行时保留索引部分(不同的列)

Posted

技术标签:

【中文标题】使用数据透视表(熊猫)中的小计行时保留索引部分(不同的列)【英文标题】:Keeping index section (different columns) when subtotal row in pivot table (pandas) is used 【发布时间】:2018-06-03 12:14:27 【问题描述】:

我正在尝试在数据透视表中添加小计行(使用 pandas pd.pivot_table)。这是代码table = pd.pivot_table(df, values= ['Quantity', 'Money', 'Cost'], index=['house','date', 'currency', 'family name'], columns=[], fill_value=0, aggfunc=np.sum)。这是对应的输出(导出到excel):

然后,我尝试使用house 作为参考来获取小计行。我按照此链接Pivot table subtotals in Pandas 中所述的步骤操作,所以我使用tablesum = table.groupby(level='house').sum() 创建了一个组。在我尝试连接 tabletablesum 数据帧之前,一切似乎都很好。这就是我得到的(对于 A 家庭):

基本上,我只在一列(用逗号分隔)中获得了表格索引中所述的四个类别(房屋、日期、货币、姓氏)。所以,即使我按房子得到小计,我也失去了 pivot_table 的分离。所以,我的问题是:我怎样才能保留它(在不同的列中维护 pivot_table 的索引)?

任何帮助将不胜感激。

问候,

pd:我还检查了这个链接Sub Total in pandas pivot Table,但这给了我另一种与字符串和数字相关的错误。

【问题讨论】:

你能提供一些测试数据来说明发生了什么吗? 我完全编辑答案,请检查。 【参考方案1】:

您可以使用4 级别创建自定义MultiIndex,然后进行分配。

注意:二级date必须转换为字符串,因为concat也与字符串,否则得到:

TypeError:无法将类型“时间戳”与类型“str”进行比较

df = pd.DataFrame('house':list('aaaaabbbbb'),
                   'date':['2015-01-01'] * 3 + ['2015-01-02'] * 2 + 
                          ['2015-01-01'] * 3 +['2015-01-02'] * 2,
                   'currency':['USD'] * 3 + ['NK'] * 2 + ['USD'] * 3 +['NK'] * 2,
                   'Quantity':[1,3,5,7,1,0,7,2,3,9],
                   'Money':[5,3,6,9,2,4,7,2,3,9],
                   'Cost':[5,3,6,9,2,4,7,2,3,9],
                   'family name':list('aabbccaabb'))

print (df)
   Cost  Money  Quantity currency        date family name house
0     5      5         1      USD  2015-01-01           a     a
1     3      3         3      USD  2015-01-01           a     a
2     6      6         5      USD  2015-01-01           b     a
3     9      9         7       NK  2015-01-02           b     a
4     2      2         1       NK  2015-01-02           c     a
5     4      4         0      USD  2015-01-01           c     b
6     7      7         7      USD  2015-01-01           a     b
7     2      2         2      USD  2015-01-01           a     b
8     3      3         3       NK  2015-01-02           b     b
9     9      9         9       NK  2015-01-02           b     b

#convert only for subtotal - join with empty strings
df['date'] = df['date'].astype(str)

table = pd.pivot_table(df, values= ['Quantity', 'Money', 'Cost'], 
                       index=['house','date', 'currency', 'family name'], 
                       fill_value=0, 
                       aggfunc=np.sum)
print (table)
                                       Cost  Money  Quantity
house date       currency family name                       
a     2015-01-01 USD      a               8      8         4
                          b               6      6         5
      2015-01-02 NK       b               9      9         7
                          c               2      2         1
b     2015-01-01 USD      a               9      9         9
                          c               4      4         0
      2015-01-02 NK       b              12     12        12

tablesum = table.groupby(level='house').sum()

tablesum.index = pd.MultiIndex.from_arrays([tablesum.index.get_level_values(0)+ '_sum', 
                                            len(tablesum.index) * [''],
                                            len(tablesum.index) * [''],
                                            len(tablesum.index) * ['']])

print (tablesum)
          Cost  Money  Quantity
a_sum       25     25        17
b_sum       25     25        21

print (tablesum.index)
MultiIndex(levels=[['a_sum', 'b_sum'], [''], [''], ['']],
           labels=[[0, 1], [0, 0], [0, 0], [0, 0]])


df = pd.concat([table, tablesum]).sort_index(level=0)
print (df)
                                       Cost  Money  Quantity
house date       currency family name                       
a     2015-01-01 USD      a               8      8         4
                          b               6      6         5
      2015-01-02 NK       b               9      9         7
                          c               2      2         1
a_sum                                    25     25        17
b     2015-01-01 USD      a               9      9         9
                          c               4      4         0
      2015-01-02 NK       b              12     12        12
b_sum                                    25     25        21

【讨论】:

谢谢!关于这一点,我想问你另一个问题。我为 house ''a': 10, 'b': 100 '' 创建了一个字典。是否可以使用 map 将其链接到新的数据框(df)。我正在尝试,但出现错误:'Key error house'【参考方案2】:

您可以在 goupby 之后使用 transform 保持原始表格布局。所以下面可能会给你想要的结果。

table.groupby(level='house').transform("sum") 

如果这不是您想要的,请澄清。

https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.transform.html

【讨论】:

以上是关于使用数据透视表(熊猫)中的小计行时保留索引部分(不同的列)的主要内容,如果未能解决你的问题,请参考以下文章

如何删除熊猫数据透视表中的多级索引

从 R 中的数据透视表库呈现的数据透视表中删除小计和总计

数据透视表不显示小计

您可以对数据透视表中的行和/或列进行小计吗?

排除元素的 Excel 数据透视表小计

Excel 数据透视表:将小计乘以标量