K 均值聚類演算法 K means

2021-07-05 10:44:49 字數 4820 閱讀 6714

k-means是一種無監督的學習,將相似的物件歸到同乙個簇中.可以將一批資料分為k個不同的簇,並且每個簇的中心採用簇中所含樣本的均值計算而成.

k-means演算法的k值需要由使用者指定,演算法開始時隨機選擇k個初始點作為質心,然後將資料集中的每個點分配到乙個簇中.那麼,如何確定某一組資料歸於哪個簇中呢?這是通過計算這一組資料與k個質心的距離來實現的,這組資料離哪個質心最近,就將其歸於哪個簇中.待所有資料第一次迴圈完畢後,重新計算質心,質心更新為該簇所有點的平均值.直到每乙個簇的質心都不發生變化為止.

那麼上面所述的距離到底是個什麼?這可以由使用者自己來選擇某種距離計算方法來實現,如歐氏距離,曼哈頓距離等等.

#計算兩組資料間的歐氏距離

def disteclud(veca, vecb):

return sqrt(sum(power(veca - vecb, 2)))

#構造質心

def randcent(dataset, k):

n = shape(dataset)[1]#求出資料的列數

centroids = mat(zeros((k, n)))#生成k組n列的矩陣,值全為0

for j in range(n):#對每一列的數字隨機生成

minj = min(dataset[:, j])#讀取某列中的最小值

rangej = float(max(dataset[:, j]) - minj)#某列資料範圍

centroids[:, j] = minj + rangej * random.rand(k, 1)#隨機矩陣該列的值為最小值+資料範圍乘以乙個0到1的隨機數,rand(k, 1)生成k行1列的隨機矩陣

return centroids

該程式片段會根據傳入的dataset和k值計算出k個初始質心

#計算kmeans,返回k個中心點以及各組資料離中心點的距離

def kmeans(dataset, k, distmeas=disteclud, createcent=randcent):

m = shape(dataset)[0]#獲取待分組樣本總數

clusterassment = mat(zeros((m,2)))#用於儲存各組樣本屬於哪個簇,同時儲存與簇中心的距離

centroids = createcent(dataset, k)#隨機建立k個質心

clusterchanged = true#質心變化標誌,初始化為true,在迴圈中,任何乙個質心發生變化,該值就為true

while clusterchanged:

clusterchanged = false

for i in range(m):#對m組樣本進行迴圈

mindist = inf#取正無窮

minindex = -1#取下標為-1

for j in range(k):#對每個質心進行迴圈

distji = distmeas(centroids[j,:],dataset[i,:])#計算第i組樣本離質心j的距離

if distji < mindist:#若距離比上一步計算的最小距離還小

mindist = distji#更新該值

minindex = j#則樣本i離質心j最近

if clusterassment[i,0] != minindex:#若儲存的質心與新計算的質心不一致

clusterchanged = true

clusterassment[i,:] = minindex,mindist**2#計算的質心,與質心距離平方

print centroids

for cent in range(k):#對k個中心進行迴圈

ptsinclust = dataset[nonzero(clusterassment[:,0].a==cent)[0]]#將屬於第cent個中心的所以樣本從dataset中取出

centroids[cent,:] = mean(ptsinclust, axis=0) #根據簇cent中的所有樣本,計算新的質心

return centroids, clusterassment#返回最終穩定的質心,以及各樣本所屬質心和距離

程式的詳細過程都寫在注釋中.大致思路是,根據傳入的dataset和k值,以及構造初始質心的方法,計算距離的方法等引數生成最終的

質心,以及各樣本距離所屬

質心和與

質心的距離.計算過程中只要發現任何乙個

質心發生了調整,則繼續進行下一輪計算,直到各

質心保持不變為止.

問題來了,對待分組樣本,如何能夠事先知道可以分為多少組呢?並且,如何衡量該聚類的效果好壞呢?其實上面的程式有可能陷入區域性最小值,而非全域性最小值.有一種度量聚類效果的指標是sse(sum of squared error,誤差平方和),誤差平方也就是上面程式2的clusterassment中下標為1的那些資料.

首先我們假設k的值已經固定,即明確資料要分成多少類.由於採用sse指標,那麼離

質心越遠的點對該指標的影響最大.為了降低sse的值,首先想到的是可以增加

