最小二乘法公式推导以及在线性回归中的应用

2023-05-16

    机器学习算法中,有一个基础的算法,线性回归,它的目的是求出一条直线,满足所有点到这条直线的距离最短,也就是这些数据点能够看起来都在这条直线附近,最后,可以根据这条直线来预测其他数据的值。

    线性回归,最推荐的做法其实是使用梯度下降算法,这种算法比较通用,对数据要求不高,可以离散不连续。如下所示,是一个使用梯度下降算法来进行线性回归的示例:

    准备数据:

    这两列数据最后是放在lineardata.csv中的,分别对应x,y集合。

1	3
1.2	3
1.2	4
1.5	4.5
1.6	4.3
6.5	12
3.6	7.1
2.5	9
5.7	14
6	11
9	17
8.9	17
7.1	15
7	14
2.5	4
0.8	2
0.5	2
3.4	7
3.6	9
5.6	12
6.7	15
6.9	15
7.1	14
7.5	17
7.8	16
8.1	15
8.3	15
8.5	15
8.7	16
8.7	17
8.8	18
8.8	20
8	16
9	19
9.2	18
10.1	20
1.1	3.2
1.6	4.2
4	9
12	25
9.5	20

    程序代码:

import numpy as np
import matplotlib.pyplot as plt


def loss_error(w, b, data):
    x = data[:, 0]
    y = data[:, 1]
    loss = np.sum((y - w * x - b) ** 2) / data.shape[0]
    return loss


def linear_gradient(w, b, data, lr):
    N = float(len(data))
    x = data[:, 0]
    y = data[:, 1]
    dw = np.sum(-(2 / N) * x * (y - w * x - b))
    db = np.sum(-(2 / N) * (y - w * x - b))

    w = w - (lr * dw)
    b = b - (lr * db)
    return w, b


def optimizer(data, w, b, lr, epoch):
    for i in range(epoch):
        w, b = linear_gradient(w, b, data, lr)
        if i % 100 == 0:
            print('epoch {0}:loss={1}'.format(i, loss_error(w, b, data)))
    return w, b


def plot_data(data, w, b):
    x = data[:, 0]
    y = data[:, 1]
    y_predict = w * x + b
    plt.plot(x, y, 'o')
    plt.plot(x, y_predict, 'k-')
    plt.show()


def linear_regression():
    data = np.loadtxt('lineardata.csv', delimiter=',')
    # data = pd.read_csv('lineardata.csv',encoding='utf8')
    x = data[:, 0]
    y = data[:, 1]
    plt.plot(x, y, 'o')
    #plt.show()

    lr = 0.01
    epoch = 1000
    w = 0.0
    b = 0.0
    print("initial variables:\n initial_b={0}\n initial_w={1}\n loss={2}\n".format(b, w, loss_error(w, b, data)))

    w, b = optimizer(data, w, b, lr, epoch)
    print('final formula parameters:\n b = {0}\n w={1} \n loss={2}\n'.format(b, w, loss_error(w, b, data)))
    plot_data(data, w, b)


if __name__ == '__main__':
    linear_regression()

    运行,打印结果:

initial variables:
 initial_b=0.0
 initial_w=0.0
 loss=184.68365853658537

epoch 0:loss=3.265436338536489
epoch 100:loss=1.4187213286545117
epoch 200:loss=1.3652986742281288
epoch 300:loss=1.3437697330412992
epoch 400:loss=1.3350937263246236
epoch 500:loss=1.3315973587190568
epoch 600:loss=1.330188348003359
epoch 700:loss=1.329620526932774
epoch 800:loss=1.3293916991711343
epoch 900:loss=1.3292994832474747
final formula parameters:
 b = 1.2393038013472177
 w=1.8672419688724071 
 loss=1.3292625499252577

    同时,画出的图形:

 

    我们这里重点关注最后计算出来的系数w,b,他们分别是 w=1.8672419688724071, b = 1.2393038013472177,后面通过最小二乘法计算来做对别。

