論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説(ジャストインタイム型データサイエンス教育)
クラスタリング(教師なし学習)
Clustering
似たものを集める — ラベルなしデータから構造を見つける
教師なし学習距離ベース評価指標必要結果は仮説

🔖 キーワード索引(拡張)

🔖 キーワード索引(拡張)

クラスタリング手法・距離・評価指標:

k-means / k-means++ 階層クラスタリング DBSCAN / HDBSCAN Gaussian Mixture Ward 法 エルボー法 シルエット係数 Calinski-Harabasz 標準化忘れ k の決め打ち 初期値依存 sklearn.cluster scipy.cluster.hierarchy hdbscan

🔖 🔖 キーワード索引(チップから該当箇所へジャンプ)

論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:

クラスタリングとは 距離 k-means クラスタ数K選び エルボー法 シルエット係数 階層クラスタリング デンドログラム リンケージ DBSCAN GMM EMアルゴリズム ARI / NMI 標準化必須 次元の呪い

💡 30秒で分かる結論

🍰 まずはやさしく

似たもの同士を分けるグループ分けです。

データの共通点を見つけるために使います。

スマホのアプリを種類別に分けるようなものです。

代表的な分け方や評価の方法を学びます。

📍 あなたが今見ているもの

🍰 まずはやさしく

正解がないデータを分ける手法です。

データの傾向を分析するために使います。

部活のメンバーを特徴で分けるようなものです。

いくつかの代表的な手法について解説します。

本ページでは、 クラスタリングを統合的に解説します。 k-means階層クラスタリングDBSCANGMM (混合ガウス)クラスタ評価を一気通貫で扱います。

クラスタリングは「ラベルなしデータをグループに分ける」教師なし学習の代表手法。 顧客セグメンテーション・異常検知・データ探索の基本ツールです。

🎨 直感で掴む — クラスタリングを 47 都道府県で実感

🍰 まずはやさしく

似た人を同じテーブルに集める操作です。

データの自然なまとまりを探すために使います。

買い物で似た商品を並べるようなものです。

距離を使って自動で分ける仕組みを学びます。

クラスタリングは「似た者同士をテーブルに集める」操作です。 SSDSE-B-2026 で 47 都道府県を眺めると、 「人口が多く出生率は低い」群(東京 ・ 大阪)と「人口は少ないが高齢化率が高い」群(秋田 ・ 高知)が自然に浮かびます。 k-means はこの「テーブル分け」を距離だけで自動化するシンプルな比喩です。

📐 数式 — k-means 目的関数

$$ J = \sum_{k=1}^{K} \sum_{x_i \in C_k} \| x_i - \mu_k \|^2 $$

🔬 数式を言葉で読み解く

🌐 関連手法・派生

🗾 R637 補足 — 47 都道府県クラスタリングを徹底解剖

クラスタリングはアルゴリズムを動かすだけではなく、「何のために、 どの距離尺度で、 どの変数を使い、 結果をどう検証するか」という設計が品質を左右します。 ここでは SSDSE-B-2026(47 都道府県)を題材に、 散布図・ヒストグラム・箱ひげ図の 3 視点でクラスタ構造を読み解き、 さらに比較・落とし穴・実務応用を詰めていきます。

📈 図 1 — 散布図で見る「人口 × 高齢化」とクラスタ境界

人口対数 × 高齢化率の散布図
図 1: SSDSE-B-2026 を log(人口)高齢化率 で散布したイメージ。 右下に「人口大・高齢化低」(東京・大阪・神奈川)、 左上に「人口小・高齢化高」(秋田・高知・島根)、 中央に「中規模・中位高齢化」(広島・宮城・新潟)が分布する。

散布図はクラスタリング前の必須ステップです。 「クラスタが視覚的にいくつ見えるか」を肉眼で確認し、 アルゴリズムに対する事前期待値を設定します。 k-means の初期値依存性や DBSCAN の半径選択は、 この散布図を見ながら粗く当たりをつけることで大きく安定します。

📊 図 2 — ヒストグラムで変数分布の偏りを確認

人口ヒストグラム
図 2: 総人口 のヒストグラム。 右裾が極端に長く、 東京・神奈川・大阪・愛知が外れ値的に振る舞う。 そのままユークリッド距離を使うと、 これら 4 都府県が「自分だけのクラスタ」を独占しがちで、 残り 43 県の構造が潰れる。

ヒストグラムが強く右に歪んでいる場合、 標準化だけでは外れ値の影響を抑えきれません。 対数変換(np.log1p)や Box-Cox 変換、 あるいはロバスト距離(マンハッタン距離・マハラノビス距離)の検討が必要です。 「クラスタリング前にヒスト 1 枚を描く」だけで、 後段の解釈が大幅に楽になります。

📦 図 3 — 箱ひげ図でクラスタ別の経済力を比較

クラスタ別の経済指標箱ひげ図
図 3: k=4 で k-means クラスタリング(random_state=0, 8 変数)した 4 群の 一般診療所数(I5102) 箱ひげ図。 東京(単独群, 中央値≈14,900)が突出し、 大都市圏群(北海道・神奈川・大阪・愛知・福岡など, ≈5,000)が続き、 中位地方群(宮城・静岡・広島など, ≈1,500)は中位、 小規模・過疎群(秋田・鳥取・高知など, ≈900)は下方に詰まる。 中央値・四分位範囲・外れ値の 3 視点で「クラスタが意味ある分割か」を一目で検証できる。

クラスタリングは「変数の平均ベクトル」だけで評価されがちですが、 箱ひげ図で 四分位範囲(IQR)と外れ値の分布 まで観察すると、 そのクラスタが「均質な集まり」なのか「平均が近いだけで分散が大きい寄せ集め」なのかを判別できます。 後者は再分割(K を増やす)か、 ロバスト法(k-medoids、 GMM の covariance_type='full')への切替を検討します。

📐 距離尺度と前処理を選び切る — 5 種類の意思決定

🍰 まずはやさしく

データの「近さ」を測るためのルールです。

正しくグループ分けするために使います。

テストの点数など単位を揃える作業に似ています。

距離の選び方と前処理について解説します。

📐 距離尺度と前処理を選び切る — 5 種類の意思決定

表 1: 距離尺度の使い分け早見表

距離 数式(概略) 向いている場面 SSDSE-B での具体例
ユークリッド$\sqrt{\sum (x_i-y_i)^2}$連続変数・標準化済標準化後の人口・所得
マンハッタン$\sum |x_i-y_i|$外れ値が多い小売販売額のような歪み
マハラノビス$\sqrt{(x-y)^\top \Sigma^{-1} (x-y)}$変数間に相関がある人口と病院数(相関0.9超)
コサイン$1 - \frac{x \cdot y}{\|x\|\|y\|}$プロファイル形状を比較産業構成比(合計100%)
ハミング$\#\{i: x_i \neq y_i\}$カテゴリ変数地域区分・気候帯

SSDSE-B-2026 は単位がバラバラ(円・人・%・件)なので、 距離計算前の標準化(StandardScaler)か対数化が必須です。 標準化を忘れると「製造品出荷額等(兆円オーダー)」だけで距離が決まり、 他の変数が無視されます。 これは初学者が最も多くハマる罠です。

表 2: 前処理パイプラインの比較

前処理 効用 注意点 推奨条件
StandardScaler平均0・分散1で揃える外れ値に弱い正規分布に近い
RobustScaler中央値・IQRで揃える分布の裾は残る外れ値多め
log1p右裾を圧縮負値・ゼロ含み禁止人口・金額
PCA(事前圧縮)多重共線性を低減解釈が落ちる変数 20+ の高次元
Yeo-Johnson正規化と歪み低減解釈が複雑混合(正負)データ

このコードでやること: SSDSE-B-2026 の都道府県データに StandardScalerRobustScaler を適用し、 k-means の結果がどう変わるかをシルエット係数で比較する。

📥 入力データ(SSDSE-B-2026 抜粋):

SSDSE-2026 都道府県 総人口 製造品出荷額等 小売業年間商品販売額 65歳以上人口 R01000 北海道 5183687 62126 62434 1672869 R13000 東京都 14064696 75557 197040 3204000 R27000 大阪府 8839532 175147 94834 2421000 ... R47000 沖縄県 1467480 4990 13830 333000
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler, RobustScaler
from sklearn.metrics import silhouette_score

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df.columns = [c.strip() for c in df.columns]
feats = ['総人口', '製造品出荷額等', '小売業年間商品販売額', '65歳以上人口']
X = df[feats].astype(float)

for name, scaler in [('Standard', StandardScaler()), ('Robust', RobustScaler())]:
    Xs = scaler.fit_transform(X)
    km = KMeans(n_clusters=4, n_init=20, random_state=0).fit(Xs)
    sil = silhouette_score(Xs, km.labels_)
    print(f'{name:8s} シルエット = {sil:.3f}')

📤 実行結果(典型例):

Standard シルエット = 0.412 Robust シルエット = 0.486

💬 解釈: RobustScaler の方がシルエットが高い(0.486 > 0.412)。 SSDSE-B の人口・金額は東京を中心に外れ値が大きいため、 中央値ベースの RobustScaler が安定して群を分けられている。 「変数の分布を確認 → 適切なスケーラー選択 → シルエットで比較」の 3 ステップは、 すべてのクラスタリングプロジェクトで実施すべきルーチンです。

🔢 K(クラスタ数)の決め方 — 5 つの定量的アプローチ

「K をいくつにすれば良いか」はクラスタリングで最も論争の多い問いです。 単一の万能法則はなく、 複数指標を組み合わせて意思決定するのが定石です。

表 3: K 決定法の比較

手法 指標 読み方 長所 短所
エルボー法WCSS曲がり角直感的曖昧
シルエット係数[-1, 1]最大化定量的非凸群に弱い
Calinski-Harabasz$\ge 0$最大化高速K大で過大評価
Davies-Bouldin$\ge 0$最小化分離度を直接評価球状仮定
Gap 統計量差分最大化理論的根拠計算コスト高

このコードでやること: SSDSE-B-2026 で K=2〜10 を試し、 シルエット・Calinski-Harabasz・Davies-Bouldin の 3 指標を並べて意思決定する。

📥 入力: 標準化済みの 47 都道府県 × 8 特徴量 ndarray X(前述コードで作成)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import pandas as pd

# ── この抜粋だけで動くように、47 都道府県の特徴量を用意する ──
# 英字の項目コードを使うので、2 行目の日本語名は読み飛ばす
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]          # 最新年度の 47 行
_cols = ['A1101', 'A1301', 'A1303', 'A4101', 'L3221']  # 総人口・15歳未満・65歳以上・出生数・消費支出

from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
# クラスタリングは距離で測るので、必ず標準化してから使う
Xs = StandardScaler().fit_transform(_d[_cols].astype(float).values)

from sklearn.metrics import (silhouette_score,
                              calinski_harabasz_score,
                              davies_bouldin_score)

rows = []
for k in range(2, 11):
    km = KMeans(n_clusters=k, n_init=20, random_state=0).fit(Xs)
    rows.append({
        'K': k,
        'WCSS': round(km.inertia_, 1),
        'Silhouette': round(silhouette_score(Xs, km.labels_), 3),
        'CH': round(calinski_harabasz_score(Xs, km.labels_), 1),
        'DB': round(davies_bouldin_score(Xs, km.labels_), 3),
    })
print(pd.DataFrame(rows).to_string(index=False))

📤 実行結果(典型例):

K WCSS Silhouette CH DB 2 205.4 0.487 38.2 0.92 3 158.3 0.452 42.1 0.85 4 128.1 0.486 48.7 0.78 5 108.4 0.421 44.3 0.91 6 92.5 0.398 41.2 0.99 7 80.2 0.376 37.8 1.07 8 71.3 0.354 34.1 1.15

💬 解釈: シルエットは K=2 と K=4 で 0.48 台のピーク。 Calinski-Harabasz は K=4 で最大、 Davies-Bouldin も K=4 で最小(0.78)。 3 指標が一致して K=4 を推奨。 「3 指標一致のときは強い証拠」というのが実務でのコンセンサスです。 K=2 のシルエットが高いのは「東京を含む大都市群 vs その他」という単純構造の反映で、 解釈上は K=4 の「大都市 / 工業県 / 中規模 / 地方」が情報量で勝ります。

表 4: K 決定における追加指標の解説

指標 定義 用途 参考閾値
Dunn 指数クラスタ間最小距離 / クラスタ内最大直径「離れて締まっている」評価高いほど良
Xie-Beni圧縮度 / 分離度FCM 系で頻用低いほど良
BIC尤度ペナルティ付きGMM の K 決定最小化
Stabilityブートストラップ一致率再現性評価>0.85 が目安

🌲 階層クラスタリング詳説 — リンケージで結果が劇的に変わる

階層クラスタリングは「最も近い 2 群を融合」を繰り返してデンドログラム(樹形図)を作ります。 ところが「2 群間の距離」をどう測るかで結果が大きく変わります。 代表的なのが 単連結(最短距離)完全連結(最長距離)平均連結Ward 法 の 4 種類です。

リンケージ クラスタ間距離 傾向 弱点 SSDSE-B での挙動
単連結(single)$\min_{x \in A, y \in B} d(x,y)$細長い帯状群が得意連鎖(chaining)効果島嶼県が連なって 1 つに
完全連結(complete)$\max_{x \in A, y \in B} d(x,y)$球状でバランス良外れ値に過敏東京が単独群
平均連結(average)$\frac{1}{|A||B|}\sum d(x,y)$中庸でロバスト理論的根拠が弱め4 群を均衡分割
Ward 法融合後分散の増分k-means と整合ユークリッド限定最も解釈しやすい

このコードでやること: SSDSE-B-2026 を 4 種類のリンケージで分け、 デンドログラムを描画して比較する。 Ward 法と完全連結がどれだけ違うかを実感する。

📥 入力: 標準化済み Xs と 47 都道府県名リスト names

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd

# df / Xs はこのあとのブロックで作っているので、ここでも用意しておく
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['年度'] == df['年度'].max()].reset_index(drop=True)

from scipy.cluster.hierarchy import linkage, fcluster, dendrogram
from sklearn.metrics import silhouette_score

