关于线性回归Python库

numpy是一款基础Python包,它可以在单维和多维数组上进行高效的操作。它还提供很多数值计算方法,同时也是开源库。

如果不熟悉numpy,可以阅读官方的numpy使用指南,此外还有numpy相关的文章会在附录中提供。网络上还有大量的numpy资料可供搜索。

scikit-learn是一个被大量用户用于机器学习的Python库,该库是基于numpy和其他库建立的。它可以执行数据预处理,降维,回归,分类和聚类等功能。和numpy一样,scikit-learn也是开源的。

可以在scikit-learn官网上查看Generalized Linear Models页面了解更多关于线性模型的内容以进一步了解该库的原理。

statsmodels库可以实现一些在做线性回归时scikit-learn中没有的功能。它也是一个不错的Python库,主要用于统计模型的估计,模型的测试等等。同时它也是开源的。

基于sklearn的单变量线性回归

这里从最简单的单变量线性回归开始,手把手教你在Python中做线性回归模型,整个过程大致分五个基本步骤:

① 导入相关库和类

② 读取相关数据,对数据进行适当处理

③ 创建回归模型并对现有数据样本进行拟合

④ 查看模型的拟合结果,判断模型是否合理

⑤ 用模型进行预测

这几个步骤在大多数回归方法中基本是通用的。

Step 1:导入相关库和类

首先导入pandas,tushare库和sklearn.linear_model中的LinearRegression类:

import pandas as pd
import numpy as np
import tushare as ts
from sklearn.linear_model import LinearRegression

当然,也可以用numpy库。pandas和numpy的数据类型可以与sklearn无缝对接,并且高效,可读性强。而类sklearn.linear_model.LinearRegression提供了执行线性回归的相关功能。

Step 2:读取数据

# 使用tushare获取数据ts.set_token('your token')
pro = ts.pro_api()

# 获取沪深300与中国平安股票2018年全年以及2019年前7个交易日的日线数据
index_hs300 = pro.index_daily(ts_code='399300.SZ', start_date='20180101', end_date='20190110')
stock_000001 = pro.query('daily', ts_code='000001.SZ', start_date='20180101', end_date='20190110', fields='ts_code, trade_date ,pct_chg')

# 保留用于回归的数据,数据对齐
# join的inner参数用于剔除指数日线数据中中国平安无交易日的数据,比如停牌。
# 同时保留中国平安和指数的日收益率并分别命名两组列名y_stock, x_index,确定因变量和自变量
index_pct_chg = index_hs300.set_index('trade_date')['pct_chg']
stock_pct_chg = stock_000001.set_index('trade_date')['pct_chg']
df = pd.concat([stock_pct_chg, index_pct_chg], keys=['y_stock', 'x_index'], join='inner', axis=1, sort=True)

# 选中2018年的x,y数据作为现有数据进行线性回归
df_existing_data = df[df.index]
#注意:自变量x为pandas.DataFrame类型,其为二维数据结构,注意与因变量的pandas.Series数据结构的区别。也可以用numpy.array的.reshape((-1, 1))将数据结构改为二维数组。

x = df_existing_data[['x_index']]
y = df_existing_data['y_stock']

经过简单处理,现在有了自变量x和因变量y。需要注意的是,sklearn.linear_model.LinearRegression类需要传入的自变量是一组二维数组结构,因此可以通过numpy的.reshape()方法将一维数组变更为二维数组,另一种方法就是使用pandas的DataFrame格式。

现在自变量和因变量看起来像这样:

print(x.head())
print(y.head())
            x_index
trade_date         
20180102     1.4028
20180103     0.5870
20180104     0.4237
20180105     0.2407
20180108     0.5173
trade_date
20180102    3.01
20180103   -2.70
20180104   -0.60
20180105    0.38
20180108   -2.56
Name: y_stock, dtype: float64

可以通过.shape参数看到x有两个维度(243, 1),而y是一维数组,(243, )。

Step 3:建立模型并拟合数据

第三步,建立线性回归模型,并用中国平安和沪深300的2018年全年日线收益率数据进行拟合。先创建一个LinearRegression的实例用于建立回归模型:

model = LinearRegression()

这里创建了一个默认参数的LinearRegression类实例。可以为LinearRegression传入以下几个可选参数:

  • fit_intercept:布尔值,默认为True。True为需要计算截距b0,False为不需要截距,即b0=0。
  • normalize:布尔值,默认为False。参数作用是将数据标准化,False表示不做标准化处理。
  • copy_x:布尔值,默认为True。True为保留x数组,False为覆盖原有的x数组。
  • n_jobs:整型或者None,默认为None。这个参数用于决定并行计算线程数。None表示单线程,-1表示使用所有线程。

模型建立以后,首先需要在模型上调用.fit()方法:

model.fit(x, y)

用现有的数据集x-y,通过.fit()方法,可以计算出线性回归方程的最优权重b0和b1。换句话说,数据集x-y通过.fit()方法拟合了回归模型。.fit()方法输出self,也就是输出model模型本身。可以将以上两个语句简化为:

model = LinearRegression().fit(x, y)

Step 4:输出结果

数据拟合模型后,可以输出结果看看模型是否满意,以及是否可以合理的解释数据的趋势或者依赖关系。

可以通过调用.score()方法来获取model的R2:

model = LinearRegression().fit(x, y)
r_sq = model.score(x, y)
print('coefficient of determination: ', r_sq)
coefficient of determination:  0.5674052646582468

同时,也可以通过调取model的.intercept_和.coef_属性获取截距b0和斜率b1:

print('intercept:', model.intercept_)
print('slope:', model.coef_)
intercept: 0.01762302497463801
slope: [1.18891167]

需要注意的是,.intercept_是一个numpy.float64数值,而.coef_是一个numpy.array数组。

b0=0.017,表示自变量沪深300的日收益率为0时,因变量中国平安股票的日收益率大约为 0.017%。而b1=1.189,表示沪深300的日收益率增加1%时,中国平安股票的日收益率增加1.189%。反之亦然。

在上面的数据载入中,因变量y也可以是二维数组,这种情形下的输出结果和以上类似:

y = pd.DataFrame(y)
new_model = LinearRegression().fit(x, y)
print('intercept:', new_model.intercept_)
print('slope:', new_model.coef_)
intercept: [0.01762302]
slope: [[1.18891167]]

可以看到此次输出结果中,b0变为一维numpy.array数组,而不是之前的float64数值。而b1输出一组二维numpy.array数组。

Step 5:模型预测

获得了比较合理的模型后,可以用现有数据或者新数据来进行预测。

本例中使用了沪深300指数2019年前7个交易日的收益率数据对中国平安股票进行预测,由于本文主旨是介绍线性回归的原理与相关使用方法,模型的预测效果本文中不做探讨。当然,也可以用2018年的现有的自变量数据获取回归模型的数据f(x)。

要获得预测结果,可以使用.predict()方法:

# 选2019年前7个交易日的数据作为新数据进行预测df_new_data = df[df.index > '20190101']
# 将自变量x,数据类型为DataFrame
new_x = df_new_data[['x_index']]

# 预测
y_pred = model.predict(new_x)
print('predicted response:', y_pred, sep='\n')
predicted response:
[-1.60619253 -0.17022502  2.86601759  0.73929241 -0.23930079  1.21806713
 -0.20601126]

.predict()方法需要将新的自变量传入该方法中以获得预测值。也可以用下面这种方法:

b0, b1 = model.intercept_, model.coef_
y_pred = b0 + b1 * new_x
y_pred.columns = ['y_pred']
print('predicted response:', y_pred, sep='\n')
predicted response:
              y_pred
trade_date          
20190102   -1.606193
20190103   -0.170225
20190104    2.866018
20190107    0.739292
20190108   -0.239301
20190109    1.218067
20190110   -0.206011

这种方式可以将模型通过函数形式直观的表达出来。与.predict()的方法相比,这种方式的输出结果是一个DataFrame类型,其为二维数组结构。而.predict()仅输出一组一维numpy.array数组。

如果将new_x改为一维数组,y_pred的输出结果将与.predict()一致。

实践中,回归模型通常可以用来做预测。这意味着可以将一些新的自变量数据x传入拟合好的模型中来计算结果。比如假设一组沪深300日收益率数据[0, 1, 2, 3, 4],通过model获得中国平安股票的日收益率预测结果:

x_new = np.arange(5).reshape((-1, 1))
y_new = model.predict(x_new)
print(y_new)
[0.01762302 1.20653469 2.39544636 3.58435802 4.77326969]