根据列属性对多索引级别进行排序

时间:2014-03-26 23:03:29

标签: python pandas

假设我有一个MultiIndex数据帧df

                   C         D  E
A    B                           
bar  one    0.934232  0.518263  0
     three  0.079759  0.192417  2
flux six    1.484391 -0.607172  2
     three -1.816136 -0.660524  1
foo  five  -0.695819 -0.406685  0
     one   -0.589729 -0.974765  1
     two    0.640990  0.319567  0
     two    0.485979 -2.127268  1

我想根据级别的每个值的列级属性对第一级A进行排序,即:

  • E的最后一个值,降序
  • D的最低值,升序

我该怎么做?

最终df应保持第一级"连续" (即A中的所有项目仍应位于单个A下,而B则相同,等等。

如果它有帮助,这里是生成随机df的代码,如上所示:

from numpy.random import randn as randn
from numpy.random import randint as randint

def create_random_multi_index():
  df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
                            'foo', 'flux', 'foo', 'flux'],  
                     'B' : ['one', 'one', 'two', 'three',
                            'two', 'six', 'five', 'three'],
                     'C' : randn(8), 'D' : randn(8), 'E': randint(0,3, size=(8,))})
  df.set_index(['A', 'B'], inplace=True)
  df.sort_index(inplace=True)
  return df


df = create_random_multi_index()

更新

我试过了:

e0 = df.groupby(level=0, as_index=False).E.max().E
d0 = df.groupby(level=0, as_index=False).D.last().D
new = df.iloc[pd.concat([e0, d0], 1).sort(['E', 'D'], ascending=[True, False]).index]

但我明白了:

                   C         D  E
A    B                           
flux six    1.484391 -0.607172  2
bar  one    0.934232  0.518263  0
     three  0.079759  0.192417  2

[3 rows x 3 columns]

这是不对的(它缺少整个第一级条目)。

1 个答案:

答案 0 :(得分:2)

一个有效的黑客攻击是替换(MultiIndex)级别,排序,然后将它们放回去:

In [11]: levels = df.index.levels

In [12]: e0 = -df.groupby(level=0).E.median()

In [13]: d1 = df.groupby(level=1).D.min()

In [14]: df.index.levels = [e0, d1]

In [15]: df = df.sort_index()

In [16]: df.index.levels = levels

这只能起作用,因为每列都有一个聚合。

无论如何,使用transform进入sort passing a list to ascending的方式可能更加强大:

In [21]: e0 = df.groupby(level=0, as_index=False).transform("median").E

In [22]: d0 = df.groupby(level=0, as_index=False).transform("min").D

In [23]: to_sort = pd.concat([e0, d0], 1).reset_index(drop=True)

In [24]: to_sort
Out[24]: 
   E         D
0  2  0.278293
1  2 -0.548683
2  2  0.723572
3  0 -0.160737
4  1  1.174394
5  0 -0.304647
6  0 -0.916528
7  1 -0.350992

In [25]: to_sort.sort(['E', 'D'], ascending=[True, False])
Out[25]: 
   E         D
3  0 -0.160737
5  0 -0.304647
6  0 -0.916528
4  1  1.174394
7  1 -0.350992
2  2  0.723572
0  2  0.278293
1  2 -0.548683

并使用此结果重新索引:

In [26]: df.iloc[to_sort.sort(['E', 'D'], ascending=[True, False]).index]
Out[26]:
                   C         D  E
A    B                           
flux three  0.479158 -0.160737  0
foo  one    0.598025 -0.304647  0
     two    0.073532 -0.916528  0
     five   0.866019  1.174394  1
     two    1.259768 -0.350992  1
flux six    2.380352  0.723572  2
bar  one   -0.443605  0.278293  2
     three  0.506341 -0.548683  2