149 lines
3.8 KiB
Plaintext
149 lines
3.8 KiB
Plaintext
<snippet>
|
|
<subclass>afryca.ase.Snippet</subclass>
|
|
<file></file>
|
|
<category>Library</category>
|
|
<name>mds</name>
|
|
<description></description>
|
|
<code>
|
|
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
|
|
</code>
|
|
</snippet> |