Оптимизировать переменную из функции в Python - PullRequest
0 голосов
/ 10 июля 2020

Я привык использовать Excel для такого рода проблем, но сейчас пробую Python.

В основном у меня есть два набора массивов, одна константа и значения другого происходят из определяемой пользователем функции.

Это достаточно простая функция.

import scipy.stats as sp

def calculate_probability(spread, std_dev):
    return sp.norm.sf(0.5, spread, std_dev)

У меня есть два массива данных, один с записями, которые выполняются через функцию calculate_probability ( это spreads), а другой набор констант, называемый expected_probabilities.

spreads = [10.5, 9.5, 10, 8.5]

expected_probabilities = [0.8091, 0.7785, 0.7708, 0.7692]

Я пытаюсь оптимизировать следующую функцию.

import numpy as np
def calculate_mse(std_dev):
    spread_inputs = np.array(spreads)
    model_probabilities = calculate_probability(spread_inputs,std_dev)
    subtracted_vector = np.subtract(model_probabilities,expected_probabilities)
    vector_powered = np.power(subtracted_vector,2)
    mse_sum = np.sum(vector_powered)
    return mse_sum/len(spreads)

I хочет найти такое значение std_dev, чтобы функция calculate_mse возвращала как можно более близкое к нулю. Это очень просто в Excel с помощью решателя, но я не уверен, как это сделать в Python. Каков наилучший способ?

РЕДАКТИРОВАТЬ: Я изменил свою функцию calculate_mse так, что в качестве параметра для оптимизации используется только стандартное отклонение. Я попытался вернуть ответ Эндрю в формате API, используя flask, но столкнулся с некоторыми проблемами:

class Minimize(Resource):

    std_dev_guess = 12.0  # might have a better guess than zeros
    result = minimize(calculate_mse, std_dev_guess)

    def get(self):
        return {'data': result},200

api.add_resource(Minimize,'/minimize')

Это ошибка:

NameError: name 'result' is not defined

Я думаю что-то не так с вводом?

1 Ответ

1 голос
/ 10 июля 2020

Я бы посоветовал использовать библиотеку оптимизации scipy. Оттуда у вас есть несколько вариантов, самый простой из ваших текущих настроек - просто использовать метод минимизации. Сам Minimize имеет огромное количество опций, от симплексных методов (по умолчанию) до BFGS и COBYLA. https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html

from scipy.optimize import minimize

n_params = 4  # based of your code so far
spreads_guess = np.zeros(n_params)  # might have a better guess than zeros
result = minimize(calculate_mse, spreads_guess)

Попробуйте, и если у вас есть дополнительные вопросы, я могу отредактировать ответ и уточнить его по мере необходимости.

Вот лишь пара предложений для очистите свой код.

class Minimize(Resource):
    result = None

    def _calculate_probability(self, spread, std_dev):
        return sp.norm.sf(0.5, spread, scale=std_dev)
  
    def _calculate_mse(self, std_dev):
        spread_inputs = np.array(self.spreads)
        model_probabilities = self._calculate_probability(spread_inputs, std_dev)
        mse = np.sum((model_probabilities - self.expected_probabilities)**2) / len(spread_inputs)
        print(mse)
        return mse

    def __init__(self, expected_probabilities, spreads, std_dev_guess):
        self.std_dev_guess = std_dev_guess
        self.spreads = spreads
        self.expected_probabilities = expected_probabilities

    def solve(self):
        self.result = minimize(self._calculate_mse, self.std_dev_guess, method='BFGS')

    def get(self):
        return {'data': self.result}, 200

# run something like
spreads = [10.5, 9.5, 10, 8.5]
expected_probabilities = [0.8091, 0.7785, 0.7708, 0.7692]
minimizer = Minimize(expected_probabilities, spreads, 10.)
print(minimizer.get())  # returns none since it hasn't been run yet, up to you how to handle this
minimizer.solve()
print(minimizer.get())

...