python插值与拟合

kl

 由这张图我们粗略的了解插值和拟合:下面正式介绍。

一维插值

一维插值就是在已知互不相同的观测点x_{0}<x_{1}<x_{2}<...<x_{n}除的函数值:寻找一个近似函数f(x)使得f(x_{i})=y_{i},也就是这个函数的曲线要通过所有观测点。这样我们就能观测x^{\hat{}}在非观测点x_{0}<x_{1}<x_{2}<...<x_{n}之外的点的函数值。

f(x)称为插值函数,含x_{i}(i=0,1,,,n)的最小区间[a,b]称作插值区间,x^{\hat{}}称作插值点。

注意:插值方法一般用于插值区间内部点的函数值估计或者预测,当大于预测区间时,通常我们也可以进行短期的预测,对于中长区是不可取的。这也就告诉我们插值方法可以对数据中缺失的数据进行填补

多项式插值

f(x_{i})=y_{i}(i=0,1,2,,n),这个插值条件式子共有n+1个约束方程,而n次多项式也恰好有n+1个待定系数法。如果已知这些函数点以及函数值,我们可以确定一个次数不超过n的多项式。

P_{n}=a_{n}x^{n}+a_{n-1}x^{n-1}+....+a_{1}x+a_{0},这个多项式满足P_{n}=f(x_{i})=y_{i}

对于上面多项式系数通常可以用三种方法;待定系数法,拉格朗日插值,牛顿插值。

这里我们介绍前两种方法,因为根据克莱姆法则方程的解唯一,所以三种插值方法的计算结果相同,掌握一种即可。

待定系数法

将已知的函数点和函数值代入多项式中:得到

\left\{\begin{matrix} a_{n}x^{n}_{0}+a_{n-1}x^{n-1}_{0}+....+a_{1}x_{0}+a_{0}= y_{0}& & & \\ a_{n}x^{n}_{1}+a_{n-1}x^{n-1}_{1}+....+a_{1}x_{1}+a_{0}= y_{0} & & & \\ ..... & & & \\ a_{n}x^{n}_{n}+a_{n-1}x^{n-1}_{n}+....+a_{1}x_{n}+a_{0}= y_{n}\end{matrix}\right.

我们将其写成矩阵的形式:

\begin{bmatrix} x_{0}^{n}&x_{0}^{n-1} & ... & 1\\ x_{1}^{n} &x_{1}^{n-1} & ... &1 \\ ... & ...& ...&1\\ x_{n}^{n}& x_{n}^{n-1} &... &1 \end{bmatrix}.\begin{bmatrix} a_{n}\\ a_{n-1}\\ ...\\ a_{0}\end{bmatrix}=\begin{bmatrix} y_{0}\\ y_{1}\\ ...\\ y_{n}\end{bmatrix}

于是我们根据举证乘法可以得到这个系数的解:记系数矩阵为A,所以有A=Y\cdot X^{-}

引入几个例题;

已知函数的6个观测点,求插值函数y=f(x),并求x=1.5,2.6的观测值。

x 1 2 3 4 5 6
y 16 18 21 17 15 12
import numpy as np
x0=np.arange(1,7)
y=np.array([16,18,21,17,15,12])
X=np.vander(x0)
a=np.linalg.inv(X)@y
print(a)
yh=np.polyval(a,[1.5,2.6])
print(yh)

(1) 我们可以看出多项式中的X矩阵是一个标椎的范德蒙矩阵,所以我们使用numpy库里的内置函数构造一个范德蒙矩阵——vander

(2)我们在numpy中求逆函数的标准函数是np.linalg.inv()

(3)函数polyval(A,[m,n...]),A输入多项式系数值,列表中包含需要预测的函数点。

拉格朗日插值 

 原理不具体介绍,这里直接介绍在python的方法。还是以上面的例子为例。

import numpy as np
from scipy.interpolate import lagrange
x0=np.arange(1,7)
y=np.array([16,18,21,17,15,12])
a=lagrange(x0,y)
print(a)
yh=np.polyval(a,[1.5,2.6])
print(yh)

输出以后的系数和用待定系数法求得的结果是一样的,预测方法也相同的。

但是我们在实际问题中很少使用多项式插值,因为多项式插值随着次数的增高,会产生龙格现象。(龙格现象指的是随着插值的次数增加,也就是插值点的增加,插值结果越偏离原函数。),所以我们通常使用分段线性插值和三次样条插值。

分段线性插值和三次样条插值

分段线性插值:简单来说就是每两个相邻的节点用直线相连,如此形成的一条直线就是分段线性插值函数,记作I_{n}(x),并且同样满足I_{n}(x)=f(x),在每个小区间内是线性函数。这里简单介绍一下原理。

三次样条插值:分段线性插值在连接点处的光滑程度不高,于是我们重新定义一个函数S(x),这个函数满足(1)在每个小区间[x,x+1]上S(x)是K次多项式。\int_{0}^{10}g\hat{}(x)dx

(2)S(x)在[a,b]上具有k-1阶连续导数

具备这两个条件就称S(x)为关于划分\Delta的k次样条函数。而三次样条函数就是其中之一, 在每个小区间[x,x+1]上S(x)是三次多项式, S(x)在[a,b]上具有2阶连续导数,并且在节点处有S_{i}(x)=y_{i}=f(x)

话不多说直接上例题,原理我们稍作了解具体还是了解代码运作

先介绍我们使用的函数,scipy.interpolate模块有一维插值函数interp1d,二维插值函数interp2d.

interp1d基本的调用格式为interp1d(x,y,kind='linear'),kind取值是方法为字符串,指明了插值方法,默认为分段线性插值,'zero','slinear','quadratic','cubic'分别指的是0阶,一阶,二阶,三阶样条插值。

在区间[0,10]上取等间距1000个点x_{i},并计算这些点x_{i}处函数g(x)=\frac{(3x^{2}+4x+6)sin(x)}{x^{2}+8x+6}的函数值y_{i}利用观测点,求三次样条插值函数。并且积分\int_{0}^{10}g(x)dx\int_{0}^{10}g\hat{}(x)dx

from scipy.interpolate import interp1d
from scipy.integrate import quad
import scipy as sp
import numpy as np
y=lambda x: (3*x**2+x*4+6)*np.sin(x)/(x**2+8*x+6)
x=np.linspace(0,10,1000)
y1=y(x)
y2=interp1d(x,y1,'cubic')
y3=y2(x)
I=quad(y,0,10)
print(I)
I2=np.trapz(y3,x)
print(I2)

(1)对于进行插值的interp1d函数,我们已经介绍过,学会使用即可。

(2)对于有具体函数形式的方程,我们使用从 scipy.integrate导入的函数quad进行定积分处理,使用形式如下 quad(fun,n,m),fun中是具体的函数,剩余两个参数指的是从n到m的积分区域。对于使用插值预测的函数,我们通常使用numpy给出的函数trapz函数,trapz(y,x)函数中y指的是使用积分区域预测出的插值,x指的是积分区域。(通常x需要有多个插值点)

例题2

已知温度为T,T=[700,720,740,760,780] ,过热蒸汽体积的变化V=[0.0977,0.1218,0.1406,0.1551,0.1664],分别采用分段线性插值和三次样条插值求解T=[750,770]的体积变化,并在一个图形中画出这两个函数。

from scipy.interpolate import interp1d
import pylab as plt
import numpy as np
T=np.array([700,720,740,760,780])
V=np.array([0.0977,0.1218,0.1406,0.1551,0.1664])
s3=interp1d(T,V,'cubic')
s=interp1d(T,V)
x=[750,770]
y1=s3(x);print('三次样条预测=',y1)
y2=s(x);print('分段线性插值=',y2)
x=np.linspace(700,780,81)
y3=s3(x);y4=s(x)
plt.rc('font',family='SimHei')
plt.plot(x,y3,'*-',label='三次样条插值')
plt.plot(x,y4,'-',label='分段线性插值')
plt.legend()
plt.show()

plt.rc('font',family='SimHei')这个语句做用是使中文能够正常显示,而plt.legend()是为了让标签显示,如果不明白可以去掉这个语句在查看图形。

二维插值

二维插值问题描述如下:给定的xOy平面上有m*n个互不相同的插值节点,同时也已知这些插值节点处的观测值。求一个近似的二元插值曲面函数f(x,y),使其通过全部已知节点即要求任一插值点(x^{*},y^{*})处的函数值,可以利用插值函数进行预测。

二维插值常见的分为两种:网格节点插值和散乱数据插值

网格节点插值:用于规则矩形网格点插值情形。散乱数据插值:用于一般数据点,尤其是数据点杂乱无章的情况。

在python中对于网格节点插值我们使用interp2d函数,而对于散乱数据插值我们使用griddata函数,这两个函数均来自scipy.interpolate中,由于通常我们使用二维插值较少,所以再此不过多介绍。

拟合

已知一组二维数据,即平面上的n个点(x_{i},y_{i}),要寻求一个函数(曲线)y=f(x),使f(x)在某种准则下与所有数据点最为接近,也就是曲线拟合的最好,同时记\lambda _{i}=f(x_{i})-y_{i},称\lambda _{i}为拟合函数f(x)x_{i}点出的残差。

最小二乘拟合

 前面介绍了残差的概念,为了使f(x)与其给定数据最接近,可以采用‘残差的平方和最小’作为评判标准,使得残差平方和最小。这一原则被称为最小二乘原则,根据最小二乘原则确定拟合函数f(x)的方法被称为最小二乘法。

通常,拟合函数是自变量x和待定参数a_{1},a_{2}...a_{m}的函数,也就是f(x)=f(x,a_{1},a_{2},,,a_{m}),所以按照参数a_{1},a_{2}...a_{m}的线性与否,最小二乘法也分为线性最小二乘和非线性最小二乘。

 线性最小二乘

给定一个线性无关的函数系\begin{Bmatrix} \phi _{k}(x)=k=1,2,...,m \end{Bmatrix},如果拟合函数以其线性组合的形式

f(x)=\sum_{k=1}^{m}a_{k}\phi _{k}(x),例如f(x)=a_{1}x^{m-1}+a_{2}x^{m-2}+...+a_{m-1}x+a_{m},则f(x)就是关于参数a_{1},a_{2}...a_{m}的线性函数,然后将式子f(x)=\sum_{k=1}^{m}a_{k}\phi _{k}(x)代入残差公式\sum_{i=1}^{m}(f(x_{i})-y_{i}),然后我们对系数求偏导,最终形成一个关于a_{1},a_{2}...a_{m}的线性方程组,称为正规方程组。记

R=\begin{bmatrix} \phi _{1}(x_{1}) &\phi _{2}(x_{1}) &... &\phi _{m}(x_{1}) \\ \phi _{1}(x_{2}) & \phi _{2}(x_{2}) & ... &\phi _{m}(x_{2}) \\ ...&... & ... &... \\ \phi _{1}(x_{n})& \phi _{2}(x_{n}) &... & \phi _{m}(x_{n}) \end{bmatrix},A=\begin{bmatrix} a_{1}\\ a_{2}\\ ...\\ a_{m}\end{bmatrix},Y=\begin{bmatrix} y_{1}\\ y_{2}\\ ...\\ y_{n}\end{bmatrix},则正矩方程组可以表示为R^{T}RA=R^{T}Y,那么我们可以算出A=(R^{T}R)^{-1}R^{T}Y,未所求拟合函数的系数。

非线性最小二乘法

对于给定的线性无关函数系\begin{Bmatrix} \phi _{k}(x)=k=1,2,...,m \end{Bmatrix},如果拟合函数不能以线性组合的形式出现例如:f(x)=\frac{x}{a_{1}x+a_{2}},f(x)=a_{1}+a_{2}e^{-a_{3}x},将表达式代入残差平方和中,形成了一个非线性函数极小化问题,可以使用非线性优化问题解出参数值。

值得注意的是拟合函数的选择非常重要,如果能根据问题的机理分析出变量之间的函数关系,那么只需要估计出相应参数即可,但是大多我们无法分析出问题的函数关系,所以最好先做出数据的散点图然后选择使用什么样的拟合函数。

一般来说数据分布接近曲线,适宜选用线性函数f(x)=a_{1}x+a_{2}

例题1:

利用下面的数据,根据最小二乘法建立p和q的之间的检验Q=ap+b

p 0 1 2 3 4 5 6 7
q 27.0 26.8 26.5 26.3 26.1 25.7 25.3 24.8
import numpy as np
T=np.arange(8)
y=np.array([27.0,26.8,26.5,26.3,26.1,25.7,25.3,24.8])
p=np.vstack([T,np.ones(8)]).T
a=np.linalg.pinv(p)@y
print(a)

这里是将数据条件写成矩阵进行求解的,X\copyright A=Y所以有A=X^{-}Y,这里的函数np.linalg.pinv()是将非方阵矩阵求伪逆。np.vstack([T,np.ones(8)]).T指的是将函数垂直组合,.T的意义是将函数转置。

当我们拟合的函数形式为多项式时,我们可以使用polyfit函数进行拟合,调用格式为polyfit(x,y,n),拟合n次多项式,返回的系数从高次到低次幂。

以刚才的例题为例

import numpy as np
T=np.arange(8)
y=np.array([27.0,26.8,26.5,26.3,26.1,25.7,25.3,24.8])
a=np.polyfit(T,y,1)
print(a)

得到的结果和上面代码的结果几乎相同。

非线性拟合在python中一般我们使用scipy.optimize模块中的函数curve_fit,leastsq,least_squares等函数。这里我们介绍curve_fit()函数的用法。

调用格式为curve_fit(func,xdata,ydata),func为拟合的函数,xdata是自变量观测值,ydata是函数的观测值。会返回两个参数,第一个参数是拟合参数,第二个参数是数据的协方差矩阵。

例题,使用下面的数据拟合函数z=ae^{bx}+cy^{2},x=[6,2,6,7,4,2,5,9],y=[4,9,5,3,8,5,8,2],z=[5,2,1,9,7,4,3,3]

import numpy as np
from scipy.optimize import curve_fit
xy=np.array([[6,2,6,7,4,2,5,9],[4,9,5,3,8,5,8,2]])
z0=np.array([5,2,1,9,7,4,3,3])
z=lambda t,a,b,c: a*np.exp(b*t[0]) +c*t[1]**2
p,xov = curve_fit(z,xy,z0)
print(p)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340