岭回归

上一节我们说到了 标准方程法,最后说到如果数据的特征比样本点还要多的时候,此时(XTX)不是满秩矩阵,就没有办法求出逆矩阵。所以我们这里引入了岭回归的概念。

标准方程法最后推出来的公式为:

岭回归n拟合效果差 岭回归的参数_回归


岭回归的公式为:

岭回归n拟合效果差 岭回归的参数_岭回归_02


岭回归n拟合效果差 岭回归的参数_算法_03


这里就通过一点扰动使其变成满秩矩阵。

那么这个公式的由来的表示就是原代价函数经过正则化变成L2正则化的代价函数:

岭回归n拟合效果差 岭回归的参数_岭回归_04


岭回归n拟合效果差 岭回归的参数_机器学习_05


数学符号λ为岭系数。没有加入正则项是一个无偏估计,加上正则项变成有偏估计,所以岭回归是一种有偏估计。

岭回归n拟合效果差 岭回归的参数_岭回归n拟合效果差_06


这里就要涉及到λ的取值,选择一个好的取值最好可以达到使得上图中后面的函数趋于稳定,以及残差平方和不会差别特别的,因为对于代价函数来说值越小越好就是预测值和真实值越吻合越好,对于岭回归代价函数后面的λ也是控制后面一项的大小。

岭回归n拟合效果差 岭回归的参数_回归_07


下面代码部分我们使用两种方式,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正则变化演化出来的。

岭回归n拟合效果差 岭回归的参数_算法_08

岭回归n拟合效果差 岭回归的参数_岭回归n拟合效果差_09

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. ]