根据线性回归模型的参数估计公式 β = ( X ′ X ) − 1 X ′ y \beta=(X'X)^{-1}X'y β=(X′X)−1X′y 可知,得到 β \beta β 的前提是 ( X ′ X ) − 1 (X'X)^{-1} (X′X)−1 必须不为零,即可逆。但在实际应用中,可能会出现自变量个数多于样本量,或者自变量间存在多重共线性的情况,此时 X ′ X = 0 X'X=0 X′X=0 ,将无法再根据公式计算出回归系数的估计值 β \beta β.
为解决多元线性回归模型中可能存在的不可逆问题,提出了岭回归模型。该模型解决思路就是,在线性回归模型的目标函数上添加 l 2 l2 l2正则项(惩罚项)
J ( β ) = ∑ ( y − X β ) 2 + λ ∣ ∣ β ∣ ∣ 2 2 = ∑ ( y − X β ) 2 + ∑ λ β 2 J(\beta)=\sum(y-X\beta)^2+\lambda||\beta||_2^2=\sum(y-X\beta)^2+\sum\lambda\beta^2 J(β)=∑(y−Xβ)2+λ∣∣β∣∣22=∑(y−Xβ)2+∑λβ2
在线性回归模型的目标函数中添加l2正则项,其中 λ \lambda λ为非负数。当 λ = 0 \lambda=0 λ=0 时目标函数退化为线性回归模型的目标函数,当 λ → + ∞ \lambda\rightarrow+\infin λ→+∞ 时,通过缩减回归系数使 β \beta β 趋向于0
另外, λ \lambda λ是 l 2 l2 l2正则项的平方数,用于平衡模型方差(回归系数的方差)和偏差。
系数求解如下:
展开岭回归模型中的平方项
J ( β ) = ( y − X β ) ′ ( y − X β ) + λ β ′ β = y ′ y − y ′ X β − β ′ X ′ y + β ′ X ′ X β + λ β ′ β J(\beta)=(y-X\beta)'(y-X\beta)+\lambda\beta'\beta=y'y-y'X\beta-\beta'X'y+\beta'X'X\beta+\lambda\beta'\beta J(β)=(y−Xβ)′(y−Xβ)+λβ′β=y′y−y′Xβ−β′X′y+β′X′Xβ+λβ′β
计算导函数
∂ J ( β ) ∂ β = 2 ( X ′ X + λ I ) β − 2 X ′ y \frac{\partial J(\beta)}{\partial \beta}=2(X'X+\lambda I)\beta-2X'y ∂β∂J(β)=2(X′X+λI)β−2X′y
参数求解
2 ( X ′ X + λ I ) β − 2 X ′ y = 0 ∴ β = ( X ′ X + λ I ) − 1 X ′ y 2(X'X+\lambda I)\beta-2X'y=0\\\therefore\beta=(X'X+\lambda I)^{-1}X'y 2(X′X+λI)β−2X′y=0∴β=(X′X+λI)−1X′y
其中需要注意的是 λ \lambda λ 值的确定,这里采用交叉验证法:
首先将数据集拆分为k个样本量大体相等的数据组,并且每个数据组与其他组都没有重叠的观测。
然后从k组数据中挑选k-1组数据用于模型的训练,剩下的一组数据用于模型的测试。
以此类推,将会得到k中训练集和测试集。在每一种训练集和测试集下,都会对应一个模型及模型得分(如均方误差)。
python提供 RidgeCV(alphas = (0.1,1.0,10), fit_intercept=True, normalize=False, scoring=None, cv=None)
函数提供交叉验证法来确定 λ \lambda λ的值
import pandas as pd
import numpy as np
from sklearn.linear_model import Ridge,RidgeCV # Ridge岭回归,RidgeCV带有广义交叉验证的岭回归
# 导入数据
data = pd.read_excel(r'diabetes.xlsx')
X_train = data[['AGE','SEX','BMI','BP','S1','S2','S3']]
y_train = data['Y']
# 运用等比数列构造200个不同的Lambda值
Lambdas = np.logspace(-5,2,200)
# 设置交叉验证的参数,对于每一个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
得到最佳的 λ \lambda λ值为0.0090110182516650178
# 基于最佳的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())
结果如下:
Intercept -61.021183
AGE 0.078594
SEX -21.941443
BMI 6.240046
BP 1.234446
S1 1.143375
S2 -1.207391
S3 -2.344764
dtype: float64
即:y = -61.021183 + 0.078594AGE - 21.941443SEX + 6.240046BMI + 1.234446BP + 1.143375S1 - 1.207391S2 - 2.344764S3
岭回归模型解决线性回归模型中矩阵X’X不可逆的办法是添加I2正则的惩罚项,但缺陷在于始终保留建模时的所有变量,无法降低模型的复杂度。对于此,Lasso回归采用了l1正则的惩罚项。
J ( β ) = ∑ ( y − X β ) 2 + λ ∣ ∣ β ∣ ∣ 1 = ∑ ( y − X β ) 2 + ∑ λ ∣ β ∣ J(\beta)=\sum(y-X\beta)^2+\lambda||\beta||_1=\sum(y-X\beta)^2+\sum\lambda|\beta| J(β)=∑(y−Xβ)2+λ∣∣β∣∣1=∑(y−Xβ)2+∑λ∣β∣
对于Lasso回归模型中 λ \lambda λ值的确定,提供函数 LassoCV(alphas=None, fit_intercept=True, normalize=False, max_iter=1000, tol=0.0001)
# 导入第三方模块
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(r'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)
# 岭回归模型的交叉验证
# 设置交叉验证的参数,对于每一个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
λ \lambda λ= 0.013509935211980266
# 导入第三方包中的函数
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
RSM= 53.12361694661972
Lasso回归:
# 导入第三方模块中的函数
from sklearn.linear_model import Lasso,LassoCV
# 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
λ \lambda λ = 0.062949889902218878
# 基于最佳的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
RMSE = 53.06143725822573
线性回归:
# 导入第三方模块
from statsmodels import api as sms
# 为自变量X添加常数列1,用于拟合截距项
X_train2 = sms.add_constant(X_train)
X_test2 = sms.add_constant(X_test)
# 构建多元线性回归模型
linear = sms.OLS(y_train, X_train2).fit()
# 返回线性回归模型的系数
linear.params
# 模型的预测
linear_predict = linear.predict(X_test2)
# 预测效果验证
RMSE = np.sqrt(mean_squared_error(y_test,linear_predict))
RMSE
RMSE = 53.426239397229892
故此数据集应采用Lasso回归拟合最好。