1. 程式人生 > >聚類分析(三) K中心點演算法(k-mediods)

聚類分析(三) K中心點演算法(k-mediods)

K 中心點演算法( K-medoids )

前面介紹了 k-means 演算法,並列舉了該演算法的缺點。而 K 中心點演算法( K-medoids )正好能解決 k-means 演算法中的 “噪聲”敏感這個問題。

如何解決的呢?

首先,我們得介紹下 k-means 演算法為什麼會對“噪聲”敏感。還記得 K-means 尋找質點的過程嗎?對某類簇中所有的樣本點維度求平均值,即獲得該類簇質點的維度。當聚類的樣本點中有“噪聲”(離群點)時,在計算類簇質點的過程中會受到噪聲異常維度的干擾,造成所得質點和實際質點位置偏差過大,從而使類簇發生“畸變”。

Eg: 類簇 C1 中已經包含點 A(1,1) 、 B(2,2) 、 C(1,2) 、 D(2,1) , 假設 N(100,100) 為異常點,當它納入類簇 C1時,計算質點 Centroid((1+2+1+2+100)/5,(1+2+2+1+100)/5)=centroid(21,21), 此時可能造成了類簇 C1 質點的偏移,在下一輪迭代重新劃分樣本點的時候,將大量不屬於類簇 C1 的樣本點納入,因此得到不準確的聚類結果。

為了解決該問題, K 中心點演算法( K-medoids )提出了新的質點選取方式,而不是簡單像 k-means 演算法採用均值計演算法。在 K 中心點演算法中,每次迭代後的質點都是從聚類的樣本點中選取,而選取的標準就是當該樣本點成為新的質點後能提高類簇的聚類質量,使得類簇更緊湊。該演算法使用絕對誤差標準來定義一個類簇的緊湊程度。

聚類分析(三) <wbr>K中心點演算法(k-mediods)   (p 是空間中的樣本點,Oj 是類簇Cj 的質點)

如果某樣本點成為質點後,絕對誤差能小於原質點所造成的絕對誤差,那麼 K 中心點演算法認為該樣本點是可以取代原質點的,在一次迭代重計算類簇質點的時候,我們選擇絕對誤差最小的那個樣本點成為新的質點。

Eg :樣本點 A –>E1=10

樣本點 B –>E2=11

樣本點 C –>E3=12

原質點 O–>E4=13 ,那我們選舉 A 作為類簇的新質點。

與 K-means 演算法一樣, K-medoids 也是採用歐幾里得距離來衡量某個樣本點到底是屬於哪個類簇。終止條件是,當所有的類簇的質點都不在發生變化時,即認為聚類結束。

該演算法除了改善 K-means 的“噪聲”敏感以後,其他缺點和 K-means 一致,並且由於採用新的質點計算規則,也使得演算法的時間複雜度上升: O ( k(n-k)2 )

Java實現程式碼如下:

package com.kmedoids;
import java.util.ArrayList;
public class Cluster {
    private String clusterName; // 類簇名
    private Medoid medoid; // 類簇的質點
    private ArrayList<DataPoint> dataPoints; // 類簇中各樣本點

    public Cluster(String clusterName) {
        this.clusterName = clusterName;
        this.medoid = null; // will be set by calling setCentroid()
        dataPoints = new ArrayList<DataPoint>();
    }

    public void setMedoid(Medoid c) {
        medoid = c;
    }

    public Medoid getMedoid() {
        return medoid;
    }

   
    public void addDataPoint(DataPoint dp) { // called from CAInstance
        dp.setCluster(this);// 標註該類簇屬於某點,計算歐式距離
        this.dataPoints.add(dp);
    }

    public void removeDataPoint(DataPoint dp) {
        this.dataPoints.remove(dp);
    }

    public int getNumDataPoints() {
        return this.dataPoints.size();
    }

    public DataPoint getDataPoint(int pos) {
        return (DataPoint) this.dataPoints.get(pos);
    }


    public String getName() {
        return this.clusterName;
    }

    public ArrayList<DataPoint> getDataPoints() {
        return this.dataPoints;
    }
}

