数学建模——插值与拟合

文章目录

  • 一.插值和拟合
    • 1.什么是插值与拟合?
    • 2.常用一维插值方法
      • (1)分段线性插值
      • (2)样条插值
    • 3.常用二维插值方法
      • (1)插值节点为网格数据
      • (2)插值节点为非网格数据
    • 4.拟合
  • 二.插值函数
    • 1.interp1d函数
    • 2.interp2d函数
    • 3.griddata函数
  • 三.拟合函数
    • 1.polyfit函数
    • 2.curve_fit函数
  • 四.绘图函数
    • 1.contour函数
    • 2.plot_surface函数

一.插值和拟合

1.什么是插值与拟合?

 插值和拟合是通过样本数据构造出一个函数。如果要求构造出的函数图像过所有的样本点那就是插值,反之就是拟合。

2.常用一维插值方法

(1)分段线性插值

 分段线性插值就是先把样本分为n段,求一个分段的一次多项式P(x)是得其在各个分段上满足: P i ( x ) = y i , i = 0 , 1... , n P_{i}(x)=y_{i} ,i=0,1...,n Pi(x)=yi,i=0,1...,n

(2)样条插值

 样条插值是将样本分为n段即设置(n+1)个分点。设分点为 x i , i = 0 , 1 , . . . , n x_{i},i=0,1,...,n xi,i=0,1,...,n.有函数 S ( x ) S(x) S(x)满足 S i ( x ) S_{i}(x) Si(x):
(1)在区间 [ x i , x i + 1 ] [x_{i},x_{i+1}] [xi,xi+1]上是 m m m次多项式
(2)在区间 [ x 0 , x n ] [x_{0},x_{n}] [x0,xn]上有 m − 1 m-1 m1阶连续导数
则称 S ( x ) S(x) S(x)为关于这个划分的 m m m次样条函数, m m m次样条函数的曲线称为样条曲线。
 可见分段线性插值实际上一次样条插值。
 在Python中一维插值可用scipy.interpolate模块的interp1d函数来实现。

3.常用二维插值方法

(1)插值节点为网格数据

 插值节点为网格数据时,一般用双三次样条插值。在Pyhon中可以用scipy.interpolate模块的interp2d函数实现。
数学建模——插值与拟合_第1张图片

这就是网格插值节点
在这里插入图片描述
这是非网格插值节点(如果写成上表形式则只表格的对角线上有z的数据)

(2)插值节点为非网格数据

 使用scipy.interpolate模块的griddata函数解决。

4.拟合

 在数学上拟合曲线常用的方法最小二乘拟合。Python中有据此原理设计的拟合函数,如scipy.optimize模块的curve_fit函数用的是非线性最小二乘拟合。以及numpy的polyfit多项式最小二乘拟合。
 不同于得到插值函数,拟合前要先猜测拟合函数。猜测最好依据已有数据的散点图进行。有一下原则选择合适的拟合函数:

数据趋势 选用函数
趋于直线 f ( x ) = a 1 x + a 2 f(x)=a_{1}x+a_{2} f(x)=a1x+a2
趋于抛物线 f ( x ) = a 1 x 2 + a 2 x + a 3 f(x)=a_{1}x^{2}+a_{2}x+a_{3} f(x)=a1x2+a2x+a3
开始上升快然后上升缓慢 f ( x ) = a 1 e − a 2 x f(x)=a_{1}e^{\frac{-a_{2}}{x}} f(x)=a1exa2 f ( x ) = x a 1 x + a 2 f(x)=\frac{x}{a_{1}x+a_{2}} f(x)=a1x+a2x
开始下降快然后下降缓慢 f ( x ) = a 1 e − a 2 x f(x)=a_{1}e^{-a_{2}x} f(x)=a1ea2x f ( x ) = 1 a 1 x + a 2 f(x)=\frac{1}{a_{1}x+a_{2}} f(x)=a1x+a21 f ( x ) = 1 a 1 x 2 + a 2 f(x)=\frac{1}{a_{1}x^{2}+a_{2}} f(x)=a1x2+a21

二.插值函数

