Python量化投资:技术、模型与策略
上QQ阅读APP看书,第一时间看更新

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