手書き数字の K - Means クラスタリング

Beginner

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

はじめに

この実験では、Python の scikit - learn ライブラリを使って K - Means クラスタリングアルゴリズムを探索します。手書き数字のデータセットを使います。このデータセットには、数字の 8x8 画像を表す 64 個の特徴が含まれており、表される数字に基づいて画像をグループ化しようとします。K - Means の異なる初期化方法を比較し、様々な指標を使ってクラスタリングの性能を評価します。

VM のヒント

VM の起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebook を使って練習しましょう。

時々、Jupyter Notebook が読み込み終わるまで数秒待つ必要がある場合があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。

学習中に問題に直面した場合は、Labby に質問してください。セッション後にフィードバックを提供してください。すぐに問題を解決いたします。

データセットの読み込み

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 - Means の異なる初期化方法を比較するための基準を定義します。私たちの基準は、以下のことを行います。

  • 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 - Means を初期化するための 3 つのアプローチを比較します。

  • k - means++を使った初期化。この方法は確率的で、初期化を 4 回実行します。
  • ランダムな初期化。この方法も確率的で、初期化を 4 回実行します。
  • PCA 射影に基づく初期化。PCA のコンポーネントを使って K - Means を初期化します。この方法は決定論的で、1 回の初期化で十分です。
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 を使ってデータセットを 2 次元に削減し、この新しい空間でデータとクラスタをプロットします。

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)

## メッシュのステップサイズ。VQ の品質を向上させるには、この値を小さくする。
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-means クラスタリング on the digits dataset (PCA により次元削減したデータ)\n"
    "重心は白い十字でマークされています"
)
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
plt.show()

まとめ

この実験では、K - Means クラスタリングアルゴリズムを調べ、手書き数字のデータセットに適用しました。異なる初期化方法を比較し、様々な指標を使ってクラスタリングの性能を評価しました。また、PCA を使って 2 次元空間で結果を可視化しました。