我正在尝试定义分段函数以供python中的lmfit库拟合。我遇到的问题是我为该函数定义的参数,不会与我提交的数据一起评估。
我有一个与我的here类似的案例。但是,答案描述的vectorize函数不能产生我想要的值,并且在阅读文档时,它似乎并不是我的解决方案的答案。我还使用了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
我也尝试使用lambda函数进行内联。
我收到一个错误消息:具有多个元素的数组的真值不明确。当我得到该错误时,就可以理解为什么会发生,因为(param2 lmfit的工作方式似乎也有所不同,因为我们必须始终使残差返回(模型-y),而一旦给出函数,nlinfit就会输出结果,我不确定这可能是另一个问题。 因此,我要重申的主要问题是,是否存在一种定义分段函数的方法,以便可以将参数与数据集进行比较。 任何帮助或解释将不胜感激,谢谢!
答案 0 :(得分:0)
您要使用(param2 < x)
来代替param2
(其中x
是浮点数,而numpy.where
是一个numpy数组)。您可以尝试:
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
希望有帮助。