前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从零开始学量化(五):用Python做回归

从零开始学量化(五):用Python做回归

作者头像
量化小白
发布2019-07-10 15:33:33
7.8K0
发布2019-07-10 15:33:33
举报
文章被收录于专栏:量化小白上分记

回归作为数据分析中非常重要的一种方法,在量化中的应用也很多,从最简单的因子中性化到估计因子收益率,以及整个Barra框架,都是以回归为基础,本文总结各种回归方法以及python实现的代码。

OLS

回归是研究多组自变量X1,X2,...,Xn与一个因变量Y关系的模型,首先从最简单的OLS开始,变量假设如下

回归模型可以表示为

同时线性回归还必须满足“BLUE”的假设,在这些假设下,回归的目标是在已知X,Y的情况下估计回归系数beta,OLS的思想是最小化残差平方和,即

OLS估计量具有一致性、无偏性等优点。

接下用用python实现OLS,所用数据为特定日期全A股的PB、ROE、行业、市值数据,部分数据如下,数据和代码获取后台回复“回归”。

python中实现OLS的模块很多,numpysklearnstatsmodels中都有,这里给出numpy,statsmodel中的用法。

np.linalg.lstsq(a, b, rcond='warn')

lstsq的输入包括三个参数,a为自变量X,b为因变量Y,rcond用来处理回归中的异常值,一般不用。

lstsq的输出包括四部分:回归系数、残差平方和、自变量X的秩、X的奇异值。一般只需要回归系数就可以了。

这里需要注意的一点是,必须自己在自变量中添加截距项,否则回归结果是没有截距项的,其他细节可以参考help。

这里我们用一个行业股票的数据实现PB-ROE回归,代码如下

代码语言:javascript
复制
datas = pd.read_excel('data.xlsx',index_col = 0)
datas = datas.loc[(datas.pb_lf>0) &(datas.pb_lf<10) ]
datas = datas.loc[(datas.roe_ttm2>0) &(datas.roe_ttm2 < 10)]
datas1 = datas.loc[datas.classname == '医药生物']

x = datas1[['roe_ttm2']]
x['Intercept'] = 1

y = datas1['pb_lf']

beta,resid,ranks,s = np.linalg.lstsq(x,y)
y_fitted = beta[0]*datas1[['roe_ttm2']] + beta[1]

plt.figure(figsize = (8,6))
plt.plot(datas1.roe_ttm2, datas1.pb_lf,'ko', label='sample')
plt.plot(datas1.roe_ttm2, y_fitted, 'black',label='OLS',linewidth = 2)
plt.xlabel('ROE')
plt.ylabel('PB')

plt.legend()
plt.show()

关于PB-ROE

PB-ROE提供了一种投资的框架,这种框架是说,股票的PB和ROE之间存在近似的线性关系,ROE越高,PB越高,因此如果同时根据PB、ROE值来投资,很难选到同时满足PB最小、ROE最大的股票。但可以根据他们的线性关系进行选择,回归直线上的点可以视为合理的PB、ROE组合水平,这样位于回归线下方的股票都是PB被低估的,未来有很大的上升修复空间,而位于回归线上方的股票都是当前PB被高估的,未来会下降,因此投资可以选择位于回归线下方的股票。使用这种方法最重要的点是回归必须是靠谱的,比如ROE应该是稳定的,确保未来可持续,比如应想办法消除行业间的差异等等。

lstsq比较方便用在只需要回归系数的情况下,如果需要对回归结果做评估,比如算拟合值、算残差、算R2,做t检验、F检验、算P值,就很麻烦了,而statsmodel恰好适合这种情况。

statsmodels.formula.api(sml)

statsmodels中做回归有很多模块都能实现,sml.ols的优点是可以写成公式型的回归,类似R中做回归的过程,比如PB和ROE的回归可以用公式表示为'pb~roe',多个自变量之间用加号连接。sml.ols一般包括formula和data两个输入,formula是回归的公式,data为使用的数据。此外,还有missing这个参数,对于回归数据包含缺失值时很好用,比如设置missing = 'drop'表示回归时删除包含缺失值的样本。代码如下

代码语言:javascript
复制
import statsmodels.formula.api as sml
model = sml.ols(formula='pb_lf~roe_ttm2',data = datas1)
result=model.fit()

result.params # 回归系数
result.rsquared # R方
result.resid # 残差
result.fittedvalues # 拟合值

summary函数可以出比较美观的结果。

