Оптимизация функции, где один из параметров является массивом - PullRequest
0 голосов
/ 21 мая 2018

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

...
# initial parameters
params0 = np.array([p1, p2, ... , p_array1, p_array2])
p_min = minimize(myfunc, params0, args)
...

, где pj - это скаляры, а p_array1 и p_array2 - это массивы одинаковой длины, но это дало мне ошибку, говоря:

ValueError: setting an array element with a sequence.

также попытался передать p_array1 и p_array2 как скаляры в myfunc, а затем создать предопределенные массивы из этих двух внутри myfunc (например, установить p_array1 = p_array1 * np.arange (6) и аналогично для p_array2), устраняя ошибки, но я не хочу ихбыть предопределенным - вместо этого я хочу, чтобы «минимизировать» выяснил, какими они должны быть.

Можно ли как-нибудь использовать одну из функций оптимизации Сципи, не получая эту ошибку, сохраняя при этом p_array1 и p_array2 в качестве массивова не скаляры?

РЕДАКТИРОВАТЬ

Извините за очень широкий, но вот мой код:

ПРИМЕЧАНИЕ : 'myfunc'вот на самом деле norm_residual .

import pandas as pd
import numpy as np

def f(yvec, t, a, b, c, d, M, theta):
    # the system of ODEs to be solved
    x, y = yvec
    dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
    return dydt

ni = 3 # the number of periodic forcing functions to add to the DE system
M = 0.56*np.random.rand(ni) # the initial amplitudes of forcing functions
theta = np.pi/6*np.arange(ni) # the initial coefficients of the forcing functions

# initialize the parameters
params0 = [0.75, 0.23, 1.0, 0.2, M, theta]

# grabbing the data to be used later
data = pd.read_csv('data.csv')
y_data = data['Y']

N = y_data.shape[0] #20
t = np.linspace(0, N, N) # array of t values to integrate over
yvec0 = [0.3, 0.34] # initial conditions for x and y respectively

def norm_residual(params, *args):
    """
    Computes the L^2 norm of the residual of y and the data (y as defined above).
    Input:    params = array of parameters (scalars or arrays) for the DE system
              args = other arguments to pass into the function f or to use
                   to compute the residual.
    Output: err = L^2 error of the solution vector (scalar).
    """
    data, yvec0, t = args
    a, b, c, d, M, theta = params
    sol = odeint(f, yvec0, t, args=(a, b, c, d, M, theta))
    x = sol[:, 0]; y = sol[:, 1]
    res = data - y
    err = np.linalg.norm(res, 2)
    return err

from scipy.optimize import minimize

p_min = minimize(norm_residual, params0, args=(y_data, yvec0, t))
print(p_min)

и обратная связь

Traceback (most recent call last):
  File "model_ex_1.py", line 62, in <module>
    p_min = minimize(norm_residual, params0, args=(y_anom, yvec0, t))
  File "/usr/lib/python2.7/dist-packages/scipy/optimize/_minimize.py", line 354, in minimize
    x0 = np.asarray(x0)
  File "/usr/lib/python2.7/dist-packages/numpy/core/numeric.py", line 482, in asarray
    return array(a, dtype, copy=False, order=order)
ValueError: setting an array element with a sequence.

Ответы [ 3 ]

0 голосов
/ 21 мая 2018

Было бы полезно, если вы публикуете myfunc, но вы можете сделать это -

def foo():
    return [p0,p1,p2..pn]

params0 = numpy.array([foo(), p_array1, p_array2])
p_min = minimize(myfunc, params0, args) 

ИЛИ от Несколько переменных в SciPy's optimize.minimize

import scipy.optimize as optimize

def f(params):
    # print(params)  # <-- you'll see that params is a NumPy array
    a, b, c = params # <-- for readability you may wish to assign names to the component variables
    return a**2 + b**2 + c**2

initial_guess = [1, 1, 1]
result = optimize.minimize(f, initial_guess)
if result.success:
    fitted_params = result.x
    print(fitted_params)
else:
    raise ValueError(result.message)
0 голосов
/ 22 мая 2018

Я понял это!Решение, которое я нашел для работы, состояло в том, чтобы изменить

params0 = [0.75, 0.23, 1.0, 0.2, M, theta]

в строке 6 на

params0 = np.array([ 0.75, 0.23, 1.0, 0.2, *M, *theta], dtype=np.float64)

и в моем определении функции моей системы ODE, которую нужно решить, вместо того, чтобы

def f(yvec, t, a, b, c, d, M, theta):
    x, y = yvec
    dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
    return dydt

Теперь у меня есть

def f(yvec, t, myparams):
    x, y = yvec
    a, b, c, d = myparams[:4]
    ni = (myparams[4:].shape[0])//2 # halved b/c M and theta are of the same shape
    M = myparams[4:ni+4]
    theta = myparams[ni+4:]
    dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
    return dydt

ПРИМЕЧАНИЕ : мне пришлось добавить «dtype = np.float64» для «params0», потому что я получаю ошибку

AttributeError: 'numpy.float64' object has no attribute 'cos'

когда у меня его там не было, и кажется, что 'cos' не знает, как обрабатывать 'ndarray' объекты.Обходной путь можно найти здесь .

Спасибо всем за предложения!

0 голосов
/ 21 мая 2018

Вы не можете поместить список в массив numpy, если другие элементы являются скалярами.

>>> import numpy as np
>>> foo_array = np.array([1,2,3,[5,6,7]])
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    foo_array = np.array([1,2,3,[5,6,7]])
ValueError: setting an array element with a sequence.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...