數據分析|透徹地聊聊k-means聚類的原理和應用

  • 2020 年 2 月 19 日
  • 筆記

K-Means 是一種非監督學習,解決的是聚類問題。K 代表的是 K 類,Means 代表的是中心,你可以理解這個演算法的本質是確定 K 類的中心點。當你找到了中心點,也就完成了聚類!

可以從以下三個角度來梳理k-means:

如何確定 K 類的中心點? 如何將其他點劃分到k類中? 如何區分k-means與k-近鄰演算法?

為了對k-means有個感性的認識,我們從熟悉的場景亞洲足球隊的水平開始談起:

熟悉足球的朋友可能心理已經有了預期?你可能會說,」伊朗,韓國「一流水平,中國」二流水平「,越南」三流水平「。這樣的猜測是基於我們的經驗。

那麼,伊朗,中國,越南就是三個等級的代表—中心。

那麼如何確定k類的中心了?一開始我們是隨機指認的,當確定了中心點後,我們就可以按照距離將其它足球隊劃分到不同的類別中。

在這裡我們默認k=3,在工業界k的選擇是個難事!但我們可以通過其它方式來確定k,後文會講到。

從上面的描述中,我們可以抽象出聚類方法的步驟:

1. 隨機從數據集中選擇k個點作為我們聚類的中心點; 2. 講每個點分配到離它最近的類中心點,就形成了k類。然後重新計算每個類的中心點(比如取各類的均值作為新的中心點) 3. 重複第2步,直到類不再發生變化,或者設置最大迭代次數,讓演算法收斂。

下面舉例說明,上述過程:

其中 2019 年國際足聯的世界排名,2015 年亞洲杯排名均為實際排名,2018年,很多球隊沒有入圍決賽,進入決賽圈的有自己的排名,沒有進入決賽圈我們按照以下原則來給其一個排名:

如果是亞洲區域入選賽12強的隊伍,設置為40名 如果沒有進入亞洲區域預選賽,設置為50名

數據太過於分散,量級相差過大,通過特徵工程中的最大最小歸一化來對數據進行處理(也可以是z-評分歸一化),得到如下的數據:

#最大最小歸一化處理  # coding:utf-8  from sklearn import preprocessing  import numpy as np  # 初始化數據,每一行表示一個樣本,每一列表示一個特徵  x = np.array([[ 0., -3.,  1.],                [ 3.,  1.,  2.],                [ 0.,  1., -1.]])  # 將數據進行 [0,1] 規範化  min_max_scaler = preprocessing.MinMaxScaler()  minmax_x = min_max_scaler.fit_transform(x)  print minmax_x    #z-評分歸一化處理  from sklearn import preprocessing  import numpy as np  # 初始化數據  x = np.array([[ 0., -3.,  1.],                [ 3.,  1.,  2.],                [ 0.,  1., -1.]])  # 將數據進行 Z-Score 規範化  scaled_x = preprocessing.scale(x)

接下來,開始計算各個足球隊舉例k類中心點的距離,距離的距離方式有很多,這裡我們選擇歐式距離。

那麼你是如何計算中國與日本的距離? 採用歐式距離,默認19年,18年,15年的數據權重是一樣的,比如中國與日本的距離:

根據初始隨機選擇的k類中心點:中國,韓國,日本,我們計算各俱樂部與三類中心點的距離,各俱樂部就近選擇中心點(就有了劃分這一列)。劃分這一列是我們迭代一次後的聚類結果,顯然不是最優。

那麼如何更新中心點了?

選擇同一類別下各個俱樂部三個指標下各自的平均值作為新的聚類中心(聚類中心是三個特徵值哦)。

為什麼會使用均值作為中心點的選擇呢?這主要是由於我們目標函數的設置有關。我們使用誤差平方和作為聚類的目標函數,就要求我們最終選擇均值為聚類中心點迭代的原則。

這樣不端迭代,直到達到迭代次數或是類別不再發生變化,結束。

最終的聚類結果,如下圖:

如何使用 sklearn 中的 K-Means 演算法

# coding: utf-8  from sklearn.cluster import KMeans  from sklearn import preprocessing  import pandas as pd  import numpy as np  # 輸入數據  #np.random.seed(1234) #不加隨機數種子,每次聚類結果都不一樣  data = pd.read_csv('data.csv', encoding='gbk')  train_x = data[["2019 年國際排名 ","2018 世界盃 ","2015 亞洲杯 "]]  df = pd.DataFrame(train_x)  kmeans = KMeans(n_clusters=3)  # 規範化到 [0,1] 空間  min_max_scaler=preprocessing.MinMaxScaler()  train_x=min_max_scaler.fit_transform(train_x)  # kmeans 演算法  kmeans.fit(train_x)  predict_y = kmeans.predict(train_x)  # 合併聚類結果,插入到原數據中  result = pd.concat((data,pd.DataFrame(predict_y)),axis=1)  result.rename({0:u'聚類'},axis=1,inplace=True)  print(result)      國家  2019年國際排名  2018世界盃  2015亞洲杯  聚類  0     中國       73     40       7   2  1     日本       60     15       5   0  2     韓國       61     19       2   0  3     伊朗       34     18       6   0  4     沙特       67     26       10   0  5    伊拉克      91     40       4   2  6    卡達      101    40       13   1  7    阿聯酋      81     40       6   2  8  烏茲別克   88     40       8   2  9     泰國      122     40       17   1  10    越南      102     50       17   1  11    阿曼      87      50       12   1  12    巴林      116     50       11   1  13    朝鮮      110     50       14   1  14    印尼      164     50       17   1  15    澳洲      40      30       1   0  16   敘利亞     76      40       17   1  17    約旦      118     50       9   1  18   科威特     160      50      15   1  19  巴勒斯坦     96      50      16   1

因為初始中心點是隨機選擇的,所以每次的聚類結果都不一樣,這就要求我們加上隨機數種子!加入隨機數種子只是保證我們的結果穩定不變,並不代表當前的聚類結果就是最好的。也就是說,聚類結果依賴於初始中心點的選擇!

參數設置:

當然 K-Means 只是 sklearn.cluster 一共提供了 9 種聚類方法,比如 Mean-shift,DBSCAN,Spectral clustering(譜聚類)等

KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1, algorithm='auto')

總結:

如何區分k-means與knn:

k-means是聚類演算法,knn是有監督的分類演算法;聚類沒有標籤,分類有標籤

聚類演算法中的k是k類,knn中的k是k個最近的鄰居。

k-means優點:

計算簡單,可解釋性強。

k-means缺點:

需要確定分類數

,一般根據經驗或者已經有預判,其次是根據R語言提供的暴力試錯k值選擇最合適的分類數k。

初始值的選取會影響最終聚類效果,並且目標函數

可能會達到局部最優解。這個有相應的改進方法,包括k-means++和二分k-means。

演算法本身的局限性:對於類似下面圓形的數據集,聚類效果很差,主要是演算法原因。所以還有其他的聚類演算法,比如基於密度的方法等。

不適合發現非凸形狀的簇或者大小差別較大的簇;

對雜訊和異常點比較敏感

End.

作者:求知鳥

來源:知乎