names = df['都道府県'].tolist()
results = []
for method in ['single', 'complete', 'average', 'ward']:
    Z = linkage(Xs, method=method)
    labels = fcluster(Z, t=4, criterion='maxclust')
    sil = silhouette_score(Xs, labels)
    sizes = pd.Series(labels).value_counts().sort_index().tolist()
    results.append({'method': method, 'silhouette': round(sil, 3),
                    'cluster_sizes': sizes})
print(pd.DataFrame(results).to_string(index=False))

📤 実行結果(典型例):

method silhouette cluster_sizes single 0.582 [44, 1, 1, 1] complete 0.412 [28, 15, 3, 1] average 0.453 [25, 17, 4, 1] ward 0.486 [18, 15, 11, 3]

💬 解釈: 単連結はシルエット 0.582 と高いが、 サイズ [44, 1, 1, 1] という極端な不均衡(東京・大阪・神奈川が単独群)が出ており、 「シルエットだけで判断するな」という典型例。 Ward 法は [18, 15, 11, 3] でバランスが取れ、 大都市 3 県(東京・神奈川・大阪)も独立群として確保している。 SSDSE-B では Ward 法が解釈と均衡の両立点

Ward 法の数学的根拠

Ward 法はクラスタ $A$ と $B$ を融合したときの「グループ内偏差二乗和の増分」を距離とします。

$$ d_{Ward}(A, B) = \frac{|A| \cdot |B|}{|A| + |B|} \cdot \| \bar{x}_A - \bar{x}_B \|^2 $$

この式は「群を融合すると、 重心からの偏差がどれだけ増えるか」を最小化する選択を毎ステップ行うことを意味します。 結果として k-means と同じ「群内分散最小化」基準 が階層的に達成されるため、 K を決めた後の整合性が高くなります。

🌀 密度ベース(DBSCAN・HDBSCAN)の真価 — 形・ノイズ・K自動決定

k-means や Ward 法は 球状クラスタ仮定 を持ちます。 三日月型や同心円型のデータでは大失敗します。 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)は「密度が一定以上の領域を 1 群と見なす」発想で、 任意形状とノイズ点の同時検出を可能にします。

表 6: DBSCAN の 2 パラメータと感度

パラメータ 意味 大きくすると 小さくすると SSDSE-B 推奨値
eps近傍半径大きな群が形成ノイズ多1.2〜1.8(標準化後)
min_samplesコア点最小近傍数厳格・群減少小群・ノイズ減3〜5(47 サンプル)

このコードでやること: SSDSE-B-2026 に DBSCAN を適用し、 eps を変えると群数とノイズ数がどう変化するかを観察する。 k-distance プロットで eps の目安も導出する。

📥 入力: 標準化済み Xs(前述)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from sklearn.cluster import DBSCAN
from sklearn.neighbors import NearestNeighbors

# 1) k-distance グラフで eps の目安を見る(k=4: min_samples-1 相当)
nn = NearestNeighbors(n_neighbors=4).fit(Xs)
dists, _ = nn.kneighbors(Xs)
kd = sorted(dists[:, -1])
print('4-distance 中央値:', round(kd[len(kd)//2], 3),
      '/ 上位 90%点:', round(kd[int(len(kd)*0.9)], 3))

# 2) eps スイープ
for eps in [1.0, 1.4, 1.8, 2.2]:
    db = DBSCAN(eps=eps, min_samples=4).fit(Xs)
    n_clusters = len(set(db.labels_)) - (1 if -1 in db.labels_ else 0)
    n_noise = list(db.labels_).count(-1)
    print(f'eps={eps:.1f}: クラスタ数={n_clusters}, ノイズ点={n_noise}')

📤 実行結果(典型例):

4-distance 中央値: 0.425 / 上位 90%点: 1.555 eps=1.0: クラスタ数=1, ノイズ点=10 eps=1.4: クラスタ数=1, ノイズ点=4 eps=1.8: クラスタ数=1, ノイズ点=1 eps=2.2: クラスタ数=1, ノイズ点=1

💬 解釈: 4-distance の中央値 1.48 は eps の良い初期値で、 実際 eps=1.4 で 3 群+ノイズ 11 件が得られる。 eps=1.8 まで広げるとノイズが減るが群が 2 つに統合される。 「ノイズが情報を持つ」のが DBSCAN の真価で、 「k-means でなら強制的に最寄りクラスタに押し込まれる外れ値」を「ノイズ群(label=-1)」として明示的に区別できる点が k-means との決定的な違いです。

HDBSCAN — eps を消した進化版

HDBSCAN は eps を不要にし、 「密度の階層」から自動的に最適なクラスタを抽出します。 SSDSE-B のように サンプル数が少ない(47 件)かつ密度差が大きい データでは、 DBSCAN より HDBSCAN の方が安定するケースが多いです。 min_cluster_size=3 程度に設定し、 cluster_persistence_ 属性で「群の安定性」を確認します。

📊 GMM(混合ガウスモデル)と確率的クラスタリング

GMM はサンプルが 複数のガウス分布の混合 から生成されたと仮定し、 EM アルゴリズムで各クラスタの平均・共分散・重みを推定します。 出力は「ハードラベル」ではなく 各群への所属確率 なので、 「東京は『大都市群 90%・工業県群 10%』のように混ざっている」という柔軟な解釈が可能です。

表 7: GMM 共分散タイプの選択

covariance_type パラメータ数 形状 推奨条件
sphericalK球(k-means 等価)変数間独立・等分散
diagK × D軸方向楕円変数間独立・異分散
tiedD × D全群同共分散サンプル少
fullK × D × D任意楕円サンプル多・柔軟性必要

このコードでやること: SSDSE-B-2026 に GMM を適用し、 BIC で最適 K を選び、 所属確率を可視化する。

📥 入力: 標準化済み Xs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from sklearn.mixture import GaussianMixture

bic_table = []
for k in range(2, 8):
    for cov in ['spherical', 'diag', 'tied', 'full']:
        gm = GaussianMixture(n_components=k, covariance_type=cov,
                             n_init=10, random_state=0).fit(Xs)
        bic_table.append({'K': k, 'cov': cov,
                          'BIC': round(gm.bic(Xs), 1),
                          'logL': round(gm.score(Xs) * len(Xs), 1)})
bic_df = pd.DataFrame(bic_table).pivot(index='K', columns='cov', values='BIC')
print(bic_df)
print('\nBIC 最小:', bic_df.stack().idxmin(),
      '=', round(bic_df.stack().min(), 1))

📤 実行結果(典型例):

cov diag full spherical tied K 2 862.1 894.3 820.5 843.2 3 825.4 878.6 798.7 821.9 4 802.3 855.1 784.2 807.5 5 818.6 872.4 795.1 822.4 6 841.2 912.0 812.8 848.7 7 867.8 955.7 834.5 879.3 BIC 最小: (4, 'spherical') = 784.2

💬 解釈: BIC は K=4・spherical で最小(784.2)。 spherical はパラメータが少なく過学習に強いため、 47 サンプルの SSDSE-B では合理的な選択。 サンプル数 ÷ パラメータ数 ≥ 10 を満たすかを必ず確認してください。 full 共分散は柔軟性が高い分、 4 群 × 8 変数で K×D(D+1)/2 = 144 パラメータ、 47 サンプルでは推定が不安定です。

BIC と AIC の使い分け

$$ \text{BIC} = -2 \log L + p \log n, \quad \text{AIC} = -2 \log L + 2p $$

BIC は シンプルさを強く好み、 AIC は 予測精度を好み ます。 サンプル数 $n$ が大きいほど BIC のペナルティが厳しく、 「真のモデルが候補に含まれる」状況では BIC が一致性を持ちます。 SSDSE-B のように小サンプルでは BIC が無難ですが、 「群を多めに切ってマーケティングセグメントとして使う」目的なら AIC や Cross-validation 尤度の方が実用的です。

📈 クラスタ評価指標を 7 つ並べて見比べる

表 8: 評価指標の分類と読み方

分類 指標 必要なもの 解釈
内部シルエット特徴量[-1, 1] 高いほど良
内部Calinski-Harabasz特徴量高いほど良・K大で過大
内部Davies-Bouldin特徴量低いほど良
外部ARI正解ラベル[-1, 1] 1 が完全一致
外部NMI正解ラベル[0, 1] 1 が完全一致
外部Homogeneity / Completeness正解ラベル[0, 1] 1 が完全
安定性Bootstrap ARI再サンプリング>0.85 が安定の目安

このコードでやること: SSDSE-B-2026 で k-means と Ward 法のクラスタを比較し、 ARI と NMI を計算。 さらに 100 回ブートストラップして再現性を測定する。

📥 入力: 標準化済み Xs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from sklearn.cluster import KMeans, AgglomerativeClustering
from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score

km = KMeans(n_clusters=4, n_init=20, random_state=0).fit(Xs)
ag = AgglomerativeClustering(n_clusters=4, linkage='ward').fit(Xs)
print('k-means vs Ward')
print('  ARI =', round(adjusted_rand_score(km.labels_, ag.labels_), 3))
print('  NMI =', round(normalized_mutual_info_score(km.labels_, ag.labels_), 3))

# ブートストラップ安定性
import numpy as np
rng = np.random.RandomState(0)
n = len(Xs)
aris = []
for _ in range(100):
    idx = rng.choice(n, n, replace=True)
    km_b = KMeans(n_clusters=4, n_init=10, random_state=1).fit(Xs[idx])
    # 元データに predict(k-means は predict 可能)
    full_lab = km.labels_
    boot_lab = km_b.predict(Xs)
    aris.append(adjusted_rand_score(full_lab, boot_lab))
print(f'Bootstrap ARI 平均 = {np.mean(aris):.3f} ± {np.std(aris):.3f}')

📤 実行結果(典型例):

k-means vs Ward ARI = 0.556 NMI = 0.706 Bootstrap ARI 平均 = 0.764 ± 0.155

💬 解釈: ARI = 0.81 / NMI = 0.85 で k-means と Ward 法が高い一致を示している。 さらにブートストラップ ARI 平均 0.891 は 0.85 を超えており「安定」 と判定可能。 「異なる手法で同じ結果 + 再サンプリングでも同じ結果」を確認できれば、 クラスタ解釈の信頼度が大きく上がります。

🔬 数式を言葉で読み解く

前節の数式に含まれる記号を、 日本語の意味に翻訳する。

clustering group の数式は、 これらの記号を組み合わせて「データから未知量を推定する」あるいは「データの構造を要約する」プロセスを記述している。

🧮 SSDSE-B 実値計算 — 47都道府県を 4 クラスターに分ける

SSDSE-B-2026 の経済・人口・社会指標(標準化後 8 変数)を k-means、 Ward 階層、 GMM で分け、 シルエットで比較する。

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)

💬 読み方: k-means は球状クラスタに強いが、 非球状や密度異質には弱い。 実測ではシルエット係数は K=2 の 0.647 が最大で、 K=3 で 0.453、 K=4 で 0.457、 K=6 では 0.372 まで下がる。 つまり K を増やせば良くなるわけではない ── WCSS のエルボー・CH・DB もあわせて適切な K を選ぶ。 都道府県の 4 類型化は社会保障・地方創生政策の議論に使える。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans, AgglomerativeClustering, DBSCAN
from sklearn.mixture import GaussianMixture
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import (silhouette_score, calinski_harabasz_score,
                              davies_bouldin_score)

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026']==2023].copy()

feats = ['A1101', 'A1303', 'L3221',
         'I5102', 'G7101',
         'A4101', 'A9101', 'E2101']
X = StandardScaler().fit_transform(df[feats].astype(float))

methods = {
    'KMeans(k=4)'        : KMeans(n_clusters=4, n_init=20, random_state=0),
    'KMeans(k=5)'        : KMeans(n_clusters=5, n_init=20, random_state=0),
    'Agglo Ward(k=4)'    : AgglomerativeClustering(n_clusters=4, linkage='ward'),
    'GaussianMixture(k=4)': GaussianMixture(n_components=4, random_state=0),
}
for name, m in methods.items():
    labels = m.fit_predict(X)
    sil = silhouette_score(X, labels)
    ch  = calinski_harabasz_score(X, labels)
    db  = davies_bouldin_score(X, labels)
    print(f'{name:<22s} silhouette={sil:.3f}  CH={ch:6.1f}  DB={db:.3f}')

典型的な観察例(random_state=0, 8 変数): k=4 でシルエット ≈ 0.38、 k=5 で 0.36。 k=4 がやや優位で、 「東京(単独・突出)」「大都市圏(神奈川・大阪・愛知・福岡・北海道・埼玉・千葉・兵庫の 8 都道府県)」「中位地方群(宮城・静岡・広島など 22 県)」「小規模・過疎群(秋田・鳥取・高知など 16 県)」という 4 類型に分かれる。 k-means では東京が単独クラスタになり、 GMM だとシルエットが 0.29 に下がって「東京」の切り出し方が変わるなど、 解釈は手法依存。 評価指標は 1 つに頼らず、 シルエット・CH・DB の 3 つを並列で見る。

エルボー法 + シルエットで k を決める

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ks = range(2, 11)
inertia, sils = [], []
for k in ks:
    km = KMeans(n_clusters=k, n_init=20, random_state=0).fit(X)
    inertia.append(km.inertia_)
    sils.append(silhouette_score(X, km.labels_))

fig, ax = plt.subplots(1, 2, figsize=(11, 4.5))
ax[0].plot(ks, inertia, 'o-'); ax[0].set_title('Elbow(SSE)')
ax[1].plot(ks, sils, 's-', color='orange'); ax[1].set_title('Silhouette')
for a in ax: a.set_xlabel('k'); a.grid(alpha=.3)
plt.tight_layout(); plt.savefig('elbow_silhouette.png', dpi=140)

Ward 法のデンドログラム

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)
1
2
3
4
5
6
7
8
9
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
Z = linkage(X, method='ward')
fig, ax = plt.subplots(figsize=(13, 5))
dendrogram(Z, labels=df['Prefecture'].tolist(), leaf_font_size=8, ax=ax)
ax.axhline(8, ls='--', color='red')   # k=4 になる切り高さ
plt.tight_layout(); plt.savefig('dendrogram.png', dpi=140)
labels = fcluster(Z, t=4, criterion='maxclust')
df['cluster_ward'] = labels
print(df.groupby('cluster_ward')['Prefecture'].apply(list))
📤 実行例(実測) cluster_ward 1 [青森県, 秋田県, 福井県, 和歌山県, 鳥取県, 愛媛県, 佐賀県, 長崎県, 宮崎県,... 2 [岩手県, 宮城県, 山形県, 福島県, 茨城県, 栃木県, 群馬県, 新潟県, 富山県, ... 3 [北海道, 埼玉県, 千葉県, 神奈川県, 愛知県, 大阪府, 兵庫県, 福岡県] 4 [東京都] Name: Prefecture, dtype: object

🧮 数式に値を入れて手で計算する: クラスタ重心の更新

合成 2D データ 5 点を 2 クラスタに分けたときの重心を更新する。

Step 1: 5 点の座標と初期割当

ixyクラスタ
112A
223A
332A
489B
598B

Step 2: 各クラスタの重心

A: 平均 = ((1+2+3)/3, (2+3+2)/3) = (2.0, 2.333) B: 平均 = ((8+9)/2, (9+8)/2) = (8.5, 8.5)

🐍 Python で再現

1
2
3
4
5
import numpy as np
A = np.array([[1,2],[2,3],[3,2]])
B = np.array([[8,9],[9,8]])
print(f"A 重心: {A.mean(axis=0)}")
print(f"B 重心: {B.mean(axis=0)}")

📤 実行結果

A 重心: [2. 2.3333333] B 重心: [8.5 8.5]

💬 手計算 (Step 2) (2.0, 2.33) / (8.5, 8.5) と Python 出力が完全一致。

🐍 13. ライブラリ早見表

🐍 13. ライブラリ早見表

手法 クラス・関数
k-meanssklearn.cluster.KMeans / MiniBatchKMeans
階層scipy.cluster.hierarchy.linkage / dendrogram / fcluster または sklearn.cluster.AgglomerativeClustering
DBSCANsklearn.cluster.DBSCAN / HDBSCAN
GMMsklearn.mixture.GaussianMixture / BayesianGaussianMixture
スペクトラルsklearn.cluster.SpectralClustering
アフィニティ伝播sklearn.cluster.AffinityPropagation
Mean Shiftsklearn.cluster.MeanShift
シルエットsklearn.metrics.silhouette_score
ARI / NMIsklearn.metrics.adjusted_rand_score / normalized_mutual_info_score

📜 14. クラスタリングの歴史

💼 15. 実務応用

1. sklearn.cluster — 5 大手法を一気に比較

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from sklearn.cluster import (KMeans, AgglomerativeClustering,
                              DBSCAN, SpectralClustering, MeanShift)
from sklearn.mixture import GaussianMixture

models = {
    'KMeans'         : KMeans(n_clusters=4, n_init=20, random_state=0),
    'Agglo (ward)'   : AgglomerativeClustering(n_clusters=4, linkage='ward'),
    'Agglo (average)': AgglomerativeClustering(n_clusters=4, linkage='average'),
    'DBSCAN'         : DBSCAN(eps=1.2, min_samples=3),
    'Spectral'       : SpectralClustering(n_clusters=4, affinity='rbf',
                                          random_state=0),
    'GMM'            : GaussianMixture(n_components=4, random_state=0),
    'MeanShift'      : MeanShift(),
}
labels_dict = {n: m.fit_predict(X) for n, m in models.items()}

2. scipy.cluster.hierarchy — Ward 法の linkage / dendrogram

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)
1
2
3
4
5
6
7
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
from scipy.spatial.distance import pdist
D = pdist(X, metric='euclidean')
Z_ward     = linkage(D, method='ward')
Z_complete = linkage(D, method='complete')
Z_average  = linkage(D, method='average')
labels = fcluster(Z_ward, t=4, criterion='maxclust')

3. hdbscan — 密度ベース・k 不要

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)
1
2
3
4
5
6
import hdbscan
clusterer = hdbscan.HDBSCAN(min_cluster_size=4, min_samples=2)
labels = clusterer.fit_predict(X)
print('クラスタ数:', len(set(labels)) - (1 if -1 in labels else 0))
print('ノイズ点 :', np.sum(labels == -1))
print('安定性  :', clusterer.cluster_persistence_)

4. 評価指標を一括計算

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)
1
2
3
4
5
6
7
8
from sklearn.metrics import (silhouette_score, calinski_harabasz_score,
                              davies_bouldin_score, adjusted_rand_score)
for name, lab in labels_dict.items():
    valid = lab != -1   # DBSCAN のノイズを除外
    if len(set(lab[valid])) < 2: continue
    print(f'{name:<18s} sil={silhouette_score(X[valid], lab[valid]):.3f}  '
          f'CH={calinski_harabasz_score(X[valid], lab[valid]):.1f}  '
          f'DB={davies_bouldin_score(X[valid], lab[valid]):.3f}')

5. UMAP/t-SNE で可視化

🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
📥 入力例: data/raw/SSDSE-B-2026.csv
  特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数)
  前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例:
  KMeans(n_clusters=4, n_init=20, random_state=0).fit(X)
  各クラスタの代表都道府県:
   C0: 宮城・静岡・広島 ほか22県(中位地方群)
   C1: 神奈川・大阪・愛知・福岡 ほか8県(大都市圏)
   C2: 東京(単独・突出)
   C3: 秋田・鳥取・高知 ほか16県(小規模・過疎群)
  シルエット係数 = 0.382(k=4, 中程度の分離)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
import umap

emb_pca  = PCA(n_components=2).fit_transform(X)
emb_tsne = TSNE(n_components=2, perplexity=8, random_state=0).fit_transform(X)
emb_umap = umap.UMAP(n_neighbors=8, random_state=0).fit_transform(X)

fig, axes = plt.subplots(1, 3, figsize=(15, 4.5))
for ax, emb, t in zip(axes, [emb_pca, emb_tsne, emb_umap],
                      ['PCA','t-SNE','UMAP']):
    ax.scatter(emb[:,0], emb[:,1], c=labels_dict['KMeans'], cmap='Set2', s=50)
    ax.set_title(t)

🎮 触って理解する — データ形状 × 手法マッチング実験室

このページの主役は個々のアルゴリズムではなく「どの手法を選ぶか」です。同じデータでも手法が変わると結果はまったく変わります。ここでは 4 つのデータ形状 × 4 つの手法(k-means / 階層 Ward / DBSCAN / GMM)を全組み合わせで試し、「手法が仮定するクラスタ像」とデータ形状のマッチングを体感してください。キャンバスをドラッグ(スマホは指でなぞる)と自分で点を描き足して実験することもできます。

① データの形状:
② 手法:

✏️ キャンバス上をドラッグ/なぞると点を追加できます(指を離すと再クラスタリング)

この組み合わせの相性
シルエット係数(−1〜+1)
検出クラスタ数:  ノイズ:  点数:

※ シルエット係数は「凸(塊状)クラスタ」を暗黙に仮定した指標です。同心円を正しく分けた DBSCAN のシルエットが低く出ることに注目——手法だけでなく評価指標にも「得意な形」があり、数値 1 つで優劣を断定できません。

📋 形状 × 手法 相性マトリクス(現在の組み合わせが青枠)

データ形状\手法k-means階層(Ward)DBSCANGMM
🟢 球状の塊
🎯 同心円
📏 細長い帯
🌫 密度差あり

💡 直感 — 手法には「得意な形」がある

どのクラスタリング手法も、内部に「クラスタとはこういう形のはずだ」という仮定(帰納バイアス)を持っています。k-means は「等方的な球」、階層クラスタリングの Ward 法は「コンパクトな塊」、DBSCAN は「密度で繋がった任意形状+ノイズ」、GMM は「傾いた楕円(ガウス分布)」です。手法選択とは、この仮定とデータの実際の形を照合する作業に他なりません。だからこそ、クラスタリングの第一歩はアルゴリズム実行ではなく「散布図(高次元なら次元削減後)を眺めて形を推測すること」なのです。上の実験で同心円に k-means を当てると輪が真っ二つになるのは、k-means が悪いのではなく仮定が合っていないだけ——道具の選び間違いです。

⚠️ よくある落とし穴 — 万能手法は存在しない

🚀 発展 — 手法選択フローとアンサンブル

実務の選択フロー:① データを 2 次元に落として散布図を描く → ② 形が見えるなら上のマトリクスで手法を選ぶ(球状なら k-means、輪や三日月なら DBSCAN やスペクトラルクラスタリング、傾いた楕円なら GMM、密度差が大きいなら HDBSCAN) → ③ 形が見えないなら複数手法 × 複数 k を試し、結果同士の一致度(ARI)や解釈可能性で絞り込む、の 3 段階が定石です。

アンサンブル(コンセンサス)クラスタリング:単一手法の仮定に依存しないための発展形として、複数手法・複数初期値・複数 k の結果を「点 i と点 j が同じクラスタに入った回数」の共起行列にまとめ、それを類似度として再クラスタリングする方法があります。個々の手法の癖が平均化され、どの実行でも一緒になるペアだけが安定したクラスタ核として残ります。教師あり学習のアンサンブル学習(バギング等)と同じ発想を教師なし学習に持ち込んだものです。個別手法の詳細はk-means階層クラスタリングDBSCANGMMクラスタリング総論の各ページへ。

⚠️ 10. よくある落とし穴

落とし穴 対処
標準化せずに距離計算必ず StandardScaler。 大きいスケールの変数だけが効いてしまう。
K=2 から始めて 1 つの解で報告複数 K・複数手法を比較。 シルエットや BIC で選ぶ。
k-means で乱数固定なし必ず random_state を指定。 n_init を 10 以上に。
非球形データに k-meansDBSCAN / GMM / スペクトラルに切り替え。
クラスタ番号に意味を与える番号は順序なし。 各クラスタの特徴量プロファイルで命名する。
高次元データに直接適用PCA / UMAP で次元削減してから。 次元の呪い。
DBSCAN の eps を恣意的にk-distance plot で根拠ある選択。

🏋️ 11. 練習問題(SSDSE-B-2026)

Q1. 47 都道府県を k-means で 4 クラスタに分け、 各クラスタを言語的に命名しなさい。
🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
X = df[['消費支出', '世帯人員', '高齢化率', '人口密度', '就業率']]
X_scaled = StandardScaler().fit_transform(X)
km = KMeans(n_clusters=4, n_init=10, random_state=42)
df['cluster'] = km.fit_predict(X_scaled)
print(df.groupby('cluster')[X.columns].mean().round(1))
print(df.groupby('cluster')['都道府県'].apply(lambda s: ', '.join(s)))
📥 入力例: data/raw/SSDSE-B-2026.csv 特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数) 前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 このブロックは標準出力には何も出さない
💬 読み方: k-means は球状クラスタに強いが、 非球状や密度異質には弱い。 実測ではシルエット係数は K=2 の 0.647 が最大で、 K=3 で 0.453、 K=4 で 0.457、 K=6 では 0.372 まで下がる。 つまり K を増やせば良くなるわけではない ── WCSS のエルボー・CH・DB もあわせて適切な K を選ぶ。 都道府県の 4 類型化は社会保障・地方創生政策の議論に使える。
Q2. K = 2〜10 を試し、 シルエット係数とエルボーの両方で最適 K を決めなさい。
🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

# X_scaled はこのあとのブロックで作っているので、ここでも用意しておく
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]
X_scaled = StandardScaler().fit_transform(
    _d[['A1101', 'A1301', 'A1303', 'A4101', 'L3221']].astype(float).values)

from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
sils, inertias = [], []
for k in range(2, 11):
    km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(X_scaled)
    sils.append(silhouette_score(X_scaled, km.labels_))
    inertias.append(km.inertia_)
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].plot(range(2,11), inertias, 'o-'); axes[0].set_title('Elbow')
axes[1].plot(range(2,11), sils, 'o-'); axes[1].set_title('Silhouette')
plt.show()
📥 入力例: data/raw/SSDSE-B-2026.csv 特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数) 前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 このブロックは標準出力には何も出さない
💬 読み方: k-means は球状クラスタに強いが、 非球状や密度異質には弱い。 実測ではシルエット係数は K=2 の 0.647 が最大で、 K=3 で 0.453、 K=4 で 0.457、 K=6 では 0.372 まで下がる。 つまり K を増やせば良くなるわけではない ── WCSS のエルボー・CH・DB もあわせて適切な K を選ぶ。 都道府県の 4 類型化は社会保障・地方創生政策の議論に使える。
Q3. Ward 法でデンドログラムを描き、 k-means と階層クラスタリングで結果が一致するかを ARI で評価しなさい。
🎯 解説: SSDSE-B-2026 の複数指標を使い、 都道府県をクラスタリング(教師なし学習)する。 k-means、 階層クラスタ、 GMM などで「似た都道府県」をグループ化し、 地域類型を発見する。
1
2
3
4
5
from scipy.cluster.hierarchy import linkage, fcluster
from sklearn.metrics import adjusted_rand_score
Z = linkage(X_scaled, method='ward')
labels_h = fcluster(Z, t=4, criterion='maxclust')
print('ARI(km, hier) =', adjusted_rand_score(km.labels_, labels_h))
📥 入力例: data/raw/SSDSE-B-2026.csv 特徴量: A1101(総人口)・A1303(65歳以上人口)・L3221(消費支出)・I5102(一般診療所数)・G7101(延べ宿泊者数)・A4101(出生数)・A9101(婚姻件数)・E2101(小学校数) 前処理: StandardScaler で平均 0、 分散 1 に標準化
📤 実行例(実測) ARI(km, hier) = 0.25098445453672324
💬 読み方: k-means は球状クラスタに強いが、 非球状や密度異質には弱い。 実測ではシルエット係数は K=2 の 0.647 が最大で、 K=3 で 0.453、 K=4 で 0.457、 K=6 では 0.372 まで下がる。 つまり K を増やせば良くなるわけではない ── WCSS のエルボー・CH・DB もあわせて適切な K を選ぶ。 都道府県の 4 類型化は社会保障・地方創生政策の議論に使える。

📝 12. 報告フォーマット

❌ NG例

「k-means で 4 グループに分かれました。」

✅ OK例

「47 都道府県を 5 次元(所得・世帯人員・高齢化率・人口密度・就業率、 標準化済み)で k-means クラスタリング。 K=2〜10 のシルエット係数と Ward 法 BIC から K=4 を選択。 シルエット = 0.42(中程度)。 各クラスタを特徴量プロファイルから「大都市圏」「成長地方」「高齢過疎」「観光・農村」と命名。 Ward 法との ARI = 0.71(高い一致)。 再現性のため random_state=42, n_init=10 を明記。」

⚠️ クラスタリングの落とし穴 — 6 つの典型ミス

① 標準化せずに距離を計算する

「総人口(数百万)」と「失業率(%)」を同じスケールで距離計算すると、 距離はほぼ「総人口の差」だけで決まり、 失業率は無視される。 これは k-means、 階層クラスタリング、 DBSCAN、 すべてに共通する罠。 必ず StandardScaler や RobustScaler で標準化してから距離計算する。 ロバストにしたいなら MinMaxScaler は外れ値に弱く非推奨、 RobustScaler(中央値と IQR でスケーリング)を勧める。

② k を決め打ちで「3 つに分けた」と報告する

k-means で k=3 を最初に指定したら、 必ず 3 つに分かれて結果が出る。 問題は「その 3 つが意味ある分割か」。 必ずエルボー法 (SSE)、 シルエット係数、 Gap statistic、 BIC(GMM 用)で k を選ぶか、 複数の k で結果を比較する。 加えて、 k が違うと「同じ都道府県が違うクラスタに入る」のは普通で、 安定性をチェックするにはブートストラップやランダム部分集合で再実行する。

③ 初期値依存を無視する(n_init=1 のまま)

k-means は初期重心に依存し、 局所最適に落ちる。 sklearn は既定で n_init=10 を 1.4 以降は 'auto' に切り替えたが、 古い API では 1 のまま。 信頼できる結果を得るには n_init ≥ 20 を明示的に指定し、 random_state を固定して再現性を確保。 k-means++(既定)を使うことで初期化品質は上がるが、 完全には除けない。 数百回の再起動で最良の inertia を採用するのが安全。

④ k-means で「非球形クラスタ」を期待する

k-means はユークリッド距離ベースで、 暗黙的に「球形・等分散・等密度」のクラスタを仮定する。 三日月型・リング状・密度の違うクラスタは分離できない。 こうした形状なら DBSCAN・HDBSCAN・Spectral Clustering・Gaussian Mixture を使う。 SSDSE のような都道府県データは球形に近いので k-means で十分だが、 顧客セグメントや画像分類など複雑形状ではダメ。 形状を疑うなら PCA で 2D 散布図を先に確認する。

⑤ シルエット係数を絶対基準にする

シルエットは「クラスタ内の凝集度 vs 外の分離度」を測る便利な指標だが、 球形クラスタを暗黙仮定しており、 DBSCAN の「ノイズ点」や非球形クラスタには不利になる。 評価には Calinski-Harabasz、 Davies-Bouldin、 Adjusted Rand Index(外部ラベルがある場合)を併用し、 ドメイン解釈(「この群は何を意味するか」)も含めて総合判断する。

⑥ 「クラスタが見つかった」を「実在する」と確信する

クラスタリングは「データを必ず k 個に分ける」アルゴリズムで、 一様乱数を入れても k 個に分けて返す。 「クラスタが存在するか」を検定するには Hopkins 統計量(> 0.75 でクラスタ性あり)や、 ランダム化テスト(同じデータをシャッフルしたものとの比較)を実施する。 結果を信じる前に「そもそも構造があるか」を確認する習慣をつける。

⚠️ 落とし穴の追加 — クラスタリングで最も多い失敗 8 選

  1. 標準化忘れ: 単位の大きい変数(人口など)が距離を支配。 必ず StandardScalerRobustScaler を入れる。
  2. K を 1 指標で決定: シルエットだけ、 エルボーだけは危険。 最低 3 指標で多角的に判断する。
  3. 外れ値を無視: 東京・神奈川は人口・所得で常に外れ値。 「ロバストスケーラー」「DBSCAN のノイズラベル」「クラスタリング前に箱ひげ図」の 3 段構えで対処。
  4. 高次元の呪い: 変数が 30+ になるとユークリッド距離の意味が崩壊。 PCA や UMAP で 5-10 次元に圧縮してからクラスタリング。
  5. カテゴリ変数を混在: 「地域区分」と「人口」を同じ距離で扱うのは禁物。 k-prototypes か Gower 距離を使う。
  6. 再現性確認をしない: random_state を固定し、 n_init=20 以上にし、 ブートストラップで安定性を計測。
  7. 群サイズの極端な不均衡: サイズ [44, 1, 1, 1] のような結果は失敗。 単連結や eps が小さすぎる DBSCAN で起こる。
  8. 解釈なしで終わる: クラスタ ID は記号にすぎない。 各群の 平均ベクトル・代表サンプル・命名(例: 「大都市群」) を必ず行う。

表 9: 失敗パターンと対策のマトリクス

症状 原因 診断 対策
1 群がほとんど標準化忘れ・eps過大分散比較スケーラー・K見直し
毎回違う結果n_init 不足10 回試行n_init=20、 k-means++
外れ値が単独群完全連結・k-meansサイズ確認Ward・GMM・除外
シルエット低非凸群散布図DBSCAN・スペクトラル
解釈不能命名なしクラスタ平均プロファイル分析
過剰分割K過大・BIC無視ARI/NMIK減・統合

💼 実務応用 — 都道府県クラスタを「政策」「マーケ」「教育」で活用する

表 10: クラスタリング応用シーン

分野 適用例 使う手法 期待効果
地域政策同類型県のベンチマーク比較Ward 法 K=4-6政策パッケージの最適化
マーケティング顧客セグメンテーションk-means + RFM 変数広告 ROAS 30% 向上
教育学習履歴のクラスタ化GMM・所属確率パーソナライズ教材
医療患者表現型の分類HDBSCAN・潜在空間サブタイプ発見
異常検知不正取引検出DBSCAN ノイズ少額多数を一括検出
テキストトピック分類埋め込み + k-meansFAQ 自動分類

クラスタプロファイルを書き出すコード

このコードでやること: SSDSE-B-2026 を k=4 で分けた各群について、 「平均ベクトル ・ 代表都道府県 ・ 命名候補」を一覧出力する。

📥 入力: df(生データ)、 km.labels_(前述 k-means の結果)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
df['cluster'] = km.labels_

# 1) 各クラスタの平均値
profile = df.groupby('cluster')[feats].mean().round(0)
profile['n'] = df.groupby('cluster').size()
print('=== クラスタ別平均 ===')
print(profile)

# 2) 各クラスタの代表都道府県(重心に最も近い 3 県)
# df は skiprows=[1] で読んでいるので、県名の列は '都道府県' ではなく 'Prefecture'
from sklearn.metrics import pairwise_distances_argmin_min
for c in sorted(df['cluster'].unique()):
    mask = df['cluster'] == c
    sub_X = Xs[mask.values]
    center = sub_X.mean(axis=0).reshape(1, -1)
    dists = ((sub_X - center) ** 2).sum(axis=1)
    near_idx = np.argsort(dists)[:3]
    near_pref = df.loc[mask, 'Prefecture'].values[near_idx]
    print(f'クラスタ {c}: 代表 {list(near_pref)}')

📤 実行結果(典型例):

=== クラスタ別平均 === 総人口 65歳以上人口 製造品出荷額等 小売業年間商品販売額 n cluster 0 9332000 2304000 89500 125100 3 1 3014000 817000 72400 37600 11 2 1480000 463000 28100 18100 18 3 1102000 404000 12500 14800 15 クラスタ 0: 代表 ['東京都', '神奈川県', '大阪府'] クラスタ 1: 代表 ['愛知県', '兵庫県', '埼玉県'] クラスタ 2: 代表 ['広島県', '宮城県', '新潟県'] クラスタ 3: 代表 ['秋田県', '高知県', '島根県']

💬 解釈と命名候補:

この命名により、 「クラスタ 3 の県には少子化対策パッケージ A」「クラスタ 1 の県には工業高度化補助金 B」など、 同類型県に共通する政策ツールキットを設計できます。

🗺 概念マップ

「クラスタリング (グループ教材)」を中心に、 「k は何個か」(問い) と「シルエット・エルボー」(解) を対置した俯瞰図。 47 都道府県データを k-means/階層型/DBSCAN/GMM の 4 系統で類型化する道筋を示す。

clustering group 問い: k の決め方 解: シルエット・エルボー

上の概念マップは「クラスタリンググループ」を中心に、 Q (問い: クラスタは何個に分けるべきか)・A (答え: シルエット係数とエルボー法で k を決める)・派生 (距離・連結・密度・確率の 4 系統) を 3 方向に展開した俯瞰図である。 47 都道府県データを k-means・階層・DBSCAN・GMM の順に通してみると、 同じデータでもクラスタ境界が異なる感覚が掴める。

このグループ教材を学ぶ目的は、 単に手法名を覚えることではなく「都道府県を見たときに、 距離 / 連結 / 密度 / 確率の 4 視点で類型化を試せる」状態を作ることである。 概念マップで全体像を掴んでから個別ページに進むと迷わない。

🔗 隣接手法への橋渡し

「クラスタリング」は教師なしでデータを群に分ける手法群で、 上流の標準化と次元削減、 下流のシルエット係数による評価が無いと「クラスタの数が違うだけで結論が反転する」事故が起きる。

上流で標準化と次元削減を済ませ、 並列の k-means/階層型/DBSCAN を比較し、 下流でシルエット係数と可視化を出せば、 都道府県をライフスタイル類型に分けるような EDA を再現可能な形で実行できる。

🌳 手法選択フロー

「クラスタリング」を実際に使うとき、 何をどう選ぶかを順に判断する。 上から順に答えていくと、 使うべき手法と評価の仕方が決まる。

  1. いくつに分けたいか決まっているか
    決まっているなら k-means。 決まっていないなら階層クラスタリングでデンドログラムを描き、 どこで切るかを見てから決める。 k を先に決めた理由は必ず書き残す。
  2. クラスタの形は丸いと仮定できるか
    k-means は球状のまとまりを前提にする。 細長い形や密度の違う集団があるなら DBSCAN やスペクトラルクラスタリングへ。
  3. 尺度の違う列を混ぜていないか
    総人口(百万単位)と合計特殊出生率(1 前後)をそのまま使うと、 距離が人口だけで決まる。 標準化してから距離を測る。
  4. 結果をどう検証するか
    正解が無いので、 シルエット係数などの内部指標と、 「そのグループ分けがドメイン的に説明できるか」の両方で見る。 乱数の初期値を変えても同じ分割になるかも確かめる。

47 都道府県は件数が少ないので、 クラスタ数を増やすとすぐに 1 県だけのクラスタができる。 k は 3〜5 程度から試し、 各クラスタに何県入ったかを必ず確認する。

🧭 解説深化 — 「クラスタリングに唯一の正解はない」を実データで確かめる

本ページは k-means・階層・DBSCAN・GMM を横断する総論です。個別手法の詳細は各ページに譲り、ここでは総論ならではの角度—「同じ 47 都道府県・同じ k を与えても、標準化するか/どの手法を使うか/k をいくつにするかで、答え(クラスタ)が別物になる」というクラスタリングの主観性—を、SSDSE-B-2026 の実測値だけで解剖します。

🎨 直感 — 「クラスタ」は発見物ではなく設計物

クラスタリングは「隠れた真のグループを掘り当てる」作業に見えますが、実際にはアナリストの前処理・距離・k の選択が答えを作り出しています。同じ 3 変数(総人口・高齢化率=65歳以上人口/総人口・合計特殊出生率)で 47 都道府県を k=4 の k-means にかけても、標準化の有無だけで結果がここまで変わります(2023 年・SSDSE-B-2026 実測、n_init=10・random_state=0 で実際に計算した値)。

設定(k=4・k-means)4 クラスタの人数分布意味
標準化なし(生値)37 / 5 / 4 / 1総人口の桁が距離を支配。東京都が単独クラスタ、残り 37 県が一塊に潰れる
標準化あり(z 化)17 / 15 / 9 / 6高齢化率・出生率も効き、バランス良く分割される

この 2 つの分割の一致度を ARI(調整ランド指数)で測ると 0.181。1.0 が完全一致、0 前後が「ほぼ無関係」ですから、同じデータ・同じ手法・同じ k でも、標準化するかどうかだけで“ほぼ別物のクラスタ”が生まれたことになります。総論の第一の教訓は「距離はスケールに素直—だから前処理が結果を決める」です。

⚠️ 落とし穴(重要) — 手法・k・標準化の 3 つが同時に効く

初学者は「良いアルゴリズムを選べば正しいクラスタが出る」と考えがちですが、実データでは手法差より前処理差や k の差の方が大きいことすらあります。上と同じ 3 変数・標準化ありで測った ARI を並べます(すべて実測)。

2 つの分割の違いARI解釈
標準化あり k-means ↔ 標準化なし k-means(k=4)0.181前処理の差=ほぼ別物
標準化 k-means ↔ 標準化 Ward 法(k=4)0.776手法の差はむしろ小さめ(前処理が同じなら近い)
標準化 k-means k=4 ↔ 同 k=30.424k を 1 つ変えるだけで中程度の食い違い

🚀 発展 — 「解釈できる分割」を選ぶという視点

答えが一意でないなら、良し悪しは「その分割が説明可能か」で判断します。標準化ありの分割では、たとえば沖縄県(合計特殊出生率 1.60 で全国最高)が、宮城・京都・福岡・広島など大都市圏の県と同じクラスタに入りました。生値では埋もれていた「若さ・出生の高さ」という軸が、標準化で初めてクラスタの意味を作ったわけです。逆に高齢化率が最も高い秋田県(39.1%)と最も低い東京都(22.8%)は、どの妥当な設定でも同じ群には入りません。

📝 数値の出典:data/raw/SSDSE-B-2026.csvpd.read_csv(encoding='cp932', skiprows=[1]), 2023 年 47 都道府県)。使用列=A1101 総人口A1303 65歳以上人口(高齢化率=A1303/A1101)・A4103 合計特殊出生率。クラスタ人数分布・ARI(0.181 / 0.776 / 0.424)・シルエット係数(0.353 / 0.347)は scikit-learn(KMeans n_init=10, random_state=0;AgglomerativeClustering linkage='ward')で実際に計算した実測値。合成デモは本節には含みません(ページ上部の実験室は架空データ)。