# How to use FindFit to fit an implicit function?

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: 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?

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}]] Note the use of formal parameters as stand-ins for the parameters sought within NArgMin[].

• 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). – J. M. will be back soon Aug 31 '12 at 12:19
• +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. – whuber Aug 31 '12 at 13:21
• A 2 per mil in the objective function ... OMG – Dr. belisarius Aug 31 '12 at 13:58
• @belisarius, if you're angling for four good digits... :) – J. M. will be back soon Aug 31 '12 at 14:03
• JM: Help yourself and remove some data points :) – Dr. belisarius Aug 31 '12 at 14:31

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

• Thanks very much! It works well now. – lyon Aug 31 '12 at 11:43
• 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. – Sasha Aug 31 '12 at 12:48
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.

• This provides another method to fit a implicit function. I appreciate your nice answer. – lyon Aug 31 '12 at 11:49