- 8.1 层次化索引
- 重排与分级排序
- 根据级别汇总统计
- 使用DataFrame的列进行索引
8.1 层次化索引
层次化索引(hierarchical indexing)是pandas的一项重要功能,它使你能在一个轴上拥有多个(两个以上)索引级别。抽象点说,它使你能以低维度形式处理高维度数据。我们先来看一个简单的例子:创建一个Series,并用一个由列表或数组组成的列表作为索引:
In [9]: data = pd.Series(np.random.randn(9),...: index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'],...: [1, 2, 3, 1, 3, 1, 2, 2, 3]])In [10]: dataOut[10]:a 1 -0.2047082 0.4789433 -0.519439b 1 -0.5557303 1.965781c 1 1.3934062 0.092908d 2 0.2817463 0.769023dtype: float64
看到的结果是经过美化的带有MultiIndex索引的Series的格式。索引之间的“间隔”表示“直接使用上面的标签”:
In [11]: data.indexOut[11]:MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0, 1, 1, 2]])
对于一个层次化索引的对象,可以使用所谓的部分索引,使用它选取数据子集的操作更简单:
In [12]: data['b']Out[12]:1 -0.5557303 1.965781dtype: float64In [13]: data['b':'c']Out[13]:b 1 -0.5557303 1.965781c 1 1.3934062 0.092908dtype: float64In [14]: data.loc[['b', 'd']]Out[14]:b 1 -0.5557303 1.965781d 2 0.2817463 0.769023dtype: float64
有时甚至还可以在“内层”中进行选取:
In [15]: data.loc[:, 2]Out[15]:a 0.478943c 0.092908d 0.281746dtype: float64
层次化索引在数据重塑和基于分组的操作(如透视表生成)中扮演着重要的角色。例如,可以通过unstack方法将这段数据重新安排到一个DataFrame中:
In [16]: data.unstack()Out[16]:1 2 3a -0.204708 0.478943 -0.519439b -0.555730 NaN 1.965781c 1.393406 0.092908 NaNd NaN 0.281746 0.769023
unstack的逆运算是stack:
In [17]: data.unstack().stack()Out[17]:a 1 -0.2047082 0.4789433 -0.519439b 1 -0.5557303 1.965781c 1 1.3934062 0.092908d 2 0.2817463 0.769023dtype: float64
stack和unstack将在本章后面详细讲解。
对于一个DataFrame,每条轴都可以有分层索引:
In [18]: frame = pd.DataFrame(np.arange(12).reshape((4, 3)),....: index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],....: columns=[['Ohio', 'Ohio', 'Colorado'],....: ['Green', 'Red', 'Green']])In [19]: frameOut[19]:Ohio ColoradoGreen Red Greena 1 0 1 22 3 4 5b 1 6 7 82 9 10 11
各层都可以有名字(可以是字符串,也可以是别的Python对象)。如果指定了名称,它们就会显示在控制台输出中:
In [20]: frame.index.names = ['key1', 'key2']In [21]: frame.columns.names = ['state', 'color']In [22]: frameOut[22]:state Ohio Coloradocolor Green Red Greenkey1 key2a 1 0 1 22 3 4 5b 1 6 7 82 9 10 11
注意:小心区分索引名state、color与行标签。
有了部分列索引,因此可以轻松选取列分组:
In [23]: frame['Ohio']Out[23]:color Green Redkey1 key2a 1 0 12 3 4b 1 6 72 9 10
可以单独创建MultiIndex然后复用。上面那个DataFrame中的(带有分级名称)列可以这样创建:
MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']],names=['state', 'color'])
重排与分级排序
有时,你需要重新调整某条轴上各级别的顺序,或根据指定级别上的值对数据进行排序。swaplevel接受两个级别编号或名称,并返回一个互换了级别的新对象(但数据不会发生变化):
In [24]: frame.swaplevel('key1', 'key2')Out[24]:state Ohio Coloradocolor Green Red Greenkey2 key11 a 0 1 22 a 3 4 51 b 6 7 82 b 9 10 11
而sort_index则根据单个级别中的值对数据进行排序。交换级别时,常常也会用到sort_index,这样最终结果就是按照指定顺序进行字母排序了:
In [25]: frame.sort_index(level=1)Out[25]:state Ohio Coloradocolor Green Red Greenkey1 key2a 1 0 1 2b 1 6 7 8a 2 3 4 5b 2 9 10 11In [26]: frame.swaplevel(0, 1).sort_index(level=0)Out[26]:state Ohio Coloradocolor Green Red Greenkey2 key11 a 0 1 2b 6 7 82 a 3 4 5b 9 10 11
根据级别汇总统计
许多对DataFrame和Series的描述和汇总统计都有一个level选项,它用于指定在某条轴上求和的级别。再以上面那个DataFrame为例,我们可以根据行或列上的级别来进行求和:
In [27]: frame.sum(level='key2')Out[27]:state Ohio Coloradocolor Green Red Greenkey21 6 8 102 12 14 16In [28]: frame.sum(level='color', axis=1)Out[28]:color Green Redkey1 key2a 1 2 12 8 4b 1 14 72 20 10
这其实是利用了pandas的groupby功能,本书稍后将对其进行详细讲解。
使用DataFrame的列进行索引
人们经常想要将DataFrame的一个或多个列当做行索引来用,或者可能希望将行索引变成DataFrame的列。以下面这个DataFrame为例:
In [29]: frame = pd.DataFrame({'a': range(7), 'b': range(7, 0, -1),....: 'c': ['one', 'one', 'one', 'two', 'two',....: 'two', 'two'],....: 'd': [0, 1, 2, 0, 1, 2, 3]})In [30]: frameOut[30]:a b c d0 0 7 one 01 1 6 one 12 2 5 one 23 3 4 two 04 4 3 two 15 5 2 two 26 6 1 two 3
DataFrame的set_index函数会将其一个或多个列转换为行索引,并创建一个新的DataFrame:
In [31]: frame2 = frame.set_index(['c', 'd'])In [32]: frame2Out[32]:a bc done 0 0 71 1 62 2 5two 0 3 41 4 32 5 23 6 1
默认情况下,那些列会从DataFrame中移除,但也可以将其保留下来:
In [33]: frame.set_index(['c', 'd'], drop=False)Out[33]:a b c dc done 0 0 7 one 01 1 6 one 12 2 5 one 2two 0 3 4 two 01 4 3 two 12 5 2 two 23 6 1 two 3
reset_index的功能跟set_index刚好相反,层次化索引的级别会被转移到列里面:
In [34]: frame2.reset_index()Out[34]:c d a b0 one 0 0 71 one 1 1 62 one 2 2 53 two 0 3 44 two 1 4 35 two 2 5 26 two 3 6 1
