2011-06-02 96 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