Message Boards Message Boards

0
|
10156 Views
|
4 Replies
|
0 Total Likes
View groups...
Share
Share this post:

Use FindFit with functions with integer input only?

Posted 8 years ago

I have defined a few basic real functions that accept integer arguments only. I tried to use my basic functions to fit decimal data. But it keep saying that: "Unable to solve for the fit parameters; the design matrix is nonrectangular, non-numerical, or could not be inverted."

I figured out a work-around: to allow my basic functions to accept decimal values. But I really like to keep the basic functions 'pure' with integer input only. I have attached a picture to explain the issue.

The example is simplified: fit 4 points (1,1), (2,1), (3,1) and (4,1) using sin^2(x) and cos^2(x). The answer is obviously:

  1 * sin^2(x) + 1* cos^2(x).

In example 1, I defined sin^2 and cos^2 to accept integer arguments only. The FindFit worked as expected.

In example 2, I used decimals y=1.0 for one of the point. The FindFit failed.

In example 3, I allowed sin^2 and cos^2 to accept real numbers. Now FindFit worked again.

The strange thing is: the integral argument is about x-coordinates; yet FindFit failed when y-coord is not integer. Why would the fitting algorithm insists lattice points (integer x and y) if x has to be 1,2,3,4,5,...?

This behavior seemed a 'bug' to me. Because, in my real example, my basic functions are real, they produce decimal numbers, But I have good reason to restrict the arguments to integers only. I don't want to throw away the "n_Integer" tag in the argument. examples

POSTED BY: Yuen Mlv
4 Replies
Posted 8 years ago

I am not trying to fit in integer domain. I am actually fitting data such as:

(1,5.213),  (2,8.140),  (3,1.917),  (4,5.000),  (5,-1.191),  (6,0.182),  (7,3.851),  (8,-9.611)

with basic functions which are defined for x=1,2,3,4,5,... (undefined for decimal x). The y-coordinates are not integers. The example I gave in the original post shows the 'strange' behavior that y has to be integers in order for it to work.

In my actual case, y coordinates are real. Everything works correctly if I throw away n_Integer tag. But I know Mathematica did not actually use any non-integer x in the fitting algorithm because if it had used, it would have encountered error: my basic functions are undefined for non-integer x. Hence un-restricting x to integers has NO real benefit/significance for the actual Mathematica's fitting algorithm.

As I say, the basic functions are undefined for non-integer x; and the Mathematica's FindFit algorithm works perfectly with such restriction. But I can not tell Mathematica explicitly that x has to be integers.

The truth remains that x has to be integers only, so I would like to keep n_Integer tag, and still have Mathematica uses its actual FindFit algorithm, which works perfectly anyway.

POSTED BY: Yuen Mlv
Posted 8 years ago

But I know Mathematica did not actually use any non-integer x in the fitting algorithm because if it had used, it would have encountered error: my basic functions are undefined for non-integer x.

It does throw an error as seen from the second example in your original post (emphasis is mine): "FindFit::fitm: Unable to solve for the fit parameters; the design matrix is nonrectangular, non-numerical, or could not be inverted." The same message is generated when non-integer x is present in the data:

FindFit[{{1., 1}, {2, 1}, {3, 1}, {4, 1}}, (a + 1) sin2[x] + b cos2[x], {a, b}, x];

FindFit::fitm: Unable to solve for the fit parameters; the design matrix is nonrectangular, non-numerical, or could not be inverted. >>

From this message I suppose that when y values aren't integers Mathematica does pass non-integer values for x to your basic functions, hence the error.

Hence un-restricting x to integers has NO real benefit/significance for the actual Mathematica's fitting algorithm.

You can find what the algorithm is by using Trace:

trace = Trace[FindFit[{1, 1, 1, 1}, (a + 1) sin2[x] + b cos2[x], {a, b}, x], 
   TraceInternal -> True];
trace[[6 ;;]] 

From the output you see that in this case at first the objective function is evaluated for integer x, then real values for Sin and Cos are calculated and passed to PseudoInverse. It shouldn't be difficult to implement this algorithm yourself.

Or you can use FindMinimum as follows (note that y = 1. is non-integer):

sin2[n_Integer] := Sin[n]^2
cos2[n_Integer] := Cos[n]^2
FindMinimum[
 Total[Table[(a + 1) sin2[x] + b cos2[x] - 1., {x, 1, 4}]^2], {a, b}]
{3.15853*10^-32, {a -> 0., b -> 1.}}

Alternatively you can relax your conditions as follows:

sin2[n_ /; FractionalPart[n] == 0] := Sin[n]^2
cos2[n_ /; FractionalPart[n] == 0] := Cos[n]^2

FindFit[{{1., 1.}, {2, 1}, {3, 1}, {4, 1}}, a sin2[x] + b cos2[x], {a, b}, x]
{a -> 1., b -> 1.}
POSTED BY: Alexey Popkov
Posted 8 years ago

Actually the fact that with non-integer y Mathematica supply non-integer x to your basis functions can be proven as simple as follows:

sin2[n_Integer] := Sin[n]^2
sin2[n_Real] := (Print["sin2[", n, "]"]; Sin[n]^2)
cos2[n_Integer] := Cos[n]^2
cos2[n_Real] := (Print["cos2[", n, "]"]; Cos[n]^2)

FindFit[{1., 1, 1, 1}, a sin2[x] + b cos2[x], {a, b}, x]

sin2[1.]

cos2[1.]

sin2[2.]

cos2[2.]

sin2[3.]

cos2[3.]

sin2[4.]

cos2[4.]

{a -> 1., b -> 1.}
POSTED BY: Alexey Popkov
Posted 8 years ago

As you can see from the Documentation for FindFit, it has the following Methods: "ConjugateGradient", "Gradient", "LevenbergMarquardt", "Newton", "NMinimize", and "QuasiNewton". With exception for NMinimize none of these supports fitting in integer domain. So you should recast your problem for NMinimize as follows:

sin2[n_Integer] := Sin[n]^2
cos2[n_Integer] := Cos[n]^2
NMinimize[{Total[Table[a sin2[x] + b cos2[x] - 1, {x, 1, 4}]^2]}, {a, b}, Integers]
{3.15853*10^-32, {a -> 1, b -> 1}}
POSTED BY: Alexey Popkov
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract