KMeans.java 代码解读与时间序列聚类

1.KMeans 算法思想:
对于给定的类别数目k,首先给出初始划分,通过迭代改变样本和簇的隶属关系,使得每一次改进之后的划分方案都较前一次好。

2.KMeans 算法步骤:

2.1. 选择初始的k个类别中心μ1,μ2 ...μk
2.2. 根据簇中心打标签阶段,即assignment。
对于每个样本x i ,将其标记为距离类别中心最近的类别,即:
label(i) = arg min|| Xi-μj||

2.3. 根据新做的标签的各个簇update簇中心阶段。即K-Means。
将每个类别中心更新为隶属该类别的所有样本的均值: μj = 1/Cj  * sum(Xi)
2.4. 重复最后两步,直到类别中心的变化小于某阈值。
中止条件: 达到迭代次数或者簇中心变化率满足阈值


3.KMeans.java 算法代码如下:
 /*numClusters 簇的数目,即聚类的数目K,K是预先指定的。
 * niter 迭代计算的最大轮数
 * centroids 各个簇中心的初始值,如果初始值是null,则会随机产生。
 */
 public void clustering(int numClusters, int niter, double [][] centroids)
  {
      _numClusters = numClusters;//簇的数目
      if (centroids !=null)
          _centroids = centroids;//簇中心
      else{
        // randomly selected centroids 随机产生
        _centroids = new double[_numClusters][];

        ArrayList idx= new ArrayList();// idx 用来存储各个簇的label
        for (int i=0; i           int c;
          do{
            c = (int) (Math.random()*_nrows);
          }while(idx.contains(c)); // avoid duplicates
          idx.add(c);

          // copy the value from _data[c]
          _centroids[i] = new double[_ndims];//针对每个向量i, new一个数组,数组的长度是维数。因为向量i的簇中心的长度也是相同的_ndims维数
          for (int j=0; j<_ndims; j++)
            _centroids[i][j] = _data[c][j];// _data[c][j] 为全局的原始数据,这里针对每个i,都随机选择了一个原始数据中的_data[c][j]作为各个簇的中心
        }
        System.out.println("selected random centroids");

      }

      double [][] c1 = _centroids;
      double threshold = 0.001;
      int round=0;

      while (true){
        // update _centroids with the last round results
        _centroids = c1;

        //assign record to the closest centroid. 根据簇中心,打标签阶段。nrows为样本向量的个数
        _label = new int[_nrows];                      // new一个标签数组
        for (int i=0; i<_nrows; i++){
          _label[i] = closest(_data[i]);              // 计算到各个簇中心的距离。最近距离即标记为该簇label,label数组的大小为向量个数,值为各个label
        }
        
        // recompute centroids based on the assignments  
        c1 = updateCentroids();
        round ++;
        if ((niter >0 && round >=niter) || converge(_centroids, c1, threshold))
          break;
      }

      System.out.println("Clustering converges at round " + round);
  }

  // find the closest centroid for the record v
  private int closest(double [] v){
    double mindist = dist(v, _centroids[0]);
    int label =0;
    for (int i=1; i<_numClusters; i++){   // 计算到各个簇中心的距离。最近距离即标记为该簇label
      double t = dist(v, _centroids[i]);
      if (mindist>t){
        mindist = t;
        label = i;
      }
    }
    return label;
  }

  // compute Euclidean distance between two vectors v1 and v2
  private double dist(double [] v1, double [] v2){
    double sum=0;
    for (int i=0; i<_ndims; i++){
      double d = v1[i]-v2[i];
      sum += d*d;
    }
    return Math.sqrt(sum);
  }

  // according to the cluster labels, recompute the centroids
  // the centroid is updated by averaging its members in the cluster.
  // this only applies to Euclidean distance as the similarity measure.

  private double [][] updateCentroids(){
    // initialize centroids and set to 0
    double [][] newc = new double [_numClusters][]; //new centroids
    int [] counts = new int[_numClusters]; // sizes of the clusters

    // intialize
    for (int i=0; i<_numClusters; i++){///////初始化新的簇中心newc[i][j], i 是簇个数k是预设值,j是维数
      counts[i] =0;
      newc[i] = new double [_ndims];
      for (int j=0; j<_ndims; j++)//////初值为0
        newc[i][j] =0;
    }


    for (int i=0; i<_nrows; i++){
      int cn = _label[i]; // the cluster membership id for record i, 得到每个向量i的label值,利用label值当成新的簇中心newc的index
      for (int j=0; j<_ndims; j++){
        newc[cn][j] += _data[i][j]; // update that centroid by adding the member data record,
      }                             //针对每个原始向量i以及其所当前所在的label-cn,把每个维度j都要进行计算一次加和并求出均值,作为当前的簇中心
      counts[cn]++;
    }

    // finally get the average
    for (int i=0; i< _numClusters; i++){
      for (int j=0; j<_ndims; j++){
        newc[i][j]/= counts[i];
      }
    }

    return newc;
  }



4.  KMeans + DTW

4.1// input data

4.2// clustering {
// 初始化簇中心 ,init each cluster centroid

// calcate every two vector DTW distance.  DTW[i][j], 
// 计算当前簇最近closest距离,并reasignment 给每个sample  i 做标记
    dist() 使用dtw进行计算
//  updateCentroids 刷新簇中心,可选的穷举方法如下:
遍历每个样本为各个簇的中心位置,计算新的reasignment后的距离和,当距离和最小的时候,
簇中心不在变化,循环终止。即为最终结果。


}



你可能感兴趣的:(机器学习与数据挖掘)