关于线性回归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]