------------------------------------

package com.kmedoids;
import java.util.ArrayList;

public class DataPoint {
    private double dimension[]; //樣本點的維度
    private String pointName; //樣本點名字
    private Cluster cluster; //類簇
    private double euDt;//樣本點到質點的距離

    public DataPoint(double dimension[], String pointName) {
        this.dimension = dimension;
        this.pointName = pointName;
        this.cluster = null;
    }

    public void setCluster(Cluster cluster) {
        this.cluster = cluster;
    }


   
    public double calEuclideanDistanceSum() {
        double sum=0.0;
        Cluster cluster=this.getCluster();
        ArrayList<DataPoint> dataPoints=cluster.getDataPoints();

        for(int i=0;i<dataPoints.size();i++){
            double[] dims=dataPoints.get(i).getDimensioin();
            for(int j=0;j<dims.length;j++){
                 double temp=Math.pow((dims[j]-this.dimension[j]),2);
                 sum=sum+temp;
            }
        }

        return Math.sqrt(sum);
    }

   
    public double testEuclideanDistance(Medoid c) {
        double sum=0.0;
        double[] cDim=c.getDimensioin();

        for(int i=0;i<dimension.length;i++){
           double temp=Math.pow((dimension[i]-cDim[i]),2);
           sum=sum+temp;
        }

        return Math.sqrt(sum);
    }

    public double[] getDimensioin() {
        return this.dimension;
    }

    public Cluster getCluster() {
        return this.cluster;
    }

    public double getCurrentEuDt() {
        return this.euDt;
    }

    public String getPointName() {
        return this.pointName;
    }
}
-------------------------------

package com.kmedoids;
import java.util.ArrayList;

public class Medoid{

    private double dimension[]; // 質點的維度
    private Cluster cluster; //所屬類簇
    private double etdDisSum;//Medoid到本類簇中所有的歐式距離之和


    public Medoid(double dimension[]) {
        this.dimension = dimension;
    }

    public void setCluster(Cluster c) {
        this.cluster = c;
    }

    public double[] getDimensioin() {
        return this.dimension;
    }

    public Cluster getCluster() {
        return this.cluster;
    }

    public void calcMedoid() {// 取代價最小的點
        calcEtdDisSum();
        double minEucDisSum = this.etdDisSum;
        ArrayList<DataPoint> dps = this.cluster.getDataPoints();
        for (int i = 0; i < dps.size(); i++) {
            double tempeucDisSum = dps.get(i).calEuclideanDistanceSum();
            if (tempeucDisSum < minEucDisSum) {
                dimension = dps.get(i).getDimensioin();
                minEucDisSum=tempeucDisSum;
            }
        }
    }

    // 計算該Medoid到同類簇所有樣本點的歐斯距離和
    private void calcEtdDisSum() {
        double sum=0.0;
        Cluster cluster=this.getCluster();
        ArrayList<DataPoint> dataPoints=cluster.getDataPoints();

        for(int i=0;i<dataPoints.size();i++){
            double[] dims=dataPoints.get(i).getDimensioin();
            for(int j=0;j<dims.length;j++){
                 double temp=Math.abs(dims[j]-this.dimension[j]);
                 sum=sum+temp;
            }
        }
        etdDisSum= sum;
    }
}

--------------------------

package com.kmedoids;

import java.util.ArrayList;

public class ClusterAnalysis {

    private Cluster[] clusters;// 所有類簇
    private int miter;// 迭代次數
    private ArrayList<DataPoint> dataPoints = new ArrayList<DataPoint>();// 所有樣本點
    private int dimNum;//維度

    public ClusterAnalysis(int k, int iter, ArrayList<DataPoint> dataPoints,int dimNum) {
        clusters = new Cluster[k];// 類簇種類數
        for (int i = 0; i < k; i++) {
            clusters[i] = new Cluster("Cluster:" + i);
        }
        this.miter = iter;
        this.dataPoints = dataPoints;
        this.dimNum=dimNum;
    }

    public int getIterations() {
        return miter;
    }

    public ArrayList<DataPoint>[] getClusterOutput() {
        ArrayList<DataPoint> v[] = new ArrayList[clusters.length];
        for (int i = 0; i < clusters.length; i++) {
            v[i] = clusters[i].getDataPoints();
        }
        return v;
    }

   
    public void startAnalysis(double[][] medoids) {

        setInitialMedoids(medoids);

        double[][] newMedoids=medoids;
        double[][] oldMedoids=new double[medoids.length][this.dimNum];

        while(!isEqual(oldMedoids,newMedoids)){
            for(int m = 0; m < clusters.length; m++){//每次迭代開始情況各類簇的點
                clusters[m].getDataPoints().clear();
            }
            for (int j = 0; j < dataPoints.size(); j++) {
                int clusterIndex=0;
                double minDistance=Double.MAX_VALUE;

                for (int k = 0; k < clusters.length; k++) {//判斷樣本點屬於哪個類簇
                    double eucDistance=dataPoints.get(j).testEuclideanDistance(clusters[k].getMedoid());
                    if(eucDistance<minDistance){
                        minDistance=eucDistance;
                        clusterIndex=k;
                    }
                }

               //將該樣本點新增到該類簇
                clusters[clusterIndex].addDataPoint(dataPoints.get(j));

            }

            for(int m = 0; m < clusters.length; m++){
                clusters[m].getMedoid().calcMedoid();//重新計算各類簇的質點
            }

            for(int i=0;i<medoids.length;i++){
                for(int j=0;j<this.dimNum;j++){
                    oldMedoids[i][j]=newMedoids[i][j];
                }
            }


            for(int n=0;n<clusters.length;n++){
                newMedoids[n]=clusters[n].getMedoid().getDimensioin();
            }

            this.miter++;
        }


    }

    private void setInitialMedoids(double[][] medoids) {
        for (int n = 0; n < clusters.length; n++) {
            Medoid medoid = new Medoid(medoids[n]);
            clusters[n].setMedoid(medoid);
            medoid.setCluster(clusters[n]);
        }
    }

   
    private boolean isEqual(double[][] oldMedoids,double[][] newMedoids){
        boolean flag=false;
        for(int i=0;i<oldMedoids.length;i++){
            for(int j=0;j<oldMedoids[i].length;j++){
                if(oldMedoids[i][j]!=newMedoids[i][j]){
                    return flag;
                }
            }
        }
        flag=true;
        return flag;
    }
}
--------------------------------------------

package com.kmedoids;

import java.util.ArrayList;
import java.util.Iterator;

public class TestMain {
    public static void main (String args[]){
        ArrayList<DataPoint> dataPoints = new ArrayList<DataPoint>();

       
        double[] a={2,3};
        double[] b={2,4};
        double[] c={1,4};
        double[] d={1,3};
        double[] e={2,2};
        double[] f={3,2};

        double[] g={8,7};
        double[] h={8,6};
        double[] i={7,7};
        double[] j={7,6};
        double[] k={8,5};

        double[] l={100,2};//孤立點

        double[] m={8,20};
        double[] n={8,19};
        double[] o={7,18};
        double[] p={7,17};
        double[] q={7,20};

        dataPoints.add(new DataPoint(a,"a"));
        dataPoints.add(new DataPoint(b,"b"));
        dataPoints.add(new DataPoint(c,"c"));
        dataPoints.add(new DataPoint(d,"d"));
        dataPoints.add(new DataPoint(e,"e"));
        dataPoints.add(new DataPoint(f,"f"));

        dataPoints.add(new DataPoint(g,"g"));
        dataPoints.add(new DataPoint(h,"h"));
        dataPoints.add(new DataPoint(i,"i"));
        dataPoints.add(new DataPoint(j,"j"));
        dataPoints.add(new DataPoint(k,"k"));

        dataPoints.add(new DataPoint(l,"l"));

        dataPoints.add(new DataPoint(m,"m"));
        dataPoints.add(new DataPoint(n,"n"));
        dataPoints.add(new DataPoint(o,"o"));
        dataPoints.add(new DataPoint(p,"p"));
        dataPoints.add(new DataPoint(q,"q"));

        ClusterAnalysis ca=new ClusterAnalysis(3,0,dataPoints,2);
       double[][] cen={{8,7},{8,6},{7,7}};
       ca.startAnalysis(cen);

 

      ArrayList<DataPoint>[] v = ca.getClusterOutput();
        for (int ii=0; ii<v.length; ii++){
            ArrayList tempV = v[ii];
            System.out.println("-----------Cluster"+ii+"---------");
            Iterator iter = tempV.iterator();
            while(iter.hasNext()){
                DataPoint dpTemp = (DataPoint)iter.next();
                System.out.println(dpTemp.getPointName());
            }
        }
    }

}