1.interp1d函数

1.语法:scipy.interpolate.interp1d(x, y, kind='linear', axis=- 1, copy=True, bounds_error=None, fill_value=nan, assume_sorted=False)
2.功能:插值一维函数
3.常用参数:
(1)x:表示插值节点的实值向量
(2)y:N维实值数组,插值方向长度等于x的长度
(3)kind:插值方法选择。linear(分段线性插值),nearest(最近邻插值),slinear(一次样条),quadratic(二次样条),cubic(三次样条)
(4)axis:指定插值方向,默认是最后一轴向。即若y是二维数组,那么插值方向是横向(axis==1)
4.返回值:返回插值函数f(x)

示例
根据如下样本数据得到插值函数并绘制
在这里插入图片描述

import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import interp1d
# 插值节点
x=np.arange(0,25,2)
# 插值节点对应的值
y=np.array([12,9,9,10,18,24,28,27,25,20,18,15,13])
# 插值点
x_new=np.linspace(0,24,500)
# 插值函数,第一个用分段线性插值,第二个用三次样条插值
f1=interp1d(x,y)
f2=interp1d(x,y,kind='cubic')
# 绘制
ax1=plt.subplot(1,2,1)
ax1.plot(x_new,f1(x_new))
ax2=plt.subplot(1,2,2)
ax2.plot(x_new,f2(x_new))

数学建模——插值与拟合_第2张图片

2.interp2d函数

1.语法:scipy.interpolate.interp2d(x, y, z, kind='linear', copy=True, bounds_error=False, fill_value=None)
2.功能:在二维网格上插值
3.常用参数:
(1)x和y:样本点坐标x方向和y方向的向量,如果x和y是多维的,那么它们会自动被flatten后再使用
(2)z:插值点值的数组,使用前会被压缩为一维
(3)kind:插值方法选择。默认是分段线性插值l(inear),可选三次样条(cubic)或五次样条插值(quintic)
4.返回值:返回插值函数f(x,y)

示例
根据如下高程数据计算地域表面积近似值,求得插值函数并绘制区域等高线和三维表面图。
数学建模——插值与拟合_第3张图片

import matplotlib.pyplot as plt
import numpy as np
from numpy.linalg import norm #norm函数的作用是求矩阵范数
from scipy.interpolate import interp2d
import warnings
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname=r"C:\Windows\Fonts\Dengb.ttf")
warnings.filterwarnings('ignore')
# 插值节点对应的值
z=np.array([[1350,1370,1390,1400,1410,960,940,880,800,690,570,430,290,210,150],
          [1370,1390,1410,1430,1440,1140,1110,1050,950,820,690,540,380,300,210],
          [1380,1410,1430,1450,1470,1320,1280,1200,1080,940,780,620,460,370,350],
          [1420,1430,1450,1480,1500,1550,1510,1430,1300,1200,980,850,750,550,500],
          [1430,1450,1460,1500,1550,1600,1550,1600,1600,1600,1550,1500,1500,1550,1550],
          [950,1190,1370,1500,1200,1100,1550,1600,1550,1380,1070,900,1050,1150,1200],
          [910,1090,1270,1500,1200,1100,1350,1450,1200,1150,1010,880,1000,1050,1100],
          [880,1060,1230,1390,1500,1500,1400,900,1100,1060,950,870,900,936,950],
            [830,980,1180,1320,1450,1420,400,1300,700,900,850,810,380,780,750],
          [740,880,1080,1130,1250,1280,1230,1040,900,500,700,780,750,650,550],
          [650,760,880,970,1020,1050,1020,830,800,700,300,500,550,480,350],
          [510,620,730,800,850,870,850,780,720,650,500,200,300,350,320],
          [370,470,550,600,670,690,670,620,580,450,400,300,100,150,250]])
# 插值节点
x=np.arange(0,1500,100)
y=np.arange(1200,-100,-100)
#使用双三次样条插值得到插值函数f
f=interp2d(x,y,z,kind='cubic')


# 设分点xi=10i (i=0,1...140),yi=10j (j=0,1,...,120)平面被这分点分为140*120个小矩形
xi=np.linspace(0,1400,141)
yj=np.linspace(1200,0,120)
# 小矩形顶点的插值
zn=f(xi,yj)
# 面积的求法;小块矩形对应曲面面积可以近似为空间中的一个四边形求解。这个四边形的面积又可以看做两个三角形的面积和
# 三角形面积考虑用海伦公式求解:p=(a+b+c)/2   s=sqrt(p*(p-a)*(p-b)*(p-c))
s=0
for i in range(len(xi)-1):
    for j in range(len(yj)-1):
        p1=np.array([xi[i],yj[j],f(xi[i],yj[j])])
        p2=np.array([xi[i],yj[j+1],f(xi[i],yj[j+1])])
        p3=np.array([xi[i+1],yj[j],f(xi[i+1],yj[j])])
        p4=np.array([xi[i+1],yj[j+1],f(xi[i+1],yj[j])])
        a1,b1,c1=norm(p1-p2),norm(p1-p3),norm(p2-p3);p_1=(a1+b1+c1)/2;s1=np.sqrt(p_1*(p_1-a1)*(p_1-b1)*(p_1-c1))
        a2,b2,c2=norm(p4-p2),norm(p4-p3),norm(p3-p2);p_2=(a2+b2+c2)/2;s2=np.sqrt(p_2*(p_2-a2)*(p_2-b2)*(p_2-c2))
        s+=(s1+s2)
print('区域面积{}立方米'.format(s[0]))


# 用plt.contour 绘制contour line(等高线)
ax1=plt.subplot(1,2,1)
cont1=ax1.contour(xi,yj,zn)
# 使用plt.clabel函数给等高线添加标签
ax1.clabel(cont1)
plt.title('contour line')
# 三维曲面图,子图投影类型设置为3d。默认2d
ax2=plt.subplot(1,2,2,projection='3d')
X,Y=np.meshgrid(xi,yj)
ax2.plot_surface(X,Y,zn,cmap='viridis')
ax2.set_title('surface')
# 全图标题
plt.suptitle('Interpolate')

数学建模——插值与拟合_第4张图片
区域面积:4880683.019677971立方米

3.griddata函数

1.语法:scipy.interpolate.griddata(points, values, xi, method='linear', fill_value=nan, rescale=False)
2.功能:做非网格插值节点数据的插值
3.常用参数:
(1)points:一般传递数据点坐标向量的元组比较方便。如x是插值节点x方向的值向量,y是插值节点y方向值的向量。于是传递 (x,y)
(2)values:是插值点对应的值得浮点数或复数的向量
(3)xi:这个参数是插值点。通过np.meshgrid函数处理x,y方向插值点向量后获得网格矩阵再作为一个元组传递给xi比较方便
(4)kind:插值方法。可选nearest,linear,cubic
4.返回值:直接返回插值点xi对应的插值数组

示例
根据海域水深数据绘制海底地形图和等高线图
在这里插入图片描述

import  numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
# 插值节点向量数据
x=np.array([129,140,103.5,88,185.5,195,105,157.5,107.5,77,81,162,162,117.5])
y=np.array([7.5,141.5,23,147,22.5,137.5,85.5,-6.5,-81,3,56.5,-66.5,84,-33.5])
z=-np.array([4,8,6,8,6,8,8,9,9,8,8,9,4,9])
# 插值点x方向和y方向向量
xn=np.linspace(x.min(),x.max(),100)
yn=np.linspace(y.min(),y.max(),100)
# 使用向量xn和yn构造网格节点
xng,yng=np.meshgrid(xn,yn)
# 用griddata 函数根据非结构化数据来在网格节点处插值
zn1=griddata((x,y),z,(xng,yng),method='nearest') # 最近邻插值
# 绘制三维图像
ax1=plt.subplot(131,projection='3d')
ax2=plt.subplot(133)
ax1.plot_surface(xng,yng,zn1,cmap='viridis')
contour=ax2.contour(xng,yng,zn1)
plt.clabel(contour)

数学建模——插值与拟合_第5张图片

三.拟合函数

1.polyfit函数

