論文で「クラスタリング」「クラスタ分析」「教師なし学習で分類」と書かれているとき。 「47都道府県を似ているグループに自動分類」「顧客を購買行動で分類」など、 ラベルなしデータから自然なグループ構造を発見する手法の総称。
クラスタリング とは:教師ラベルなしで、似たサンプル同士をグループ(クラスタ)に分ける手法の総称。
sklearn.cluster に各種手法が実装されているクラスタリング(clustering)は、 「似たサンプル同士を自動でグループ化する」教師なし学習の代表的タスク。 「正解ラベル」を一切与えず、 データの内部構造をアルゴリズムが自力で発見します。
教師あり学習との違い:
クラスタリングは「データの中に自然なグループはあるか?あるならどんな?」という探索的な問いに使います。 正解がないので、 結果の「正しさ」を評価するのが難しい一方、 仮説生成・データの初期理解で強力な道具になります。
クラスタリング手法は次の4大カテゴリに分かれます:
| 分類 | 仕組み | 代表例 | 向くデータ |
|---|---|---|---|
| 分割型(partitional) | k個の中心への距離で分割 | k-means, k-medoids | 球形クラスタ、 大規模 |
| 階層型(hierarchical) | 点を段階的に結合 or 分割 | Ward法, 単連結, 完全連結 | 中規模、 階層構造あり |
| 密度ベース | 密な領域をクラスタとみなす | DBSCAN, OPTICS, Mean Shift | 非球形、 ノイズあり |
| モデルベース | 確率分布の混合と仮定 | GMM, EM, ベイズクラスタ | 確率的所属、 重なり許容 |
クラスタリングの中核は「2つのサンプルがどれだけ似ているか」の数値化。 これを「距離」(または類似度)と呼びます:
選択の指針:
単位の違う変数を混ぜると、 桁の大きい変数だけで距離が決まり、 他の変数の情報が消えます。 例えば「人口(万人)」と「失業率(%)」をユークリッド距離で測れば、 人口の差が圧倒的に大きいため、 結果は実質「人口」だけでクラスタリングしたものに。
対策:必ず標準化(z-score化)してから距離計算。 sklearn.preprocessing.StandardScaler で平均0・分散1に揃える。 これで全変数が「平等」に効く。
k-means のような分割型では「何個のクラスタに分けるか」を事前に決める必要があります。 客観的指標:
「死亡率」「高齢化率」「保健医療費」「転入率」の4変数で47都道府県を k-means(k=4)でクラスタリングすると、 典型的に次のような結果になります:
これがクラスタリングの典型的な使い方。 「データ駆動で47都道府県を4類型に分類した」という客観的根拠として、 政策資料に使えます。
「正解」がないので、 結果の良さを評価するのが難しい。 主な評価手法:
内部評価(ラベルなしで評価):
外部評価(真のラベルがある場合):
解釈の難しさ:クラスタが見つかっても、 「なぜそうグルーピングされたか」「各クラスタの特徴は何か」は別途分析が必要。 クラスタごとの変数の平均値・標準偏差・代表サンプルを確認するのが定石。

