尝试使用分类索引对多索引索引进行排序

问题描述 投票:0回答:2

我有一个像下面这样的

MultiIndexed
数据框

months = ['January','February','March','April','May','June','July','August','September','October','November','December']
df = pd.DataFrame({'col' : np.arange(1,25,1)},\
                  index = pd.MultiIndex.from_product([months, [1,2]], names = ['idx_1', 'idx_2'])).sort_index()

print(df)

                 col
idx_1     idx_2     
April     1        7
          2        8
August    1       15
          2       16
December  1       23
          2       24
February  1        3
          2        4
January   1        1
          2        2
July      1       13
          2       14
June      1       11
          2       12
March     1        5
          2        6
May       1        9
          2       10
November  1       21
          2       22
October   1       19
          2       20
September 1       17
          2       18

我想要

sort the index
,所以我创建了一个
CategoricalIndex
并将其分配给MultiIndex的level_0。但是,即使在此之后,排序命令也不会对索引进行排序。

cidx = pd.CategoricalIndex(data = df.index.get_level_values(0).unique(), categories = months, ordered=True)
df.index = df.index.set_levels(cidx, level = 0)
df = df.sort_index(level = 0)
print(df)

它将产生与上面相同的输出。我认为这是一个

bug
。有人可以帮我吗?

这是 MultiIndex 的 level_0

print(df.index.get_level_values(0))

CategoricalIndex(['April', 'April', 'August', 'August', 'December', 'December',
                  'February', 'February', 'January', 'January', 'July', 'July',
                  'June', 'June', 'March', 'March', 'May', 'May', 'November',
                  'November', 'October', 'October', 'September', 'September'],
                 categories=['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', ...], ordered=True, dtype='category', name='idx_1')
pandas dataframe multi-index
2个回答
0
投票

首先,我必须说这个问题是 Pandas 的 bug。

在此问题中,Dataframe 在创建后已进行排序。在前面的步骤中使用像

sort_index()
这样的排序命令会导致 Pandas 出现排序问题。对于按字典顺序排序的多索引数据,分类索引排序失败。 在这些情况下,可以使用一些技巧来解决这个问题。

  1. 避免使用按字典顺序对索引进行排序的命令。按字典顺序排序的数据无法使用分类索引进行排序。

  2. 您可以首先使用

    reset_index()
    重置所需的索引级别。然后您可以创建一个
    CategoricalIndex
    并使用它对列进行分类。

    months = ['January', 'February', 'March', 'April', 'May', 'June', 
              'July', 'August', 'September', 'October', 'November', 'December']    
    df = pd.DataFrame({'col': np.arange(1, 25, 1)},
              index=pd.MultiIndex.from_product([months, [1, 2]], names=['idx_1', 'idx_2'])).sort_index()
    
    
    df.reset_index(level=0, inplace=True)
    
    df['idx_1'] = pd.CategoricalIndex(df['idx_1'], months,  ordered=True)
    
    df.set_index('idx_1', append=True, inplace=True)
    
    df.swaplevel(0, 1).sort_index(level=0)
    
  3. 您可以先创建一个

    CategoricalIndex
    并将其分配给MultiIndex的level_0。之后,您需要从零级索引中消除字典排序。您可以在这里使用两个连续的
    sort_index()
    作为技巧。

    months = ['January', 'February', 'March', 'April', 'May', 'June',
       'July', 'August', 'September', 'October', 'November', 'December']
    
    df = pd.DataFrame({'col': np.arange(1, 25, 1)},
              index=pd.MultiIndex.from_product([months, [1, 2]], names=['idx_1', 'idx_2'])).sort_index()
    
    categories = pd.CategoricalIndex(df.index.levels[0], categories=months, ordered=True)
    
    df.index = df.index.set_levels(categories, level=0)
    
    df.sort_index(level=1).sort_index(level=0)
    

输出:

                 col
idx_1     idx_2     
January   1        1
          2        2
February  1        3
          2        4
March     1        5
          2        6
April     1        7
          2        8
May       1        9
          2       10
June      1       11
          2       12
July      1       13
          2       14
August    1       15
          2       16
September 1       17
          2       18
October   1       19
          2       20
November  1       21
          2       22
December  1       23
          2       24

因为,这实际上是一个错误,可以在此处的 repo 上看到更新。


0
投票

我也遇到了这个问题。以下是另外两个不依赖于

pd.CategoricalIndex
的解决方法:

使用
reindex

您可以通过重新索引相关级别来应用自定义订单:

months = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
]

mi = pd.MultiIndex.from_product([months, [1, 2]], names = ['idx_1', 'idx_2'])
df = (
    pd.DataFrame(
        data = range(1,25),
        columns = ['col'],
        index = mi
    )
    .reindex(months, level=0)
)
df

使用
sort_index

中的排序键

我们可以利用

key
sort_index
参数将索引映射到自定义排序顺序:

months = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
]

mi = pd.MultiIndex.from_product([months, [1, 2]], names = ['idx_1', 'idx_2'])
sorter = lambda idx: idx.map({m:n for m,n in zip(months, range(len(months)))})
df = (
    pd.DataFrame(
        data = range(1,25),
        columns = ['col'],
        index = mi
    )
    .sort_index(level=0, key=sorter)
)
df
© www.soinside.com 2019 - 2024. All rights reserved.