19
$\begingroup$

Now I am trying to fit some data with a implicit model function.

Firstly, I tried a toy example.

Toy example with input and output

data = {{1, 1}, {2, 1.4}, {3, 1.8}, {4, 2.4}, {5, 2.9}};
fitfunc[a_,b_,x_] := y /. FindRoot[a y + b Log[y] == x, {y, 1}];
FindFit[data, fitfunc[a, b, x], {a, b}, x]

Mathematica gives the following warning message and answer:

FindRoot::nlnum: The function value {0. +1. a-1. x} is not a list of numbers with dimensions {1} at {y} = {1.}. >>
ReplaceAll::reps: {FindRoot[a y+b Log[y]==x,{y,1}]} is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing. >>
{a -> 0.986636, b -> 1.96879}

The fit seems good.

Show[ListPlot[data], ContourPlot[Evaluate[a y + b Log[y] == x /. %], {x, 1, 5}, {y, 1, 4}]]

The fit result:

enter image description here

I have read the documentation of Symbolic Evaluation, and tried to use NumberQ in the function declaration, but I got the same warning message.

What am I doing wrong and how to solve this problem to avoid the warning message?

$\endgroup$
0

3 Answers 3

15
$\begingroup$

One can always fall back on the definition of least-squares fitting, if the situation demands:

data = {{1, 1}, {2, 1.4}, {3, 1.8}, {4, 2.4}, {5, 2.9}};

{a, b} = NArgMin[Norm[Function[{x, y}, \[FormalA] y + \[FormalB] Log[y] - x] @@@ data],
                 {\[FormalA], \[FormalB]}]
   {0.9909829665303092, 1.952060702019563}

Show[ListPlot[data], ContourPlot[a y + b Log[y] == x, {x, 1, 5}, {y, 1, 4}]]

fit of implicit nonlinear model

Note the use of formal parameters as stand-ins for the parameters sought within NArgMin[].

$\endgroup$
5
  • $\begingroup$ Note, also, that this version returns a lower value for the least squares objective function (0.129153) as opposed to the version using FindFit[]+FindRoot[] (0.129416). $\endgroup$ Commented Aug 31, 2012 at 12:19
  • 6
    $\begingroup$ +1 This answer is squarely within the spirit of the question: if the function is to be defined implicitly, then we are not emphasizing errors in either the x or y directions (unlike FindFit), but should be penalizing them in a symmetric way, which is what this approach does. $\endgroup$
    – whuber
    Commented Aug 31, 2012 at 13:21
  • $\begingroup$ A 2 per mil in the objective function ... OMG $\endgroup$ Commented Aug 31, 2012 at 13:58
  • $\begingroup$ @belisarius, if you're angling for four good digits... :) $\endgroup$ Commented Aug 31, 2012 at 14:03
  • $\begingroup$ JM: Help yourself and remove some data points :) $\endgroup$ Commented Aug 31, 2012 at 14:31
14
$\begingroup$

It's an evaluation problem. fitfunc[a, b, x] evaluates to your definition which is y /. FindRoot[a y + b Log[y] == x, {y, 1.}] this returns the error, since it cannot find the root without numeric arguments for a and b. To avoid it, you need to tell it not to evaluate your function until you have numeric arguments. I assume this is what you tried to do with NumberQ.

 data = {{1, 1}, {2, 1.4}, {3, 1.8}, {4, 2.4}, {5, 2.9}};
 fitfunc[a_?NumericQ, b_?NumericQ, x_?NumericQ] := 
             y /. FindRoot[a y + b Log[y] == x, {y, 1.}];

 FindFit[data, fitfunc[a, b, x], {a, b}, x]

Returns

{a -> 0.986636, b -> 1.96879}

With no warning messages

$\endgroup$
2
  • $\begingroup$ Thanks very much! It works well now. $\endgroup$
    – lyon
    Commented Aug 31, 2012 at 11:43
  • 5
    $\begingroup$ Of course, in this toy example, explicit solution is also available. $y = \frac{b}{a} W\left(\frac{a}{b}\exp\left(\frac{x}{b}\right)\right)$. Using fitfuncExact[a_, b_, x_] := ProductLog[a/b Exp[x/b]] b/a gives the same fitted parameters. $\endgroup$
    – Sasha
    Commented Aug 31, 2012 at 12:48
12
$\begingroup$
data = {{1, 1}, {2, 1.4}, {3, 1.8}, {4, 2.4}, {5, 2.9}};
fitfunc[a_, b_, x_] := y /. Solve[a y + b Log[y] == x, {y},InverseFunctions -> True];
FindFit[data, fitfunc[a, b, x], {a, b}, x]

When inverse functions are allowed, Solve solves for f[expr] first, then applies InverseFunction[f] to the result, equates it to expr, and continues trying to solve for the remainder of the variables.

$\endgroup$
1
  • $\begingroup$ This provides another method to fit a implicit function. I appreciate your nice answer. $\endgroup$
    – lyon
    Commented Aug 31, 2012 at 11:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.