Допуск на завершение игнорируется в Scipy Optimize минимизировать - PullRequest
0 голосов
/ 03 февраля 2020

У меня есть простая проблема оптимизации, которая с некоторыми указанными c данными заставляет scipy.optimize.minimize игнорировать аргумент tol. Из документации , tol определяет «допуск для завершения», то есть максимальную ошибку, принятую для целевой функции, в моем понимании (я ошибаюсь?). Однако в следующем рабочем примере, когда, например, tol установлено равным 0,1 или другими небольшими числами, оптимизация заканчивается сообщением «Оптимизация успешно завершена», даже когда целевая функция> tol. Это ошибка в методе Сципи или я что-то здесь неправильно понимаю?

Проблема оптимизации: мне нужно сделать линейную комбинацию var1 и var2, которые являются двумя временными рядами, масштабируя их по параметрам Btd и Bta. Мне нужно, чтобы среднее значение линейной комбинации приближалось к целевому значению Target, скаляру. Поэтому я просто минимизирую абсолютную разницу между np.mean(Btd*var1 + Bta*var2) и Target. Ограничения заключаются в том, что коэффициенты масштабирования должны быть> 0, а отношение средних значений np.mean(Btd*var1)/np.mean(Bta*var2) должно приближаться к функции gi/(1-gi), где gi - скаляр в интервале [0,1].

Воспроизводимый код:

import numpy as np
import scipy.optimize as opt

# The data that exactly reproduce the error:
time = np.arange(1979,2011)
var2=np.array([ 88.95705521,  74.5398773 ,  72.08588957,  65.64417178,
        50.        ,  72.39263804,  77.3006135 ,  72.08588957,
        64.41717791,  96.62576687,  69.93865031,  84.96932515,
        86.50306748,  82.20858896,  80.98159509,  73.00613497,
        66.25766871,  67.48466258,  79.75460123,  65.64417178,
        70.24539877,  84.66257669,  76.3803681 ,  83.74233129,
        83.74233129,  78.2208589 ,  88.03680982,  87.73006135,
       100.        ,  71.16564417,  73.6196319 ,  85.58282209])
var1=np.array([300.        , 420.89552239, 333.58208955, 355.97014925,
       376.11940299, 510.44776119, 420.89552239, 434.32835821,
       333.58208955, 394.02985075, 523.88059701, 411.94029851,
       353.73134328, 434.32835821, 355.97014925, 398.50746269,
       476.86567164, 371.64179104, 445.52238806, 544.02985075,
       416.41791045, 427.6119403 , 541.79104478, 579.85074627,
       429.85074627, 414.17910448, 420.89552239, 528.35820896,
       577.6119403 , 490.29850746, 600.        , 454.47761194])
X=np.transpose([var1, var2])

# Global parameters
Target = 3.0
gi = 0.7

# This model is a simple linear combination of the two time series.
def MyModel(modelparams, X, gi):
    Bta, Btd = modelparams
    Eta = Bta*X[:,0]
    Etd = Btd*X[:,1]
    Etot = Eta + Etd
    return Etot, Eta, Etd

# Objective function
def Obj(modelparams):
    Bta, Bdt = modelparams
    Etot, Eta, Etd = MyModel([Bta, Bdt], X, gi)
    return abs(np.mean(Etot)-Target)

# Ratio constraint
def Ratio(modelparams):
    import numpy as np
    Bta, Btd = modelparams
    Etot, Eta, Etd = MyModel([Bta, Btd], X, gi)
    A = np.mean(Etd)/np.mean(Eta)
    B = gi/(1-gi)
    # The epsilon comes in to loosen a bit only this constraint
    epsilon = 0.1
    return  -abs(abs(A-B)-epsilon)

# This is my solution to make the parameters different from zero.
# The ineq-type constraint makes them >=0.
def TDPos(modelparams):
    Bta, Btd = modelparams
    return Btd - 10**(-5) 
def TAPos(modelparams):
    Bta, Btd = modelparams
    return Bta - 10**(-5)

constraints=[{'type': 'ineq', 'fun': Ratio},
             {'type': 'ineq', 'fun': TDPos},
             {'type': 'ineq', 'fun': TAPos}]

# Bounds or Model Parameters
bounds=((0, None), (0, None))

# Minimize
modelparams0=[Target/np.nanmean(var1), Target/np.nanmean(var2)]
result = opt.minimize(Obj, modelparams0, 
                      tol=0.1,
                      method='SLSQP',
                      options={'maxiter': 40000 }, #,'ftol': 0.1}, 
                      bounds=bounds,
                      constraints=constraints)
print(result)

Распечатывает:

     fun: 3.0
     jac: array([439.92537314,  77.31019938])
 message: 'Optimization terminated successfully.'
    nfev: 20
     nit: 4
    njev: 4
  status: 0
 success: True
       x: array([0., 0.])

Моя проблема: веселье: 3,0> Тол: 0,1, что не желательно.

TL ; DR : scipy.optimize.minimize игнорирует аргумент stop tol. Почему?

РЕДАКТИРОВАТЬ: Кроме того, оптимальное решение [0, 0] игнорирует два из неравенства ограничений, предназначенных для того, чтобы сделать эту пару параметров> 10 ** (- 5). Это часть той же проблемы?

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