statsmodels.api(sm)

sm.ols是statsmodels中另一个回归的模块,它的输入类似lstsq,输入变量y,x即可,这里使用patsy中的dmatrics生成x,y,需要注意的是,dmatrices生生成的x是自带截距项的,代码如下,summary输出结果同上。

代码语言:javascript
复制
import statsmodels.api as sm
from patsy import dmatrices
from scipy.linalg import toeplitz
import numpy.linalg as la
y,X=dmatrices('pb_lf~roe_ttm2',data=datas1,return_type='dataframe')
mod = sm.OLS(y,X)
res = mod.fit()
res.summary()

GLS

GLS是广义最小二乘法的缩写,刚才总结的OLS满足很多假设,但实际数据往往没有那么好的性质,GLS用来解决异方差的问题,在数据有异方差的问题时,OLS的结果不再具有无偏性等性质,GLS的结果更好。它的主要思想是给解释变量加上一个权重,从而使得加上权重后的回归方程方差是相同的.因此在GLS方法下可以得到估计量的无偏和一致估计。

使用这种方法的前提时,你已经对误差项的协方差阵有了较好的估计。statsmodel中实现GLS的模块如下

sm.GLS

常用的输入包括因变量endog,自变量exog,残差的协方差阵sigma,missing设定样本中缺失值的处理方法,这里exog也是不带截距项的,需要自己加入,可以用sm.add_constant(),代码如下

代码语言:javascript
复制
x = datas1[['roe_ttm2','mktcap']]
x['mktcap'] = np.log(x.mktcap)
sigma = x.T.var()
x = sm.add_constant(x)
y = datas1['pb_lf']

sm.GLS(y, x,sigma = sigma).fit().params

WLS

WLS是加权最小二乘法的简称,如果仔细看上一张图GLS函数的说明,可以看到,当sigma是一个向量的时候,GLS等价于WLS,即WLS表示残差的协方差阵是对角阵。可以用sm.WLS或者sm.GLS实现,代码同上。

RLS

RLS表示带约束的最小二乘法,这里的约束只包括线性约束,可以表示为AX = B的形式,如果有其他类型的约束,需要用其他方法,数学上可以证明,线性约束下,最小二乘法仍有最优解。rls的实现可以使用statsmodels.sandbox.rls。函数说明如下

endog表示Y,exog表示X,constr线性约束的A,params表示线性约束的B,默认为0,sigma是权重,同GLS。大部分跟之前都是一样的,唯一需要注意的是约束的输入,根据约束条件写出A,B然后输入。

带约束的最小二乘法在量化中非常常用,比如做行业中性化时,如果所有行业虚拟变量都保留,并且添加了截距项的情况下,会出现变量多重共线性,回归结果无效,这时候一种方法是删除一个虚拟变量,还有一种方法是添加一个约束。比如可以添加行业的市值占比和系数乘积的和为0:

其中,w为各行业流通市值占比,这种方法下,对pb因子做中性化的代码如下

代码语言:javascript
复制
from statsmodels.sandbox.rls import *
weights = datas.mktcap.groupby(datas.classname).sum()/datas.mktcap.sum()


class_var = pd.get_dummies(datas['classname'],columns=['classname'],prefix='class',
 prefix_sep="_", dummy_na=False, drop_first = False)

x = class_var
x = pd.concat([class_var,np.log(datas.mktcap)],axis = 1)
x = sm.add_constant(x)
y = datas['pb_lf']
con1= [0] + list(weights) + [0]

models = RLS(y, x,constr = con1).fit()

models.resid

Logistic

Logistic回归是一种用来做Y是类别变量的方法,可以用statsmodels.discrete.discrete_model.Logit实现,代码输入跟之前的差不多

写在最后

本文总结了比较常用的一些方法,除此外,还有Lasso、Ridge等回归方法,可以用sklearn实现,不再赘述,列出一些参考网站,如果有没有写清楚的地方,可以再看一看。

  1. http://www.statsmodels.org/stable/index.html
  2. https://patsy.readthedocs.io/en/latest/API-reference.html#patsy.DesignInfo.linear_constraint
  3. https://tedboy.github.io/statsmodels_doc/_modules/statsmodels/sandbox/rls.html#RLS
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 量化小白躺平记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • np.linalg.lstsq(a, b, rcond='warn')
  • statsmodels.formula.api(sml)
  • statsmodels.api(sm)
  • sm.GLS
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档