我希望用最大似然法将六个参数拟合到非常难看的分布函数中。为此,我尝试使用scipy.optimize.minimize
。
这是一段代码
import math
form scipy.optimize import minimize
import numpy as np
#generate some data
xdata = np.random.lognormal(0,1,812)
#function for the Log likelihood
def mfpdf2(params):
c1 = params[0]
A1 = params[1]
a1 = params[2]
c2 = params[3]
A2 = params[4]
a2 = params[5]
LL_vec = [math.log(c1*(math.exp(-A1*x) - math.exp(-a1*x))+c2*(math.exp(-A2*x) - math.exp(-a2*x))) for x in xdata]
LL = -sum(LL_vec)
return LL
#try to find max likelihood (minimize negative loglikelihood)
start_params = [1,1,2,1,1,2]
pars = minimize(mfpdf2, start_params)
这段代码给我一个错误:
File "C:/Users/Robert/Desktop/python/pokusy_analyza_multiexp.py", line 79, in <listcomp>
LL_vec = [math.log(c1*(math.exp(-A1*x) - math.exp(-a1*x))+c2*(math.exp(-A2*x) - math.exp(-a2*x))) for x in xdata]
ValueError: math domain error
我做错了什么?
答案 0 :(得分:1)
看起来你可能正在记录一个未定义的负数
答案 1 :(得分:0)
如果math.log
为否定,x
函数中的表达式将返回负数。负数的对数仅针对复数定义,因此常规日志函数将为您提供ValueError: math domain error
。您可以将x_data
转换为复数并使用np.log
,如果这样可以从您的特定应用中获得minimize
的可接受结果:
xdata = np.random.lognormal(0,1,812).astype(np.complex)
...
LL_vec = [np.log(c1*(math.exp(-A1*x) - m ...
或者您可以指定不同的最小化技术(并非所有支持定义的边界)并指定值的边界。这不支持A1 > a1
之类的符号边界,因此您必须对变量进行重新排序才能建立关系:
from scipy.optimize import minimize
import numpy as np
xdata = np.random.lognormal(0,1,812)
def mfpdf2(params):
c1 = params[0]
A1 = params[1]
offset1 = params[2] #this can obviously be condensed to one line
a1 = A1 + offset1 #bound offset to be positive so a is always > A
c2 = params[3]
A2 = params[4]
offset2 = params[5]
a2 = A2 + offset2
LL_vec = [np.log(
c1*(np.exp(-A1*x) - np.exp(-a1*x))+
c2*(np.exp(-A2*x) - np.exp(-a2*x))
) for x in xdata]
#this will not account for the possibility that
# one of c1*(...) or c2*(...) is negative but
# the sum is still positive. This could conceiveably
# be achieved with more ratios or offsets instead of
# direct values, but would make the math real nasty.
LL = -sum(LL_vec)
return LL
start_params = [1,1,2,1,1,2]
pars = minimize(mfpdf2,
start_params,
method='L-BFGS-B',
#now define your bounds
bounds=((None, None), # c1
(None, None), # A1
(0, None), # a1 - A1 (makes a1 always larger than A1)
(None, None), # c2
(None, None), # A2
(0, None))) # a2