假设我有一个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]
这是不对的(它缺少整个第一级条目)。
答案 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