============================================

    下面开始这篇文章的主题,最小二乘法。

     在最小二乘法之前,人们知道,让一些离散的数据点靠近一条直线,可以通过求距离的办法,但是距离是作减法,结果有正,有负,最后其实是计算绝对值的和最小。

     最小二乘法最早是由法国科学家勒让德发明的,但是当时没有人知道,直到高斯提供了最小二乘法优化方法强于其他方法的证明才被世人知道。 

     最小二乘法是计算差值的平方和最小。

     假定拟合直线为 y = wx + b ,最小二乘法就是要求公式:

Q = \sum_{i=1}^{n} (y_{i}-wx_{i}-b)^{2}  最小值。

    一般使用求导法。分别对w,b求导:

\frac{\partial Q}{\partial w} = 2\sum_{i=1}^{n}(y_{i}-wx_{i}-b)(-x_{i})=0                                                (1)

\frac{\partial Q}{\partial b} = 2\sum_{i=1}^{n}(y_{i}-wx_{i}-b)(-1)=0                                                 (2)

    这里分别要求出w,b的值。上面的公式中(2)中,可以把求和公式展开,得到:

\sum_{i=1}^{n}y_{i} - w\sum_{i=1}^{n}x_{i} = nb

  进而求出b,     b = \frac{\sum_{i=1}^{n}y_{i} - w\sum_{i=1}^{n}x_{i}}{n}         (3) ,将b带入(1)式,求出w。

\sum_{i=1}^{n}y_{i}x_{i} = w\sum_{i=1}^{n}x_{i}^{2}+ \sum_{i=1}^{n}x_{i}b \\ ----------------------- \\ \sum_{i=1}^{n}y_{i}x_{i} = w\sum_{i=1}^{n}x_{i}^{2}+ \sum_{i=1}^{n}x_{i}\frac{\sum_{i=0}^{n}y_{i}-w\sum_{i=0}^{n}x_{i}}{n}\\ ----------------------- \\ n\sum_{i=0}^{n}y_{i}x_{i}-\sum_{i=1}^{n}x_{i}\sum_{i=1}^{n}y_{i}=w(n\sum x_{i}^2-(\sum x_{i})^2)\\ -----------------------\\ w = \frac{n\sum y_{i}x_{i}-\sum x_{i}\sum y_{i}}{n\sum x_{i}^2-(\sum x_{i})^2}

求出了w,那么再计算b就容易了。一般直接使用上面推导的公式(3)表示。

 下面,我们通过java语言编写算法来实现最小二乘法:

package mr;
public class LeastSquareMethod {

    private static double w;
    private static double b;
    private static int n;

    public static void fit(double[] x,double[] y){
        n = x.length<y.length?x.length:y.length;
        double xy = 0,xT = 0,yT = 0,xS = 0;
        for(int i=0;i<n;i++){
            xy+=x[i]*y[i];
            xT += x[i];
            yT += y[i];
            xS += Math.pow(x[i],2);
        }
        w = (n*xy-xT*yT)/(n*xS-Math.pow(xT,2));
        b = yT/n - w*xT/n;
    }

    public static double predict(double x){
        System.out.println("w="+w);
        System.out.println("b="+b);
        return w*x + b;
    }

    public static void main(String[] args) {
        double[] x = {1,1.2,1.2,1.5,1.6,6.5,3.6,2.5,5.7,6,9,8.9,7.1,7,2.5,0.8,0.5,3.4,3.6,5.6,6.7,6.9,7.1,7.5,7.8,8.1,8.3,8.5,8.7,8.7,8.8,8.8,8,9,9.2,10.1,1.1,1.6,4,12,9.5};
        double[] y = {3,3,4,4.5,4.3,12,7.1,9,14,11,17,17,15,14,4,2,2,7,9,12,15,15,14,17,16,15,15,15,16,17,18,20,16,19,18,20,3.2,4.2,9,25,20};
        fit(x,y);
        System.out.println(predict(15));
    }
}

    程序运行结果:

w=1.8658557134722435
b=1.2497797817573275
29.237615483840983

    这个结果跟上面梯度下降计算的直线系数,w=1.8672419688724071, b = 1.2393038013472177,很接近,但是有一些差别。

    最小二乘法公式里面,还有一个隐含的公式就是:

\bar{y} = \frac{\sum y_{i}}{n}  和 \bar{x} = \frac{\sum x_{i}}{n},这两个很好理解,就是y的平均数= \frac{y_{1}+y_{2}+...+y_{n}}{n},x的平均数 = \frac{x_{1}+x_{2}+...+x_{n}}{n}

     所以把这两个公式代入上面w的表达式,可以计算出另一个w,b的表达式:

w=\frac{\sum x_{i}y_{i}-n\bar{x}\bar{y}}{\sum x_{i}^2-n\bar{x}^2} = \frac{\sum (x_{i}-\bar{x})(y_{i}-\bar{y})}{\sum (x_{i}-\bar{x})^2}    (4)

b = \bar{y} - w\bar{x}

    公式(4)中的分子推导如下:

\sum (x_{i}-\bar{x})(y_{i}-\bar{y})\\ = \sum (x_{i}y_{i} - \bar{x}y_{i}-x_{i}\bar{y}+\bar{x}\bar{y})\\ =\sum x_{i}y_{i} - n\bar{x}\bar{y} - n\bar{x}\bar{y}+n\bar{x}\bar{y}\\ = \sum x_{i}y_{i} - n\bar{x}\bar{y}

    分母的推导如下:

\sum (x_{i}-\bar{x})^2\\ =\sum (x_{i}^2 - 2x_{i}\bar{x}+\bar{x}^2)\\ =\sum x_{i}^2 - 2n\bar{x}^2 + n\bar{x}^2\\ =\sum x_{i}^2 - n\bar{x}^2

     根据公式(4),我们有另一种计算最小二乘法直线系数的算法:

package mr;

import org.apache.commons.math3.stat.descriptive.moment.Mean;

public class LeastSquareMethod2 {
    private double[] x;
    private double[] y;
    public LeastSquareMethod2(double[] x, double[] y){
        this.x = x;
        this.y = y;
    }

    public double[] getRegressionModel(){
        if(x.length!=y.length)
            return null;
        Mean meanUtil = new Mean();
        double xmean = meanUtil.evaluate(x);
        double ymean = meanUtil.evaluate(y);
        double numerator = 0d;
        double denominator = 0d;
        for(int i=0;i<x.length;i++){
            double xi = x[i];
            double yi = y[i];
            numerator = numerator+(xi-xmean)*(yi-ymean);
            denominator = denominator+(xi-xmean)*(xi-xmean);
        }
        double w = numerator/denominator;
        double b = ymean - w*xmean;
        double[] model = {w,b};
        return model;
    }

    public static void main(String[] args) {
        double[] x = {1,1.2,1.2,1.5,1.6,6.5,3.6,2.5,5.7,6,9,8.9,7.1,7,2.5,0.8,0.5,3.4,3.6,5.6,6.7,6.9,7.1,7.5,7.8,8.1,8.3,8.5,8.7,8.7,8.8,8.8,8,9,9.2,10.1,1.1,1.6,4,12,9.5};
        double[] y = {3,3,4,4.5,4.3,12,7.1,9,14,11,17,17,15,14,4,2,2,7,9,12,15,15,14,17,16,15,15,15,16,17,18,20,16,19,18,20,3.2,4.2,9,25,20};
        LeastSquareMethod2 leastSquareMethod2 = new LeastSquareMethod2(x,y);
        double[] model = leastSquareMethod2.getRegressionModel();
        System.out.println("w=" +  model[0]);
        System.out.println("b=" +  model[1]);
    }

}

    打印结果:

w=1.8658557134722438
b=1.2497797817573257

    这个结果跟上面算法结果高度接近。只有w结果最后一位有差别。

    这篇文章通过机器学习算法中线性回归的实例,分别使用梯度下降和最小二乘法来计算,效果很接近,一般而言,梯度下降使用的更广泛一些,但是最小二乘法对于这类线性回归也是适合的。

    最小二乘法的这套公式推导,使用了求导数,求和运算,不管怎么样,这里要计算出w,b两个未知数,需要两个方程。最后根据公式计算出w,b的值,同时根据平均数的计算公式,我们又推导了另一种表示方法,他们是等价的。 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

