LMFIT on Python: TypeError: only size-1 arrays can be converted to Python scalars
I’m trying to create a curve fitting program with LMFIT on Python (Anaconda), but I keep getting the same error message: TypeError: only size-1 arrays can be converted to Python scalars. I was able to perform optimization using only one function, but I get this error when I try to optimize a function that calls another user-defined function.
import numpy as np
from matplotlib import pyplot
import scipy.special as sp
from scipy import integrate
import lmfit as lm
#Defining the first function.
def function1(alpha,q,s,l):
Intensity = alpha**2 + q -s*alpha / (5*l)
return Intensity
#Defining a second function that will perform a integration over the first function.
def integrate_function(q,s,l):
func_parameters = {
'q':q,
's':s,
'l':l,
}
to_be_integrated = lambda alpha: function1(alpha, **func_parameters)
result, error = integrate.quad(to_be_integrated, 0, 10)
return result
#Setting up the LMFIT model. Here I also provide the initial guess for the parameters.
integrate_function_model = lm.Model(integrate_function, independent_vars=['q'])
integrate_function_model.set_param_hint('s', value=2, min=-10.0, max=20.0, vary=True)
integrate_function_model.set_param_hint('l', value=3, min=1.0, max=10.0, vary=True)
initial_params = integrate_function_model.make_params()
#Creating data to be fitted (I also add some noise)
#Here I set s=1.5 and l=5.0 and I want the optimization routine to be able to find out these numbers.
x_data = np.linspace(0, 10, 100)
y_data = np.zeros(len(x_data))
for i in range(len(x_data)):
y_data[i] = integrate_function(x_data[i],1.5,5.0) + 5.0*np.random.random()
#Fitting the data.
fitting = integrate_function_model.fit(y_data, initial_params, q=x_data, method='leastsq')
#Printing original data and fitted model.
pyplot.plot(x_data, y_data, color='green', lw=2)
pyplot.plot(x_data, fitting.best_fit, color='blue', lw=2)
pyplot.show()
Solution
The error occurs integrate_function
your function is called with np.array
as an argument to q
:
>>> integrate_function(1,1,1)
333.33333333333337
>>> integrate_function(np.array([1,2]),1,1)
TypeError: only size-1 arrays can be converted to Python scalars
This happens during output.fit,
where integrate.quad
is called. The quad
cannot handle vectorized input, which is happening in your case.
One way to solve this problem is to change the case where integrate_function
handle
q to be an array accordingly, such as by manually containing a loop that contains all the values in q
:
def integrate_function(q,s,l):
# Make q iterable if it is only a float/int
if not hasattr(q, '__iter__'):
q = np.array([q])
result = []
for q0 in q:
func_parameters = {
'q':q0,
's':s,
'l':l,
}
to_be_integrated = lambda alpha: function1(alpha, **func_parameters)
result.append(integrate.quad(to_be_integrated, 0, 10)[0])
return np.array(result)
Execute your code with the modified integrate_function
and then produce the following plot: