如何解决lmfit 不适合返回单个标量值的简单示例中的唯一参数
残差函数 (res
) 对 y>thr (threshold) 的 y 值求和。它返回这个总和和目标之间的残差。
在这个例子中,一个 target
是为 y>70 计算的,我想在最小化之后找到从 y=60 开始的 y=70。
import numpy as np
import lmfit
x=np.linspace(0,10,51)
y=(x+4)*(x-14)*-1
def res(params,y,target):
parvals = params.valuesdict()
sum=y[y>parvals['thr']].sum()
return [(target-sum)**2]
target=y[y>70].sum()
pars=lmfit.Parameters()
pars.add('thr',value=60,min=y.min(),max=y.max())
minner = lmfit.Minimizer(res,pars,fcn_args=(y,target))
result = minner.minimize()
为什么拟合不起作用:不返回 70 而是返回 60(初始值)?
感谢回答。
解决方法
拟合不起作用,因为您使用连续变量 (pars['thr']
) 作为离散值 [y>parvals['thr']]
。当拟合运行时,它会尝试通过对变量值进行小的更改来计算结果的变化。
如果您在函数中添加 print()
:
def res(params,y,target):
parvals = params.valuesdict()
print(parvals['thr'])
sum=y[y>parvals['thr']].sum()
return [(target-sum)**2]
你会得到
60.0
60.0
60.0
60.00000089406967
60.0
当拟合试图找出 thr
应该改变的方式和程度。它会看到更改 thr
对结果没有影响。
基本上,您需要将 thr
的使用从离散变量更改为连续变量。一种简单的方法是使用 erf
函数(或另一个 sigmoidal 函数),例如在一些小的但不是无穷小的区间上从 ~0 到 ~1 缩放
from scipy.special import erf
def res(params,target):
parvals = params.valuesdict()
step = (1 + erf(y-parvals['thr']))/2.0
sum = (y*step).sum()
return target-sum # was [(target-sum)**2]
该 step
数组将具有接近阈值的非零/非 1 值,从而为拟合提供足够的信号来决定移动的位置。
另外,请注意,返回 [(target-sum)**2]
会起作用,但仅返回残差 target-sum
将使拟合不仅可以看到大小,还可以看到失配的符号,并允许拟合收敛更快。
通过这些更改,您应该通过大约 11 次函数评估获得正确的 thr
值为 70。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。