岭回归
上一节我们说到了 标准方程法,最后说到如果数据的特征比样本点还要多的时候,此时(XTX)不是满秩矩阵,就没有办法求出逆矩阵。所以我们这里引入了岭回归
的概念。
标准方程法最后推出来的公式为:
岭回归的公式为:
这里就通过一点扰动使其变成满秩矩阵。
那么这个公式的由来的表示就是原代价函数经过正则化变成L2正则化的代价函数:
数学符号λ为岭系数。没有加入正则项是一个无偏估计,加上正则项变成有偏估计,所以岭回归是一种有偏估计。
这里就要涉及到λ的取值,选择一个好的取值最好可以达到使得上图中后面的函数趋于稳定,以及残差平方和不会差别特别的,因为对于代价函数来说值越小越好就是预测值和真实值越吻合越好,对于岭回归代价函数后面的λ也是控制后面一项的大小。
下面代码部分我们使用两种方式,sklearn和标准方程法构造矩阵按照公式的方法写出来:
sklearn:
首先导入包:
import numpy as np
from numpy import genfromtxt
from sklearn import linear_model
import matplotlib.pyplot as plt
linear_model是岭回归的包
导入数据并处理:
# 读入数据
data = genfromtxt(r"longley.csv",delimiter=',')
# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1]
构建岭回归模型:
# 创建模型
# 生成50个值
alphas_to_test = np.linspace(0.001, 1) # 莫名生成50个值
# 创建模型,保存误差值
model = linear_model.RidgeCV(alphas=alphas_to_test, store_cv_values=True)
model.fit(x_data, y_data)
# 岭回归选区最好的岭系数
print(model.alpha_)
# loss值
print(model.cv_values_.shape) # (16, 50)表示每一行都会做一次数据集都会做一次测试集都会产生一个loss的值,50指的是岭系数一共验证了50个
RidgeCV是交叉验证 alphas指的是岭回归系数 store_cv_values存储交叉验证的结果
最后画图:
# 画图
# 岭系数跟loss值的关系
plt.plot(alphas_to_test, model.cv_values_.mean(axis=0)) # mean求的是loss值的平均值,axis=0是对横坐标求
# 选取的最好的岭系数值的位置
plt.plot(model.alpha_, min(model.cv_values_.mean(axis=0)),'ro')
plt.show()
标准方程法
导入包:
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 # np.eye()构造单位矩阵 .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)
预测也可以发现和我们源数据没有相差多少:
# 计算预测值
np.mat(X_data)*np.mat(ws)
[[ 83. ]
[ 88.5]
[ 88.2]
[ 89.5]
[ 96.2]
[ 98.1]
[ 99. ]
[100. ]
[101.2]
[104.6]
[108.4]
[110.8]
[112.6]
[114.2]
[115.7]
[116.9]]([[ 83.55075226],
[ 86.92588689],
[ 88.09720227],
[ 90.95677622],
[ 96.06951002],
[ 97.81955375],
[ 98.36444357],
[ 99.99814266],
[103.26832266],
[105.03165135],
[107.45224671],
[109.52190685],
[112.91863666],
[113.98357055],
[115.29845063],
[117.64279933]])
LASSO
前面讲的岭回归是同归代价函数L2正则化变化出来的,而这里的LASSO回归则是通过代价函数的L1正则变化演化出来的。
lasso与岭回归对比来说,在改变λ的值时,最后所有的参数会趋近于0,但是对于0回归来说,在逐渐改变λ的时候,有一些参数值就会变为0,这样就剔除多重共线性。
这是使用代码直接用slearn实现:
导入包:
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.LassoCV()
model.fit(x_data, y_data)
# lasso系数
print(model.alpha_)
# 相关系数
print(model.coef_) # 就会有一些特征值变为0,这就是和岭回归最大的区别
20.03464209711722
[0.10206856 0.00409161 0.00354815 0. 0. 0. ]