Python小白的數學建模課-22.插值方法
- 插值、擬合、回歸和預測,都是數學建模中經常提到的概念,也經常被混淆,
- 插值,是在離散資料的基礎上補插連續函式,使得插值函式通過全部給定的離散資料點,多用于影像處理和缺失資料處理,
- 使用 Scipy 工具包的 interpolate 插值模塊,通過例程講解一維插值、二維插值的實作方法,
- 『Python小白的數學建模課 @ Youcans』帶你從數模小白成為國賽達人,
1. 資料插值
1.1 插值與擬合
插值與擬合,不僅是基本的數學建模方法,也是最常用的資料處理方法,
不過,插值和擬合卻經常會被混為一談,所以我們首先看看這兩個概念,
- 插值,是在離散資料的基礎上補插連續函式,使得插值函式通過全部給定的離散資料點, 插值是離散函式逼近的重要方法,利用它可通過函式在有限個點處的取值狀況,估算出函式在其他點處的近似值,簡單地說,插值是求過一組已知點的近似函式,
- 擬合,是用一個連續函式(曲線)靠近給定的離散資料,使其與給定的資料相吻合,擬合也是根據一組已知點求近似函式,但不要求過已知點,
因此,插值和擬合都是根據一組已知資料點,求變化規律和特征相似的近似曲線的程序,但是插值要求近似曲線完全經過所有的給定資料點,而擬合只要求近似曲線在整體上盡可能接近資料點,并反映資料的變化規律和發展趨勢,
插值可以看作是一種特殊的擬合,是要求誤差函式為 0 的擬合,由于資料點通常都帶有誤差,誤差為 0 往往意味著過度擬合,過擬合模型對于訓練集以外的資料的泛化能力往往是較差的,因此在實踐中,插值多用于影像處理和缺失資料處理,擬合多用于實驗資料處理,
此外,還有一個常用而且容易混淆的概念: 回歸,回歸是研究一組隨機變數與另一組隨機變數之間關系的統計分析方法,包括建立數學模型并估計模型引數,并檢驗數學模型的可信度,也包括利用建立的模型和估計的模型引數進行預測或控制,
回歸是一種資料分析方法,擬合是一種具體的資料處理方法,擬合側重于曲線引數尋優,使曲線與資料相符;而回歸側重于研究兩個或多個變數之間的關系,
1.2 Scipy 插值工具箱
資料插值是資料處理的常用方法,常見的插值演算法有線性插值、B樣條插值、臨近插值等,
Scipy 工具包帶有插值工具箱,提供了豐富的插值方法和函式,可以用于一維、二維和多維插值,
一維函式插值的類 interp1d,提供了多種插值方法,如樣條函式插值、一維和多維插值、拉格朗日插值、泰勒多項式插值及自定義插值函式,函式 griddata 則提供了 N維插值的介面(N=1,2,3,…),
2. Scipy 一維插值方法:內插值
2.1 一維插值類 interp1d
Scipy.interpolate 中的 interp1d 類是一種基于固定資料點創建函式的方法,可以使用函式插值在給定資料定義的域內的任何位置對其進行計算,注意 interp1d 是內插法,不能外推運算(外插值),
該類定義呼叫,允許使用 x 軸值呼叫物件,此時應計算插值函式,并回傳插值的 y 軸值,具體地說,interp1d 類生成已知資料點集的插值函式 y=f(x),通過呼叫這個插值函式,可以在已知資料之間插值,得到指定 x 的函式值 f(x),
class scipy.interpolate.interp1d(x, y, kind=‘linear’, axis=- 1, copy=True, bounds_error=None, fill_value=nan, assume_sorted=False)
主要引數:
- x:一維陣列,給定資料點集的 x 值,
- y:N 維陣列,給定資料點集的 y 值,陣列長度必須與 x 相等,
- kind:字串或整數,可選項,指定使用的樣條曲線的種類或插值方法,
- 可選的字串:‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘previous’, ‘next’;
- ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’ 分別表示零次、一次、二次、三次樣條插值;
- ‘previous’, ‘next’ 分別表示只前點插值或后點插值;
- ‘nearest’ 表示向下舍入, ‘nearest-up’ 表示向上舍入;
- 默認值為 ‘linear’,即線性插值,
interp1d 允許通過引數 bounds_error、fill_value 設定外推時的邊界值,但這并不是進行外推插值,
回傳值:
- 類 interp1d() 回傳一個函式,其呼叫方法使用插值來查找新點的值,
2.2 Python 例程:interp1d 的使用
使用示例:
# 1. 一維插值使用示例
import numpy as np
import matplotlib.pyplot as plt # 匯入 Matplotlib 工具包
from scipy.interpolate import interp1d # 匯入 scipy 中的一維插值工具 interp1d
# 已知資料點集 (x,y)
x = [0.0, 2.0, 4.0, 6.0, 8.0, 10.0] # 已知資料 x
y = [3.1, 2.7, 1.5, 0.1, 1.0, 3.9] # 已知資料 y
# 由給定資料點集 (x,y) 求插值函式 fx
fx = interp1d(x, y, kind='linear') # 由已知資料 (x,y) 求出插值函式 fx
# 由插值函式 fx 計算插值點的函式值
xInterp = np.linspace(0,10,100) # 指定需插值的資料點集 xInterp
yInterp = fx(xInterp) # 呼叫插值函式 fx,計算 xInterp 的函式值
# 繪圖
plt.plot(xInterp, yInterp, label="linear interpolate")
plt.show()
2.3 Python 例程:一維插值方法比較
通過設定 interp1d 類的引數kind,可以指定使用的樣條曲線的種類或插值方法,
上節中介紹了 kind 各種選項所指的插值方法,本節進一步通過例程來比較不同方法的插值結果,
Python 例程:
# mathmodel24_v1.py
# Demo24 of mathematical modLSing algorithm
# Demo of interpolate with Scipy.interpolate
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-01
# 2. 一維插值方法(內插)比較
import numpy as np
import matplotlib.pyplot as plt # 匯入 Matplotlib 工具包
from scipy.interpolate import interp1d # 匯入 scipy 中的一維插值工具 interp1d
# 生成已知資料點集 (x,y),需插值的資料點集 xnew
np.random.seed(5)
x = np.linspace(0, 5, 10) # 生成已知資料點集的 x
y = np.cos(x/10)*2 + 0.5*np.random.rand(10) # 生成已知資料點集的 y
xnew = np.linspace(0, 5, 100) # 指定需插值的資料點集 xnew
# 使用不同插值方法,由給定資料點集 (x,y) 求插值函式 fx
f1 = interp1d(x, y, kind="linear") # 線性插值
f2 = interp1d(x, y, kind="zero") # 零階樣條插值
f3 = interp1d(x, y, kind="slinear") # 一次樣條插值
f4 = interp1d(x, y, kind="quadratic") # 二次樣條插值
f5 = interp1d(x, y, kind="cubic") # 三次樣條插值
f6 = interp1d(x, y, kind="nearest") # 臨近點插值,向下舍入
# f7 = interp1d(x, y, kind="nearest-up") # 臨近點插值,向上舍入
f8 = interp1d(x, y, kind="previous") # 前點插值
f9 = interp1d(x, y, kind="next") # 后點插值
# 繪圖
plt.figure(figsize=(8,6))
plt.suptitle("Data interpolate") # 全域標題
plt.subplot(221)
plt.plot(x, y, "o", label="data") # 已知資料點
plt.plot(xnew, f2(xnew), label="0-order spline") # 零階樣條插值
plt.plot(xnew, f3(xnew), label="1-order spline") # 一階樣條插值
plt.legend(loc="lower left")
plt.subplot(222)
plt.plot(x, y, "o", label="data") # 已知資料點
plt.plot(xnew, f4(xnew), label="2-order spline") # 二階樣條插值
plt.plot(xnew, f5(xnew), label="3-order spline") # 三階樣條插值
plt.legend(loc="lower left")
plt.subplot(223)
plt.plot(x, y, "o", label="data") # 已知資料點
plt.plot(xnew, f1(xnew), label="linear") # 線性插值
plt.plot(xnew, f6(xnew), label="nearest") # 臨近點插值,向下舍入
# plt.plot(xnew, f7(xnew), label="nearest-up") # 臨近點插值,向上舍入
plt.legend(loc="lower left")
plt.subplot(224)
plt.plot(x, y, "o", label="data") # 已知資料點
plt.plot(xnew, f8(xnew), label="previous") # 前點插值
plt.plot(xnew, f9(xnew), label="next") # 后點插值
plt.legend(loc="lower left")
plt.show()
程式運行結果:

