If I have a function of list argument (presumably with large number of entries), how can I pass it to NonlinearModelFit? I don’t want to pass it by pattern checking (f[x_?(VectorQ[#, Numeric!]&)]) because apparently it turns off some intermediate operations and heavily slows down the fitting.

Example:

f[x_, a_] := Exp[-Sin[{x, x}.a]];

NonlinearModelFit[RandomReal[{0, 1}, {10, 3}], f[x, a], {{a, {1, 2}}},

x]

=================

2

What are your fit parameters?

– BlacKow

Apr 13 at 19:34

@BlacKow I corrected, does my question make sense?

– Al Guy

Apr 13 at 22:05

What are dimensions of x and a?

– BlacKow

Apr 13 at 22:13

2

Oh… I think I understand now, you want to find a matrix that fits your data

– BlacKow

Apr 13 at 22:21

=================

2 Answers

2

=================

I’ve always done it like this, and I’ve done fits with a few hundred parameters so it isn’t that much of a pain.

The point is that you define the function f to take a vector input for x and a. Then you define a vector of variables, {x1, x2,….} and that is the fourth argument to NonlinearModelFit. The second argument to NonlinearModelFit needs to be a scalar function, where all the matrix expansions have happened already. In the case here, f[variables, parameters] evaluates the matrix product before it does any fitting.

parameters = Array[a, {7}]

variables = Array[x, {7}]

guess = Range[7]

f[x_, a_] := Exp[-Sin[x.a]];

nlm = NonlinearModelFit[RandomReal[{0, 1}, {40, 8}],

f[variables, parameters], Transpose[{parameters, guess}],

Evaluate@variables]

nlm[“BestFitParameters”]

(* {a[1], a[2], a[3], a[4], a[5], a[6], a[7]} *)

(* {x[1], x[2], x[3], x[4], x[5], x[6], x[7]} *)

(* {1, 2, 3, 4, 5, 6, 7} *)

(* {a[1] -> 3.47592, a[2] -> 0.155765, a[3] -> 4.18935, a[4] -> 1.59981,

a[5] -> 7.34998, a[6] -> 1.60615, a[7] -> 10.3245} *)

But your x is a scalar and a is a vector. I think he wants x as vector and a as a matrix.

– BlacKow

Apr 14 at 14:46

That isn’t how I read his code, he gives an initial guess for a that is a vector. Likewise he takes the Sin of {x, x}.a which to me implies {x, x}.a is a scalar. Sure, he could be taking advantage of the listability of Sin and Exp, but the way it is written x should be a scalar.

– JasonB

Apr 14 at 14:50

Well if you look at it your way, there is no need to have several as, because you could just replace it with Exp[-Sin[ax]]. Look at the edit history of his question, his last edit confused it a bit.

– BlacKow

Apr 14 at 14:58

Right, but I’m sure this is just a minimal simple working example. I’m gonna go on the assumption that the argument of Sin and Exp should be a scalar, but this can be easily extended to account for a vector x as well. Whether it’s x.a.x or x.a, it’s easily extended. I think the main point is that you want to do the matrix alagebra on your function rather than asking FindFit to do it.

– JasonB

Apr 14 at 15:02

1

You don’t, you define the function f to take a vector input for x and a. Then you define a vector of variables, {x[1], x[2],….} and that is the fourth argument to NonlinearModelFit. The second argument to NonlinearModelFit needs to be a scalar function, where all the matrix expansions have happened already. In the case above, f[variables, parameters] evaluates the matrix product before it does any fitting.

– JasonB

Apr 14 at 15:11

This is not a real answer, but applying @JasonB’s approach to 2D case. So x is a vector and a is a matrix.

I simplified the function to see how good is the fit in simple case.

We have noisy data and we want to try to find fit and compare it with test

f[x_, a_] := Exp[-x.a.x];

test = {{0.75, 0.}, {0, 0.25}};

data = Flatten[{#, f[#, test] + RandomReal[{-0.05, 0.05}]}] & /@

Tuples[Range[-4, 4, 0.1], 2];

parameters = Array[a, {2, 2}];

z = Array[x, {2}];

paramFull = Flatten[#, 1] &@Map[{#, 0} &, parameters, {2}]; (* sets initial guess to zero for all parameters *)

fit = NonlinearModelFit[data, f[z, parameters], paramFull, z];

parameters /.fit[“BestFitParameters”]

(*{{0.748501, 96.3969}, {-96.3989, 0.248822}}*)

So the fit is pretty good (although the non diagonal elements are way off it doesn’t matter, because antisymmetric matrix gives zero in xTAxx^TAx).

Show[ListPointPlot3D[data, PlotRange -> Full],

Plot3D[fit[x, y], {x, -4, 4}, {y, -4, 4}, PlotRange -> Full,

Mesh -> None]]

Thanks!………

– Al Guy

Apr 14 at 18:41