python 非线性多项式拟合_[Python] 二维曲线拟合 ( 含有笔记、代码、注释 )

多项式拟合一次函数

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from numpy import polyfit, poly1d 
%matplotlib inline

x = np.linspace(-5, 5, 100) # 产生[-5,5]的100个等间隔的数组
y = 4 * x + 1.5 # y是关于x的一次函数
noise_y = y + np.random.randn(y.shape[-1]) * 2.5 # y添加噪声后的函数值。
print(y.shape[-1]) # 100个元素

运行结果:

100

p = plt.plot(x, noise_y, 'rx') # 画红色叉叉就是rx,画红色叉叉虚线图就是rx--
p = plt.plot(x, y, 'b:') # 画蓝色点图,"b" 表示蓝色,":"表示点图。

d19c11580ab0b52a0505906213032d8f.png
coeff = polyfit(x, noise_y, 1)
print(coeff)

运行结果:

[4.00355516 1.55927961]

p = plt.plot(x, noise_y, 'rx')
p = plt.plot(x, coeff[0] * x + coeff[1], 'k-') # 画黑色实线图,"k" 表示实线,"-"表示实线。
p = plt.plot(x, y, 'b--') # 这里可看出拟合出一阶函数与原函数重合了,课通过注释该语句看出。

bbb621a7e0f44abcc68ecc3b167550b3.png
# 还可以用 poly1d 生成一个以传入的 coeff 为参数的多项式函数:
f = poly1d(coeff)
p = plt.plot(x, noise_y, 'rx') # 绘制红色叉叉散点图
p = plt.plot(x, f(x)) # 带入x点,画出f函数。

092de96f5a2951974fcc574cdb36c0e1.png

多项式拟合正弦函数

x = np.linspace(-np.pi,np.pi,100)
y = np.sin(x)

# 用一阶到九阶多项式拟合,类似泰勒展开:
y1 = poly1d(polyfit(x,y,1))
y3 = poly1d(polyfit(x,y,3))
y5 = poly1d(polyfit(x,y,5))
y7 = poly1d(polyfit(x,y,7))
y9 = poly1d(polyfit(x,y,9))

x = np.linspace(-3 * np.pi,3 * np.pi,100)

p = plt.plot(x, np.sin(x), 'k') # 黑色为原始的图形,
p = plt.plot(x, y1(x)) 
p = plt.plot(x, y3(x))
p = plt.plot(x, y5(x))
p = plt.plot(x, y7(x))
p = plt.plot(x, y9(x)) # 可以看到,随着多项式拟合的阶数的增加,曲线与拟合数据的吻合程度在逐渐增大。

a = plt.axis([-3 * np.pi, 3 * np.pi, -1.25, 1.25])

f6597e0ee355f452bc066c8d87e12e46.png

最小二乘拟合

from scipy.linalg import lstsq

x = np.linspace(0,5,100)
y = 0.5 * x + np.random.randn(x.shape[-1]) * 0.35

plt.plot(x,y,'x') # 产生含有一定线性关系的散点图,含有噪音。

运行结果:

[<matplotlib.lines.Line2D at 0x251c6b60970>]

69c0c3a05b3fd7864da4afb23fef14e4.png
X = np.hstack((x[:,np.newaxis], np.ones((x.shape[-1],1)))) # 这里将x扩展成X了,这里N=2。
X[1:5]

运行结果:

array([[0.05050505, 1. ],
[0.1010101 , 1. ],
[0.15151515, 1. ],
[0.2020202 , 1. ]])

C, resid, rank, s = lstsq(X, y)

p = plt.plot(x, y, 'rx')
p = plt.plot(x, C[0] * x + C[1], 'k--')
print("sum squared residual = {:.3f}".format(resid)) # 平方和残差
print("rank of the X matrix = {}".format(rank)) # 秩
print("singular values of X = {}".format(s)) # X的奇异值

运行结果:

sum squared residual = 12.986
rank of the X matrix = 2
singular values of X = [30.23732043 4.82146667]

4faac0a8e478054290a7a1b911fd4e7d.png

线性回归拟合

from scipy.stats import linregress

slope, intercept, r_value, p_value, stderr = linregress(x, y)
slope, intercept

运行结果:

(0.5028457518511993, 0.024071946424871093)

p = plt.plot(x, y, 'rx')
p = plt.plot(x, slope * x + intercept, 'k--') # 由图可以看出两者(线性回归、最小二乘)求解的结果是一致的,但是出发的角度是不同的。
print("R-value = {:.3f}".format(r_value)) 
print("p-value (probability there is no correlation) = {:.3e}".format(p_value))
print("Root mean squared error of the fit = {:.3f}".format(np.sqrt(stderr)))

运行结果:

R-value = 0.912
p-value (probability there is no correlation) = 1.254e-39
Root mean squared error of the fit = 0.151

3963b09a21049c8628eac105b8326942.png

更高级的拟合

from scipy.optimize import leastsq

def function(x, a , b, f, phi): # 定义非线性函数
    """a function of x with four parameters"""
    result = a * np.exp(-b * np.sin(f * x + phi))
    return result

x = np.linspace(0, 2 * np.pi, 50)
actual_parameters = [3, 2, 1.25, np.pi / 4] # 实际参数
y = function(x, *actual_parameters)
p = plt.plot(x,y) # 画出实际的x、y函数。

c31dbc8eceb4d5e397d7291a0cad25d4.png
from scipy.stats import norm
y_noisy = y + 0.8 * norm.rvs(size=len(x)) # 加入噪声
p = plt.plot(x, y, 'k-')
p = plt.plot(x, y_noisy, 'rx')

cbbf0fd07dcf9013dd2dde186dd372d8.png
# 定义误差函数,将要优化的参数放在前面:

def f_err(p, y, x):
    return y - function(x, *p) 

# 将这个函数作为参数传入 leastsq 函数,第二个参数为初始值:

c, ret_val = leastsq(f_err, [1, 1, 1, 1], args=(y_noisy, x))
print(c)
print(ret_val) # ret_val是 1~4 时,表示成功找到最小二乘解:

p = plt.plot(x, y_noisy, 'rx')
p = plt.plot(x, function(x, *c), 'k--')

运行结果:

[3.32130888 1.89218577 1.28617493 0.68515905]
1

cf5458070cde8ffb5b0c0c614dd6310a.png
# 更高级的做法:不需要定义误差函数,直接传入function作为参数。

from scipy.optimize import curve_fit
p_est, err_est = curve_fit(function, x, y_noisy) # p_est 为返回的是给定模型的最优参数,err_est。r_est为估计协方差。
print(p_est)
print(err_est)

运行结果:

[3.32130886 1.89218577 1.28617493 0.68515906]
[[ 0.13806975 -0.04121882 0.01507384 -0.04721358]
[-0.04121882 0.01262612 -0.00431895 0.01352772]
[ 0.01507384 -0.00431895 0.00224488 -0.00703102]
[-0.04721358 0.01352772 -0.00703102 0.02227572]]

p = plt.plot(x, y_noisy, "rx")
p = plt.plot(x, function(x, *p_est), "k--")

cf5458070cde8ffb5b0c0c614dd6310a.png
print("normalized relative errors for each parameter")
print("   at  bt ftphi")
print(np.sqrt(err_est.diagonal()) / p_est)

运行结果:

normalized relative errors for each parameter
a b f phi
[0.11187679 0.05938424 0.03683802 0.21783342]

附录01:matplotlib库

① Matplotlib库 是 Python 的绘图库。

② 它常与 NumPy 一起使用。

附录02:matplotlib.pyplot库

① matplotlib的pyplot子库提供了绘图API,方便用户快速绘制2D图表。

② matplotlib.pyplot是函数的集合,每一个函数都对图像作了修改,比如其中有创建图形,在图像上创建画图区域,在画图区域上画线,在线上标注等。

附录03:np.polyfit()函数

① polyfit()函数是多项式拟合函数,polyfit(x, noise_y, 1)表示拟合一阶多项式,即线性拟合函数。