結果分析:
-
線性插值是常用的插值方法,簡單地說可以理解為將相鄰的資料點用線段連接,演算法簡單、運算速度快,一階樣條曲線插值,等效于線性插值,
-
最近鄰點插值、前點插值、后點插值和 0階樣條插值的結果都是階梯形狀曲線,只是選點方法不同,
-
樣條插值是重要的插值方法,用光滑曲線連接資料點,每一個樣條都是用一個多項式表達的,多項式的次數就是樣條曲線的階數,決定了樣條曲線的形狀和性質:
- 0 階樣條曲線,在每一區間上樣條函式為常數,樣條曲線呈階梯形狀;
- 1 階樣條曲線,在每一區間上樣條函式為線性函式,樣條曲線呈折線段形狀;
- 2 階樣條曲線,在每一區間上樣條函式為二次函式,整體一階連續可導;依次類推,
- 由二階開始,插值函式不再具有局域性,改變某一節點,函式整體都會改變,
- 2 階和 3階樣條插值最為常用,更高階的樣條插值過于復雜,通常結果的差異并不大,圖中的 2階和 3階樣條插值結果就已經近似是重合的,
3. Scipy 一維插值方法:外插值
3.1 一維插值類 UnivariateSpline
Scipy.interpolate 中的 UnivariateSpline 類是一種基于固定資料點創建函式的方法,使用一維樣條曲線擬合到給定的資料點集,
該類定義呼叫,允許使用 x 軸值呼叫物件,此時應計算樣條曲線,并回傳插值的 y 軸值,具體地說,UnivariateSpline 類生成已知資料點集的樣條插值函式 y=spl(x),通過呼叫樣條插值函式,可以計算指定 x 的函式值 f(x),
class scipy.interpolate.UnivariateSpline(x, y, w=None, bbox=[None, None], k=3, s=None, ext=0, check_finite=False)
主要引數:
- x:一維陣列,數值必須遞增,
- y:一維陣列,陣列長度必須與 x 相等,
- w:一維陣列,正數,可選項,每個資料點的權重,默認所有點的權重相等,
- k:整數,可選項,樣條函式的階數, 1 ≤ k ≤ 5 1 \leq k \leq 5 1≤k≤5,默認值為 3,
- s:實數,可選項,平滑引數:
- s=0,資料插值,樣條曲線必須通過所有資料點;
- s>0,資料擬合,滿足 ∑ ( w ( y ? s p l ( x ) ) ) 2 ≤ s \sum(w(y-spl(x)))^2 \leq s ∑(w(y?spl(x)))2≤s;
- 默認不設定 s,則 s=len(w),
- ext:整數或字串,可選項,用于控制外推插值的方案:
- ext= 0 或 “extrapolate”,回傳外推值,默認值;
- ext= 1 或 “zeros”,回傳 0;
- ext= 2 或 “raise”,拋出例外值 ValueError;
- ext= 3 或 “const”,回傳邊界值,
回傳值:
- 類 UnivariateSpline() 回傳一個函式,其呼叫方法使用插值來查找新點的值,
UnivariateSpline 可以外插值,允許通過設定引數 ext= 0 或 “extrapolate” 外推插值,但如果外推范圍過大,
3.2 Python 例程:一維插值(UnivariateSpline)
Python 例程:
# 3. 一維插值方法(外插)
import numpy as np
import matplotlib.pyplot as plt # 匯入 Matplotlib 工具包
from scipy.interpolate import UnivariateSpline # 匯入 scipy 中的一維插值工具 UnivariateSpline
# 生成已知資料點集 (x,y),需插值的資料點集 xnew
x = np.linspace(0, 10, 11) # 生成已知資料點集的 x
y = np.cos((x)**2/30)*2+2 # 生成已知資料點集的 y
xnew = np.linspace(-0.5, 10.5, 110) # 指定需插值的資料點集 xnew
# 使用 UnivariateSpline 插值工具,由給定資料點集 (x,y) 求插值函式 fSpl
fSpl1 = UnivariateSpline(x, y, s=0) # 三次樣條插值,s=0:插值函式經過所有資料點
y1 = fSpl1(xnew) # 由插值函式 fSpl1 計算插值點的函式值 y1
fSpl2 = UnivariateSpline(x, y) # 三次樣條插值,默認 s= len(w)
y2 = fSpl2(xnew) # 由插值函式 fSpl2 計算插值點的函式值 y2
fSpl2.set_smoothing_factor(0.1) # 設定光滑因子 sf
y3 = fSpl2(xnew) # 由插值函式 fSpl2(sf=0.1) 計算插值點的函式值 y3
# 繪圖
fig, ax = plt.subplots(figsize=(8,6))
plt.plot(x, y, 'ro', ms=5, label="data")
plt.plot(xnew, y1, 'm', label="3rd spline interpolate")
plt.plot(xnew, y2, 'g', label="3rd spline fitting")
plt.plot(xnew, y3, 'b--', label="smoothing factor")
ax.set_title("Data interpolate with extrapolation")
plt.legend(loc="best")
plt.show()
程式運行結果:

