Python scipy.optimize.leastsq使用NaN调用目标函数

Python scipy.optimize.leastsq使用NaN调用目标函数,python,numpy,scipy,mathematical-optimization,Python,Numpy,Scipy,Mathematical Optimization,我正在使用来尝试在存在噪声的情况下将一些参数拟合到真实世界的数据中。目标函数偶尔会从minpack中使用NAN调用。这是scipy.optimize.leastsq的预期行为吗?在这种情况下,有没有比只返回NaN残差更好的选择 以下代码演示了该行为: import scipy.optimize import numpy as np xF = np.array([1.0, 2.0, 3.0, 4.0]) # Target value for fit NOISE_LEVEL = 1e-6 # Th

我正在使用来尝试在存在噪声的情况下将一些参数拟合到真实世界的数据中。目标函数偶尔会从minpack中使用NAN调用。这是scipy.optimize.leastsq的预期行为吗?在这种情况下,有没有比只返回NaN残差更好的选择

以下代码演示了该行为:

import scipy.optimize
import numpy as np

xF = np.array([1.0, 2.0, 3.0, 4.0]) # Target value for fit
NOISE_LEVEL = 1e-6 # The random noise level
RETURN_LEN = 1000  # The objective function return vector length

def func(x):
    if np.isnan(np.sum(x)):
        raise ValueError('Invalid x: %s' % x)
    v = np.random.rand(RETURN_LEN) * NOISE_LEVEL
    v[:len(x)] += xF - x
    return v

iteration = 0
while (1):
    iteration += 1
    x = np.zeros(len(xF))
    y, cov = scipy.optimize.leastsq(func, x)
    print('%04d %s' % (iteration, y))
雅可比矩阵正在进行数值计算。在产生式代码中,优化通常有效,除非初始估计值太好,曲面非常平坦,并且噪声淹没了用于数值计算雅可比矩阵的增量。在这种情况下,目标函数的残差像上面的代码示例一样显示为随机噪声,我不希望优化收敛


在此代码示例中,使用较小的“噪波”(NOISE)级别值(),因为您的问题定义在非线性问题(噪波)上使用线性解算器,解算器将崩溃,除非噪波级别低于显著性阈值

为了解决这个问题,您可以尝试使用非线性解算器。 例如,使用broyden1求解算法代替leastsq:

import scipy.optimize
import numpy as np

xF = np.array([1.0, 2.0, 3.0, 4.0]) # Target value for fit
NOISE_LEVEL = 1.e-6 # The random noise level
RETURN_LEN = 1000  # The objective function return vector length

def func(x):
    if np.isnan(np.sum(x)):
        raise ValueError('Invalid x: %s' % x)
    v = np.random.rand(RETURN_LEN) * NOISE_LEVEL

    v[:len(x)] += xF - x

    return v[:len(x)]

iteration = 0
while iteration < 10:
    iteration += 1
    x = np.random.rand(len(xF))
    y = scipy.optimize.broyden1(func, x)
    print('%04d %s' % (iteration, y))

似乎噪声和数值雅可比矩阵的组合将x射入远离的区域,从而导致NaN。这强烈表明优化器无法提供可靠的结果。这通常要求通过施加额外的约束来重新表述优化问题,使其不太不适定。也许使用受约束的优化器()可能是一种可行的解决方法。另外,放松终止条件可能会有所帮助。
import scipy.optimize
import numpy as np

xF = np.array([1.0, 2.0, 3.0, 4.0]) # Target value for fit
NOISE_LEVEL = 1.e-6 # The random noise level
RETURN_LEN = 1000  # The objective function return vector length

def func(x):
    if np.isnan(np.sum(x)):
        raise ValueError('Invalid x: %s' % x)
    v = np.random.rand(RETURN_LEN) * NOISE_LEVEL

    v[:len(x)] += xF - x

    return v[:len(x)]

iteration = 0
while iteration < 10:
    iteration += 1
    x = np.random.rand(len(xF))
    y = scipy.optimize.broyden1(func, x)
    print('%04d %s' % (iteration, y))
0001 [ 1.00000092  2.00000068  3.00000051  4.00000097]
0002 [ 1.0000012   2.00000214  3.00000272  4.00000369]
0003 [ 0.99999991  1.99999931  2.99999815  3.9999978 ]
0004 [ 1.00000097  2.00000198  3.00000345  4.00000425]
0005 [ 1.00000047  1.99999983  2.99999938  3.99999922]
0006 [ 1.00000024  2.00000021  3.00000071  4.00000136]
0007 [ 1.00000116  2.00000102  3.00000225  4.00000357]
0008 [ 1.00000006  2.00000002  3.00000017  4.00000039]
0009 [ 1.0000002   2.00000034  3.00000062  4.00000051]
0010 [ 1.00000137  2.0000015   3.00000193  4.00000344]