# Why LinearModelFit is slower than NonlinearModelFit?

Why LinearModelFit is slower than NonlinearModelFit?

data = Table[{x, 0.68 x - 0.33 + RandomReal[1000]}, {x, 0, 200000}];

nlm = NonlinearModelFit[data, a + b x, {a, b}, x] // AbsoluteTiming
> {0.081027, FittedModel[500.052 +0.679998 x]}

lm = LinearModelFit[data, {1, x}, x] // AbsoluteTiming
> {1.168421, FittedModel[500.052 +0.679998 x]}


It's almost 16 times slower, than NonlinearModelFit!

Since the actual fitting is quite fast:

Fit[data, {1, x}, x] // AbsoluteTiming


{0.0480027, 498.465 + 0.680009 x}

I must assume that the extra time is spent on the construction of the FittedModel object.

The InputForm of the FittedModel objects give some clue. The lm model is considerably more complicated, having two sections additional to the input data that are not in the nlm model. Using highly abridged data:

xlist = Sort @ RandomInteger[1000, 10]
data = Table[{x, 0.68 x - 0.33 + RandomReal[1000]}, {x, xlist}];

{51, 149, 191, 248, 285, 336, 415, 478, 676, 833}

Last @ nlm // InputForm


FittedModel[{"Nonlinear", {a -> 417.39173824442327, b -> 0.8789467743580213}, {{x}, a + b*x}}, {1}, {{51, 427.5070649996163}, {149, 866.0983410584965}, {191, 733.5246301659654}, {248, 226.92795545444534}, {285, 994.7118043721894}, {336, 315.78528074990083}, {415, 1001.5398600985629}, {478, 603.1246737474789}, {676, 777.5181444646195}, {833, 1445.8827150320312}}, Function[Null, InternalLocalizedBlock[{a, b, x}, #1], {HoldAll}]]

Last @ lm // InputForm

FittedModel[{"Linear", {417.39173824442327, 0.8789467743580213}, {{x}, {1, x}}, {0, 0}}, {{1., 1., 1., 1., 1., 1., 1., 1., 1., 1.}},
{{51, 427.5070649996163}, {149, 866.0983410584965}, {191, 733.5246301659654}, {248, 226.92795545444534}, {285, 994.7118043721894}, {336, 315.78528074990083}, {415, 1001.5398600985629}, {478, 603.1246737474789},
{676, 777.5181444646195}, {833, 1445.8827150320312}}, {{1., 51.}, {1., 149.}, {1., 191.}, {1., 248.}, {1., 285.}, {1., 336.}, {1., 415.}, {1., 478.}, {1., 676.}, {1., 833.}}, Function[Null, InternalLocalizedBlock[{x}, #1], {HoldAll}]]


Of course the extra sections are very simple: a vector of ones and a list of the xlist values paired with ones, which doesn't explain why this is slower, but I suspect it may point in the direction of an explanation. That's all I've got.