在Pandas DataFrame中重新调整多级列中的标签和级别

时间:2015-06-10 12:55:09

标签: python pandas

基于我在另一个问题上找到的具有多级列的示例DataFrame:

arrays = [[1, 2]*3, ['A', 'B', 'C']*2]
columns = pd.MultiIndex.from_arrays(arrays, names=['foo', 'bar'])
​
df = pd.DataFrame(np.random.randn(2,6),
                  columns=columns,
                  index= pd.date_range('20000103',periods=2))
print(df)

foo                1         2         1         2         1         2
bar                A         B         C         A         B         C
2000-01-03  2.040867 -1.727071  0.126223  2.101799  1.811349 -0.003293
2000-01-04 -2.644979  0.156852 -1.034756  0.609625 -0.213968 -0.293759

我需要重新排序列标签,而不是遵循这种模式,根据需要重新对齐数据:

bar                A         A         B         B         C         C
foo                1         2         1         2         1         2
2000-01-03  2.040867  2.101799  1.811349 -1.727071  0.126223 -0.003293
2000-01-04 -2.644979  0.609625 -0.213968  0.156852 -1.034756 -0.293759

我用以下任何一个交换了列级别:

 # option one
 df.columns = df.columns.reorder_levels([1,0])

 # option two
 df.columns = df.columns.swaplevel(0, 1)

这很有效,但如何在保持数据对齐的同时移动标签呢?

我尝试了以下内容:

df.columns = df.columns.set_labels([0,0,1,1,2,2], level=0).set_labels([0,1,0,1,0,1], level=1)

不幸的是,数据不随标签移动(即数据现在未对齐):

bar                A                   B                   C          
foo                1         2         1         2         1         2
2000-01-03  2.040867 -1.727071  0.126223  2.101799  1.811349 -0.003293
2000-01-04 -2.644979  0.156852 -1.034756  0.609625 -0.213968 -0.293759

我有很多东西,包括重新索引,但无济于事。

编辑:这只是一个比喻性的例子,但实际上我的数据在列轴的第二级(交换后)中包含分类标签[Min,Max,Single],即:< / p>

arrays = [['Max', 'Min', 'Single']*3, np.repeat(['A', 'B', 'C'], 3)]
columns = pd.MultiIndex.from_arrays(arrays, names=['foo', 'bar'])
​
df = pd.DataFrame(np.random.randn(2,9),
                  columns=columns,
                  index= pd.date_range('20000103',periods=2))
print(df)
​
foo              Max       Min    Single       Max       Min    Single       Max       Min    Single
bar                A         A         A         B         B         B         C         C         C
2000-01-03 -0.004233  0.820975  1.481674  0.064850 -0.178978 -0.862092  0.136279 -0.517081 -1.557611
2000-01-04  0.835346 -0.403773 -0.035985  1.079355  1.780113 -1.037420  1.459070 -0.254668 -0.091501

df.columns = df.columns.swaplevel(0,1)
​
print(df)

bar                A                             B                             C                    
foo              Max       Min    Single       Max       Min    Single       Max       Min    Single
2000-01-03 -0.004233  0.820975  1.481674  0.064850 -0.178978 -0.862092  0.136279 -0.517081 -1.557611
2000-01-04  0.835346 -0.403773 -0.035985  1.079355  1.780113 -1.037420  1.459070 -0.254668 -0.091501

对于第二级,我想使用明确提供的订单:['Min', 'Max', 'Single']。因此,按照@Primer的建议按字母顺序排序将不起作用。

1 个答案:

答案 0 :(得分:1)

交换完需要使用.sort_index的级别后,这将产生所需的结果。 这对我有用:

arrays = [[1, 2]*3, ['A', 'B', 'C']*2]
columns = pd.MultiIndex.from_arrays(arrays, names=['foo', 'bar'])

df = pd.DataFrame(pd.np.random.randn(2,6),
                  columns=columns,
                  index= pd.date_range('20000103',periods=2))
print(df)

foo             1      2      1      2      1      2
bar             A      B      C      A      B      C
2000-01-03 -1.165  0.901  0.466 -1.536  1.488  1.896
2000-01-04  1.179 -0.180 -1.071  1.054 -0.403  1.222

df.columns = df.columns.swaplevel(0, 1)
df.sort_index(1, inplace=True)
print df

bar             A             B             C       
foo             1      2      1      2      1      2
2000-01-03 -1.165 -1.536  1.488  0.901  0.466  1.896
2000-01-04  1.179  1.054 -0.403 -0.180 -1.071  1.222

<强>更新

Categorical具有ordered属性,您可以使用该属性设置所需的任何订单,然后使用.sort_index.sort对其进行排序。 以下是如何为foo设置自定义订单的说明:

array1 = ['A', 'B']*3
array2 = ['Min', 'Max', 'Single']*2
columns = pd.MultiIndex.from_tuples(zip(array2, array1), names=['foo', 'bar'])

df = pd.DataFrame(pd.np.random.randn(2,6),
                  columns=columns,
                  index= pd.date_range('20000103',periods=2))

print df

foo        Single    Max    Min Single    Max    Min
bar             A      B      A      B      A      B
2000-01-03  0.098  0.583 -0.399  0.370 -1.307  1.658
2000-01-04 -0.118 -0.680  0.666 -0.461 -1.334 -1.347

# Here is we extract foo column just to illustrate that it is Categorical and sorted in 'wrong' order:
df = df.stack().stack().reset_index().rename(columns={'level_0':'date',0:'val'})
df['foo'] = df.foo.astype('category')
print df.foo

0        Max
1        Min
2     Single
3        Max
4        Min
5     Single
6        Max
7        Min
8     Single
9        Max
10       Min
11    Single
Name: foo, dtype: category
Categories (3, object): [Max, Min, Single]

请注意最后一行中的列表 - 如果您在其上调用.sort,则会按顺序(按字母顺序排列)对其进行排序。

现在我们将使用新订单重新定义此列:

df['foo'] = pd.Categorical(pd.np.asarray(df.foo), categories=['Min','Single','Max'], ordered=True)
print df.foo

0        Max
1        Min
2     Single
3        Max
4        Min
5     Single
6        Max
7        Min
8     Single
9        Max
10       Min
11    Single
Name: foo, dtype: category
Categories (3, object): [Min < Single < Max]

请注意,在最后一行中,列表现在显示新订单,<符号表明这是一个ordered Categorical系列。 当您在其上调用.sort时,它将按所示顺序排序。

希望这有帮助。