List of Strings as Independent Variables of a Model

84 views
Skip to first unread message

James Winkleblack

unread,
Mar 27, 2020, 8:22:57 PM3/27/20
to lmfit-py
Hello, 

I am trying to pass in a list of strings as the independent variables for a model in the example below. The lmfit documentation states: 'Note that independent variables are not required to be arrays, or even floating point numbers.', though with this example, there appears to be somewhat stringent requirements on the types required for independent variables. 

In this example, I am trying to have categorical x data in that the data corresponds to some independent variable, ie -1 corresponds to the key 'c'. I would like to align the model and data values such that I may be able to change the ordering of the data without altering the original sequence's ordering. Is this possible with lmfit, must I try an implementation with minimize instead?

from lmfit import Model, fit_report, Parameters, Parameter

def ln_model(M:float,B:float,sequence=None):
    model_data = []
    alter_dict: {'a':M*3+B,'d':2*M*3+2*B,'c':3*M*3+3*B} 
    for seq in sequence:
        alteration = alter_dict['seq']
        model_data.append(alteration)
    
    return np.array(model_data)

class LinearModel(Model):
    def __init__(self, *args, **kwargs):
        super(LinearModel, self).__init__(ln_model, *args, **kwargs)
        
m = Model(ln_model,independent_vars=['a','c','d'])
pars = Parameters() #2-parameter fit model
pars.add(name='M',value=1,vary=True)
pars.add(name='B',value=0,vary=True)
original_sequence = ['a','c','d'] #Array with ordering to conform the data to
keys = ['c','d','a']  #Data keys, with altered ordering 
data_list = [-1,0,1] 
data_dict = {key: val for key,val in zip(keys,data_list)}

#perform the fit on data_dict.values() to try and find best fit values for our parameters (M,B) 
fit = m.fit(
    np.array(data_dict.values()),
    params=pars,
    sequence=list(data_dict.keys())
)

With stack-trace: 

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-a34f5dd3c58f> in <module>
     14         super(LinearModel, self).__init__(ln_model, *args, **kwargs)
     15 
---> 16 m = Model(ln_model,independent_vars=['a','c'])
     17 pars = Parameters() #2-parameter fit model
     18 pars.add(name='M',value=1,vary=True)

~/miniconda3/envs/v6.0.0/lib/python3.6/site-packages/lmfit/model.py in __init__(self, func, independent_vars, param_names, nan_policy, missing, prefix, name, **kws)
    153         # the following has been changed from OrderedSet for the time being
    154         self._param_names = []
--> 155         self._parse_params()
    156         if self.independent_vars is None:
    157             self.independent_vars = []

~/miniconda3/envs/v6.0.0/lib/python3.6/site-packages/lmfit/model.py in _parse_params(self)
    408         for arg in self.independent_vars:
    409             if arg not in allargs or arg in self._forbidden_args:
