岭回归

在线性回归模型中,其参数估计公式为$\beta=\left(X^{T} X\right)^{-1} X^{T} y$,当$X^TX$ 不可逆时无法求出$β$,另外如果$|X^TX|$ 越趋近于0,会使得回归系数趋向于无穷大,此时得到的回归系数是无意义的。解决这类问题可以使用岭回归和LASSO回归,主要针对**自变量之间存在多重共线性**或者**自变量个数多于样本量**的情况。 ## 1 **参数推导** 线性回归模型的目标函数 ::: hljs-center $J(\beta)=\sum(y-X \beta)^{2}$ ::: 为了保证回归系数$β$可求,岭回归模型在目标函数上加了一个L2范数的惩罚项 ::: hljs-center $\begin{aligned} J(\beta) &=\sum(y-X \beta)^{2}+\lambda\|\beta\|_{2}^{2} \&=\sum(y-X \beta)^{2}+\sum \lambda \beta^{2} \end{aligned}$ ::: 其中$λ$为非负数,$λ$越大,则为了使$J(\beta)$最小,回归系数$β$就越小。 **推导过程:** $\begin{aligned} J(\beta) &=(y-X \beta)^{T}(y-X \beta)+\lambda \beta^{T} \beta =y^{T} y-y^{T} X \beta-\beta^{T} X^{T} y+\beta^{T} X^{T} X \beta &+\lambda \beta^{T} \beta \end{aligned}$ 令 $\frac{\partial J(\beta)}{\partial \beta}=0$ $\Rightarrow 0-X^{T} y-X^{T} y+2 X^{T} X \beta+2 \lambda \beta=0$ $\Rightarrow \beta=\left(X^{T} X+\lambda I\right)^{-1} X^{T} y$ L2范数惩罚项的加入使得 $(X^{T} X+\lambda I)$ 满秩,保证了可逆,但是也由于惩罚项的加入,使得回归系数$β$的估计不再是无偏估计。所以岭回归是以放弃无偏性、降低精度为代价解决病态矩阵问题的回归方法。 **单位矩阵$I$的对角线上全是1,像一条山岭一样,这也是岭回归名称的由来。** ## 2 λ的选择 - 模型的方差:回归系数的方差 - 模型的偏差:预测值和真实值的差异 随着模型复杂度的提升,在训练集上的效果就越好,即模型的偏差就越小;但是同时模型的方差就越大。对于岭回归的$λ$而言,随着$λ$的增大,$|X^{T} X+\lambda I|$就越大,${(X^{T} X+\lambda I)}^{-1}$就越小,模型的方差就越小;而$λ$越大使得$β$的估计值更加偏离真实值,模型的偏差就越大。所以岭回归的关键是找到一个合理的λλ值来平衡模型的方差和偏差。 根据凸优化,可以将岭回归模型的目标函数$J(β)$最小化问题等价于 ::: hljs-center ![批注 20200823 220649.png](https://cos.easydoc.net/17082933/files/ke760zjk.png) ::: 其中$t$为一个常数。以最简单的二维为例,即$β(β_1,β_2)$其几何图形是 ::: hljs-center ![image.png](https://cos.easydoc.net/17082933/files/ke7622gc.png) ::: ::: hljs-center ![image.png](https://cos.easydoc.net/17082933/files/ke7629on.png) ::: 抛物面代表的是$\sum(y-X \beta)^{2}$的部分,圆柱体代表的是$\beta_{1}^{2}+\beta_{2}^{2} \leq t$的部分。最小二乘解是抛物面的中心,岭回归解是抛物面与圆柱体的交点。岭回归的惩罚项$\sum \lambda \beta^{2}$是关于回归系数ββ的二次函数,对目标函数求偏导时会保留$β$,抛物面与圆柱体很难相交于轴上使某个变量的回归系数为0,因此岭回归不能实现变量的剔除。 1) **岭迹法确定$λ$值** 由$\beta=\left(X^{T} X\right)^{-1} X^{T} y$可知$β$是$λ$的函数,当$\lambda \in[0, \infty)$时,在平面直角坐标系中的 $β$−$λ$ 曲线称为岭迹曲线。当$β$趋于稳定的点就是所要寻找的$λ$值。 ```python import pandas as pd import numpy as np from sklearn import model_selection from sklearn.linear_model import Ridge import matplotlib.pyplot as plt data=pd.read_excel(r'C:\Users\Administrator\Desktop\diabetes.xlsx') #拆分为训练集和测试集 predictors=data.columns[:-1] x_train,x_test,y_train,y_test=model_selection.train_test_split(data[predictors],data.Y, test_size=0.2,random_state=1234) #构造不同的lambda值 Lambdas=np.logspace(-5,2,200) #存放偏回归系数 ridge_cofficients=[] for Lambda in Lambdas: ridge=Ridge(alpha=Lambda,normalize=True) ridge.fit(x_train,y_train) ridge_cofficients.append(ridge.coef_) #绘制岭迹曲线 plt.rcParams['font.sans-serif']=['Microsoft YaHei'] plt.rcParams['axes.unicode_minus']=False plt.style.use('ggplot') plt.plot(Lambdas,ridge_cofficients) #x轴做对数处理 plt.xscale('log') plt.xlabel('Log(Lambda)') plt.ylabel('Cofficients') plt.show() ``` ::: hljs-center ![image.png](https://cos.easydoc.net/17082933/files/ke7679bc.png) ::: 书上说在0.01附近大多数回归系数就趋于稳定,这哪看得出?所以定性的方法一般不太靠谱,还是用定量的方法吧! 2) **交叉验证法确定$λ$值** 交叉验证法的思想是,将数据集拆分为k个数据组(每组样本量大体相当),从k组中挑选k-1组用于模型的训练,剩下的1组用于模型的测试,则会有k-1个训练集和测试集配对,每一种训练集和测试集下都会有对应的一个模型及模型评分(如均方误差),进而可以得到一个平均评分。对于$λ$值则选择平均评分最优的$λ$值。 >RidgeCV(alphas=(0.1, 1.0, 10.0), fit_intercept=True, normalize=False, scoring=None, cv=None, gcv_mode=None, store_cv_values=False) • lambdas:用于指定多个λλ值的元组或数组对象,默认包含0.1,1,10三种值。 • fit_intercept:bool类型,是否需要拟合截距项,默认为True。 • normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。 • scoring:指定用于模型评估的度量方法。 • cv:指定交叉验证的重数。 • gcv_mode:指定广义交叉验证的方法。 • store_cv_values:bool类型,是否保存每个λλ下交叉验证的评估信息,默认为False,只有cv为None时有效。 ```python import pandas as pd import numpy as np from sklearn import model_selection from sklearn.linear_model import RidgeCV data=pd.read_excel(r'C:\Users\Administrator\Desktop\diabetes.xlsx') #拆分为训练集和测试集 predictors=data.columns[:-1] x_train,x_test,y_train,y_test=model_selection.train_test_split(data[predictors],data.Y, test_size=0.2,random_state=1234) #构造不同的lambda值 Lambdas=np.logspace(-5,2,200) #设置交叉验证的参数,使用均方误差评估 ridge_cv=RidgeCV(alphas=Lambdas,normalize=True,scoring='neg_mean_squared_error',cv=10) ridge_cv.fit(x_train,y_train) print(ridge_cv.alpha_) ``` ![image.png](https://cos.easydoc.net/17082933/files/ke768vet.png) 得到的结果是0.135 ## 3 代码实现 >Ridge(alpha=1.0, fit_intercept=True, normalize=False, copy_X=True, max_iter=None, tol=0.001, solver=‘auto’, random_state=None) • alpha:用于指定λλ值参数,默认为1。 • fit_intercept:bool类型,是否需要拟合截距项,默认为True。 • normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。 • copy_X:bool类型,是否复制自变量X的数值,默认为True。 • max_iter:指定模型的最大迭代次数。 • solver:指定模型求解最优化问题的算法,默认为’auto’。 • random_state:指定随机生成器的种子。 ```python import pandas as pd import numpy as np from sklearn import model_selection from sklearn.linear_model import Ridge,RidgeCV from sklearn.metrics import mean_squared_error data=pd.read_excel(r'C:\Users\Administrator\Desktop\diabetes.xlsx') data=data.drop(['AGE','SEX'],axis=1) #拆分为训练集和测试集 predictors=data.columns[:-1] x_train,x_test,y_train,y_test=model_selection.train_test_split(data[predictors],data.Y, test_size=0.2,random_state=1234) #构造不同的lambda值 Lambdas=np.logspace(-5,2,200) #设置交叉验证的参数,使用均方误差评估 ridge_cv=RidgeCV(alphas=Lambdas,normalize=True,scoring='neg_mean_squared_error',cv=10) ridge_cv.fit(x_train,y_train) #基于最佳lambda值建模 ridge=Ridge(alpha=ridge_cv.alpha_,normalize=True) ridge.fit(x_train,y_train) #打印回归系数 print(pd.Series(index=['Intercept']+x_train.columns.tolist(), data=[ridge.intercept_]+ridge.coef_.tolist())) #模型评估 ridge_pred=ridge.predict(x_test) #均方误差 MSE=mean_squared_error(y_test,ridge_pred) print(MSE) ``` ![image.png](https://cos.easydoc.net/17082933/files/ke769yu8.png) --- 转载:[机器学习十大经典算法之岭回归和LASSO回归(学习笔记整理)](https://blog.csdn.net/weixin_43374551/article/details/83688913)