SciPy.optimize.least_squares() Вопросы о целевой функции

Я пытаюсь минимизировать сильно нелинейную функцию, оптимизируя три неизвестных параметра a, b и c0. Я пытаюсь воспроизвести некоторые основные уравнения шарика рулетки казино в Python 3.

Вот ссылка на исследовательскую работу: http://www.dewtronics.com/tutorials/roulette/documents/Roulette_Physik.pdf

Я буду ссылаться на уравнения (35) и (40) в статье. По сути, я измеряю секундомером круги шарика рулетки, вращающегося на колесе. Для каждого последующего круга время круга будет увеличиваться из-за потери импульса из-за неконсервативных сил трения. Затем я беру эти измерения времени и подгоняю уравнение (35) с помощью метода наименьших квадратов Левенберга-Марквардта в уравнении (40).

У меня двоякий вопрос: (1) я использую метод scipy.optimize.least_squares()='lm' и не знаю, как написать целевую функцию! Прямо сейчас у меня есть функция, написанная точно так же, как в документе:

def fall_time(k,a,b,c0):

    F = (1 / (a * b)) * (c0 - np.arcsinh(c0) * np.exp(a * k * 2 * np.pi))

    return F

def parameter_estimation_function(x0,tk):

    a = x0[0]
    b = x0[1]
    c0 = x0[2]

    S = 0

    for i,t in enumerate(tk):

        k = i + 1

        S += (t - fall_time(k,a,b,c0))**2

    return [S,1,1]

sol = least_squares(parameter_estimation_function,[0.1,0.8,-0.1],args=([tk1]),method='lm',jac='2-point',max_nfev=2000)

print(sol)

Так вот, в примерах документации я ни разу не видел, чтобы целевая функция была написана так, как она у меня есть. В документации целевая функция всегда возвращает остаток, а не квадрат остатка. Кроме того, в документации никогда не используется сумма! Поэтому мне интересно, автоматически ли сумма и квадрат обрабатываются под капотом least_squares()?

(2) Возможно, мой второй вопрос является результатом того, что я не понимаю, как записать целевую функцию. Но в любом случае, у меня возникли проблемы с тем, чтобы алгоритм сходился к минимуму. Я знаю, что это потому, что алгоритм Левенберга «жадный» и останавливается около ближайших минимумов, но я полагал, что смогу, по крайней мере, сойтись примерно с одним и тем же результатом при разных начальных предположениях. С небольшими изменениями в первоначальном предположении я получаю результаты параметров с разными знаками. Кроме того, мне еще предстоит найти комбинацию начальных предположений, которая позволила бы алгоритму сойтись! Он всегда истекает, прежде чем находит решение. Я даже увеличил количество вычислений функций до 10 000, чтобы посмотреть, так ли это. Но безрезультатно!

Возможно, кто-то может пролить свет на мои ошибки здесь! Я все еще относительно новичок в python и библиотеке scipy!

Вот несколько примеров данных для tk, которые я измерил самостоятельно по видео здесь: https://www.youtube.com/watch?v=0Zj_9ypBnzg

tk = [0.52,1.28,2.04,3.17,4.53,6.22]
tk1 = [0.51,1.4,2.09,3,4.42,6.17]
tk2 = [0.63,1.35,2.19,3.02,4.57,6.29]
tk3 = [0.63,1.39,2.23,3.28,4.70,6.32]
tk4 = [0.57,1.4,2.1,3.06,4.53,6.17]

Спасибо


person denbjornen505    schedule 29.03.2017    source источник


Ответы (1)


1) Да, как вы подозревали, сумма и квадрат остатков обрабатываются автоматически.

2) Трудно сказать, так как я не очень хорошо знаком с проблемой (например, сколько существует локальных минимумов, что представляет собой «разумный» результат и т. д.). Я могу исследовать больше позже.

Но для удовольствия я поиграл с некоторыми значениями, чтобы посмотреть, что произойдет. Например, вы можете просто заменить константу 1/b автономной переменной b_inv, и это немного стабилизирует результаты. Вот код, который я использовал для проверки результатов. (Обратите внимание, что я переписал целевую функцию для краткости. Она просто использует поэлементные операции массивов numpy без изменения общего результата.)

import numpy as np
from scipy.optimize import least_squares

def fall_time(k,a,b_inv,c0):
    return (b_inv / a) * (c0 - np.arcsinh(c0) * np.exp(a * k * 2 * np.pi))

def parameter_estimation_function(x,tk):
    return np.asarray(tk) - fall_time(k=np.arange(1,len(tk)+1), a=x[0],b_inv=x[1],c0=x[2])

