【问题标题】:Pandas pivot Table Multi-Layer SortingPandas 数据透视表多层排序
【发布时间】:2021-04-14 16:26:41
【问题描述】:

我已经给出了 df:(已更新):

import pandas as pd
import numpy as np
df = pd.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",
                         "bar", "bar", "bar", "bar","zz","zz"],
                  "B": ["one", "one", "one", "two", "two",
                         "one", "one", "two", "two","xy","zz"],
                   "Name":["Peter", "Amy", "Brian", "Amy", "Amy",
                         "Peter", "Brian", "Peter", "Brian","Brian","Brian"],
                  "Year": [2019, 2019, 2019, 2019,
                         2019, 2019, 2020, 2020,
                          2020,2019,2020],
                  "Values": [20, 4, 20, 5, 6, 6, 8, 9, 9,10,5]})
df_pivot = pd.pivot_table(df, values='Values', index=['Name','A', 'B'],
                    columns=['Year'], aggfunc=np.sum, fill_value=0, margins=True, margins_name="Totals")

一旦我以我喜欢的方式旋转它,它看起来像这样:

 Year            2019  2020  Totals
Name   A   B                      
Amy    foo one     4     0       4
           two    11     0      11
Brian  bar one     0     8       8
           two     0     9       9
       foo one    20     0      20
       zz  xy     10     0      10
           zz      0     5       5
Peter  bar one     6     0       6
           two     0     9       9
       foo one    20     0      20
Totals            71    31     102

现在“有趣”的部分开始了..

我希望这个 df 数据透视表根据值的总和从左到右对所有索引列进行排序。

让我解释一下。

首先,我想按每个名称的“总计”降序按“名称”列对该数据透视表进行排序,因此我将计算 Amy = 15、Brian = 52、Peter = 35 的总和。 由此我知道第一列应该按 Brian/Peter/Amy 排序。

现在我对第二列“A”做同样的事情,但第一列“名称”是固定的。

即对于名称 Brian(在顶部)我现在计算列“A”的总数(我想看看 foo/bar/zz 是否应该是第一个),因此我计算出 Brian-Foo 等于 20 而 Brian-bar 是等于 8+9 并且 Brian-zz 是 15,因此我们希望在第二列中首先为 Brian 设置 Foo ......对于其余索引列也是如此。

输出应如下所示:

Year            2019  2020  Totals
Name   A   B                      
Brian  foo one    20     0      20 
       bar two     0     9       9
           one     0     8       8
       zz  xy     10     0      10
           zz      0     5       5
Peter  foo one    20     0      20
       bar two     0     9       9
           one     6     0       6
Amy    foo two    11     0      11
           one     4     0       4
Totals            71    31     102

长话短说,首先我想根据该列中项目的总数对第一列进行排序并修复它,然后我想对该列中的项目进行第二列排序,但按照第一次排序等进行分组.

你能告诉我怎么做吗? 非常感谢您的帮助!

谢谢 帕维尔

【问题讨论】:

    标签: python pandas pivot


    【解决方案1】:

    您可以使用groupby.transform 获取名称中的总和,然后对其进行排序:

    df_pivot = (df_pivot.iloc[:-1]
                  .assign(sort=lambda x: x['Totals'].groupby(level=0).transform('sum'))
                  .sort_values(['sort','Name','Totals'], 
                               ascending=[False,True,False], kind='mergesort')
                  .drop('sort', axis=1)
                  .append(df_pivot.iloc[-1])
               )
    

    输出:

    Year            2019  2020  Totals
    Name   A   B                      
    Brian  foo one    20     0      20
           bar two     0     9       9
               one     0     8       8
    Peter  foo one    20     0      20
           bar two     0     9       9
               one     6     0       6
    Amy    foo two    11     0      11
               one     4     0       4
    Totals            61    26      87
    

    【讨论】:

    • 亲爱的 Quang Hoang,非常感谢你,我已经在这个 df 上运行了它并且运行良好,但是我确实在我的另一个 df 上运行了它并没有按预期工作。我在原始帖子中修改了 df,以便您可以尝试在新的 df 上运行。正如您从“A”列中的代码中看到的那样,Brian 值“zz”没有分组,但它们应该分组。你能给些建议么?谢谢
    • 您好,请看一下好吗?
    • 使用.sort_values(['sort','Name','A','Totals'] 而不是.sort_values(['sort','Name','A','Totals']
    • 亲爱的@Quang Hoang,我已经调整了公式,还添加了第 4 维进行排序,因为它不会运行,所以它是这样的:df_pivot = (df_pivot.iloc[:-1].assign (sort=lambda x: x['Totals'].groupby(level=0).transform('sum')).sort_values(['sort','Name','A','Totals'],升序= [False,True,False,False], kind='mergesort') .drop('sort', axis=1).append(df_pivot.iloc[-1])) 但它似乎不起作用,df在第一列上正确排序,但在第二列上不正确。 20 的 Brian-Foo 在中间,但应该在顶部。可以请教吗?
    猜你喜欢
    • 2012-05-22
    • 2016-09-15
    • 2016-09-05
    • 1970-01-01
    • 2023-03-29
    • 2019-05-21
    • 2016-09-27
    • 2016-06-10
    • 2017-12-31
    相关资源
    最近更新 更多