(Scikit-Learn)K-means聚类算法详解 图片色彩压缩

k-means 算法:
在不带标签的多维数据集中寻找确定数量的簇。最优的聚类结果需要符合以 下两个假设。
• “簇中心点”(cluster center)是属于该簇的所有数据点坐标的算术平均值。
• 一个簇的每个点到该簇中心点的距离,比到其他簇中心点的距离短。

%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_true = make_blobs(n_samples=300, centers=4, cluster_std=0.6, random_state=0)
plt.scatter(X[:,0], X[:,1], s=50)

在这里插入图片描述

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, s=50, cmap='viridis')
centers = kmeans.cluster_centers_
plt.scatter(centers[:,0], centers[:,1], c='red', s=200, alpha=0.5)

在这里插入图片描述
k-means算法: 期望最大化
(1) 猜测一些簇中心点。
(2) 重复直至收敛。
a. 期望步骤(E-step):将点分配至离其最近的簇中心点。
b. 最大化步骤(M-step):将簇中心点设置为所有点坐标的平均值。

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
centers, labels = find_clusters(X, 4)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');

在这里插入图片描述

使用期望最大化算法时的注意事项
(1)可能不会达到全局最优结果:
最终的聚类结果,非常依赖于初始化时的选定的初试聚类中心。(优化:KMeans++算法)

(2)簇数量必须事先定好:
它无法从数据中自动学习到簇的数量,簇数量必须认为预先给定

(3)k-means 算法只能确定线性聚类边界:
k-means 的基本模型假设(与其他簇的点相比,数据点更接近自己的簇中心点)表明, 当簇中心点呈现非线性的复杂形状时,该算法通常不起作用。

from sklearn.datasets import make_moons
X, y = make_moons(200, noise=.05, random_state=0)
labels = KMeans(2, random_state=0).fit_predict(X)
plt.scatter(X[:,0], X[:,1], c=labels, s=50, cmap='viridis')

在这里插入图片描述
这个情形让人想起线性回归中的处理,当时我们通过一个核变换将数据投影到更高维的 空间,投影后的数据使线性分离成为可能。或许可以使用同样的技巧解决 k-means 算法 无法处理非线性边界的问题。

这种核 k-means 算法在 Scikit-Learn 的 SpectralClustering 评估器中实现,它使用最近 邻图(the graph of nearest neighbors)来计算数据的高维表示,然后用 k-means 算法分配 标签

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')

在这里插入图片描述
(4)当数据量较大时, k-means 会很慢:
由于 k-means 的每次迭代都必须获取数据集所有的点,因此随着数据量的增加,算法 会变得缓慢。你可能会想到将“每次迭代都必须使用所有数据点”这个条件放宽,例 如每一步仅使用数据集的一个子集来更新簇中心点。这恰恰就是批处理(batch-based) k-means 算法的核心思想,该算法在 sklearn.cluster.MiniBatchKMeans 中实现。

案例: 将k-means用于色彩压缩
聚类算法的一个有趣应用是图像色彩压缩。设想你有一幅包含几百万种颜色的图像,但 其实大多数图像中的很大一部分色彩通常是不会被眼睛注意到的,而且图像中的很多像素 都拥有类似或者相同的颜色。

from sklearn.datasets import load_sample_image
china = load_sample_image("china.jpg")
ax = plt.axes(xticks=[], yticks=[])
ax.imshow(china)

在这里插入图片描述
该图像存储在一个三维数组 (height, width, RGB) 中,以 0~255 的整数表示红 / 蓝 / 绿信息:

china.shape

在这里插入图片描述
图片像素颜色由R,G,B三个数值组成。所以我们可以将一张图片看成三维(RGB)空间汇总的一群数据点。

先将数据变形为 [n_samples × n_features],然后缩放颜色至其取值为 0-1:

data = china / 255.0
data = data.reshape(427 * 640, 3)
data.shape

在这里插入图片描述
在颜色空间中对前 10 000 个像素的子集进行可视化。

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='Green', xlim=(0,1), ylim=(0,1))
    
    ax[1].scatter(R, B, 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 万种颜色(255 × 255 × 255 = 16 581 375)缩减到 16 种颜色。因为我们处理的是一个非常大的数据集,所以将使用 MiniBatchKMeans 算法对数据集的子集进行计算。这种算法比标准的 k-means 算法速度更快

from sklearn.cluster import MiniBatchKMeans
kmeans = MiniBatchKMeans(16)
kmeans.fit(data)
#每个像素,新的颜色为new_colors
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)

在这里插入图片描述

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值