# Fitting a very simple dataset

I am a beginner in Wolfram Mathematica. I am trying to fit the data from a CSV file using FindFit. In doing so, I am getting the following error message

FindFit::nrjnum: The Jacobian is not a matrix of real numbers at {a} = {1.}.


The output of my CSV file is

data = {{-300, 2.1977}, {-600, 2.61518}, {-900, 5.48259}, {-1200,
4.34585}, {-1500, 3.24366}, {-1800, 2.57632}, {-2100,
2.14541}, {-2400, 1.85425}, {-2700, 1.6508}, {-3000,
1.50487}, {-3300, 1.39795}, {-3600, 1.31817}, {-3900,
1.25768}, {-4200, 1.21115}, {-4500, 1.17488}, {-4800,
1.14627}, {-5100, 1.12344}, {-5400, 1.10504}, {-5700,
1.09006}, {-6000, 1.07776}}


I wonder what is the right way of performing this task. My attempt so far has been

data=Import["/home/data_variance2_r \_final.csv"]
modeltwolevelsat = 1/x^a;
eq = FindFit[data, modeltwolevelsat, {a}, x]


I would appreciate if someone can help me out or give any tip on how to solve this problem.

• Crossposted here. – Rohit Namjoshi Jul 11 at 0:15
• Sorry @RohitNamjoshi . I did not know cross-posting was discouraged. I won't repeat it. – HeitorGalacian Jul 11 at 0:22
• Hi Heitor, crossposting is fine. Just remember to link them to each other so readers are aware of the crosspost and can check to see if the question has already been answered before spending time on it. – Rohit Namjoshi Jul 11 at 1:21

The problem is that you take arbitrary exponents of negative numbers which leads to complex numbers.

A model very similar to yours would be (with an additional parameter)

modeltwolevelsat = b/Abs[x]^a;
eq = FindFit[data, modeltwolevelsat, {a, b}, x]
(* {a -> 0.33341, b -> 26.156} *)


The fit is not too good, though

Show[
ListPlot[data, PlotStyle -> Red],
Plot[modeltwolevelsat /. eq, {x, Min[data[[All, 1]]],
Max[data[[All, 2]]]}]
]


• Thank you @Natas . I was not attentive enough and ended up missing this important detail about complex values ​. – HeitorGalacian Jul 11 at 0:33
• I have slightly changed the model from the initial b/Abs[x]^a to 1+b/Abs[x]^a, as the values of y tend asymptotically to unity as the absolute of x grows. It provides a very good fit. Now, let us suppose that I have a point (x, y) = (0, c) in my data for any c different than zero. In this case, what would be the best way to generalize the power-law model above? I'd have problems with this point for which x=0. How to circumvent this? – HeitorGalacian Jul 11 at 23:38

## FindFormula

Maybe you should try FindFormula before trying FindFit...

SeedRandom[45]
fs = FindFormula[data, x, 5, PerformanceGoal -> "Speed"]
Function[{f},
ListPlot[{data,
Transpose[{data[[All, 1]], f /. x -> # & /@ data[[All, 1]]}]},
Joined -> {False, True}]] /@ fs


## ResourceFunction["QuantileRegression"]

Better results are obtained in with the Wolfram Resource Function "QuantileRegression":

qfunc = ResourceFunction["QuantileRegression"][data, 6, 0.5][[1]];
ListPlot[{data, Transpose[{data[[All, 1]], qfunc /@ data[[All, 1]]}]},
Joined -> {False, True}]
Simplify[qfunc[x]]


• Hey @Anton. This answer is very interesting, though a little beyond what I needed and can understand at the moment. Anyway, I will follow the documentation and try to understand it completely. Thank you for your time. – HeitorGalacian Jul 11 at 0:39
• @HeitorGalacian The point of my answer is that you can "postpone understanding." :) Meaning, using predefined function bases can help you understand the data; then you do model fitting. – Anton Antonov Jul 11 at 13:53
f = Interpolation[data]


Show[ListPlot[data, PlotStyle -> Red], Plot[f[x], {x, -6000, -300}]]


The result shows that the data in dense enough to the define a nice interolating function between -6000 and -1000. The three data point with highest x-value are not dense enough to do so. The Interpolation works by fitting polynomial curves between successive data points.

So the curvature change unnatural left of the data point {-900, 5.48259}. And then abruptly change right of it. This intent is to doubt whether this is the correct peak and prefers a wavy structure to smaller values closer to zero. It is Hermite of order 3.

f = Interpolation[data, InterpolationOrder -> 1] Show[ListPlot[data, PlotStyle -> Red], Plot[f[x], {x, -6000, -300}]]

All other orders and the method Spline look really alike in this question's data.

Looks like Piecewise can help here.

above = {{-300, 2.1977}, {-600, 2.61518}, {-900, 5.48259}};

below = {{-900, 5.48259}, {-1200, 4.34585}, {-1500, 3.24366},
{-1800, 2.57632}, {-2100, 2.14541}, {-2400, 1.85425},
{-2700, 1.6508}, {-3000, 1.50487}, {-3300, 1.39795},
{-3600, 1.31817}, {-3900, 1.25768}, {-4200, 1.21115},
{-4500, 1.17488}, {-4800, 1.14627}, {-5100, 1.12344},
{-5400, 1.10504}, {-5700, 1.09006}, {-6000, 1.07776}};


above is fitted to an exponential (proportional rate growth) curve; below is fitted to an asymmetric sigmoid (5PL), (not using Mathematica though - I'm still working on that).

a = 2.136917 - (0.0000665285/0.006423093) (1 - Exp[-0.006423093 x]);
b = 6.041762 + (0.9936596 - 6.041762)/
(1 + (x/-3.679663)^-2.539859)^2581986;

Plot[Piecewise[{{b, x < -900}, {a, x > -900}}],
{x, -6000, -300}, AxesOrigin -> {0, 0},
Epilog -> {PointSize[0.015], Point /@ Join[below, above]}]