2011-06-02 91 views
10

我試圖將一些MatLab代碼移植到Scipy,並且我已經嘗試了scipy.interpolate,interp1dUnivariateSpline兩個不同的函數。 interp1d結果與interp1d MatLab函數相匹配,但UnivariateSpline數字不同 - 在某些情況下,情況會有所不同。Python Interp1d與UnivariateSpline

f = interp1d(row1,row2,kind='cubic',bounds_error=False,fill_value=numpy.max(row2)) 
return f(interp) 

f = UnivariateSpline(row1,row2,k=3,s=0) 
return f(interp) 

任何人都可以提供任何見解嗎?我的x值不是等分的,儘管我不確定爲什麼這很重要。

回答

0

UnivariateSpline:在FITPACK程序的最近 包裝。

這可能解釋稍有不同的值? (我也經歷過UnivariateSpline比interp1d快得多。)

+0

它肯定快得多,這就是爲什麼我要使用它,但它給出了與MatLab非常不同的數字,所以我被迫進入了較慢的interp1d函數。 – 2011-06-02 16:43:54

2

對我的作品,

from scipy import allclose, linspace 
from scipy.interpolate import interp1d, UnivariateSpline 

from numpy.random import normal 

from pylab import plot, show 

n = 2**5 

x = linspace(0,3,n) 
y = (2*x**2 + 3*x + 1) + normal(0.0,2.0,n) 

i = interp1d(x,y,kind=3) 
u = UnivariateSpline(x,y,k=3,s=0) 

m = 2**4 

t = linspace(1,2,m) 

plot(x,y,'r,') 
plot(t,i(t),'b') 
plot(t,u(t),'g') 

print allclose(i(t),u(t)) # evaluates to True 

show() 

這給我,

enter image description here

+0

我只是跑以下: '從pylab進口*'' 從scipy.interpolate進口*' 'X = [3,5,6,8,10]'' Y =的sin(x) '' Z = R_ [3:4:0.1]' 'F = interp1d(X,Y,種類= 3)'' F1 = F(z)的' '克= UnivariateSpline(X,Y中,k = 3,S = 0)'' G1 =克(Z)' '打印F1-g1' 並將其返回: [1.13797860e-15 -2.14227085e-03 -3.88345765e-03 -5.25282403e-03 -6.27963364e-03 -6.99315013e-03 -7.42263713e-03 -7.59735830e-03 -7.54657727e-03 -7.29955769e-03] – 2011-06-02 17:26:33

+0

@Timothy Dees:啊,我看到了問題。請記住,插值是用一些其他函數來近似函數的過程;隨着您從原始函數中採樣越來越多的點,所以融合應該會得到改善。用更多'x'點試試你的例子。如果我抽樣約2 ** 6分,你的例子適用於我。 'linspace()'可以很容易地生成均勻間隔的樣本。 – lafras 2011-06-02 17:56:17

12

之所以結果不同(但兩者都可能是正確的)是由UnivariateSplineinterp1d使用的插值例程不同。

  • interp1d構建使用你給它結

  • UnivariateSplinex -points基於FITPACK,這也構造了一個平滑的B樣條光滑的B樣條。但是,FITPACK會嘗試爲樣條線選擇新的結,以更好地擬合數據(可能會將chi^2加上一些對曲率的懲罰減至最小)。你可以通過g.get_knots()找到它使用的結點。

所以你得到不同結果的原因是插值算法是不同的。如果要在數據點處使用結點的B樣條,請使用interp1dsplmake。如果你想要什麼FITPACK,使用UnivariateSpline。在密集數據的限制下,兩種方法都會得到相同的結果,但是當數據稀疏時,您可能會得到不同的結果。

(我怎麼知道這一切:我讀的代碼:-)

+0

LSQUnivariateSpline可以讓你指定結,所以你可以指定它們等於輸入?但它似乎仍然沒有產生相同的輸出。 – endolith 2013-03-20 03:21:02

13

我剛碰到同樣的問題。

簡短的回答

使用InterpolatedUnivariateSpline代替:

f = InterpolatedUnivariateSpline(row1, row2) 
return f(interp) 

龍答案

UnivariateSpline是「一維樣條函數擬合一組給定的數據點」,而InterpolatedUnivariateSpline是一個'一組給定數據點的一維插值樣條「。前者平滑數據,而後者是一種更傳統的插值方法,並重現interp1d預期的結果。下圖說明了這種差異。

Comparison of interpolation functions

重現該圖中的代碼如下所示。

import scipy.interpolate as ip 

#Define independent variable 
sparse = linspace(0, 2 * pi, num = 20) 
dense = linspace(0, 2 * pi, num = 200) 

#Define function and calculate dependent variable 
f = lambda x: sin(x) + 2 
fsparse = f(sparse) 
fdense = f(dense) 

ax = subplot(2, 1, 1) 

#Plot the sparse samples and the true function 
plot(sparse, fsparse, label = 'Sparse samples', linestyle = 'None', marker = 'o') 
plot(dense, fdense, label = 'True function') 

#Plot the different interpolation results 
interpolate = ip.InterpolatedUnivariateSpline(sparse, fsparse) 
plot(dense, interpolate(dense), label = 'InterpolatedUnivariateSpline', linewidth = 2) 

smoothing = ip.UnivariateSpline(sparse, fsparse) 
plot(dense, smoothing(dense), label = 'UnivariateSpline', color = 'k', linewidth = 2) 

ip1d = ip.interp1d(sparse, fsparse, kind = 'cubic') 
plot(dense, ip1d(dense), label = 'interp1d') 

ylim(.9, 3.3) 

legend(loc = 'upper right', frameon = False) 

ylabel('f(x)') 

#Plot the fractional error 
subplot(2, 1, 2, sharex = ax) 

plot(dense, smoothing(dense)/fdense - 1, label = 'UnivariateSpline') 
plot(dense, interpolate(dense)/fdense - 1, label = 'InterpolatedUnivariateSpline') 
plot(dense, ip1d(dense)/fdense - 1, label = 'interp1d') 

ylabel('Fractional error') 
xlabel('x') 
ylim(-.1,.15) 

legend(loc = 'upper left', frameon = False) 

tight_layout() 
+5

您鏈接到的註釋說明InterpolatedUnivariateSpline是「等同於具有s = 0的單變量樣條曲線」,這正是他正在使用的文檔。 – Craig 2014-11-13 19:12:58