2017-01-13 50 views
5

Dostaję ostrzeżenie Optymalizuj:Korzystanie scipy curve_fit z funkcją odcinkowo

OptimizeWarning: Covariance of the parameters could not be estimated 
       category=OptimizeWarning) 

gdy próbuje dopasować moją funkcję odcinkowo do moich danych za pomocą scipy.optimize.curve_fit. Oznacza to, że nic się nie dzieje. Mogę z łatwością dopasować parabolę do moich danych i dostarczam curve_fit z tym, co uważam za dobre parametry początkowe. Pełna próbka kodu poniżej. Czy ktoś wie, dlaczego curve_fit może nie współpracować z np.piecewise? Czy robię inny błąd?

import numpy as np 
from scipy.optimize import curve_fit 
import matplotlib.pyplot as plt 


def piecewise_linear(x, x0, y0, k1, k2): 
    y = np.piecewise(x, [x < x0, x >= x0], 
        [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0]) 
    return y 

def parabola(x, a, b): 
    y = a * x**2 + b 
    return y 

x = np.array([-3, -2, -1, 0, 1, 2, 3]) 
y = np.array([9.15, 5.68, 2.32, 0.00, 2.05, 5.29, 8.62]) 


popt_piecewise, pcov = curve_fit(piecewise_linear, x, y, p0=[0.1, 0.1, -5, 5]) 
popt_parabola, pcov = curve_fit(parabola, x, y, p0=[1, 1]) 

new_x = np.linspace(x.min(), x.max(), 61) 


fig, ax = plt.subplots() 

ax.plot(x, y, 'o', ls='') 
ax.plot(new_x, piecewise_linear(new_x, *popt_piecewise)) 
ax.plot(new_x, parabola(new_x, *popt_parabola)) 

ax.set_xlim(-4, 4) 
ax.set_ylim(-2, 16) 

enter image description here

Odpowiedz

5

Jest to problem z typów, trzeba zmienić następujący wiersz, tak że x jest podana jako pływaków:

x = np.array([-3, -2, -1, 0, 1, 2, 3]).astype(np.float) 

inaczej piecewise_linear będzie może skończyć się rzucanie typów.

po prostu się na bezpiecznej stronie można również dokonać początkowe punkty unosić tutaj:

popt_piecewise, pcov = curve_fit(piecewise_linear, x, y, p0=[0.1, 0.1, -5., 5.]) 
+0

jaki kiedykolwiek pan stwierdzić, że? –

+0

Próbowałem ocenić 'piecewise_linear' z danymi punktów, i to nie działało, więc doszedłem do wniosku, że problem musi gdzieś być. Myślę, że ma to związek z dziwnym zachowaniem 'np.piecewise'. –

+0

Próbowałem czegoś takiego i zupełnie tego nie dostrzegałem. Bardzo dobrze! –

2

Dla kompletności, będę podkreślić, że zamontowanie funkcja przedziałami liniowa nie wymaga np.piecewise: takiej funkcji można skonstruować z wartości bezwzględnych, stosując wielokrotność np.abs(x-x0) dla każdego zakrętu. Poniższa produkuje dobre dopasowanie do danych:

def pl(x, x0, a, b, c): 
    y = a*np.abs(x-x0) + b*x + c 
    return y 

popt_pl, pcov = curve_fit(pl, x, y, p0=[0, 0, 0, 0]) 

print(pl(x, *popt_pl)) 

Wyjście jest blisko do oryginalnych wartości y:

[ 8.90899998 5.828  2.74700002 -0.33399996 2.03499998 5.32 
    8.60500002]