![]() |
3.2 Pandas的使用 |
Pandas 是基于 NumPy 衍生出的一种工具,用于解决数据分析问题,它纳入了大量的库和一些标准的数据模型,提供了可用于高效操作大型数据集的工具,是使 Python 成为强大而高效的数据分析工具的重要因素之一。
对金融数据的大部分处理是依赖Pandas实现的。在本书中对Pandas的引入约定为:
import pandas as pd
一旦在代码中看到pd,就是使用了Pandas。
Pandas 的数据结构主要分为三种:Series(一维数组)、DataFrame(二维的表格型数据结构)和Panel(三维数组)。
Series指一维数组,与 NumPy中的一维 Array类似。Series、Array与 Python基本的数据结构List也很相近,其区别是:在List中的元素可以是不同的数据类型,而在Array和Series中则只允许存储相同的数据类型,这样可以更有效地使用内存,提高运算效率。
Series增加了对应的标签(label)以用于索引,可以包含0个或者多个任意数据类型的实体。其中,标签索引赋予了Series强大的存取元素功能。除通过位置外,Series还允许通过索引标签进行元素存取:
Series 的字符串表现形式为:索引在左边,值在右边。因为在建立过程中没有指定索引,所以Python会自动为我们加入一个0~n的整数索引,我们可以通过数字获取具体位置上的元素:
可以通过index与values获取Series的索引与数据:
当然,也可以在Series建立时就指定索引:
可以直接通过索引获取数值:
对于Series的各种计算,其结果也会保留index:
在Python中一切皆对象,Series也不例外。可通过Tab键补全查看一个Series的方法,即输入前几个字母,按下Ta b键,代码如下:
另外,Series可以被转换为字典:
In [52]:obj.to_dict() Out[52]:{'a':40,'b':12,'c':-3,'d':25}
DataFrame 指二维的表格型数据结构。在 DataFrame 有很多功能与 R 中的 data.frame类似,我们可以将DataFrame理解为Series的容器,也就是说,在DataFrame中,多个Series共用了一个索引index。
在以字典或Series的字典的结构构建DataFrame时,最外面的字典对应DataFrame的列,内嵌的字典及Series则是其中的每个值,例如:
从字典的列表中构建 DataFrame 时,其中的每个字典代表的是每条记录(DataFrame中的一行),字典中每个值对应的是这条记录的相关属性。
同时可以看到,当由多个Series组成DataFrame时,Pandas会自动按照index对齐数据,如果某个Series的index缺失,则Pandas会将其自动填写为np.nan。
在 Pandas 中可以通过 set_option 设置 Pandas 的输出格式,例如最多显示的行数、列数等:
3.2.3 Pandas 数据读取与写入
Pandas可以方便地读取本地文件如csv、txt、xlsx等,例如:
其结果截图如图3-3所示。
图3-3
我们可自行输入pd.read_,使用Tab自动完成功能查看Pandas可以读取的数据类型。
同理,可以使用to_,将DataFrame输出到文件中:
In [63]:a.to_excel('closeprice.xls')
在读入数据后,我们需要对数据做基本的统计分析,代码如下:
可以加入参数 include='all',这样 describe 就会展示全部列的统计结果。当然,我们在这里没必要对ticker进行均值统计。df.describe()会统计出各列的计数、平均数、方差、最小值、最大值及quantile数值。df.info()会展示数据类型、行列数和DataFrame占用的内存:
3.2.5 根据已有的列建立新列
本节将根据现有的代码列,加入该股票代码对应的行业列:
使用map函数映射一个字典即可:
可以使用list给出需要排序的列,同时给出是升序还是降序:
上述代码的作用就是先按照group降序排列,当group相同时再按照ounces升序排列。参数中的 inplace=True 直接将排序后的结果存在 data,即直接用排序好的数据覆盖原始数据。
在大多数时候,在数据中会有重复的数据,在做分析前需要进行去重:
在不加任何参数时,Pandas会将完全相同的行去重:
当设置 subset为 k1时,只要 k1重复,Pandas就认为是重复的,可以通过 keep参数确定需要保留哪个,一般在使用keep时先排序。
另外,如果需要查看重复的行,则可以进行如下操作:
如果我们不再需要某一列,就可以对该列进行删除操作:
或者:
axis='columns'或者axis=1都是指按照列来处理。
3.2.9 Pandas 替换数据
如果想批量替换数据中的指定数值,则可以使用 replace:
在Pandas中对缺失数据使用NumPy的np.nan。
也可以重命名某些列:
DataFrame有三种切片方法,分别为loc、iloc和ix。
df.loc的第 1个参数是行标签,第 2个参数为列标签(为可选参数,默认为所有列标签),这两个参数既可以是列表,也可以是单个字符。如果这两个参数都为列表,则返回DataFrame,否则返回Series:
“a.loc[”中的“:”表示所有的行。
df.loc的第 1个参数是行的位置,第 2个参数是列的位置(为可选参数,默认为所有列标签),这两个参数既可以是列表,也可以是单个字符。如果两个参数都是列表,则返回DataFrame,否则返回Series:
其中,loc为location的缩写,iloc为integer location的缩写。
更广义的切片方式是使用.ix,它会自动根据我们给出的索引类型判断是使用位置还是标签进行切片:
主要根据设置的条件进行筛选,通过逻辑指针进行数据切片,在DataFrame中寻找满足条件的记录,方法如下:
也可以同时设置多个条件:
实际上,因为一个bool类型的数据乘以1,可以变为1,0,所以可以将上述条件写为:
上述做法可以用于条件筛选,比如在至少或至多满足几个条件时进行筛选。
有时我们把数值聚集在一起更有意义,例如,如果要为交通状况(路上的汽车数量)根据时间(分钟数据)建模,则具体的分钟可能不重要,而时段如上午、下午、傍晚、夜间、深夜能更好地表现预测结果,这样建模会更直观,也能避免过度拟合:
也可以对分组后的结果进行统计:
也可以给定各个分组的标签并进行切分:
在数据分析过程中,我们往往需要先将数据拆分,然后在其对应的每个分组中进行运算,比如,计算各行业内的股票数量、平均市值,或者从中挑选市盈率最低的股票等。Pandas中的groupby函数恰好为我们提供了一个高效的数据分组运算功能,让我们能以一种轻松、自然的方式对数据集进行切分及再聚合等操作,可将其称为“核心功能”。接下来看看groupby函数的具体操作流程。
我们可将groupby函数的具体操作流程分解为以下三部分。
(1)拆分数据。
(2)应用函数。
(3)汇总计算结果。
如果还是一头雾水的话,则不妨看看图3-4,毕竟一图胜千言。
图3-4
为了加深理解,我们将结合实例来讲解groupby函数的应用。
首先,载入数据集,该数据集由基金前10大重仓股所对应的市值及行业组成:
接下来,计算基金的持股支数,这里利用基金 ticker 对原数据集进行分组,再使用Pandas内置的count()函数进行聚合运算:
可以发现该数据集的确为前十大重仓股,我们再根据行业对原数据集进行分组,计算每个行业对应的股票数量:
可以发现,公募基金的持仓风格一般都偏向于银行、电子、食饮和非银金融等行业。
接下来计算公募基金前十大重仓股的市值之和,这里用到了sum()函数:
可以发现,排名靠前的一般为ETF或老牌明星基金。
在这里还可以使用mean()、std()、min()和size()等聚合函数。我们不仅可以使用Pandas的内置函数进行聚合,还可以使用自定义函数进行聚合。先定义一个 t_range 函数,用于计算公募基金前十大重仓股中的最大市值与最小市值之差:
这里使用了agg()函数,可以将我们之前自定义的函数传入其中:
agg()函数还支持以列表形式传入多个函数:
在agg()函数中不仅可以应用同一种函数,还可以通过不同的列应用不同的求解函数。下面需要分别对市值及行业应用不同的统计函数,并输出不同的列的数据,这时可以通过agg自定义函数实现,只需传入以列名为键值的字典:
虽然agg()的功能已经很强大了,但是仍然有局限。细心的读者可能已经发现了,agg()返回的只能是一个标量,如果我们想返回一个DataFrame,使用agg()就会束手无策。不过不用担心,我们可以使用对象更为广泛的分组运算方法——apply()函数。
这里传入了一个匿名函数,返回前3只股票的相关信息:
有了agg和apply后,我们就可以完成关于分组再聚合的所有操作和运算了。