Skip to content

Commit a431fb9

Browse files
authored
Merge pull request #25 from chrisbubernak/master
Add option to seed the randomness for predictable results
2 parents c1c1abf + 9d07492 commit a431fb9

File tree

5 files changed

+23
-1
lines changed

5 files changed

+23
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ kmeans.clusterize(vectors, {k: 4}, (err,res) => {
3838
- **options** object:
3939
- **k** : number of clusters
4040
- **distance** (optional) : custom distance function returning the distance between two points `(a,b) => number`, *default* Euclidian Distance
41+
- **seed** (optional) : value that can be provided to get repeatable cluster generation
4142
- **callback** node-style callback taking error and result argument
4243

4344
## Outputs

lib/kmeans.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The kmeans will return an error if:
1818
- The number of different input vectors is smaller than k
1919
*/
2020

21+
const seedrandom = require('seedRandom');
2122
const _ = require('underscore');
2223

2324

@@ -60,7 +61,8 @@ class Group {
6061
if (this.centroid && this.cluster.length > 0) {
6162
this.calculateCentroid();
6263
} else { // random selection
63-
const i = Math.floor(Math.random() * self.indexes.length);
64+
const rand = self.seed == null ? Math.random() : seedrandom(self.seed)();
65+
const i = Math.floor(rand * self.indexes.length);
6466
this.centroidIndex = self.indexes[i];
6567
self.indexes.splice(i, 1);
6668
this.centroid = [];
@@ -126,6 +128,7 @@ class Clusterize {
126128
this.options = options;
127129
this.v = this.checkV(vector);
128130
this.k = this.options.k;
131+
this.seed = this.options.seed;
129132
this.distanceFunction = this.options.distance || euclidianDistance;
130133
if (this.v.length < this.k) {
131134
const errMessage = `The number of points must be greater than

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"node": ">= v0.6.0"
1313
},
1414
"dependencies": {
15+
"seedrandom": "^3.0.5",
1516
"underscore": "^1.9.1"
1617
},
1718
"devDependencies": {

test/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,17 @@ describe('kmeans', () => {
139139
done();
140140
});
141141
});
142+
143+
it('should produce consistent output when a seed is provided', (done) => {
144+
kmeans.clusterize(data3D, { k: 3, seed: 42 }, (err, res) => {
145+
146+
// Verify first value of each centroid is always the same
147+
const cs = res.map(r => r.centroid[0]);
148+
cs[0].should.equal(202.6);
149+
cs[1].should.equal(-10.15);
150+
cs[2].should.equal(39.75);
151+
done();
152+
});
153+
});
142154
});
143155
});

0 commit comments

Comments
 (0)