/**
*
* @description
* Class used to handle distances functions
* @example
* //new instance
* let distances = new Distances();
* //define two points
* let point1 = [1,3];
* let point2 = [4,-2];
* //minkowski distance from two points
* let minkowski_distance = distances.minkowski(point1,point2);
* //chebyshev distance from two points
* let chebyshev_distance = distances.chebyshev(point1,point2);
* //mahalanobis distance from two points
* let mahalanobis_distance = distances.mahalanobis(point1,point2);
* //setting the grade for minkowski
* distances.setMinkowskiDegree(2);
*/
export const Distances = function() {
this.p = 1;
this.data = [];
this.variance = 0;
this.default = function() {};
};
Distances.prototype = {
/**
* Sets the dataset and calculate the variance
* @param data {data} dataset to be used for the distances calculations
*/
setDataSet: function(data) {
this.data = data;
this.variance = variance(data);
},
/**
* Set the default function for the distance calculation
* @param {String} algorithm
*/
setDefault: function(algorithm) {
if (algorithm === "minkowski") this.default = this.minkowski;
else if (algorithm === "chebyshev") this.default = this.chebyshev;
else if (algorithm === "mahalanobis") this.default = this.mahalanobis;
else this.default = this.minkowski;
},
/**
* Returns the distance between two points using the default algorithm
* @param point1 {point} first point
* @param point2 {point} second point
* @returns {number} distance
*/
of: function(point1, point2) {
try {
return this.default(point1, point2);
} catch (e) {
console.warn(e);
}
},
/**
* Sets the degree of the minkowski distance
* @param p {Number} the degree for minkowski distance
*/
setMinkowskiDegree: function(p) {
this.p = p || this.p;
if (this.p < 1) this.p = 1;
},
/**
* Returns the minkowski distance between two points
* @param point1 {point} first point
* @param point2 {point} second point
* @returns {number} minkowski distance
*/
minkowski: function(point1, point2) {
if (point1.length !== point2.length) {
console.warn("point of different lengths");
return;
}
let sum = 0;
for (let i = 0; i < point1.length; i++)
sum += Math.pow(Math.abs(point1[i] - point2[i]), this.p);
return Math.pow(sum, 1 / this.p);
},
/**
* Returns the chebyshev distance between two points
* @param point1 {point} first point
* @param point2 {point} second point
* @returns {number} chebyshev distance between the two points
*/
chebyshev: function(point1, point2) {
let value;
let max = 0;
for (let i = 0; i < point1.length; i++) {
value = Math.abs(point2[i] - point1[i]);
if (value > max) max = value;
}
return max;
},
/**
* Returns the mahalanobis distance between two points
* @param point1 {point} first point
* @param point2 {point} second point
* @returns {number} mahalanobis distance between the two points
*/
mahalanobis: function(point1, point2) {
if (this.data.length === 0) throw "no data";
let sum = 0;
for (let i = 0; i < point1.length; i++)
sum += Math.pow(point1[i] - point2[i], 2) / Math.pow(this.variance[i], 2);
return Math.sqrt(sum);
}
};
function variance(data) {
let avg = average(data);
let variance = [0, 0];
let N = data.length;
for (let i = 0; i < data[0].length; i++) {
for (let j = 0; j < N; j++) {
variance[i] += Math.pow(data[j][i] - avg[i], 2);
}
variance[i] = Math.sqrt(variance[i] / N);
}
return variance;
}
function average(data) {
let avg = zeros(data[0].length);
let N = data.length;
for (let i = 0; i < data[0].length; i++) {
for (let j = 0; j < N; j++) {
avg[i] += data[j][i];
}
avg[i] /= N;
}
return avg;
}
function zeros(n) {
let arr = new Array(n);
for (let i = 0; i < n; i++) {
arr[i] = 0;
}
return arr;
}
Source