首页 > 解决方案 > scipy.optimize.curve_fit:max_nfev 的默认值坏了?

问题描述

scipy.optimize.curve_fit使用max_nfev参数调用时,我遇到了意外行为。该文档指出,额外kwargs的被传递给leastsqformethod='lm'least_squaresother。此外,如果提供,method则应默认为'trf'(即不是'lm'bounds。最后,least_squares采用参数,如果未提供(或显式传递为),则max_nfev默认为在其上进行曲线拟合的数组之一。100*len(x)max_nfev=Nonex

我有一个scipy.optimize.curve_fit失败的数据集(和匹配函数)。max_nfev正如预期的那样,例程放弃之前所需的时间线性取决于。但是,这次max_nfev=100*len(x)在调用中指定scipy.optimize.curve_fit和根本不传入之间有很大的不同max_nfev,这似乎与记录的行为背道而驰。

这是一个演示这一点的脚本:

import time
import numpy as np
import scipy.optimize

x, y = np.loadtxt('data.txt', unpack=True)

# Attempt curve fit
initial_guess = (1, 0)
bounds = ([-np.inf, 0], [np.inf, 15])
for max_nfev in (None, 1*len(x), 10*len(x), 100*len(x)):
    print('\nRunning with max_nfev = {}:'.format(max_nfev))
    t0 = time.time()
    try:
        scipy.optimize.curve_fit(
            lambda x, factor, exponent: factor*x**exponent,
            x,
            y,
            initial_guess,
            bounds=bounds,
            ftol=1e-10,
            maxfev=max_nfev,
        )
        deltat = time.time() - t0
        print('Succeeded after', deltat, 's')
    except RuntimeError:
        deltat = time.time() - t0
        print('Failed after', deltat, 's')

该脚本需要data.txt(24 KB) 中的数据集,您可以在此处下载。

在我的系统上,这个脚本的输出是

以 max_nfev = None 运行:
0.10752344131469727 秒后失败

以 max_nfev = 441 运行:
0.17525863647460938 秒后失败

以 max_nfev = 4410 运行:
1.732572078704834 秒后失败

以 max_nfev = 44100 运行:
17.796284437179565 秒后失败

我希望第一个 ( max_nfev=None) 和最后一个 ( max_nfev=100*len(x)) 调用花费大致相同的时间来失败。为了增加谜团,似乎max_nfev我与其通过,不如通过maxfev,这不是 的有效参数least_squares,而是maxfev由 . 采用的等效参数leastsq

我是否误解了某些东西,或者文档或实施有误?

我在 {SciPy 1.1.0, Python 3.6.5} 和 {SciPy 1.2.0, Python 3.7.1} 下都遇到了这种情况。

标签: pythonpython-3.xoptimizationscipycurve-fitting

解决方案


我希望第一个 (max_nfev=None) 和最后一个 (max_nfev=100*len(x)) 调用花费大致相同的时间

在 scipy.optimize._lsq.trf.py 的第 250 行设置断点:

    if max_nfev is None:
        max_nfev = x0.size * 100

此时x0只有两个元素,因此传入的调用None等效地传入 200。x0来自p0,默认为[1 0]

基于此,您观察到的时间确实有意义。


推荐阅读