1.语法:numpy.polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False)
2.功能:最小二乘多项式拟合,貌似只能做一维的拟合
3.常用参数:
(1)x:样本点x坐标向量
(2)y:样本点y坐标向量或是一个二维数组,每一列表示样本的y坐标向量,这些列共用x坐标向量
(3)deg:多项式次数
4.返回值:多项式的系数向量或多项式的系数向量作为列的二维数组

示例
根据样本数据得到多项式拟合曲线并得到 x = 0.25 和 0.35 x=0.25和0.35 x=0.250.35时的值
在这里插入图片描述

import numpy as np
import matplotlib.pyplot as plt
# 样本数据
x0=np.arange(0,1.1,0.1)
y0=np.array([-0.447,1.978,3.28,6.16,7.08,7.34,7.66,9.56,9.48,9.30,11.2])
# 使用ployfit函数拟合得到二次多项式的系数
p=np.polyfit(x0,y0,2)
# 使用polyval函数将指定值带入多项式计算
yhat=np.polyval(p,np.array([0.25,0.35]))
print('x=0.25的预测值{:.2}  x=0.35的预测值{:.2}'.format(yhat[0],yhat[1]))
# 绘制拟合函数的曲线
plt.plot(x0,y0,'^')
plt.plot(x0,np.polyval(p,x0),'-')

数学建模——插值与拟合_第6张图片
在这里插入图片描述

2.curve_fit函数

1.语法:scipy.optimize.curve_fit(f, xdata, ydata, p0=None, sigma=None, absolute_sigma=False, check_finite=True, bounds=(- inf, inf), method=None, jac=None, *, full_output=False, **kwargs)
2.功能:使用非线性最小二乘的方法取拟合一个函数f
3.常用参数:
(1)f:可调用的函数f(x,...)。他必须把独立的变量作为f的第一个参数,函数模型中的参数分别作为f的其余参数。x可以视为标量或向量,于是我们可以定义多维函数
(2)xdata:样本点,如果f是一维函数那么xdata就是向量;如果f是k维函数,x就是shape[0]==k的数组。比如我的样本点是(x,y,z),那么我的xdata就可以写为np.vstack((x,y))
(3)ydata:样本点对应的函数值向量
4.返回值:
(1)popt:Optimal values for the parameters so that the sum of the squared residuals of f(xdata, *popt) - ydata is minimized.
(2)pcov:The estimated covariance of popt.

示例
根据样本点拟合函数 z = a e b x + c y 2 z=ae^{bx}+cy^{2} z=aebx+cy2
在这里插入图片描述

from scipy.optimize import curve_fit
import numpy as np
# 样本点数据
x0=np.array([6,2,6,7,4,2,5,9])
y0=np.array([4,9,5,3,8,5,8,2])
z0=np.array([5,2,1,9,7,4,3,3])
# 拟合函数模型 
def fun(var,a,b,c):
    return a*np.exp(b*var[0])+c*var[1]**2
# 拟合曲线
popt,pcov=curve_fit(fun,np.vstack((x0,y0)),z0)
print("拟合得到函数模型的参数为:{}".format(popt))

在这里插入图片描述

四.绘图函数

1.contour函数

1.语法:matplotlib.pyplot.contour(*args, data=None, **kwargs)
2.功能:绘制contour line(等高线)
3.常用参数:
(1)x:x方向值的向量,满足len(x)==z.shape[0]
(2)y:y方向值得向量,满足len(y)==z.shape[1]
(3)z:等高线的高度值,是一个二维数组
(4)cmap:颜色映射可有cmap控制,可选见https://matplotlib.org/2.0.2/users/colormaps.html
(5)alpha:不透明度,0~1之间

2.plot_surface函数

1.语法:plot_surface(X, Y, Z, *, norm=None, vmin=None, vmax=None, lightsource=None, **kwargs)
2.功能:绘制三维表面
3.常用参数:
(1)X,Y,Z:样本点的二维数组。通过np.meshgrid函数可以把x向量和y向量化为二维数组X,Y
(2)cmap
(3)color

你可能感兴趣的:(数学建模,学习)