質心的個數,將sse最大的那個簇採用k`=2重新聚類.但是增加

質心個數又違背了k的個數固定這個條件.因為增加了乙個

質心,那麼我們再將其中某兩個質心進行合併是不是又減少了乙個

質心呢?如何選擇哪寫

質心進行合併?有兩種辦法,第一是合併最近的質心,第二是合併兩個使得sse增幅最小的質心.

為了避免陷入區域性最小值,可以使用二分k-means演算法(bisecting k-means).

假設資料會被分成k個組,首先將所有資料當成乙個簇,將該簇一分為2,然後選擇其中乙個簇再進行二分.每次二分都會增加乙個簇,直到簇的數目達到k為止.選擇哪乙個簇進行二分呢?哪個簇進行二分能最大成都降低sse的值就選擇哪個簇進行二分.

#二分k-means演算法

def bikmeans(dataset, k, distmeas=disteclud):

m = shape(dataset)[0]#獲取待分組資料集的數目

clusterassment = mat(zeros((m,2)))#用於儲存各組樣本屬於哪個簇,同時儲存與簇中心的距離

centroid0 = mean(dataset, axis=0).tolist()[0]#取所有樣本各個指標的平均值做為第乙個簇的質心

centlist =[centroid0] #用於儲存所有的質心

for j in range(m):#計算所有樣本與初始質心距離的平方

clusterassment[j,1] = distmeas(mat(centroid0), dataset[j,:])**2

while (len(centlist) < k):#當前質心數小於設定質心數k,則繼續二分

lowestsse = inf#初始sse為正無窮

for i in range(len(centlist)):#迴圈遍歷每乙個已有質心

ptsincurrcluster = dataset[nonzero(clusterassment[:,0].a==i)[0],:]#獲取i簇中的所有資料

centroidmat, splitclustass = kmeans(ptsincurrcluster, 2, distmeas)#將該簇進行二分

ssesplit = sum(splitclustass[:,1])#計算二分後的sse

ssenotsplit = sum(clusterassment[nonzero(clusterassment[:,0].a!=i)[0],1])#不在該簇中其他點的sse

print "ssesplit, and notsplit: ",ssesplit,ssenotsplit

if (ssesplit + ssenotsplit) < lowestsse:#兩者相加,若比最低sse還要低

bestcenttosplit = i#就在第i個質心上

bestnewcents = centroidmat#i簇上的二分質心

bestclustass = splitclustass.copy()#返回k個中心點以及各組資料離中心點的距離

lowestsse = ssesplit + ssenotsplit#最低sse更新為當前最低值

#每次二分會新增乙個質心,,bestclustass每次都是分成0和1兩種情況,

#比如之前有兩個質心0和1,發現其中1簇可以繼續二分,那麼現在就有三個質心,將新的1設定為2,將新的0設定為1,

#那麼現在的三個質心分別為0,1,2,原來的0保持不變

bestclustass[nonzero(bestclustass[:,0].a == 1)[0],0] = len(centlist) #將其中是1的更新為最新增加的簇

bestclustass[nonzero(bestclustass[:,0].a == 0)[0],0] = bestcenttosplit#將其中為0的繼續儲存在之前那個質心編號內

print 'the bestcenttosplit is: ',bestcenttosplit

print 'the len of bestclustass is: ', len(bestclustass)

centlist[bestcenttosplit] = bestnewcents[0,:].tolist()[0]#將最佳二分的i簇原來的質心替換成新生成的第乙個質心

clusterassment[nonzero(clusterassment[:,0].a == bestcenttosplit)[0],:]= bestclustass#最佳二分的i簇新的相關資訊

return mat(centlist), clusterassment

若k值不確定,有乙個canopy演算法可以用在k-means之前用於確定k的個數以及初始的質心座標。

K均值 K means 聚類演算法

j.b.macqueen 在 1967 年提出的k means演算法 22 到目前為止用於科學和工業應用的諸多聚類演算法中一種極有影響的技術。它是聚類方法中乙個基本的劃分方法,常常採用誤差平方和準則函式作為聚類準則函式,誤差平方和準則函式定義為 3 1 其中,是類 中資料物件的均值,即 j 1,2,...

K均值聚類演算法 K Means

將資料集中的資料按照距離質心的遠近分到各個簇中 將各個簇中的資料求平均值,作為新的質心,重複上一步,直到所有的簇不再改變 from numpy import defloaddataset filename dataset f open filename for line in f.readlines...

kMeans演算法(K均值聚類演算法)

機器學習中有兩類的大問題,乙個是分類,乙個是聚類。分類是根據一些給定的已知類別標號的樣本,訓練某種學習機器,使它能夠對未知類別的樣本進行分類。這屬於supervised learning 監督學習 而聚類指事先並不知道任何樣本的類別標號,希望通過某種演算法來把一組未知類別的樣本劃分成若干類別,這在機...