Почему «scipy.optimize.minimize» дает мне такое плохое соответствие?

1

У меня есть функция y(x,z) с двумя переменными x, z и 6 коэффициентами a, b, c, d, e, f. У меня есть данные для x, z и, скажем, для целей тестирования данные коэффициентов. С этими данными я вычисляю свой y.

Затем я хочу согласовать функцию с данными x, z и вычисленным y чтобы получить коэффициенты и сравнить их с целью тестирования.

import numpy as np
from scipy.optimize import minimize

x = np.array([0,0.25,0.5,0.75,1]) # data of variable x
z = np.array([0,0.25,0.5,0.75,1]) # data of variable z

def func(pars,x,z): #my function
    a,b,c,d,e,f = pars
    return a*x**2+b*x+c+d*z+e*z*x+f*z*x**2

a = np.array([1,1,1,1,1])  #define coefficients to get the y data and compare them later with fit
b = np.array([0.5,0.5,0.5,0.5,0.5])
c = np.array([0.25,0.25,0.25,0.25,0.25])
d = np.array([1,1,1,1,1])
e = np.array([0.5,0.5,0.5,0.5,0.5])
f = np.array([0.25,0.25,0.25,0.25,0.25])

y = []
y.append(func((a,b,c,d,e,f),x,z)) #calculate the y data
print(y)

def resid(pars,x,z,y): #residual function
    return ((func(pars,x,z) - y) ** 2).sum()

pars0 = np.array([0,0,0,0,0,0])
res = minimize(resid, pars0,args=(x,z,y), method='cobyla',options={'maxiter': 5000000})
print("a = %f , b = %f, c = %f, d = %f, e = %f, f = %f" % (res.x[0], res.x[1], res.x[2], res.x[3], res.x[4], res.x[5]))

Я получаю следующие коэффициенты от примерки:

a = 1.181149 , b = 1.228558, c = 0.253053, d = 0.219143, e = 0.444941, f = 0.172369

По сравнению с моими коэффициентами для расчета y данных подгонка не совсем то, что я бы назвал адекватным. Может кто-нибудь объяснить мне, почему у меня плохая посадка?

PS: Если кому-то интересно, я использую cobyla потому что cobyla мне нужно будет определить некоторые ограничения. Это всего лишь тестовый код, чтобы узнать, где находится моя проблема (надеюсь).

Теги:
scipy
curve-fitting
minimize

1 ответ

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

Глядя на res.fun, который в вашем случае около 1e-5 подходит на самом деле довольно хорошо.

Скорее всего, вы нашли локальный минимум вашей целевой функции. Чтобы лучше понять это поведение, попробуйте код ниже. Это приведет к разным результатам для разных начальных точек. Как вы увидите, вы минимизируете, но не до глобального минимума. Для глобальной оптимизации вы должны использовать другие подходы/методы. Вы также можете увеличить критерии, когда остановить оптимизацию. Или используйте гибридный подход и начните с разных начальных точек, решите локальную минимизацию и выберите лучшее значение.

for i in range(10):
    pars0 = np.random.rand(6) * 1
    res = minimize(resid, pars0, args=(x,z,y), method='cobyla',options={'maxiter': 5000000})
    print("a = %f , b = %f, c = %f, d = %f, e = %f, f = %f" % (res.x[0], res.x[1], res.x[2], res.x[3], res.x[4], res.x[5]))
    print(res.fun)

Попробуйте начальную точку, близкую к решению, которое вы ищете. Это, скорее всего, даст глобальный результат. Если вы не знаете расплывчатое местоположение вашего решения, возможно, вам придется использовать гибридный/глобальный подход к минимизации.

Например, начальная точка:

pars0 = np.array([1,0.5,0.25,1,0.5,0.25]) + np.random.rand(6)*0.01

дает вполне подходящее решение.

  • 0
    Ах, я вижу, довольно хорошо написанный ответ. Спасибо! Один маленький (глупый) вопрос: что делает res.fun ? Как вы и подозревали, я не знаю расплывчатого местоположения. Так что я думаю, я должен использовать глобальный подход.
  • 1
    Ваш welocme! Вы можете посмотреть на различные варианты УЭ объекта здесь: docs.scipy.org/doc/scipy/reference/generated/... res.fun дает значение целевой функции для минимума. См. res.success или другие для получения дополнительной информации о ваших результатах оптимизации. Вы также можете попробовать настройки оптимизатора. Но среднеквадратическая ошибка 1E-5 очень хороша, если вы спросите меня. Подождите и посмотрите, как ваш код ведет себя с реальными данными измерений.
Показать ещё 1 комментарий

Ещё вопросы

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