1. 程式人生 > >K-means聚類分析與python實現

K-means聚類分析與python實現

    K-means演算法是很典型的基於距離的聚類演算法,採用距離作為相似性的評價指標,即認為兩個物件的距離越近,其相似度就越大。該演算法認為簇是由距離靠近的物件組成的,因此把得到緊湊且獨立的簇作為最終目標。

演算法原理:

    首先從n個數據物件任意選擇 k 個物件作為初始聚類中心;而對於所剩下其它物件,則根據它們與這些聚類中心的相似度(距離),分別將它們分配給與其最相似的(聚類中心所代表的)聚類;然後再計算每個所獲新聚類的聚類中心(該聚類中所有物件的均值);不斷重複這一過程直到標準測度函式開始收斂為止。一般都採用均方差作為標準測度函式。k個聚類具有以下特點:各聚類本身儘可能的緊湊,而各聚類之間儘可能的分開。


演算法優缺點:

優點:

1.對處理大資料集,該演算法保持可伸縮性和高效性

2.演算法快速、簡單,易於理解;

缺點:

1.在 K-means 演算法中 K 是事先給定的,這個 K 值的選定是非常難以估計的;

2.若簇中含有異常點,將導致均值偏離嚴重(即:對噪聲和孤立點資料敏感);

3.該演算法需要不斷地進行樣本分類調整,不斷地計算調整後的新的聚類中心,因此當資料量非常大時,演算法的時間開銷是非常大的;

4.在 K-means 演算法中,首先需要根據初始聚類中心來確定一個初始劃分,然後對初始劃分進行優化。這個初始聚類中心的選擇對聚類結果有較大的影響,一旦初始值選擇的不好,可能無法得到有效的聚類結果;

5.區域性最優解而不是全域性優 (這個和初始點選誰有關)。

演算法流程:

step-1:首先從n個數據物件任意選擇 k 個物件作為初始聚類中心;

#隨機選擇K個點
k = rd.sample(range(count), k_count)
k_point = [[x[i], [y[i]]] for i in k]   #保證有序
k_point.sort()
step-2:根據每個聚類物件的均值(中心物件),計算每個物件與這些中心物件的距離;並根據最小距離重新對相應物件進行劃分;
        km = [[] for i in range(k_count)]      #儲存每個簇的索引
        #遍歷所有點
        for i in range(count):
            cp = [x[i], y[i]]                   #當前點
            #計算cp點到所有質心的距離
            _sse = [distance(k_point[j], cp) for j in range(k_count)]
            #cp點到那個質心最近
            min_index = _sse.index(min(_sse))   
            #把cp點併入第i簇
            km[min_index].append(i)
step-3:重新計算每個(有變化)聚類的均值(中心物件);
        #更換質心
        step+=1
        k_new = []
        for i in range(k_count):
            _x = sum([x[j] for j in km[i]]) / len(km[i])
            _y = sum([y[j] for j in km[i]]) / len(km[i])
            k_new.append([_x, _y])
        k_new.sort()        #排序
step-4: 迴圈(2)到(3)直到每個聚類不再發生變化為止
        frames.append(imageio.imread('1.jpg'))
        if (k_new != k_point):#一直迴圈直到聚類中心沒有變化
            k_point = k_new
        else:
            return km
python完整程式碼實現:
# coding:utf-8
import numpy as np
import pylab as pl
import random as rd
import imageio
#計算平面兩點的歐氏距離
step=0
color=['.r','.g','.b','.y']#顏色種類
dcolor=['*r','*g','*b','*y']#顏色種類
frames = []
def distance(a, b):
    return (a[0]- b[0]) ** 2 + (a[1] - b[1]) ** 2
#K均值演算法
def k_means(x, y, k_count):
    count = len(x)      #點的個數
    #隨機選擇K個點
    k = rd.sample(range(count), k_count)
    k_point = [[x[i], [y[i]]] for i in k]   #保證有序
    k_point.sort()
    global frames
    global step
    while True:
        km = [[] for i in range(k_count)]      #儲存每個簇的索引
        #遍歷所有點
        for i in range(count):
            cp = [x[i], y[i]]                   #當前點
            #計算cp點到所有質心的距離
            _sse = [distance(k_point[j], cp) for j in range(k_count)]
            #cp點到那個質心最近
            min_index = _sse.index(min(_sse))   
            #把cp點併入第i簇
            km[min_index].append(i)
        #更換質心
        step+=1
        k_new = []
        for i in range(k_count):
            _x = sum([x[j] for j in km[i]]) / len(km[i])
            _y = sum([y[j] for j in km[i]]) / len(km[i])
            k_new.append([_x, _y])
        k_new.sort()        #排序

        #使用Matplotlab畫圖
        pl.figure()
        pl.title("N=%d,k=%d  iteration:%d"%(count,k_count,step))
        for j in range(k_count):
            pl.plot([x[i] for i in km[j]], [y[i] for i in km[j]], color[j%4])
            pl.plot(k_point[j][0], k_point[j][1], dcolor[j%4])
        pl.savefig("1.jpg")
        frames.append(imageio.imread('1.jpg'))
        if (k_new != k_point):#一直迴圈直到聚類中心沒有變化
            k_point = k_new
        else:
            return km


x, y = np.loadtxt('2.csv', delimiter=',', unpack=True)
k_count = 4

km = k_means(x, y, k_count)
print step
imageio.mimsave('k-means.gif', frames, 'GIF', duration = 0.5)
實驗結果:
初始值選取的不同造成結果也不一樣,如:

程式碼:

連結:https://pan.baidu.com/s/1dEEEeWh 

密碼:需要的請回復或者支援下,賺點積分!吐舌頭

http://download.csdn.net/download/wind_blast/10155662

參考資料: