Здесь у вас есть различные проблемы ограничения: во-первых, выбор решателя, который сильно влияет на то, какую оптимизацию вы можете выполнять (ограниченную, ограниченную и т. Д.).Кроме того, в вашем случае вы заинтересованы в параметрах и располагаете предопределенным набором (x, y)
, поэтому вам следует обрабатывать данные многомерным способом для вычислений, связанных с (x,y)
.Тем не менее, определение ограничений, которые вы использовали, насколько мне известно, подходит для одномерных выходов.Поэтому, как предполагает SO-вопрос , использование градиента является хорошей идеей.
К сожалению, при тестировании этого по вашему случаю результаты не были убедительными для меня, несмотря на безошибочный запуск кода.Немного подправив ваш код, мне удалось найти достойный обходной путь, но я не уверен, что он лучший.Моя идея состоит в том, чтобы использовать Nelder-Mead Solver
и использовать ограничение равенства, чтобы убедиться, что ваш вектор производных является положительным.Код следующий:
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
np.set_printoptions(precision=3)
# init data
sulphur = np.array([ 71., 82., 50., 113., 153., 177., 394., 1239., 2070., 2662., 3516., 4000., 4954., 6314.])
temperature = np.array([ 70., 90., 140., 165., 210., 235., 265., 330., 350., 390., 410., 435., 540., 580.])
# init x and y
x = sulphur
y = temperature
# compute initial guess
initial = list(reversed(np.polyfit(x, y, 3)))
Nfeval = 1
# define functions
polynomial = lambda p, x: p[0] + p[1]*x + p[2]*x**2 + p[3]*x**3
derivative = lambda p, x: p[1] + 2*p[2]*x + 3*p[3]*x**2
def constraint(p):
if (derivative(p, x) > 0).all() : return 0
else : return -1
def callback(p):
global Nfeval
print("Evaluations nbr: %3s | p: %5s |cons: %3s" % (Nfeval,
p,
constraint(p)))
Nfeval += 1
func = lambda p: np.linalg.norm(y - polynomial(p, x))
cons = {'type' : 'eq', 'fun' : constraint}
res = optimize.minimize(func,
x0 = np.array(initial),
method ='Nelder-Mead',
constraints = cons,
callback = callback)
print('----------------------------------------------------------------------------------------')
print(res)
# plot results
f = plt.figure(figsize=(10,4))
ax1 = f.add_subplot(131)
ax2 = f.add_subplot(132)
ax3 = f.add_subplot(133)
ax1.plot(x, y,'ro', label = 'data')
ax1.plot(x, polynomial(res.x, x), label = 'fit using optimization', color="orange")
ax1.legend(loc=0)
ax2.plot(x, derivative(res.x, x), label ='derivative')
ax2.legend(loc=0)
ax3.plot(x, y,'ro', label = 'data')
ax3.plot(x, polynomial(initial, x), label = 'fit using polyfit', color="green")
ax3.legend(loc=0)
plt.show()
Выход:
.
.
.
Evaluations nbr: 95 | p: [ 1.400e+02 1.830e-01 -4.203e-05 3.882e-09] |cons: 0
Evaluations nbr: 96 | p: [ 1.400e+02 1.830e-01 -4.203e-05 3.882e-09] |cons: 0
Evaluations nbr: 97 | p: [ 1.400e+02 1.830e-01 -4.203e-05 3.882e-09] |cons: 0
Evaluations nbr: 98 | p: [ 1.400e+02 1.830e-01 -4.203e-05 3.882e-09] |cons: 0
----------------------------------------------------------------------------------------
final_simplex: (array([[ 1.400e+02, 1.830e-01, -4.203e-05, 3.882e-09],
[ 1.400e+02, 1.830e-01, -4.203e-05, 3.882e-09],
[ 1.400e+02, 1.830e-01, -4.203e-05, 3.882e-09],
[ 1.400e+02, 1.830e-01, -4.203e-05, 3.882e-09],
[ 1.400e+02, 1.830e-01, -4.203e-05, 3.881e-09]]), array([159.565, 159.565, 159.565, 159.565, 159.565]))
fun: 159.5654373399882
message: 'Optimization terminated successfully.'
nfev: 168
nit: 99
status: 0
success: True
x: array([ 1.400e+02, 1.830e-01, -4.203e-05, 3.882e-09])
Сюжеты: