7.1 多重索引
多重索引(MultiIndex)又可以称为“分层索引”,是Pandas中的一个核心功能。在实际工作中,如果合理应用多重索引,则可以大大简化某些复杂的数据操作,特别是高维数据的操作。
本节就来讲解“多重”和“分层”的真实含义,以及多重索引是如何在复杂的数据分析中发挥作用的。
多重索引在Pandas中也是一种对象,即MultiIndex对象,其与标准的Index对象非常相似,只不过有了“多重”的概念。我们可以将多重索引对象看成是一个由元组(tuple)元素组成的数组,其中,每一个元组对象都是唯一的。MultiIndex既可以由嵌套数组创建(使用MultiIndex.from_arrays),也可以由元组组成的数组创建(使用MultiIndex.from_tuples),或者指定每个维度的索引值,自动循环生成索引(使用MultiIndex.from_product)。
下面就来列举一个例子说明生成MultiIndex对象的方法。假设我们想生成一个由股票代码和不同年份组成的索引,股票代码分别是000001、000002、000003,年份分别是2016、2017。
最快的方式是使用from_product方法,示例代码如下:
import pandas as pd numbers = ['000001', '600000', '688001'] colors = [2016, 2017] mindex=pd.MultiIndex.from_product([numbers, colors],names=['code', 'year'])
其中,mindex的值如下所示:
MultiIndex(levels=[['000001', '600000', '688001'], [2016, 2017]], codes=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]], names=['code', 'year'])
MultiIndex最大的好处是其提供了各种便捷的方法,可以方便快速地进行各种数据变换。一个经典的例子是从Wind中导出数据,并将它变换成我们需要的数据格式。
比如,我们有时会碰到类似表7-1的数据。在表7-1中,A和B都包含了2006年、2007年的数据。
表7-1 数据表1
表7-1所示的格式有时候处理起来不是很方便,我们希望将其转换为一种更为统一的格式,如表7-2所示。
表7-2 数据表2
使用Pandas可以很容易实现这种转换。我们可以为dataframe建立列索引,然后使用stack()方法来实现这个功能。
下面引用一个实例来说明。使用Wind终端下载所有股票对应的机构持股数量,下载的季度数据是按列排列的,如图7-1所示(图7-1的右边还有数据到2016年,但限于篇幅,并没全部显示)。为了便于处理,需要将图7-1中的数据变换为表7-2所示的格式,并保存为csv文件,以供后续使用。
先导入数据,将第一列作为索引,再更改索引和名称。为了方便处理,我们将年份和季度分开,这里使用双重列索引,分别代表年份和季度。示例代码如下:
import pandas as pd import numpy as np year=np.arange(2006,2017,1) quarter=np.arange(1,5,1) col_index=pd.MultiIndex.from_product([year, quarter], names=['year', 'quarter']) df=pd.read_csv('unstack.csv',index_col=[0],header=0) df.head() df.columns=col_index df.index.name='code' df.head()
图 7-1
导入的df数据部分如图7-2所示。
图 7-2
先进行一次stack()操作,示例代码如下:
df_quarter=df.stack() df_quarter.head()
df_quarter的数据如图7-3所示,可以看到,第一次stack操作将季度由列索引转为了行索引。
图 7-3
再进行一次stack()操作,示例代码如下:
s_year=df_quarter.stack() s_year.head()
s_year的数据如图7-4所示。需要注意的是,此时s_year不再是dataframe类,而是变成了Series类,因为s_year没有column索引了。如果此时引用s.columns,则会报错。
图 7-4
将s_year输出到csv文件,示例代码如下:
s_year.to_csv('s_year.csv')
csv文件的数据格式如图7-5所示。
我们也可以将年份和季度的位置调换,这样更符合日常使用习惯。但调换之前需要先将s_year转换成dataframe类。示例代码如下:
df_year=s_year.to_frame() df_year.swaplevel(1,2,axis=0)
最后得到的数据如图7-6所示。
图 7-5
图 7-6