--> 410                 raise ValueError(self._invalid_ivar % (arg, fname))
    411         for arg in names:
    412             if (self._strip_prefix(arg) not in allargs or

ValueError: Invalid independent variable name ('a') for function ln_model



Matt Newville

unread,
Mar 27, 2020, 10:34:02 PM3/27/20
to lmfit-py
The exception

       ValueError: Invalid independent variable name ('a') for function ln_model

is telling you that 'a' is not a valid independent variable name for your model function `ln_model()`.  Your model function has arguments name 'M', 'B', and 'sequence'.   It doesn't have an argument named 'a'.  

I don;t really follow your example or what you are trying to do.   I see lots of things in your code that looks like it probably is not doing what you want (like, you iterate over `sequence`, but don't check the default case of it being the non-iterable value None.  You never use the iterable value of `seq` anyway).  You have 'values' and 'keys' then explicity put them into a dictionary in approximately the hardest way possible, only to unpack them.
You define a useless super-classing for LinearModel that you then never use.   I cannot  guess what you are trying to do unless it is "make it as needlessly complicated as possible".

But for sure, the error message you get is because 'a' is not a valid independent variable for your model function.

Hope that helps. 

--Matt

--
You received this message because you are subscribed to the Google Groups "lmfit-py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lmfit-py+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lmfit-py/e657bd33-beb3-4df1-9c3a-71d5388925dc%40googlegroups.com.


Shane Caldwell

unread,
Mar 28, 2020, 1:04:53 AM3/28/20
to lmfi...@googlegroups.com
I'm also interested in an answer to this question if someone knows how to do it.

Also fwiw I think this post is adhering to the rules of this forum and deserves a better response.

Regards,
Shane Caldwell



Matt Newville

unread,
Mar 28, 2020, 8:37:25 AM3/28/20
to lmfit-py
On Sat, Mar 28, 2020 at 12:04 AM Shane Caldwell <caldwel...@gmail.com> wrote:
I'm also interested in an answer to this question if someone knows how to do it.


Sorry, I don't understand: if someone knows how to do what?  

Also fwiw I think this post is adhering to the rules of this forum and deserves a better response.


The model function `ln_model` is defined with arguments named  'M', 'B', and 'sequence'.   It doesn't have an argument named 'a' (or 'c' or 'd' for that matter).  So

    def ln_model(M:float,B:float,sequence=None):
        .....

    m = Model(ln_model,  independent_vars=['a','c','d'])

will exactly raise the error

     ValueError: Invalid independent variable name ('a') for function ln_model

I do not understand what the intention of the code is - there are a lot of weird things going on.  But for sure, if an independent variable named 'a' is expected, the model function would have to be defined to have an argument named 'a'. 

 --Matt 

Mark Dean

unread,
Mar 28, 2020, 9:17:34 AM3/28/20
to lmfit-py
I have a slightly hard time understanding some elements of the code sent. It is, however, possible to pass in a sequence of strings. This is an example:

import lmfit
import numpy as np


def myfunction(x, amplitude=1, string_sequence=None):
    out = []
    for string in string_sequence:
        if string == 'x_comp':
            out.append(x*amplitude)
        elif string == 'x**2_comp':
            out.append(x**2*amplitude)
        else:
            out.append(x*0)
    
    return np.array(out)

mymodel = lmfit.Model(myfunction,
                      independent_vars=['x', 'string_sequence'])


# fit with the default order
x = np.linspace(0, 5)
amp = 2
data = np.array([amp*x, amp*x**2])
result = mymodel.fit(data, x=x, string_sequence=np.array(['x_comp', 'x**2_comp']))



# fit data the other way round
amp = 3
different_data = data = np.array([amp*x**2, amp*x, ])
different_result = mymodel.fit(data, x=x,
                               string_sequence=np.array(['x**2_comp', 'x_comp']))

print('Result\n' + result.fit_report() + '\n\n\nDifferent result\n'
     + different_result.fit_report())

print('Result\n' + result.fit_report() + '\n\n\nDifferent result\n'
     + different_result.fit_report())

Returns:
Result
[[Model]]
    Model(myfunction)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 5
    # data points      = 100
    # variables        = 1
    chi-square         = 0.00000000
    reduced chi-square = 0.00000000
    Akaike info crit   = -inf
    Bayesian info crit = -inf
##  Warning: uncertainties could not be estimated:
[[Variables]]
    amplitude:  2.00000000 +/- 0.00000000 (0.00%) (init = 1)


Different result
[[Model]]
    Model(myfunction)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 5
    # data points      = 100
    # variables        = 1
    chi-square         = 0.00000000
    reduced chi-square = 0.00000000
    Akaike info crit   = -inf
    Bayesian info crit = -inf
##  Warning: uncertainties could not be estimated:
[[Variables]]
    amplitude:  3.00000000 +/- 0.00000000 (0.00%) (init = 1)

Matt Newville

unread,
Mar 28, 2020, 9:42:54 AM3/28/20
to lmfit-py
Yes, an independent variable can definitely be a string (or list of strings, or a dict, or database connection, or any other python object).  But when you say, 

   mymodel = lmfit.Model(model_func, independent_vars=['x', 'y', 'z'])

then the `model_func` function does need to have arguments named 'x', 'y', and 'z'.  ;).  





--
You received this message because you are subscribed to the Google Groups "lmfit-py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lmfit-py+u...@googlegroups.com.


--
--Matt Newville <newville at cars.uchicago.edu> 630-252-0431
Reply all
Reply to author
Forward
0 new messages