public KMeansResult cluster(double[][] centroids, double[][] instances, double threshold) { int itr = -1; // initialize the result KMeansResult result = new KMeansResult(); LinkedList<Double> distortionList = new LinkedList<Double>(); result.clusterAssignment = new int[instances.length]; boolean completed = false; // loop until finally done while (!completed) { // increment iteration itr++; // call the assignInstance method to assign the instances to centroids assignInstance(centroids, instances, result); // check orphaned centroid boolean noOrphaned = false; while (!noOrphaned) { int orphanNum = -1; orphanNum = checkOrphan(centroids, result); // if the centroid is orphaned, then assign it as scenario requores if (orphanNum >= 0) { assignOrphan(orphanNum, centroids, instances, result); } else { noOrphaned = true; } } // update centroids updateCentroids(centroids, instances, result); // compute new distortion double distortion = calculateDistortion(centroids, instances, result); // track the distortion distortionList.add(distortion); // check whether the algorithm should terminate if (itr > 0 && Math.abs( (distortionList.get(itr) - distortionList.get(itr - 1)) / distortionList.get(itr - 1)) < threshold) { completed = true; } } // set centroids to KMeansResult final centroids array result.centroids = centroids; // initialize result's distortion array result.distortionIterations = new double[distortionList.size()]; // record distortionList into result of distortion array for (int i = 0; i < distortionList.size(); i++) { result.distortionIterations[i] = distortionList.get(i); } return result; }