1. 程式人生 > >插值方法收集

插值方法收集

一維插值

插值不同於擬合。插值函式經過樣本點,擬合函式一般基於最小二乘法儘量靠近所有樣本點穿過。常見插值方法有拉格朗日插值法、分段插值法、樣條插值法。

拉格朗日插值多項式:當節點數 n 較大時,拉格朗日插值多項式的次數較高,可能出現不一致的收斂情況,而且計算複雜。隨著樣點增加,高次插值會帶來誤差的震動現象稱為龍格現象。

分段插值:雖然收斂,但光滑性較差。

樣條插值:樣條插值是使用一種名為樣條的特殊分段多項式進行插值的形式。由於樣條插值可以使用低階多項式樣條實現較小的插值誤差,這樣就避免了使用高階多項式所出現的龍格現象,所以樣條插值得到了流行

#!/usr/bin/env python
# -*-coding:utf-8 -*-
import numpy as np
from scipy import interpolate
import pylab as pl
 
x=np.linspace(0,10,11)
#x=[  0.   1.   2.   3.   4.   5.   6.   7.   8.   9.  10.]
y=np.sin(x)
xnew=np.linspace(0,10,101)
pl.plot(x,y,"ro")
 
for kind in ["nearest","zero","slinear","quadratic","cubic"]:#插值方式
    #"nearest","zero"為階梯插值
    #slinear 線性插值
    #"quadratic","cubic" 為 2 階、3 階 B 樣條曲線插值
    f=interpolate.interp1d(x,y,kind=kind)
    # ‘slinear’, ‘quadratic’ and ‘cubic’ refer to a spline interpolation of first, second or third order)
    ynew=f(xnew)
    pl.plot(xnew,ynew,label=str(kind))
pl.legend(loc="lower right")
pl.show()

結果:

二維插值

方法與一維資料插值類似,為二維樣條插值。

# -*- coding: utf-8 -*-
"""
演示二維插值。
"""
import numpy as np
from scipy import interpolate
import pylab as pl
import matplotlib as mpl
 
def func(x, y):
    return (x+y)*np.exp(-5.0*(x**2 + y**2))
 
# X-Y 軸分為 15*15 的網格
y,x= np.mgrid[-1:1:15j, -1:1:15j]
 
fvals = func(x,y) # 計算每個網格點上的函式值  15*15 的值
print len(fvals[0])
 
#三次樣條二維插值
newfunc = interpolate.interp2d(x, y, fvals, kind='cubic')
 
# 計算 100*100 的網格上的插值
xnew = np.linspace(-1,1,100)#x
ynew = np.linspace(-1,1,100)#y
fnew = newfunc(xnew, ynew)#僅僅是 y 值   100*100 的值
 
# 繪圖
# 為了更明顯地比較插值前後的區別,使用關鍵字引數 interpolation='nearest'
# 關閉 imshow()內建的插值運算。
pl.subplot(121)
im1=pl.imshow(fvals, extent=[-1,1,-1,1], cmap=mpl.cm.hot, interpolation='nearest', origin="lower")#pl.cm.jet
#extent=[-1,1,-1,1]為 x,y 範圍  favals 為
pl.colorbar(im1)
 
pl.subplot(122)
im2=pl.imshow(fnew, extent=[-1,1,-1,1], cmap=mpl.cm.hot, interpolation='nearest', origin="lower")
pl.colorbar(im2)
 
pl.show()

左圖為原始資料,右圖為二維插值結果圖。

二維插值的三維展示方法

# -*- coding: utf-8 -*-
"""
演示二維插值。
"""
# -*- coding: utf-8 -*-
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl
from scipy import interpolate
import matplotlib.cm as cm
import matplotlib.pyplot as plt
 
def func(x, y):
    return (x+y)*np.exp(-5.0*(x**2 + y**2))
 
# X-Y 軸分為 20*20 的網格
x = np.linspace(-1, 1, 20)
y = np.linspace(-1,1,20)
x, y = np.meshgrid(x, y)#20*20 的網格資料
 
fvals = func(x,y) # 計算每個網格點上的函式值  15*15 的值
 
fig = plt.figure(figsize=(9, 6))
#Draw sub-graph1
ax=plt.subplot(1, 2, 1,projection = '3d')
surf = ax.plot_surface(x, y, fvals, rstride=2, cstride=2, cmap=cm.coolwarm,linewidth=0.5, antialiased=True)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('f(x, y)')
plt.colorbar(surf, shrink=0.5, aspect=5)#標註
 
#二維插值
newfunc = interpolate.interp2d(x, y, fvals, kind='cubic')#newfunc 為一個函式
 
# 計算 100*100 的網格上的插值
xnew = np.linspace(-1,1,100)#x
ynew = np.linspace(-1,1,100)#y
fnew = newfunc(xnew, ynew)#僅僅是 y 值   100*100 的值  np.shape(fnew) is 100*100
xnew, ynew = np.meshgrid(xnew, ynew)
ax2=plt.subplot(1, 2, 2,projection = '3d')
surf2 = ax2.plot_surface(xnew, ynew, fnew, rstride=2, cstride=2, cmap=cm.coolwarm,linewidth=0.5, antialiased=True)
ax2.set_xlabel('xnew')
ax2.set_ylabel('ynew')
ax2.set_zlabel('fnew(x, y)')
plt.colorbar(surf2, shrink=0.5, aspect=5)#標註
 
plt.show()

左圖的二維資料集的函式值由於樣本較少,會顯得粗糙。而右圖對二維樣本資料進行三次樣條插值,擬合得到更多資料點的樣本值,繪圖後圖像明顯光滑多了。

參考連結:

1.拉格朗日插值法:https://zh.wikipedia.org/wiki/拉格朗日插值法

2.樣條插值:https://zh.wikipedia.org/wiki/樣條插值