2020-05-17 第八章 岭回归与Lasso回归模型(pyt
岭回归与Lasso回归模型
01 线性回归模型的短板
背景知识
根据线性回归模型的参数估计公式可知,得到β的前提是矩阵可逆,但在实际应用中,可能会出现自变量个数多于样本量或者自变量间存在多重共线性的情况,即的行列式为0。此时将无法根据公式计算回归系数的估计值β。
02 岭回归与Lasso回归的系数求解
岭回归模型
为解决多元线性回归模型中可能存在的不可逆问题,统计学家提出了岭回归模型。该模型解决问题的思路就是在线性回归模型的目标函数之上添加正则项(也称为惩罚项)。
- 在线性回归模型的目标函数之上添加正则项,其中为非负数
- 当时,目标函数退化为线性回归模型的目标函数
- 当时,通过缩减回归系数使趋近于0
- 是正则项平方的系数,用于平衡模型方差(回归系数的方差)和偏差
参数β的求解
具体方程推导就不列出了
模型方差与偏差的理解
image.png随着λ的增大,模型方差会减小(因为矩阵(X^′X+λI)的行列式随λ的增加在增加,使得矩阵的逆就会逐渐减小,进而岭回归系数被“压缩”而变小)而偏差会增大。
03 系数求解的几何意义
几何意义
image.png以二维空间为例(即自变量仅包含和两个),左半边的半椭圆体代表了的部分,它是关于两个系数的二次函数;圆柱体代表了的部分;
右半边为二维坐标下的映射图,对于线性回归模型来说,抛物面的中心黑点代表模型的最小二乘解,当附加时,抛物面与圆面构成的交点就是岭回归模型的系数解。
公式推导比较抽象。
04 Lasso回归的变量选择
05 岭回归与Lasso回归的应用实战
岭回归模型的应用
λ值的确定--可视化法
由于岭回归模型的系数是关于λ值的函数,因此可以通过绘制不同的λ值和对应回归系数的折线图确定合理的λ值。
一般而言,当回归系数随着λ值的增加而趋近于稳定的点时就是所要寻找的λ值。
用法
Ridge(alpha=1.0, fit_intercept=True, normalize=False, copy_X=True,
max_iter=None, tol=0.001, solver='auto', random_state=None)
alpha:用于指定lambda值的参数,默认该参数为1
fit_intercept:bool类型参数,是否需要拟合截距项,默认为True
normalize:bool类型参数,建模时是否需要对数据集做标准化处理,默认为False
copy_X:bool类型参数,是否复制自变量X的数值,默认为True
max_iter:用于指定模型的最大迭代次数
tol:用于指定模型收敛的阈值
solver:用于指定模型求解最优化问题的算法,默认为'auto',表示模型根据数据集自动选择算法
random_state:用于指定随机数生成器的种子
核心代码
import pandas as pd
import numpy as np
from sklearn import model_selection
from sklearn.linear_model import Ridge,RidgeCV
import matplotlib.pyplot as plt
# 读取糖尿病数据集
diabetes = pd.read_excel('./diabetes.xlsx', sep = '')
# 构造自变量(剔除患者性别、年龄和因变量)
predictors = diabetes.columns[2:-1]
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = model_selection.train_test_split(diabetes[predictors], diabetes['Y'],
test_size = 0.2, random_state = 1234 )
# 构造不同的Lambda值
Lambdas = np.logspace(-5, 2, 200)
# 构造空列表,用于存储模型的偏回归系数
ridge_cofficients = []
# 循环迭代不同的Lambda值
for Lambda in Lambdas:
ridge = Ridge(alpha = Lambda, normalize=True)
ridge.fit(X_train, y_train)
ridge_cofficients.append(ridge.coef_)
# 绘制Lambda与回归系数的关系
# 中文乱码和坐标轴负号的处理
plt.rcParams['font.sans-serif'] = ['Helvetica']
plt.rcParams['axes.unicode_minus'] = False
# 设置绘图风格
plt.style.use('ggplot')
plt.plot(Lambdas, ridge_cofficients)
# 对x轴作对数变换
plt.xscale('log')
# 设置折线图x轴和y轴标签
plt.xlabel('Lambda')
plt.ylabel('Cofficients')
# 图形显示
plt.show()
Figure_1.png
解读
图中的每条折线代表了不同的变量,对于比较突出的喇叭形折线,一般代表该变量存在多重共线性;
从图中可知,当值逼近于0时,各变量对应的回归系数应该与线性回归模型的最小二乘解完全一致;随着值的不断增加,各回归系数的取值会迅速缩减为0;
按照值的选择标准,发现值在0.01附近时,绝大多数变量的回归系数趋于稳定,故认为值可以选择在0.01附近;
λ值的确定--交叉验证法
交叉验证的思想
- 首先将数据集拆分成k个样本量大体相当的数据组(如图中的第一行),并且每个数据组与其他组都没有重叠的观测;
- 然后从k组数据中挑选k−1组数据用于模型的训练,剩下的一组数据用于模型的测试(如图中的第二行);
- 以此类推,将会得到k种训练集和测试集。在每一种训练集和测试集下,都会对应一个模型及模型得分(如均方误差)。
用法
RidgeCV(alphas=(0.1, 1.0, 10.0), fit_intercept=True, normalize=False,
scoring=None, cv=None, gcv_mode=None, store_cv_values=False)
alphas:用于指定多个lambda值的元组或数组对象,默认该参数包含0.1、1和10三种值。
fit_intercept:bool类型参数,是否需要拟合截距项,默认为True。
normalize:bool类型参数,建模时是否需要对数据集做标准化处理,默认为False。
scoring:指定用于评估模型的度量方法。
cv:指定交叉验证的重数。
gcv_mode:用于指定执行广义交叉验证的方法,当样本量大于特征数或自变量矩阵X为稀疏矩阵时,该参数选用'auto';当该参数为'svd'时,表示通过矩阵X的奇异值分解方法执行广义交叉验证;当该参数为'engin'时,则表示通过矩阵X'X的特征根分解方法执行广义交叉验证。
store_cv_values:bool类型参数,是否在每一个Lambda值下都保存交叉验证得到的评估信息,默认为False,只有当参数cv为None时有效。
示例
# 岭回归模型的交叉验证
# 设置交叉验证的参数,对于每一个Lambda值,都执行10重交叉验证
ridge_cv = RidgeCV(alphas = Lambdas, normalize=True, scoring='neg_mean_squared_error', cv = 10)
# 模型拟合
ridge_cv.fit(X_train, y_train)
# 返回最佳的lambda值
ridge_best_Lambda = ridge_cv.alpha_
ridge_best_Lambda
结果为0.014649713983072863
糖尿病数据的预测
# 导入第三方包中的函数
from sklearn.metrics import mean_squared_error
# 基于最佳的Lambda值建模
ridge = Ridge(alpha = ridge_best_Lambda, normalize=True)
ridge.fit(X_train, y_train)
# 返回岭回归系数
pd.Series(index = ['Intercept'] + X_train.columns.tolist(),data = [ridge.intercept_] + ridge.coef_.tolist())
# 预测
ridge_predict = ridge.predict(X_test)
# 预测效果验证
RMSE = np.sqrt(mean_squared_error(y_test,ridge_predict))
RMSE
结果为53.11911788753519
Lasso回归的系数求解
Lasso回归模型
岭回归模型解决线性回归模型中矩阵不可逆的办法是添加正则的惩罚项,但缺陷在于始终保留建模时的所有变量,无法降低模型的复杂度。对于此,Lasso回归采用了正则的惩罚项。
具体公式推导不列出
几何意义
image.png以二维空间为例,左半边的半椭圆体代表|β_1|+|β_2|≤t$的部分;
将LASSO回归的惩罚项映射到二维空间的话,就会形成“角”,一旦“角”与抛物面相交,就会导致为0,进而实现变量的删除。而且相比于圆面,正则项的方框顶点更容易与抛物面相交,起到变量筛选的效果;
λ值的确定--可视化法
用法
Lasso(alpha=1.0, fit_intercept=True, normalize=False, precompute=False,
copy_X=True, max_iter=1000, tol=0.0001, warm_start=False,
positive=False, random_state=None, selection='cyclic')
alpha:用于指定lambda值的参数,默认该参数为1
fit_intercept:bool类型参数,是否需要拟合截距项,默认为True
normalize:bool类型参数,建模时是否需要对数据集做标准化处理,默认为False
precompute:bool类型参数,是否在建模前通过计算Gram矩阵提升运算速度,默认为False
copy_X:bool类型参数,是否复制自变量X的数值,默认为True
max_iter:用于指定模型的最大迭代次数,默认为1000
tol:用于指定模型收敛的阈值,默认为0.0001。
warm_start:bool类型参数,是否将前一次的训练结果用作后一次的训练,默认为False。
positive:bool类型参数,是否将回归系数强制为正数,默认为False。
random_state:用于指定随机数生成器的种子。
selection:指定每次迭代时所选择的回归系数,如果为'random',表示每次迭代中将随机更新回归系数;如果为'cyclic',则表示每次迭代时回归系数的更新都基于上一次运算
核心代码示例
# 导入第三方模块中的函数
from sklearn.linear_model import Lasso,LassoCV
# 构造空列表,用于存储模型的偏回归系数
lasso_cofficients = []
for Lambda in Lambdas:
lasso = Lasso(alpha = Lambda, normalize=True, max_iter=10000)
lasso.fit(X_train, y_train)
lasso_cofficients.append(lasso.coef_)
# 绘制Lambda与回归系数的关系
plt.plot(Lambdas, lasso_cofficients)
# 对x轴作对数变换
plt.xscale('log')
# 设置折线图x轴和y轴标签
plt.xlabel('Lambda')
plt.ylabel('Cofficients')
# 显示图形
plt.show()
Figure_2.png
解读
图中的每条折线代表了不同的变量,对于比较突出的喇叭形折线,一般代表该变量存在多重共线性;
从图中可知,当值逼近于0时,各变量对应的回归系数应该与线性回归模型的最小二乘解完全一致;随着值的不断增加,各回归系数的取值会迅速缩减为0;
当值落在0.05附近时,绝大多数变量的回归系数趋于稳定,所以,基本可以锁定合理的值范围;
λ值的确定--交叉验证法
用法
LassoCV(eps=0.001, n_alphas=100, alphas=None, fit_intercept=True, normalize=False,
precompute='auto', max_iter=1000, tol=0.0001, copy_X=True, cv=None,
verbose=False, n_jobs=1, positive=False, random_state=None,
selection='cyclic')
eps:指定正则化路径长度,默认为0.001,指代Lambda的最小值与最大值之商
n_alphas:指定正则项系数Lambda的个数,默认为100个
alphas:指定具体的Lambda值列表用于模型的运算
fit_intercept:bool类型参数,是否需要拟合截距项,默认为True
normalize:bool类型参数,建模时是否需要对数据集做标准化处理,默认为False
precompute:bool类型参数,是否在建模前,通过计算Gram矩阵提升运算速度,默认为False
max_iter:指定模型最大的迭代次数,默认为1000次
tol:用于指定模型收敛的阈值,默认为0.001
copy_X:bool类型参数,是否复制自变量X的数值,默认为True
cv:指定交叉验证的重数
verbose:bool类型参数,是否返回模型运行的详细信息,默认为False
n_jobs:指定交叉验证过程中使用的CPU数量,即是否需要并行处理,默认为1表示不并行运行,如果为-1,表示将所有的CPU用于交叉验证的运算
positive:bool类型参数,是否将回归系数强制为正数,默认为False
random_state:用于指定随机数生成器的种子
selection:指定每次迭代时所选择的回归系数,如果为'random',表示每次迭代中将随机更新回归系数;如果为'cyclic',则表示每次迭代时回归系数的更新都基于上一次运算
示例
# LASSO回归模型的交叉验证
lasso_cv = LassoCV(alphas = Lambdas, normalize=True, cv = 10, max_iter=10000)
lasso_cv.fit(X_train, y_train)
# 输出最佳的lambda值
lasso_best_alpha = lasso_cv.alpha_
lasso_best_alpha
结果为0.06294988990221888
# 基于最佳的lambda值建模
lasso = Lasso(alpha = lasso_best_alpha, normalize=True, max_iter=10000)
lasso.fit(X_train, y_train)
# 返回LASSO回归的系数
pd.Series(index = ['Intercept'] + X_train.columns.tolist(),data = [lasso.intercept_] + lasso.coef_.tolist())
# 预测
lasso_predict = lasso.predict(X_test)
# 预测效果验证
RMSE = np.sqrt(mean_squared_error(y_test,lasso_predict))
RMSE
结果为53.061437258225745
糖尿病数据的预测结果53.048714552744023
与前面的岭回归预测结果类似。