機器學習之非監督學習(六)——聚類(K-Means)

K-means算法 (無監督算法,聚類算法)

1-1 基本流程


一、概念:


K-means中心思想:事先確定常數K,常數K意味着最終的聚類類別數,首先隨機選定初始點爲質心,並通過計算每一個樣本與質心之間的相似度(這裏爲歐式距離),將樣本點歸到最相似的類中,接着,重新計算每個類的質心(即爲類中心),重複這樣的過程,直到質心不再改變,最終就確定了每個樣本所屬的類別以及每個類的質心。由於每次都要計算所有的樣本與每一個質心之間的相似度,故在大規模的數據集上,K-Means算法的收斂速度比較慢。

聚類算法:是一種典型的無監督學習算法,主要用於將相似的樣本自動歸到一個類別中。
聚類算法與分類算法最大的區別是:聚類算法是無監督的學習算法,而分類算法屬於監督的學習
算法,分類是知道結果的。
在聚類算法中根據樣本之間的相似性,將樣本劃分到不同的類別中,對於不同的相似度計算方法,會得到不同的聚類結果,常用的相似度計算方法有歐式距離法。

二、主要特點:


常用距離
a.歐式距離
b.曼哈頓距離
應用:
a.去除孤立點,離羣點,只針對度量算法,解決方法(常用歸一化預處理方法 )
b.離散化

三、算法流程:


1.選擇聚類的個數k(kmeans算法傳遞超參數的時候,只需設置最大的K值)
2.任意產生k個聚類,然後確定聚類中心,或者直接生成k箇中心。
3.對每個點確定其聚類中心點。
4.再計算其聚類新中心。
5.重複以上步驟直到滿足收斂要求。(通常就是確定的中心點不再改變。)

kmeans作用:去除奇異值
應爲EM算法,kmeans肯定會穩定到K箇中心點
kmeans算法k個隨機初始值怎麼選?
要多選幾次,比較,找出最好的那個。
a.bi-kmeans方法,依次補刀
b.層次聚類 k = 5,找到5箇中心點,接着把這個5箇中心點餵給kmeans,初始中心點不同,收斂的結果也可能不一樣的

四、小結


優點:
1、原理簡單(靠近中心點) ,實現容易
2、聚類效果中上(依賴K的選擇)
3、空間複雜度o(N)時間複雜度o(IKN)
N爲樣本點個數,K爲中心點個數,I爲迭代次數
缺點:
1、對離羣點, 噪聲敏感 (中心點易偏移)
2、很難發現大小差別很大的簇及進行增量計算
3、結果不一定是全局最優,只能保證局部最優(與K的個數及初值選取有關)

 

1-2 算法效果衡量標準


一、K值確定


Elbow method就是“肘”方法,對於n個點的數據集,迭代計算k from 1 to n,每次聚類完成後計算每個點到其所屬的簇中心的距離的平方和,可以想象到這個平方和是會逐漸變小的,直到k==n時平方和爲0,因爲每個點都是它所在的簇中心本身。但是在這個平方和變化過程中,會出現一個拐點也即“肘”點,下圖可以看到下降率突然變緩時即認爲是最佳的k值。

è¿éåå¾çæè¿°

肘方法的核心指標是SSE(sum of the squared errors,誤差平方和), Ci是第i個簇,
p是Ci中的樣本點, mi是Ci的質心(Ci中所有樣本的均值), SSE是所有樣本的聚
類誤差,代表了聚類效果的好壞。


 

肘方法的核心思想:
隨着聚類數k的增大,樣本劃分會更加精細,每個簇的聚合程度會逐漸提高,那麼誤差平方和SSE自然會逐漸變小。並且,當k小於真實聚類數時,由於k的增大會大幅增加每個簇的聚合程度,故SSE的下降幅度會很大,而當k到達真實聚類數時,再增加k所得到的聚合程度回報會迅速變小,所以SSE的下降幅度會驟減,然後隨着k值的繼續增大而趨於平緩,也就是說SSE和k的關係圖是一個手肘的形狀,而這個肘部對應的k值就是數據的真實聚類數。這也是該方法被稱爲肘方法的原因。

聚類效果怎麼判斷?
1、SSE誤差平方和越小越好,肘部拐點的地方。
2、也可用輪廓係數表示 係數越大,聚類效果越好,簇與簇之間距離越遠

kmeans算法的最大弱點:只能處理球形的簇(理論)

代碼實現:

import numpy as np
from sklearn.cluster import KMeans
from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt
cluster1 = np.random.uniform(0.5, 1.5, (2, 10))
cluster2 = np.random.uniform(3.5, 4.5, (2, 10))

X = np.hstack((cluster1, cluster2)).T

