[英]Writing an error function to feed scipy.optimize.least_squares in python
I am trying to fit some data to a non-linear function, and wanted to play with the model function to see if I could get a better fitting than the one I already have. 我正在尝试将一些数据拟合到一个非线性函数中,并希望使用模型函数来查看是否可以得到比现有函数更好的拟合。 As I was trying to figure things out, I came up with more questions. 在尝试解决问题时,我提出了更多问题。 I have: 我有:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import least_squares
from scipy.optimize import curve_fit
temperature = [ 38., 40., 42., 44., 46., 48., 50., 52., 54., 56., 58., 60., 62., 64., 66., 68., 70., 71.9, 73.81, 75.69, 77.6, 79.49, 81.38, 83.29, 85.19, 87.11, 89., 90., 91., 92., 93., 94., 95., 96., 97., 98., 99., 100. ]
exp_rate = [ 8.71171203e-01, 1.15342914e+00, 1.39178845e+00, 1.66700007e+00, 1.96267002e+00, 2.32390602e+00, 2.68542886e+00, 3.13116448e+00, 3.60152705e+00, 4.12575295e+00, 4.67617489e+00, 5.29745193e+00, 6.06796117e+00, 6.99056274e+00, 8.40124338e+00, 1.04449551e+01, 1.38236107e+01, 1.96811651e+01, 2.91545190e+01, 4.67945718e+01, 7.36377025e+01, 1.19474313e+02, 1.91938580e+02, 3.07692308e+02, 4.92610837e+02, 7.87401575e+02, 1.20738388e+03, 1.51773627e+03, 1.89049140e+03, 2.33880380e+03, 2.90892166e+03, 3.53003887e+03, 4.28065700e+03, 5.15251443e+03, 6.18043152e+03, 7.49720729e+03, 9.57524225e+03, 1.17175325e+04]
def Orbach_Raman(temperature, pre_1, U_1, C, n): # This is my model function
return np.array( (1./pre_1)*np.exp(-U_1/(temperature)) + C*(temperature**n) )
pre_1, U_1, C, n = np.array([1.17E-12, 1815, 1E-6, 3.77]) # Define the starting guess
guess = pre_1, U_1, C, n
popt_stret, pcov = curve_fit(Orbach_Raman, temperature, exp_rate, p0=guess)
But curve_fit() cannot find the optimal parameters and it raises 但是curve_fit()找不到最佳参数,它会引发
File "/usr/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 680, in curve_fit
raise RuntimeError("Optimal parameters not found: " + errmsg)
RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 1000.
which is very weird as the starting guess already provides a very good fit of the data 这很奇怪,因为开始的猜测已经可以很好地拟合数据
plt.loglog(temperature, exp_rate, '-o')
plt.loglog(temperature, Orbach_Raman(temperature, pre_1, U_1, C, n ), '-*')
plt.show()
So I then tried to write my own error function to use least_square() instead of curve_fit(), for which I added to the previous code 因此,我然后尝试编写自己的错误函数以使用Minimum_square()而不是curve_fit(),为此我将其添加到了先前的代码中
def error(guess, rate):
pre_1, U_1, C, n = guess
return Orbach_Raman(temperature, pre_1, U_1, C, n) - rate
least_squares(error(guess, exp_rate), guess, args=(exp_rate))
getting the following error 得到以下错误
File "fit_experiment.py", line 46, in <module>
least_squares(error(guess, exp_rate), guess, args=(exp_rate))
File "/usr/lib/python2.7/dist-packages/scipy/optimize/_lsq/least_squares.py", line 769, in least_squares
f0 = fun_wrapped(x0)
File "/usr/lib/python2.7/dist-packages/scipy/optimize/_lsq/least_squares.py", line 764, in fun_wrapped
return np.atleast_1d(fun(x, *args, **kwargs))
TypeError: 'numpy.ndarray' object is not callable
Does anyone know 有人知道吗
I think the answers are: 我认为答案是:
I'm not sure. 我不确定。 It may not be "failing" as much as "giving up after many iterations". 它可能不会像“多次迭代后放弃”那样“失败”。 Did you look at the results? 你看结果了吗?
I would also suggest that, since your plot is actually (and sensibly) on a log scale, that you might also fit on a log scale. 我还建议,由于您的绘图实际上(并且明智地)在对数刻度上,因此您可能也适合对数刻度。 That is, have your model function return the log of the model, and fit log(exp_rate)
. 也就是说,让您的模型函数返回模型的日志,并拟合log(exp_rate)
。
This is because least_squares()
wants the first argument to be the function that returns the residual, not the calculated residual. 这是因为least_squares()
希望第一个参数是返回残差而不是计算出的残差的函数 。 So, use least_squares(error, guess...)
not least_squares(error(guess, exp_rate), guess, ...)
. 因此,请使用least_squares(error, guess...)
而不是least_squares(error(guess, exp_rate), guess, ...)
。
This is because of the easy-to-be-fooled way of saying "tuple with 1 element" in Python. 这是因为在Python中说“带有1个元素的元组”的方法很容易上当。 The args=(exp_rate)
is interpreted as a tuple with the components of exp_rate
(probably 39 data points), not "a tuple with one element with the first element being exp_rate
. What you want is to add a trailing comma (which is what really defines a tuple, not the parentheses): args=(exp_rate, )
args=(exp_rate)
解释为具有exp_rate
组件(可能是39个数据点)的元组,而不是“具有一个元素且第一个元素为exp_rate
的元组。您想要的是添加尾随逗号(这就是确实定义了一个元组,而不是括号): args=(exp_rate, )
Hope that helps. 希望能有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.