付録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
アルゴリズムの手順
- k 個の初期中心点(セントロイド)をランダムに配置
- 各データ点を最も近い中心点のクラスタに割り当て
- 各クラスタの中心点を再計算(平均位置)
- 中心点が変化しなくなるまで 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 シルエット係数とは¶
シルエット係数 は、クラスタリングの品質を評価する指標です。
- \(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 クラスタリングを実行してください。
タスク
- iris の数値特徴量で k-means を実行(k=3)
- エルボー法で最適な k を探索(k=1〜10)
- シルエットスコアで評価(k=2〜10)
- 実際のラベル(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 次元に削減し、可視化してください。
タスク
- penguins データを読み込み、欠損値を削除
- 数値特徴量を標準化(
StandardScaler) - PCA で 2 次元に削減
- 種類(species)ごとに色分けして散布図を作成
- 各主成分の寄与率を確認
B.8 まとめ¶
本付録では、教師なし学習について学びました。
付録 B のまとめ
教師なし学習
- 正解ラベルなしでデータの構造を発見
- クラスタリングと次元削減が代表的
k-means
- 基本的なクラスタリング手法
- クラスタ数 k を事前に指定
- エルボー法で最適な k を探索
階層的クラスタリング
- デンドログラムでクラスタ関係を可視化
- クラスタ数を事前に決めなくてよい
シルエット分析
- クラスタリングの品質を評価
- -1〜1 の範囲で、1 に近いほど良い
PCA(主成分分析)
- 代表的な次元削減手法
- 分散が最大になる方向を抽出
- 累積寄与率で次元数を決定