Python手撸机器学习系列(五):线性回归与岭回归(最小二乘法求解)

线性回归

一、原理

线性回归应该是最简单的机器学习算法了,我们以最小二乘法为基础来进行求解

1.1 数据输入

设数据表现形式为:

D a t a = ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) Data = {(x_1,y_1),(x_2,y_2),...,(x_N,y_N)} Data=(x1,y1),(x2,y2),...,(xN,yN)

其中 x i ∈ R p ,   y i ∈ R ,   i = 1 , 2 , . . . , N x_i∈R^p,\ y_i∈R,\ i=1,2,...,N xiRp, yiR, i=1,2,...,N

就是说有N条数据,每条数据分为特征 x i x_i xi和对应的标签值 y i y_i yi,其中 x i x_i xi p ∗ 1 p*1 p1维,也就是说有 p p p个特征, x i x_i xi表现为列向量

X X X表示特征矩阵为
X = ( x 1 , x 2 , . . , x N ) = [ x 1 T x 2 T ⋮ x N T ] = [ x 11 x 12 ⋯ x 1 p x 21 x 22 ⋯ x 2 p ⋮ ⋮ ⋱ ⋯ x N 1 x N 2 ⋯ x N p ] N × p T X = (x_1,x_2,..,x_N) = \left[\begin{matrix} x_1^T\\ x_2^T\\ \vdots\\ x_N^T\end{matrix}\right]=\left[\begin{matrix} x_{11}&x_{12}&\cdots&x_{1p} \\ x_{21}&x_{22}&\cdots&x_{2p}\\\vdots&\vdots&\ddots&\cdots\\ x_{N1}&x_{N2}&\cdots&x_{Np}\end{matrix}\right]_{N×p}^T X=(x1,x2,..,xN)=x1Tx2TxNT=x11x21xN1x12x22xN2x1px2pxNpN×pT

Y Y Y表示标签矩阵为:
Y = [ y 1 y 2 ⋮ y N ] N × 1 Y =\left[\begin{matrix} y_1\\ y_2 \\ \vdots \\y_N \end{matrix}\right]_{N×1} Y=y1y2yNN×1
线性回归的目的在于拟合一个函数来根据特征值预测标签值,当数据为平面坐标点时( 横坐标为x纵坐标为y),拟合的函数表现为一条坐标平面直线。

我们需要拟合函数的权重 W W W,其维度为 p × 1 p×1 p×1,当数据为平面坐标点时为一个数( 1 × 1 1×1 1×1的矩阵)
W = [ W 1 W 2 ⋮ W N ] p × 1 W =\left[\begin{matrix} W_1\\ W_2 \\ \vdots \\W_N \end{matrix}\right]_{p×1} W=W1W2WNp×1

1.2 最小二乘法一般解法

显然,用最小二乘法求解,其损失函数为 M S E MSE MSE :
L ( W ) = ∑ i = 1 N ∣ ∣ W T x i − y i ∣ ∣ 2 = ∑ i = 1 N ( W T x i − y i ) 2 = [ W T x 1 − y 1 , W T x 2 − y 2 , . . . , W T x N − y N ] [ W T x 1 − y 1 W T x 2 − y 2 ⋮ W T x N − y B ] = ( W T X T − Y T ) ( X W − Y ) = W T X T X W − W T X T Y − Y T X W + Y T Y = W T X T X W − 2 W T X T Y + Y T Y \begin{aligned} L(W) &= \displaystyle\sum_{i=1}^N||W^Tx_i-y_i||^2 \\&=\displaystyle\sum_{i=1}^N(W^Tx_i-y_i)^2 \\&=\left[W^Tx_1-y_1,W^Tx_2-y_2,...,W^Tx_N-y_N\right]\left[\begin{matrix} W^Tx_1-y_1\\ W^Tx_2-y_2\\ \vdots\\ W^Tx_N-y_B\end{matrix}\right]\\&=(W^TX^T-Y^T)(XW-Y)\\&=W^TX^TXW-W^TX^TY-Y^TXW+Y^TY\\&=W^TX^TXW-2W^TX^TY+Y^TY\\ \end{aligned}\\ L(W)=i=1NWTxiyi2=i=1N(WTxiyi)2=[WTx1y1,WTx2y2,...,WTxNyN]WTx1y1WTx2y2WTxNyB=(WTXTYT)(XWY)=WTXTXWWTXTYYTXW+YTY=WTXTXW2WTXTY+YTY
使用损失函数对 W W W求导:
∂ L ( W ) ∂ W = 2 X T X W − 2 X T Y = 0 \large \frac{\partial L(W)}{\partial W} = 2X^TXW-2X^TY=0 WL(W)=2XTXW2XTY=0
可得
X T X W = X T Y W = ( X T X ) − 1 X T Y \begin{aligned} X^TXW &=X^TY \\ W&=(X^TX)^{-1}X^TY\\ \end{aligned} XTXWW=XTY=(XTX)1XTY
即求得参数 W W W,其中 ( X T X ) − 1 X T (X^TX)^{-1}X^T (XTX)1XT被称为 X X X的伪逆矩阵

