Single Variable

In this example written in TypeScript, we will fit a generic 2nd degree polynomial defined to a given set of (x,y) points. We'll create this dataset based on a known formula for a 2nd degree polynomial, and add some random high-frequency noise. The initial guess for our constants will all be zero, given by a2=a1=a0=0. Then, we'll determine the true value and best-fit value of f(3) using the parameter set found by the fit() function. We're able to use the best-fit curve given by our summary to extrapolate for any x value.

Here is the function used to generate the dataset.

f(x)=0.2x2+x+1.3

Here is the model function used for curve fitting.

f(x,a¯)=a2x2+a1x+a0

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 a0,a1,a2. How close is it to our original function? Try it for yourself and see if you obtain similar results!

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. f(100)) will probably not be very accurate!

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 like f(x, a2, a1, a0), then summary.params would return an array [a2, a1, a0]. You would access a2 with a[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%
MMNEPVFCICPMFPCPTTAAATR