Использование фиксированных параметров с использованием scipy.optimize.minimize

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

Вот код, который у меня есть в настоящее время:

from numpy import array
import scipy.optimize as optimize
from scipy.optimize import minimize

def objective(speed, params):
    a,b,c,d=params
    return abs(rg.predict([[speed,params]]))

p0=np.array([[98.3,46.9,119.9,59.1]])

x0=np.array([[4]])
result = optimize.minimize(objective, x0, args=(p0,),method='nelder-mead')
print(result.x)

Я ищу способ передать список или массив фиксированных параметров внутри функции optimize.minimize. Однако приведенный выше код дает мне эту ошибку:

ValueError: not enough values to unpack (expected 4, got 1)

Единственный способ заставить его работать - это жестко кодировать входные данные следующим образом:

def objective(params):
 a=100
 b=20
 c=119.9
 d=params
 e=59.1
 return abs(rg.predict([[a,b,c,d,e]]))

x0=np.array([[4.5]])
result = optimize.minimize(objective, x0, method='nelder-mead')
print(result.x)

Правильно ли я подхожу к этому? Как я могу передать список или массив в качестве фиксированных входных данных?

2 ответа

Решение

Кортеж прошел как args будет принят как *args к целевой функции. Если вы определите целевую функцию так, как вы это сделали, она ожидает один входной аргумент (кроме speed должно быть минимизировано), таким образом, передавая одноэлементный кортеж (p0,) как args ключевое слово для minimize идеально. Ваша ошибка появляется после вызова функции:

ValueError: not enough values to unpack (expected 4, got 1)

На самом деле это происходит из первой строки вашей целевой функции:

a,b,c,d=params # params = np.array([[98.3,46.9,119.9,59.1]])

Массив, который вы передали как p0 имеет два набора квадратных скобок, поэтому он имеет форму (1,4), Массивы распаковываются по своему первому измерению, поэтому во время распаковки это ведет себя как 1-кортеж (который содержит 4-элементный массив). Вот почему вы не можете распаковать форму (1,4) до четырех переменных, следовательно, ошибка.

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

def objective(speed, a, b, c, d):
    ... # return stuff using a,b,c,d

# define a0, b0, c0, d0 as convenient
result = optimize.minimize(objective, x0, args=(a0,b0,c0,d0), method='nelder-mead')

Будет ли более элегантно определять вашу функцию, как это, зависит от того, как ваши фиксированные параметры могут быть легко определены и что происходит с этими аргументами внутри objective, Если вы просто собираетесь передать список аргументов, как в MCVE, то нет необходимости разделять эти переменные в первую очередь, но если эти четыре входа используются в вычислениях совершенно по-разному, то может иметь смысл обрабатывать каждый из них. индивидуально, начиная с определения вашей целевой функции.

Это линейные ограничения вида Ax = b, Например, скажем, мы хотим держать первые две переменные x0, x1 (ваш a, b) фиксированный:

A = [[ 1 0 0 ... ]
     [ 0 1 0 ... ]]
b = [b0 b1]

Существует общий способ превратить линейно-ограниченную задачу Ax = bк неограниченной проблеме в меньшем количестве переменных, в этом примере n - 2, используя СВД.
minlin.py под моей сущностью находится одностраничная обертка SVD для этого процесса. Его документ:

""" Minlin: convert linear-constrained min f(x): Ax = b
to unconstrained min in fewer variables.
For example, 10 variables with 4 linear constraints, A 4 x 10,
-> 6 unconstrained variables:

minlin = Minlin( A, b, bigfunc, verbose=1 )   # bigfunc( 10 vars )
then
minimize( minlin.littlefunc, minlin.y0 ... )  # littlefunc( 6 vars )
    with your favorite unconstrained minimizer. For example,

from scipy.optimize import minimize
res = minimize( minlin.littlefunc, minlin.y0 ... )
fbest = res.fun
ybest = res.x  # 6 vars
xbest = minlin.tobig(ybest)  # 10 vars
    = minlin.x0  + y . nullspace  from svd(A)
    x0 = Ainv b = lstsq( A, b )

Methods: .func(x) .tonullspace(X) .torowspace(X) .tobig(y)
Attributes: .sing .Vt .Vtop .Vnull .x0

How it works, in a simple case:
consider holding x0 = b0, x1 = b1 fixed, i.e.
A = [[ 1 0 0 ... ]
     [ 0 1 0 ... ]]
We can minimize unconstrained over the n - 2 variables [x2 x3 ...]
if we could find them / find a basis for them, given just A.
This is what SVD / Minlin does.
"""

Это может быть излишним для вашей проблемы. Но хороший вопрос - хорошо бы осмотреться, попытаться понять грубую страну в 5d, варьируя лишь несколько переменных, которые вы понимаете.

Другие вопросы по тегам