使用 Pandas 重命名查找字典中的多索引行

Renaming multiindex row from a look up dictionary with Pandas

鉴于当前演示文稿中所示的多级行,我想根据存储在查找字典中的信息重命名第一级索引。

目前,我想转置 df 并循环到现在的 column 名称。此后,将根据字典中存储的信息检查并重命名合适的新列名(即str_dic)。

但是,我想知道是否有更直接的做法?

草拟的代码如下

import pandas as pd

def create_df (idx):
    df = pd.DataFrame ( {'A': [11, 21, 31],
                         'B': [12, 22, 32],
                         'C': [13, 23, 33]},
                        index=['ONE', 'TWO', 'THREE'] )

    df.columns = pd.MultiIndex.from_product ( [['level1'], ['level2'], df.columns] )
    df = df.set_index ( [[f'idx_{idx}'] * len ( df )], append=True ).swaplevel ( 0 )
    # df = df.set_index ( [['temp_general'] * len ( df )], append=True ).swaplevel ( 0 )
    return df

#look up dict
str_g = ['idx_0', 'idx_1', 'idx_2', 'idx_3','idx_4']
str_h = ['E', 'b', 'c', 'd','e']
str_dic = {str_g [i]: str_h [i] for i in range ( len ( str_g ) )}

# create the df
all_df = [create_df ( idx ) for idx in range ( 0, len(str_h)-1)] # Delibarately minus one for worse case scenario
df = pd.concat ( all_df, axis=0 )

df=df.T
all_ls=list(df.columns.values.tolist())
for xss in all_ls:
    df=df.rename ( columns={xss: str_dic[xss[0]]}, level=1) #WIP

当前演示文稿

level1        
            level2        
                 A   B   C
idx_0 ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
idx_1 ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
idx_2 ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
idx_3 ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33

预期输出

            level1        
            level2        
                 A   B   C
a     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
b     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
c     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
d     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33

#######################

奖金: 根据 的建议,我们如何根据另一个查找字典在最高级别上附加另一个级别。

天真地,我会提出这样的建议

df.index =  pd.MultiIndex.from_product ( [s1, df.index.get_level_values ( 0 ).unique (),
                                          df.index.get_level_values ( 1 ).unique ()] )

但它return一个错误

ValueError: Length mismatch: Expected axis has 12 elements, new values have 48 elements

基于Anurag修改的失败提议:

str_global=['typ1','typ1','typ2','typ2','typ3']
global_dic = {str_h [i]: str_global [i] for i in range ( len ( str_h ) )}
s1 = [global_dic.get ( x ) for x in df.index.get_level_values ( 0 ).unique ()]

df.index =  pd.MultiIndex.from_product ( [s1, df.index.get_level_values ( 0 ).unique (),
                                          df.index.get_level_values ( 1 ).unique ()] )

预期输出

                    A   B   C
typ1    E     ONE       11  12  13
              TWO       21  22  23
              THREE     31  32  33
typ1    b     ONE       11  12  13
              TWO       21  22  23
              THREE     31  32  33
 typ2   c     ONE       11  12  13
              TWO       21  22  23
              THREE     31  32  33
 typ2   d     ONE       11  12  13
              TWO       21  22  23
              THREE     31  32  33

让我们尝试使用列表理解将 'level 0' 索引中 str_dic 的键替换为它们的值,然后使用 pd.MultiIndex.from_product() 生成一个 MultiIndex 并将其设置为等于数据帧的索引通过使用 index 属性::

s=[str_dic.get(x) for x in df.index.get_level_values(0).unique()]
df.index=pd.MultiIndex.from_product([s,df.index.get_level_values(1).unique()])

更新:

因为现在你有 4 个唯一的 level0 值和 3 个唯一的 level0 索引以及 s1 中的 4 个值所以 pd.MultiIndex.from_product() 创建 48 对 MultiIndex 所以它在那种情况下没有用所以使用:

s1=[global_dic.get(x) for x in df.index.get_level_values(0)]
df=df.set_index(pd.Series(s1).values,append=True)
df.index=df.index.reorder_levels([2,0,1])

df的输出:

                level1        
                level2        
                 A   B   C
E     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
b     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
c     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33
d     ONE       11  12  13
      TWO       21  22  23
      THREE     31  32  33