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