📄 basickmeans.java
字号:
if (Runtime.getRuntime().freeMemory() < memRequired) {
throw new InsufficientMemoryException();
}
// Instantiate an array to hold the distances between coordinates
// and cluster centers
mDistanceCache = new double[numCoords][numClusters];
}
for (int coord=0; coord < numCoords; coord++) {
// Update the distances between the coordinate and all
// clusters currently in contention with update flags set.
for (int clust=0; clust<numClusters; clust++) {
ProtoCluster cluster = mProtoClusters[clust];
if (cluster.getConsiderForAssignment() && cluster.needsUpdate()) {
mDistanceCache[coord][clust] =
distance(mCoordinates[coord], cluster.getCenter());
}
}
}
}
/**
* Assign each coordinate to the nearest cluster. Called once
* per iteration. Returns the number of coordinates that have
* changed their cluster membership.
*/
private int makeAssignments() {
int moves = 0;
int coordCount = mCoordinates.length;
// Checkpoint the clusters, so we'll be able to tell
// which ones have changed after all the assignments have been
// made.
int numClusters = mProtoClusters.length;
for (int c = 0; c < numClusters; c++) {
if (mProtoClusters[c].getConsiderForAssignment()) {
mProtoClusters[c].checkPoint();
}
}
// Now do the assignments.
for (int i = 0; i < coordCount; i++) {
int c = nearestCluster(i);
mProtoClusters[c].add(i);
if (mClusterAssignments[i] != c) {
mClusterAssignments[i] = c;
moves++;
}
}
return moves;
}
/**
* Find the nearest cluster to the coordinate identified by
* the specified index.
*/
private int nearestCluster(int ndx) {
int nearest = -1;
double min = Double.MAX_VALUE;
int numClusters = mProtoClusters.length;
for (int c = 0; c < numClusters; c++) {
if (mProtoClusters[c].getConsiderForAssignment()) {
double d = mDistanceCache[ndx][c];
if (d < min) {
min = d;
nearest = c;
}
}
}
return nearest;
}
/**
* Compute the euclidean distance between the two arguments.
*/
private static double distance(double[] coord, double[] center) {
int len = coord.length;
double sumSquared = 0.0;
for (int i=0; i<len; i++) {
double v = coord[i] - center[i];
sumSquared += v*v;
}
return Math.sqrt(sumSquared);
}
/**
* Generate an array of Cluster objects from mProtoClusters.
*
* @return array of Cluster object references.
*/
private Cluster[] generateFinalClusters() {
int numClusters = mProtoClusters.length;
// Convert the proto-clusters to the final Clusters.
//
// - accumulate in a list.
List<Cluster> clusterList = new ArrayList<Cluster>(numClusters);
for (int c = 0; c < numClusters; c++) {
ProtoCluster pcluster = mProtoClusters[c];
if (!pcluster.isEmpty()) {
Cluster cluster = new Cluster(pcluster.getMembership(), pcluster.getCenter());
clusterList.add(cluster);
}
}
// - convert list to an array.
Cluster[] clusters = new Cluster[clusterList.size()];
clusterList.toArray(clusters);
return clusters;
}
/**
* Clean up items used by the clustering algorithm that are no longer needed.
*/
private void cleanup() {
mProtoClusters = null;
mDistanceCache = null;
mClusterAssignments = null;
}
/**
* Cluster class used temporarily during clustering. Upon completion,
* the array of ProtoClusters is transformed into an array of
* Clusters.
*/
private static class ProtoCluster {
// The previous iteration's cluster membership and
// the current iteration's membership. Compared to see if the
// cluster has changed during the last iteration.
private int[] mPreviousMembership;
private int[] mCurrentMembership;
private int mCurrentSize;
// The cluster center.
private double[] mCenter;
// Born true, so the first call to updateDistances() will set all the
// distances.
private boolean mUpdateFlag = true;
// Whether or not this cluster takes part in the operations.
private boolean mConsiderForAssignment = true;
/**
* Constructor
*
* @param center the initial cluster center.
* @param coordIndex the initial member.
*/
ProtoCluster(double[] center, int coordIndex) {
mCenter = (double[]) center.clone();
// No previous membership.
mPreviousMembership = new int[0];
// Provide space for 10 members to be added initially.
mCurrentMembership = new int[10];
mCurrentSize = 0;
add(coordIndex);
}
/**
* Get the members of this protocluster.
*
* @return an array of coordinate indices.
*/
int[] getMembership() {
trimCurrentMembership();
return mCurrentMembership;
}
/**
* Get the protocluster's center.
*
* @return
*/
double[] getCenter() {
return mCenter;
}
/**
* Reduces the length of the array of current members to
* the number of members.
*/
void trimCurrentMembership() {
if (mCurrentMembership.length > mCurrentSize) {
int[] temp = new int[mCurrentSize];
System.arraycopy(mCurrentMembership, 0, temp, 0, mCurrentSize);
mCurrentMembership = temp;
}
}
/**
* Add a coordinate to the protocluster.
*
* @param ndx index of the coordinate to be added.
*/
void add(int ndx) {
// Ensure there's space to add the new member.
if (mCurrentSize == mCurrentMembership.length) {
// If not, double the size of mCurrentMembership.
int newCapacity = Math.max(10, 2*mCurrentMembership.length);
int[] temp = new int[newCapacity];
System.arraycopy(mCurrentMembership, 0, temp, 0, mCurrentSize);
mCurrentMembership = temp;
}
// Add the index.
mCurrentMembership[mCurrentSize++] = ndx;
}
/**
* Does the protocluster contain any members?
*
* @return true if the cluster is empty.
*/
boolean isEmpty() {
return mCurrentSize == 0;
}
/**
* Compares the previous and the current membership.
* Sets the update flag to true if the membership
* changed in the previous call to makeAssignments().
*/
void setUpdateFlag() {
// Trim the current membership array length down to the
// number of members.
trimCurrentMembership();
mUpdateFlag = false;
if (mPreviousMembership.length == mCurrentSize) {
for (int i=0; i<mCurrentSize; i++) {
if (mPreviousMembership[i] != mCurrentMembership[i]) {
mUpdateFlag = true;
break;
}
}
} else { // Number of members has changed.
mUpdateFlag = true;
}
}
/**
* Clears the current membership after copying it to the
* previous membership.
*/
void checkPoint() {
mPreviousMembership = mCurrentMembership;
mCurrentMembership = new int[10];
mCurrentSize = 0;
}
/**
* Is this protocluster currently in contention?
*
* @return true if this cluster is still in the running.
*/
boolean getConsiderForAssignment() {
return mConsiderForAssignment;
}
/**
* Set the flag to indicate that this protocluster is
* in or out of contention.
*
* @param b
*/
void setConsiderForAssignment(boolean b) {
mConsiderForAssignment = b;
}
/**
* Get the value of the update flag. This value is
* used to determine whether to update the cluster center and
* whether to recompute distances to the cluster.
*
* @return the value of the update flag.
*/
boolean needsUpdate() {
return mUpdateFlag;
}
/**
* Update the cluster center.
*
* @param coordinates the array of coordinates.
*/
void updateCenter(double[][] coordinates) {
Arrays.fill(mCenter, 0.0);
if (mCurrentSize > 0) {
for (int i=0; i<mCurrentSize; i++) {
double[] coord = coordinates[mCurrentMembership[i]];
for (int j=0; j<coord.length; j++) {
mCenter[j] += coord[j];
}
}
for (int i=0; i<mCenter.length; i++) {
mCenter[i] /= mCurrentSize;
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -