我有一个像下面这样的
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 的 bug。
在此问题中,Dataframe 在创建后已进行排序。在前面的步骤中使用像
sort_index()
这样的排序命令会导致 Pandas 出现排序问题。对于按字典顺序排序的多索引数据,分类索引排序失败。
在这些情况下,可以使用一些技巧来解决这个问题。避免使用按字典顺序对索引进行排序的命令。按字典顺序排序的数据无法使用分类索引进行排序。
您可以首先使用
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)
您可以先创建一个
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 上看到更新。
我也遇到了这个问题。以下是另外两个不依赖于
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