手写数字的 K 均值聚类

Machine LearningMachine LearningBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,我们将使用 Python 中的 scikit-learn 库探索 K 均值聚类算法。我们将使用手写数字数据集,该数据集包含 64 个特征,代表一个数字的 8x8 图像,并且我们将尝试根据它们所代表的数字将图像分组在一起。我们将比较 K 均值的不同初始化方法,并使用各种指标评估聚类的性能。

虚拟机提示

虚拟机启动完成后,点击左上角切换到“笔记本”标签以访问 Jupyter Notebook 进行练习。

有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作的验证无法自动化。

如果你在学习过程中遇到问题,请随时向 Labby 提问。课程结束后提供反馈,我们将立即为你解决问题。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn(("Sklearn")) -.-> sklearn/DataPreprocessingandFeatureEngineeringGroup(["Data Preprocessing and Feature Engineering"]) sklearn(("Sklearn")) -.-> sklearn/AdvancedDataAnalysisandDimensionalityReductionGroup(["Advanced Data Analysis and Dimensionality Reduction"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn/CoreModelsandAlgorithmsGroup -.-> sklearn/cluster("Clustering") sklearn/DataPreprocessingandFeatureEngineeringGroup -.-> sklearn/preprocessing("Preprocessing and Normalization") sklearn/DataPreprocessingandFeatureEngineeringGroup -.-> sklearn/pipeline("Pipeline") sklearn/AdvancedDataAnalysisandDimensionalityReductionGroup -.-> sklearn/decomposition("Matrix Decomposition") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/cluster -.-> lab-49180{{"手写数字的 K 均值聚类"}} sklearn/preprocessing -.-> lab-49180{{"手写数字的 K 均值聚类"}} sklearn/pipeline -.-> lab-49180{{"手写数字的 K 均值聚类"}} sklearn/decomposition -.-> lab-49180{{"手写数字的 K 均值聚类"}} sklearn/datasets -.-> lab-49180{{"手写数字的 K 均值聚类"}} ml/sklearn -.-> lab-49180{{"手写数字的 K 均值聚类"}} end

加载数据集

我们将首先使用 scikit-learn 的 load_digits() 函数加载数字数据集。此函数返回数据集的特征和标签。

import numpy as np
from sklearn.datasets import load_digits

data, labels = load_digits(return_X_y=True)
(n_samples, n_features), n_digits = data.shape, np.unique(labels).size

定义评估基准

我们将定义一个基准来比较 K 均值的不同初始化方法。我们的基准将:

  • 创建一个管道,该管道将使用 StandardScaler 对数据进行缩放
  • 训练并记录管道拟合的时间
  • 通过不同指标测量所获得聚类的性能
from time import time
from sklearn import metrics
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

def bench_k_means(kmeans, name, data, labels):
    """评估KMeans初始化方法的基准。

    参数
    ----------
    kmeans : KMeans实例
        一个已设置好初始化的`KMeans`实例。
    name : str
        赋予该策略的名称。它将用于在表格中展示结果。
    data : 形状为(n_samples, n_features)的ndarray
        要聚类的数据。
    labels : 形状为(n_samples,)的ndarray
        用于计算需要一些监督的聚类指标的标签。
    """
    t0 = time()
    estimator = make_pipeline(StandardScaler(), kmeans).fit(data)
    fit_time = time() - t0
    results = [name, fit_time, estimator[-1].inertia_]

    ## 定义仅需要真实标签和估计器标签的指标
    clustering_metrics = [
        metrics.homogeneity_score,
        metrics.completeness_score,
        metrics.v_measure_score,
        metrics.adjusted_rand_score,
        metrics.adjusted_mutual_info_score,
    ]
    results += [m(labels, estimator[-1].labels_) for m in clustering_metrics]

    ## 轮廓系数需要完整的数据集
    results += [
        metrics.silhouette_score(
            data,
            estimator[-1].labels_,
            metric="euclidean",
            sample_size=300,
        )
    ]

    ## 展示结果
    formatter_result = (
        "{:9s}\t{:.3f}s\t{:.0f}\t{:.3f}\t{:.3f}\t{:.3f}\t{:.3f}\t{:.3f}\t{:.3f}"
    )
    print(formatter_result.format(*results))

运行基准测试

我们将比较三种初始化 K 均值的方法:

  • 使用 k-means++ 进行初始化。此方法是随机的,我们将运行初始化 4 次;
  • 随机初始化。此方法也是随机的,我们将运行初始化 4 次;
  • 基于主成分分析(PCA)投影的初始化。我们将使用 PCA 的成分来初始化 K 均值。此方法是确定性的,单次初始化就足够了。
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA

print(82 * "_")
print("init\t\ttime\tinertia\thomo\tcompl\tv-meas\tARI\tAMI\tsilhouette")

kmeans = KMeans(init="k-means++", n_clusters=n_digits, n_init=4, random_state=0)
bench_k_means(kmeans=kmeans, name="k-means++", data=data, labels=labels)

kmeans = KMeans(init="random", n_clusters=n_digits, n_init=4, random_state=0)
bench_k_means(kmeans=kmeans, name="random", data=data, labels=labels)

pca = PCA(n_components=n_digits).fit(data)
kmeans = KMeans(init=pca.components_, n_clusters=n_digits, n_init=1)
bench_k_means(kmeans=kmeans, name="PCA-based", data=data, labels=labels)

print(82 * "_")

在 PCA 降维后的数据上可视化结果

我们将使用主成分分析(PCA)将数据集降维到二维,并在这个新空间中绘制数据和聚类。

import matplotlib.pyplot as plt

reduced_data = PCA(n_components=2).fit_transform(data)
kmeans = KMeans(init="k-means++", n_clusters=n_digits, n_init=4)
kmeans.fit(reduced_data)

## 网格的步长。减小步长可提高量化的质量。
h = 0.02  ## 网格中的点 [x_min, x_max]x[y_min, y_max]。

## 绘制决策边界。为此,我们将为每个点分配一种颜色
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))

## 获取网格中每个点的标签。使用最后训练的模型。
Z = kmeans.predict(np.c_[xx.ravel(), yy.ravel()])

## 将结果放入彩色图中
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)
## 将质心绘制为白色 X
centroids = kmeans.cluster_centers_
plt.scatter(
    centroids[:, 0],
    centroids[:, 1],
    marker="x",
    s=169,
    linewidths=3,
    color="w",
    zorder=10,
)
plt.title(
    "K 均值聚类在数字数据集上(PCA 降维后的数据)\n"
    "质心用白色十字标记"
)
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
plt.show()

总结

在本实验中,我们探索了 K 均值聚类算法,并将其应用于手写数字数据集。我们比较了不同的初始化方法,并使用各种指标评估了聚类的性能。我们还使用主成分分析(PCA)在二维空间中可视化了结果。