Ashvin_3 0 Newbie Poster

I came across a KMeans implementation in Java. The number of clusters generated by the code is 3. But when I tried to change it to 2, I am getting the error: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2

Any help is much appreciated. Here is the code:

public class KMeans 
{

    public static void main(String[] args) {

        int data[] = {2,4,10,12,3,20,30,11, 12, 14, 19, 21, 29, 31, 40};//,25,17,23};    // initial data

        int noofclusters = 2;

        int centroid[][]=new int[][]{
            {0,0,0},
            {2,4,30}
        };
        getCentroid(data,noofclusters,centroid);

    }//main

    public static int[][] getCentroid(int data[],int noofclusters,int centroid[][]){

        int distance[][]=new int[noofclusters][data.length];
        int cluster[]=new int[data.length];
        int clusternodecount[]=new int[noofclusters];

        centroid[0]=centroid[1];
        centroid[1]=new int[]{0,0,0};
        System.out.println("========== Starting to get new centroid =========");

        for(int i=0;i<noofclusters;i++){
            for(int j=0;j<data.length;j++){
                //System.out.println(distance[i][j]+"("+i+","+j+")="+data[j]+"("+j+")-"+centroid[0][i]+"="+(data[j]-centroid[0][i]));
                distance[i][j]=Math.abs(data[j]-centroid[0][i]);
                System.out.print(distance[i][j]+" ,");
                //System.out.println("Centroid: "+centroid[0][i]);
            }
            System.out.println();
        }

        for(int j = 0; j < data.length; j++){
            int smallerDistance=0;
            if(distance[0][j]<distance[1][j] && distance[0][j]<distance[2][j])
                smallerDistance=0;
            if(distance[1][j]<distance[0][j] && distance[1][j]<distance[2][j])
                smallerDistance=1;
            if(distance[2][j]<distance[0][j] && distance[2][j]<distance[1][j])
                smallerDistance=2;//

            centroid[1][smallerDistance]=centroid[1][smallerDistance]+data[j];
            clusternodecount[smallerDistance]=clusternodecount[smallerDistance]+1;
            cluster[j]=smallerDistance;

            //System.out.println("Centerid at 1:  "+centroid[1][smallerDistance]);
            //System.out.print(cluster[j]+", ");



        }
        //for(int j=0;j<data.length;j++)
        //System.out.println("c at out: "+cluster[j]);

                System.out.println("======================================== ");

                System.out.println("New clusters are ");
                // cluster[]= { 0  1   0  1  0  2  2  1}
                // data[]={2,4,-10,12,3,20,30,11};
                 for(int i=0;i<noofclusters;i++){               
                    System.out.print("C"+(i+1)+": ");
                     for(int l=0;l<data.length;l++){
                    if(cluster[l]==i)
                        System.out.print(data[l]+" ,");

                }
                System.out.println();
            }
                System.out.println("======================================== ");

        System.out.println("New centroid is ");

        for(int j=0;j<noofclusters;j++){
            centroid[1][j]=centroid[1][j]/clusternodecount[j];
            System.out.print(centroid[1][j]+",");
        }
        System.out.println();

        boolean isAchived=true;
        for(int j=0;j<noofclusters;j++){
            if(isAchived && centroid[0][j] == centroid[1][j]){
                isAchived=true;
                continue;
            }
            isAchived=false;
        }

        if(!isAchived){

            getCentroid(data,noofclusters,centroid);
        }

        if(isAchived){
            System.out.println("======================================== ");
            System.out.println(" Final Cluster is ");
            for(int i=0;i<noofclusters;i++){    
                              System.out.print("C"+(i+1)+":");
                for(int j=0;j<data.length;j++){
                    if(cluster[j]==i)
                        System.out.print(data[j]+" ,");

                }
                System.out.println();
            }
        }

        return centroid;

    }
}

Dani AI

Generated

The crash is coming from hard-coded "three-cluster" logic mixed with a variable noofclusters. Code paths like comparing distance[2] or indexing the centroid array by 2 assume three clusters; when noofclusters is 2 those accesses are out of range. The fix is to stop special-casing three clusters and write the assignment step as a general argmin over noofclusters.

Practical fixes for :

  • Represent centroids as a 1-D array sized noofclusters (and a second 1-D for the next iteration), or use double[] for better precision.
  • For each data point, loop over all clusters and pick the cluster with the smallest distance (argmin). Do not use fixed if chains for cluster indices.
  • Recompute centroids by summing assigned points and dividing by counts; guard division by zero (empty clusters) by reinitializing that centroid or keeping the previous value.
  • Replace recursion with an iterative loop and a maxIter guard to avoid stack overflow or infinite loops.
  • Use double for centroids to avoid integer truncation.

Example assignment + update loop (replace the hard-coded logic with this pattern):

int k = noofclusters;
double[] centroids = new double[k]; // init to k distinct values
double[] sums = new double[k];
int[] counts = new int[k];
int[] assignment = new int[data.length];

boolean changed = true;
int iter = 0, maxIter = 100;
while (changed && iter++ < maxIter) {
  for (int c = 0; c < k; c++) { sums[c] = 0; counts[c] = 0; }
  for (int i = 0; i < data.length; i++) {
    int best = 0;
    double bestDist = Math.abs(data[i] - centroids[0]);
    for (int c = 1; c < k; c++) {
      double d = Math.abs(data[i] - centroids[c]);
      if (d < bestDist) { bestDist = d; best = c; }
    }
    assignment[i] = best;
    sums[best] += data[i];
    counts[best]++;
  }
  changed = false;
  for (int c = 0; c < k; c++) {
    if (counts[c] > 0) {
      double newC = sums[c] / counts[c];
      if (newC != centroids[c]) changed = true;
      centroids[c] = newC;
    } else {
      centroids[c] = data[(int)(Math.random()*data.length)]; // handle empty cluster
      changed = true;
    }
  }
}

Quick troubleshooting: search your code for any literal index like 2 or distance[2] and replace the logic with a cluster loop; print centroids each iteration while developing; and consider kmeans++ or a library (for production) if initialization quality matters.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.