Skip to content

Instantly share code, notes, and snippets.

@doleron
Last active February 1, 2022 13:30
Show Gist options
  • Save doleron/742028d2dd2c02f476d7623977585b0d to your computer and use it in GitHub Desktop.
Save doleron/742028d2dd2c02f476d7623977585b0d to your computer and use it in GitHub Desktop.
Example of polynomial fitting in Javascript
/* *
* requires numeric js
* https://cdnjs.cloudflare.com/ajax/libs/numeric/1.2.6/numeric.min.js
*/
const ctx = document.getElementById('synthetic');
const N = 91;
const xs = [...Array(N).keys()].map(x => 2*Math.PI*x / (N - 1));
function mulberry32(a) {
return function() {
var t = a += 0x6D2B79F5;
t = Math.imul(t ^ t >>> 15, t | 1);
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
}
// change seed to an arbitrary number
const seed = 1111;
jStat.setRandom(mulberry32(1111));
const signal = xs.map(x => Math.sin(x) );
const sampleSize = 20;
const sample = [...Array(N).keys()].sort(() => 0.5 - jStat.uniform.sample(0,1)).slice(0, sampleSize).map(index => ({x: index, y: signal[index] + jStat.normal.sample(0.0, 0.4)}));
sample.sort(() => 0.5 - jStat.uniform.sample(0,1));
const dataSplit = Math.round(sampleSize * 0.67);
const training_data = sample.slice(0, dataSplit);
const validation_data = sample.slice(dataSplit, sampleSize);
_labels = ["0", "π/5", "2π/5", "3π/5", "4π/5", "π", "6π/5", "7π/5", "8π/5", "9π/5", "2π"];
const x = [];
const y = [];
for (let i = 0; i < training_data.length; ++i) {
const elem = training_data[i];
x.push(xs[elem.x]);
y.push(elem.y);
}
function fit(x, y, order) {
const xMatrix = [];
const yMatrix = numeric.transpose([y]);
let xTemp = [];
for (let j=0; j<x.length; ++j) {
xTemp = [];
for(let i = 0; i <= order; ++i) {
xTemp.push(Math.pow(x[j], i));
}
xMatrix.push(xTemp);
}
const xMatrixT = numeric.transpose(xMatrix);
const dot1 = numeric.dot(xMatrixT, xMatrix);
const dotInv = numeric.inv(dot1);
const dot2 = numeric.dot(xMatrixT, yMatrix);
const result = numeric.dot(dotInv, dot2);
return result.flat(1);
}
function predict(x, coeffs) {
let result = 0;
let xx = 1;
for (let i = 0; i < coeffs.length; ++i) {
result += xx*coeffs[i];
xx *= x;
}
return result;
}
function generateModelData(x, y, order) {
const model = fit(x, y, order);
const result = [];
for (let i = 0; i < xs.length; ++i) {
result.push(predict(xs[i], model));
}
return result;
}
const myChart = new Chart(ctx, {
data: {
labels: xs,
datasets: [{
type: 'line',
label: 'Original Generative Signal',
pointRadius: 0,
borderColor: 'rgb(0, 125, 255)',
pointBackgroundColor: 'rgb(0, 125, 255)',
data: signal
},{
type: 'line',
label: 'Linear approximation',
pointRadius: 0,
borderColor: 'rgb(88, 24, 69)',
borderDash: [5, 3],
data: generateModelData(x, y, 1)
},{
type: 'line',
label: 'Cubic Approximation',
pointRadius: 0,
borderColor: 'rgb(255, 87, 51)',
data: generateModelData(x, y, 3)
},{
type: 'line',
label: '5th-degree polynomial approximation',
pointRadius: 0,
borderColor: 'rgb(165, 255, 51)',
borderDash: [10, 5],
data: generateModelData(x, y, 5)
},{
type: 'line',
label: '9th-degree polynomial approximation',
pointRadius: 0,
borderColor: 'rgb(123, 36, 28)',
pointBackgroundColor: 'rgb(255, 0, 0)',
borderDash: [10, 2],
data: generateModelData(x, y, 9)
},
{
type: 'scatter',
label: 'Training data',
pointStyle: 'crossRot',
pointRadius: 10,
borderColor: 'rgb(255, 128, 0)',
data: Array(N).fill().map((element, index) => {
const v = training_data.find(elem => elem.x == index);
if (v != undefined) {
return v.y;
} else {
return null;
}
})
}]
},
options: {
plugins: {
legend: {
position: 'bottom'
},
title: {
display: true,
text: 'Training/validation sets',
font: {
size: 48,
family: 'Arial'
}
}
},
scales: {
x: {
ticks: {
maxTicksLimit: _labels.length,
maxRotation: 0,
minRotation: 0,
callback: function(value, index, ticks) {
const factor = index * (_labels.length - 1);
let result = "";
const n = N - 1;
if (factor % n == 0){
result = _labels[Math.ceil(factor / n)];
}
return result;
}
}
},
y: {
min: -2,
max: 2,
}
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment