1. 前言
我们做量化,最要和数据打交道。而Pandas则是Python众多库当中,用来进行数据分析,数据处理的一把利器,掌握了Pandas当中的方法,不单单是量化,凡是设计到数据分析的任务或者工作当中,都可让我们事半功倍。所以我这里特地的写一篇文章来介绍怎么用pandas进行数据分析。
我大概整理了一些场景,主要分为行情数据和基本面数据,看看在实战当中如何使用pandas。
2. 行情数据
import sys
sys.path.append(r'E:\Heat')
from acrab.utils.data_function import DataAPI
2.1 股票收益率的计算
price = DataAPI.get_stock_quote('20191231', '20200204', ['closePrice'])
price.head()
这里我们获取了A股从20191231至今所有股票的收盘价,以一个三列表格存放。现在我们计算每支股票: 年初至今的收益率 过去5天的收益率
price = price.pivot(index='trade_date', columns='ticker', values='closePrice')
price.iloc[:5, :5]
借助pivot方法,我们把窄表转成宽表,索引为日期,列为股票代码,数据为后复权收盘价。
ytd = price.loc['20200204'].divide(price.loc['20191231']) - 1
ytd.head()
ticker
000001 -0.112462
000002 -0.141703
000004 -0.126612
000005 -0.152127
000006 -0.171642
dtype: float64
这里我使用了两种不同的从DataFrame截取数据的方法,iloc与loc,其中iloc为按行列的位置进行选择,而loc则按索引进行选择。
注意:price.iloc[:5, :5]获得的仍为DataFrame,而price.loc['20200204']获得的为Series。
使用Series的divide方法,我们完成了除法运算,类似的方法还有sub,add,multiply等。
计算过去5天的收益率,我们有两种方法:
# 方法一:
pre_5d = DataAPI.get_shift_date('20200204', 5)
ret_5d = price.loc['20200204'].divide(price.loc[pre_5d]) - 1
ret_5d.head()
ticker
000001 -0.112462
000002 -0.075326
000004 -0.154313
000005 -0.165616
000006 -0.173183
dtype: float64
# 方法二:
ret_5d = price.pct_change(5)
ret_5d.iloc[-5:, :5]
方法一如同前面提到的计算年初至今的收益率,而方法二借助了DataFrame的pct_change方法,返回的是实现这段时间,每天的过去5天收益率,而今天的则取最后一行即可
2.2 股票收益波动率的计算
ret_1d = price.pct_change()
vol = ret_1d.std(axis=0)
vol.head()
ticker
000001 0.030634
000002 0.027112
000004 0.032529
000005 0.027228
000006 0.026813
dtype: float64
我们首先计算了年初至今每支股票的日收益率,然后借助了DataFrame的std方法,其中axis=0表示按列运算,而axis=1表示按行计算。
波动率的计算需要一个时间窗口。这个返回的结果是年初至今个股收益率的波动,但不一定是我们需要的,例如我们计算个股过去10天收益的波动。
vol_10d = ret_1d.rolling(10).std()
vol_10d.iloc[-5:, :5]
这里我们使用了rolling方法,表示过去10天滚动窗口计算标准差,类似的还可以计算方差,偏度,峰度,最大值,最小值,分位数,均值,求和等等
2.3 收益中位数
这里我们分别计算20200204这天,深交所与上交所股票的收益率中位数。
ret = ret_1d.loc['20200204'].to_frame('return').reset_index()
ret.head()
ret = ret[~ret['ticker'].str.startswith('68')] # 剔除科创板
ret['exchange'] = ret['ticker'].apply(lambda x: 'sh' if x[0] == '6' else 'sz')
ret.head()
ret.groupby('exchange').apply(lambda x: x['return'].median())
exchange
sh -0.014278
sz -0.020324
dtype: float64
这里六个知识点:使用ret中ticker列保存的都是string,因此我们使用string的startswith方法来判断每个字符串起始元素是不是68,是为True,否为False
~运算符对保存布尔变量的Series取反,将False变成True,True变成False
DataFrame可以按照保存布尔变量的Series,list等来选择行
Series的apply是对每一个元素进行运算,接收的参数是一个函数
DataFrame如何添加新列
通过groupby函数,进行数据聚合
不得不说,运营一个专栏真的挺耗时间的,佩服佩服!下一篇,我们将基本面数据当中pandas的一些应用。