zoukankan      html  css  js  c++  java
  • 【353】线性回归损失函数求导举例

    参考:【351】实数对向量求导公式

    参考:【352】矩阵转置性质

    参考:机器学习实战教程(十一):线性回归基础篇之预测鲍鱼年龄

    其他方法可参考 回归算法之线性回归

    参考:通过一个例子快速上手矩阵求导


    线性回归的损失函数如下:
    $$E_b = {(X b - y)^T (X b - y)}$$

    将转置打开,像是开平方一样,运用到上面的性质:
    $$
    egin{equation*}
    egin{split}
    E_b &= (X b - y)^T (X b - y)\\
    &=((Xb)^T - y^T)(Xb-y)\\
    &=(b^T X^T - y^T)(Xb-y)\\
    &=b^T X^T Xb - b^T X^T y - y^T Xb + y^T y
    end{split}
    end{equation*}
    $$

    根据实数对向量求导的公式,对上面的实数分别对向量 $b$ 求导。

    $$
    egin{equation*}
    egin{split}
    abla_b E_b &= abla_b (b^T X^T Xb - b^T X^T y - y^T Xb + y^T y)\\
    &= abla_b (b^T X^T Xb) - abla_b (b^T X^T y) - abla_b (y^T Xb) + abla_b (y^T y)\\
    &= abla_b (b^T (X^T X)b) - abla_b (b^T (X^T y)) - abla_b ((y^T X)b) + 0\\
    &= (X^T X + (X^T X)^T)b - X^T y - (y^T X)^T\\
    &= 2 X^T X b - 2 X^T y\\
    &= 2 X^T (Xb-y)
    end{split}
    end{equation*}
    $$


    Python 实现算法

    通过 sklearn 实现

    from sklearn import linear_model
    
    x = [
        [100.0, 4.0],
        [50.0, 3.0],
        [100.0, 4.0],
        [100.0, 2.0],
        [50.0, 2.0],
        [80.0, 2.0],
        [75.0, 3.0],
        [65.0, 4.0],
        [90.0, 3.0],
        [90.0, 2.0]
    ]
    
    y = [9.3, 4.8, 8.9, 6.5, 4.2, 6.2, 7.4, 6.0, 7.6, 6.1]
    
    test_row = [50, 3]
    sk = linear_model.LinearRegression()
    sk.fit(x, y)
    print(sk.coef_)
    print(sk.intercept_)
    print(sk.predict([test_row]))
    

    [0.0611346 0.92342537]
    -0.868701466781709
    [4.95830457] 

    x1, x2 = sk.coef_
    print(x1)
    print(x2)
    

    0.06113459879206212
    0.9234253666954272 

    得到的模型为:$y = -0.87 + 0.06 cdot x_1 + 0.92 cdot x_2 $

    参考:Python:类属性,实例属性,私有属性与静态方法,类方法,实例方法

    通过矩阵计算实现

    参考:回归算法之线性回归

    得到正规方程组:

    说明:"$$" - 表示独占一行。
    参考:在Jupyter Notebook里面写Python代码和数学公式

    $$
    mb_0 + sum_{i=1}^{m} x_{i1}b_1 + ... + sum_{i=1}^{m} x_{in}b_n = sum_{i=1}^{m} y_i
    $$
    $$
    sum_{i=1}^{m} x_{i1} b_0 + sum_{i=1}^{m} x_{i1} x_{i1} b_1 + ... + sum_{i=1}^{m} x_{i1} x_{in}b_n = sum_{i=1}^{m} x_{i1} y_i
    $$
    $$...$$
    $$
    sum_{i=1}^{m} x_{in} b_0 + sum_{i=1}^{m} x_{in} x_{i1} b_1 + ... + sum_{i=1}^{m} x_{in} x_{in}b_n = sum_{i=1}^{m} x_{in} y_i
    $$

    写成矩阵表示为:
    $$
    mathbf{X}^T mathbf{X}mathbf{B}=mathbf{X}^T mathbf{Y}
    $$
    解得:
    $$
    mathbf{B}=(mathbf{X}^T mathbf{X})^{-1} mathbf{X}^T mathbf{Y}
    $$

    这一步的结果,与上面通过求偏导得到的结果一致,只需让导数为 0 即可。

    import numpy as np
    class MyLinearRegression(object):
        def __init__(self):
            # 添加属性,并且初始化,b 为列表
            self.b = []
            self.intercept_ = 0.0
            self.coef_ = []
            
        def fit(self, x:list, y:list):
            # 为每条训练数据前都添加 1,作为 b0 的系数
            point_num, future_num = np.shape(x)
            # 在原来 x 的维度基础上增加一列
            tmpx = np.ones(shape=(point_num, future_num + 1))
            # 将索引为 1 的列往后的部分赋值与 x 相同
            tmpx[:, 1:] = x
            
            # 矩阵 X
            x_mat = np.mat(tmpx)
            # 矩阵 y
            y_mat = np.mat(y).T
            # 获取矩阵 X 的转置矩阵 xT
            xT = x_mat.T
            # 直接按照公式计算
            self.b = (xT * x_mat).I * xT * y_mat
            
            # 从 b 中截取相应部分
            self.intercept_ = self.b[0]
            self.coef_ = self.b[1:]
            
        def predict(self, x):
            # [1] + x 表示将两个列表合并成一个连续的列表
            return np.mat([1] + x) * self.b
    

    调用自定义的类:

    linear = MyLinearRegression()
    linear.fit(x,y)
    print(linear.intercept_)
    print(linear.coef_)
    print(linear.predict(test_row))
    

    [[-0.86870147]]
    [[0.0611346 ]
    [0.92342537]]
    [[4.95830457]]

  • 相关阅读:
    使用cordova开发移动app时用form表单的submit时遇到的问题
    收藏链接
    Hibernate总结
    MyBatis基本应用
    Java中字符串(String)总结
    SpringMVC
    SpringIOC----注解
    栈与堆的区别
    IOS模型
    Java Web容器的启动过程
  • 原文地址:https://www.cnblogs.com/alex-bn-lee/p/10297893.html
Copyright © 2011-2022 走看看