У вас есть два избыточных параметра.Версия функции, которую вы называете находящейся работой, это exp(a + b*(c - d*x))
.Выражение
a + b*(c - d*x)
можно записать
a + b*c - b*d*x = A + B*x
, где A = a + b*c
и B = -b*d
.Таким образом, вы можете упростить вашу функцию до exp(A + B*x)
.Проблема с наличием слишком большого количества параметров состоит в том, что решение не является изолированным - пространство решений имеет то же измерение, что и число избыточных параметров.Это приводит к тому, что матрица Гессе является единственной.Из-за обычной числовой неточности матрица Гессе в избыточном случае не будет точно единственного числа, но будет плохо обусловлена и почти единственной.Ковариационная матрица получена из обратной матрицы Гессе, поэтому, если матрица Гессиана близка к единственному, вычисление ковариации является численно нестабильным и не должно вызывать доверия.
Вот полный скрипт, демонстрирующийПроблема:
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def func(x, a, b, c, d):
return np.exp(a + b*(c - d*x))
def func2(x, a, b):
return np.exp(a - b*x)
np.random.seed(8675309)
x = np.linspace(0, 10, 16)
y = (10*np.exp(-0.5*x)*np.random.lognormal(sigma=0.25, size=len(x))
+ 0.5*np.random.rand(len(x)))
p, pcov = curve_fit(func, x, y)
print("p:", p)
print("pcov:")
print(pcov)
print()
p2, pcov2 = curve_fit(func2, x, y)
print("p2:", p2)
print("pcov2:")
print(pcov2)
plt.plot(x, y, 'bo', label="data")
xx = np.linspace(0, 10, 101)
yy = func(xx, *p)
plt.plot(xx, yy, 'k--', label="4 parameter fit")
yy2 = func2(xx, *p2)
plt.plot(xx, yy2, 'g', linewidth=4, alpha=0.3, label="2 parameter fit")
plt.legend(shadow=True)
plt.grid(True)
plt.xlabel('x')
plt.show()
Сценарий генерирует следующий график:
Использовали ли мы два параметра или четыре, curve_fit
нашел то же решение.
Вот распечатка скрипта:
p: [1.15386327 1.18656718 1.09383746 0.47713239]
pcov:
[[-2.43958994e+12 -7.92454940e+12 9.37347302e+12 3.19227931e+12]
[-3.98689093e+13 -1.05598664e+13 4.33789687e+13 4.25387501e+12]
[ 3.88631613e+13 1.64330041e+13 -4.79524254e+13 -6.61977557e+12]
[ 1.60605592e+13 4.25387505e+12 -1.74745310e+13 -1.71360622e+12]]
p2: [2.45177495 0.56614914]
pcov2:
[[0.00143014 0.00077371]
[0.00077371 0.00130843]]
pcov
, результат подбора из четырех параметров, по сути, мусор.В этом примере все диагональные элементы отрицательны, а матрица не симметрична.
pcov2
, ковариационная матрица для подгонки двух параметров в порядке.
Мораль этой истории: не используйте избыточные параметры в функции модели, если вам нужно использовать ковариационную матрицу, возвращаемую curve_fit
.
Кстати, как вы уже отметили,Вы можете переписать exp(A + B*x)
как exp(A)*exp(B*x)
, а затем определить C = exp(A)
, чтобы выразить свою функцию как C*exp(B*x)
.Затем вы можете использовать параметры B
и C
вместо A
и B
в curve_fit
.Просто помните, что эта версия позволяет C
быть меньше или равным 0, поэтому возможен ответ, такой как -2*exp(-3*x)
.Отрицательная функция, подобная этой, невозможна при использовании exp(A + B*x)
.Чтобы обе параметризации имели одинаковые возможные решения, вы должны использовать аргумент bounds
для ограничения C
.