Python 在对数据帧进行切片后,如何更新多索引的级别?

Python 在对数据帧进行切片后,如何更新多索引的级别?,python,pandas,Python,Pandas,我有一个带有多索引的数据帧: In [1]: import pandas as pd In [2]: multi_index = pd.MultiIndex.from_product([['CAN','USA'],['total']],names=['country','sex']) In [3]: df = pd.DataFrame({'pop':[35,318]},index=multi_index) In [4]: df Out[4]: pop country

我有一个带有多索引的数据帧:

In [1]: import pandas as pd
In [2]: multi_index = pd.MultiIndex.from_product([['CAN','USA'],['total']],names=['country','sex'])
In [3]: df = pd.DataFrame({'pop':[35,318]},index=multi_index)
In [4]: df
Out[4]:
               pop
country sex
CAN     total   35
USA     total  318
然后从该数据帧中删除一些行:

In [5]: df = df.query('pop > 100')

In [6]: df
Out[6]:
               pop
country sex
USA     total  318
但当我参考MutliIndex时,这两个国家仍处于其水平

In [7]: df.index.levels[0]
Out[7]: Index([u'CAN', u'USA'], dtype='object')
我可以用一种非常奇怪的方式自己解决这个问题:

In [8]: idx_names = df.index.names

In [9]: df = df.reset_index(drop=False)

In [10]: df = df.set_index(idx_names)

In [11]: df
Out[11]:
               pop
country sex
USA     total  318

In [12]: df.index.levels[0]
Out[12]: Index([u'USA'], dtype='object')

但这似乎相当混乱。有没有更好的方法让我错过了呢?

如果有一种更“内置”的方法来消除未使用的国家,而不是像你现在这样(或类似的方式)重新创建索引,我会感到惊讶。如果查看切片前后的索引:

In [165]: df.index
Out[165]:
MultiIndex(levels=[[u'CAN', u'USA'], [u'total']],
           labels=[[0, 1], [0, 0]],
           names=[u'country', u'sex'])

In [166]: df = df.query('pop > 100')

In [167]: df.index
Out[167]:
MultiIndex(levels=[[u'CAN', u'USA'], [u'total']],
           labels=[[1], [0]],
           names=[u'country', u'sex'])

您可以看到,标签(作为级别值的索引)已更新,但级别值未更新。这可能是一个不完美的类比,但我觉得级别值类似于数据库表中的枚举列,而标签类似于表中行的实际值。如果删除表中值为“CAN”的所有行,则不会改变“CAN”仍然是基于列定义的有效选择这一事实。要从枚举中删除“CAN”,必须更改列定义;这相当于对熊猫的数据帧重新编制索引。

这是以前让我头疼的事情。出于性能和哲学原因,删除列或行不会更改基础的多索引,官方认为这不是一个bug()。简而言之,开发人员说“这不是多重索引的目的”。如果修改后需要多索引级别的内容列表,例如用于迭代或检查是否包含内容,可以使用:

df.index.get_level_values(<levelname>)
df.index.get_level_value()
这将返回该索引级别内的当前活动值

因此,我想这里的“诀窍”是,API本机实现这一点的方法是使用get_level_值,而不仅仅是版本使用中的.index或.columns:

哦,如果不想重复,可以添加.unique()。默认级别值包括每种情况,因此在典型的多索引场景中您会看到大量重复项。您还可以使用
unique(data.index.values)
获取所有级别的值。
print (df.index)
MultiIndex(levels=[['CAN', 'USA'], ['total']],
           labels=[[1], [0]],
           names=['country', 'sex'])

df.index = df.index.remove_unused_levels()

print (df.index)
MultiIndex(levels=[['USA'], ['total']],
           labels=[[0], [0]],
           names=['country', 'sex'])