lagrange - Python interp1d vs. UnivariateSpline
signal interpolation python (4)
UnivariateSpline: un contenedor más reciente de las rutinas de FITPACK.
esto podría explicar los valores ligeramente diferentes? (También experimenté que UnivariateSpline es mucho más rápido que interp1d).
Estoy tratando de portar algún código de MatLab a Scipy, y he probado dos funciones diferentes de scipy.interpolate, interp1d y UnivariateSpline . Los resultados interp1d coinciden con la función InterLaT MatLab, pero los números Univariados se ven diferentes y, en algunos casos, muy diferentes.
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)
¿Alguien podría ofrecer alguna idea? Mis vals x no están igualmente espaciados, aunque no estoy seguro de por qué eso sería importante.
Funciona para mi,
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()
Esto me da,
El motivo por el cual los resultados son diferentes (pero ambos probablemente sean correctos) es que las rutinas de interpolación utilizadas por UnivariateSpline
e interp1d
son diferentes.
interp1d
construye una B-spline suave utilizando los puntosx
que le asignó como nudosUnivariateSpline
se basa en FITPACK, que también construye una B-spline suave. Sin embargo, FITPACK intenta elegir nuevos nudos para la spline, para ajustar mejor los datos (probablemente para minimizar chi ^ 2 más alguna penalización por curvatura, o algo similar). Puede averiguar qué puntos de nudo utilizó a través deg.get_knots()
.
Entonces, la razón por la que obtienes diferentes resultados es que el algoritmo de interpolación es diferente. Si desea B-splines con nudos en puntos de datos, use interp1d
o splmake
. Si quiere lo que hace FITPACK, use UnivariateSpline
. En el límite de datos densos, ambos métodos dan los mismos resultados, pero cuando los datos son escasos, puede obtener resultados diferentes.
(¿Cómo sé todo esto? Leí el código :-)
Me encontré con el mismo problema.
Respuesta corta
Use InterpolatedUnivariateSpline en su lugar:
f = InterpolatedUnivariateSpline(row1, row2)
return f(interp)
Respuesta larga
UnivariateSpline es una "spline de suavizado unidimensional que se ajusta a un conjunto dado de puntos de datos", mientras que InterpolatedUnivariateSpline es una "spline de interpolación unidimensional para un conjunto determinado de puntos de datos". El primero suaviza los datos mientras que el último es un método de interpolación más convencional y reproduce los resultados esperados de interp1d . La figura a continuación ilustra la diferencia.
El código para reproducir la figura se muestra a continuación.
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()