我编写了一个 Python (2.7) 程序来评估一些科学数据。它的主要任务是将这些数据拟合到某个函数(1)。由于这是相当多的数据,因此程序使用多处理将作业(=“适合一组数据”)分配给多个核心。在第一次尝试中,我使用 scipy.optimize 中的 curve_fit 实现了拟合过程,效果很好。
到目前为止,一切都很好。然后我们看到数据更精确地由函数(1)的卷积和高斯分布来描述。这个想法是首先将数据拟合到函数 (1),得到猜测值,然后再次将数据拟合到卷积。由于数据非常嘈杂,并且我试图将其拟合到具有七个参数的卷积中,因此这次的结果相当糟糕。特别是高斯参数在某种程度上在物理上是不可能的。
所以我尝试在 PyMinuit 中实现拟合过程,因为它允许将参数限制在某些边界内(如正幅度)。由于我以前从未与 Minuit 合作过,并且我尝试从小处着手,因此我重写了拟合过程的第一(“简单”)部分。完成这项工作的代码片段如下所示(简化):
import minuit
import numpy as np
# temps are the x-values
# pol are the y-values
def gettc(temps, pol, guess_values):
try:
efunc_chi2 = lambda a,b,c,d: np.sum( (efunc(temps, a,b,c,d) - pol)**2 )
fit = minuit.Minuit(efunc_chi2)
fit.values['a'] = guess_values[0]
fit.values['b'] = guess_values[1]
fit.values['c'] = guess_values[2]
fit.values['d'] = guess_values[3]
fit.fixed['d'] = True
fit.maxcalls = 1000
#fit.tol = 1000.0
fit.migrad()
param = fit.args
popc = fit.covariance
except minuit.MinuitError:
return np.zeros(len(guess_values))
return param,popc
其中 efunc() 是函数 (1)。参数 d 是固定的,因为我目前不使用它。
PyMinuit 函数参考
最后,实际问题来了:运行脚本时,Minuit 几乎每次都打印
VariableMetricBuilder: Tolerance is not sufficient - edm is 0.000370555 requested 1e-05 continue the minimization
到具有不同 edm 值的标准输出。合身仍然可以正常工作,但打印会大大减慢程序的速度。我试图增加 fit.tol 但有很多数据集返回更高的 edm。然后我尝试使用这个实际有效的解决方案隐藏 fit.migrad() 的输出。现在发生了一些奇怪的事情:在程序中间的某个地方,所有内核上的进程同时失败。不是第一次适合,而是在我的整个数据集的中间。我唯一改变的是
with suppress_stdout_stderr():
fit.migrad()
我知道这是一个很长的介绍,但我认为当您了解整个框架时它会帮助您更多。如果有人对如何解决这个问题有任何想法,我将不胜感激。
注:函数(1)定义为
def efunc(x,a,b,c,d):
if x < c:
return a*np.exp(b*x**d)
else:
return a*np.exp(b*c**d) # therefore constant
efunc = np.vectorize(efunc)