根据级别 0 索引对多索引 Pandas DataFrame 的级别 1 索引进行自定义排序

Posted

技术标签:

【中文标题】根据级别 0 索引对多索引 Pandas DataFrame 的级别 1 索引进行自定义排序【英文标题】:Custom sorting of the level 1 index of a multiindex Pandas DataFrame according to the level 0 index 【发布时间】:2018-07-08 11:58:33 【问题描述】:

我有一个多索引数据框,df:

arrays = [['bar', 'bar', 'baz', 'baz', 'baz', 'baz', 'foo', 'foo'],
          ['one', 'two', 'one', 'two', 'three', 'four', 'one', 'two']]

df = pd.DataFrame(np.ones([8, 4]), index=arrays)

看起来像:

             0    1    2    3
bar one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0
baz one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0
    three  1.0  1.0  1.0  1.0
    four   1.0  1.0  1.0  1.0
foo one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0

我现在需要将 'baz' 子级别排序为新顺序,以创建类似于 df_end 的内容:

arrays_end = [['bar', 'bar', 'baz', 'baz', 'baz', 'baz', 'foo', 'foo'],
              ['one', 'two', 'two', 'four', 'three', 'one', 'one', 'two']]

df_end = pd.DataFrame(np.ones([8, 4]), index=arrays_end)

看起来像:

             0    1    2    3
bar one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0
baz two    1.0  1.0  1.0  1.0
    four   1.0  1.0  1.0  1.0
    three  1.0  1.0  1.0  1.0
    one    1.0  1.0  1.0  1.0
foo one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0

我认为我可以重新索引baz 行:

new_index = ['two','four','three','one']

df.loc['baz'].reindex(new_index)

这给出了:

         0    1    2    3
two    1.0  1.0  1.0  1.0
four   1.0  1.0  1.0  1.0
three  1.0  1.0  1.0  1.0
one    1.0  1.0  1.0  1.0

...并将这些值插入到原始 DataFrame 中:

df.loc['baz'] = df.loc['baz'].reindex(new_index)

但结果是:

             0    1    2    3
bar one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0
baz one    NaN  NaN  NaN  NaN
    two    NaN  NaN  NaN  NaN
    three  NaN  NaN  NaN  NaN
    four   NaN  NaN  NaN  NaN
foo one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0

这不是我想要的!所以我的问题是如何使用new_indexbaz 索引中的行进行重新排序。任何建议将不胜感激。

【问题讨论】:

这对我来说似乎是一个更好的解决方案:***.com/questions/43073254/… 【参考方案1】:

编辑:(以适应所需的布局)

arrays = [['bar', 'bar', 'baz', 'baz', 'baz', 'baz', 'foo', 'foo'],
          ['one', 'two', 'one', 'two', 'three', 'four', 'one', 'two']]

df = pd.DataFrame(np.arange(32).reshape([8, 4]), index=arrays)
new_baz_index = [('baz', i) for i in ['two','four','three','one']]
index = df.index.values.copy()
index[df.index.get_loc('baz')] = new_baz_index
df.reindex(index)

df.index.get_loc('baz') 将获取baz 部分的位置作为切片对象,我们只替换那里的部分。

【讨论】:

感谢您非常快速和乐于助人的回复 Tai。这太棒了:) @tomp 没问题。很高兴它有帮助。【参考方案2】:

更新:-)

pd.concat([df[df.index.get_level_values(level=0)!='baz'],df.reindex(list(zip(['baz']*4,['two','four','three','one'])))])
Out[1156]: 
             0    1    2    3
bar one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0
foo one    1.0  1.0  1.0  1.0
    two    1.0  1.0  1.0  1.0
baz two    1.0  1.0  1.0  1.0
    four   1.0  1.0  1.0  1.0
    three  1.0  1.0  1.0  1.0
    one    1.0  1.0  1.0  1.0

【讨论】:

再次您好文,感谢您看这个!您答案中的 df 与我的问题中的输入 df 匹配,而不是输出。是否缺少步骤?

以上是关于根据级别 0 索引对多索引 Pandas DataFrame 的级别 1 索引进行自定义排序的主要内容,如果未能解决你的问题,请参考以下文章

pandas:选择索引,然后选择多索引切片上的列

在尊重其索引结构的同时对多索引进行排序

pandas np.where 基于多索引级别

Pandas:在多索引数据帧中重新索引和插值

将熊猫多索引切片彼此分开

pandas 多索引切片“级别类型不匹配”