図は典型的なクラスタリング結果。 4つの「自然なグループ」がデータから自動的に発見されています。 各クラスタには地理的・経済的に類似した県が集まり、 「データ駆動の分類」として解釈可能。
大事なポイント:このクラスタは「用意した変数(死亡率、 高齢化率)に基づく類似度」での分類。 違う変数(例えば気温や産業構造)で実行すれば、 違う分類が出ます。 「絶対的な真の分類」ではなく、 「分析者の選択を反映した類型化」なのが本質。
「どの手法を使うべきか」迷ったときの判断フロー:
① クラスタ数が事前に決まっているか?
② データの形状は球形に近いか?
③ ノイズや外れ値が多いか?
④ サンプル数は?
⑤ 結果の階層構造を見たいか?
⑥ 確率的な所属(「東京は60%大都市、 40%中核」)が欲しいか?
1つの手法だけで結論を出さず、 複数手法で結果を比較し、 安定して同じグループが出るなら信頼性が高い。 「k-means と Ward法 で同じクラスタ構造が見えた」のような頑健性チェックが論文の品質を上げます。
クラスタリングには本質的な限界もあります:
これらの限界を意識した上で、 「データを整理する道具」として使うのが正しい使い方。 「客観的真実を発見する魔法」ではない。
クラスタリング(clustering)は、 ラベルなしのデータを類似度に基づいて自動的にグループ分けする教師なし学習の一種。 「47都道府県を、 家計の似た傾向でグループ化」のような問題。
「k個に分ける」とあらかじめ決めて最適化。 代表:k-means、 k-medoids、 ファジー C-means。 計算は高速。
近いペアから順にまとめていく(凝集型)、 または大きく分割(分割型)。 結果がデンドログラムに。 任意の数のクラスタが取れる。 代表:Ward法、 群平均法。
「密度が高い領域がクラスタ」と考える。 代表:DBSCAN、 HDBSCAN、 OPTICS。 任意の形状を捉え、 ノイズ判別もできる。
| 距離 | 公式 | 使い時 |
|---|---|---|
| ユークリッド距離 | √Σ(xᵢ-yᵢ)² | 標準。 連続値 |
| マンハッタン距離 | Σ|xᵢ-yᵢ| | 高次元、 ロバスト |
| マハラノビス距離 | √((x-μ)ᵀΣ⁻¹(x-μ)) | 変数の相関を考慮 |
| コサイン距離 | 1 - cos(x, y) | テキスト、 ベクトル空間 |
| Jaccard 距離 | 1 - |X∩Y|/|X∪Y| | 集合データ |
クラスタ内分散の合計(inertia)を k に対してプロット。 折れ目(elbow)が最適 k。
各点が自クラスタ内でどれだけ凝集し、 他クラスタからどれだけ離れているかを測る。 1に近いほど良い。
ランダムデータと比較して「実データの方がクラスタ構造が強い」かを定量化。
業務的に「3地区に分けたい」「5セグメントが必要」と決まっている場合は、 それを優先する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from sklearn.cluster import KMeans, AgglomerativeClustering, DBSCAN from sklearn.preprocessing import StandardScaler from sklearn.metrics import silhouette_score import pandas as pd import numpy as np # データの標準化(重要!) scaler = StandardScaler() X_std = scaler.fit_transform(X) # k-means km = KMeans(n_clusters=3, random_state=0, n_init=10) labels_km = km.fit_predict(X_std) print(f'クラスタ中心: {km.cluster_centers_}') print(f'inertia: {km.inertia_}') # 階層クラスタリング(Ward法) agg = AgglomerativeClustering(n_clusters=3, linkage='ward') labels_agg = agg.fit_predict(X_std) # シルエットスコアで評価 score = silhouette_score(X_std, labels_km) print(f'シルエットスコア: {score:.3f}') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import matplotlib.pyplot as plt inertias = [] silhouettes = [] for k in range(2, 11): km = KMeans(n_clusters=k, random_state=0, n_init=10).fit(X_std) inertias.append(km.inertia_) silhouettes.append(silhouette_score(X_std, km.labels_)) # エルボー法 plt.subplot(1, 2, 1) plt.plot(range(2, 11), inertias, 'o-') plt.xlabel('k'); plt.ylabel('inertia') # シルエット法 plt.subplot(1, 2, 2) plt.plot(range(2, 11), silhouettes, 'o-') plt.xlabel('k'); plt.ylabel('Silhouette') |
1 2 3 4 5 6 | from scipy.cluster.hierarchy import linkage, dendrogram Z = linkage(X_std, method='ward') plt.figure(figsize=(14, 6)) dendrogram(Z, labels=labels, leaf_rotation=90) plt.show() |
クラスタリング がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 教師なし学習 › クラスタリング › クラスタリング
中心の概念から放射状に、 前提・兄弟・発展形・応用先などの関係性を矢印で結びます。 横の繋がりを見るのに最適。 ノードをドラッグ、 ホイールでズーム、 クリックで遷移。
大きな円が小さな円を包含する Circle Packing 図。 「クラスタリング」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「クラスタリング」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 ジャストインタイム学習のヒント:3つの視点を行き来することで、 概念を多角的に理解できます。 包含マップやツリーマップはズーム/ドリルダウンで大分類から細部まで探索できます。
クラスタリング 関連の補強キーワード。 クリックで該当箇所へ:
47 都道府県を経済指標 5 次元でクラスタリングし、 地域類型を抽出する完全例。 標準化+ k-means/階層/DBSCAN を比較。
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 30 | import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans, AgglomerativeClustering, DBSCAN from sklearn.preprocessing import StandardScaler from sklearn.metrics import silhouette_score from sklearn.decomposition import PCA df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) features = ['一人当たり県民所得','世帯人員','高齢化率','人口密度','就業率'] X = StandardScaler().fit_transform(df[features]) # エルボー法 inertias, silhouettes = [], [] ks = range(2, 11) for k in ks: km = KMeans(n_clusters=k, random_state=42, n_init=10).fit(X) inertias.append(km.inertia_) silhouettes.append(silhouette_score(X, km.labels_)) fig, axes = plt.subplots(1, 2, figsize=(11, 4)) axes[0].plot(ks, inertias, 'o-'); axes[0].set_xlabel('k'); axes[0].set_ylabel('Inertia (SSE)') axes[1].plot(ks, silhouettes, 'o-'); axes[1].set_xlabel('k'); axes[1].set_ylabel('Silhouette') plt.tight_layout(); plt.savefig('cluster_elbow.png', dpi=110) # 最適 k=4 で確定 km = KMeans(n_clusters=4, random_state=42, n_init=10).fit(X) df['cluster'] = km.labels_ print('クラスタごとの代表値:') print(df.groupby('cluster')[features].mean()) |
| 項目 | 値 | 参考 | 解釈 |
|---|---|---|---|
| k | Inertia | Silhouette | 解釈 |
| 2 | 180 | 0.32 | 都市/地方 二分 |
| 3 | 140 | 0.34 | 都市/中間/地方 |
| 4 | 115 | 0.36 | 最適 |
| 5 | 100 | 0.33 | 細分化(過剰) |
| クラスタ0 | 東京・大阪 | 高密度・低持家 | 大都市圏 |
| クラスタ1 | 愛知・神奈川 | 中密度・中所得 | 工業圏 |
| クラスタ2 | 北海道・新潟 | 低密度・高齢化 | 地方 |
👉 値は SSDSE-B-2026 の典型値。 同じ手順で他都道府県・他変数にも適用可能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from sklearn.cluster import KMeans, DBSCAN from sklearn.mixture import GaussianMixture from sklearn.metrics import silhouette_score, adjusted_rand_score # 複数手法の比較 results = {} for name, model in [ ('KMeans-k4', KMeans(n_clusters=4, random_state=42, n_init=10)), ('GMM-k4', GaussianMixture(n_components=4, random_state=42)), ('DBSCAN', DBSCAN(eps=1.2, min_samples=3)), ('Hierarchical', AgglomerativeClustering(n_clusters=4, linkage='ward')), ]: labels = model.fit_predict(X) if len(set(labels)) > 1 and -1 not in labels: sil = silhouette_score(X, labels) results[name] = (labels, sil) print(f'{name:18} Silhouette = {sil:.3f}') # 手法間の一致度 km_lab = results['KMeans-k4'][0] for name in ['GMM-k4', 'Hierarchical']: if name in results: ari = adjusted_rand_score(km_lab, results[name][0]) print(f'KMeans vs {name}: ARI = {ari:.3f}') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from scipy.cluster.hierarchy import linkage, dendrogram, fcluster from scipy.spatial.distance import pdist import matplotlib.pyplot as plt # 階層クラスタリング + デンドログラム Z = linkage(X, method='ward') fig, ax = plt.subplots(figsize=(14, 5)) dendrogram(Z, labels=df['都道府県'].values, leaf_rotation=90, ax=ax) ax.axhline(y=8, color='r', linestyle='--', label='切り捨て位置 (k=4)') ax.legend(); plt.tight_layout() plt.savefig('dendrogram.png', dpi=110) # 階層から flat なクラスタを取り出す labels_hier = fcluster(Z, t=4, criterion='maxclust') print('階層クラスタリング結果:', np.bincount(labels_hier)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import optuna from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score # クラスタ数 + アルゴリズムを最適化 def objective(trial): algo = trial.suggest_categorical('algo', ['kmeans', 'ward', 'gmm']) k = trial.suggest_int('k', 2, 8) if algo == 'kmeans': m = KMeans(n_clusters=k, random_state=42, n_init=10) elif algo == 'ward': m = AgglomerativeClustering(n_clusters=k, linkage='ward') else: m = GaussianMixture(n_components=k, random_state=42) labels = m.fit_predict(X) if len(set(labels)) > 1: return -silhouette_score(X, labels) return 0 study = optuna.create_study(direction='minimize') study.optimize(objective, n_trials=30) print('Best:', study.best_params, ' Silhouette:', -study.best_value) |
| ライブラリ / 関数 | 用途 |
|---|---|
sklearn.cluster.KMeans | 最も標準的 |
sklearn.cluster.AgglomerativeClustering | 階層クラスタリング |
sklearn.cluster.DBSCAN | 密度ベース |
scipy.cluster.hierarchy | デンドログラム描画 |
hdbscan | 階層 DBSCAN |
yellowbrick.cluster | シルエット可視化 |
「クラスタリング」を理解するうえで必要なキーワードを 10 件以上提示します。 各チップから対応セクションへ移動できます。
30 秒結論 文脈 直感 数式 記号読み解き 実値計算 Python 実装 落とし穴 関連手法 関連用語 グループ教材 概念マップ
このセクションは「クラスタリング」を扱う 用語ページ です。 統計データ分析コンペティション(2026)の再現教材における中核用語のひとつで、47都道府県の人口・所得・失業率を用いたクラスタ分析 という観点で SSDSE-B-2026(47 都道府県 × 複数年 × 100 超列)に紐づけられます。
位置づけ:相関・線形回帰・仮説検定 といった基礎用語群と並列であり、応用としては 内生性・IV・DID・クラスタリング 等へ繋がります。
クラスタリング を一言でいえば「47都道府県の人口・所得・失業率を用いたクラスタ分析」。 47 都道府県という小さな母集団でも、 SSDSE-B-2026 の A1101 列に注目すると、 大都市圏と地方の差・人口規模に伴う相対比較など、 様々なパターンが見えてきます。
比喩でいうと、 クラスタリング はデータ分析の「眼鏡」のようなもの。 同じデータでも眼鏡を変えれば、 平均(中心)・分散(ばらつき)・相関(連動)・因果(影響)と、 異なる情報が浮かび上がります。 SSDSE-B-2026 を題材に、 この眼鏡をかけてみるのが本ページの狙いです。
クラスタリング の代表的な定義式は次のとおりです。
$$ \arg\min_C \sum_{k=1}^K \sum_{x \in C_k} \lVert x - \mu_k \rVert^2 $$ここで使われる記号や演算の意味は次節で言葉に翻訳します。
数式の各記号を、日本語の意味に変換します。
SSDSE-B-2026(公的統計の社会・教育系データセット、 47 都道府県 × 10 年分超 × 100 以上の列)を用いて、 「クラスタリング」を体感します。 ファイル名は SSDSE-B-2026.csv、 読み込みは下記の Python コードで行います。
import pandas as pd
# SSDSE-B-2026 を読み込む(cp932 / Shift_JIS)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
print(df.shape) # (564, 112)
print(df['SSDSE-B-2026'].unique()) # 含まれる年度
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
print(latest[['Prefecture', 'A1101', 'A4101']].head())
ここで使った中心列 A1101 は SSDSE-B-2026 における 47都道府県の人口・所得・失業率を用いたクラスタ分析 に関連する指標です。 算出例:
A1101 平均と標準偏差を求めるA1101 と A4101 の相関(線形・順位)を比較するscipy / pandas / scikit-learn / statsmodels を中心とした標準的な実装例です。 まず CSV を読み込み、 次に クラスタリング の解析を行います。
import pandas as pd
import numpy as np
from scipy import stats
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
df = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
x = df['A1101'].astype(float).values
y = df['A4101'].astype(float).values
# 基本統計量
print('n =', len(x))
print('mean(x) =', np.mean(x))
print('std(x) =', np.std(x, ddof=1))
# クラスタリング の代表的計算(用途に応じて scipy/statsmodels を切替える)
r, p = stats.pearsonr(x, y)
print(f'Pearson r = {r:.4f}, p = {p:.4g}')
rs, ps = stats.spearmanr(x, y)
print(f'Spearman rho = {rs:.4f}, p = {ps:.4g}')
用途別の追加実装:
# 標準化と簡易クラスタリングの例
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
X = df[['A1101', 'A4101']].astype(float).values
Xs = StandardScaler().fit_transform(X)
km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Xs)
df['cluster'] = km.labels_
print(df[['Prefecture', 'A1101', 'A4101', 'cluster']].head(10))
# 時系列(北海道の A1101)— 例として ARIMA 系の前処理
import statsmodels.api as sm
ts = df.sort_values('SSDSE-B-2026').groupby('SSDSE-B-2026')['A1101'].mean()
print(ts.tail())
res = sm.tsa.stattools.adfuller(ts)
print('ADF stat:', res[0], 'p:', res[1])
クラスタリング を実務で扱う際に踏みやすい落とし穴を 5 件挙げます。
本ページでは「クラスタリング」を 12 セクション(🔖 キーワード索引/💡 30 秒結論/📍 文脈/🎨 直感/📐 数式/🔬 記号読み解き/🧮 実値計算/🐍 Python 実装/⚠️ 落とし穴/🌐 関連手法/🔗 関連用語/📚 グループ教材)で完結に整理しました。 SSDSE-B-2026 を素材に、 概念の輪郭・式の意味・実装手順・典型的な失敗パターンの 4 点を最低限押さえれば、 統計データ分析コンペの現場で迷わず使えるはずです。