'''
參數的意義:
n_clusters:簇的個數,即你想聚成幾類
init: 初始簇中心的獲取方法
n_init: 獲取初始簇中心的更迭次數
max_iter: 最大迭代次數(因爲kmeans算法的實現需要迭代)
tol: 容忍度,即kmeans運行準則收斂的條件
precompute_distances:是否需要提前計算距離
verbose: 冗長模式(不太懂是啥意思,反正一般不去改默認值)
random_state: 隨機生成簇中心的狀態條件。
copy_x: 對是否修改數據的一個標記,如果True,即複製了就不會修改數據。
n_jobs: 並行設置
algorithm: kmeans的實現算法,有:'auto', 'full', 'elkan', 其中 'full'表示用EM方式實現
'''
K = range(1, 10)
# print(X)
meandistortions = []
for k in K:
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(X)
    meandistortions.append(sum(np.min(cdist(X,kmeans.cluster_centers_, 'euclidean'), axis=1)) / X.shape[0])
    '''
    # cdist(X, kmeans.cluster_centers_, 'euclidean')  求出X到cluster_centers_之間的距離
    #np.min(cdist(X,kmeans.cluster_centers_, 'euclidean'), axis=1)   按行的方向,對每一行求出一個最小值
    #sum(np.min(cdist(X,kmeans.cluster_centers_, 'euclidean'), axis=1)) 求出每次得到最小值列表的和
    # 求出每次最小值列表和的平均值
    '''
print(meandistortions)
plt.plot(K, meandistortions, 'bx-')
plt.xlabel('k')
# plt.ylabel('平均畸變程度',fontproperties=font)
plt.ylabel('Ave Distor')
# plt.title('用肘部法則來確定最佳的K值',fontproperties=font);
plt.title('Elbow method value K');
plt.show()


二、輪廓係數:


( Silhouette Coefficient)結合了聚類的凝聚度( Cohesion)和分離度
( Separation),用於評估聚類的效果。該值處於-1~1之間,值越大,表示聚類效果
越好。
 

a是Xi與同簇的其他樣本的平均距離,稱爲凝聚度;
b是Xi與最近簇中所有樣本的平均距離,稱爲分離度。

最近簇的定義:
 

其中p是某個簇中的樣本。即,用Xi 到某個簇所有樣本平均距離作爲衡量該點到該簇的距離後,選擇離Xi最近的一個簇作爲最近簇。
求出所有樣本的輪廓係數後再求平均值就得到了平均輪廓係數。平均輪廓係數的取值範圍爲[-1,1],且簇內樣本的距離越近,簇間樣本距離越遠,平均輪廓係數越大,聚類效果越好。
代碼實現:

import numpy as np
from sklearn.cluster import KMeans
from sklearn import metrics
import matplotlib.pyplot as plt

# 分割出6個子圖, 並在1號作圖
plt.figure(figsize=(8, 10))
plt.subplot(3, 2, 1)
# 初始化原始數字點
x1 = np.array([1, 2, 3, 1, 5, 6, 5, 5, 6, 7, 8, 9, 7, 9])
x2 = np.array([1, 3, 2, 2, 8, 6, 7, 6, 7, 1, 2, 1, 1, 3])
X = np.array(list(zip(x1, x2))).reshape(len(x1), 2)
# 在1號子圖做出原始數據點陣的分佈
# xlim 座標的刻度
plt.xlim([0, 10])
plt.ylim([0, 10])
plt.title('Sample')
plt.scatter(x1, x2)

# 點的顏色
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b']
# 點的標號
markers = ['o', 's', 'D', 'v', '^', 'p', '*', '+']
# 簇的個數
tests = [2, 3, 4, 5, 8]
subplot_counter = 1  # 訓練模型
for t in tests:
    subplot_counter += 1
    plt.subplot(3, 2, subplot_counter)
    kmeans_model = KMeans(n_clusters=t).fit(X)
    for i, l in enumerate(kmeans_model.labels_):
        plt.plot(x1[i], x2[i], color=colors[l], marker=markers[l], ls='None')
        plt.xlim([0, 10])
        plt.ylim([0, 10])
        # silhouette_score計算所有樣本的平均輪廓係數。
        # kmeans_model.labels_ 每個樣本的預測標籤。即預測的類的標籤
        # metric='euclidean' 用的方法爲歐式距離
        plt.title('K = %s, SCoefficient = %.03f' % (t, metrics.silhouette_score(X, kmeans_model.labels_, metric='euclidean')))
plt.show()


三、Canopy算法配合初始聚類


1、Canopy簡介:
Canopy聚類最大的特點是不需要事先指定k值(即clustering的個數),因此具有很大的實際應用價值。 Canopy聚類雖然精度較低,但其在速度上有很大優勢,因此可以使用Canopy聚類先對數據進行“粗”聚類, 得到k值後再使用K-means進行進一步“細”聚類。

