La cosa migliore che posso pensare è di fare una minimizzazione con un vincolo con scipy.optimize.minimize
. È abbastanza facile prendere la derivata di una spline, quindi il vincolo è semplicemente. Vorrei usare una spline regolare (UnivariateSpline
) per ottenere i nodi (t
), e tenere i nodi fissi (e il grado k
, ovviamente) e variare i coefficienti c
. Forse c'è un modo per variare le posizioni dei nodi, ma lo lascerò a te.
import numpy as np
from scipy.interpolate import UnivariateSpline, splev, splrep
from scipy.optimize import minimize
def guess(x, y, k, s, w=None):
"""Do an ordinary spline fit to provide knots"""
return splrep(x, y, w, k=k, s=s)
def err(c, x, y, t, k, w=None):
"""The error function to minimize"""
diff = y - splev(x, (t, c, k))
if w is None:
diff = np.einsum('...i,...i', diff, diff)
else:
diff = np.dot(diff*diff, w)
return np.abs(diff)
def spline_neumann(x, y, k=3, s=0, w=None):
t, c0, k = guess(x, y, k, s, w=w)
x0 = x[0] # point at which zero slope is required
con = {'type': 'eq',
'fun': lambda c: splev(x0, (t, c, k), der=1),
#'jac': lambda c: splev(x0, (t, c, k), der=2) # doesn't help, dunno why
}
opt = minimize(err, c0, (x, y, t, k, w), constraints=con)
copt = opt.x
return UnivariateSpline._from_tck((t, copt, k))
E poi abbiamo generare alcuni dati falsi che dovrebbe avere pendenza iniziale zero e testarlo:
import matplotlib.pyplot as plt
n = 10
x = np.linspace(0, 2*np.pi, n)
y0 = np.cos(x) # zero initial slope
std = 0.5
noise = np.random.normal(0, std, len(x))
y = y0 + noise
k = 3
sp0 = UnivariateSpline(x, y, k=k, s=n*std)
sp = spline_neumann(x, y, k, s=n*std)
plt.figure()
X = np.linspace(x.min(), x.max(), len(x)*10)
plt.plot(X, sp0(X), '-r', lw=1, label='guess')
plt.plot(X, sp(X), '-r', lw=2, label='spline')
plt.plot(X, sp.derivative()(X), '-g', label='slope')
plt.plot(x, y, 'ok', label='data')
plt.legend(loc='best')
plt.show()
Sembra che il seguente codice possa fare ciò che è necessario http://eqtools.readthedocs.org/en/latest/_modules/eqtools/trispline.html –
Ho apportato una modifica per correggere il tuo esempio. Basandomi sul tuo dire cosa sia 'data.shape', penso che la mia modifica corrisponda al tuo intento, ma per favore controlla e ripristina se no. – askewchan
Grazie, ora è stato risolto. Ho confuso l'ordine degli indici ... – Dux