[SciPy-Dev] curve_fit() should require initial values for parameters

Johann Goetz theodore.goetz at gmail.com
Wed Jan 30 11:46:52 EST 2019


I appologize for the anecdotal nature of my experience, but I have used
curve_fit() since it was first introduced and I just took a tour of almost
all the times I've used it (well over 100 times, all told) and not once did
I fail to provide initial parameters - even if I merely set them to all
ones which it turns out I did more than I care to admit. This covers
"production-level" code used by others as well as one-off throw-away
jupyter notebooks. It may be that it never occured to me that p0 was
optional.

Anyways, I'm all for correctness and quality over backward-compatibility,
even in the libraries and modules I consume, so I'd vote for making p0
required.
-- Johann <https://sites.google.com/site/theodoregoetz/>


On Wed, Jan 30, 2019 at 8:05 AM Matt Newville <newville at cars.uchicago.edu>
wrote:

> Hi Ilhan,
>
> On Tue, Jan 29, 2019 at 10:54 AM Ilhan Polat <ilhanpolat at gmail.com> wrote:
>
>> > The problem I have with this is that there really is not an option to "try
>> automatic first".  There is "try `np.ones(n_variables)` first".   This,
>> or any other value, is really not a defensible choice for starting values.
>>  Starting values always depend on the function used and the data being
>> fit.
>>
>> Why not? 1.s are as good as any other choice.
>>
>
> Well, I agree that `np.ones(n_variables)` is as good as any other choice.
> All default choices are horrible and not defensible.
>
> Mathematically, algorithmically, and conceptually, initial values ARE
> REQUIRED for non-linear least squares optimization.  The codes underlying
> `curve_fit()` (including `leastsq` and the mess that is `least_square`) do
> not permit the user to not provide initial values.  The algorithms used
> simply do not make sense without initial values.
>
> Programmatically, an optional keyword argument to a function, say with a
> default value of `None`, implies that there is a sensible default for that
> value.  Thus, default fitting tolerances might be 1.e-7 (or, perhaps square
> root of machine precision) or the default value for "method to calculate
> jacobian" might be `None` to mean "calculate by finite difference".  For
> these optional inputs, the function (say, `curve_fit()`) has a sensible
> default value that will work independently from the other input.
>
> That notion of "independent, sensible default value" is not ever possible
> for the initial values `p0` for `curve_fit`.  Sensible initial values
> always depend on the data to be fit and the function modeling the data.
>  Change the data values dramatically and `p0` must change.  Change the
> definition of the function (or even the order of the arguments), and `p0`
> must change.   There is not and cannot be a sensible default.
>
> Telling the user that `p0` is optional and can be `None` (as the current
> documentation does clearly state) is utterly and profoundly wrong.   It is
> mathematically indefensible.  It is horrible API design.  It harms the
> integretiy of `scipy.optimize` to tell the user this.
>
>  I don't know anything about the curve fit I will get in the end. So I
>> don't need to pretend that I know a good starting value.
>>
>
> It is not possible to do curve-fitting or non-linear least-squares
> minimization when you "don't know anything".  The user MUST provide data to
> be modeled and MUST provide a function to model that data.   It is
> "pretending" to think that this is sufficient.  The user also must provide
> initial values.
>
> Maybe for 3 parameter functions, fine I can come up with an argument but
>> you surely don't expect me to know the starting point if I am fitting a 7
>> parameter func involving esoteric structure. At that point I am completely
>> ignorant about anything about this function. So not knowing where to start
>> is not due to my noviceness about the tools but because by definition. My
>> search might even turn out to be convex so initial value won't matter.
>>
>
> It is not possible to do curve-fitting or non-linear least-squares
> minimization when one is completely ignorant of the the function.
>
>
>
>> > Currently `curve_fit`  converts `p0=None` to `np.ones(n_variables)`
>> without warning or explanation.  Again, I do not use `curve_fit()` myself.
>> I find several aspects of it unpleasant.
>>
>> It is documented in the p0 argument docs. I am using this function quite
>> often. That's why I don't like extra required arguments. It's annoying to
>> enter some random array just to please the API where I know that I am just
>> taking a shot in the dark.
>>
>
> It is not an extra keyword argument.  It is required input for the
> problem. `curve_fit()` is converting your feigned (or perhaps obstinate)
> ignorance to a set of starting values for you.   But starting values simply
> cannot be independent of the input model function or input data.
>
>
> I am pretty confident that if we force this argument most of the people
>> you want to educate will enter np.zeros(n). Then they will get an even
>> weirder error then they'll try np.ones(n) but misremember n then they get
>> another error to remember the func parameter number which has already
>> trippped up twice. This curve_fit function is one of those functions that
>> you don't run just once and be done with it but over and over again until
>> you give up or satisfied. Hence defaults matter a lot from a UX
>> perspective. "If you have an initial value in mind fine enter it otherwise
>> let me do my thing" is much better than "I don't care about your quick
>> experiment give me some values or I will keep tripping up".
>>
>>
> I refuse to speculate on what "most users" will do, and I also refuse to
> accept your speculation on this without evidence.  There a great many
> applications of curve-fitting for which `np.ones(n_variables)` and
> `np.zeros(n_variables)` will completely fail -- the fit will never move
> from the starting point.   For the kinds of fits done in the programs I
> support, either of these would mean that essentially all fits would never
> move from its starting point, as at least one parameter being 0 or 1 would
> essentially always mean the model function was 0 over the full data range.
>
>
> But, again, I don't use `curve_fit` but other tools built on top of
> `scipy.optimize()`.  Generally, the model function and data together imply
> sensible or at least guessable default values, but these cannot independent
> of model or data.  In lmfit we do not permit the user to not supply default
> starting values -- default parameter values are `None` which will quickly
> raise a ValueError. I don't recall ever getting asked to change this.
> Because it should be obvious to all users that each parameter requires an
> initial value.  Where appropriate and possible, we do provide methods for
> model functions to make initial guesses based on data.  But again, the
> starting values always depend on model function and data.
>
> Default arguments *do* matter from a UX perspective when defaults are
> sensible.   `curve_fit` has three required positional arguments:  a model
> function (that must be annoying to have to provide), "y" data to be fit
> (well, I guess I have that), and "x" data.  Why are those all required?
> Why not allow `func=None` to be a function that calculates a sine wave?
> Why not allow `y=None` to mean `np.ones(1000)`?  Why not allow `x=None` to
> mean `np.arange(len(y))`?    Wouldn't that be friendlier to the user?
>
>
> >   But this behavior strikes me as utterly wrong and a disservice to the
>> scipy ecosystem.   I do not think that a documentation change is
>> sufficient.
>>
>> Maybe a bit overzealous?
>>
>>
> Nope, just trying to help `curve_fit()` work better.
>
> --Matt
>
> _______________________________________________
> SciPy-Dev mailing list
> SciPy-Dev at python.org
> https://mail.python.org/mailman/listinfo/scipy-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/scipy-dev/attachments/20190130/daaaf597/attachment-0001.html>


More information about the SciPy-Dev mailing list