Pythonによる非教師学習:K平均法(K-Means)の実装と可視化

K平均法(K-Means)の基本概念

K平均法は、教師なし学習における代表的な分割型クラスタリングアルゴリズムです。与えられたデータ集合をユーザーが指定した数(K個)のグループに分類し、各データポイントが自身に割り当てられたクラスタの重心(平均ベクトル)とユークリッド距離的に最も近くなるよう反復的に最適化を行います。この手法は「類似した特徴を共有するデータ同士を同一グループに収束させる」という性質から、市場セグメンテーション、画像データの前処理、異常値検出など多岐にわたる分野で基盤技術として活用されています。k近傍法(k-NN)とは計算原理も目的も完全に異なるため、混同しないよう注意が必要です。

scikit-learn による実装のポイント

scikit-learnのKMeansクラスを適用する際、以下の設計特性を把握しておくことが不可欠です。

  • クラスタ数の明示n_clustersパラメータでグループ数を事前に決定する必要があります。
  • 非教師学習の特性fit()メソッドには特徴量行列のみを渡します。正解ラベル(教師データ)は学習プロセスに一切関与しません。
  • ラベルの任意性:出力されるクラスタインデックス(0, 1, 2...)は数学的な順序を持たないため、正解データと比較する場合はラベルマッピングや順序不変の評価指標の導入が標準的です。

合成データでの動作確認と可視化

2次元の人工データを用いて、モデルの初期化、学習、予測、および重心の可視化までを一連のコードで実装します。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

# 2つの密な分布からなる合成特徴量
sample_features = np.array([
    [1.0, 1.0], [1.1, 1.1], [1.2, 1.2],
    [2.5, 2.5], [2.6, 2.6], [2.7, 2.7]
])
true_labels = np.array([0, 0, 0, 1, 1, 1])

# K平均モデルの定義と学習(n_initは警告抑制のため明示)
clustering_model = KMeans(n_clusters=2, random_state=42, n_init=10)
clustering_model.fit(sample_features)

# 結果の抽出
predicted_labels = clustering_model.labels_
centroids = clustering_model.cluster_centers_

# 未観測データに対するクラス归属判定
unseen_points = np.array([[1.3, 1.3], [2.8, 2.8]])
unseen_predictions = clustering_model.predict(unseen_points)

print(f"計算された重心座標:\n{centroids}")
print(f"学習データの予測ラベル: {predicted_labels}")
print(f"未観測データの予測結果: {unseen_predictions}")

# 可視化処理
plt.figure(figsize=(6, 5))
plt.scatter(sample_features[:, 0], sample_features[:, 1], 
            c=predicted_labels, cmap='tab10', s=120, edgecolor='gray')
plt.scatter(centroids[:, 0], centroids[:, 1], 
            c='crimson', marker='X', s=250, linewidths=2, label='Centroids')
plt.title('K-Means Clustering Workflow')
plt.xlabel('Dimension X')
plt.ylabel('Dimension Y')
plt.legend(loc='upper left')
plt.grid(True, linestyle=':', alpha=0.6)
plt.show()

Irisデータセットへの適用と性能評価

実データでの検証として、アヤメ(Iris)データセットを用いた3クラス分割を行います。クラスタリングではモデルが内部で割り振るインデックスと実際の生物学的分類が一致しないため、評価時にはラベルの対応付けを実施します。ここでは可視化に有用な2次元特徴量を抽出し、クラスタリング結果をプロットします。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.cluster import KMeans
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# データの取得と学習・テスト分割
dataset = datasets.load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    dataset.data, dataset.target, test_size=0.2, random_state=42
)

# 3クラスタでK平均法を適用
km_model = KMeans(n_clusters=3, random_state=42, n_init=10)
km_model.fit(X_train)
y_pred = km_model.labels_

# クラスタラベルは実行ごとにシフトするため、正解分布と一致させるマッピングを行う
# ※実務では Adjusted Rand Index (ARI) や Normalized Mutual Information (NMI) の使用を推奨
label_mapping = {0: 2, 1: 1, 2: 0}
y_pred_aligned = np.array([label_mapping[l] for l in y_pred])

accuracy = accuracy_score(y_train, y_pred_aligned)
print(f"クラスタリング精度 (Accuracy): {accuracy:.2f}")

# 特徴量1次元目と2次元目を使用した散布図描画
plt.figure(figsize=(6, 5))
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_pred, cmap='viridis', 
            alpha=0.7, edgecolor='k', s=60)
plt.scatter(km_model.cluster_centers_[:, 0], km_model.cluster_centers_[:, 1],
            c='black', s=300, marker='*', zorder=5, label='Cluster Centers')
plt.title('Iris Dataset Clustering (Sepal Length vs Width)')
plt.xlabel(dataset.feature_names[0])
plt.ylabel(dataset.feature_names[1])
plt.legend()
plt.tight_layout()
plt.show()

タグ: Python Scikit-learn 機械学習 K-Means クラスタリング

5月22日 03:48 投稿