Hike News
Hike News

機器學習-非監督學習- K-means

Introduction

非監督學習:dataset只有特徵值,沒有目標值

  • 把具有相近特徵的數據歸為一個類別,稱為聚類(物以類聚,人以群分)
    • 聚類通常在分類之前進行,才進行分類(預測類別)
  • 主要方法:k-means
    • K:把數據劃分成多少個類別
      • 知道類別的個數則設定K值後fit
      • 不知道類別的個數時,則K為超參數

流程

前提:在知道為k個類別的情況下

  1. 隨機在數據當中抽取k個樣本當作k個類別的中心點
  2. 計算其餘的點到k個中心點的距離
    • 其餘的每一個點都會存著k個與中心點之間的距離
  3. 從中選出距離最近的一個點作為自己類別的標記,形成k個族群
  4. 分別計算這k個族群的平均值
    • 得到平均值點有可能不再數據類別中
  5. 把k個族群的平均值點 與 k個舊中心點進行比較
    • 比較結果相同:兩點重合,結束聚類
    • 比較結果不同:把這k個平均值點當作新的中心點,從第2步開始執行

sklearn中k-means API

  • 使用sklearn.cluster.KMeans

KMeans(n_cluster=8, init=’k-means++’)

  • n_clusters : 開始聚類的中心數量
    • 將全部樣本分為多少個類別

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


X = load_iris().data

def cluster():
KM = KMeans(n_clusters=3)
KM.fit(X)

# 回傳標記的結果
predict_y = KM.predict(X)
print(predict_y)

# 多少n_clusters就使用多少顏色標記
color_list = ["red","blue","green"]
point_color = [color_list[i] for i in predict_y]


fig = plt.figure(figsize=(10,10))
ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134)
ax.scatter(X[:,3],X[:,0],X[:,2],color=point_color,edgecolor="k",s=100)

# 去除scale
ax.w_xaxis.set_ticklabels([])
ax.w_yaxis.set_ticklabels([])
ax.w_zaxis.set_ticklabels([])

#設置不同軸的label
ax.set_xlabel('Petal width')
ax.set_ylabel('Sepal length')
ax.set_zlabel('Petal length')
ax.dist = 12

for name, label in [('Setosa', 0),
('Versicolour', 1),
('Virginica', 2)]:
ax.text3D(X[predict_y == label, 3].mean(),
X[predict_y == label, 0].mean(),
X[predict_y == label, 2].mean() + 2, name,
horizontalalignment='center',
bbox=dict(alpha=.2, edgecolor='w', facecolor='w'))

fig.show()

if __name__ == '__main__':
cluster()

Result

1
2
3
4
5
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 2 2 2 1 2 2 2 2
2 2 1 1 2 2 2 2 1 2 1 2 1 2 2 1 1 2 2 2 2 2 1 2 2 2 2 1 2 2 2 1 2 2 2 1 2
2 1]

result


Kmeans性能評估標準

理想聚類目的效果如下圖所示
effect of clustering

  • 族群與族群之間的距離最大
  • 族群內部各個樣本之間越相似越好

輪廓係數

使用輪廓係數作為Kmeans性能評估標準

  • 每一個樣本都有自己的輪廓係數

$$
sc_i = \frac {b_i-a_i}{max(b_i,a_i)}
$$

  • 對於每個點$i$為已聚類數據中的樣本

    • $b_i$為$i$到 其他族群的所有樣本的距離最小值
    • $a_i$為$i$到 本身簇其他點的距離之平均值
  • $sc_i$值介於$1$~$-1$之間

    • $b_i$ >> $a_i$ : 會使$sc_i$趨近於1,聚類效果最好(分離度和內聚度相對較優)
      • 通常超過0或是0.1以上聚類效果已經非常好
    • $b_i$ << $a_i$ : 會使$sc_i$趨近於-1,聚類效果不好

Kmeans性能評估指標API

使用sklearn.metrics.silhouette_score

silhouette_score(X, labels)

計算所有樣本的平均輪廓係數

  • X:特徵值
  • labels: 被聚類標記的目標值

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
from sklearn.metrics import silhouette_score

X = load_iris().data

def cluster():
KM = KMeans(n_clusters=3)
KM.fit(X)

# 回傳標記的結果
predict_y = KM.predict(X)
print(predict_y)

# 輪廓係數計算
score = silhouette_score(X,predict_y)
print("score = ",score)

if __name__ == '__main__':
cluster()

Result

1
2
3
4
5
6
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 2 2 2 1 2 2 2 2
2 2 1 1 2 2 2 2 1 2 1 2 1 2 2 1 1 2 2 2 2 2 1 2 2 2 2 1 2 2 2 1 2 2 2 1 2
2 1]
score = 0.5525919445213676

tips

在不知道類別數目(n_clusters)的情況下,
可使用silhouette_score評估,並把n_clusters作為超參數,
進行多次驗證查看哪個輪廓係數最高


總結

特點分析

採用迭代算法,直觀易懂並且非常實用

缺點

容易收斂到局部最優解,需多次隨機聚類找出最優解(API以內建)