最小二乘拟合正弦幂级数

时间:2015-11-07 00:23:33

标签: python numpy scipy mathematical-optimization curve-fitting

我试图适应形式的功能:

enter image description here

其中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术语导致溢出错误。这不是函数本身的问题,因为这里的单项式乘以它们的系数非常小。

我的问题是:

  1. 我上面做过的代码是否有错误?
  2. 还是有其他问题吗?
  3. 如果我的假设是正确的,有没有办法预处理拟合函数,那么雅可比行为更好?也许我可以适应数据和时间的对数等等。
  4. 谢谢!

    编辑:忘记原始功能形式的方块

1 个答案:

答案 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