2
$\begingroup$

Simplified version Using the simpler version suggested by @ulrich-neumann :

data1 = Table[{i, i + 2}, {i, 1, 10}]
data2 = Table[3 i + 2, {i, 1, 10}]
fd = LinearModelFit[{data1, data2}]
testData = Table[{i, i + 2}, {i, 1, 3}](*{{1, 3}, {2, 4}, {3, 5}}*)

Map[Apply[fd, #] &, testData] (* {5., 8., 11.} WORKS AS EXPECTED *)

`

Now I want to embed this in a function :

testFunc1[f1_, data_] := Map[Apply[f1, #] &, data]
testFunc2[f1_, data_] := Table[Apply[f1, data[[i]]] , {i, 1, Length[data]}]
 
testFunc3[f1_, data_] := f1 @@@ data (* as suggested by @MarcoB *)
testFunc4[f1_, data_] := {#, f1 @@ #} & /@ data 

I expect the results to be the same for testFunc1,2,3 but they aren't:

testFunc2[fd, testData]  (* {5., 8., 11.} *)
testFunc3[fd, testData]  (* {5., 8., 11.} *)

but

testFunc1[fd, testData]  (* error messages plus {{{1, 3}, {2., 1.}.{{1, 3}, 3}}, .... *)
testFunc4[fd, testData]  (* error messages plus {{{1, 3}, {2., 1.}.{{1, 3}, 3}}, .... *)

Question : Why do these not give the same output ?

original question I am generating a FittedModel and want to evaluate it on a list of data. This works fine when I use Table to generate the results, but not when I try to use Map. The simple example below takes two inputs x and x+2, and produces the output 3x+2. The fitted model works as expected, until I try to Map it over a list of inputs.

    With[{data1 = Table[{i, i + 2}, {i, 1, 10}], 
      data2 = Table[3 i + 2, {i, 1, 10}]}, 
     With[{fd = LinearModelFit[{data1, data2}], 
       testData = Table[{i, i + 2}, {i, 1, 3}]}, Print["function is ", fd];
(* check it works *)      
      Print["function applied to {4,6} is ", fd[4, 6]]; 
      
(* explicitly generate input data *)      
      Print[Grid[
        Table[{"apply ", fd, " to args ", {i, i + 2}, " result:", 
          Apply[fd, {i, i + 2}]}, {i, 1, Length[testData]}], 
        Frame -> True]];
    
(* Use Table to find the value over test data *)
      Print[Grid[
        Table[{"apply ", fd, " to args ", testData[[k]], " result:", 
          Apply[fd, testData[[k]]]}, {k, 1, Length[testData]}], 
        Frame -> True]];
     
(* Try to map over test data *)      
      Print[Grid[
        Map[{"apply ", fd, " to args ", #, " result:", Apply[fd, #]} &, 
         testData], Frame -> True]]]]

Output looks like this:

output

so I am guessing the FittedModel somehow picks up the wrong arguments when I try to use Map. Is there a way to make Map behave the same as Table ?

$\endgroup$
2
  • 1
    $\begingroup$ Since I assume that this is a minimal example, your code is unnecessarily complex with all the With, Print, Grid formatting expressions. Can you pare it down to the MINIMUM that reproduces your problem, without formatting and scoping constructs? In particular, I don't think you need to show us what behaves according to expectations, but concentrate on what doesn't. Also, have you tried fd @@@ testData or {#, fd @@ #}& /@ testData? Do those work? $\endgroup$
    – MarcoB
    Commented Dec 8, 2021 at 13:42
  • $\begingroup$ Looks like a bug. Please report it to the support. $\endgroup$ Commented Dec 9, 2021 at 8:25

2 Answers 2

2
$\begingroup$

I think your code should work. Let's get both the FittedModel object as well as the pure function within it:

fd = LinearModelFit[{data1, data2}]
fdFunction = LinearModelFit[{data1, data2}]["Function"]

The first returns the FittedModel object; the second returns the pure function expression obtained from the fit. In my opinion, the two should behave the same way on any input. Indeed:

({#, fd @@ #} & /@ testData ) == ({#, fdFunction @@ #} & /@ testData)
(* True *)

However, the two behave differently when used in your testFunc4:

ClearAll[testFunc4]
testFunc4[f1_, data_] := {#, f1 @@ #} & /@ data

testFunc4[fdFunction, testData]
testFunc4[fd, testData]

The first outputs {{{1, 3}, 5.}, {{2, 4}, 8.}, {{3, 5}, 11.}} as expected. The second returns a mess of errors and an incorrect final expression. I think you are running into some scoping conflict between the pure function inside the FittedModel and the pure function you wrote in your testFunc, but I can't put my finger on it quite yet. I am not even sure if the problem should exist, or if this is buggy behavior.

$\endgroup$
2
  • 2
    $\begingroup$ Using the pure function gives consistent output for the different ways of mapping it over the list. The fact that the FittedModel gives different output suggests a bug to me. $\endgroup$
    – Martin42
    Commented Dec 9, 2021 at 8:10
  • $\begingroup$ @Martin42 I agree. Please report this behavior to Wolfram Support. $\endgroup$
    – MarcoB
    Commented Dec 9, 2021 at 8:57
0
$\begingroup$

Your model is ok I think (but somewhat convoluted):

data1 = Table[{i, i + 2}, {i, 1, 10}]
data2 = Table[3 i + 2, {i, 1, 10}] 
fd = LinearModelFit[{data1, data2}]

fd is a pure function of two variables.

Apply the fit to testData

testData = Table[{i, i + 2}, {i, 1, 3}](*{{1, 3}, {2, 4}, {3, 5}}*)
Map[Apply[fd, #] &, testData] (*{5., 8., 11.}*)

The corrected first print command :

Print[Grid[Table[{"apply ", fd[x, y], " to args ", {i, i + 2}, " result:", Apply[fd, testData[[i]]]}, {i, 1, Length[testData]}],Frame -> True]]

enter image description here

$\endgroup$
1
  • $\begingroup$ This works (when mod = fd ) ... but not when embedded in a function - see revised question $\endgroup$
    – Martin42
    Commented Dec 8, 2021 at 15:17

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.