这两种回归主要针对特征之间存在多重共线性或者特征数多于样本量的情况。话句话说就是特征向量组成的矩阵不是一个满秩矩阵(特征数大于对应矩阵的秩)
岭回归的代价函数是经过L2正则化(正则化可以降低模型复杂度)后的代价函数,如下,并对其求导令导数为0,得到参数
θ
θ
θ(也即
w
w
w)如下:
单位矩阵 I I I的对角线上全是1,像一条山岭一样,这也是岭回归名称的由来。
随着模型复杂度的提升,在训练集上的效果就越好,即模型的偏差就越小;但是同时模型的方差就越大(即曲线越“曲折”)。
对于岭回归的 λ \lambda λ而言,随着 λ \lambda λ的增大, ∣ ( X T X + λ I ) ∣ {|( X^TX+\lambda I)|} ∣(XTX+λI)∣ 就越大, ( X T X + λ I ) − 1 {( X^TX+\lambda I)^{-1}} (XTX+λI)−1 就越小,进而算出来的系数矩阵 θ \theta θ(即 w w w)的值就相对较小,模型的方差就越小(测试数据不变的情况下,系数小方差就会小);然而, λ \lambda λ越大使得 θ \theta θ(即 w w w)的估计值更加偏离真实值,模型的偏差就越大(该值越大惩罚越大,进而模型越简单)。所以岭回归的关键是找到一个合理的 λ \lambda λ值来平衡模型的方差和偏差。
选择𝜆值,使得:
1.各回归系数的岭估计基本稳定。
2.残差平方和增大不太多。
longley.csv数据:
import numpy as np
from numpy import genfromtxt
import matplotlib.pyplot as plt
data = genfromtxt(r"longley.csv",delimiter=',')
# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1,np.newaxis]
# 给样本添加偏置项
X_data = np.concatenate((np.ones((16,1)),x_data),axis=1)
# 岭回归标准方程法求解回归参数,给定默认
def weights(xArr, yArr, lam=0.2):
xMat = np.mat(xArr)
yMat = np.mat(yArr)
xTx = xMat.T*xMat # 矩阵乘法
rxTx = xTx + np.eye(xMat.shape[1])*lam
# 计算矩阵的值,如果值为0,说明该矩阵没有逆矩阵
if np.linalg.det(rxTx) == 0.0:
print("This matrix cannot do inverse")
return
# xTx.I为xTx的逆矩阵
ws = rxTx.I*xMat.T*yMat
return ws
ws = weights(X_data,y_data)
# 计算预测值
matrix1=np.mat(X_data)*np.mat(ws)
print(matrix1)
结果如下:
数据和上面用python自己实现一样。
import numpy as np
from numpy import genfromtxt
from sklearn import linear_model
import matplotlib.pyplot as plt
data = genfromtxt(r"longley.csv",delimiter=',')
# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1]
# 创建模型
# 生成50个值,从0.001-1之间等距生成50个值,该函数默认是生成50个值
alphas_to_test = np.linspace(0.001, 1)
# 创建模型,store_cv_values=True保存误差值
model = linear_model.RidgeCV(alphas=alphas_to_test, store_cv_values=True)
model.fit(x_data, y_data)
# 使用sklearn会交叉验证得到最终岭系数
print(model.alpha_) # 0.40875510204081633
# loss值
print(model.cv_values_.shape) # (16, 50),16行数据每一行都会作50次验证,因为每行要用50个岭系数验证
# 画图
# 岭系数跟loss值的关系,mean(axis=0)表示按列求平均,得到50个平均损失值
plt.plot(alphas_to_test, model.cv_values_.mean(axis=0))
# 选取的岭系数值的位置
plt.plot(model.alpha_, min(model.cv_values_.mean(axis=0)),'ro')
plt.show()
# 根据训练的模型预测结果
model.predict(x_data[2,np.newaxis]) # array([88.11216213])
岭回归无法剔除变量,而LASSO回归模型,将惩罚项由L2范数变为L1范数,可以将一些不重要的回归系数缩减为0,达到剔除变量的目的。
上图是以 n = 2 n=2 n=2为例画的二维图像,红色的圈是误差 J ( θ ) J(\theta) J(θ)等高线,蓝绿色的区域为正则化限定,之所以要限定在一个较小的范围,是因为这样可以增大 J ( θ ) J(θ) J(θ)与残差之间的相关性。
由图可以看到,LASSO回归限定区域与最低等高线的交点可能使得某些参数为0,这就更好的剔除了那些线性相关的特征。
import numpy as np
from numpy import genfromtxt
from sklearn import linear_model
data = genfromtxt(r"longley.csv",delimiter=',')
# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1]
# 创建模型,CV表示使用交叉验证
model = linear_model.LassoCV()
model.fit(x_data, y_data)
# lasso系数
print(model.alpha_) # 14.134043936116361
# 相关系数
print(model.coef_)# [0.1016487 0.00416716 0.00349843 0. 0. 0.]
# 预测倒数第二行的结果
model.predict(x_data[-2,np.newaxis]) #array([115.77558105])
弹性网的偏置是结合岭回归和lasso回归综合考虑的,用系数α来调节他们之间的权重。
import numpy as np
from numpy import genfromtxt
from sklearn import linear_model
data = genfromtxt(r"longley.csv",delimiter=',')
# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1]
# 创建模型
model = linear_model.ElasticNetCV()
model.fit(x_data, y_data)
# 弹性网系数
print(model.alpha_) # 30.31094405430269
# 相关系数
print(model.coef_) # [0.1006612 0.00589596 0.00593021 0. 0. 0. ]
model.predict(x_data[-2,np.newaxis]) # array([115.74523947])
因篇幅问题不能全部显示,请点此查看更多更全内容