多项式拟合一次函数
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" 表示蓝色,":"表示点图。

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--') # 这里可看出拟合出一阶函数与原函数重合了,课通过注释该语句看出。

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

多项式拟合正弦函数
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])

最小二乘拟合
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>]

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]

线性回归拟合
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

更高级的拟合
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函数。

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')

# 定义误差函数,将要优化的参数放在前面:
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

# 更高级的做法:不需要定义误差函数,直接传入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--")

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 个点,关系式为:
② 即:

③ 要得到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()函数第一个返回的是函数的参数,第二个返回值为各个参数的协方差矩阵,协方差矩阵的对角线为各个参数的方差。
参考文献:
- Henri Jambo:Python曲线拟合详解
帮忙点个赞,谢谢!
整理不易,给点鼓励,谢谢!
我整理的所有笔记!( 专栏里有 )