聚類分析之層次聚類演算法
層次聚類演算法:
前面介紹的K-means演算法和K中心點演算法都屬於劃分式(partitional)聚類演算法。層次聚類演算法是將所有的樣本點自底向上合併組成一棵樹或者自頂向下分裂成一棵樹的過程,這兩種方式分別稱為凝聚和分裂。
凝聚層次演算法:
初始階段,將每個樣本點分別當做其類簇,然後合併這些原子類簇直至達到預期的類簇數或者其他終止條件。
分裂層次演算法:
初始階段,將所有的樣本點當做同一類簇,然後分裂這個大類簇直至達到預期的類簇數或者其他終止條件。
兩種演算法的代表:
傳統的凝聚層次聚類演算法有AGENES,初始時,AGENES將每個樣本點自為一簇,然後這些簇根據某種準則逐漸合併,例如,如果簇
傳統的分裂層次聚類演算法有DIANA,初始時DIANA將所有樣本點歸為同一類簇,然後根據某種準則進行逐漸分裂,例如類簇C中兩個樣本點A和B之間的距離是類簇C中所有樣本點間距離最遠的一對,那麼樣本點A和B將分裂成兩個簇C1和C2,並且先前類簇C中其他樣本點根據與A和B之間的距離,分別納入到簇C1和C2中,例如,類簇C中樣本點O與樣本點A的歐幾里得距離為2,與樣本點B的歐幾里得距離為4,因為Distance(A,O)<Distance(B,O)那麼O將納入到類簇
如圖所示:
演算法:AGENES。傳統凝聚層次聚類演算法
輸入:K:目標類簇數 D:樣本點集合
輸出:K個類簇集合
方法:1) 將D中每個樣本點當做其類簇;
2) repeat
3) 找到分屬兩個不同類簇,且距離最近的樣本點對;
4) 將兩個類簇合並;
5) util 類簇數=K
演算法:DIANA。傳統分裂層次聚類演算法
輸入:K:目標類簇數 D:樣本點集合
輸出:K個類簇集合
方法:1) 將D中所有樣本點歸併成類簇;
2) repeat
3) 在同類簇中找到距離最遠的樣本點對;
4)
5) util 類簇數=K
缺點:
傳統的層次聚類演算法的效率比較低O(tn2) t:迭代次數 n:樣本點數,最明顯的一個缺點是不具有再分配能力,即如果樣本點A在某次迭代過程中已經劃分給類簇C1,那麼在後面的迭代過程中A將永遠屬於類簇C1,這將影響聚類結果的準確性。
改進:
一般情況下,層次聚類通常和劃分式聚類演算法組合,這樣既可以解決演算法效率的問題,又能解決樣本點再分配的問題,在後面將介紹BIRCH演算法。首先把鄰近樣本點劃分到微簇(microcluseters)中,然後對這些微簇使用K-means演算法。
----------------貼上本人實現的AGENES演算法,大家有興趣可以把DIANA演算法自己實現下---------------
package com.agenes;
public class DataPoint {
String dataPointName; // 樣本點名
Cluster cluster; // 樣本點所屬類簇
private double dimensioin[]; // 樣本點的維度
public DataPoint(){
}
public DataPoint(double[] dimensioin,String dataPointName){
this.dataPointName=dataPointName;
this.dimensioin=dimensioin;
}
public double[] getDimensioin() {
return dimensioin;
}
public void setDimensioin(double[] dimensioin) {
this.dimensioin = dimensioin;
}
public Cluster getCluster() {
return cluster;
}
public void setCluster(Cluster cluster) {
this.cluster = cluster;
}
public String getDataPointName() {
return dataPointName;
}
public void setDataPointName(String dataPointName) {
this.dataPointName = dataPointName;
}
}
package com.agenes;
import java.util.ArrayList;
import java.util.List;
public class Cluster {
private List<DataPoint> dataPoints = new ArrayList<DataPoint>(); // 類簇中的樣本點
private String clusterName;
public List<DataPoint> getDataPoints() {
return dataPoints;
}
public void setDataPoints(List<DataPoint> dataPoints) {
this.dataPoints = dataPoints;
}
public String getClusterName() {
return clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
}
package com.agenes;
import java.util.ArrayList;
import java.util.List;
public class ClusterAnalysis {
public List<Cluster> startAnalysis(List<DataPoint> dataPoints,int ClusterNum){
List<Cluster> finalClusters=new ArrayList<Cluster>();
List<Cluster> originalClusters=initialCluster(dataPoints);
finalClusters=originalClusters;
while(finalClusters.size()>ClusterNum){
double min=Double.MAX_VALUE;
int mergeIndexA=0;
int mergeIndexB=0;
for(int i=0;i<finalClusters.size();i++){
for(int j=0;j<finalClusters.size();j++){
if(i!=j){
Cluster clusterA=finalClusters.get(i);
Cluster clusterB=finalClusters.get(j);
List<DataPoint> dataPointsA=clusterA.getDataPoints();
List<DataPoint> dataPointsB=clusterB.getDataPoints();
for(int m=0;m<dataPointsA.size();m++){
for(int n=0;n<dataPointsB.size();n++){
double tempDis=getDistance(dataPointsA.get(m),dataPointsB.get(n));