选取 DataFrame 使用正常的 loc 或 iloc 索引数据,但是对于 Multiindex 层次化索引该怎么索引数据呢?
引入需要使用的包裹
in [1]: import pandas as pd
import numpy as np
创建层次化索引,使用 from_tuples 方法创建层次化索引
in [2]: arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
新建数据,将层次化索引建为列标签
in [3]: arrays = [np.array(['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux']),np.array(['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two'])]
df = pd.DataFrame(np.random.randn(3, 8), index=['A', 'B', 'C'], columns=index)
in [4]: df
out[4]:
first bar baz foo qux
second one two one two one two one two
A 0.778818 2.521446 0.415141 0.384948 0.094009 -0.590066 -0.703295 0.983774
B -0.237388 -0.211130 0.108585 0.610035 -1.844551 -0.408197 -0.398825 -0.577074
C 0.239472 0.208049 -0.477733 -0.295725 -0.645410 0.444975 -1.565026 1.211517
in [5]: df.index
out[5]: Index(['A', 'B', 'C'], dtype='object')
in [6]: df.columns
out[6]: MultiIndex(levels=[['bar', 'baz', 'foo', 'qux'], ['one', 'two']],
codes=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]],
names=['first', 'second'])
可以看到行索引只是正常的索引,而列标签却是层次化索引
对于列标签来说,层次化索引跟正常索引的选取没有什么区别
in [7]: df['bar']
out[7]: second one two
A 0.778818 2.521446
B -0.237388 -0.211130
C 0.239472 0.208049
in [8]: df['bar', 'one']
out[8]:
A 0.778818
B -0.237388
C 0.239472
Name: (bar, one), dtype: float64
in [9]: df = df.T
df.loc[('bar', 'two')]
out[9]:
A 2.521446
B -0.211130
C 0.208049
Name: (bar, two), dtype: float64
使用 T 转置数据,将层次化索引的列标签转置为层次化行索引
in [10]: df.loc[('bar', 'two'), 'A']
out[10]: 2.5214458248137617
in [11]: df.loc['baz':'foo']
out[11]:
A B C
first second
baz one 0.415141 0.108585 -0.477733
two 0.384948 0.610035 -0.295725
foo one 0.094009 -1.844551 -0.645410
two -0.590066 -0.408197 0.444975
对于层次化行索引进行切片或索引数据会比较麻烦,可以使用 loc 并且使用元组索引数据
pandans 提供了 xs 方法可以对 Multiindex 进行更为细腻的索引操作,可以直接指定层次化索引中元素和层级
in [12]: df.xs('one', level='second')
out[12]:
A B C
first
bar 0.778818 -0.237388 0.239472
baz 0.415141 0.108585 -0.477733
foo 0.094009 -1.844551 -0.645410
qux -0.703295 -0.398825 -1.565026
另外可以使用 loc 和 slice 方法进行切片操作,其实使用slice 和直接使用元组是没有区别的。
in [13]: df.loc[(slice(None), 'one'), :]
out[13]:
A B C
first second
bar one 0.778818 -0.237388 0.239472
baz one 0.415141 0.108585 -0.477733
foo one 0.094009 -1.844551 -0.645410
qux one -0.703295 -0.398825 -1.565026
对于列标签(层次化索引) 可以使用 axis=1 来指定轴
in [15]: df = df.T
in [16]: df.xs('one', level='second', axis=1)
out[16]:
first bar baz foo qux
A 0.778818 0.415141 0.094009 -0.703295
B -0.237388 0.108585 -1.844551 -0.398825
C 0.239472 -0.477733 -0.645410 -1.565026
对于列标签(层次化索引)同样可以使用 slice 进行切片操作
in [17]: df.loc[:, (slice(None), 'one')]
out[17]:
first bar baz foo qux
second one one one one
A 0.778818 0.415141 0.094009 -0.703295
B -0.237388 0.108585 -1.844551 -0.398825
C 0.239472 -0.477733 -0.645410 -1.565026
in [18]: df.xs(('one', 'bar'), level=('second', 'first'), axis=1)
in [18]:
first bar
second one
A 0.778818
B -0.237388
C 0.239472
还可以使用 drop_level 来指定是否显示所有的层次化索引
in [19]: df.xs('one', level='second', axis=1, drop_level=False)
out[19]:
first bar baz foo qux
second one one one one
A 0.778818 0.415141 0.094009 -0.703295
B -0.237388 0.108585 -1.844551 -0.398825
C 0.239472 -0.477733 -0.645410 -1.565026
in [20]: df.xs('one', level='second', axis=1)
out[20]:
first bar baz foo qux
A 0.778818 0.415141 0.094009 -0.703295
B -0.237388 0.108585 -1.844551 -0.398825
C 0.239472 -0.477733 -0.645410 -1.565026
更加详细的内容可以参考 MultiIndex,这里面详细的讲述了层次化索引的创建和使用方法。