Skip to content

付録B. 教師なし学習

本付録では、ラベルなしデータから構造やパターンを発見する 教師なし学習 について学びます。クラスタリングと次元削減という 2 つの代表的な手法を扱います。

B.1 教師なし学習とは

B.1.1 教師あり学習との違い

教師なし学習(Unsupervised Learning) は、正解ラベルのないデータからパターンや構造を見つける手法です。

graph TB
    A[機械学習] --> B[教師あり学習]
    A --> C[教師なし学習]

    B --> B1[正解ラベルあり<br/>分類・回帰]
    C --> C1[正解ラベルなし<br/>クラスタリング・次元削減]

    style A fill:#e6ccff
    style B fill:#ccffcc
    style C fill:#ffffcc
項目 教師あり学習 教師なし学習
正解ラベル あり なし
目的 予測 構造の発見
代表的手法 分類、回帰 クラスタリング、次元削減
応用例 スパム判定、価格予測 顧客セグメント、異常検知

B.1.2 教師なし学習の応用例

  • 顧客セグメンテーション: 購買行動が似た顧客をグループ化
  • 異常検知: 通常と異なるパターンを検出
  • 次元削減: データの可視化、特徴量圧縮
  • トピックモデリング: 文書のテーマを自動分類

B.2 クラスタリングとは

B.2.1 クラスタリングの概念

クラスタリング(Clustering) は、データを類似したグループ(クラスタ)に分割する手法です。

graph LR
    A[データ] --> B[クラスタリング]
    B --> C[クラスタ 1]
    B --> D[クラスタ 2]
    B --> E[クラスタ 3]

    style A fill:#e6ccff
    style B fill:#ffffcc
    style C fill:#ccffcc
    style D fill:#ffcccc
    style E fill:#e6f3ff

クラスタリングの特徴

  • 正解ラベルが不要
  • データの構造を探索的に発見
  • クラスタ数は事前に決める必要がある場合が多い

B.3 k-means

B.3.1 k-means とは

k-means は、最も基本的なクラスタリング手法です。データを k 個のクラスタに分割します。

B.3.2 k-means の仕組み

graph TB
    A[1. 初期中心点をランダムに配置] --> B[2. 各点を最も近い中心点に割り当て]
    B --> C[3. 各クラスタの中心点を再計算]
    C --> D{中心点が変化した?}
    D -->|Yes| B
    D -->|No| E[完了]

    style A fill:#e6ccff
    style B fill:#ccffcc
    style C fill:#ffffcc
    style D fill:#ffcccc
    style E fill:#e6f3ff

アルゴリズムの手順

  1. k 個の初期中心点(セントロイド)をランダムに配置
  2. 各データ点を最も近い中心点のクラスタに割り当て
  3. 各クラスタの中心点を再計算(平均位置)
  4. 中心点が変化しなくなるまで 2-3 を繰り返す

B.3.3 k-means の実装

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

# サンプルデータの生成
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.6, random_state=42)

# k-means クラスタリング
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
y_pred = kmeans.fit_predict(X)

# 可視化
plt.figure(figsize=(10, 4))

# クラスタリング前
plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], s=50, alpha=0.6)
plt.title('クラスタリング前')

# クラスタリング後
plt.subplot(1, 2, 2)
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='viridis', s=50, alpha=0.6)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
            c='red', marker='x', s=200, linewidths=3, label='中心点')
plt.title('クラスタリング後')
plt.legend()

plt.tight_layout()
plt.show()

B.3.4 最適なクラスタ数の決定

クラスタ数 k をどう決めるかは重要な問題です。エルボー法 がよく使われます。

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

# 異なる k での慣性(inertia)を計算
inertias = []
k_range = range(1, 11)

for k in k_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    kmeans.fit(X)
    inertias.append(kmeans.inertia_)

# エルボー法の可視化
plt.figure(figsize=(8, 5))
plt.plot(k_range, inertias, 'bo-')
plt.xlabel('クラスタ数 k')
plt.ylabel('慣性(Inertia)')
plt.title('エルボー法')
plt.grid(alpha=0.3)
plt.show()

