Оптимизация Scipy с умножением матриц - PullRequest
1 голос
/ 07 октября 2019

Я пытался использовать spicy.optimize.minimize для решения проблемы оптимизации умножения матриц, однако результат дает мне ошибку измерения, может ли кто-нибудь помочь мне с этим?

import numpy as np
from scipy.optimize import minimize

# define known variables, mu, sigma, rf
mu = np.matrix([[0.12], 
                [0.08], 
                [0.05]])

sigma = np.matrix([[0.5, 0.05, 0.03],
                   [0.05, 0.4, 0.01],
                   [0.03, 0.01, 0.2]])

rf = 0.02

def objective_fun(x):
'''
This is the objective function
'''
    s = np.sqrt(x.T * sigma * x)/(mu.T * x - rf)
    return s

def constraint(x):
    con = 1 
    for i in np.arange(0,3):
        con = con - x[i] 
    return con

# set up the boundaries for x
bound_i = (0, np.Inf)
bnds = (bound_i, bound_i, bound_i)

#set up the constraints for x
con = {'type':'eq', 'fun':constraint}

# initial guess for variable x
x = np.matrix([[0.5],
               [0.3],
               [0.2]])

sol = minimize(objective_fun, x, method = 'SLSQP', bounds = bnds, constraints = con)

Ошибка дает мне:

ValueError                                Traceback (most recent call last)
<ipython-input-31-b8901077b164> in <module>
----> 1 sol = minimize(objective_fun, x, method = 'SLSQP', bounds = bnds, constraints = con)

e:\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    606     elif meth == 'slsqp':
    607         return _minimize_slsqp(fun, x0, args, jac, bounds,
--> 608                                constraints, callback=callback, **options)
    609     elif meth == 'trust-constr':
    610         return _minimize_trustregion_constr(fun, x0, args, jac, hess, hessp,

e:\Anaconda3\lib\site-packages\scipy\optimize\slsqp.py in _minimize_slsqp(func, x0, args, jac, bounds, constraints, maxiter, ftol, iprint, disp, eps, callback, **unknown_options)
    397 
    398             # Compute objective function
--> 399             fx = func(x)
    400             try:
    401                 fx = float(np.asarray(fx))

e:\Anaconda3\lib\site-packages\scipy\optimize\optimize.py in function_wrapper(*wrapper_args)
    324     def function_wrapper(*wrapper_args):
    325         ncalls[0] += 1
--> 326         return function(*(wrapper_args + args))
    327 
    328     return ncalls, function_wrapper

<ipython-input-28-b1fb2386a380> in objective_fun(x)
      3     This is the objective function
      4     '''
----> 5     s = np.sqrt(x.T * sigma * x)/(mu.T * x - rf)
      6     return s

e:\Anaconda3\lib\site-packages\numpy\matrixlib\defmatrix.py in __mul__(self, other)
    218         if isinstance(other, (N.ndarray, list, tuple)) :
    219             # This promotes 1-D vectors to row vectors
--> 220             return N.dot(self, asmatrix(other))
    221         if isscalar(other) or not hasattr(other, '__rmul__') :
    222             return N.dot(self, other)

ValueError: shapes (1,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)

Тем не менее, я пытался по отдельности каждую написанную мной функцию, все они не имеют ошибок в конце, например, если после определения матрицы x, как показано в коде, я просто запускаю objective_fun(x) вконсоль, и я сразу же получаю ответ:

optimize_fun(x)
matrix([[5.90897598]])

Это означает, что моя функция может правильно выполнять умножение матриц, так что не так с кодом здесь?

1 Ответ

1 голос
/ 07 октября 2019

Документы для minimize() говорят, что x0 должен быть массивом (n,), но вы пытаетесь рассматривать его как массив (3,1). Я не уверен во внутренней работе minimize(), но я подозреваю, что когда он переходит через другие значения параметров подгонки, он конвертируется в формат, который, как он думает, он хочет. В любом случае, следующие незначительные исправления делают так, чтобы код работал.

import numpy as np
from scipy.optimize import minimize

# define known variables, mu, sigma, rf
mu = np.matrix([[0.12], 
                [0.08], 
                [0.05]])

sigma = np.matrix([[0.5, 0.05, 0.03],
                   [0.05, 0.4, 0.01],
                   [0.03, 0.01, 0.2]])

rf = 0.02

def objective_fun(x):
  '''
  This is the objective function
  '''
  x = np.expand_dims(x, 1) # convert the (3,) shape to (3,1). Then we can do our normal matrix math on it
  s = np.sqrt(x.T * sigma * x)/(mu.T * x - rf) # Transposes so the shapes are correct
  return s

def constraint(x):
  con = 1 
  for i in np.arange(0,3):
      con = con - x[i] 
  return con

# set up the boundaries for x
bound_i = (0, np.Inf)
bnds = (bound_i, bound_i, bound_i)

#set up the constraints for x
con = {'type':'eq', 'fun':constraint}

# initial guess for variable x

x = np.array([0.5, 0.3, 0.2]) # Defining the initial guess as an (3,) array)

sol = minimize(objective_fun, x, method = 'SLSQP', bounds = bnds, constraints = con)
print(sol) # and the solution looks reasonable

Вывод

     fun: 5.86953830952583
     jac: array([-1.70555401, -1.70578796, -1.70573896])
 message: 'Optimization terminated successfully.'
    nfev: 32
     nit: 6
    njev: 6
  status: 0
 success: True
       x: array([0.42809911, 0.29522438, 0.27667651])

Посмотрите на комментарии, которые я вставил, для объяснения того, что вам нужно сделать,

...