spectral-clustering-js
Version:
Spectral clustering package for TypeScript
98 lines (97 loc) • 4.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var Utils_1 = require("./Utils");
var ml_matrix_1 = require("ml-matrix");
var Kmeans1D_1 = require("./Kmeans1D");
/**
* Class dedicated to spectral clustering :
* * compute the eigen values
* * sort the eigen vectors accorting to the eigen values
* * focus on the 2nd eiven vector (Fiedler's)
* * run a k-means to cluster the components of the Fiedler's vector
*/
var SpectralClustering = /** @class */ (function () {
function SpectralClustering(graph) {
this.graph = graph;
}
SpectralClustering.prototype.compute = function (options) {
if (options === void 0) { options = new Map(); }
var defaultOptions = new Map([
["laplacianMatrix", "connected"],
["requestedNbClusters", -1],
["maxClusters", 8]
]);
var runningOptions = Utils_1.Utils.resolveRunningParameters(defaultOptions, options);
var laplacianMatrix = null;
if (runningOptions.get("laplacianMatrix") == "connected") {
laplacianMatrix = this.extractStrictLaplacianMatrix();
}
else {
laplacianMatrix = this.extractDistanceLaplacianMatrix();
}
var eigen = new ml_matrix_1.EigenvalueDecomposition(laplacianMatrix, { assumeSymmetric: true });
var nodes = this.graph.getNodes();
// the eigen vectors & values are already sorted
// there is not need to do it again
var fiedlerVector = eigen.eigenvectorMatrix.getColumn(1);
// k-means to divide the FiedlerVector
var kmeanCluster = new Kmeans1D_1.Kmeans1D(fiedlerVector);
// is the number of clusters already known ?
var requestedNbClusters = (runningOptions.get("requestedNbClusters"));
var clusterResult = null;
if (requestedNbClusters == -1) {
clusterResult = kmeanCluster.findBestClustering((runningOptions.get("maxClusters")));
}
else {
// the methods returns [clusters, centroids], let's keep the clusters only
clusterResult = kmeanCluster.tryToCluster(requestedNbClusters)[0];
}
for (var i = 0; i < fiedlerVector.length; i++) {
var nodeI = nodes[i];
nodeI.setCluster(clusterResult[i]);
}
};
SpectralClustering.prototype.extractStrictLaplacianMatrix = function () {
var result = new ml_matrix_1.Matrix(this.graph.getNodes().length, this.graph.getNodes().length);
var nodes = this.graph.getNodes();
for (var i = 0; i < nodes.length; i++) {
var nodeI = nodes[i];
var connected = nodeI.getConnectedNodes();
for (var j = 0; j < nodes.length; j++) {
var nodeJ = nodes[j];
if (nodeI.isConnectedTo(nodeJ)) {
result.set(i, j, -1);
}
}
result.set(i, i, connected.size);
}
return result;
};
/**
* Build a matrix showing the distance of nodes
*/
SpectralClustering.prototype.extractDistanceLaplacianMatrix = function () {
var result = new ml_matrix_1.Matrix(this.graph.getNodes().length, this.graph.getNodes().length);
var nodes = this.graph.getNodes();
for (var i = 0; i < nodes.length; i++) {
var nodeI = nodes[i];
var sumDistances = 0;
for (var j = 0; j < nodes.length; j++) {
if (i != j) {
var nodeJ = nodes[j];
if (nodeI.isConnectedTo(nodeJ)) {
var distance = nodeI.getPoint().euclieanDistanceTo(nodeJ.getPoint());
//let distanceInLaplacian = 1/distance;
var distanceInLaplacian = 1 / Math.log10(distance);
result.set(i, j, -distanceInLaplacian);
sumDistances += distanceInLaplacian;
}
}
}
result.set(i, i, sumDistances);
}
return result;
};
return SpectralClustering;
}());
exports.SpectralClustering = SpectralClustering;