2、Canopy + Kmeans:
a. 聚類最耗費計算的地方是計算對象相似性的時候,Canopy聚類在第一階段選擇簡單、計算代價較低的方法計算對象相似性,將相似的對象放在一個子集中,這個子集被叫做Canopy,通過系列計算得到若干Canopy,Canopy之間可以是重疊的,但不會存在某個對象不屬於任何Canopy的情況, 可以把這一階段看做數據預處理;
b . 在各個Canopy 內使用傳統的聚類方法(如K-means),不屬於同一Canopy的對象之間不進行相似性計算。 (即, 根據Canopy算法產生的Canopies代替初始的K個聚類中心點,由於已經將所有數據點進行Canopies有覆蓋劃分,在計算數據離哪個k-center最近時,不必計算其到所有k-centers的距離, 只計算和它在同一個Canopy下的k-centers這樣可以提高效率)
c、Canopy詳解:
1, 首先選擇兩個距離閾值: T1和T2, 其中T1 > T2
2, 從list中任取一點P,用低計算成本方法快速計算點P與所有Canopy之間的距離(如果當前不存在Canopy,則把點P作爲一個Canopy),如果點P與某個Canopy距離在T1以內,則將點P加入到這個Canopy
3, 如果點P曾經與某個Canopy的距離在T2以內,則需要把點P從list中刪除,這一步是認爲點P此時與這個Canopy已經夠近了, 因此它不可以再做其它Canopy的中心了
4, 重複步驟2、 3, 直到list爲空結束

è¿éåå¾çæè¿°

優點:
1、 Kmeans對噪聲抗干擾較弱,通過Canopy對比,將較小的NumPoint的Cluster直接去掉有利於抗干擾。
2、 Canopy選擇出來的每個Canopy的centerPoint作爲K會更精確。
3、 只是針對每個Canopy的內做Kmeans聚類, 減少相似計算的數量。
缺點:
算法中 T1、 T2(T2 < T1) 的確定問題

四、Calinski-Harabasz Index


Calinski-Harabasz:類別內部數據的協方差越小越好,類別之間的協方差越大越好,這樣的Calinski-Harabasz分數s會高, 分數s高則聚類效果越好

 

其中m爲訓練集樣本數, k爲類別數。 爲類別之間的協方差矩陣, 爲類別內部數據的協方差矩陣。 tr爲矩陣的跡。

1-3 算法優化


四種硬聚類算法(K-means++,二分K-means,ISODATA和Kernel K-means)

K-means++:


2007年由D. Arthur等人提出的K-means++針對圖1中的第一步做了改進。可以直觀地將這改進理解成這K個初始聚類中心相互之間應該分得越開越好。

那麼初始點怎麼選呢?
第一個簇心A隨機找,是因爲一開始你不知道哪個是簇心;
第二個簇心B要找距離A最遠的,是因爲簇心之間要相距遠一些,如果很近的話,很容易當作一類,影響聚類效果;
第三個簇心C也是同樣的,它得離A、B遠一些;
其它依次類推。

怎麼選取下一個聚類中心,整個算法的描述如下圖所示:

 K-means++算法
 K-means++算法


                   

 

下面結合一個簡單的例子說明K-means++是如何選取初始聚類中心的。數據集中共有8個樣本,分佈以及對應序號如下圖所示:

è¿éåå¾çæè¿°
K-means++示例

 

假設經過圖2的步驟一後6號點被選擇爲第一個初始聚類中心,那在進行步驟二時每個樣本的D(x)和被選擇爲第二個聚類中心的概率如下表所示:

è¿éåå¾çæè¿°


其中的P(x)就是每個樣本被選爲下一個聚類中心的概率。最後一行的Sum是概率P(x)的累加和,用於輪盤法選擇出第二個聚類中心。方法是隨機產生出一個0~1之間的隨機數,判斷它屬於哪個區間,那麼該區間對應的序號就是被選擇出來的第二個聚類中心了。例如1號點的區間爲[0,0.2),2號點的區間爲[0.2, 0.525)。
從上表可以直觀的看到第二個初始聚類中心是1號,2號,3號,4號中的一個的概率爲0.9。而這4個點正好是離第一個初始聚類中心6號點較遠的四個點。這也驗證了K-means的改進思想:即離當前已有聚類中心較遠的點有更大的概率被選爲下一個聚類中心。可以看到,該例的K值取2是比較合適的。當K值大於2時,每個樣本會有多個距離,需要取最小的那個距離作爲D(x)。

ISODATA


類別數目隨着聚類過程而變化;
對類別數的“合併”: ( 當聚類結果某一類中樣本數太少, 或兩個類間的距離太近時)(樣本太少或太散會被打散)
“分裂”( 當聚類結果中某一類的類內方差太大, 將該類進行分裂)

Kernel k-means


kernel k-means實際上公式上,就是將每個樣本進行一個投射到高維空間的處理,然後再將處理後的數據使用普通的k-means算法思想進行聚類。

二分K-means


首先將所有點作爲一個簇,然後將該簇一分爲二。之後選擇能最大限度降低聚類代價函數(也就是誤差平方和)的簇劃分爲兩個簇。 以此進行下去,直到簇的數目等於用戶給定的數目k爲止。

Mini Batch K-Means

對大數據分小批量處理
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章