There are a few issues with the fitting. Some issues are issues with fitting in general (i.e., no matter what software package is used) and some issues are caused by you. First the issues caused by you:
- Maybe it's different in your field but I find it rare that errors have a uniform distribution.
- You have the errors increase with the predictor value (which is fine) but you then attempt a fit with
NonlinearModelFit
that assumes the variance of the errors is constant for all values of the predictors.
I understand that this is a toy example but understand you have put in issues that can cause a lack of fit that are not the fault of NonlinearModelFit
.
The function being fit (a sine curve) typically requires good starting values (as NonlinearModelFit
uses an iterative fitting procedure that attempts to find parameters that minimize a sum of squares). The sum of squares being minimized for this example fluctuates wildly (i.e. not in a nice convex manner):
(* Generate data *)
SeedRandom[12345];
target[x_] := Sin[5 x] + RandomReal[{0, x}]/10
discretized = Table[{x, target[x]}, {x, 0, 1, 0.1}]
(* Calculate sum of squares for various values of the parameter a *)
sumOfSquares = (discretized[[All, 2]] -
Sin[a discretized[[All, 1]]])^2 // Total
(* 0. + (0.482725 - Sin[0.1 a])^2 + (0.857126 - Sin[0.2 a])^2 + (1.0104 -
Sin[0.3 a])^2 + (0.918241 - Sin[0.4 a])^2 + (0.621625 -
Sin[0.5 a])^2 + (0.185401 - Sin[0.6 a])^2 + (-0.30125 -
Sin[0.7 a])^2 + (-0.69353 - Sin[0.8 a])^2 + (-0.968016 -
Sin[0.9 a])^2 + (-0.92088 - Sin[1. a])^2 *)
(* Plot sum of squares vs value of a *)
Plot[sumOfSquares, {a, -20, 20}, PlotRange -> {All, {0, Automatic}}, Frame -> True,
FrameLabel -> (Style[#, Bold, 18] &) /@ {"a", "Sum of squares"}]
From the above plot it appears that getting an estimate of $a$ around 5 minimizes the sum of squares (which clearly matches the value used to generate the data). However, because there are many local minima (as pointed out by @SjoerdSmit), the algorithm can stop at the wrong value.
If we look at starting values from -23 to 20, there are 7 (essentially) unique results. Here is a plot of the starting value vs. the resulting estimate of $a$:
results =
Table[{a0, a, sumOfSquares[a], sumOfSquares[a0]} /.
NonlinearModelFit[discretized, Sin[a x], {{a, a0}}, x][BestFitParameters"],
{a0, -23, 20, 1/10}];
(* Round the estimates of a to account for not stopping at the exact same value *)
results[[All, 2]] = Round[results[[All, 2]], 0.001];
(* Separate results by the unique values of the estimates of a *)
uniqueA = DeleteDuplicates[results[[All, 2]]];
r = Table[Select[results, #[[2]] == uniqueA[[i]] &], {i, Length[uniqueA]}];
(* Plot results *)
Show[ListPlot[r[[All, All, {1, 4}]], Joined -> True,
PlotRange -> {All, {0, Automatic}}, Frame -> True,
FrameLabel -> (Style[#, Bold, 18] &) /@ {"a", "Sum of squares"}],
ListPlot[r[[All, All, {2, 3}]], PlotStyle -> PointSize[0.02]],
PlotRangeClipping -> False]
So for this particular model and data generation process, starting values for $a$ should be between 2 and 8.
I'll also note that your not-completely described real model ("a product of polynomials and non-linear functions") might also be a linear model if that model is "linear in the parameters" even though there are nonlinear functions of the predictors. In that case LinearModelFit
would be more stable (as it doesn't require - or even allow - starting values).
a
, like:NonlinearModelFit[discretized, approx[x], {{a, 4}}, x]
. Providing constraints on your fit parameters is highly recommended as well. $\endgroup$