Pandas MultiIndex 按分类顺序自定义排序级别,而不是按字母顺序

Pandas MultiIndex custom sort levels by categorical order, not alphabetically

我是 Pandas (0.16.1) 的新手,想在多索引中进行自定义排序,所以我使用分类。 我的多索引的一部分:

Part  Defect Own
Кузов 504    ИП
Кузов 504    Итого
Кузов 504    ПС
Кузов 505    ПС
Кузов 506    ПС
Кузов 507    ПС
Кузов 530    ИП
Кузов 530    Итого
Кузов 530    ПС

我创建了具有 MultiIndex 级别 [缺陷,自己] 的枢轴 table。然后我将 "Own" 分类(参见 p.s. 问题的一部分)将其排序为 [ИП, ПС, Итого]。但是当我在 "Part" 前面添加级别时,这也是基于 "Defect" 级别的分类,并使用

对索引进行排序
pvt.sortlevel(0, inplace=True)

"Own" 级别按字母顺序排序:[ИП, Итого, ПС]。我如何在多索引中自定义排序两个级别?

P. S. 我使用以下代码将 "Own" 级别转换为分类级别:创建新列,用它替换索引级别。可以吗?

def makeLevelCategorical(pdf, pname, cats):
    names = pdf.index.names
    namei = names.index(pname)
    pdf["tmp"] = pd.Categorical(pdf.index.get_level_values(pname), categories=cats) #New temp column
    pdf.set_index("tmp", append=True, inplace=True) #Append column to index
    pdf = pdf.reset_index(pname, drop=True) #Remove /pname/ level
    names2 = list(names)
    names2[namei] = "tmp"
    pdf.reorder_levels(names2)  #Put "tmp" level to /pname/'s position
    pdf.index.names = names     #Rename "tmp" level to /pname/
    return pdf

可以使用 Dataframe.sort_index 函数对多索引进行排序。

这是一个小例子:

df = pd.DataFrame(
    {"i1":[1,1,1,1,2,4,4,2,3,3,3,3],
     "i2":[1,3,2,2,1,1,2,2,1,1,3,2],
     "d1":['a','b','c','d','e','f','g','h','i','j','k','l']}
)
df.set_index(['i1', 'i2'], inplace=True)
df.sort_index()

输出:

        d1
i1  i2  
1   1   a
    2   c
    2   d
    3   b
2   1   e
    2   h
3   1   i
    1   j
    2   l
    3   k
4   1   f
    2   g

如果你想改变基于列的排序顺序,Dataframe.sort_index 函数接受一个参数 ascending=,它可以给出一个列表 [True, False] 语句对应于列订单。

Categorical 是 pandas 中一个新的闪亮数据类型,应该使用它,但本身不需要此操作。

根据评论进行编辑:

排序将始终按字母顺序或倒序排序。如果您想要自定义排序,那么您需要创建一个新列,该列可以按字母顺序排序,但它是可以确定排序的列的结果。使用 Series.map 执行此操作,就像这个例子一样,首先对数据集进行元音排序:

mappings = {'a': 0, 'b':1, 'c':1, 'd':1,
            'e':0, 'f':1, 'g':1, 'h':1,
            'i':0, 'j':1, 'k': 1, 'l': 1}
df['sortby'] = df['d1'].map(mappings)
df.sort('sortby')

        d1  sortby
i1  i2      
1   1   a   0
2   1   e   0
3   1   i   0
1   3   b   1
    2   c   1
    2   d   1
4   1   f   1
    2   g   1
2   2   h   1
3   1   j   1
    3   k   1
    2   l   1

如果你不想要之后的 sortby 列,你可以简单地删除它,像这样:

del df['sortby']