如何在排序MultiIndex数据框时使用两个关键函数?

5 投票
1 回答
51 浏览
提问于 2025-04-12 06:25

在这个对多重索引数据框调用 df.sort_index() 的过程中,怎么在第二个层级使用 func_2 呢?

func_1 = lambda s: s.str.lower()
func_2 = lambda x: np.abs(x)
m_sorted = df_multi.sort_index(level=['one', 'two'], key=func_1)

文档中提到“对于多重索引的输入,关键字是按层级应用的”,这句话有点模糊。


import pandas as pd
import numpy as np
np.random.seed(3)

# Create multiIndex
choice = lambda a, n: np.random.choice(a, n, replace=True)
df_multi = pd.DataFrame({
    'one': pd.Series(choice(['a', 'B', 'c'], 8)),
    'two': pd.Series(choice([1, -2, 3], 8)),
    'A': pd.Series(choice([2,6,9,7] ,8))
    })
df_multi = df_multi.set_index(['one', 'two'])

# Sort MultiIndex
func_1 = lambda s: s.str.lower()
func_2 = lambda x: np.abs(x)
m_sorted = df_multi.sort_index(level=['one'], key=func_1)

1 个回答

5

sort_index 这个函数可以接受一个特别的函数作为 key,这个函数会在所有层级上使用。

也就是说,你可以用一个包装函数来为每个层级名称指定你想要的排序函数:

def sorter(level, default=lambda x: x):
    return {
      'one': lambda s: s.str.lower(),
      'two': np.abs,
    }.get(level.name, default)(level)

df_multi.sort_index(level=['one', 'two'], key=sorter)

注意:如果没有匹配的情况,会使用一个默认的函数,这个函数会让层级保持不变。

还有一个选择是使用 numpy.lexsort,而不是 sort_index

# levels, functions in desired sorting order
sorters = [('one', lambda s: s.str.lower()), ('two', np.abs)]

out = df_multi.iloc[np.lexsort([f(df_multi.index.get_level_values(lvl))
                                for lvl, f in sorters[::-1]])]

lexsort 会把主要的键放在最后,所以需要用 [::-1] 来反转。

输出结果:

         A
one two   
a    1   6
    -2   2
     3   7
B    1   6
    -2   7
    -2   7
     3   2
     3   6

撰写回答