Как найти пару параметров, минимизирующих значение скалярной функции, принимающей 4 входных аргумента?

#python #python-3.x #list #optimization #scipy

#python #python-3.x #Список #оптимизация #scipy

Вопрос:

Я определил python-функцию, принимающую четыре входных параметра и возвращающую скаляр. Первые два входа являются векторами, в то время как последние два входа являются скалярами. Для заданных двух векторов (первых двух входных данных) я хочу найти значения y0 и y1 , которые минимизируют функцию. Каков наилучший способ сделать это?

Вот пример кода функции:

 def f(y_,y,y0,y1):
    xy1 = [i*y1 for i in range(len(y_))]
    diff = [(y_[i]   y0   xy1[i] - y[i])**2 for i in range(len(y_))]
    return sum(diff)

y_ = [x**2   1.4 for x in range(-10,11,1)]
y= [x**2   1. for x in range(-10,11,1)]
x = [3*i for i in range(len(y_))]
print('x:',x)
print('y_:',y_,'n','y:',y)
print('f:',f(y_,y,0,0))
  

Вывод:

 x: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60]
y_: [101.4, 82.4, 65.4, 50.4, 37.4, 26.4, 17.4, 10.4, 5.4, 2.4, 1.4, 2.4, 5.4, 10.4, 17.4, 26.4, 37.4, 50.4, 65.4, 82.4, 101.4] 
y: [101.0, 82.0, 65.0, 50.0, 37.0, 26.0, 17.0, 10.0, 5.0, 2.0, 1.0, 2.0, 5.0, 10.0, 17.0, 26.0, 37.0, 50.0, 65.0, 82.0, 101.0]
f: 3.360000000000019
  

Ответ №1:

Вот ваша функция, завернутая в python lambda, поэтому она принимает один векторный аргумент и может быть передана в scipy.minimize.

 from scipy.optimize import minimize

def f(y_,y,y0,y1):
    xy1 = [i*y1 for i in range(len(y_))]
    diff = [(y_[i]   y0   xy1[i] - y[i])**2 for i in range(len(y_))]
    return sum(diff)

y_ = [x**2   1.4 for x in range(-10,11,1)]
y= [x**2   1. for x in range(-10,11,1)]
x = [3*i for i in range(len(y_))]
print('x:',x)
print('y_:',y_,'n','y:',y)
print('f:',f(y_,y,0,0))



toMinimize = lambda x: f(y_,y, x[0], x[1])
res = minimize(toMinimize, (0, 0))

print(res.message)
print('optimizal position: ',res.x)
print('minimal value: ',res.fun)
  

Это дает следующий результат.

 x: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60]
y_: [101.4, 82.4, 65.4, 50.4, 37.4, 26.4, 17.4, 10.4, 5.4, 2.4, 1.4, 2.4, 5.4, 10.4, 17.4, 26.4, 37.4, 50.4, 65.4, 82.4, 101.4] 
 y: [101.0, 82.0, 65.0, 50.0, 37.0, 26.0, 17.0, 10.0, 5.0, 2.0, 1.0, 2.0, 5.0, 10.0, 17.0, 26.0, 37.0, 50.0, 65.0, 82.0, 101.0]
f: 3.360000000000019
Optimization terminated successfully.
optimizal position:  [-4.00000011e-01 -5.25897060e-09]
minimal value:  1.0614222972874884e-13
  

Ответ №2:

Просто публикую альтернативное решение для «полноты»:

 from scipy.optimize import minimize

def f(params,y_,y):
    y0,y1 = params
    xy1 = [i*y1 for i in range(len(y_))]
    diff = [(y_[i]   y0   xy1[i] - y[i])**2 for i in range(len(y_))]
    return sum(diff)

y_ = [(x-3)**2   1.4 for x in range(-10,11,1)]
y= [x**2   1. for x in range(-10,11,1)]
x = [3*i for i in range(len(y_))]
print('x:',x)
print('y_:',y_,'n','y:',y)
print('f:',f([0,0],y_,y))

y0 = 0.
y1 = 0.
minimize(f, [y0, y1], args=(y,y_))