Кусочная функция lmfit - PullRequest
       10

Кусочная функция lmfit

0 голосов
/ 03 февраля 2019

Я пытаюсь определить кусочную функцию для подгонки библиотекой lmfit в Python.У меня проблема с параметром, который я определил для функции, которая не будет оцениваться вместе с данными, которые я отправляю.

У меня есть один пример, похожий на мой здесь .Тем не менее, функция векторизации, описанная в ответе, не выдает желаемых значений, и при чтении документации она, похоже, не является ответом на мое решение.Я также использовал scipy.optimize.leastsq, но у меня возникла та же проблема с lmfit, описанная ниже.

У меня определена остаточная функция, такая как

from lmfit import minimize, Parameters, Model

def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    if(param2 < x):
        p = 1
    else:
        p = param1*x + param2
    return p - y 

params = Parameters()
params.add('one', value=1)
params.add('two', value=2)
out = minimize(residual, params,args=(y,x))

Я также попытался определить функциютакой, что

  def f(param1,param2,x):
    if(param2 < x):
        p = 1
    else:
        p = param1*x + param2
    return p

  def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    return f(param1,param2,x) - y

Я также попытался встроить с помощью лямбда-функции.

Я получаю сообщение об ошибке «Значение истинности массива с более чем одним элементом неоднозначно».Когда я получил ошибку, было понятно, почему это произошло, потому что (param2

Похоже, что lmfit также работает немного по-другому по сравнению с nlinfit, потому что мы должны всегда возвращать остатки (модель - y), в то время как nlinfit выводит результат, как только задана функция, что, я не уверен, могло бытьдругая проблема.

Итак, еще раз повторяю, мой главный вопрос заключается в том, существует ли метод определения кусочной функции, позволяющий сравнивать параметр с набором данных.

Буду признателен за любую помощь или объяснение,спасибо!

1 Ответ

0 голосов
/ 04 февраля 2019

Вместо (param2 < x) (где param2 - это число с плавающей запятой, а x - это пустой массив), вы хотите использовать numpy.where.Вы можете попробовать:

def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    p = param1 * x + param2
    p[np.where(param2 < x)] = 1.0 
    return p - y

Я также должен предупредить вас о потенциальной проблеме с этим подходом к тому, чтобы переменная была границей для кусочной функции.

В нелинейных подгонках переменныевсегда значения с плавающей точкой (непрерывные, недискретные).По мере того, как выполняется подбор, он вносит небольшие корректировки в значения и видит, как это небольшое изменение влияет на результат.В вашем подходе параметр 'two' используется как для перехода между частями, так и для смещения линии - это хорошо.

Если параметр используется только в качестве перехода, он может не работать.Рассмотрим, скажем, x=np.array([0, 1., 2., 3., 4., ..., 20.0]).Наличие two = 10.5 и two=10.4 даст тот же результат.В этом случае подгонка не сможет изменить значение two: она попытается сделать очень небольшое изменение, не увидит изменений в результате и сдастся.

Итак, либо убедитесь, что two также используется в других местах вашей реальной модели (при условии, что ваша реальная модель более сложна, чем приведенный пример), или рассмотрите возможность использования более плавного перехода, а не жесткого изменения частей.Я считаю, что функция ошибок ширины ~ расстояния между x точками часто работает.В зависимости от характера вашей проблемы, вы можете попробовать что-то вроде этого:

 from scipy.special import erf, erfc
 def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    dx = (max(x) - min(x))/(len(x)-1)
    xhi = (erf((x-param2)/dx) + 1)/2.0
    xlo = (erfc((x-param2)/dx) + 1)/2.0
    p = xlo*1.0 + xhi*(param1*x + param2)
    # note: did you really want?
    # p = xlo*param + xhi*(param1*x + param2)
    # p = param2 + xhi*param1*x
    return p - y

Надеюсь, это поможет.

...