最小二乘法公式推导以及在线性回归中的应用 的相关文章

  • 通过vue ui方式构建vue+electron项目

    以前我构建vue 43 electron项目都是使用一些模版比如webpack simulatedgreg electron vue等 xff0c 这些模版在github上 xff0c 有时候可能因为网络原因下载会慢一些 后来看到一些文章介
  • vue+echarts画甘特图

    vue项目中添加echarts xff0c 只需要增加echarts依赖 xff0c 然后在main js中引入echarts就可以使用了 1 npm install echarts save 2 修改main js import as e
  • mac系统下node版本管理工具n的安装与使用

    node版本管理 xff0c 在windows和linux下都叫nvm 在mac下 xff0c 更加简洁 xff0c 直接就是n xff0c 似乎容易让人产生怀疑 xff0c 这太简洁了 xff0c n可以表示很多意思啊 这就是mac系统独
  • python输出不换行与多行注释

    默认情况下 xff0c python输出打印方法print xff0c 每一次调用都会单独输出一行内容 xff0c 有些场景下面 xff0c 我们需要输出是连在一起的 xff0c 不用单行显示 这就需要对打印做设置 xff0c 参数是end
  • vue转electron项目以及使用fs报错:Module not found: Error: Can‘t resolve ‘fs‘ in解决办法

    前面写了一篇博客 xff0c 通过vue ui创建electron 43 vue项目 xff0c 其实关键的一步就是增加vue cli plugin electron builder插件依赖 这一步可以通过界面上添加 xff0c 也可以手动
  • python将图片转矩阵

    在机器学习手写数字识别案例中 xff0c 需要将手写数字图片转矩阵向量 其实转矩阵 xff0c 就需要根据图片上像素点来组成一个矩阵 xff0c 如果把图片看作一个 长 宽 的二维矩阵 xff0c 那么矩阵中的每个点的像素表示的数字组成一个
  • ant-design-vue中this.$confirm 确认框使用

    cancelService obj let self 61 this this confirm title 39 确认提示 39 content 96 是否确认取消服务 xff1f 96 okType 39 danger 39 onOk r
  • javascript数组排序

    javascript原生排序算法sort xff0c 如果不带排序函数 xff0c 那么就是默认按照升序排列 如果是数字类型就按照从小到大的顺序排列 xff0c 如果是字符串 xff0c 就按照字母顺序排列 Sorts an array i
  • electron项目打包之后显示空白页面以及发送http请求地址错误

    electron项目在开发阶段 xff0c 因为使用webpack脚手架 启用了webServer提供的http服务 xff0c 所以有路由功能 xff0c 当我们运行npm run electron serve的时候 xff0c 最后可以
  • mac系统electron项目打包出现:Error: Exit code: ENOENT. spawn /usr/bin/python ENOENT

    mac系统下 xff0c electron项目打包 xff0c 好像需要python可执行程序 xff0c 如果找不到就报这个错误 xff0c 而且python版本需要2 7版本 我的系统不知道怎么回事 xff0c 因为已经安装了pytho
  • 矩阵的乘法与利用矩阵求解线性方程组

    矩阵的乘法定义 xff1a 假定A 61 是一个m s的矩阵 xff0c B 61 是一个s n的矩阵 xff0c 那么规定 xff0c 矩阵A与矩阵B的乘积是一个m n的矩阵C 61 xff0c 其中 xff0c i 61 1 2 m j
  • 正则表达式[^]的作用

    与数字组合然后用中括号扩起来的用法比如 0 9 xff0c 或者与字母组合 a z 我们经常能见到 xff0c 表示匹配除了0 9或者a z之外的其他字符 但是有一种形式 xff0c 就是中括号 里面单独一个 xff1a 这种情况 xff0
  • [Java] synchronized在代码块中修饰.class与this的区别

    synchronized是java中的关键字 xff0c 表示同步 xff0c 可以在多线程环境中起到锁的作用 它是jvm层面的锁 xff0c 不需要人为获取释放锁资源 xff0c 由jvm决定 synchronized可以直接用在方法上
  • java面向对象编程中可能出现的隐藏hide、遮蔽shadow、遮掩obscure

    在java面向对象编程中 xff0c 我们最常遇到的两个场景是覆盖和重载 这两种情形是因为方法名相同的不同展现形式 方法覆盖是表现在父类和子类之间 方法重载发生在一个类的内部 在面向对象编程中 xff0c 我们还可能出现下面几种场景 xff
  • java控制台输出颜色设置

    在java中 xff0c 控制台输出 xff0c System out println 显示默认黑色 xff0c 如果是System err println 显示红色 要想让控制台输出改变颜色 xff0c 需要做一些设置 就像在linux终
  • java删除非空文件夹

    java中删除文件和空文件夹很简单 xff0c 直接调用File api xff0c file delete 就可以删除文件或者空文件夹本身 但是如果是非空文件夹 xff0c 这个方法就会失败 xff0c 就像在linux下我们使用命令rm
  • springboot项目中PropertySource读取yaml配置文件

    springboot项目中 xff0c 当我们使用 64 Value注解读取配置属性 xff0c 默认的配置文件是properties类型文件 xff0c 如果一些配置来自yaml格式配置文件 xff0c 那么就需要做一个配置 Proper
  • Java内存溢出问题排查分析

    目录 前言 一 MAT xff08 Memory Analyzer Tool xff09 二 软件初识 三 捕获dump文件 1 主动方式 2 被动方式 四 分析dump文件 总结 前言 项目运行过程中 xff0c 我们可能会遇到Java内
  • Excel行变列,列变行技巧以及单元格换行

    在excel操作中 xff0c 有可能有这样的需求 xff0c 就是一列数据 xff0c 我们最终需要把他们放在一行上展示 xff0c excel提供了复制粘贴功能 xff0c 在粘贴的时候 xff0c 右键选择 选择性粘贴 xff0c 再

