[量化学堂-数学知识]线性回归

线性回归
标签: #<Tag:0x00007f5c009d0068>

(iQuant) #1

导语: 线性回归模型的最大特点就是简单高效,本文将对线性回归做详细介绍。


线性回归是衡量两个变量之间线性关系的一种建模技术。 如果我们有一个变量$X$和一个依赖变量$X$的变量$Y$,则线性回归可以确定哪个线性模型$Y=α+βX$能够最好地解释数据。 例如,我们考虑浦发银行和沪深300的价格指数, 我们想知道浦发银行如何随着沪深300的变化而变化,因此我们将对这两个标的的日收益率进行回归。

Python的statsmodels库具有内置的线性回归功能。 它将给出最能够拟合数据的一条的直线,并且能够帮助你决定该线性关系是否显著。 线性回归的输出还包括一些有关模型的数值统计信息,如$R方$和$F值$,可以帮助您量化模型的实际的解释能力。


附件:线性回归的使用

克隆策略
In [1]:
# 导入库
import numpy as np
from statsmodels import regression
import statsmodels.api as sm
import matplotlib.pyplot as plt
import math
In [2]:
# 编辑线性回归函数
def linreg(X,Y):
    # 运行线性回归
    X = sm.add_constant(X)
    model = regression.linear_model.OLS(Y, X).fit()
    a = model.params[0]
    b = model.params[1]
    X = X[:, 1]

    # 返回信息并绘图
    X2 = np.linspace(X.min(), X.max(), 100)
    Y_hat = X2 * b + a
    plt.scatter(X, Y, alpha=0.3) # 显示原始数据
    plt.plot(X2, Y_hat, 'r', alpha=0.9);  # 添加拟合直线
    plt.xlabel('X Value')
    plt.ylabel('Y Value')
    return model.summary()
In [3]:
start_date = '2016-01-01'
end_date = '2017-04-11'
# 获取浦发银行的价格数据
asset = D.history_data('600000.SHA',start_date,end_date,fields=['close']).set_index('date')['close']
benchmark = D.history_data('000300.SHA',start_date,end_date,fields=['close']).set_index('date')['close']

 
# 通过价格数据计算收益率数据并删除第一个元素,因为其为缺失值
r_a = asset.pct_change()[1:]
r_b = benchmark.pct_change()[1:]

linreg(r_b.values, r_a.values)
Out[3]:
OLS Regression Results
Dep. Variable: y R-squared: 0.196
Model: OLS Adj. R-squared: 0.194
Method: Least Squares F-statistic: 74.53
Date: Tue, 09 May 2017 Prob (F-statistic): 3.37e-16
Time: 18:56:57 Log-Likelihood: 967.26
No. Observations: 307 AIC: -1931.
Df Residuals: 305 BIC: -1923.
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 5.152e-05 0.001 0.087 0.931 -0.001 0.001
x1 0.4253 0.049 8.633 0.000 0.328 0.522
Omnibus: 91.263 Durbin-Watson: 1.880
Prob(Omnibus): 0.000 Jarque-Bera (JB): 4735.483
Skew: -0.037 Prob(JB): 0.00
Kurtosis: 22.240 Cond. No. 83.0

上述图表中的每个点表示每一个交易日,x坐标是沪深300的收益率,y坐标是浦发银行的收益率。 我们可以看到,拟合度最好的线条告诉我们,沪深300收益每增加1个百分点,浦发银行会增加0.42%。 这由参数$β$表示,估计值为0.4253。 当然,对于收益下降,我们也会看到浦发银行的损失大约不到一半,所以我们看到,浦发银行比沪深300还要稳定

了解参数与估计值

非常重要的是,通过线性回归估计的$α$和$β$参数只是估计值。 除非你知道数据产生的的真实过程,否则你永远不会知道的真实参数。 你今天得到的估计值和明天得到的估计值很可能不一样,即使使用相同的分析方法,真实参数可能也不断在变化。 因此,在进行实际分析时关注参数估计的标准误差是非常重要的。 关于标准误差的更多资料我们将在后文中介绍。 了解估计值的稳定性的一种方法是使用 滚动数据窗口来估计它们。

例子

现在我们看看如果我们对两个随机变量进行回归会发生什么。

In [4]:
X = np.random.rand(100)
Y = np.random.rand(100)
linreg(X, Y)
Out[4]:
OLS Regression Results
Dep. Variable: y R-squared: 0.059
Model: OLS Adj. R-squared: 0.049
Method: Least Squares F-statistic: 6.090
Date: Tue, 09 May 2017 Prob (F-statistic): 0.0153
Time: 18:59:02 Log-Likelihood: -18.045
No. Observations: 100 AIC: 40.09
Df Residuals: 98 BIC: 45.30
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 0.3917 0.058 6.765 0.000 0.277 0.507
x1 0.2450 0.099 2.468 0.015 0.048 0.442
Omnibus: 26.817 Durbin-Watson: 1.605
Prob(Omnibus): 0.000 Jarque-Bera (JB): 5.519
Skew: 0.015 Prob(JB): 0.0633
Kurtosis: 1.849 Cond. No. 4.31

上面显示了一个具有 正态分布 的云点。需要注意的是,即使有100个随机样本,拟合的直线依然具有可见的斜率。 这就是为什么使用统计数据而不是可视化来验证结果的重要性。

现在,我们在X变量的基础上加 随机噪声来构造变量Y

In [21]:
Y = X + 0.2*np.random.randn(100)
linreg(X,Y)
Out[21]:
OLS Regression Results
Dep. Variable: y R-squared: 0.684
Model: OLS Adj. R-squared: 0.681
Method: Least Squares F-statistic: 212.4
Date: Thu, 13 Apr 2017 Prob (F-statistic): 2.85e-26
Time: 16:26:06 Log-Likelihood: 25.939
No. Observations: 100 AIC: -47.88
Df Residuals: 98 BIC: -42.67
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 0.0303 0.040 0.751 0.454 -0.050 0.110
x1 0.9827 0.067 14.573 0.000 0.849 1.116
Omnibus: 4.565 Durbin-Watson: 2.210
Prob(Omnibus): 0.102 Jarque-Bera (JB): 4.238
Skew: 0.327 Prob(JB): 0.120
Kurtosis: 3.768 Cond. No. 4.64

在上述情况下,拟合度最高的直线确实对因变量Y进行了很好的建模(因为具有较高的 R方值)。

基于模型进行预测时,不仅输出预测值,而且还输出 置信区间通常是非常有用的。我们可以使用python的 seaborn库来进行可视化,不仅绘制拟合直线,还会突出显示拟合直线的95%(默认)置信区间:

In [6]:
import seaborn

start_date = '2016-01-01'
end_date = '2017-05-08'
asset = D.history_data('600000.SHA',start_date,end_date,fields=['close']).set_index('date')['close']
benchmark = D.history_data('000300.SHA',start_date,end_date,fields=['close']).set_index('date')['close']
 
# 删除第一个元素(0th),因为其为缺失值
r_a = asset.pct_change()[1:]
r_b = benchmark.pct_change()[1:]

seaborn.regplot(r_b.values, r_a.values)
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fac4a4556d8>

本文由BigQuant宽客学院推出,版权归BigQuant所有,转载请注明出处。


社区干货与精选整理(持续更新中...)