エルボー法

慣性(各点から中心点までの距離の二乗和)を k ごとにプロットし、グラフが「肘」のように曲がる点を最適な k とします。

B.4 階層的クラスタリング

B.4.1 階層的クラスタリングとは

階層的クラスタリング(Hierarchical Clustering) は、データをツリー構造(デンドログラム)で表現するクラスタリング手法です。

graph TB
    A[全データ] --> B[クラスタ A]
    A --> C[クラスタ B]
    B --> D[サブクラスタ A1]
    B --> E[サブクラスタ A2]
    C --> F[サブクラスタ B1]
    C --> G[サブクラスタ B2]

    style A fill:#e6ccff
    style B fill:#ccffcc
    style C fill:#ffffcc

特徴

  • 事前にクラスタ数を決める必要がない
  • デンドログラムでクラスタの関係を可視化できる
  • 計算コストが高い(大規模データには不向き)

B.4.2 階層的クラスタリングの実装

from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.cluster import AgglomerativeClustering
import matplotlib.pyplot as plt

# デンドログラムの作成
linkage_matrix = linkage(X, method='ward')

plt.figure(figsize=(12, 5))
dendrogram(linkage_matrix)
plt.title('デンドログラム')
plt.xlabel('サンプルインデックス')
plt.ylabel('距離')
plt.show()

# クラスタリングの実行
clustering = AgglomerativeClustering(n_clusters=4)
y_pred = clustering.fit_predict(X)

B.5 シルエット分析

B.5.1 シルエット係数とは

シルエット係数 は、クラスタリングの品質を評価する指標です。

\[ s(i) = \frac{b(i) - a(i)}{\max(a(i), b(i))} \]
  • \(a(i)\): 同じクラスタ内の他の点との平均距離
  • \(b(i)\): 最も近い他のクラスタの点との平均距離

シルエット係数の解釈

  • 1 に近い: 適切なクラスタに割り当てられている
  • 0 に近い: クラスタの境界にある
  • 負の値: 誤ったクラスタに割り当てられている可能性

B.5.2 シルエット分析の実装

from sklearn.metrics import silhouette_score, silhouette_samples
import matplotlib.pyplot as plt
import numpy as np

# 異なる k でシルエットスコアを計算
silhouette_scores = []
k_range = range(2, 11)

for k in k_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    y_pred = kmeans.fit_predict(X)
    score = silhouette_score(X, y_pred)
    silhouette_scores.append(score)
    print(f"k={k}: シルエットスコア = {score:.4f}")

# 可視化
plt.figure(figsize=(8, 5))
plt.plot(k_range, silhouette_scores, 'bo-')
plt.xlabel('クラスタ数 k')
plt.ylabel('シルエットスコア')
plt.title('シルエット分析')
plt.grid(alpha=0.3)
plt.show()

シルエット分析の活用

シルエットスコアが最も高い k が最適なクラスタ数の候補となります。エルボー法と併用することで、より信頼性の高い判断ができます。

B.6 次元削減(PCA)

B.6.1 次元削減とは

次元削減(Dimensionality Reduction) は、データの特徴量を減らしながら重要な情報を保持する手法です。

次元削減の目的

  • 可視化: 高次元データを2〜3次元に投影して可視化
  • 計算効率: 特徴量を減らして計算コストを削減
  • ノイズ除去: 不要な次元を削除してモデルの性能向上

B.6.2 主成分分析(PCA)

主成分分析(Principal Component Analysis, PCA) は、最も一般的な次元削減手法です。データの分散が最大になる方向を見つけます。

graph LR
    A[高次元データ<br/>n次元] --> B[PCA]
    B --> C[低次元データ<br/>k次元]

    B --> D[第1主成分<br/>最大分散方向]
    B --> E[第2主成分<br/>次に大きい分散方向]

    style A fill:#e6ccff
    style B fill:#ffffcc
    style C fill:#ccffcc

B.6.3 PCA の実装

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import seaborn as sns
import matplotlib.pyplot as plt

# アヤメデータセットの読み込み
iris = sns.load_dataset('iris')
X = iris.drop('species', axis=1)
y = iris['species']

