1. 程式人生 > >Scikit-Learn學習筆記——k-means聚類:影象識別、色彩壓縮

Scikit-Learn學習筆記——k-means聚類:影象識別、色彩壓縮

k-means聚類

k-means是一種無監督學習模型——聚類演算法的一種演算法。k-means演算法可以在不帶標籤的多維資料集中尋找確定數量的簇。
最優的聚類結果需要符合一下兩個假設

  • “簇中心點“是屬於該簇的所有資料點座標的算術平均值
  • 一個簇的每個點到該簇中心點的距離,比到其他簇中心點的距離短。
#簡單演示k-means演算法
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns;sns.set()
import numpy as np
from sklearn.datasets.samples_generator import
make_blobs x, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0) from sklearn.cluster import KMeans kmeans = KMeans(n_clusters=4) kmeans.fit(x) y_kmeans = kmeans.predict(x) #視覺化 plt.scatter(x[:, 0], x[:, 1], c=y_kmeans, cmap='viridis') centers = kmeans.cluster_centers_ plt.scatter(centers[:, 0
], centers[:, 1], c='k', s=200, alpha=0.5)

這裡寫圖片描述

手動實現一個簡單的k-means演算法


from sklearn.metrics import pairwise_distances_argmin
def find_clusters(x, n_clusters, rseed=2):
    #1.隨機選擇簇中心點
    rng = np.random.RandomState(rseed)
    i = rng.permutation(x.shape[0])[:n_clusters]
    centers = x[i]

    while True:
        # 2a.給於最近的中心執行標籤
labels = pairwise_distances_argmin(x, centers) #2b.根據點的平均值找到新的中心 new_centers =np.array([x[labels==i].mean(0) for i in range(n_clusters)]) #2c.確認收斂 if np.all(centers == new_centers): break centers = new_centers return centers, labels center, labels = find_clusters(x, 4) plt.scatter(x[:, 0], x[:, 1], c=labels, s=50, cmap='viridis')

這裡寫圖片描述

使用核k-means演算法實現非線性聚類

#k-means演算法遇到非線性邊界時會失效
from sklearn.datasets import make_moons
x, y = make_moons(200, noise=.05, random_state=0)
labels = KMmeans(2, random_state=0).fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=labels, s=50, cmap='viridis')

這裡寫圖片描述

#通過一個核變換將資料投影到更高維空間,投影后的資料線性分離成為可能
from sklearn.cluster import SpectralClustering
model = SpectralClustering(n_clusters=2, affinity='nearest_neighbors',assign_labels='kmeans')
labels = model.fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=labels, s=50, cmap='viridis')

這裡寫圖片描述

用k-means演算法處理手寫數字

### 用k-means演算法處理手寫數字
from sklearn.datasets import load_digits
digits = load_digits()

kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits.data)
#視覺化10類中的中心點——最具有代表性的10個數字
fig, ax = plt.subplots(2, 5, figsize=(8, 3))
centers = kmeans.cluster_centers_.reshape(10, 8, 8)
for axi, center in zip(ax.flat, centers):
    axi.set(xticks=[], yticks=[])
    axi.imshow(center, interpolation='nearest', cmap=plt.cm.binary)

這裡寫圖片描述

#將每個學習到的簇標籤和真實標籤進行匹配
from scipy.stats import mode
labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

#計算分類的準確率
from sklearn.metrics import accuracy_score
accuracy_score(digits.target, labels)

#輸出結果:
0.7935447968836951
#視覺化分類的混淆矩陣
from sklearn.metrics import confusion_matrix
mat = confusion_matrix(digits.target, labels)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            yticklabels=digits.target_names, xticklabels=digits.target_names)
plt.xlabel('true label')
plt.ylabel('predicted label')

這裡寫圖片描述

使用t-分佈鄰域演算法對資料進行預處理

#使用t-分佈鄰域嵌入演算法在執行k-means之前對資料進行預處理。t-SNE是一個非線性嵌入演算法,特別擅長保留簇中的資料點
from sklearn.manifold import TSNE
#投影資料:這一步將要執行幾秒鐘
tsne = TSNE(n_components=2, init='pca', random_state=0)
digits_proj = tsne.fit_transform(digits.data)

#計算類
kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits_proj)

#排列標籤
labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

#計算分類的準確率
from sklearn.metrics import accuracy_score
accuracy_score(digits.target, labels)

#輸出結果:
0.9371174179187535

將k-means用於色彩壓縮

#將k-means用於色彩壓縮
#需要安裝pillow影象程式包
from sklearn.datasets import load_sample_image
china = load_sample_image("china.jpg")
ax = plt.axes(xticks=[], yticks=[])
ax.imshow(china)

這裡寫圖片描述

#將畫素資料轉換成三維顏色空間中的一群資料點
data = china / 255.0 #轉換為0~1區間
data = data.reshape(427*640, 3)

#在顏色空間中對這些畫素進行視覺化
def plot_pixels(data, title, colors=None, N=10000):
    if colors is None:
        colors = data
    #隨機選擇一個子集
    rng = np.random.RandomState(0)
    i = rng.permutation(data.shape[0])[:N]
    colors = colors[i]
    R, G, B = data[i].T

    fig, ax = plt.subplots(1, 2, figsize=(16, 6))
    ax[0].scatter(R, G, color=colors, marker='.')
    ax[0].set(xlabel='Red', ylabel='Blue', xlim=(0, 1), ylim=(0, 1))

    ax[1].scatter(R, G, color=colors, marker='.')
    ax[1].set(xlabel='Red', ylabel='Blue', xlim=(0, 1), ylim=(0, 1))

    fig.suptitle(title, size=20)

plot_pixels(data, title='Input color space: 16 million possible colors')

這裡寫圖片描述

#對畫素空間使用k-means聚類,將1600萬種顏色(255x255x255=16581375)縮減到16種顏色。
#因為我們處理的是非常大的資料集,所以將使用MiniBatchKMeans演算法,這種演算法速度比k-means速度快
from sklearn.cluster import  MiniBatchKMeans
kmeans = MiniBatchKMeans(16)
kmeans.fit(data)
new_colors = kmeans.cluster_centers_[kmeans.predict(data)]

plot_pixels(data, colors=new_colors, title='Reduced color space:16 colors')

這裡寫圖片描述

#用計算結果對原始畫素重新著色,即每個畫素被指定為距離其距離最近的簇中心點的顏色。
china_recolored = new_colors.reshape(china.shape)

fig, ax = plt.subplots(1, 2, figsize=(16, 6),
                       subplot_kw=dict(xticks=[], yticks=[]))
fig.subplots_adjust(wspace=0.05)
ax[0].imshow(china)
ax[0].set_title("Original Image", size=16)
ax[1].imshow(china_recolored)
ax[1].set_title('16-color Image', size=16)

這裡寫圖片描述