Scikit-learn機器學習實戰之Kmeans

摘要
上篇博客談到了如何安裝Python中強大的機器學習庫scikit-learnWindos環境安裝scikit-learn函數庫流程,本篇主要是對其Kmeans示例進行學習。
有關Kmeans的介紹可以參見這篇博客: K均值聚類算法及Matlab函數使用

Kmeans算法的缺陷

  • 聚類中心的個數K 需要事先給定,但在實際中這個 K 值的選定是非常難以估計的,很多時候,事先並不知道給定的數據集應該分成多少個類別才最合適
  • Kmeans需要人爲地確定初始聚類中心,不同的初始聚類中心可能導致完全不同的聚類結果。

(1)第一種缺陷通常人爲解決,例如假設有K=10(根據先驗知識,儘量大些),進行第一次聚類,如果結果顯示某一類中的樣本過少,則K=K-1,重新進行聚類。
(2)第二種缺陷如下圖所示,隨機初始化的聚類中心在更新過程中可能陷入局部極小值,造成聚類效果不佳,常用的方法是多次初始化聚類中心,找到使得代價函數最小的初始化中心。

從上圖可以看出,如果初始聚類中心間的距離儘可能遠的話,聚類的效果可能會更好,因此初始化時應使得聚類中心距離儘可能遠(即Kmeans++算法)

Scikit-learn示例
該例爲手寫識別(數字0~9)數據(8*8圖像)的聚類,主要是對Kmeans、kmeans++、以及(Pca+Kmean)做了算法性能比較,並且使用了Pca進行數據可視化。
(1)數據樣本
from sklearn.datasets import load_digits
digits = load_digits()
print(digits.data.shape)
(1797, 64)   #1797個數據,每個數據64維
import matplotlib.pyplot as plt 
plt.gray() 
plt.matshow(digits.images[0]) 
plt.show()  
           

(2)算法性能比較
from time import time
import numpy as np
import matplotlib.pyplot as plt

from sklearn import metrics
from sklearn.cluster import KMeans
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.preprocessing import scale

np.random.seed(42) #隨機種子,用於初始化聚類中心

digits = load_digits() #載入數據 
data = scale(digits.data) #中心標準化數據

n_samples, n_features = data.shape #1797,64
n_digits = len(np.unique(digits.target)) #10
labels = digits.target #數據真實標籤

sample_size = 300

print("n_digits: %d, \t n_samples %d, \t n_features %d"
      % (n_digits, n_samples, n_features))


print(79 * '_')
print('% 9s' % 'init'
      '    time  inertia    homo   compl  v-meas     ARI AMI  silhouette')

#算法評估函數,包括處理時間、最終代價函數值、以及不同的聚類評價指標
def bench_k_means(estimator, name, data):
    t0 = time()
    estimator.fit(data)
    print('% 9s   %.2fs    %i   %.3f   %.3f   %.3f   %.3f   %.3f    %.3f'
          % (name, (time() - t0), estimator.inertia_,
             metrics.homogeneity_score(labels, estimator.labels_),
             metrics.completeness_score(labels, estimator.labels_),
             metrics.v_measure_score(labels, estimator.labels_),
             metrics.adjusted_rand_score(labels, estimator.labels_),
             metrics.adjusted_mutual_info_score(labels,  estimator.labels_),
             metrics.silhouette_score(data, estimator.labels_,
                                      metric='euclidean',
                                      sample_size=sample_size)))

#Kmeans++,隨機初始化10次
bench_k_means(KMeans(init='k-means++', n_clusters=n_digits, n_init=10),
              name="k-means++", data=data)

#Kmeans,隨機初始化10次
bench_k_means(KMeans(init='random', n_clusters=n_digits, n_init=10),
              name="random", data=data)

#Pca+kmeans,採用如下調用方式聚類中心是確定的,因此只初始化一次
pca = PCA(n_components=n_digits).fit(data) #fit函數表示擬合數據
bench_k_means(KMeans(init=pca.components_, n_clusters=n_digits, n_init=1),
              name="PCA-based",
              data=data)
print(79 * '_')
處理結果:
性能上:Kmeans++>random Kmeans>Pca Kmeans,但差別不大。
時間上:Pca Kmeans處理時間遠快於另兩種算法。並且降維度越低,處理速度越快,但代價函數會逐漸上升,因此尋找一個合適的處理的維度是關鍵。
PS:這些函數的介紹在Scikit-learn官網都有介紹;PCA函數也可以參看這篇博客:Scikit-learn中PCA的用法

(3)可視化聚類結果
在(2)中,是將數據從64降維10,再進行Kmeans聚類;在(3)中,爲方便可視化,將數據降到2維,進行聚類,可視化。
reduced_data =PCA(n_components=2).fit_transform(data)
#fit_transform得到是用降維度處理後的數據
kmeans = KMeans(init='k-means++', n_clusters=n_digits, n_init=10)
kmeans.fit(reduced_data)
#fit表示用括號數據“訓練”模型,返回一個kmeans對象

#定義網格步長
# Step size of the mesh. Decrease to increase the quality of the VQ.
h = .02     # point in the mesh [x_min, x_max]x[y_min, y_max].

#定義邊界座標,定義網格座標
# Plot the decision boundary. For that, we will assign a color to each
x_min, x_max = reduced_data[:, 0].min() - 1, reduced_data[:, 0].max() + 1
y_min, y_max = reduced_data[:, 1].min() - 1, reduced_data[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))

#用訓練模型獲得網格預測每一點的類值
# Obtain labels for each point in mesh. Use last trained model.
Z = kmeans.predict(np.c_[xx.ravel(), yy.ravel()])

#繪製函數
# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.figure(1)
plt.clf()
plt.imshow(Z, interpolation='nearest',
           extent=(xx.min(), xx.max(), yy.min(), yy.max()),
           cmap=plt.cm.Paired,
           aspect='auto', origin='lower')

plt.plot(reduced_data[:, 0], reduced_data[:, 1], 'k.', markersize=2)
# Plot the centroids as a white X
centroids = kmeans.cluster_centers_
plt.scatter(centroids[:, 0], centroids[:, 1],
            marker='x', s=169, linewidths=3,
            color='w', zorder=10)
plt.title('K-means clustering on the digits dataset (PCA-reduced data)\n'
          'Centroids are marked with white cross')
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
繪製結果:

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