afryca.ase.Snippet
Library
mds
var mds = (typeof exports === "undefined")?(function mds() {}):(exports);
if(typeof global !== "undefined") { global.mds = mds; }
//
// Compute euclidean dissimilarity
//
mds.euclideanDissimilarity = function euclideanDissimilarity(x, y) {
var result = 0;
for (var i = 0; i < x.length; i++) {
if(isNaN(x[i])){
x[i]=0;
}
if(isNaN(y[i])){
y[i]=0;
}
result += Math.pow(x[i] - y[i], 2);
}
return Math.sqrt(result);
}
//
// Compute dissimilarity matrix
//
mds.dissimilarityMatrix = function dissimilarityMatrix(preferences) {
var vectorsArrays = adapters.matrixAsVectorsArray(preferences);
var vectors = vectorsArrays.length;
var result = [];
for (var i = 0; i < vectors; i++) {
result[i] = [];
for (var j = 0; j < vectors; j++) {
result[i][j] = mds.euclideanDissimilarity(vectorsArrays[i], vectorsArrays[j]);
}
}
return result;
}
//
// https://github.com/benfred/mds.js/blob/master/mds.js
//
mds.classicalMDS = function classicalMDS(distances, dimensions) {
dimensions = dimensions || 2;
// square distances
var M = numeric.mul(-0.5, numeric.pow(distances, 2));
// double centre the rows/columns
function mean(A) { return numeric.div(numeric.add.apply(null, A), A.length); }
var rowMeans = mean(M),
colMeans = mean(numeric.transpose(M)),
totalMean = mean(rowMeans);
for (var i = 0; i < M.length; ++i) {
for (var j =0; j < M[0].length; ++j) {
M[i][j] += totalMean - rowMeans[i] - colMeans[j];
}
}
// take the SVD of the double centred matrix, and return the
// points from it
var ret = numeric.svd(M),
eigenValues = numeric.sqrt(ret.S);
return ret.U.map(function(row) {
return numeric.mul(row, eigenValues).splice(0, dimensions);
});
}
mds.classicalMDS3D = function classicalMDS3D(distances, dimensions) {
dimensions = dimensions;
// square distances
var M = numeric.mul(-0.5, numeric.pow(distances, 2));
// double centre the rows/columns
function mean(A) { return numeric.div(numeric.add.apply(null, A), A.length); }
var rowMeans = mean(M),
colMeans = mean(numeric.transpose(M)),
totalMean = mean(rowMeans);
for (var i = 0; i < M.length; ++i) {
for (var j =0; j < M[0].length; ++j) {
M[i][j] += totalMean - rowMeans[i] - colMeans[j];
}
}
// take the SVD of the double centred matrix, and return the
// points from it
var ret = numeric.svd(M),
eigenValues = numeric.sqrt(ret.S);
return ret.U.map(function(row) {
return numeric.mul(row, eigenValues).splice(0, dimensions);
});
}
//
// Adapt MDS points to AFRYCA input [X -> values, Y -> values]
//
mds.mdsForAFRYCA = function mdsForAFRYCA(points) {
var result = [];
var X = 0;
var Y = 1;
result[X] = []; // X values
result[Y] = []; // Y values
for (var p = 0; p < points.length; p++) {
result[X][p] = points[p][X];
result[Y][p] = points[p][Y];
}
return result;
}
//
// Adapt MDS points to AFRYCA input [X -> values, Y -> values, Z -> values]
//
mds.mds3dForAFRYCA = function mds3dForAFRYCA(points) {
var result = [];
var X = 0;
var Y = 1;
var Z = 2;
result[X] = []; // X values
result[Y] = []; // Y values
result[Z] = []; // Z values
for (var p = 0; p < points.length; p++) {
result[X][p] = points[p][X];
result[Y][p] = points[p][Y];
result[Z][p] = points[p][Z];
}
return result;
}
//
// Compute MDS
//
mds.MDS = function MDS(preferences) {
var dissimilarityMatrix = mds.dissimilarityMatrix(preferences);
var points = mds.classicalMDS(dissimilarityMatrix);
return mds.mdsForAFRYCA(points);
}
//
// Compute MDS 3D
//
mds.MDS3D = function MDS3D(preferences) {
var dissimilarityMatrix = mds.dissimilarityMatrix(preferences);
var points = mds.classicalMDS3D(dissimilarityMatrix, 3);
return mds.mds3dForAFRYCA(points);
}
mds