Кривая Python подходит для нескольких переменных

1

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

Вот пример кода

import numpy as np
from scipy.optimize import curve_fit

# Fit function returns two values
def func(X, a, b, c):
    x,y = X
    val1 = np.log(a) + b*np.log(x) + c*np.log(y)
    val2 = np.log(a)-4*val1/3
    return (val1,val2)

# some artificially noisy data to fit
x = np.linspace(0.1,1.1,101)
y = np.linspace(1.,2., 101)
a, b, c = 10., 4., 6.
z ,v = func((x,y), a, b, c) * 1 + np.random.random(101) / 100

# initial guesses for a,b,c:
p0 = 8., 2., 7.

curve_fit(func, (x,y), (z,v), p0)

Он отлично работает с fitfunction одного возвращаемого значения, но он не работает с двумя. Он дает: N = 3 не должен превышать ошибку M = 2.

if n > m:
     raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m))    
Improper input: N=3 must not exceed M=2

Мне нужно найти параметры, которые минимизируют остатки между значениями val1 - z и val2- v в одно и то же время.

Что мне здесь не хватает?

Вот как выглядят мои входные данные.

Изображение 174551

Мне нужны параметры, которые подходят как для z/x, так и для v/x.

  • 1
    По определению, учитывая одно значение x , функция должна возвращать одно значение y . Кажется, вы возвращаете два значения y , я не уверен, что вы решаете. Если бы вы выписали уравнение для функции подбора вручную, как бы это выглядело?
  • 0
    Я добавляю картинки
Показать ещё 1 комментарий
Теги:
scipy
curve-fitting
model-fitting

2 ответа

1
Лучший ответ

Как замечают другие, ваша функция должна вернуть что-то с формой входных данных, поэтому вам нужно будет изменить форму вывода функции ошибки. Поскольку scipy выполняет функцию наименьших квадратов, это достигается за счет возврата функции np.sqrt(val1 ** 2 + val2 ** 2).

Однако для этого типа проблем я предпочитаю использовать обертку вокруг scipy которую я написал, чтобы упорядочить этот процесс работы с несколькими компонентами, называемый symfit.

В symfit эта проблема будет решена следующим образом:

from symfit import parameters, variables, log, Fit, Model
import numpy as np
import matplotlib.pyplot as plt

x, y, z1, z2 = variables('x, y, z1, z2')
a, b, c = parameters('a, b, c')

z1_component = log(a) + b * log(x) + c * log(y)
model_dict = {
    z1: z1_component,
    z2: log(a) - 4 * z1_component/3
}
model = Model(model_dict)
print(model)

# Make example data
xdata = np.linspace(0.1, 1.1, 101)
ydata = np.linspace(1.0, 2.0, 101)
z1data, z2data = model(x=xdata, y=ydata, a=10., b=4., c=6.) + np.random.random(101)

# Define a Fit object for this model and data. Demand a > 0.
a.min = 0.0
fit = Fit(model_dict, x=xdata, y=ydata, z1=z1data, z2=z2data)
fit_result = fit.execute()
print(fit_result)

# Make a plot of the result
plt.scatter(xdata, z1data, s=1, color='blue')
plt.scatter(xdata, z2data, s=1, color='green')
plt.plot(xdata, model(x=xdata, y=ydata, **fit_result.params).z1, color='blue')
plt.plot(xdata, model(x=xdata, y=ydata, **fit_result.params).z2, color='green')

Выход:

z1(x, y; a, b, c) = b*log(x) + c*log(y) + log(a)
z2(x, y; a, b, c) = -4*b*log(x)/3 - 4*c*log(y)/3 - log(a)/3

Parameter Value        Standard Deviation
a         2.859766e+01 1.274881e+00
b         4.322182e+00 2.252947e-02
c         5.008192e+00 5.497656e-02
Fitting status message: b'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
Number of iterations:   23
Regression Coefficient: 0.9961974241602712

Изображение 174551

0

scipy.optimize.curve_fit проверяет, есть ли у вас по крайней мере столько точек данных, как установленные параметры, сравнивая длину списка параметров func (a, b, c) как 3 с длиной зависимой переменной (z, v) как 2. Да, оба z и v содержат более трех точек данных, но длина (z, v) равна двум.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню