scipy.optimize.curve_fit: значение по умолчанию для max_nfev нарушено? - PullRequest
0 голосов
/ 03 марта 2019

У меня неожиданное поведение при вызове scipy.optimize.curve_fit с аргументом max_nfev.В документации говорится, что дополнительные kwargs передаются leastsq для method='lm' и least_squares в противном случае.Кроме того, method должно по умолчанию 'trf' (т.е. не 'lm'), если указано bounds.Наконец, least_squares принимает аргумент max_nfev, который по умолчанию равен 100*len(x), если не предоставлен (или явно передан как max_nfev=None), x является одним из массивов, для которых выполняется подгонка кривой.

У меня есть набор данных (и функция сопоставления), в котором 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 КБ), который вы можете скачать здесь .

Вкл.В моей системе вывод этого сценария:

Запуск с max_nfev = Нет:
Ошибка после 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}.

1 Ответ

0 голосов
/ 03 марта 2019

Я ожидаю, что первый (max_nfev = None) и последний (max_nfev = 100 * len (x)) вызов займет примерно одинаковое количество времени

Установите точку останова настрока 250 scipy.optimize._lsq.trf.py:

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

На данный момент x0 имеет только два элемента, поэтому ваш вызов, переданный в None, мог бы эквивалентно пройти в 200. x0 пришло от p0, по умолчанию [1 0].

Исходя из этого, ваши наблюдаемые сроки do имеют смысл.

...