Python金融系列第五篇:多元线性回归和残差分析
作者:chen_h
微信号 & QQ:862251340
微信公众号:coderpai
第一篇:计算股票回报率,均值和方差
第二篇:简单线性回归
第三篇:随机变量和分布
第四篇:置信区间和假设检验
第五篇:多元线性回归和残差分析
第六篇:现代投资组合理论
第七篇:市场风险
第八篇:Fama-French 多因子模型
介绍
在前某章中,我们介绍了简单的线性回归,它只有一个自变量。在本章中,我们将学习具有多个自变量的线性回归。
简单的线性回归模型以下列形式编写:
Y=α+βX+ϵY = \alpha + \beta X + \epsilonY=α+βX+ϵ
具有 p 个变量的多元线性回归模型可以由下面的公式给出:
Y=α+β1X1+β2X2+β3X3+⋯+βpXp+ϵY = \alpha + \beta_{1}X_{1}+ \beta_{2}X_{2}+ \beta_{3}X_{3}+ \cdots + \beta_{p}X_{p} + \epsilonY=α+β1X1+β2X2+β3X3+⋯+βpXp+ϵ
Python 实现
在上一章中,我们使用标普500指数来预测亚马逊股票收益率。现在我们将添加更多变量来改进模型的预测。特别是,我们将考虑亚马逊的竞争对手。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.formula.api as sm
from pandas_datareader import data as pdr
import fix_yahoo_finance as yf# Get stock prices
spy_table = pdr.get_data_yahoo("SPY")
amzn_table = pdr.get_data_yahoo("AMZN")
ebay_table = pdr.get_data_yahoo("EBAY")
wal_table = pdr.get_data_yahoo("WMT")
aapl_table = pdr.get_data_yahoo("AAPL")
然后我们从 2016 年开始获取收盘价:
spy = spy_table .loc['2016',['Close']]
amzn = amzn_table.loc['2016',['Close']]
ebay = ebay_table.loc['2016',['Close']]
wal = wal_table .loc['2016',['Close']]
aapl = aapl_table.loc['2016',['Close']]
在获取每个股票的日志返回后,我们将它们连接成一个 DataFrame,并打印出最后五行:
spy_log = np.log(spy.Close) .diff().dropna()
amzn_log = np.log(amzn.Close).diff().dropna()
ebay_log = np.log(ebay.Close).diff().dropna()
wal_log = np.log(wal.Close) .diff().dropna()
aapl_log = np.log(aapl.Close).diff().dropna()
df = pd.concat([spy_log,amzn_log,ebay_log,wal_log,aapl_log],axis = 1).dropna()
df.columns = ['SPY', 'AMZN', 'EBAY', 'WAL', 'AAPL']
df.tail()
SPY | AMZN | EBAY | WAL | AAPL | |
---|---|---|---|---|---|
Date | |||||
2016-12-23 | 0.001463 | -0.007531 | 0.008427 | -0.000719 | 0.001976 |
2016-12-27 | 0.002478 | 0.014113 | 0.014993 | 0.002298 | 0.006331 |
2016-12-28 | -0.008299 | 0.000946 | -0.007635 | -0.005611 | -0.004273 |
2016-12-29 | -0.000223 | -0.009081 | -0.001000 | -0.000722 | -0.000257 |
2016-12-30 | -0.003662 | -0.020172 | -0.009720 | -0.002023 | -0.007826 |
跟以前一样,我们使用 statsmodels
包来执行简单的线性回归:
import statsmodels.formula.api as sm
simple = sm.ols(formula = 'amzn ~ spy',data = df).fit()
print(simple.summary())
OLS Regression Results
==============================================================================
Dep. Variable: amzn R-squared: 0.230
Model: OLS Adj. R-squared: 0.227
Method: Least Squares F-statistic: 74.46
Date: Tue, 09 Oct 2018 Prob (F-statistic): 7.44e-16
Time: 11:55:12 Log-Likelihood: 680.94
No. Observations: 251 AIC: -1358.
Df Residuals: 249 BIC: -1351.
Df Model: 1
Covariance Type: nonrobust
==============================================================================coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept 0.0002 0.001 0.196 0.845 -0.002 0.002
spy 1.0661 0.124 8.629 0.000 0.823 1.309
==============================================================================
Omnibus: 67.332 Durbin-Watson: 2.018
Prob(Omnibus): 0.000 Jarque-Bera (JB): 2026.389
Skew: -0.074 Prob(JB): 0.00
Kurtosis: 16.919 Cond. No. 121.
==============================================================================
同样,我们可以构建一个多元线性回归模型:
import statsmodels.formula.api as sm
model = sm.ols(formula = 'amzn ~ spy + ebay + wal',data = df).fit()
print(model.summary())
OLS Regression Results
==============================================================================
Dep. Variable: amzn R-squared: 0.250
Model: OLS Adj. R-squared: 0.238
Method: Least Squares F-statistic: 20.52
Date: Tue, 09 Oct 2018 Prob (F-statistic): 1.32e-14
Time: 13:23:15 Log-Likelihood: 684.25
No. Observations: 251 AIC: -1358.
Df Residuals: 246 BIC: -1341.
Df Model: 4
Covariance Type: nonrobust
==============================================================================coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept 0.0002 0.001 0.229 0.819 -0.002 0.002
spy 1.0254 0.170 6.038 0.000 0.691 1.360
ebay -0.0774 0.058 -1.325 0.186 -0.193 0.038
wal -0.0838 0.089 -0.943 0.346 -0.259 0.091
aapl 0.1576 0.084 1.883 0.061 -0.007 0.322
==============================================================================
Omnibus: 69.077 Durbin-Watson: 1.983
Prob(Omnibus): 0.000 Jarque-Bera (JB): 1890.930
Skew: -0.272 Prob(JB): 0.00
Kurtosis: 16.435 Cond. No. 179.
==============================================================================
从上表中我们可以看出,ebay,walmart 和 apple 的 p 值分别是 0.186,0.346,0.061,因此在 95% 置信水平下他们都不显著。多元回归模型具有比简单模型更高的R2R^{2}R2 ,0.254 VS 0.234。实际上,R2R^{2}R2 不会随着变量数量的增加而减少。为什么呢?如果在我们的回归模型中添加一个额外的变量,但它无法解释响应中的变化(amzn),那么它的估计系数将只是零。就好像该变量从未包含在模型中一样,因此 R2R^{2}R2 不会改变。但是,添加数百个变量并不总是更好,这个问题我们会在后续章节中讨论。
我们可以进一步改进模型吗?在这里,我们尝试 Fama-French 5因子模型,这是资产定价理论中的一个重要模型。我们将会在后面的教程中介绍。数据下载地址
path = './F-F_Research_Data_5_Factors_2x3_daily.CSV'
fama_table = pd.read_csv(path)# Convert time column into index
fama_table.index = [datetime.strptime(str(x), "%Y%m%d")for x in fama_table.iloc[:,0]]
# Remove time column
fama_table = fama_table.iloc[:,1:]
通过这些数据,我们可以构建一个 Fama-French 因子模型:
fama = fama_table['2016']
fama = fama.rename(columns = {'Mkt-RF':'MKT'})
fama = fama.apply(lambda x: x/100)
fama_df = pd.concat([fama, amzn_log], axis = 1)
fama_model = sm.ols(formula = 'Close~MKT+SMB+HML+RMW+CMA', data = fama_df).fit()
print(fama_model.summary())
OLS Regression Results
==============================================================================
Dep. Variable: Close R-squared: 0.387
Model: OLS Adj. R-squared: 0.375
Method: Least Squares F-statistic: 30.96
Date: Tue, 09 Oct 2018 Prob (F-statistic): 2.24e-24
Time: 13:46:31 Log-Likelihood: 709.57
No. Observations: 251 AIC: -1407.
Df Residuals: 245 BIC: -1386.
Df Model: 5
Covariance Type: nonrobust
==============================================================================coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept 0.0010 0.001 1.027 0.305 -0.001 0.003
MKT 0.9614 0.125 7.692 0.000 0.715 1.208
SMB -0.5891 0.182 -3.235 0.001 -0.948 -0.230
HML -0.1342 0.211 -0.636 0.525 -0.550 0.282
RMW -0.4852 0.264 -1.840 0.067 -1.005 0.034
CMA -1.5543 0.324 -4.797 0.000 -2.193 -0.916
==============================================================================
Omnibus: 69.466 Durbin-Watson: 1.937
Prob(Omnibus): 0.000 Jarque-Bera (JB): 2013.541
Skew: 0.241 Prob(JB): 0.00
Kurtosis: 16.867 Cond. No. 399.
==============================================================================
Fama-French 5因子模型的 R2R^2R2 值更高,为 0.387。我们可以将简单线性回归和 Fama-French 多元回归的预测进行比较,将它们绘制在一个图表上:
result = pd.DataFrame({'simple regression': simple.predict(),'fama_french': fama_model.predict(),'sample': df.amzn}, index = df.index)# Feel free to adjust the chart size
plt.figure(figsize = (15,7.5))
plt.plot(result['2016-7':'2016-9'].index,result.loc['2016-7':'2016-9','simple regression'])
plt.plot(result['2016-7':'2016-9'].index,result.loc['2016-7':'2016-9','fama_french'])
plt.plot(result['2016-7':'2016-9'].index,result.loc['2016-7':'2016-9','sample'])
plt.legend()
plt.show()
虽然从上图中很难看出,多元回归的预测回报更接近实际回报。通常我们不会绘制预测来确定哪个模型更好。
模型意义测试
我们可以执行假设检验:F 检验。而不是使用 R2R^{2}R2 来评估我们的回归模型是否适合数据。F检验的零假设和替代假设是:
H0:β1=β2=⋯=βp=0H_{0} : \beta_{1} = \beta_{2} = \cdots = \beta_{p} = 0H0:β1=β2=⋯=βp=0
H1:Atleastonecoefficientisnot0H_{1} : At least one coefficient is not 0H1:Atleastonecoefficientisnot0
我们不会再这里详细解释 F 检验程序。你只需要了解 null 和替代假设。在 F 检验的汇总表中,‘F-statistic’ 是 F 分数,而 ‘prob (F-statistic)’ 是 p 值。在 Fama-French 模型上进行这个测试,我们得到一个 p 值为 2.21e-24,所以我们几乎可以肯定至少有一个系数不是 0。如果 p 值大于 0.05,你应该考虑用其他自变量重建模型。在简单线性回归中,F检验等效于斜率上的 t 检验,因此它们的 p 值将是相同的。
残差分析
线性回归要求预测变量和响应具有线性关系。无论预测变量 X1,⋯ ,XpX_{1}, \cdots , X_{p}X1,⋯,Xp 采用什么值,这个假设都保留残差平均为零。通常,它也假设残差是独立的,并且通常以相同的方差(同方差性)分布 ,因此我们可以构建预测区间。为了检查这些假设是否成立,我们需要分析残差。在统计套利中,残差分析也可用于生成信号。
常态
线性模型的残差通常具有正太分布。我们可以绘制残差密度来检查正态性:
plt.figure()
#ols.fit().model is a method to access to the residual.
fama_model.resid.plot.density()
plt.show()
从图中可以看出,残差是正太分布的。顺便说一句,残差平均值始终为零,达到机器精度:
print('Residual mean:', np.mean(fama_model.resid))
#[out]: Residual mean: -2.3133332345775173e-16
print('Residual variance:', np.var(fama_model.resid))
#[out]: Residual variance: 0.00020513219588900726
同方差(Homoskedasticity)
这个词英文太难念了,但是不难理解。这意味着残差对于 X 的所有值具有相同的方差。否则我们说 “异方差性” 被检测到。
plt.figure(figsize = (20,10))
plt.scatter(df.spy,simple.resid)
plt.axhline(0.05)
plt.axhline(-0.05)
plt.xlabel('x value')
plt.ylabel('residual')
plt.show()
从图表中可以看出,残差的方差不会随着 X 而增加。这三个异常值并没有改变我们的结论。虽然我们可以绘制残差用于简单回归,但我们不能对多元回归进行绘制,因此我们使用 statsmodels
来测试异方差性:
from statsmodels.stats import diagnostic as dia
het = dia.het_breuschpagan(fama_model.resid,fama_df[['MKT','SMB','HML','RMW','CMA']][1:])
print('p-value: ', het[-1])
#[out]:p-value of Heteroskedasticity: 0.14396983553305295
在 95% 的显著性水平上没有检测到异方差性。
Python金融系列第五篇:多元线性回归和残差分析相关推荐
- Python金融系列第八篇:Fama-French 多因子模型
作者:chen_h 微信号 & QQ:862251340 微信公众号:coderpai 第一篇:计算股票回报率,均值和方差 第二篇:简单线性回归 第三篇:随机变量和分布 第四篇:置信区间和假设 ...
- sklearn实现一元线性回归 【Python机器学习系列(五)】
sklearn实现一元线性回归 [Python机器学习系列(五)] 文章目录 1.获取数据 2.线性回归模型 大家好,我是侯小啾! 本期blog分享的内容是通过sklearn库实现一元线性回归.相比 ...
- Python学习系列(五)(文件操作及其字典)
Python学习系列(五)(文件操作及其字典) Python学习系列(四)(列表及其函数) 一.文件操作 1,读文件 在以'r'读模式打开文件以后可以调用read函数一次性将文件内容全部读出 ...
- Python使用sklearn和statsmodels构建多元线性回归模型(Multiple Linear Regression)并解读
Python使用sklearn和statsmodels构建多元线性回归模型(Multiple Linear Regression)并解读 #仿真数据集(预测股票指数) 这里的目标是根据两个宏观经济变量 ...
- python连载第十五篇~史上最全列表知识源码+答案
#2017-12-19 19:34:41 December Tuesday the 51 week, the 353 day #python连载第十五篇~list列表#列表定义,访问,索引,操作,切片 ...
- 转载 解密蓝牙mesh系列 | 第五篇 【好友(Friend)和低功耗节点(LPN)】【友谊(Friendship)参数】【友谊建立】【友谊(Friendship)消息传送】【安全性】【友谊终止】
YD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机.32位ARM Cortex-M0处理器.128kB Flash存储器.以及丰富的数字接口.SYD8801片上集成了B ...
- python学习[第十五篇] 文件系统
python学习[第十五篇] 文件系统 对文件系统访问大多数都通过os模块实现. os 模块文件/目录访问函数 文件处理 mkfifo() 创建命名通道只用于linux remove(path)/un ...
- 互联网神经学系列第五篇:研究大脑中的谷歌,脸书和华为思科路由,脑互联网生理学
本文是互联网神经学系列第五篇-"大脑中的类互联网应用和结构,脑互联网生理学" 一.人类大脑研究的困境 大脑的秘密一直是科学皇冠上最明亮的宝石之一,但在两千年前,人们确连它的重要意义 ...
- 【云原生Kubernetes系列第五篇】kubeadm v1.20 部署K8S 集群架构(人生这道选择题,总会有遗憾)
系列文章目录 ??即日起,更新云原生相关知识,喜欢的小伙伴可以给我点个三连喔 ??收录至专栏 云原生 ??[云原生Docker系列第一篇]Docker镜像管理 ??[云原生Docker系列第二篇]Do ...
最新文章
- Delphi 原生ADO(二)
- vue 返回滚动条顶部组件_vue中回到顶部
- 阿里云服务器(Ubuntu16.04 64位)远程连接
- 不同浏览器前端调试查看返回页面的json数据
- 三点到六点是几个小时_环卫工在10吨垃圾里找了6小时,终于找到这张价值19万元的餐巾纸...
- 漫画:什么是HashMap?
- 【教程】javascript浏览器对象入门教程
- 【刷算法】LeetCode- 阶乘后的零
- 为什么我会觉得SegmentFault做得越来越力不从心了?
- 原生js预览ofd文件
- 韩顺平 javascript教学视频_学习笔记24_dom编程开山篇_dom编程实例(乌龟抓鸡)
- 青花瓷 Charles 抓包工具下载安装破解 JDK环境下载安装
- 2021年最推荐的十大进销存管理软件排名
- 组态软件DIAView、扫码枪和第三方系统MES、SAP等应用
- C++厘米和英寸的换算
- <一起JS(基础篇)>4.标识符、字符串、Number、波尔值、Null和Undefined
- 《沃顿商学院谈判课》读书笔记
- png转ico+windows图标+GIMP
- 小米9 MIUI12.5 红米 K40s MIUI13.0.10 安装谷歌框架
- js判断字符超长度中间用...替换