I am just trying to fit a function which retrieves the correlation Pearson coefficient between two arrays. These two arrays are passed to the function as input parameters but they do not change. For the function, they should be interpreted as constants. I found an option for the parameters where it is possible to fix one parameter, i.e., it can not vary, but it works only for scalar values.
When I call Model.make_params(), the Model Class tries to check of these arrays are lower or grater than the minimum/maximum. This evaluation is not needed as they are constants.
My function:
def __lin_iteration2__(xref, yref_scaled, xobs, yobs, slope, offset, verbose=False, niter=None):
Acal = 1 + (offset + slope*xref)/xref
xr_new = xref * Acal
obs_interp1d = interp1d(xobs, yobs, kind='cubic')
yobs_new = scale_vector(obs_interp1d(xr_new))
rho = Pearson(yref_scaled, yobs_new)
return rho
Where xref, yref_scaled, xobs and yobs are arrays that do not change, i.e., constants. 'interp1d' is the interpolator operator coming from scipy.interpolate, 'scale_vector' scale a vector between -1 and 1, and 'Pearson' calculates the Pearson correlation coefficient.
Who I setup the Model class:
m = Model(corr.__lin_iteration3__)
par = m.make_params(yref_scaled = corr.yref_scaled, \
obs_interp1d=corr.obs_interp1d, offset=0, scale=0)
par['yref_scaled'].vary = False
par['obs_interp1d'].vary = False
r = m.fit
The error I got (just in the second line when I call the 'make_params' function of Model Class):
Traceback (most recent call last):
File "<ipython-input-3-c8f6550e831e>", line 1, in <module>
runfile('/home/andrey/Noveltis/tests/new_correl_sp/new_correl.py', wdir='/home/andrey/Noveltis/tests/new_correl_sp')
File "/usr/lib/python3/dist-packages/spyder/utils/site/sitecustomize.py", line 705, in runfile
execfile(filename, namespace)
File "/usr/lib/python3/dist-packages/spyder/utils/site/sitecustomize.py", line 102, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "/home/andrey/Noveltis/tests/new_correl_sp/new_correl.py", line 264, in <module>
obs_interp1d=corr.obs_interp1d, offset=0, scale=0)
File "/usr/lib/python3/dist-packages/lmfit/model.py", line 401, in make_params
params.add(par)
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 338, in add
self.__setitem__(name.name, name)
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 145, in __setitem__
self._asteval.symtable[key] = par.value
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 801, in value
return self._getval()
File "/usr/lib/python3/dist-packages/lmfit/parameter.py", line 786, in _getval
if self._val > self.max:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
In lmfit
, arguments to the model function are expected to be scalar, floating point parameter values, except for "independent variables" which can be any python objects. By default, the first function argument is assumed to be an independent variable, as is any keyword argument with a non-numeric default value. But, you can specify which arguments are the independent variables (and there can be more than one) when creating your model.
I think what you want is:
m = Model(corr.__lin_iteration3__, independent_vars=['xref', 'yref_scaled', 'xobs', 'yobs'])
But also: You could also pass is any Python object, so you could pack your ref and obs data into other structures and do something like
def lin_iteration(Data, slope, offset, verbose=False, niter=None):
Acal = 1 + (offset + slope*Data['xref'])/Data['xref']
xr_new = Data['xref'] * Acal
# or maybe that would be clearer as just
# xr_new = offset + (1+slope)* Data['xref']
obs_interp1d = interp1d(Data['xobs'], Data['yobs'], kind='cubic')
yobs_new = scale_vector(obs_interp1d(xr_new))
rho = Pearson(Data['yref_scaled'], yobs_new)
return rho
and
m = Model(lin_iteration)
par = m.make_params(offset=0, scale=0)
Data = {'xref': xref, 'yref_scaled': yref_scaled, 'xobs': xobs, 'yobs': yobs}
result = m.fit(Data, params)
Of course, that's all untested but it might make your life easier...