機器學習(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")