【问题标题】:Pandas: How to include all columns and all indexes for multiple pivot tablePandas:如何包含多个数据透视表的所有列和所有索引
【发布时间】:2021-10-26 20:13:56
【问题描述】:

我正在尝试从以下数据框 (df) 为不同位置创建数据透视表:

Location Category Status Price
1 Furniture New $100
1 Furniture Old $50
2 Office Supplies New $200
1 Furniture New $100
1 Office Supplies New $300
1 Office Supplies Old $150

首先,我使用代码过滤了数据框以将位置 1 和 2 分开:

df1 = df[df['Location'] == 1]

df2 = df[df['Location'] == 2]

接下来我使用了标准的 pandas 数据透视表函数:

pd.pivot_table(df1, values='Price', index='Status', columns='Category', aggfunc=np.sum)

pd.pivot_table(df2, values='Price', index='Status', columns='Category', aggfunc=np.sum)

所以我有以下两个数据透视表作为输出:

位置 1:

Status Furniture Office Supplies
New $200 $300
Old $50 $150

位置 2:

Status Office Supplies
New $200

但是,我希望位置 2 的数据透视表包含所有可能的类别和状态,如果它们不存在,则为 0。总而言之,我想要位置 2 的以下数据透视表:

位置 2:

Status Furniture Office Supplies
New $0 $200
Old $0 $0

我已经查看了 pivot_table() 函数的所有选项,但到目前为止还没有找到解决这个问题的方法。

【问题讨论】:

    标签: python pandas dataframe pivot-table


    【解决方案1】:

    您可以在通过Location分割之前创建数据透视表。

    对于pd.pivot_table

    • index=['Location', 'Status']设置索引
    • 传递参数dropna=False 以允许所有类别显示所有Location 和所有Status,即使为空。 (默认是隐藏空条目)。
    • 传递参数fill_value=0NaN 值填充为0

    然后通过.loc从数据透视表中找到Location,如下:

    df_out = pd.pivot_table(df, 
                            values='Price', 
                            index=['Location', 'Status'], 
                            columns='Category', 
                            aggfunc=np.sum, 
                            dropna=False, 
                            fill_value=0)
    

    结果:

    print(df_out)
    
    Category         Furniture  Office Supplies
    Location Status                            
    1        New           200              300
             Old            50              150
    2        New             0              200
             Old             0                0
    

    那么,要获取只针对Location 2 的数据透视表,可以使用.loc,如下:

    df2 = df_out.loc[2]
    

    输出:

    print(df2)
    
    Category  Furniture  Office Supplies
    Status                              
    New               0              200
    Old               0                0
    

    编辑(用于添加总计和小计)

    如果您还想包含 Total(对于所有 Location)和 Sub-total(对于每个 Location),您也可以这样做,如下:

    对于pd.pivot_table

    • 通过参数margins=Truemargins_name='Total' 设置Total 的边距(所有Location 的总和)
    • pd.pivot_table 之后链接命令fillna(0, downcast='infer')。这是为了处理pd.pivot_table故障/错误,即使fill_value=0 参数时,保证金总额仍将显示NaN 用于空条目(例如Location=2Status='Old' 在这种情况下)已指定。
    df_out = pd.pivot_table(df, 
                            values='Price', 
                            index=['Location', 'Status'], 
                            columns='Category', 
                            aggfunc=np.sum, 
                            dropna=False, 
                            fill_value=0,
                            margins=True,
                            margins_name='Total'
                            ).fillna(0, downcast='infer')
    

    结果

    print(df_out)
    
    Category         Furniture  Office Supplies  Total
    Location Status                                   
    1        New           200              300    500
             Old            50              150    200
    2        New             0              200    200
             Old             0                0      0
    Total                  250              650    900
    

    然后,添加小计(对于每个Location),我们进一步使用:

    (pd.concat([df_out, 
                df_out.query('Location != "Total"')
                      .groupby(level=0).sum()
                      .assign(Status='Sub-total')
                      .set_index('Status', append=True)])
       .sort_index())
    

    结果:

    Category            Furniture  Office Supplies  Total
    Location Status                                      
    1        New              200              300    500
             Old               50              150    200
             Sub-total        250              450    700
    2        New                0              200    200
             Old                0                0      0
             Sub-total          0              200    200
    Total                     250              650    900
    

    【讨论】:

    • @EkaraiGlass 哦,我明白了。您还可以在数据透视表中设置边距。对于小计,建议你看看this post,可能是this post too
    • 第一篇完美解决问题
    • @EkaraiGlass 是的,这是一个非常好的解决方案。我还将编辑我的解决方案以包含这部分。
    • @EkaraiGlass 我还根据我传递给您的参考帖子为您定制了添加小计的代码。你可以看看。 :-)
    • 感谢@SeaBean 提供如此优雅的解决方案
    猜你喜欢
    • 1970-01-01
    • 2017-09-24
    • 2020-08-30
    • 2017-10-04
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多