Comparing version 0.0.0 to 0.1.0
{ | ||
"name": "ml-kmeans", | ||
"version": "0.0.0", | ||
"version": "0.1.0", | ||
"description": "K-means in Javascript", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -15,10 +15,16 @@ # clustering | ||
## Methods | ||
### kmeans(data, centers, [maxIter], [tol]) | ||
Returns an array of cluster indexes for the training dots. | ||
### kmeans(data, centers, [props]) | ||
Returns an object containing the following: | ||
* `clusters`: array of [cluster indexes](https://en.wikipedia.org/wiki/K-means_clustering) for the training dots. | ||
* `centroids`: array of calculated centroids. | ||
* `iterations`: array of `clusters` and `centroids` calculated during each iteration. It's optional, only included when `withIter` is set to true (see below). | ||
__Arguments__ | ||
* `data`: An array of the (x,y) points to cluster, represented also as an array. | ||
* `centers`: An array of the K centers in format (x,y), represented also as an array. | ||
* `maxIter`: Maximum number of iterations allowed. Its default is 100. | ||
* `tol`: The numerical error tolerance. Its default is 1e-6. | ||
* `props`: A property object that can be used to set some parameters: | ||
* `maxIter`: Maximum number of iterations allowed. Its default is 100. | ||
* `tol`: The numerical error tolerance. Its default is 1e-6. | ||
* `withIter`: If `true` it adds an `iterations` property in the returned object. Its default is false. | ||
@@ -25,0 +31,0 @@ ## Test |
@@ -110,9 +110,19 @@ 'use strict'; | ||
* @param {Array <Array <number>>} centers - the K centers in format (x,y) | ||
* @param {Object} props - properties | ||
* @param {number} maxIter - maximum of iterations allowed | ||
* @param {number} tol - the error tolerance | ||
* @returns {Array <number>} the cluster identifier for each data dot | ||
* @param {boolean} withIter - store clusters and centroids for each iteration | ||
* @returns {Object} the cluster identifier for each data dot and centroids | ||
*/ | ||
function kmeans(data, centers, maxIter, tol) { | ||
maxIter = (typeof maxIter === "undefined") ? 100 : maxIter; | ||
tol = (typeof tol === "undefined") ? 1e-6 : tol; | ||
function kmeans(data, centers, props) { | ||
var maxIter, tol, withIter; | ||
if (typeof props === "undefined") { | ||
maxIter = 100; | ||
tol = 1e-6; | ||
withIter = false; | ||
} else { | ||
maxIter = (typeof props.maxIter === "undefined") ? 100 : props.maxIter; | ||
tol = (typeof props.tol === "undefined") ? 1e-6 : props.tol; | ||
withIter = (typeof props.withIter === "undefined") ? false : props.withIter; | ||
} | ||
@@ -135,2 +145,3 @@ var nData = data.length; | ||
var curDistance = 0; | ||
var iterations = []; | ||
for (var iter = 0; iter < maxIter; iter++) { | ||
@@ -140,9 +151,39 @@ clusterID = updateClusterID(data, centers); | ||
curDistance = computeSSE(data, centers, clusterID); | ||
if ((lastDistance - curDistance < tol) || ((lastDistance - curDistance)/lastDistance < tol)) | ||
return clusterID; | ||
if (withIter) { | ||
iterations.push({ | ||
"clusters": clusterID, | ||
"centroids": centers | ||
}); | ||
} | ||
if ((lastDistance - curDistance < tol) || ((lastDistance - curDistance)/lastDistance < tol)) { | ||
if (withIter) { | ||
return { | ||
"clusters": clusterID, | ||
"centroids": centers, | ||
"iterations": iterations | ||
}; | ||
} else { | ||
return { | ||
"clusters": clusterID, | ||
"centroids": centers | ||
}; | ||
} | ||
} | ||
lastDistance = curDistance; | ||
} | ||
return clusterID; | ||
if (withIter) { | ||
return { | ||
"clusters": clusterID, | ||
"centroids": centers, | ||
"iterations": iterations | ||
}; | ||
} else { | ||
return { | ||
"clusters": clusterID, | ||
"centroids": centers | ||
}; | ||
} | ||
} | ||
module.exports = kmeans; | ||
module.exports = kmeans; |
@@ -6,11 +6,43 @@ var kmeans = require('..'); | ||
var clusterID = [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0]; | ||
var expectedCentroids = [[-8.4199, -1.6654], [4.4661, 1.3475]]; | ||
describe('K-means test', function () { | ||
describe('K-means', function () { | ||
it('main test', function () { | ||
var ans = kmeans(data, centers); | ||
for (var i = 0, l = clusterID.length; i < l; i++) { | ||
ans[i].should.equal(clusterID[i]); | ||
} | ||
describe('when passing data points and centroids', function () { | ||
it('main test', function () { | ||
var ans = kmeans(data, centers); | ||
clusts = ans.clusters; | ||
centrs = ans.centroids; | ||
for (var i = 0, l = clusterID.length; i < l; i++) { | ||
clusts[i].should.equal(clusterID[i]); | ||
} | ||
for (var i = 0, l = centers.length; i < l; i++) { | ||
centrs[i][0].should.be.approximately(expectedCentroids[i][0], 0.1); | ||
centrs[i][1].should.be.approximately(expectedCentroids[i][1], 0.1); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe('when passing `withIter` property', function () { | ||
it('should store iterations', function () { | ||
var ans = kmeans(data, centers, {"withIter": true}); | ||
clusts = ans.clusters; | ||
centrs = ans.centroids; | ||
iters = ans.iterations; | ||
for (var i = 0, l = clusterID.length; i < l; i++) { | ||
clusts[i].should.equal(clusterID[i]); | ||
} | ||
for (var i = 0, l = centers.length; i < l; i++) { | ||
centrs[i][0].should.be.approximately(expectedCentroids[i][0], 0.1); | ||
centrs[i][1].should.be.approximately(expectedCentroids[i][1], 0.1); | ||
} | ||
iters.length.should.equal(12); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18244
236
53
1