Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4562596
  • 博文数量: 1214
  • 博客积分: 13195
  • 博客等级: 上将
  • 技术积分: 9105
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
个人简介

C++,python,热爱算法和机器学习

文章分类

全部博文(1214)

文章存档

2021年(13)

2020年(49)

2019年(14)

2018年(27)

2017年(69)

2016年(100)

2015年(106)

2014年(240)

2013年(5)

2012年(193)

2011年(155)

2010年(93)

2009年(62)

2008年(51)

2007年(37)

分类: IT业界

2020-09-07 17:30:26

https://blog.csdn.net/sinat_34328764/article/details/85473276

最近接触到了Scipy中optimize模块的一些函数,optimize模块中提供了很多数值优化算法,其中,最小二乘法可以说是最经典的数值优化技术了, 通过最小化误差的平方来寻找最符合数据的曲线。在optimize模块中,使用leastsq()函数可以很快速地使用最小二乘法对数据进行拟合。

首先来看leastsq()函数地调用格式:

leastsq(func, 
        x0,
        args=(),
        Dfun=None,
        full_output=0,
        col_deriv=0,
        ftol=1.49012e-08,
        xtol=1.49012e-08,
        gtol=0.0,
        maxfev=0,
        epsfcn=0.0,
        factor=100,
        diag=None,
        warning=True)


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

参数还是非常多的,一般来说,我们只需要前三个参数就够了他们的作用分别是:

  • func:误差函数
  • x0:表示函数的参数
  • args()表示数据点

举个例子:
这里要进行拟合的数据点都分布在这条正弦曲线附近:

def func(x):
    return 2*np.sin(2*np.pi*x) 
  • 1
  • 2

然后定义误差函数,所谓误差就是指我们拟合的曲线的值对应真实值的差:

def residuals(p, x, y):
    fun = np.poly1d(p)    # poly1d()函数可以按照输入的列表p返回一个多项式函数
    return y - fun(x)   # 返回真实值 与我们拟合的曲线上对应的值的差 
  • 1
  • 2
  • 3

这里设计了一个poly1d()函数,关于这个函数,简单理解下就是输入一个列表,返回以这个列表中的值为参数的多项式,例如:

输入:[1,2,3]
返回:x^2 + 2x + 3
多项式的次数是从0开始记的,要注意这个地方 
  • 1
  • 2
  • 3

下面定义关于拟合的曲线的函数:

# 拟合函数
def fitting(p):
    pars = np.random.rand(p+1)  # 生成p+1个随机数的列表,这样poly1d函数返回的多项式次数就是p
    r = leastsq(residuals, pars, args=(X, Y))   # 三个参数:误差函数、函数参数列表、数据点
    return r 
  • 1
  • 2
  • 3
  • 4
  • 5

注释里的内容就是要注意的地方,由于会多次调用拟合,多以写成了函数的形式,这里传入的p是一个数字,表示我们想要得到拟合曲线的次数,比如我想针对这些数据点得到一条3次的曲线,就调用p=3类似,注意这里leastsq()函数的返回值,这里的返回值保存的是拟合的曲线的信息,如果打印这里的r,就会发现返回了一个truple,其中第一维是一个列表,保存的是拟合的曲线的参数,所以要注意如何获得这些参数。
接下来定义一下我们要进行拟合的数据点,这里定义了10个:

# 要进行拟合的数据点
X = np.linspace(0, 1, 10)
Y = [np.random.normal(0, 0.1)+num for num in func(X)]  # 添加噪声

# 方便绘制曲线,所以创建多一些点
x_ = np.linspace(0, 1, 100)
y_ = func(x_) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

调用拟合函数,并进行绘图:

fit_pars = fitting(3)[0]    # 注意返回值中的第一行才是拟合曲线的参数列表

plt.plot(x_, y_, label='real line')
plt.scatter(X, Y, label='real points')
plt.plot(x_, np.poly1d(fit_pars)(x_), label='fitting line')
plt.legend()
plt.show() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

p=3的时候的图像:
在这里插入图片描述
当然,这里我直接传入p=3,也就是建立3次的曲线对数据点进行拟合,如果传入的p=1的时候,图像如下:
在这里插入图片描述
如果p=2,则是:
在这里插入图片描述
可以看到没有变化,也就是说没办法找到一条二次曲线,使得二次误差少于上面的一次曲线了。
完整代码如下:

import numpy as np
from scipy.optimize import leastsq
import matplotlib.pyplot as plt

# 数据点分布在这条曲线附近
def func(x):
    return 2*np.sin(2*np.pi*x)

# 误差函数, 计算拟合曲线与真实数据点之间的差 ,作为leastsq函数的输入
def residuals(p, x, y):
    fun = np.poly1d(p)    # poly1d()函数可以按照输入的列表p返回一个多项式函数
    return y - fun(x)

# 拟合函数
def fitting(p):
    pars = np.random.rand(p+1)  # 生成p+1个随机数的列表,这样poly1d函数返回的多项式次数就是p
    r = leastsq(residuals, pars, args=(X, Y))   # 三个参数:误差函数、函数参数列表、数据点
    return r

# 要进行拟合的数据点
X = np.linspace(0, 1, 10)
Y = [np.random.normal(0, 0.1)+num for num in func(X)]  # 添加噪声

# 方便绘制曲线,所以创建
x_ = np.linspace(0, 1, 100)
y_ = func(x_)

# print(fitting(3))   可以看一下返回的是什么
fit_pars = fitting(3)[0]

plt.plot(x_, y_, label='real line')
plt.scatter(X, Y, label='real points')
plt.plot(x_, np.poly1d(fit_pars)(x_), label='fitting line')
plt.legend()
plt.show() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

以上~

阅读(1311) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~