推荐开源项目:简单的SLAM与机器人教程与编程实践-githubhtml
今日疯言疯语:
不少算法看不懂大几率是这些算法作出的一些假设你不知道——@Ai酱python
问题:已知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极可能不是方阵,不是方阵是不能求逆的。ios
问题:已知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。若是你还不了解为什么要哦用牛顿法,你能够再看看前面的问题描述。c++
注意:用牛顿法(Newton’s Method)求解一个函数最小值点对应的自变量值时,默认对这个函数有个假设“这个函数的最小值接近于0”。也就是说咱们知道这个函数的最小值。可是就是不知道取得最小值时自变量的值。咱们要用牛顿法求这个自变量的值。git
只要提到牛顿法必定要注意前面这个假设,不少算法看不懂大几率是这些算法作出的一些假设你不知道。github
咱们整理下思路,如今想求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)的最小值时对应的自变量的值。算法
假如你须要求sin(x)=0.233时的x的取值。注意x的单位是弧度。虽然你能够调用Python代码里面的arcsin这个函数,可是为什么咱们不试试本身编程实现arcsin呢?引用某知名网友的话“抱着造轮子的心态学东西(逃”。编程
咱们整理下思路如今的最小二乘法问题就是咱们须要求g(x) = |sin(x)-0.233|的最小值所在点的自变量值x。
在使用牛顿法前咱们不要忘了牛顿法是有个假设的。那就是目标函数g(x)的最小值是0.显然如今咱们这个例子是知足的。dom
第一步:随便猜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<math.h> #include<iostream> 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; }