'ValueError: не удалось передать входной массив из shape (5,5) в shape (5)' для scipy.optimize-minimal - PullRequest
0 голосов
/ 02 марта 2019

У меня есть функция y(T,x,p).У меня есть данные для T, p, x, y.С этими данными я хочу знать коэффициенты, чтобы я мог использовать функцию, чтобы получить любой y, который я хочу.До сих пор у меня есть это с использованием scipy.optimize.minimize и method='cobyla':

import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt

T = np.array([262,257,253,261,260,243], dtype=float)
p = np.array([25,22,19,24,24,14], dtype=float)
x = np.array([0.1,0.1,0.2,0.2,0.3,0.3], dtype=float)
y = np.array([10,9,13,16,20,12], dtype=float)

T2 = np.array([[262,262,262,262,262],[257,257,257,257,257],[253,253,253,253,253],[261,261,261,261,261],[260,260,260,260,260],[243,243,243,243,243]])
p2 = np.array([[25,25,25,25,25],[22,22,22,22,22],[19,19,19,19,19],[24,24,24,24,24],[24,24,24,24,24],[14,14,14,14,14]])
x2 = np.array([[0,0.25,0.5,0.75,1],[0,0.25,0.5,0.75,1],[0,0.25,0.5,0.75,1],[0,0.25,0.5,0.75,1],[0,0.25,0.5,0.75,1],[0,0.25,0.5,0.75,1]])

def func(pars, T, x, p): #my actual function
    a,b,c,d,e,f = pars
    return  x * p + x * (1 - x) * (a + b * T + c * T ** 2 + d * x + e * x * T + f * x * T ** 2) * p


def resid(pars): #residual function
    return ((func(pars, T, x, p) - y) ** 2).sum()

def der(pars): #constraint function: Derivation of func() after x positive everywhere
    a,b,c,d,e,f = pars
    return p2+p2*(2*x2*a+2*x2*b*T2+2*x2*c*T2**2+3*x2**2*d+3*x2**2*e*T2+3*x2**2*f*T2**2)+p2*(a+b*T2+c*T2**2+2*x2*d+2*e*x2*T2+2*f*x2*T2**2)


con1 = (dict(type='ineq', fun=der))
pars0 = np.array([0,0,0,0,0,0])
res = minimize(resid, pars0, method='cobyla',options={'maxiter': 500000}, constraints=con1)

print("a = %f , b = %f, c = %f, d = %f, e = %f, f = %f" % (res.x[0], res.x[1], res.x[2], res.x[3], res.x[4], res.x[5]))

T0 = 262.741   # plot an example graph y(x) for a certain T and p
x0 = np.linspace(0, 1, 100)
p0 = 26
fig, ax = plt.subplots()
fig.dpi = 80
ax.plot(x0, func(res.x, T0, x0, p0), '-')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

Поскольку мои данные для x достигают только 0,3, ограничение (что деривация после x везде положительна)соответствовать только для этой области.Для более высоких значений x это не соответствует.Поэтому я решил определить многомерные массивы T2, x2, p2 со случайными значениями от 0 до 1 для x и использовать их в функции ограничения def der().Идея заключалась в том, что каждое значение T и p имеет диапазон x от 0 до 1. К сожалению, я получаю следующую ошибку:

ValueError: operands could not be broadcast together with shapes (6,5) (6,)

Я знаю, что есть много других вопросов с этимошибка, но я не могу перенести ее в мою реальную проблему, поэтому любая помощь будет полезна.

1 Ответ

0 голосов
/ 03 марта 2019

Ошибка возникает из-за того, что решатели пытаются сопоставить выходные данные функции der(pars) с вектором, полным нулей.По сути, вы должны построить свою производную так, чтобы возвращение функции der(pars) имело форму (6,1).Вы правильно рассчитали якобиан функции.Чтобы сгладить якобиан, вы можете использовать следующий подход:

Поскольку вас интересует только ограниченное неравенство, а не каждое значение якобиана, вы можете вернуть минимум каждой строки.Если минимум больше нуля, чем весь якобиан.Попробуйте этот код для вашей функции der(pars).функция .min(axis=1) возвращает минимальное значение каждой строки в якобиане:

def der(pars): #constraint function: Derivation of func() after x positive everywhere
    a,b,c,d,e,f = pars
    jacobian = p2+p2*(2*x2*a+2*x2*b*T2+2*x2*c*T2**2+3*x2**2*d+3*x2**2*e*T2+3*x2**2*f*T2**2)+p2*(a+b*T2+c*T2**2+2*x2*d+2*e*x2*T2+2*f*x2*T2**2)
    return jacobian.min(axis=1)

Это дает следующий результат, используя оставшуюся часть вашего кода:

a = 1.312794 , b = -0.000001, c = -0.000084, d = 1.121216, e = -0.003784, f = 0.000129

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...