# How can I consistently get a good logistic regression fit?

I'm executing the command

NonlinearModelFit[data, c/(1 + a Exp[-b x]), {a, b, c}, x]


with the data being

data = { {0, 15576}, {10, 15935}, {20, 16326},
{30, 18235}, {40, 21680}, {50, 22927}, {60, 28667},
{70, 41674}, {80, 50020}, {90, 75979}, {100, 148700},
{110, 197200}, {120, 212801}, {130, 215499}, {140, 227511}}


and I'm getting a nonsensical result. It's a horrible fit. I've tried various Method options and I always get a bad fit. My goal is to try to replicate what a TI-84 would give.

I don't know enough about this stuff to know why the TI-84 always seems to give reasonable fits but Mathematica does not.

-
Here is a shallow description of how TI calculators do logistic fitting. –  Guess who it is. Apr 25 '13 at 9:56

I think you have to give some reasonable start values for the fit. E.g. try

fitFkt = NonlinearModelFit[data,c/(1 + a Exp[-b x]), {a, {b, 0.1}, {c, Max[data[[All, 2]]]}}, x]


As you can see from Show[ListPlot[data], Plot[fitFkt[x], {x, 0, 150}]], the fit is quite ok.

-
Indeed, the second example under "scope" in the documentation for NonlinearModelFit is exactly this kind of thing. Apparently, if you don't specify initial conditions, it assumes initial values 1. reference.wolfram.com/mathematica/ref/NonlinearModelFit.html –  bill s Apr 25 '13 at 8:27
Now, suppose one was given a different set of data with a logistic trend. How does one pick out a reasonable initial guess for b? :) –  Guess who it is. Apr 25 '13 at 13:41
If another data set shows a similar trend and if you do not know which initial value for b you should chose, then you could try to change the Method. E.g. NonlinearModelFit[data, c/(1 + a Exp[-b x]), {a, b, {c, Max[data[[All, 2]]]}}, x, Method -> "Newton"] leads to the same result without any initial guess for b. –  partial81 Apr 26 '13 at 6:35

Here's a rather ad hoc procedure for logistic fitting that I use:

dat = N[{{0, 15576}, {10, 15935}, {20, 16326}, {30, 18235}, {40, 21680}, {50, 22927},
{60, 28667}, {70, 41674}, {80, 50020}, {90, 75979}, {100, 148700}, {110, 197200},
{120, 212801}, {130, 215499}, {140, 227511}}];

(* rough estimate of asymptote *)
c0 = Max[dat[[All, 2]]];

dm = DeleteCases[dat, {_, c0}];
(* linear regression of transformed data *)
{a0, b0} = {Exp[-\[FormalK]], \[FormalM]} /.
FindFit[Transpose[{dm[[All, 1]], Log[#/(c0 - #)] &[dm[[All, 2]]]}],
\[FormalK] + \[FormalM] \[FormalX], {\[FormalK], \[FormalM]}, \[FormalX]];

{at, bt, ct} = {\[FormalA], \[FormalB], \[FormalC]} /.
FindFit[dat, \[FormalC]/(1 + \[FormalA] Exp[-\[FormalB] \[FormalX]]),
{{\[FormalA], a0}, {\[FormalB], b0}, {\[FormalC], c0}}, \[FormalX]]
{874.6314992136595, 0.07113415632530808, 242526.3213562982}


We obtain something a bit useful:

Plot[ct/(1 + at Exp[-bt x]), {x, 0, 140},
Epilog -> {Directive[Red, AbsolutePointSize[6]], Point[dat]}]


FWIW, I also tried the problem on my TI-83 Plus. Using the built-in logistic regression function, I obtained {a, b, c} = {874.6224282, 0.0711340415, 242526.4026}. Pretty close...

-
Thank you for your detailed answer. –  YequalsX Apr 25 '13 at 14:49
You're welcome. I figured you'd want to see a way to handle sigmoidally-shaped data in general instead of just the specific data set in the OP, so I presented one of the usual ways. –  Guess who it is. Apr 25 '13 at 15:12