Social Data Science Courseware

4. クラスタリング

学習目標

  • クラスタリングの目的と PCA との違いを説明できる
  • K-means のアルゴリズム(重心と所属の更新)を理解する
  • scikit-learn の KMeans で実行し、結果を取り出せる
  • クラスタ数 k の決め方を 2 つ以上挙げられる(エルボー法・シルエット係数)
  • 散布図やレーダーチャートで結果を可視化し、各クラスタの特徴を言葉で表現できる

本文

クラスタリングとは

クラスタリング は「似た特徴を持つデータをまとめて、いくつかのグループに分ける」教師なし学習の手法です。前単元の PCA は 次元を減らして眺める 手法でしたが、クラスタリングは 明示的にグループに分けてラベルを付ける 点が違います。

手法目的出力
PCA(前単元)次元を減らして眺める各データ点の主成分得点
クラスタリング似たもの同士をまとめる各データ点のクラスタ番号

両者を組み合わせることもよくあります(PCA で 2 次元に落としてから K-means で分ける、など)。

何に使えるか

  • 顧客セグメンテーション:購買傾向の似た顧客をグループにしてマーケティング
  • 観光スポットの分類:評価項目から「自然系」「都市系」「家族向け」のクラスタを見つける
  • 遺伝子発現の解析:似たパターンの遺伝子をまとめる
  • 画像のセグメンテーション:色やテクスチャが似た領域を抽出

ラベル付けされていないデータから 「自然なまとまり」 を見つけたいとき全般に使えます。

K-means のアルゴリズム

代表的な手法 K-means 法 は、「各クラスタの 重心(中心点) を見つける」ことを目的にした、シンプルで強力なアルゴリズムです。

  1. クラスタ数 k を決める(あらかじめ指定)
  2. ランダムに k 個の重心を配置
  3. 各データ点を「最も近い重心のクラスタ」に割り当てる
  4. 各クラスタに割り当てられたデータ点の平均を計算し、重心を更新する
  5. 3〜4 を、重心がほとんど動かなくなるまで繰り返す

要するに 「データ点を最も近い重心に振り分け → 重心を新しい平均で更新」を繰り返す だけ。シンプルですが、多くのケースで十分実用的な結果を返します。

標準化が必要

PCA と同じく、変数のスケールが揃っていない場合は 標準化 が必須です。K-means は「重心からの距離」でクラスタを決めるため、単位が大きい変数(収入:万円単位)と小さい変数(年齢:歳)を混ぜると、収入だけで結果が決まってしまいます。

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

すべての変数が同じスケール(たとえばアンケート評価の 1〜5 点)なら省いてもよいですが、迷ったときは標準化しておくのが安全です。

scikit-learn での実行

scikit-learn の KMeans クラスを使います:

from sklearn.cluster import KMeans

kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
labels = kmeans.fit_predict(X_scaled)
  • n_clusters=4 — 作りたいクラスタの数(K-means の k
  • random_state=42 — 乱数シード。指定すると毎回同じ結果が得られて再現性が確保できる
  • n_init=10 — 初期重心の配置を 10 通り試して、最良の結果を選ぶ
  • fit_predict(X) — 学習と所属判定を同時に行うショートカット。返り値は各データ点のクラスタ番号

結果を元の DataFrame に列として追加すれば、後段の集計や可視化に渡せます:

df["cluster"] = labels
df.groupby("cluster").mean(numeric_only=True)   # クラスタごとの平均特徴

クラスタ数 k の決め方

K-means の最大の悩みどころが k をいくつにすればいいか」 です。代表的な決め方は 2 つ:

エルボー法

k を変えながら クラスタ内誤差平方和(inertia) を計算し、k ごとにプロットします。k を増やすと誤差は単調に減りますが、「これ以上増やしても改善が小さい」屈折点(エルボー、肘) がベストな k の目安になります。

inertias = []
for k in range(1, 11):
    km = KMeans(n_clusters=k, random_state=42, n_init=10)
    km.fit(X_scaled)
    inertias.append(km.inertia_)

plt.plot(range(1, 11), inertias, marker="o")
plt.xlabel("k")
plt.ylabel("クラスタ内誤差平方和")
plt.show()

シルエット係数

各データ点について「自分のクラスタに似ているか」「他のクラスタと離れているか」を -1〜1 の値で評価する指標です。シルエット係数が大きい k を選ぶ のが定石。

from sklearn.metrics import silhouette_score
score = silhouette_score(X_scaled, labels)

実務では両方を計算して総合判断するのが普通です。

結果の可視化

散布図(2 変数で見る、または PCA 経由)

クラスタの分かれ方を視覚的に確認するには散布図が手っ取り早い方法です。元の変数が多い場合は、PCA で 2 次元に落としてから散布図にすることが多いです。

クラスタリング結果の 2 次元散布図

レーダーチャート(各クラスタの特徴)

「クラスタごとの平均特徴量」をレーダーチャートで可視化すると、「このクラスタはこの軸が強い」 が一目で分かります。

クラスタごとの特徴をレーダーチャートで可視化

結果の解釈

クラスタリングは「グループに分ける」までで、「そのグループが何を意味するか」は分析者が解釈する 必要があります。PCA と同じく、ラベル付けは人間の仕事です。

たとえば観光スポットを 4 クラスタに分けた場合:

  • クラスタ A:自然度が高く、利便性が低い → 「自然系」
  • クラスタ B:ショッピング度・グルメ度が高い → 「都市系」
  • クラスタ C:家族向け度が高い → 「ファミリー系」
  • クラスタ D:文化度が高い → 「歴史・文化系」

このように、各クラスタの平均特徴を眺めて、人間が分かる言葉でラベルを付ける のがクラスタリングの仕上げです。

よく出る躓きどころ

  • 標準化を忘れる — スケールの大きい変数だけで結果が決まる
  • random_state を指定しない — 実行のたびに結果が変わって再現できない
  • k=2 から決め打ち — エルボー法かシルエット係数で根拠を持って決める
  • 「クラスタ」と「ラベル」を混同する — アルゴリズムが返すのは番号だけ。「自然系」「都市系」のラベルは分析者が付ける
  • K-means は球状に分けるのが得意 — 非球状のクラスタ(三日月型など)は苦手。そのときは DBSCAN や階層型クラスタリングを検討

サンプルコード

演習

完成 Notebook を題材に、次を順に行いなさい。

  1. Notebook を Colab で開き、最後まで実行してクラスタリング結果を確認する
  2. n_clusters3, 4, 5 と変えて再実行し、散布図とレーダーチャートの違いを観察する
  3. 各クラスタの平均特徴を df.groupby("cluster").mean() で算出する
  4. それぞれのクラスタに 自分の言葉でラベル(例:「自然系」「都市系」)を付け、ノートブックに書く

n_clusters を変えると同じデータでも全く違うグループ分けになります。「何を見たいか」によって最適な k が変わることを体感してください。

発展課題(オプション)

  • エルボー法のグラフを描いて、最適な k を視覚的に判断する
  • シルエット係数を計算し、k ごとに比較する
  • 別のクラスタリング手法(sklearn.cluster.AgglomerativeClusteringDBSCAN)を試して、K-means との結果の違いを観察する