guess method of composite models

573 views
Skip to first unread message

glenn....@gmail.com

unread,
Mar 22, 2016, 10:26:23 AM3/22/16
to lmfit-py
Hi,
Is there a clever way to implement a guess method for composite models? A custom method is probably in order, since the guess methods for either component of the model might not work well with data generated by a composite model. But since the composite model is instantiated by applying an operator to two model instances, it's not clear to me how to add a custom guess method to a composite model instance. Am I missing something?

Thanks,
Glenn

Matt Newville

unread,
Mar 22, 2016, 11:10:36 AM3/22/16
to glenn....@gmail.com, lmfit-py
Hi Glenn,


A custom method is in order.

Each Model (including each composite model) has a `guess()` method that raises NotImplementedError by default.  You can overwrite this for any model -- of course you would have to assign that method after the composite is created.    For reference, Model.guess() should take a `data` array as the first argument (meant to be the Y values), and any keyword args you want (you might need to pass in an `x` array, for example), and should return a set of Parameters appropriate for the modelwith initial values set however you think they should be guessed from the data.

The examples in models.py might be useful.   But also, if you have the knowledge to write a custom `guess` method, you could probably just assign starting values to the Parameters.

See also examples/doc_nistgauss2.py and the discussion starting at "One final point" after http://cars9.uchicago.edu/software/python/lmfit/builtin_models.html#example-3-fitting-multiple-peaks-and-using-prefixes

--Matt



glenn....@gmail.com

unread,
Mar 22, 2016, 11:15:57 AM3/22/16
to lmfit-py, glenn....@gmail.com, newv...@cars.uchicago.edu
Hi Matt,
Thanks for the reply. What you say makes sense; instead of keeping around references to the component model instances, I would just call composite.right.guess and .left.guess accordingly.
But the crux of my question is: suppose that neither guess method of the component models makes sense when the data comes from a composite model, so a more general guess is needed. If I were making a new model class, I could of course override the Model.guess method. But since the composite model is made by composite = model1 + model2, for example, there's no opportunity to add a .guess method to composite. I suppose I could create a custom subclass of CompositeModel, complete with the custom guess function, and then manually instantiate it with left=model1, right=model2, op=add, or something, but that seems inelegant. Just wondering if there was a cleaner solution. Probably just calling .right.guess and .left.guess will work in most cases.

Thanks again,
Glenn

Matt Newville

unread,
Mar 22, 2016, 12:16:31 PM3/22/16
to glenn....@gmail.com, lmfit-py
On Tue, Mar 22, 2016 at 10:15 AM, <glenn....@gmail.com> wrote:
Hi Matt,
Thanks for the reply. What you say makes sense; instead of keeping around references to the component model instances, I would just call composite.right.guess and .left.guess accordingly.
But the crux of my question is: suppose that neither guess method of the component models makes sense when the data comes from a composite model, so a more general guess is needed. If I were making a new model class, I could of course override the Model.guess method. But since the composite model is made by composite = model1 + model2, for example, there's no opportunity to add a .guess method to composite.

Um, yes there is. Like I said earlier (apparently not clearly enough) each Model has a guess() method, you just have to overwrite it. Of course, you'd have to do this after the composite model is created, perhaps like

def MyCompositeGuesser(data, x=None, **kws):
   pars =  create_parameters()
   assign_initial_values(pars)
   return pars

composite = Model(func1) + Model(func2) * Model(func3)

composite.guess = MyCompositeGuesser

 
I suppose I could create a custom subclass of CompositeModel, complete with the custom guess function, and then manually instantiate it with left=model1, right=model2, op=add, or something, but that seems inelegant. Just wondering if there was a cleaner solution. Probably just calling .right.guess and .left.guess will work in most cases.

I don't think there is a "most cases" for composite models, especially with respect to guessing initial values. But also keep in mind that, in general, .left.guess and .right.guess will raise NotImplementedError, and you have to overwrite these methods as well.


--Matt
 

glenn....@gmail.com

unread,
Mar 23, 2016, 9:19:26 AM3/23/16
to lmfit-py, glenn....@gmail.com, newv...@cars.uchicago.edu
Hi Matt,
I am aware of that sort of 'monkey patching', but I was looking for a more elegant solution. Note in particular I don't think that method will allow you to access "self" since it's not actually a class method. 
It sounds like the cleanest solution is probably subclassing CompositeModel, defining guess, and then instantiating with the composite models.

Thanks,
Glenn

Matt Newville

unread,
Mar 23, 2016, 2:16:31 PM3/23/16
to glenn....@gmail.com, lmfit-py
On Wed, Mar 23, 2016 at 8:19 AM, <glenn....@gmail.com> wrote:
Hi Matt,
I am aware of that sort of 'monkey patching', but I was looking for a more elegant solution. Note in particular I don't think that method will allow you to access "self" since it's not actually a class method. 
It sounds like the cleanest solution is probably subclassing CompositeModel, defining guess, and then instantiating with the composite models.
 
Well, for `guess()` to work at all, you have to know quite a bit about your model, like is it "2 peaks and a smooth background" or "step function times a peak".  There is not a general solution. Specifically, a composite model does not necessarily imply that the `guess()` methods of its components would be appropriate or useful. 

In short, you have to overwrite the `guess()` for each particular model. Whether you do this by assigning to the `guess` method of an instance or subclassing the Model is up to you.   It's not really a matter of one being more elegant, but whether you want to use an object oriented / class inheritance approach or a procedural approach.  Python intentionally supports both.  As an aside: you don't **need** `self` in the procedural approach; you can pass in a reference to the instance of the model if you want.

Alternatively, you can avoid any `guess()` method altogether and assign initial values any way you like.

Hope that helps,

--Matt
Reply all
Reply to author
Forward
0 new messages