この記事は
本記事では、K-Meansクラスタリングにおける適切なクラスタ数 $K$ の決定手法として、
エルボー法 と シルエットスコア を解説し、
Pythonによる実装例と具体的な解釈までをひととおり紹介します。
概要
- クラスタリングの結果は「何個に分けるか」に大きく依存する
- エルボー法:クラスタ内誤差(Inertia)の減少幅に注目して"肘"を探す
- シルエットスコア:クラスター内の一体感と外との分離度を定量化する
- 両者を組み合わせることで、より安定したクラスタ数の判断が可能
エルボー法とは
-
Inertia(慣性/クラスタ内誤差) を各 $K$ で計算
$$
\text{Inertia} = \sum_{i=1}^{n} \min_{j=1..K} |x_i - \mu_j|^2
$$ - $K$ を増やすほど必ず下がるが、減少幅は次第に小さくなる
- グラフ上で「急激に減ったあと平坦になる箇所=肘(Elbow)」を最適 $K$ の候補とする
- メリット:直感的、計算も軽量 / デメリット:明確に折れ曲がりが見えない場合もある
シルエットスコアとは
- 各サンプル $i$ に対して
- $a(i)$:同じクラスタ内の他点との平均距離
- $b(i)$:最も近い異クラスタとの平均距離
- シルエット係数
$$
s(i) = \frac{b(i) - a(i)}{\max(a(i),,b(i))}
$$
- 平均シルエットスコア(全サンプルの $s(i)$ の平均)を算出
- $-1$~$+1$ の範囲で、+1 に近いほど "よく分かれている"
- メリット:クラスタの質を定量評価できる / デメリット:計算量がやや多い
Pythonでの実装例
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
# --- データの前処理 ---
X_scaled = ... # 標準化済み特徴量行列
# --- 評価指標の計算 ---
inertia = []
silhouette_scores = []
K_range = range(2, 11)
for k in K_range:
km = KMeans(n_clusters=k, random_state=42, n_init=10)
km.fit(X_scaled)
inertia.append(km.inertia_)
silhouette_scores.append(silhouette_score(X_scaled, km.labels_))
# --- 結果のプロット ---
plt.figure(figsize=(12,5))
plt.subplot(1,2,1)
plt.plot(K_range, inertia, marker='o')
plt.title('Elbow Method for Optimal K')
plt.xlabel('Number of Clusters (K)')
plt.ylabel('Inertia')
plt.grid(True)
plt.subplot(1,2,2)
plt.plot(K_range, silhouette_scores, marker='o')
plt.title('Silhouette Score for Optimal K')
plt.xlabel('Number of Clusters (K)')
plt.ylabel('Silhouette Score')
plt.grid(True)
plt.tight_layout()
plt.show()
具体例での解釈
-
エルボー法:
- $K=2 \to 3 \to 4$ の減少が大きく、以降は緩やか
- "肘" と見なせるのは $K=4$
-
シルエットスコア:
- 平均スコアのピークが $K=4$(約0.43)
- $K>4$ ではスコアが下がり、クラスタ分離度が低下
-
結論:
両者とも $K=4$ がもっともバランス良く、過剰分割のリスクも抑えられる最適解
まとめ
- K-Means のクラスタ数選定には、エルボー法 と シルエットスコア の併用が有効
- エルボー法でざっくり"肘"のあたりを絞り、シルエットスコアで最適値を確かめる流れ
- Python/scikit-learn なら数行のコードで実装可能
- 実務では結果の「解釈しやすさ」や「ドメイン知見」も組み合わせて最終判断しましょう