Python 熊猫的多指标排序

Python 熊猫的多指标排序,python,sorting,pandas,multi-index,Python,Sorting,Pandas,Multi Index,我有一个通过groupby操作创建的多索引数据帧。我试图使用多个级别的索引进行复合排序,但似乎找不到满足我需要的排序函数 初始数据集如下所示(各种产品的每日销售计数): 我使用groupby获得日期范围内的总和: > grouped = df.groupby(['Manufacturer', 'Product Name', 'Product Launch Date']).sum() Sales M

我有一个通过groupby操作创建的多索引数据帧。我试图使用多个级别的索引进行复合排序,但似乎找不到满足我需要的排序函数

初始数据集如下所示(各种产品的每日销售计数):

我使用groupby获得日期范围内的总和:

> grouped = df.groupby(['Manufacturer', 'Product Name', 'Product Launch Date']).sum()
                                               Sales
Manufacturer Product Name Product Launch Date       
Apple        iPad         2010-04-03              30
             iPod         2001-10-23              34
Samsung      Galaxy       2009-04-27              24
             Galaxy Tab   2010-09-02              22
到目前为止还不错

现在,我最不想做的事情是按发布日期对每个制造商的产品进行排序,但要将它们按制造商的级别进行分组-我想做的就是:

                                               Sales
Manufacturer Product Name Product Launch Date       
Apple        iPod         2001-10-23              34
             iPad         2010-04-03              30
Samsung      Galaxy       2009-04-27              24
             Galaxy Tab   2010-09-02              22
当我尝试sortlevel()时,我失去了以前的公司等级制度:

> grouped.sortlevel('Product Launch Date')
                                               Sales
Manufacturer Product Name Product Launch Date       
Apple        iPod         2001-10-23              34
Samsung      Galaxy       2009-04-27              24
Apple        iPad         2010-04-03              30
Samsung      Galaxy Tab   2010-09-02              22
sort()和sort_index()失败:

grouped.sort(['Manufacturer','Product Launch Date'])
KeyError: u'no item named Manufacturer'

grouped.sort_index(by=['Manufacturer','Product Launch Date'])
KeyError: u'no item named Manufacturer'
看起来是个简单的手术,但我不太明白

我不想为此使用多索引,但因为groupby()返回的是多索引,所以我一直在使用多索引

顺便说一句,生成初始数据帧的代码是:

data = {
  'Date': ['2013-01-01', '2013-01-01', '2013-01-01', '2013-01-01', '2013-01-02', '2013-01-02', '2013-01-02', '2013-01-02'],
  'Manufacturer' : ['Apple', 'Apple', 'Samsung', 'Samsung', 'Apple', 'Apple', 'Samsung', 'Samsung',],
  'Product Name' : ['iPod', 'iPad', 'Galaxy', 'Galaxy Tab', 'iPod', 'iPad', 'Galaxy', 'Galaxy Tab'], 
  'Product Launch Date' : ['2001-10-23', '2010-04-03', '2009-04-27', '2010-09-02','2001-10-23', '2010-04-03', '2009-04-27', '2010-09-02'],
  'Sales' : [12, 13, 14, 15, 22, 17, 10, 7]
}
df = DataFrame(data, columns=['Date', 'Manufacturer', 'Product Name', 'Product Launch Date', 'Sales'])

黑客可能会改变级别的顺序:

In [11]: g
Out[11]:
                                               Sales
Manufacturer Product Name Product Launch Date
Apple        iPad         2010-04-03              30
             iPod         2001-10-23              34
Samsung      Galaxy       2009-04-27              24
             Galaxy Tab   2010-09-02              22

In [12]: g.index = g.index.swaplevel(1, 2)
Sortlevel,它(如您所发现的)按顺序对多索引级别进行排序:

In [13]: g = g.sortlevel()
并调回:

In [14]: g.index = g.index.swaplevel(1, 2)

In [15]: g
Out[15]:
                                               Sales
Manufacturer Product Name Product Launch Date
Apple        iPod         2001-10-23              34
             iPad         2010-04-03              30
Samsung      Galaxy       2009-04-27              24
             Galaxy Tab   2010-09-02              22
我认为sortlevel不应按顺序对其余标签进行排序,因此会产生github问题。:)虽然值得一提的是docnote

注意:您可以通过重新排列初始groupby的顺序来避免第一个
swaplevel

g = df.groupby(['Manufacturer', 'Product Launch Date', 'Product Name']).sum()

如果您想避免在非常深的多重索引中进行多重交换,您也可以尝试以下方法:

  • 按级别X进行切片(按列表理解+.loc+索引)
  • 按所需级别排序(sortlevel(2))
  • 连接每一组X级索引
  • 这里有代码:

    import pandas as pd
    idx = pd.IndexSlice
    g = pd.concat([grouped.loc[idx[i,:,:],:].sortlevel(2) for i in grouped.index.levels[0]])
    g
    

    如果您不关心保存索引(我通常更喜欢一个任意整数索引),您可以使用以下一个线性函数:

    grouped.reset_index().sort(["Manufacturer","Product Launch Date"])
    

    这一行适合我:

    In [1]: grouped.sortlevel(["Manufacturer","Product Launch Date"], sort_remaining=False)
    
                                                   Sales
    Manufacturer Product Name Product Launch Date       
    Apple        iPod         2001-10-23              34
                 iPad         2010-04-03              30
    Samsung      Galaxy       2009-04-27              24
                 Galaxy Tab   2010-09-02              22
    
    请注意,这也适用于:

    groups.sortlevel([0,2], sort_remaining=False)
    

    这在两年前你最初发布的时候是行不通的,因为sortlevel在默认情况下是根据所有的索引排序的,这些索引会破坏你公司的等级结构。去年添加了禁用该行为的sort_。这里有一个提交链接供参考:

    要按“索引列”(又名.levels)对多索引进行排序,需要使用该方法并设置其
    level
    参数。如果要按多个级别排序,则需要将参数设置为按顺序排列的级别名称列表

    这将为您提供所需的数据帧:

    df.groupby(['Manufacturer',
                'Product Name', 
                'Launch Date']
              ).sum().sort_index(level=['Manufacturer','Launch Date'])
    

    “数据将按所选级别按字典顺序排序,然后按其他级别(顺序)”(这太糟糕了…)表明需要对级别进行排序,尽管这显然只是一个实现细节。现在还不清楚这是否意味着它们必须从最高索引级别到最低索引级别进行分层排序。@BrenBarn这是一个很好的观点,我以前听Jeff说过……:)顺便说一句,您能否通过按交换顺序执行初始groupby(然后在组后旋转)来消除解决方案中额外的交换/排序?@BrenBarn谢谢(将提及此)!:)感谢您发布更新的答案。我有一个三级多索引,只想按前两级排序。这非常有效。您还可以使用布尔值列表设置
    升序
    参数,以分别控制每个级别的方向。e、 g.
    .sort_index(级别=['Manufacturer','LaunchDate',升序=[True,False])
    df.groupby(['Manufacturer',
                'Product Name', 
                'Launch Date']
              ).sum().sort_index(level=['Manufacturer','Launch Date'])