非线性最小二乘法 python_通俗易懂最小二乘法与牛顿法总结:线性与非线性,文末有Python和c++代码编程实践教程...

今日疯言疯语:

很多算法看不懂大概率是这些算法做出的一些假设你不知道——@Ai酱

线性最小二乘法||Ax-y||可以直接求解

问题:已知A和y,需要求x。并且需要最小化||Ax-y||。

下面是求解x的方法:

Ax=yATAx=ATyx=(ATA)−1ATyAx=y \\

A^TAx = A^Ty\\

x = (A^TA)^{-1}A^TyAx=yATAx=ATyx=(ATA)−1ATy

之所以要乘个ATA^TAT是因为A很可能不是方阵,不是方阵是不能求逆的。

非线性最小二乘法需要用牛顿法求解

问题:已知f()表达式和y,需要求x。并且需要最小化∣∣f(x)−y∣∣||f(x)-y||∣∣f(x)−y∣∣。这个||xx||是指范数的意思,你把它当做是绝对值或者平方就行.而我们知道∣∣f(x)−y∣∣||f(x)-y||∣∣f(x)−y∣∣的最小值是0,所以我们就是想求∣∣f(x)−y∣∣||f(x)-y||∣∣f(x)−y∣∣等于0时x的取值。

什么是牛顿法?

它是一个用来求某个函数最小值所在点的自变量的值算法。牛顿法这和这里我们需要求解的问题有什么联系。我们就是想求g(x)=∣f(x)−y∣g(x)=|f(x)-y|g(x)=∣f(x)−y∣这个函数的最小值点的自变量x。如果你还不了解为何要哦用牛顿法,你可以再看看前面的问题描述。

牛顿法思想是怎样的?具体步骤怎么做?

注意:用牛顿法(Newton’s Method)求解一个函数最小值点对应的自变量值时,默认对这个函数有个假设“这个函数的最小值接近于0”。也就是说我们知道这个函数的最小值。但是就是不知道取得最小值时自变量的值。我们要用牛顿法求这个自变量的值。

只要提到牛顿法一定要注意前面这个假设,很多算法看不懂大概率是这些算法做出的一些假设你不知道。

我们整理下思路,现在想求g(x)g(x)g(x)的最小值点时候对应的x。并且知道g(x)g(x)g(x)的最小值是0. 牛顿法的思路是随便先猜最小值点对应的x。然后慢慢修正它直到接近最小值点对应的自变量值。假如我猜是x0x_0x0​。然后怎么修正这个猜测值呢?现在我们已知一个点(x0,g(x0))(x_0,g(x_0))(x0​,g(x0​)),并且知道在这个点时函数g(x)的导数值g′(x0)g'(x_0)g′(x0​)。那么我们根据高中学的点斜式就可以写出经过(x0,g(x0))(x_0,g(x_0))(x0​,g(x0​))这个点的切线方程y−g(x0)=g′(x0)(x−x0)y-g(x_0)=g'(x_0)(x-x_0)y−g(x0​)=g′(x0​)(x−x0​)。我们可以把这个切线当做g(x)g(x)g(x)的近似。前面提到了牛顿法有一个假设(函数g(x)的最小值等于0),现在这个假设开始发挥大作用了。现在y−g(x0)=g′(x0)(x−x0)y-g(x_0)=g'(x_0)(x-x_0)y−g(x0​)=g′(x0​)(x−x0​)是对g(x)的近似,那么我们可以令函数值y=0求得一个x。把这个x当做最小值点对应自变量值的一个新的猜测。然后重复以上过程直到找到一个变量xnx_nxn​使得g(xn)g(x_n)g(xn​)非常接近于0.此时的xnx_nxn​就是我们要求的g(x)的最小值时对应的自变量的值。

Python编程实践非线性的最小二乘法

