Параметры соответствия ограничения Python LMFIT

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

Например, в следующем коде я подгоняю свои данные для оптимизации значений A, B и C. Но я также хочу, чтобы отношение A к B было равным pi / 4, умноженному на некоторое целое число. Есть ли способ наложить это ограничение?

from lmfit import  Model
import numpy
from numpy import cos, sin, pi, linspace

Загрузить данные:

data = numpy.genfromtxt('data')
axis = numpy.genfromtxt('axis')

Определите функцию:

def func(x, A, B, C):
return (A*cos(x)*cos(x) + B*sin(x)*sin(x) + 2*C*sin(x)*cos(x))**2

Я должен сделать первоначальное предположение о своих параметрах:

a = 0.009 
b = 0.3 
c = 0.3 

Затем создайте модель, соответствующую моей функции:

func_model = Model(func)

Подгоните функцию к входным данным с начальными предположениями (A = a, B = b, C = c):

result = func_model.fit(data, x=axis, A = a, B = b, C = c) 
fitted_vals = result.best_values #dictionary structure
Afit = fitted_vals['A']
Bfit = fitted_vals['B']
Cfit = fitted_vals['C']

Как я могу убедиться, что отношение Afit к Bfit равно числу pi / 4, умноженному на целое число?

Если это невозможно, знает ли кто-нибудь о программном обеспечении, в котором есть такая возможность?


person Ross G    schedule 10.05.2018    source источник


Ответы (2)


Проблема со стандартной подгонкой - это оценка якобиана. Если параметр дискретный, производная почти всюду равна нулю. Обходной путь может заключаться в использовании leastsq с самоопределяемой функцией остатка и дополнительным предоставлением производных. Можно установить параметр дискретным в функции невязки, но пусть он будет непрерывным по производной. Я не говорю, что это общее решение проблемы такого типа, но в случае функции OP оно работает вполне нормально.

Изменить - код будет:

# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import leastsq

def f0( x, A, B, C ):
    return ( A * np.cos( x )**2 + B * np.sin( x )**2 + 2 * C * np.sin( x ) * np.cos( x ) )

def func(x, A, B, C):
    return f0( x, A, B, C )**2

a = 0.009
b = 0.3
c = 0.4

xList = np.linspace( -1, 6, 500 )
yList = np.fromiter( ( func( x, a, b, c ) for x in xList ), np.float )


def residuals( p, x, y ):
    return func(x, p[0], int(p[1]) * np.pi / 2. * p[0], p[2] ) - y

def dfunc( p, x, y ):     #Derivative
    return [ 
        f0( x, p[0], int( p[1] ) * np.pi / 2. * p[0] , p[2] ) * ( np.cos( x )**2 + p[1] * np.pi / 2. * np.sin( x )**2 ),
        f0( x, p[0], int( p[1] ) * np.pi / 2. * p[0] , p[2] ) * ( p[0] * np.pi / 2.* np.sin( x )**2 ),
        f0( x, p[0], int( p[1] ) * np.pi / 2. * p[0] , p[2] ) * ( 2 * np.sin( x ) * np.cos( x ) ),
     ]

plsq, cov, infodict, mesg, ier = leastsq( residuals, [ 0.009, .3/.01, .4 ], args=( xList, yList ), Dfun=dfunc, col_deriv=1, full_output=True )

fit = func(xList, plsq[0], int( plsq[1] ) * np.pi / 2. * plsq[0],  plsq[2] )
print plsq
print int( plsq[1] ) 
fig1 = plt.figure( 1, figsize=( 6, 4 ), dpi=80 )
ax = fig1.add_subplot( 1, 1, 1 )
ax.plot( xList, yList )
ax.plot( xList, fit, ls='--')
plt.show()

Предоставление:

>>[8.68421935e-03 2.22248626e+01 4.00032135e-01]
>>22

данные и соответствие

person mikuszefski    schedule 14.05.2018
comment
это интересное предложение. Можете ли вы опубликовать код, который показывает, как вы это сделаете? - person M Newville; 14.05.2018
comment
@MNewville, вот и все - person mikuszefski; 15.05.2018
comment
Спасибо - это хорошая иллюстрация того, как обмануть якобианскую информацию, обрабатывающую дискретную переменную. Как вы и сказали, для многих проблем это не применимо, но может вдохновить на подобные случаи. - person M Newville; 15.05.2018

Я думаю, ответ - нет. Решатели в scipy.optimize, что оболочки lmfit не поддерживают дискретные переменные, только непрерывные переменные.

person M Newville    schedule 11.05.2018