In this example written in TypeScript, we will fit a generic 2nd degree polynomial defined to a given set of fit()
function. We're able to use the best-fit curve given by our summary to extrapolate for any
Here is the function used to generate the dataset.
Here is the model function used for curve fitting.
In the output, the line with params:
contains the set of best-fit parameters in the order of the model function parameters. That means, my outputs are in the order of
The other lines in the summary tell us other information from the computation. See summary for more details.
f
is the best-fit function we used to extrapolating from our dataset.params
contains the set of best-fit parameters.error
is the total residual squared error (for all data points.) This is the value that the algorithm is minimizing.errorAvgAbs
is the average absolute error we would get from the model function with params
compared to the actual dataset values. Lower numbers are better here. This only compares the best-fit with values from the dataset. By extrapolating beyond our dataset, our average error may increase. See below for an explanation.In this example, the x values for our data points are given as [-2, -1, 0, 1, 2]
. If we interpolate within this range, the model will be about as accurate as what is shown in the summary. Extrapolating very far beyond either end of this range (e.g.
Mind the order of your parameters!
fit()
will output a parameter array that follows the same order as the model function parameters, even if it is non-intuitive! For example, if my function signature looks likef(x, a2, a1, a0)
, thensummary.params
would return an array[a2, a1, a0]
. You would accessa2
witha[0]
!
Follow these steps to create a new project workspace and install the datafit dependency to run this example.
# Create and open project folder
mkdir Single_Variable_demo
cd Single_Variable_demo
# Initialize project and install dependencies
npm init -y
npm i datafit@1.4.8
# Create and open source file
touch "Single Variable.mjs"
open "Single Variable.mjs"
Copy and paste this source code into Single Variable.mjs
.
import { fit } from 'datafit';
// Define a model function for curve fitting.
// Let's use a generic 2nd degree polynomial
// with all constants unknown. Unfortunately,
// in JavaScript we cannot define default
// parameter values in the signature, so we
// must use the `??` operator within the function.
function f(x, a0, a1, a2) {
a0 = a0 ?? 1.3;
a1 = a1 ?? 1.0;
a2 = a2 ?? -0.2;
return a2 * x ** 2 + a1 * x + a0;
}
// Define a function to add noise to the dataset
function noise(A) {
return A * (2 * Math.random() - 1)
}
// Define the dataset from our noisy signal
const data = [-2, -1, 0, 1, 2].map(x => ({ x: x, y: f(x) + noise(0.1) }));
console.log('Dataset', data);
// Compute the best-fit set of parameters
// starting with an initial guess of [x^2 + x + 1]
// with 10,000 iterations, and each parameter
// can vary up to 50% on the first iteration
const summary = fit(f, data, [1, 1, 1], 10000, 0.5);
console.log('Summary', summary);
// Compute the actual value and
// best-fit value of f(3) to compare
const f3_act = f(3);
const f3_fit = summary.f(3);
console.log('f(3)', f3_act, f3_fit);
// Compute the relative error
const rel_error = (f3_fit - f3_act) / f3_act * 100;
console.log('Error: ' + rel_error.toFixed(2) + '%');
In Single_Variable_demo/
, execute Single Variable.mjs
with NodeJS to generate an output.
node "Single Variable.mjs"
You should expect to see an output similar to the one below.
Dataset [
{ x: -2, y: -1.4662935499313132 },
{ x: -1, y: 0.11653884497400244 },
{ x: 0, y: 1.252700841192022 },
{ x: 1, y: 2.065039051080345 },
{ x: 2, y: 2.450257451843449 }
]
Summary {
f: [Function: f],
params: [ 1.2724470417716522, 0.9775229402119768, -0.19424686280026762 ],
error: 0.0007733384273995462,
errorAvgAbs: 0.012436546364642769
}
f(3) 2.5 2.456794097205174
Error: -1.73%