結果分析:
- 類 UnivariateSpline 既可以進行資料插值,也可以進行資料擬合,
- 引數 s=0 時,要求樣條函式通過所有資料點,即為資料插值;
- s>0 或不設定引數 s 時,不要求樣條函式通過所有資料點,就是用樣條函式擬合給定的資料,
- 類 UnivariateSpline 進行資料插值或資料擬合,具有一定的外推能力,可以由插值函式進行外推計算,但插值演算法的外推范圍十分有限,容易發散或失真,使用時要非常謹慎,
- 圖中綠色曲線是三次樣條資料擬合的結果,藍色曲線對擬合曲線作了進一步的平滑處理,
4. Scipy 二維插值方法
4.1 二維插值類 interp2d
Scipy.interpolate 中的 interp2d 類是一種基于固定資料點集創建函式的二維插值方法,經常用于二維影像處理,
類 interp2d 的定義和使用方法與一維插值 interp1d 類似,該類定義呼叫,允許使用 (x,y) 值呼叫物件,此時計算插值函式,并回傳插值的 z軸值,具體地說,interp2d 類生成已知資料點集的插值函式 z=f(x,y),通過呼叫這個插值函式,可以在已知資料之間插值,得到指定 (x,y) 的函式值 f(x,y),
class scipy.interpolate.interp2d(x,y,z,kind=‘linear’,copy=True,bounds_error=False,fill_value=None))
主要引數:
- x,y:一維陣列,給定資料點集的 x,y 值,
- z:一維陣列,給定資料點集對應的函式值 z,
- kind:字串或整數,可選項,指定使用的樣條曲線的種類或插值方法:‘linear’ 表示線性插值,‘cubic’ 表示三次插值,‘quintic’ 表示五次插值,默認值為 ‘linear’,即線性插值,
回傳值:
- 類 interp2d() 回傳一個函式,其呼叫方法使用插值來查找新點的值,
注意:給定資料點集 x,y,z 有兩種方式:
-
以一維陣列 x 和 y 定義給定網路點集的列坐標和行坐標序列,一維陣列 x 與 y 的長度 len(x)、len(y) 不一定相等,二維陣列 z 的形狀為 len(x)*len(y), z i j = f ( x i , y i ) z_{ij}=f(x_i,y_i) zij?=f(xi?,yi?) 是資料網格點 (xi,yj) 的函式值,
-
以一維陣列 x, y 定義給定網路點集的列坐標和行坐標序列,網路點集中每個點的坐標分別由二維陣列 xx 和 yy 表示, 二維陣列 z 是與 (xx,yy) 對應的網格中每一個資料點的函式值,$z_{ij} = f(xx_{ij}, yy_{ij}) $,
4.2 Python 例程:二維插值(interp2d)
使用示例:
# mathmodel24_v1.py
# Demo24 of mathematical modLSing algorithm
# Demo of interpolate with Scipy.interpolate
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-01
# 4. 二維插值方法
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp2d # 匯入 scipy 中的二維插值工具 interp2d
# 生成已知資料網格點集 (xx,yy,z)
x = np.linspace(-1, 1.5, 25) # x 是一維陣列
y = np.linspace(-1, 1, 20) # y 是一維陣列
xx, yy = np.meshgrid(x, y) # 生成網格點的坐標 xx,yy (二維陣列)
z = np.sin((xx+yy+xx**2+yy**2)) # 計算資料網格點的值 z=f(xx,yy)
print("shape of original dataset:\n\txx:{},yy:{},z:{}".format(xx.shape,yy.shape,z.shape))
# 由給定資料網格點集 (xx,yy,z) 求插值函式 fInterp: xx,yy,z 都是形狀相同的二維陣列
fInterp = interp2d(xx, yy, z, kind='cubic') # 三階樣條插值
# 由插值函式 fInterp 計算需插值的資料點的函式值
xnew = np.linspace(-1, 1.5, 150) # xnew 是一維陣列
ynew = np.linspace(-1, 1, 100) # ynew 是一維陣列
znew = fInterp(xnew, ynew) # 計算插值函式 fInterp 在 (xnew, ynew) 所描述網格點集的函式值
print("shape of interpolation dataset:\n\txnew:{},ynew:{},znew:{}".format(xnew.shape,ynew.shape,znew.shape))
# 繪圖
fig = plt.figure(figsize=(10, 6))
ax1 = plt.subplot(1, 2, 1, projection='3d')
ax1.set_title("2-D original data")
# ax1.plot_wireframe(xx, yy, z, rstride=2, cstride=2, linewidth=1)
surf = ax1.plot_surface(xx, yy, z, rstride=2, cstride=2, cmap=plt.cm.coolwarm)
ax1.set_zlabel('zData')
xxnew, yynew = np.meshgrid(xnew, ynew) # 將一維陣列 xnew, ynew 轉換為網格點集(二維陣列)
print("\txxnew:{},yynew:{},znew:{}".format(xxnew.shape,yynew.shape,znew.shape))
ax2 = plt.subplot(1, 2, 2, projection='3d') # 3D 繪圖要求 x,y,z 都是 n*m 二維陣列
ax2.set_title("2-D interpolation data")
ax2.plot_wireframe(xxnew, yynew, znew, rstride=2, cstride=2,linewidth=1)
surf2 = ax2.plot_surface(xxnew, yynew, znew, rstride=2, cstride=2, cmap=plt.cm.coolwarm)
ax2.set_zlabel('zInterp')
plt.show()
運行結果:
shape of original dataset:
xx:(20, 25),yy:(20, 25),z:(20, 25)
shape of interpolation dataset:
xnew:(150,),ynew:(100,),znew:(100, 150)
xxnew:(100, 150),yynew:(100, 150),znew:(100, 150)
注意:
由給定資料點集 (xx,yy,z) 求插值函式 fInterp 時 xx,yy,z 都是形狀相同的二維陣列(矩陣),由插值函式 fInterp 計算插值時所使用的 xnew,ynew 是一維陣列,插值函式 fInterp 在 (xnew, ynew) 所構造的柵格點計算并回傳插值函式值,回傳值 z 是二維陣列(矩陣),

