我试图适应形式的功能:
其中A和B是固定常数。在scipy中,我通常(我认为合理的规范)方法就是这样:
def func(t, coefs):
phase = np.poly1d(coefs)(t)
return A * np.cos(phase) + B
def fit(time, data, guess_coefs):
residuals = lambda p: func(time, p) - data
fit_coefs = scipy.optimize.leastsq(residuals, guess_coefs)
return fit_coefs
这样可行,但我想提供一个解析雅可比行列式来改善收敛。因此:
def jacobian(t, coefs):
phase = np.poly1d(coefs, t)
the_jacobian = []
for i in np.arange(len(coefs)):
the_jac.append(-A*np.sin(phase)*(t**i))
return the_jac
def fit(time, data, guess_coefs):
residuals = lambda p: func(time, p) - data
jac = lambda p: jacobian(time, p)
fit_coefs = scipy.optimize.leastsq(residuals, guess_coefs,
Dfun=jac, col_deriv=True)
即使订单为2或更低,这也不起作用。使用optimize.check_gradient()快速检查也不会产生积极的结果。
我几乎可以肯定Jacobian和代码是正确的(虽然请纠正我)并且问题更为基础:雅各比派中的t ** i术语导致溢出错误。这不是函数本身的问题,因为这里的单项式乘以它们的系数非常小。
我的问题是:
谢谢!
编辑:忘记原始功能形式的方块
答案 0 :(得分:5)
poly1D
函数首先具有最高系数,而雅可比函数首先假设最低系数。如果在jacobian
中您创建了返回语句return the_jac[::-1]
(并且还修复了更明显的拼写错误),则您的函数将通过optimize.check_gradient()
并在leastsq()
中正常工作。
此处还有关于数值稳定性的进一步问题。如果您有大的 t 值和大量系数,则很容易出现数值精度问题:例如,在32位精度中,如果多项式的计算结果大于10 ^ 8,正弦曲线的相位将在尾数中完全丢失,正弦评估的结果基本上是垃圾!
您可以通过在多项式中使用模幂运算来解决这个问题:基本上您在多项式的每个项中关注的是(a_k t ** k) % p
,其中p = 2 * np.pi
是正弦曲线。对于具有t
的大(a_k * (t % (p / a_k)) ** k) % p
,您可以将此模块指数计算为更高的精度;对于大k
的准确性来说,事情变得有点复杂。有关此类内容的详细讨论,请参阅this answer。