我正在尝试使用负对数似然最小化来拟合指数衰减函数,但即使对于最小化器具有良好的起始参数x0
,我似乎也无法使其收敛。为什么?我写错了吗?
以包括传统的分箱可能性,即“曲线”拟合
import numpy as np
from scipy.optimize import minimize, curve_fit
import matplotlib.pyplot as plt
np.random.seed(1)
def exp_fit(x, N, L):
return N * np.exp(- L * x)
def negloglik(args, func, data):
"""Negative log likelihood"""
return - np.sum(np.log(func(data, *args)))
def histpoints_w_err(X, bins):
counts, bin_edges = np.histogram(X, bins = bins, normed = False)
bin_centers = (bin_edges[1:] + bin_edges[:-1]) / 2
bin_err = np.sqrt(counts)
# Generate fitting points
x = bin_centers[counts > 0] # filter along counts, to remove any value in the same position as an empty bin
y = counts[counts > 0]
sy = bin_err[counts > 0]
return x, y, sy
data = np.random.exponential(0.5, 1000)
bins = np.arange(0, 3, 0.1)
x, y, sy = histpoints_w_err(data, bins)
popt, pcov = curve_fit(exp_fit, x, y, sigma = sy)
xpts = np.linspace(0, 3, 100)
# All variables must be positive
bnds = ((0, None),
(0, None))
result = minimize(negloglik,
args = (exp_fit, data),
x0 = (popt[0], popt[1]), # Give it the parameters of the fit that worked
method = "SLSQP",
bounds = bnds)
jac = result.get("jac")
plt.hist(data, bins = bins)
plt.plot(xpts, exp_fit(xpts, *popt), label = "Binned fit: {:.2f}exp(-{:.2f}x)".format(*popt))
plt.plot(xpts, exp_fit(xpts, *jac), label = "Unbinned fit: {:.2f}exp(-{:.2f}x)".format(*jac))
plt.text(s = result, x = 0.8, y = popt[0]*0.2)
plt.legend()
plt.show()
答案 0 :(得分:0)
我已经删除了这样的方法:
# minimize the negative log-Likelihood
result = minimize(negloglik, args = (exp_fit, data), x0 = (15, 0.5))
我得到的是:
fun: -1601.1177190942697
hess_inv: array([[2.16565679e+11, 5.15680574e+09],
[5.15680574e+09, 1.22792520e+08]])
jac: array([0., 0.])
message: 'Optimization terminated successfully.'
nfev: 120
nit: 28
njev: 30
status: 0
success: True
x: array([8986009.32851534, 213973.66153225])
之前的成功是假的。也许该方法应该改为其他?默认值为,如果未指定,则为BFGS,L-BFGS-B,SLSQP,具体取决于问题是否存在约束或界限。
答案 1 :(得分:0)
所以,使用iminuit和probfit而不是scipy重新整理整个事物。语法有点奇怪(尤其是iminuit如何更改输入参数名称以匹配拟合参数),但是一旦开始使用它就非常简单。遗憾的是,那里的社区文档非常少,就此而言。
在这里,我完成了未组合的可能性:
import iminuit, probfit
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats
np.random.seed(1)
data = np.random.exponential(0.5, 500)
def unbinned_exp_LLH(data, loc_init, scale_init, limit_loc, limit_scale):
# Define function to fit
def exp_func(x, loc, scale):
return scipy.stats.expon.pdf(x, loc, scale)
# Define initial parameters
init_params = dict(loc = loc_init, scale = scale_init)
# Create an unbinned likelihood object with function and data.
unbin = probfit.UnbinnedLH(exp_func, data)
# Minimizes the unbinned likelihood for the given function
m = iminuit.Minuit(unbin,
**init_params,
limit_scale = limit_loc,
limit_loc = limit_scale,
pedantic=False,
print_level=0)
m.migrad()
params = m.values.values() # Get out fit values
errs = m.errors.values()
return params, errs
params, errs = unbinned_exp_LLH(data, loc_init = 0, scale_init = 0.5, limit_loc = (-1, 1), limit_scale = (-1, 1))
loc, scale = params
# Plot
x_pts = np.linspace(0, 3, 100)
plt.plot(x_pts, scipy.stats.expon.pdf(x_pts, *params), label = "exp(-{1:.2f}x)".format(*params), color = "black")
plt.hist(data, color = "lightgrey", bins = 20, label = "generated data", normed = True)
plt.xlim(0, 3)
plt.legend()
plt.show()