我具有如下所示的功能
def PPM(x,a,b,c,d): # d is the fixed parameter
if x>d:
return 100/(1+((x-d)/c)**(-a))**b
else: return 0
参数d是固定的(根据实验室数据计算),我需要进行曲线拟合以获取所有其他参数。
我现在正在使用lmfit,因为我可以轻松地修复参数d。
from lmfit import minimize, Parameters
def residual(params, x, data):
d = params['d']
a = params['a']
b = params['b']
c = params['c']
if x>d:
PP = 100/(1+((x-d)/c)**(-a))**b
else: PP = 0
return data-PP
但显示 ValueError:具有多个元素的数组的真值不明确。使用a.any()或a.all(),我知道它与使用数组矢量化函数有关,但是不知道如何在lmfit中做到这一点
我也通过
修改了上面的代码 def residual(params, x, data):
d = params['d'] #the value of d is 0.078528, the fixed parameter
a = params['a']
b = params['b']
c = params['c']
PP = 100/(1+((x-d)/c)**(-a))**b
PP[np.where(d>x)] = 0
return data-PP
params = Parameters()
params.add('d', value=0.078528, vary=False)
params.add('a', value=0.25, min=0, max=1)
params.add('b', value=5, min=0.5, max=500)
params.add('c', value=0.001, min=0.0001, max=1)
out = minimize(residual, params, args=(x, data))
修改代码后,运行后没有警告(错误),但拟合的数据看起来很糟糕。似乎无论我分配的初始值如何,都没有更改。 (我想是因为如果x小于d,则该函数没有值) 顺便说一下,我使用从lmfit到Minimumsquare的最小化残差 有办法在python中做到吗? Data and Fitting in excel这是我所期望的 还有数据
x = [6.2e-5, 1.2e-4, 2.5e-4, 5.0e-4, 1.0e-3, 2.0e-3, 4.2e-3, 8.8e-3, 2.0e-2,
4.6e-2, 1.1e-1, 2.6e-1, 6.0e-1]
Data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0.056, 0.478, 3.725, 7.800]
谢谢!
此致
史蒂夫
答案 0 :(得分:1)
如果不必进行向量化,则可以使用列表理解
from lmfit import minimize, Parameters
import numpy as np
x=[0.0000621, 0.0001242, 0.00024932, 0.00049772, 0.00100004, 0.00202676, 0.00417128,0.00878876, 0.01984992, 0.04636064, 0.10731156, 0.25733504, 0.60121724]
data=[ 0,0,0,0,0,0,0,0,0,0.056443102,0.478543944,3.724743415,7.795926674]
def residual(params, x, data):
d = params['d']
a = params['a']
b = params['b']
c = params['c']
PP = [100/(1+((x_-d)/c)**(-a))**b if x_>d else 0 for x_ in x]
return np.array(data)-np.array(PP)
我不知道a,b,c和d的值应该是什么,所以我把它们补了。
residual({'d':1,'a':2,'b':3,'c':4},x,data)
array([0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0.0564431 ,
0.47854394, 3.72474341, 7.79592667])
答案 1 :(得分:1)
最好总是包含一个完整的最小脚本,以显示您的实际操作以及您实际获得的实际结果,包括拟合报告。
您的问题表明您确实解决了np.any()
与np.where()
的问题。太好了!
您的模型仍然有
PP = 100/(1+((x-d)/c)**(-a))**b
以及该图和问题表明x
的某些值将为< d
。使用c
和a
都为正实数
((x-d)/c)**(-a)
将具有一些复杂的值或给出nan
。然后你拿
1 + ((x-d)/c)**(-a)
并将其提高到b
的幂,b
的起始值为20!那是很大的,而且不是很稳定:2.0**20
〜= 100万,2.5**20
〜= 1亿,3.0**20
〜= 30亿。
我建议您进一步探索参数空间。例如,当您仅用初始值评估模型时,您会得到什么? b=20
是否适合您的数据?请注意,拟合将从您的初始值开始,对其进行非常非常小的更改,以查看将参数值移动到哪个方向。如果非常非常小的更改不会改变结果,则拟合将不知道要移动到哪里。
作为对您的提示:数据图使用x
轴的对数刻度。我还建议为y轴使用对数刻度,甚至拟合对数空间:也就是说,将log(data)
视为要拟合的数据,并使用模型计算PP功能的日志。当然,您不会在PP=0
的地方设置x<d
,但是您可以将其设置为很小的值,例如:
pparg = (x-d)/c
pparg[np.where(pparg<0)] = 1.e-30
# log(pp) = np.log(100 * (1 + pparg**(-a)) **(-b)))
logpp = np.log(100) - b * np.log(1 + pparg**(-a))
return (log(data) - logpp)
希望有帮助。...
答案 2 :(得分:0)
我要感谢所有参与此问题的人。
通过将固定值限制在很小的范围内,我终于得到了想要的东西。
我将在下面显示代码。
import numpy as np
from scipy import optimize
import pylab as pl
def PPM(x,a,b,c,d): # model
"""
The model is pp=100/(1+((x-d)/c)**(-a))**b, d is the fixed parameter
"""
pp = np.piecewise(x,[x <= d, x > d],[ 0,lambda x: 100/(1+((x-d)/c)**(-a))**b])
return pp
x = [6.2e-5, 1.2e-4, 2.5e-4, 5.0e-4, 1.0e-3, 2.0e-3, 4.2e-3, 8.8e-3, 2.0e-2, 4.6e-2, 1.1e-1, 2.6e-1, 6.0e-1]
y0 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0.056, 0.478, 3.725, 7.800] #x,yo are lab data
d = 0.071010176 #Calculated value for the fixed parameter
p1 = [1,1,0.5,d] # initial values for parameters
param_bounds = ([0, 0.1, 0.00001,0.99*d],[1, 18, 1, 1.01*d])
popt,pcov = optimize.curve_fit(PPM, x, y0, p0=p1,bounds=param_bounds)
#interpolation for plotting
x1 = np.linspace(x[0],x[-1],100)
y1 = [PPM(i,popt[0], popt[1], popt[2], popt[3]) for i in x1]
#plot
pl.semilogx(x, y0, "o", label=u"Lab Data")
pl.semilogx(x1, y1, label=u"Fitted Model")
pl.legend(loc="best")
pl.show
对我来说看起来不错。如果您有任何意见或建议,请发表评论。
再次感谢!
史蒂夫