Scikit-Learn學習筆記——k-means聚類:影象識別、色彩壓縮
阿新 • • 發佈:2019-02-20
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)