随机推荐

  • snakeyaml生成yaml文件空值显示问题

    snakeyaml开源库 xff0c 可以很方便的加载和生成yaml文件 xff0c 普通的加载 xff0c 其实springboot项目都可以实现 xff0c 在生成yaml文件的时候 xff0c 有几个问题需要注意 xff0c 第一个是
  • java反射调用System.out.println实现控制台打印

    在java编程中 xff0c 我们最常用的控制台打印就是System out println 我们如果想用反射的方式来实现打印 xff0c 该如何操作呢 xff1f 我们可能会想着直接这样使用 Class forName 34 java l
  • vscode官方下载太慢解决办法

    不说话 xff0c 直接上动态图 xff1a 详细步骤 xff1a 1 打开官网 xff1a Visual Studio Code 点击下载 2 在下载器这里复制下载链接 xff0c 粘贴到浏览器地址栏 3 改变官网地址主地址为 vscod
  • node通过node-java库调用java

    node有一个库 node java xff0c 可以通过js的方式调用java语言 xff0c 听起来好像很好玩 xff0c 但是这个玩意要求很复杂 1 本机安装msbuild环境 这个东西简单的安装方式就是npm install g w
  • node-gyp编译c++编写的node扩展

    node有一个模块addon xff0c 翻译过来 xff0c 是插件 xff0c 但是有的地方也叫扩展 xff0c 这部分是用c 43 43 来编写的 xff0c 最后可以通过node gyp来针对各个平台编译适合自己平台的扩展 xff0
  • log4j日志漏洞问题

    去年 xff0c log4j被爆出了一个漏洞 xff0c 说可以通过利用日志格式化中的远程注入控制主机 当时 xff0c 这个漏洞被形容为史诗级漏洞 xff0c 因为这个远程操作可以执行一些操作 xff0c 如果这个操作有恶意 xff0c
  • postgresql数据备份与恢复

    postgresql数据备份与恢复在实际工作中可能会用到 xff0c 这里记录一下自己整理的备份与恢复的过程 xff0c 备份一般使用pg dump来做 xff0c 但是它备份的结果有两种格式 xff0c 默认不加 Fc参数 xff0c 产
  • bat批处理脚本大全

    目录 1 echo 2 注释 3 常见cmd命令 4 参数与变量 5 for循环 6 函数 7 数组 在windows上编程或者制作一些小工具 xff0c 少不了使用批处理脚本 xff0c 而且在各种开发环境搭建中我们经常会看到批处理脚本
  • node日志log4js库使用示例

    在node开发或者electron项目开发中 xff0c 我们可能需要记录日志的功能 xff0c 便于我们出错排查问题 今天介绍node中的日志库log4js log日志记录 xff0c 一般需要配置日志记录的级别 xff0c 日志输出类型
  • Maven项目引用本地jar涉及scope配置

    在项目开发过程中 xff0c 难免遇到需要引用私有jar的情况 xff0c 这时候最好是将该jar推送到私服仓库 xff0c 但是由于种种 现实问题 xff0c 比如权限不够 时间不够等等 于是就可以尝试将jar放入项目中进行集成 xff0
  • postgresql使用pg_basebackup备份与恢复

    postgresql可以使用pg dump pg restore等命令来进行备份与恢复 xff0c 那种情况不用停止pgsql服务 xff0c 只需要执行备份恢复命令即可 今天介绍的这种备份方式 xff0c 类似于文件系统的备份与恢复 xf
  • java中list与数组相互转换

    java中 xff0c list转数组 xff0c 很方便 xff0c list本身自带一个方法toArray xff0c 但是这个方法默认返回的数组类型是Object xff0c 我们可以给toArray 方法传递一个类型参数 xff0c
  • cython混淆加密

    python代码是一种解释型的语言 xff0c 有了代码和环境就可以执行 xff0c 它无需编译 如果需要对代码进行混淆 xff0c 可以借助cython这个库 它的安装很简单 xff0c 直接运行pip install cython就可以
  • python文件夹拷贝思路

    最近在做项目中 xff0c 要使用python xff0c 对文件拷贝有了一些了解 xff0c 这里将自己理解的文件拷贝整理出来 如下所示 xff0c 文件拷贝思路 xff1a 文件拷贝 xff0c 从io上来说就是读文件 xff0c 写文
  • node检测端口是否被占用isPortOccupied.js

    如题所示 xff0c node开发中 xff0c 可能会遇到开启tcp http服务端口被占用的问题 xff0c 解决起来也很简单 xff0c 直接换一个端口就可以了 但是每次启动 xff0c 发现失败 xff0c 然后更改监听端口来测试
  • commons-math3求解线性方程组

    python语言numpy scipy库可以实现矩阵求解线性方程组 xff0c 在java语言中 xff0c commons math3提供了强大的矩阵计算功能 xff0c 同样也可以用来解决线性方程组问题 如下所示 xff0c 线性方程组
  • 2022记忆

    今年开年来就重新找工作 xff0c 因为就在去年大概这个时候 xff0c 公司裁员了 找工作 xff0c 对于我们这种大龄程序员来说是一种挑战 xff0c 很多公司表面说可以聊聊 xff0c 最后谈了之后 xff0c 发现技术也可以 xff
  • java调用js示例

    jdk1 8引入了js引擎功能 xff0c 可以在命令行下运行js交互程序 xff1a 在jdk11之后 xff0c 这个功能又去掉了 如下代码 xff0c 是一个通过js调起计算器的示例 javascript代码 function mai
  • 查询是: LOCK TABLE test.xx_test IN ACCESS SHARE MODE问题解决办法

    如题所示 xff0c 这个问题是我在postgresql中使用pg dump备份多个schema的表时遇到的问题 bin pg dump dbname 61 postgresql dbuser 123456 64 localhost 543
  • 最小二乘法公式推导以及在线性回归中的应用

    机器学习算法中 xff0c 有一个基础的算法 xff0c 线性回归 xff0c 它的目的是求出一条直线 xff0c 满足所有点到这条直线的距离最短 xff0c 也就是这些数据点能够看起来都在这条直线附近 xff0c 最后 xff0c 可以根