假如你需要求sin(x)=0.233时的x的取值。注意x的单位是弧度。虽然你可以调用Python代码里面的arcsin这个函数,但是为何我们不试试自己编程实现arcsin呢?引用某知名网友的话“抱着造轮子的心态学东西(逃”。

我们整理下思路现在的最小二乘法问题就是我们需要求g(x) = |sin(x)-0.233|的最小值所在点的自变量值x。

在使用牛顿法前我们不要忘了牛顿法是有个假设的。那就是目标函数g(x)的最小值是0.显然现在我们这个例子是满足的。

第一步:随便猜g(x) 最小值所在点对应的自变量值. 现在我们假设这个自变量值是x0=3.14x0=3.14x0=3.14。所以我们得到了一个点(3.14,sin(3.14)−0.233)(3.14, sin(3.14)-0.233)(3.14,sin(3.14)−0.233)。而且知道这个点的导数值g′(3.14)=cos(3.14)g'(3.14)=cos(3.14)g′(3.14)=cos(3.14)。然后我们可以写出经过这个点的切线方程y−(sin(3.14)−0.233)=g′(3.14)∗(x−3.14)y-(sin(3.14)-0.233) =g'(3.14)*(x-3.14)y−(sin(3.14)−0.233)=g′(3.14)∗(x−3.14)。所以切线方程为y−(sin(3.14)−0.233)=cos(3.14)∗(x−3.14)y-(sin(3.14)-0.233) =cos(3.14)*(x-3.14)y−(sin(3.14)−0.233)=cos(3.14)∗(x−3.14)

第二步:将切线看做是原函数g(x)g(x)g(x)的一个近似,然后令切线函数值y等于0来修正第一步的猜测值。根据0−(sin(3.14)−0.233)=cos(3.14)∗(x−3.14)0-(sin(3.14)-0.233) =cos(3.14)*(x-3.14)0−(sin(3.14)−0.233)=cos(3.14)∗(x−3.14)可以解得x=−(sin(3.14)−0.233)/cos(3.14)+3.14x=-(sin(3.14)-0.233)/cos(3.14)+3.14x=−(sin(3.14)−0.233)/cos(3.14)+3.14。我们可以将这个字作为g(x) 最小值所在点对应的自变量值的一个新的猜测值。

重复上面两步直到g(猜测值)非常接近于0.

下面是Python代码:

'''牛顿法求解非线性最小二乘法

author: @Ai酱

欢迎评论

'''

import math

import random

def g(x0):

'''

目标函数在x0处的函数值

Args:

x0 自变量:角度,单位是弧度

'''

return math.sin(x0) + 0.233

def dg_dx(x0):

'''

目标函数g(x)在x0处导数g'(x0)

Args:

x0 自变量:角度,单位是弧度

'''

return math.cos(x0)

# 1. 为g(x) 最小值所在点对应的自变量值随便猜一个值

x0 = random.random()

while abs(g(x0)) > 0.001: # 一直迭代直到g(x0)接近0

# 2. 令切线函数值y=0求得一个x值,将它作为一个新的猜测值修正原先的猜测x0

new_x0 = x0 - g(x0)/dg_dx(x0)

x0 = new_x0

print("我们自己写的牛顿法求得的arcsin(0.233)=",x0)

# 我们用python自带的arcsin检验下

print("Python自带的arcsin求得的arcsin(0.233)=",math.asin(0.233))

如果你看不懂Python代码,下面是我写的c++代码:

#include

#include

using namespace std;

/**

* 返回g(x)在x0处的函数值g(x0)

* params:

* x 自变量:角度,单位弧度

*/

float g(float x0)

{

return sin(x0) - 0.2333;

}

/**

* 目标函数g(x)在x0处导数g'(x0)

* params:

* x0 自变量:角度,单位是弧度

*/

float dg_dx(float x0)

{

return cos(x0);

}

int main()

{

// 1. 为g(x) 最小值所在点对应的自变量值随便猜一个值

float x0 = 1.233;//这个你随便设(由于是弧度所以不要太大)

while (abs(g(x0)) > 0.001) // 一直迭代直到g(x0)接近0

{

// 2. 令切线函数值y = 0求得一个x值,将它作为一个新的猜测值修正原先的猜测x0

float new_x0 = x0 - g(x0) / dg_dx(x0);

x0 = new_x0;

}

cout << "我们自己写的牛顿法求得的arcsin(0.233)=" << x0 << endl;

// 我们用c++自带的arcsin检验下

cout << "c++自带的arcsin求得的arcsin(0.233)=" << asin(0.233) << endl;

return 0;

}

你的关注和赞是支持我分享易懂教程的最大动力!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值