Skip to content

Commit

Permalink
rename files and separate into class files
Browse files Browse the repository at this point in the history
  • Loading branch information
stanleyfok committed Dec 22, 2017
1 parent c61ce1c commit 82a0272
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 111 deletions.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('./lib/kmeans');
module.exports = require('./lib/KMeansEngine');
36 changes: 36 additions & 0 deletions lib/Cluster.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const _ = require('underscore');
const Vector = require('./Vector');

class Cluster {
constructor(centroid) {
this.centroid = centroid;

this.init();
}

init() {
this.hasMoved = false;
this.vectorIds = [];
}

addVectorId(id) {
this.vectorIds.push(id);
}

calculateCentroids(allVectors) {
const newCentroid = new Vector();

this.vectorIds.map(id => allVectors[id]).forEach((vector) => {
newCentroid.add(vector);
});

newCentroid.divide(this.vectorIds.length);

if (!_.isEqual(this.centroid.getObject(), newCentroid.getObject())) {
this.centroid = newCentroid;
this.hasMoved = true;
}
}
}

module.exports = Cluster;
111 changes: 5 additions & 106 deletions lib/kmeans.js → lib/KMeansEngine.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,8 @@
const _ = require('underscore');
const Vector = require('./Vector');
const Cluster = require('./Cluster');

class Vector {
constructor(vector) {
this.vector = vector || {};
}

clone() {
return new Vector(Object.assign({}, this.getObject()));
}

getKeys() {
return Object.keys(this.vector);
}

getObject() {
return this.vector;
}

getEuclideanDistance(vector) {
const tmpVector = this.clone().subtract(vector);
const tmp = tmpVector.getObject();
let d = 0;

tmpVector.getKeys().forEach((k) => {
// only need to consider the overlapping keys
d += tmp[k] * tmp[k];
});

return Math.sqrt(d);
}

add(vector) {
const tmp = vector.getObject();

vector.getKeys().forEach((k) => {
if (this.vector[k] === undefined) { this.vector[k] = 0; }

this.vector[k] += tmp[k];
});

return this;
}

subtract(vector) {
const tmp = vector.getObject();

vector.getKeys().forEach((k) => {
if (this.vector[k] === undefined) { this.vector[k] = 0; }

this.vector[k] -= tmp[k];
});

return this;
}

multiply(c) {
this.getKeys().forEach((k) => {
this.vector[k] *= c;
});

return this;
}

divide(c) {
this.getKeys().forEach((k) => {
this.vector[k] /= c;
});

return this;
}
}

class Cluster {
constructor(centroid) {
this.centroid = centroid;

this.init();
}

init() {
this.hasMoved = false;
this.vectorIds = [];
}

addVectorId(id) {
this.vectorIds.push(id);
}

calculateCentroids(allVectors) {
const newCentroid = new Vector();

this.vectorIds.map(id => allVectors[id]).forEach((vector) => {
newCentroid.add(vector);
});

newCentroid.divide(this.vectorIds.length);

if (!_.isEqual(this.centroid.getObject(), newCentroid.getObject())) {
this.centroid = newCentroid;
this.hasMoved = true;
}
}
}

class KMeanEngine {
class KMeansEngine {
constructor(vectors, k, callback) {
this.vectors = [];
vectors.forEach((v) => {
Expand Down Expand Up @@ -142,7 +41,7 @@ class KMeanEngine {
this.iterations = 0;
this.clusters = [];

const randNums = KMeanEngine.getRandomSequence(0, this.vectors.length - 1, this.k);
const randNums = KMeansEngine.getRandomSequence(0, this.vectors.length - 1, this.k);

// randomly pick a vector to be the centroid
for (let i = 0; i < this.k; i += 1) {
Expand Down Expand Up @@ -234,6 +133,6 @@ class KMeanEngine {
}

exports.clusterize = (vectors, k, callback) => {
const kmeans = new KMeanEngine(vectors, k, callback);
const kmeans = new KMeansEngine(vectors, k, callback);
return kmeans.clusterize();
};
72 changes: 72 additions & 0 deletions lib/Vector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
class Vector {
constructor(vector) {
this.vector = vector || {};
}

clone() {
return new Vector(Object.assign({}, this.getObject()));
}

getKeys() {
return Object.keys(this.vector);
}

getObject() {
return this.vector;
}

getEuclideanDistance(vector) {
const tmpVector = this.clone().subtract(vector);
const tmp = tmpVector.getObject();
let d = 0;

tmpVector.getKeys().forEach((k) => {
// only need to consider the overlapping keys
d += tmp[k] * tmp[k];
});

return Math.sqrt(d);
}

add(vector) {
const tmp = vector.getObject();

vector.getKeys().forEach((k) => {
if (this.vector[k] === undefined) { this.vector[k] = 0; }

this.vector[k] += tmp[k];
});

return this;
}

subtract(vector) {
const tmp = vector.getObject();

vector.getKeys().forEach((k) => {
if (this.vector[k] === undefined) { this.vector[k] = 0; }

this.vector[k] -= tmp[k];
});

return this;
}

multiply(c) {
this.getKeys().forEach((k) => {
this.vector[k] *= c;
});

return this;
}

divide(c) {
this.getKeys().forEach((k) => {
this.vector[k] /= c;
});

return this;
}
}

module.exports = Vector;
4 changes: 0 additions & 4 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@


const chai = require('chai');

const should = chai.should();

const kmeans = require('../');

const set1 = require('../fixtures/engineers');
Expand Down

0 comments on commit 82a0272

Please sign in to comment.