Python小白的数学建模课-22.插值方法
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≤51 \leq k \leq 51≤k≤5,默認值為 3。
- s:實數,可選項,平滑參數:
- s=0,數據插值,樣條曲線必須通過所有數據點;
- s>0,數據擬合,滿足 ∑(w(y?spl(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 計算插值點的函數值 y1fSpl2 = UnivariateSpline(x, y) # 三次樣條插值,默認 s= len(w) y2 = fSpl2(xnew) # 由插值函數 fSpl2 計算插值點的函數值 y2fSpl2.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()程序運行結果:
結果分析:
- 參數 s=0 時,要求樣條函數通過所有數據點,即為數據插值;
- s>0 或不設置參數 s 時,不要求樣條函數通過所有數據點,就是用樣條函數擬合給定的數據。
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),zij=f(xi,yi)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改進模型
總結
以上是生活随笔為你收集整理的Python小白的数学建模课-22.插值方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab指令vpa(j10),mat
- 下一篇: python基础(16)之 日期