② 即拟合出一阶多项式 y=a1x+a0,返回两个系数 [a1,a0]。

附录04:np.poly1d()函数

① np.poly1d()函数有两个入口参数。

② 若没有第二个参数,则生成一个多项式。

③ 例如:

p = np.poly1d([2,3,5,7])

print(p)==>>2x3+3x2+5x+7

④ 若第二个参数为True,则表示把数组中的值作为根,然后反推多项式。

⑤ 例如:

q = np.poly1d([2,3,5],True)

print(q)===>>(x-2)(x-3)(x-5)=x3-10x2+31x-30

附录05:%matplotlib inline

① 有了%matplotlib inline 就可以省掉plt.show()了。

② 如果不加这一句的话,我们在画图结束之后需要加上plt.show()才可以显示图像。

附录06:numpy.random.randn()函数

① randn函数返回一组样本,具有标准正态分布。

② 标准正态分布又称为u分布,是以0为均值、以1为标准差的正态分布,记为N(0,1)。

附录07:plt.axis()函数

① axis是用来设置具体某一个坐标轴的属性的。

② xmin, xmax, ymin, ymax = axis([xmin, xmax, ymin, ymax])

附录08:最小二乘法

① 当M个点具有线性关系时,我们可以使用一个 N-1 阶的多项式拟合这 M 个点,关系式为:

② 即:

d2d2e88e0a3ad0ef1db067c37ac33217.png

③ 要得到C,可以使用scipy.linalg.lstsq求最小二乘解。

附录09:numpy.linalg库

① numpy.linalg模块包含线性代数的函数,使用这个模块,可以计算逆矩阵、求特征值、解线性方程组以及求解行列式等。

附录10:scipy.stats库

① Scipy的stats模块包含了多种概率分布的随机变量,随机变量分为连续的和离散的两种。

附录11:lstsq()函数

① lstsq()函数表示最小二乘法,它有四个返回值,第一个返回值的第一个元素为多项式的系数,第二个返回值为平方和残差,第三个返回值句矩阵X的秩,第四个返回值为矩阵X的奇异值。

附录12:linregress()函数

① linregress(x,y)函数就是线性回归的函数。

② linregress(x,y)函数有五个返回值,第一个返回值slope为斜率,第二个返回值intercept为截距,第三个返回值r_value为相关系数,第四个返回值p-value为没有相关性的可能性,第五个返回值stderr为拟合的均方根误差。

附录13:np.hstack()函数

① np.hstack()函数使得数组沿着水平方向堆叠起来。

import numpy as np

arr1 = np.array([1, 2, 3])

arr2 = np.array([4, 5, 6])

res = np.hstack((arr1, arr2))

print(res)

输出结果:

[1 2 3 4 5 6]

arr1 = np.array([[1, 2], [3, 4], [5, 6]])

arr2 = np.array([[7, 8], [9, 0], [0, 1]])

res = np.hstack((arr1, arr2))

print(res)

输出结果:

[[1 2 7 8]

[3 4 9 0]

[5 6 0 1]]

附录14:x[:,np.newaxis]

① x[:,np.newaxis]使得一行元素变成一列元素了。

附录15:np.exp()函数

① np.exp()函数返回e(自然对数的底)的幂次方。

附录16:norm.rvs()函数

① norm函数 可以实现正态分布,norm.rvs()函数通过loc和scale参数可以指定随机变量的偏移和缩放参数,这里对应的是正态分布的期望和标准差。

② size得到随机数数组的形状参数。(也可以使用np.random.normal(loc=0.0, scale=1.0, size=None))

附录17:curve_fit()函数

① 而curve_fit()函数是将模型函数适用于噪声数据的最后一步,它的主要功能就是计算出参数。

② curve_fit()函数第一个返回的是函数的参数,第二个返回值为各个参数的协方差矩阵,协方差矩阵的对角线为各个参数的方差。

参考文献:

  1. Henri Jambo:Python曲线拟合详解

帮忙点个赞,谢谢!

整理不易,给点鼓励,谢谢!

我整理的所有笔记!( 专栏里有 )


版权声明:本文为weixin_28999575原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。