4.3 Python 例程:二維插值
通過設定 interp1d 類的引數kind,可以指定使用的樣條曲線的種類或插值方法,
上節中介紹了 kind 各種選項所指的插值方法,本節進一步通過例程來比較不同方法的插值結果,
Python 例程:
# mathmodel24_v1.py
# Demo24 of mathematical modLSing algorithm
# Demo of interpolate with Scipy.interpolate
# Copyright 2021 YouCans, XUPT
# Crated:2021-08-01
# 5. 二維插值方法
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp2d # 匯入 scipy 中的二維插值工具 interp2d
# 生成已知資料網格點集 (xx,yy,z)
yy, xx = np.mgrid[-2:2:20j,-3:3:30j] # 生成網格點 30x20 = 600
z = (1-0.5*xx+xx**5+yy**3) * np.exp(-xx**2-2*yy**2) # 計算網格點的值 z
x, y = xx[0,:], yy[:,0] # 由資料網格點 xx,yy 轉換一維陣列 x, y
print("shape of original dataset:\n\txx:{},yy:{},z:{}".format(xx.shape,yy.shape,z.shape))
print("\tx:{},y:{},z:{}".format(x.shape, y.shape, z.shape))
# 由給定資料點集 (x,y,z) 求插值函式 fInterp: x,y 是一維陣列,z 是 len(x)*len(y) 二維陣列
f1 = interp2d(x, y, z, kind='linear') # 線性插值
f2 = interp2d(x, y, z, kind='cubic') # 三階樣條插值
f3 = interp2d(x, y, z, kind='quintic') # 五階樣條插值
# 由插值函式 fInterp 計算需插值的網格點集 ynew,xnew 的函式值
xnew = np.linspace(-3, 3, 120) # xnew 是一維陣列
ynew = np.linspace(-2, 2, 80) # ynew 是一維陣列
z1 = f1(xnew, ynew) # 根據線性插值函式 f1 計算需插值的網格點集的函式值
z2 = f2(xnew, ynew) # 根據三階樣條插值函式 f2 計算需插值的網格點集的函式值
z3 = f3(xnew, ynew) # 根據五階樣條插值函式 f3 計算需插值的網格點集的函式值
print("shape of interpolation dataset:\n\txnew:{},ynew:{},znew:{}".format(xnew.shape,ynew.shape,z1.shape))
# 繪圖
plt.figure(figsize=(8,6))
plt.suptitle("2-D data interpolate") # 全域標題
plt.subplot(221)
plt.pcolor(xx, yy, z, cmap=plt.cm.hsv, shading='auto')
plt.title("original")
plt.colorbar()
plt.subplot(222)
plt.pcolor(xnew, ynew, z1, cmap=plt.cm.hsv, shading='auto')
plt.title("linear")
plt.colorbar()
plt.subplot(223)
plt.pcolor(xnew, ynew, z2, cmap=plt.cm.hsv, shading='auto')
plt.title("cubic")
plt.colorbar()
plt.subplot(224)
plt.pcolor(xnew, ynew, z3, cmap=plt.cm.hsv, shading='auto')
plt.title("quintic")
plt.colorbar()
plt.show()
程式運行結果:

【本節完】
著作權宣告:
歡迎關注『Python小白的數學建模課 @ Youcans』 原創作品
原創作品,轉載必須標注原文鏈接:(https://blog.csdn.net/youcans/article/details/119139374),
Copyright 2021 Youcans, XUPT
Crated:2021-08-01
歡迎關注 『Python小白的數學建模課 @ Youcans』 系列,持續更新
Python小白的數學建模課-01.新手必讀
Python小白的數學建模課-02.資料匯入
Python小白的數學建模課-03.線性規劃
Python小白的數學建模課-04.整數規劃
Python小白的數學建模課-05.0-1規劃
Python小白的數學建模課-06.固定費用問題
Python小白的數學建模課-07.選址問題
Python小白的數學建模課-09.微分方程模型
Python小白的數學建模課-10.微分方程邊值問題
Python小白的數學建模課-12.非線性規劃
Python小白的數學建模課-15.圖論的基本概念
Python小白的數學建模課-16.最短路徑演算法
Python小白的數學建模課-17.條件最短路徑演算法
Python小白的數學建模課-18.最小生成樹問題
Python小白的數學建模課-19.網路流優化問題
Python小白的數學建模課-20.網路流優化案例
Python小白的數學建模課-21.關鍵路徑法
Python小白的數學建模課-A1.國賽賽題型別分析
Python小白的數學建模課-21.關鍵路徑法
Python小白的數學建模課-22.插值方法
Python小白的數學建模課-A2.2021年數維杯C題探討
Python小白的數學建模課-A3.12個新冠疫情數模競賽賽題及短評
Python小白的數學建模課-B2. 新冠疫情 SI模型
Python小白的數學建模課-B3. 新冠疫情 SIS模型
Python小白的數學建模課-B4. 新冠疫情 SIR模型
Python小白的數學建模課-B5. 新冠疫情 SEIR模型
Python小白的數學建模課-B6. 新冠疫情 SEIR改進模型
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/291655.html
標籤:python