tk_samples = [
    [0.52,1.28,2.04,3.17,4.53,6.22],
    [0.51,1.4,2.09,3,4.42,6.17],
    [0.63,1.35,2.19,3.02,4.57,6.29],
    [0.63,1.39,2.23,3.28,4.70,6.32],
    [0.57,1.4,2.1,3.06,4.53,6.17]
    ]

for i in range(len(tk_samples)):
    sol = least_squares(parameter_estimation_function,[0.1,1.25,-0.1],
        args=(tk_samples[i],),method='lm',jac='2-point',max_nfev=2000)
    print(sol.x)

с консольным выводом:

[ 0.03621789  0.64201913 -0.12072879]
[  3.59319972e-02   1.17129458e+01  -6.53358716e-03]
[  3.55516005e-02   1.48491493e+01  -5.31098257e-03]
[  3.18068316e-02   1.11828091e+01  -7.75329834e-03]
[  3.43920725e-02   1.25160378e+01  -6.36307506e-03]
person CrepeGoat    schedule 26.12.2017
comment
Fwiw, least_squares( ... method='trf', ftol=1e-4, verbose=2 ) печатает строку на каждой итерации. (К сожалению, у method='lm' нет verbose.) - person denis; 14.09.2018
comment
@CrepeGoat извиняется, но обнаружил, что это diff, чтобы обдумать это - могу ли я уточнить, что least_square каким-то образом минимизирует SSR, передавая разные значения после предоставления начальных значений, и оптимизирует первый параметр (в данном случае список параметров) до parameter_estimation_function? если у меня есть другие параметры, которые мне нужно передать в parameter_estimation_function, которые не требуют оптимизации, но зависят от текущего значения i, как я могу передать эти параметры в parameter_estimation_function? Спасибо! - person AiRiFiEd; 23.02.2019
comment
@AiRiFiEd, похоже, ты правильно понял. (Чтобы было ясно, вам нужен «i» только в том случае, если вы оптимизируете несколько раз с разными параметрами; если вам нужно запустить только одну оптимизацию, вам не нужен цикл.) Чтобы передать параметр, который зависит от «i» (извините за галочки, на моем планшете), вы делаете что-то похожее на «tk_samples[i]» в приведенном выше примере: добавляете параметр к вашей целевой функции «parameter_estimation_function» (в данном случае это было «tk» ) и добавьте значение к вызову функции 'least_squares' в кортеже 'args'. Это помогает? - person CrepeGoat; 23.02.2019
comment
Я чувствую, что просто повторил то, что вы только что сказали, прошу прощения. Если это не помогло, можете ли вы перефразировать то, на чем вы зациклились? - person CrepeGoat; 23.02.2019
comment
@CrepeGoat спасибо за быстрый ответ и извините за неясность! Я не могу опубликовать свой вопрос в отдельном сообщении, так как это будет дубликат... ценю вашу помощь здесь. Предполагая, что для каждого набора tk_samples есть другой набор значений, скажем, [1,2] для [0.52,1.28,2.04,3.17,4.53,6.22], а [1,2] являются входными данными для fall_time -fall_time(k,a,b_inv,c0, new_param1, new_param2), но я хочу оптимизировать только в отношении k, a, b_inv и c0, как мне передать [1,2] в least_squares? - person AiRiFiEd; 23.02.2019
comment
@AiRiFiEd tbh В любом случае я бы, вероятно, просто опубликовал его как новый вопрос, сославшись на этот вопрос для удобства. Ваша проблема на 95% похожа на эту, но ваш вопрос касается дополнительных 5% разницы. Если он будет помечен как дубликат, это нормально, верно? Просто мое мнение. - person CrepeGoat; 23.02.2019
comment
@AiRiFiEd в любом случае. так что для каждой проблемы оптимизации у вас есть список tk_samples и два других параметра, таких как p1, p2? Я бы заменил tk_samples список списков на opt_args список кортежей, где каждый кортеж имеет параметры, необходимые для каждой отдельной оптимизации. Например, opt_args = [([0.52,1.28,2.04,3.17,4.53,6.22], 1, 2), ...], а затем sol = least_squares(..., args=opt_args[i], ...). (Обратите внимание, что многоточие просто означает, что есть другие вещи, которые я не хочу явно печатать.) Дайте мне знать, если это сработает для вас. - person CrepeGoat; 23.02.2019
comment
@CrepeGoat извинения, я мог только реализовать код на работе - у меня есть некоторые другие ошибки, но я считаю, что ваш ответ решает мою первоначальную проблему. Спасибо большое за вашу помощь! - person AiRiFiEd; 26.02.2019
comment
@AiRiFiEd рад помочь :) - person CrepeGoat; 26.02.2019