# 標準化(PCA の前に推奨)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# PCA で2次元に削減
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

# 寄与率の確認
print(f"各主成分の寄与率: {pca.explained_variance_ratio_}")
print(f"累積寄与率: {pca.explained_variance_ratio_.sum():.4f}")

# 可視化
plt.figure(figsize=(8, 6))
for species in y.unique():
    mask = y == species
    plt.scatter(X_pca[mask, 0], X_pca[mask, 1], label=species, alpha=0.7, s=50)

plt.xlabel(f'PC1 ({pca.explained_variance_ratio_[0]:.2%})')
plt.ylabel(f'PC2 ({pca.explained_variance_ratio_[1]:.2%})')
plt.title('PCA による次元削減(Iris データセット)')
plt.legend()
plt.grid(alpha=0.3)
plt.show()

B.6.4 次元数の決定

累積寄与率をもとに、適切な次元数を決定します。

# 全主成分を計算
pca_full = PCA()
pca_full.fit(X_scaled)

# 累積寄与率の計算
cumulative_variance = np.cumsum(pca_full.explained_variance_ratio_)

# 可視化
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(cumulative_variance) + 1), cumulative_variance, 'bo-')
plt.axhline(y=0.95, color='r', linestyle='--', label='95% の寄与率')
plt.xlabel('主成分の数')
plt.ylabel('累積寄与率')
plt.title('累積寄与率')
plt.legend()
plt.grid(alpha=0.3)
plt.show()

寄与率とは

寄与率は、各主成分がデータの分散(情報量)をどれだけ説明しているかを示します。累積寄与率が 80〜95% 以上になる次元数を選ぶことが多いです。

B.7 演習問題

演習 B-1: k-means クラスタリングの実践

演習 B-1

iris データセット(アヤメの花の計測データ、150 件・4 つの数値特徴量・3 品種ラベル)を使って、k-means クラスタリングを実行してください。

タスク

  1. iris の数値特徴量で k-means を実行(k=3)
  2. エルボー法で最適な k を探索(k=1〜10)
  3. シルエットスコアで評価(k=2〜10)
  4. 実際のラベル(species)とクラスタリング結果を比較する
テンプレートコード
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

# 0. iris データセットの読み込み・数値特徴量を取り出す
iris = sns.load_dataset('iris')

# 1. k=3 で k-means を実行

# 2. エルボー法(k=1〜10 の慣性をプロット)

# 3. シルエットスコア(k=2〜10)

# 4. 実ラベルとの比較(クロス集計など)

演習 B-2: PCA による可視化

演習 B-2

penguins データセット(パルマー諸島のペンギンの計測データ、3 種類のペンギンに対する数値特徴量)を PCA で 2 次元に削減し、可視化してください。

タスク

  1. penguins データを読み込み、欠損値を削除
  2. 数値特徴量を標準化(StandardScaler)
  3. PCA で 2 次元に削減
  4. 種類(species)ごとに色分けして散布図を作成
  5. 各主成分の寄与率を確認
テンプレートコード
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 1. penguins データの読み込み + 欠損値削除
penguins = sns.load_dataset('penguins').dropna()

# 2. 数値特徴量を標準化

# 3. PCA で 2 次元に削減

# 4. 種類ごとに色分けして散布図

# 5. 各主成分の寄与率を表示

B.8 まとめ

本付録では、教師なし学習について学びました。

付録 B のまとめ

教師なし学習

  • 正解ラベルなしでデータの構造を発見
  • クラスタリングと次元削減が代表的

k-means

  • 基本的なクラスタリング手法
  • クラスタ数 k を事前に指定
  • エルボー法で最適な k を探索

階層的クラスタリング

  • デンドログラムでクラスタ関係を可視化
  • クラスタ数を事前に決めなくてよい

シルエット分析

  • クラスタリングの品質を評価
  • -1〜1 の範囲で、1 に近いほど良い

PCA(主成分分析)

  • 代表的な次元削減手法
  • 分散が最大になる方向を抽出
  • 累積寄与率で次元数を決定