Ограниченная оптимизация Scipy SLSQP не всегда работает - PullRequest
0 голосов
/ 11 июня 2018

Я пытаюсь свернуть функцию с помощью scipy.optimize.minimize с помощью метода SLSQP.Но иногда происходит сбой с сообщением об ошибке «Превышен лимит итераций» или «Положительная производная по направлению для linesearch», для того же самого ввода.

Пример, который только что произошел: у меня это работает на сервере Flask, поэтому яинициализировал его и отправил запрос, не удалось (предел итерации).Я отправил много одного и того же запроса, не выключая флягу, он не удался с каждым из них.Затем я перезапустил колбу.Внезапно ВСЕ запросы были успешно оптимизированы, я продолжал отправлять их, и они никогда не подводили.Но если я перезапущу колбу снова, она может перестать работать, или нет, она кажется случайной, но если она работала один раз, она будет работать вечно, пока сервер не будет перезапущен.

Но даже когда он один изэкземпляр сервера, на котором работает оптимизатор, все еще работает для менее сложных входных данных.

Контекст проблемы: я пытаюсь оптимизировать портфель фондового рынка с учетом таких ограничений, как волатильность.Обычно он терпит неудачу, когда он превышает 500 000 долларов США.

con = {"type": "eq", "fun": self.sum}
con2 = {"type": "ineq", "fun": self.volatility_ceiling}
con3 = {"type": "ineq", "fun": self.volatility_floor}
cons = (con, con2, con3)

#allocation_list is a list of percentages for each stock in the portfolio

optimized_result = minimize(self.gain, allocation_list, constraints=cons, bounds=self.bounds, method="SLSQP", options={"maxiter": 400})

def gain(self, allocation_list):
    gain_list = [get_gain(id) for id in self.id_list]
    gain_avg = np.average(gain_list, weights=allocation_list)
    return (gain_avg) * (-1)

def sum(self, allocation_list):
    return np.sum(allocation_list) - 1

def volatility_ceiling(self, allocation_list):
    standard_dev = self.vol_portfolio(lista_aloc)
    if self.current_risk_profile == "PROFILE_1":
        return (standard_dev * (-1)) + 0.009
    elif self.current_risk_profile == "PROFILE_2":
        return (standard_dev * (-1)) + 0.011
    elif self.current_risk_profile == "PROFILE_3":
        return (standard_dev * (-1)) + 0.015
    elif self.current_risk_profile == "PROFILE_4":
        return (standard_dev * (-1)) + 0.024
    #The function continues until PROFILE_10

def volatility_ceiling(self, allocation_list):
    standard_dev = self.vol_portfolio(allocation_list)
    if self.current_risk_profile == "PROFILE_1":
        return standard_dev - 0.0
    elif self.current_risk_profile == "PROFILE_2":
        return standard_dev - 0.009
    elif self.current_risk_profile == "PROFILE_3":
        return standard_dev - 0.011
    elif self.current_risk_profile == "PROFILE_4":
        return standard_dev - 0.015
    #The function continues until PROFILE_10

1 Ответ

0 голосов
/ 12 июня 2018

Я бы порекомендовал изменить «единицы» долларов в вашей модели.Например, вместо «долларов» при представлении бюджета переключитесь на «тысячи долларов».Для этого используйте «500» вместо «500 000» и интерпретируйте результаты соответствующим образом.Например, если для актива выделено 3,5 единицы из доступного бюджета, это будет соответствовать 3500 долл. США и т. Д. *

В качестве общего модельного принципа, если числовые значенияЧисла охватывают широкий диапазон, модель будет плохо масштабироваться, и это приглашение к численным проблемам.Большинство коммерческих оптимизаторов будут выдавать предупреждения, предупреждающие вас о действиях по улучшению масштабирования.Если бы модель была линейной (с целочисленными переменными или без них), оптимизатор обычно пытался бы улучшить само масштабирование.Например,

https://www.lindo.com/doc/online_help/lingo15_0/205_themodelispoorlyscaled_.htm

Для нелинейных моделей типа черного ящика такие функции могут быть недоступны.

...