Как использовать scipy.optimize.curve_fit для использования списков переменных - PullRequest
0 голосов
/ 21 февраля 2020

У меня есть изменяемая во времени трассировка данных, к которой я хочу приспособить функцию. Входными данными для функций являются списки, и я хочу, чтобы curve_fit оптимизировал все значения в списке, чтобы соответствовать кривой. Я дошел до сих пор -

from scipy.optimize import curve_fit
from matplotlib.pylab import plt
from numpy import exp

def ffunc2(x, a, b):
    counter = 0
    return_value = 0
    while counter < len(a):
        return_value += a[counter] * exp(b[counter] * x)
        counter += 1
    return return_value

# INITIAL DATA
x = [1, 2, 3, 5]
y = [1, 8, 81, 125]


number_variable = 2

# INTIAL GUESS
p0 = []
counter = 0
while counter < number_variable:
    p0.append(0.0)
    counter += 1

p, _ = curve_fit(ffunc2, x, y, p0=[0.0, 0.0])

Я хочу создать al oop, который повторяется так, что он дает мне наилучшее соответствие с максимальным количеством переменных путем минимизации ошибки.

Я также нашел это обсуждение - Использование scipy curve_fit для переменного числа параметров

from numpy import exp
from scipy.optimize import curve_fit

def wrapper_fit_func(x, N, *args):
    a, b, c = list(args[0][:N]), list(args[0][N:2*N]), list(args[0][2*N:3*N])
    return fit_func(x, a, b)

def fit_func(x, a, b):
    counter = 0
    return_value = 0
    while counter < len(a):
        return_value += a[counter] * exp(b[counter] * x)
        counter += 1
    return return_value


x = [1, 2, 3, 5]
y = [1, 8, 81, 125]
params_0 = [0,1.0,2.0,3.0,4.0,5.0]

popt, pcov = curve_fit(lambda x, *params_0: wrapper_fit_func(x, 3, params_0), x, y, p0=params_0)

Но получите сообщение об ошибке --´´´ File 'C: \ python \ lib \ site-packages \ scipy \ optimize \ minpack.py ", строка 387, в leastsq повышение TypeError ('Неправильный ввод: N =% s не должно превышать M =% s'% (n, m) ) TypeError: Неправильный ввод: N = 6 не должно превышать M = 4 ´´´

Ответы [ 2 ]

1 голос
/ 26 февраля 2020

Я смог решить эту проблему, используя sci_py.optimize.least_squares напрямую, так как он принимает в качестве входных данных кортеж, а не переменные напрямую. Но я должен определить функцию ошибки. Я бы предположил, что это поможет решить мою проблему на данный момент.

from scipy.optimize import least_squares
from matplotlib.pylab import plt
from numpy import exp
import numpy as np


# define function to fit
def ffunc2(a, x):
    counter = 0
    return_value = 0
    while counter < len(a):
        return_value += a[counter] * exp(x * a[counter + 1])
        counter += 2

    return return_value


def error_func(tpl, x, y):
    return ffunc2(tpl,x) - y


# INPUT DATA
x = np.array([1, 2, 3, 5])
y = np.array([0.22103418, 0.24428055, 0.26997176, 0.32974425,])

# INITIAL GUESS
p0 = (1, 1)*10
output = least_squares(error_func, x0=p0, jac='2-point', bounds=(0, np.inf), method='trf', ftol=1e-08,
                       xtol=1e-08, gtol=1e-08, x_scale=1.0, loss='linear', f_scale=1.0, diff_step=None,
                       tr_solver=None,
                       tr_options={}, jac_sparsity=None, max_nfev=None, verbose=0, args=(x, y))

tpl_final = output.x
print (tpl_final)

final_curve = ffunc2(tpl_final,x)

plt.plot(x, y, 'r-', x, final_curve, 'g-')
plt.show()

0 голосов
/ 22 февраля 2020

Краткий ответ - «Нет». curve_fit требует единого списка / ndarray переменных параметров, которые по порядку соответствуют аргументам функции модели, которую вы предоставляете. То есть вам нужно было бы явно назвать все параметры в вашей функции и сделать список списков переменных строго 1D.

Опять же, curve_fit не намного больше, чем обертка вокруг scipy.optimize.least_squares. Чтобы использовать этот подход, вы передаете (все еще строго одномерный) список / ndarray и используете эти значения для построения минимизируемого массива (обычно data-model) из этого единственного массива переменных. В некоторых сложных случаях со многими компонентами или наборами данных это может стать проще в использовании. То есть подход curve_fit не очень хорошо масштабируется до 50 позиционных переменных.

В зависимости от характера вашей проблемы, вы также можете найти lmfit (https://lmfit.github.io/lmfit-py/ - отказ от ответственности: я автор оригинала) полезно. Это упорядочивает параметры по имени, а не по позиции в списке и предоставляет более встроенные способы ограничения параметров и исследования неопределенностей. Что может быть особенным для вашего случая, класс lmfit.Model для подгонки кривой включает в себя возможность легко добавлять модели вместе в композит (например, 2 гауссиана + n экспоненциальный фон, как показано в https://lmfit.github.io/lmfit-py/examples/documentation/builtinmodels_nistgauss2.html). Это может помочь вам express, что вы пытаетесь сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...