1. 程式人生 > >機器學習(1):K-MEANS聚類演算法

機器學習(1):K-MEANS聚類演算法

一、聚類簡介

1.無監督問題:我們手裡沒有標籤了
2.聚類:相似的東西分到一組
3.難點:如何評估,如何調參

二、基本概念:

1.K:要得到簇的個數,需要指定K
2.質心:均值,即向量各維取平均
3.距離的度量:常用歐幾里得距離和餘弦相似度(先標準化)
4.優化目標


(1)Ci代表第i個簇的中心
(2)x是屬於Ci的點
(3)dist:為distance距離,即歐幾里得距離
(4)目標為:每一個點到該簇的距離之和,以及各個簇中心之和,為最小值!
5.注意:
(1)標準化
比如X軸0.01,0.02,0.03偏差比較小;Y軸,105,161偏差比較大。為了消除值本身大小的影響,所以需要將X/Y的範圍都歸類到[0,1]或者[-1,1]。
(2)一般用歐幾里得距離

 

三、工作流程

1.初始化:假設K=3,即三個初始化點,C1,C2,C3。初始化三個點。


2.分類:然後,依據其他點與三個核心點距離來分類。


3.更新質心C1,C2,C3:依據2中的分類,求取每個分類的質心,作為新的C1',C2',C3。


4.迴圈2到3
5.結束:當C1,C2,C3和C1',C2',C3'偏差滿足要求停止。即,滿足優化目標為止!

四、優勢和劣勢

1.優勢
簡單,快速,適合常規資料集
2.劣勢
(1)K值難確定
(2)複雜度與樣本呈線性關係
(3)很難發現任意形狀的簇

五、聚類視覺化

視覺化網址過程【老外的網址,不錯!】
(1)k-means
https://www.naftaliharris.com/blog/visualizing-k-means-clustering/
(2)dbscan
https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/

六、例項

針對資料data.txt

	name	calories	sodium	alcohol	cost
0	Budweiser	144	15	4.7	0.43
1	Schlitz	151	19	4.9	0.43
2	Lowenbrau	157	15	0.9	0.48
3	Kronenbourg	170	7	5.2	0.73
4	Heineken	152	11	5.0	0.77
5	Old_Milwaukee	145	23	4.6	0.28
6	Augsberger	175	24	5.5	0.40

1.python程式碼實現

1.獲取資料
# beer dataset
import pandas as pd
beer = pd.read_csv('data.txt', sep=' ')
beer
2.抽取資料X
X = beer[["calories","sodium","alcohol","cost"]]
print(X)
3.K-means clustering建立例項
from sklearn.cluster import KMeans

km = KMeans(n_clusters=3).fit(X)
km2 = KMeans(n_clusters=2).fit(X)

4.結果:獲取分類結果
km.labels_

5.載入到原始資料
beer['cluster'] = km.labels_
beer['cluster2'] = km2.labels_
beer.sort_values('cluster')

2.繪圖驗證

(1)求每一類中心點:聚合函式groupby

1.獲取中心值
from pandas.tools.plotting import scatter_matrix
%matplotlib inline

cluster_centers = km.cluster_centers_

cluster_centers_2 = km2.cluster_centers_
2.groupby:求取三個類簇的聚類中心點值
(1)
beer.groupby("cluster").mean()
(2)
beer.groupby("cluster2").mean()
結果:
	calories	sodium	alcohol	cost	cluster
cluster2					
0	91.833333	10.166667	3.583333	0.433333	1.333333
1	150.000000	17.000000	4.521429	0.520714	0.000000

3.重新排序
centers = beer.groupby("cluster").mean().reset_index() #按照對應分組類別
結果:
centers為
   cluster  calories  sodium   alcohol      cost  cluster  cluster2
0        0     70.00    10.5  2.600000  0.420000         1         1
1        1    150.00    17.0  4.521429  0.520714         0         0
2        2    102.75    10.0  4.075000  0.440000         1         2

(2)繪圖驗證

 繪製兩個特徵的圖以及中心點

%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams['font.size'] = 14

import numpy as np
colors = np.array(['red', 'green', 'blue', 'yellow'])

---------
plt.scatter(beer["calories"], beer["alcohol"],c=colors[beer["cluster"]])

plt.scatter(centers.calories, centers.alcohol, linewidths=3, marker='+', s=300, c='black')

plt.xlabel("Calories")
plt.ylabel("Alcohol")

結果:

(3)兩兩特徵分析

(a)三個簇

scatter_matrix(beer[["calories","sodium","alcohol","cost"]],s=100, alpha=1, c=colors[beer["cluster"]], figsize=(10,10))
plt.suptitle("With 3 centroids initialized")

(2)兩個簇

scatter_matrix(beer[["calories","sodium","alcohol","cost"]],s=100, alpha=1, c=colors[beer["cluster2"]], figsize=(10,10))
plt.suptitle("With 2 centroids initialized")

結果:

 

七、歸一化改進Scaled data

1.歸一化
四個特徵值基本都在[-2,2]之間,消除差異

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_scaled

2.KMeans擬合

km = KMeans(n_clusters=3).fit(X_scaled)

3.結果新增到原始資料上

beer["scaled_cluster"] = km.labels_
beer.sort_values("scaled_cluster")

4.求取每個簇的中心點

beer.groupby("scaled_cluster").mean()

5.繪製兩兩特徵的關係

pd.scatter_matrix(X, c=colors[beer.scaled_cluster], alpha=1, figsize=(10,10), s=100)

6.優劣勢

(1)優勢:使每個特徵的權重相似,不至於忽略較小,但是比較重要的特徵。

(2)劣勢:可能有的特徵比較大,而且非常重要。這樣會抹殺掉該特徵的重要性。

八、聚類評估:輪廓係數(Silhouette Coefficient )

1.公式

(1)單點的輪廓係數

(2)將所有點的輪廓係數求平均,就是該聚類結果總的輪廓係數

2.概念:

(1)ai:計算樣本i到同簇其他樣本的平均距離ai。ai 越小,說明樣本i越應該被聚類到該簇。將ai 稱為樣本i的簇內不相似度。
(2)bi:計算樣本i到其他某簇Cj 的所有樣本的平均距離bij,稱為樣本i與簇Cj 的不相似度。定義為樣本i的簇間不相似度:bi =min{bi1, bi2, ..., bik}
(3)結果:輪廓係數si
si接近1,則說明樣本i聚類合理
si接近-1,則說明樣本i更應該分類到另外的簇
若si 近似為0,則說明樣本i在兩個簇的邊界上。

(4)將所有點的輪廓係數求平均,就是該聚類結果總的輪廓係數!

3.程式碼實現

from sklearn import metrics
score = metrics.silhouette_score(X,beer.cluster) #歸一化前的結果
score_scaled = metrics.silhouette_score(X,beer.scaled_cluster) #歸一化後的結果
print(score_scaled, score)

結果:
0.673177504646 0.179780680894 

解釋:
歸一化後反而變差,因為,可能會消除部分重要的特徵的值。

4.選擇k值可以,迴圈看輪廓係數得分,選擇輪廓係數偏高的值

scores = []
for k in range(2,20):
    labels = KMeans(n_clusters=k).fit(X).labels_
    score = metrics.silhouette_score(X, labels)
    scores.append(score)

scores

5.繪圖

plt.plot(list(range(2,20)), scores)
plt.xlabel("Number of Clusters Initialized")
plt.ylabel("Sihouette Score")

結果:
[0.6917656034079486,
 0.6731775046455796,
 0.5857040721127795,
 0.4355716067265817,
 0.4559182167013378,
 0.43776116697963136,
 0.38946337473126,
 0.39746405172426014,
 0.4081599013899603,
 0.41282646329875183,
 0.3459775237127248,
 0.31221439248428434,
 0.30707782144770296,
 0.2736836031737978,
 0.2849514001174898,
 0.23498077333071996,
 0.1588091017496281,
 0.08423051380151177]

6.繪圖

plt.plot(list(range(2,20)), scores)
plt.xlabel("Number of Clusters Initialized")
plt.ylabel("Sihouette Score")