1.3 最小二乘法的几何理解

我们将 X X X理解为一种特征空间,比如说,现在由 x 1 、 x 2 x_1、x_2 x1x2两个特征组成了一个平面,而使用 Y Y Y向该平面投影:

请添加图片描述

投影可以理解为在向量 x 1 、 x 2 x_1、x_2 x1x2的线性组合,则可以找到一组 w w w用来表示这段线性组合的权重,即 [ x 1 , x 2 ] [ w 1 , w 2 ] T [x_1,x_2][w_1,w_2]^T [x1,x2][w1,w2]T

扩展到全部的 X X X Y Y Y,投影就是 X W XW XW,而根据向量的减法,垂直于平面的那一段可以描述为 Y − X W Y-XW YXW

垂直的向量内积为0,即:
X T ( Y − X W ) = 0 X T Y = X T X W W = ( X T X ) − 1 X T Y \begin{aligned} X^T(Y-XW) &= 0\\ X^TY&=X^TXW\\ W &= (X^TX)^{-1}X^TY \end{aligned} XT(YXW)XTYW=0=XTXW=(XTX)1XTY
与之前使用求导算得的 W W W一致

二、正则化与岭回归

对于上述问题,求得的线性回归损失函数及其 W W W为:
L ( W ) = ∑ i = 1 N ∣ ∣ W T x i − y i ∣ ∣ 2 W = ( X T X ) − 1 X T Y \begin{aligned} L(W) &= \displaystyle\sum_{i=1}^N||W^Tx_i-y_i||^2\\W&=(X^TX)^{-1}X^TY \end{aligned} L(W)W=i=1NWTxiyi2=(XTX)1XTY
而在实际应用中, ( X T X ) (X^TX) (XTX)可能是不可逆的,比如特征大于样本时,而且样本过少特征过多还容易造成过拟合,由此提出了正则化的解决方案。

正则化的框架为:
L ( W ) + λ P ( W ) L(W)+\lambda P(W) L(W)+λP(W)
其中 λ P ( w ) \lambda P(w) λP(w)被称为惩罚项

一般正则化可以分为L1正则化和L2正则化:

  • L1正则化:也被称作Lasso,此时 P ( W ) = ∣ ∣ W ∣ ∣ 1 P(W) = ||W||_1 P(W)=W1,即 W W W的一范式
  • L2正则化:也被称作Ridge和岭回归,此时 P ( W ) = ∣ ∣ W ∣ ∣ 2 2 = W T W P(W)=||W||_2^2=W^TW P(W)=W22=WTW

在这里我们主要介绍L2正则化,也就是岭回归

在岭回归的情况下,损失函数就变为:
J ( W ) = ∑ i = 1 N ∣ ∣ W T x i − y i ∣ ∣ 2 + λ W T W = ( W T X T − Y T ) ( X W − Y ) + λ W T W = W T X T X W − 2 W T X T Y + Y T Y + λ W T W = W T ( X T X + λ I ) W − 2 W T X T Y + Y T Y \begin{aligned} J(W)&=\displaystyle\sum_{i=1}^N||W^Tx_i-y_i||^2+\lambda W^TW \\ &=(W^TX^T-Y^T)(XW-Y)+\lambda W^TW\\ &=W^TX^TXW-2W^TX^TY+Y^TY+\lambda W^TW\\ &=W^T(X^TX+\lambda I)W-2W^TX^TY+Y^TY \end{aligned} J(W)=i=1NWTxiyi2+λWTW=(WTXTYT)(XWY)+λWTW=WTXTXW2WTXTY+YTY+λWTW=WT(XTX+λI)W2WTXTY+YTY
W W W进行求导:
∂ J ( W ) ∂ W = 2 ( X T X + λ I ) W − 2 X T Y = 0 \frac{\partial J(W)}{\partial W} = 2(X^TX+\lambda I)W - 2X^TY = 0 WJ(W)=2(XTX+λI)W2XTY=0
求得
W = ( X T X + λ I ) − 1 X T Y W = (X^TX+\lambda I)^{-1}X^TY W=(XTX+λI)1XTY
此时 ( X T X + λ I ) (X^TX+\lambda I) (XTX+λI)一定可逆,理由如下:

假设 X T X X^TX XTX不可逆,即不满秩,其可以变换为某一行或某一列为全0的矩阵:
X T X = [ a 11 a 12 a 13 ⋯ a 1 n 0 a 22 a 23 ⋯ a 2 n 0 0 a 33 ⋯ a 3 n ⋮ ⋮ ⋮ ⋱ ⋮ 0 0 0 ⋯ 0 ] X^TX = \left[\begin{matrix} a_{11}&a_{12} &a_{13} &\cdots & a_{1n} \\0&a_{22} &a_{23} &\cdots & a_{2n} \\0&0 &a_{33} &\cdots & a_{3n} \\ \vdots&\vdots &\vdots &\ddots & \vdots \\0&0 &0 &\cdots & 0 \end{matrix} \right] XTX=a11000a12a2200a13a23a330a1na2na3n0

X T X + λ I = [ a 11 + λ a 12 a 13 ⋯ a 1 n 0 a 22 + λ a 23 ⋯ a 2 n 0 0 a 33 + λ ⋯ a 3 n ⋮ ⋮ ⋮ ⋱ ⋮ 0 0 0 ⋯ λ ] X^TX+\lambda I = \left[\begin{matrix} a_{11}+\lambda&a_{12} &a_{13} &\cdots & a_{1n} \\0&a_{22}+\lambda &a_{23} &\cdots & a_{2n} \\0&0 &a_{33}+\lambda &\cdots & a_{3n} \\ \vdots&\vdots &\vdots &\ddots & \vdots \\0&0 &0 &\cdots & \lambda \end{matrix} \right] XTX+λI=a11+λ000a12a22+λ00a13a23a33+λ0a1na2na3nλ

此时不存在全为0的行或列,矩阵满秩可逆,当然,还是有特殊清况,比如:

  • λ = 0 \lambda=0 λ=0
  • 原本矩阵中存在对象线上元素为 − λ -\lambda λ,其他元素都为0的行或列

当然,这些情况可以通过调节 λ \lambda λ来解决

三、代码实现

梯度下降法,使用之前公式中损失函数 L L L W W W的求导作为梯度,每次乘上学习率进行衰减,即:

d W = 2 X T X W − 2 X T Y d_W = 2X^TXW-2X^TY dW=2XTXW2XTY

W = W − l r ∗ d W W = W-lr*d_W W=WlrdW

公式法则是直接用最后的公式计算 X X X的伪逆矩阵乘上 Y Y Y

岭回归只需要在原始基础上加上惩罚项

其实两种方法实现起来几乎是一模一样的:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.linear_model import  LinearRegression

def get_points():
    #获取坐标点
    point = [[3,3],[4,3],[2,5],[6,7],[8,10]]
    X = np.array([x[0] for x in point])
    Y = np.array([x[1] for x in point])
    X = X.reshape(X.shape[0],1)
    Y = Y.reshape(Y.shape[0],1)

    #另一组点,此时x为二维,画图函数无效,记得注释掉
    # X = np.array([[1, 2], [3, 4], [3, 6]])
    # Y = np.array([3, 6, 9])
    # X = X.reshape(X.shape[0],2)
    # Y = Y.reshape(Y.shape[0],1)
    # return X,Y.reshape(Y.shape[0],1)
    return X,Y

def get_house():
    #波士顿房价数据集
    data,target = load_boston(return_X_y=True)
    return data,target.reshape(target.shape[0],1)

def cal_w(X,Y):
    #公式直接计算W
    w = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(Y)
    return w

def Ridge_w(X,Y):
    #岭回归,可以通过调节lambda,此处为a来改变直线
    a = 5
    w = np.linalg.inv(X.T.dot(X)+a*np.eye(X.shape[1])).dot(X.T).dot(Y)
    return w

def gradient(X,Y):
    #梯度下降法
    lr = 0.01
    epochs = 2
    w = np.zeros((X.shape[1],1))
    for epoch in range(epochs):
        dw = X.T.dot(X).dot(w)-X.T.dot(Y)
        w -= lr*dw
    return w

if __name__ == '__main__':
    X,Y = get_points()
    w1 = gradient(X,Y)
    w2 = cal_w(X,Y)
    w3 = Ridge_w(X,Y)
    plt.scatter(X, Y, c='b',label = 'points')
    plt.plot(np.arange(1, 9), w1[0][0] * np.arange(1, 9), c='r',label = 'line_gradient')
    plt.plot(np.arange(1, 9), w2[0][0] * np.arange(1, 9), c='g',label = 'line_cal_w')
    plt.plot(np.arange(1, 9), w3[0][0] * np.arange(1, 9), c='y',label = 'Ridge_cal_w')
    plt.legend()
    plt.show()

结果如下图所示:

注意,调节梯度下降的epochs,lr 以及岭回归的惩罚系数可以使三条直线完全吻合,但为了方便展示这里做了区分。

在实验中发现梯度下降法当学习率过大或者过小时会发生梯度消失或是梯度爆炸,原因可能是数据量太小。
在这里插入图片描述
同时,线性回归也可以尝试其他更复杂的点以及波士顿房价预测数据集,代码中已给出数据集,请自行尝试。

四、结语

参考内容:

如有问题欢迎评论区指出,有问题也可以联系我:
1759412770@qq.com

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锌a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值