pandas 0.20:如何对具有多级索引的列进行自定义排序?

问题描述

熊猫新手。使用熊猫 0.20,所以没有 CategoricalDtype。在将几个 df 与 concat 合并后,我想对列进行自定义排序。合并后的 df 将具有多级索引列。

使用 Categorical,它不适用于自定义排序。

dfs=[table2,table3,table4]
L_list=['A','B','C']     
test=pd.Categorical(L_list,categories=['B','C','A'],ordered=True)

merged_df = pd.concat(

    dfs,axis=1,keys=pd.MultiIndex.from_arrays([

        test,# Top Level Keys

        ['Cat1','Cat2','Cat1']  # Second Level Keys

    ],names=['Importance','Category'])

)

output=merged_df.sort_index(axis=1,level=[0])

当前状态

**Merged_df**

Importance| A         |  B   | C       |
Category | Cat1       | Cat2 | Cat1    |
         |Total Assets| AUMs | Revenue |
Firm 1   | 100        | 300  | 300     |
Firm 2   | 200        | 3400 | 200     |
Firm 3   | 300        | 800  | 400     |
Firm 4   | NaN        | 800  | 350     |


理想状态

**Merged_df**

Importance|  B   | C       | A            |
Category  | Cat2 | Cat1    | Cat1         |
         |AUMs | Revenue | Total Assets |
Firm 1   | 300  | 300     | 100          |  
Firm 2   | 3400 | 200     | 200          |  
Firm 3   |  800  | 400     | 300          |  
Firm 4   |  800  | 350     | NaN          |  

解决方法

不确定 0.20 的所有可能性,但一个想法是将多索引列转换为框架,将每个级别更改为分类数据(就像您在问题中对 test 所做的那样),然后对数据框进行 sort_values,保留索引是按照您想要重新排列merged_df 列的方式对列进行排序。看看这个例子:

# simple example
dfs=[
    pd.DataFrame({'a':[0,1]},index=[0,1]),pd.DataFrame({'b':[0,pd.DataFrame({'c':[0,]

L_list=['A','B','B'] # changed C to have 2 B with 2 Cat  

merged_df = pd.concat(
    dfs,axis=1,keys=pd.MultiIndex.from_arrays([
        test,# Top Level Keys
        ['Cat1','Cat1','Cat2']  # Second Level Keys
    ],names=['Importance','Category'])
)
print(merged_df)
#      A    B     
#   Cat1 Cat1 Cat2
#      a    b    c
# 0    0    0    0
# 1    1    1    1

所以你可以这样做

# create dataframes of columns names
col_df = merged_df.columns.to_frame()

# change to catagorical each level you want
col_df[0] = pd.Categorical(col_df[0],categories=['B','C','A'],ordered=True)
col_df[1] = pd.Categorical(col_df[1],categories=['Cat2','Cat1'],ordered=True)

# sort values and get the index
print(col_df.sort_values(by=col_df.columns.tolist()).index)
# MultiIndex([('B','Cat2','c'),# B is before A and Cat2 before Cat1
#             ('B','b'),#             ('A','a')],#            )
output = merged_df[col_df.sort_values(by=col_df.columns.tolist()).index]
print(output)  
#      B         A
#   Cat2 Cat1 Cat1
#      c    b    a
# 0    0    0    0
# 1    1    1    1