Я пытаюсь подобрать кинетическую модель роста и распада населения четырех переменных A, B, C, D в химической системе. Я пытаюсь решить следующую систему уравнений, которую я приложил в матричной форме:
где t - временной шаг, k1, k2, k3 - константы в экспоненциальной функции. Я хочу подгонять кривые на основе этих уравнений для решения для k1, k2 и k3, учитывая мои популяции A, B, C, D.
Для этого я использую optimize.curve_fit, t - временной шаг в массиве (1000), X - матрица (4,1000) и где u и w - две матрицы:
from scipy import optimize
def func(t,X,k1,k2,k3):
u = np.array([[1,0,0],
[-k1/(k1+k2-k3),k1/(k1+k2-k3),0],
[(k1*k3)/((k1+k2-k3)*(k1+k2)),-k1/(k1+k2k3),k1/(k1+k2)],
[-k2/(k1+k2),0,k2/(k2+k1)]],dtype=float)
w = np.array([[np.exp(-t*(k1+k2))],
[np.exp(-t*k3)],
[1]])
return X*np.dot(u,w)
X = np.array([A,B,C,D]) # A,B,C,D are (1000,) arrays
# X.shape = (4, 1000)
# t.shape = (1000,)
optimize.curve_fit(func,t,X,method='lm')
Когда я запускаю этот фрагмент кода, я получаю следующий вывод:
ValueError: объект слишком глубокий для желаемого массива
Ошибка: результат вызова функции не является подходящим массивом поплавков.
Я видел в подобном сообщении, что формы массивов важны, но, насколько я могу судить, они верны.
Может ли кто-нибудь предложить, где проблема может быть в этом коде, и как я могу лучше всего решить проблему k1, k2, k3 с помощью функции подгонки кривой?
Спасибо
Как я уже упоминал в своем комментарии, вам не нужно передавать X
на func
. @WarrenWeckesser кратко объясняет, почему. Итак, вот как func
должен быть:
def func(t,k1,k2,k3):
u = np.array([[1,0,0],
[-k1/(k1+k2-k3),k1/(k1+k2-k3),0],
[(k1*k3)/((k1+k2-k3)*(k1+k2)),-k1/(k1+k2*k3),k1/(k1+k2)],
[-k2/(k1+k2),0,k2/(k2+k1)]],dtype=float)
w = np.array([np.exp(-t*(k1+k2)),
np.exp(-t*k3),
np.ones_like(t)]) # must match shapes with above
return np.dot(u,w).flatten()
Выход в конце сплющен, потому что иначе он выдаст ошибку с curve_fit
. Теперь мы проверяем это:
from scipy.optimize import curve_fit
t = np.arange(1000)*0.01
data = func(t, *[0.5, 2, 1])
data +=np.random.normal(size=data.shape)*0.01 # add some noise
po, pcov = curve_fit(func,t, data.flatten(), method='lm') #data must also be flattened
print(po)
#[ 0.50036411 2.00393807 0.99694513]
plt.plot(t, data.reshape(4,-1).T, t, func(t, *po).reshape(4,-1).T)
Оптимизированные значения довольно близки к оригинальным, и подгонка кажется хорошей
func
не нуженX
параметр, вашt
является й парами. Кроме того, третий элемент в матрицеw
имеет длину один, он должен иметь длину 1000, чтобы соответствовать другим двум элементам вышеX
здесь плохое имя для переменной; Я должен назвать это `` Y, так что мой параметр x равенt
а мой параметр y равенY
, гдеY
- матрица формы (4,1000). Для третьего элемента матрицыw
я просто хочу, чтобы он был константой, поэтому, когда скалярное произведение берется с матрицей u, третий столбец вu
возвращается как константа.