相關推薦

分析 K中心演算法k-mediods

K 中心點演算法( K-medoids ) 前面介紹了 k-means 演算法,並列舉了該演算法的缺點。而 K 中心點演算法( K-medoids )正好能解決 k-means 演算法中的 “噪聲”敏感這個問題。 如何解決的呢? 首先,我們得介紹下 k-means 演算法為什麼會對“噪聲”敏感。還記

k-中心演算法k-medoids及Matlab程式碼實現

k-中心點演算法(k-medoids)及Matlab程式碼 1. 提出: k-means演算法是每次選擇簇的均值作為新的中心點,迭代直到簇中心不再變化(趨於穩定)。其缺點是對離群點特別敏感,因為一個很大的極端值物件會扭曲資料分佈,使簇均值嚴重偏離;於是我

K-means和K-中心演算法

K-means和K-中心點演算法 k-means演算法 在聚類的演算法中這個演算法比較常用,首先是將資料集中的每一條資料想象稱為超空間中的一個點,因為通常資料不只是只有三個特徵屬性,當超過三個特徵屬性之後就難以在座標空間中進行表示,所以這裡統一的稱為超空間 先確立一些比較重要的思

分析 層次及matlab程式

一、層次聚類介紹 1.1 簡介 層次聚類,主要是對給定的待聚類的資料集進行層次化分解。主要分為兩大類: 1.從下到上的凝聚聚類 2.從上到下的分裂聚類 其他演算法大部分是對樣本之間距離度量或者類間凝聚/分裂依據進行改進。 1.2從下到上的凝聚演算法 從下到上的凝聚演算法能夠讓人們較為直觀的觀

分析k-means及matlab程式

1.介紹 k-means是一種常見的基於劃分的聚類演算法。劃分方法的基本思想是:給定一個有N個元組或者記錄的資料集,將資料集依據樣本之間的距離進行迭代分裂,劃分為K個簇,其中每個簇至少包含一條實驗資料。 2.k-means原理分析 2.1工作原理 (1)首先,k-means方法從資料集中隨機

機器學習筆記3——使用分析演算法對文字分類分類數k未知

聚類分析是一種無監督機器學習(訓練樣本的標記資訊是未知的)演算法,它的目標是將相似的物件歸到同一個簇中,將不相似的物件歸到不同的簇中。如果要使用聚類分析演算法對一堆文字分類,關鍵要解決這幾個問題: 如何衡量兩個物件是否相似 演算法的效能怎麼度量 如何確定分類的個數或聚類

python資料分析:流量資料化運營——基於自動K值得KMeans廣告效果分析

案例背景 某企業由於投放的廣告渠道比較多,需要對其做廣告效果分析以實現有針對性的廣告效果測量和優化工作。跟以應用為目的的案例不同的是,由於本案例是一個分析型案例,該過程的輸出其實是不固定的,因此需要跟業務運營方具體溝通需求。 以下是在開展研究之前的基本預設條件: 廣告渠道

無監督分類:分析K均值

1.K均值聚類 K均值聚類是最基礎的一種聚類方法。K均值聚類,就是把看起來最集中、最不分散的簇標籤分配到輸入訓練樣本{xi}中。具體而言就是通過下式計算簇y的分散狀況: 在這裡,∑i,yi=y表示

第11章 K-means文件分析

載入資料集 已標記好類別的四個文件資料集:(網路安全,電子學,醫學medical,太空) import matplotlib.pyplot as plt import numpy as np from time import time from sklearn.datasets

分析演算法Python3.6實踐K均值K-means

在http://blog.csdn.net/zouxy09/article/details/17589329 上看到聚類分析演算法,但是是基於python2.7.5版本,直接移植到Python3.6會有問題,更改程式碼後為增加對比性,繪製原始資料不部分;程式碼如下: ##

機器學習之分析---K-means

初探k-means(Matlab)俗話說:,聚類分析的目的是:在資料中發現數據物件之間的關係,並將資料進行分組,使得組內的相似性儘可能大,組間的差別盡可能大,那麼聚類的效果越好。例如在市場營銷中,聚類分

基於R語言的分析k-means,層次

今天給大家展示基於R語言的聚類,在此之前呢,首先談談聚類分析,以及常見的聚類模型,說起聚類我們都知道,就是按照一定的相似性度量方式,把接近的一些個體聚在一起。這裡主要是相似性度量,不同的資料型別,我們需要用不同的度量方式。除此之外,聚類的思想也很重要,要是按照聚

K-中心演算法K-Medoide

K-中心點演算法也是一種常用的聚類演算法,K-中心點聚類的基本思想和K-Means的思想相同,實質上是對K-means演算法的優化和改進。在K-means中,異常資料對其的演算法過程會有較大的影響。在K-means演算法執行過程中,可以通過隨機的方式選擇初始質心,也只有初始

分析K均值與層次

介紹三類聚類分析演算法,本篇介紹K均值聚類、層次聚類,下篇介紹圖團體(graph community)聚類。 聚類分析又稱群分析,它是研究樣本分類問題的一種統計分析方法,同時也是資料探勘的一個重要演算法。聚類分析以相似性為基礎,在一個聚類(cluster)中的

數據分析 第四篇:分析劃分

think trace stat pid 函數返回 around 構建 之前 得出 聚類是把一個數據集劃分成多個子集的過程,每一個子集稱作一個簇(Cluster),聚類使得簇內的對象具有很高的相似性,但與其他簇中的對象很不相似,由聚類分析產生的簇的集合稱作一個聚類。在相同的

分析劃分方法,層次方法、密度方法 ---機器學習

本節學習聚類分析,聚類屬於無監督學習,其中聚類的方法有很多種常見的有K-means、層次聚類(Hierarchical clustering)、譜聚類(Spectral Clustering)等,在這裡,上來不會直接介紹這些理論,需要一些基礎知識鋪墊,和前面一樣,一上來就直接介紹聚類演算法,顯得

分析 介紹

一、 聚類演算法 1.1引言 聚類分析,在英文中是Cluster analysis,是機器學習中無監督學習的典型代表。無監督學習沒有訓練過程,給定一些樣本資料,讓機器學習演算法直接對這些資料進行分析,得到資料的某些知識。而無監督學習的另外一類典型演算法是資料降維,它將一個高維向量變換到低維空

python資料分析分析cluster analysis

何為聚類分析 聚類分析或聚類是對一組物件進行分組的任務,使得同一組(稱為聚類)中的物件(在某種意義上)與其他組(聚類)中的物件更相似(在某種意義上)。它是探索性資料探勘的主要任務,也是統計 資料分析的常用技術,用於許多領域,包括機器學習,模式識別,影象分析,資訊檢索,生物資訊學,資料

吳裕雄 資料探勘與分析案例實戰14——Kmeans分析

# 匯入第三方包import pandas as pdimport numpy as np import matplotlib.pyplot as pltfrom sklearn.cluster import KMeansfrom sklearn import metrics # 隨機生成三組二元正態分佈隨

TensorFlow學習 資料分析

本文通過K均值演算法作為例子研究資料聚類分析 一、無監督學習概念 無監督學習可以從給定的資料集中找到感興趣的模式。 無監督學習,一般不給出模式的相關資訊。所以,無監督學習演算法需要自動探索資訊是怎樣組成的,並識別資料中的不同結構。 二、什麼是聚類 聚類就是對大量未知