🍰 まずはやさしく
正解のないデータから特徴を探す方法です。
データの隠れた構造を見つけるために使います。
似た特徴を持つ県をまとめる時に役立ちます。
数式やコード、注意点をセットで学びます。
教師なし学習(Unsupervised Learning):ラベルなしデータ $\{x_i\}$ から構造(クラスタ・低次元表現・密度)を発見する手法
🍰 まずはやさしく
機械学習の基礎となる重要な考え方です。
データの分析を深く理解するために使います。
都道府県のデータを使って実際に体験します。
直感的な理解からPythonの実装まで読みます。
このページは「教師なし学習(Unsupervised Learning)」の用語解説です。 機械学習の基礎カテゴリにおける重要概念で、 機械学習の基礎 グループ教材の中で繰り返し登場します。 数式・実コード・落とし穴を 1 ページに集約し、 SSDSE-B-2026 都道府県データ(47 件 × 112 列)を題材に 手を動かしながら理解できるよう構成しています。
別称:教師なし。 まず 💡 30秒結論 で全体像を、 次に 🎨 直感 → 📐 数式 → 🧮 実値 → 🐍 Python の順で読むのがおすすめ。
🍰 まずはやさしく
自分で共通点を探す生徒のような学習です。
データの中にあるグループを見つけるために使います。
スマホのアプリを好みのジャンルで分ける感覚です。
グループ分けやデータの圧縮について読みます。
教師なし学習は「正解ラベルが無い大量のデータから、 自分でグループや構造を見つける」アプローチです。 「47 都道府県のうち、 似た特徴を持つ県をまとめてください」と頼まれて、 自分で答えを作る感覚に近い。 教師あり学習が 「先生から正解付き問題を渡されて勉強する生徒」なら、 教師なし学習は 「正解の無い問題集を渡されて『どんな共通点があるか自分で考える』生徒」です。
3 つの代表タスク(SSDSE-B-2026 47 都道府県データでの例):
総人口 15歳未満人口 65歳以上人口 出生数 の 4 変数で 47 県を K=4 にまとめると、 東京単独 → 大阪・愛知・神奈川 → 福岡・北海道・埼玉ほか中堅 → 残り 40 県の小規模という階層構造が浮かぶ。 ラベルは付与していないのに「都市規模」という概念が結果として現れる。教師なし学習の本質的価値: ラベル付けは人手がかかり高コスト(医療画像 1 枚 5 分、 製造業の異常品ラベル付け 1 時間など)。 教師なしならラベル無しの 100 万件データから「構造」を吸い上げ、 後段の教師あり学習に 事前知識を渡せる(自己教師あり学習・BERT/GPT の事前学習はこの発想)。 また「正解が定まらない探索的分析」(新カテゴリ発見、 セグメント設計、 仮説生成)には教師なしが本流。
教師あり/なしの境界はグラデーション: 半教師あり学習(少数ラベル + 大量無ラベル)、 自己教師あり学習(データ自身から疑似ラベルを作る)、 強化学習(報酬信号で学ぶ)は中間。 教師なしは「真にラベル無し」の最左端。
🍰 まずはやさしく
英語ではアンサパバイズドラーニングと言います。
計算で正解を導き出すために使います。
部活のメンバーを能力で分ける計算に似ています。
この手法を表す数式や定義について読みます。
本概念は次のように記述されます(KaTeX で描画)。
英語名 Unsupervised Learning。 別称:教師なし。
記号と意味を逐一突き合わせて読みます。 慣れないうちは式を「日本語で読む」ことが理解の近道です。
SSDSE-B の人口構成変数で 47 都道府県を K-means クラスタリングし、 PCA で 2 次元に可視化します。
データ出典:SSDSE-B-2026(独立行政法人統計センター)。 47 都道府県 × 複数年(最新 2023)の社会統計データ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import pandas as pd import numpy as np from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) feats = ['A1101', 'A1301', 'A1302', 'A1303'] # A1101総人口/A1301年少/A1302生産年齢/A1303高齢 X = df[feats].values Xs = StandardScaler().fit_transform(X) km = KMeans(n_clusters=4, random_state=0, n_init=10).fit(Xs) df['cluster'] = km.labels_ # 各クラスタの代表県 for c in range(4): sub = df[df['cluster']==c] print(f'cluster {c}: n={len(sub)}, 例={sub["Prefecture"].head(3).tolist()}') # PCA で次元削減 pca = PCA(n_components=2).fit_transform(Xs) print(pca[:5]) |
実行結果の要約(出力は環境依存。 概算値):
| 項目 | 値 |
|---|---|
| cluster 0 | 37 県(地方・小規模) |
| cluster 1 | 4 県(埼玉・神奈川・愛知・大阪) |
| cluster 2 | 5 県(北海道・千葉・静岡・兵庫・福岡) |
| cluster 3 | 1 県(東京) |
| PCA第1主成分寄与 | 約 99% |
| PCA第2主成分寄与 | 約 1% |
scikit-learn / pandas を使った最小実装パターン。 教師なし学習なので目的変数(正解ラベル)は使いません。 「読み込み→標準化→クラスタリング→評価」のテンプレを 4 つのスニペットに分けます。
1 2 3 4 5 | import pandas as pd # SSDSE-B-2026: 1行目=列コード, 2行目=日本語名 → skiprows=[1] でコード行を列名に採用 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) # 年度2023で絞り込み(47県) print(df.shape, df['Prefecture'].tolist()[:3]) |
1 2 3 4 5 6 | from sklearn.preprocessing import StandardScaler # 実在列のみ: A1101 総人口 / A1301 15歳未満人口 / A1303 65歳以上人口 / A4101 出生数 cols = ['A1101', 'A1301', 'A1303', 'A4101'] X = df[cols].astype(float).values Xs = StandardScaler().fit_transform(X) # 距離ベース手法の前提としてスケールを揃える print('X shape =', Xs.shape, ' (教師なし=正解ラベル y は無い)') |
1 2 3 4 5 | from sklearn.cluster import KMeans # 正解ラベルを与えず、データの構造だけで 47 県を 4 グループに分ける km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Xs) df['cluster'] = km.labels_ print('各クラスタの県数:', pd.Series(km.labels_).value_counts().sort_index().to_dict()) |
1 2 3 4 5 6 7 8 | import matplotlib.pyplot as plt from sklearn.metrics import silhouette_score from sklearn.decomposition import PCA print('シルエット係数 =', round(silhouette_score(Xs, km.labels_), 3)) # ラベル無しでの品質指標 Z = PCA(n_components=2).fit_transform(Xs) # 2次元に射影して可視化 plt.scatter(Z[:, 0], Z[:, 1], c=km.labels_, cmap='tab10') plt.xlabel('PC1'); plt.ylabel('PC2'); plt.title('47都道府県の K-means クラスタリング') plt.tight_layout(); plt.savefig('out.png', dpi=150) |
※ 「教師なし学習」固有の本格コードは上の 🧮 SSDSE-B 実値計算 節を参照。
総人口(10⁶ オーダー)と 合計特殊出生率(1.0 オーダー)を混ぜると人口だけで決まってしまう。 必ず StandardScaler または MinMaxScaler。 外れ値があるなら RobustScaler。SSDSE 公的データを題材に、教師なし学習 を実際に動かす最小コードです。 paths は引数に直書きで、 初心者がコピペで動かせる形を優先しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import pandas as pd import numpy as np # データ読み込み(SSDSE-B 都道府県・47県 × 112列) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) print('shape:', df.shape) print('列コードの先頭:', df.columns.tolist()[:6]) # 教師なし学習に使う実在列だけ取り出す # A1101 総人口 / A1301 15歳未満人口 / A1303 65歳以上人口 / A4101 出生数 / A4200 死亡数 features = ['A1101', 'A1301', 'A1303', 'A4101', 'A4200'] df_use = df[features].astype(float).copy() print(df_use.describe()) |
次に、 教師なし学習 に固有の処理(標準化 → K-means → シルエット評価)を加えます。 ここがページごとの「肝」になる部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score X = df_use.values Xs = StandardScaler().fit_transform(X) # スケールを揃える(距離ベースの前提) # 正解ラベル無しで 47 県を 5 つの地域類型に分ける km = KMeans(n_clusters=5, n_init=10, random_state=0).fit(Xs) df['cluster'] = km.labels_ print(f'シルエット係数 = {silhouette_score(Xs, km.labels_):.3f}') for k in range(5): pref = df.loc[km.labels_ == k, 'Prefecture'].tolist() print(f'cluster {k} (n={len(pref)}): {pref[:6]}') |
さらに PCA で 2 次元に落として可視化すると、 学んだ内容が「眼で」確認できます。
1 2 3 4 5 6 7 8 9 10 11 | import matplotlib.pyplot as plt from sklearn.decomposition import PCA Z = PCA(n_components=2).fit_transform(Xs) # 5変数 → 2軸に圧縮して可視化 plt.figure(figsize=(7, 5)) plt.scatter(Z[:, 0], Z[:, 1], c=km.labels_, cmap='tab10', edgecolor='k', alpha=0.8) plt.xlabel('PC1') plt.ylabel('PC2') plt.title('47都道府県の地域類型(K-means, K=5)— SSDSE-B-2026') plt.tight_layout() plt.savefig('out_unsupervised-learning.png', dpi=150) |
最後に、 クラスタ数 K の妥当性をシルエット係数で確認します(教師なしには「正解の K」が無いため)。
1 2 3 4 5 6 | from sklearn.metrics import silhouette_score # クラスタ数 K を変え、シルエット係数で妥当な K を探る(教師なしの「検証」) for k in range(2, 8): lab = KMeans(n_clusters=k, n_init=10, random_state=0).fit_predict(Xs) print(f'K={k}: silhouette = {silhouette_score(Xs, lab):.3f}') |
「教師なし学習」と混同しやすい概念を 1 つの表に並べることで、 違いが鮮明になります。 「共通点」と「分かれ目」を意識して読みましょう。
| 用語 | 何に焦点 | 本用語との違い | 使う場面 |
|---|---|---|---|
| 教師なし学習(本ページ) | 直感の核:正解ラベルなしで、 データ自体の構造(クラスタ・低次元表現な… | — | 基本系 |
| 類似概念 A | 同じ目的だが定義が異なる | 数式の形・計算量が違う | 特殊ケース・改良 |
| 類似概念 B | 対象データの種類が違う | 前処理・後処理の手順が異なる | 別ドメイン |
| 上位概念 | 本用語を一般化した枠組み | 教師なし学習 は特殊化された場合 | 理論を整理するとき |
| 下位概念 | 教師なし学習 の特定の応用 | 教師なし学習 を道具として使う | 具体タスク |
⚠️ 注意:「似ているからどれでも同じ」と考えると、 微妙な前提の違いから誤った結論を導きがちです。 まずは 1 つの定義に絞って深く理解し、 そのうえで他の概念に拡張するのが安全です。
fit は訓練データだけに対して行い、 テストには transform のみを適用。 これを混同するとデータリーケージになる。教師なし学習 は、 統計学と計算機科学の流れの中から生まれました。 下の年表はこの分野全体の流れで、 教師なし学習 固有の年表ではありません。 この用語がどの時代の産物かを掴むために置いています。
| 時期 | 出来事 | この時代に起きたこと |
|---|---|---|
| 前史 | 統計学・情報理論の基盤整備 | 数式的な土台 |
| 古典期 | 機械学習の黎明(1960〜80 年代) | 「教師なし学習」の原型が登場 |
| 展開期 | scikit-learn / TensorFlow など実装の普及(2010〜) | 誰でも 1 行で使える時代に |
| 現代 | 大規模モデル時代(2020〜) | 「教師なし学習」の意味が再解釈される |
現代の文脈では、 古典的な定義のままでは説明しきれない使い方も出てきています。 教科書の定義を出発点としつつ、 実務での「変奏」も知っておくとよいでしょう。
理論的には別定義も可能ですが、 「数学的に扱いやすい」「経験的に良い結果が出る」「歴史的経緯」の 3 拍子で現在の定義が標準化されています。 学術論文では別定義を「変種」として議論することもよくあります。
教育用途・探索的分析では十分。 ただし「統計的有意」を主張するには n=47 は不足することが多いので、 解釈は慎重に。 ブートストラップで信頼区間を出すと頑健性が確かめられます。
PyTorch / TensorFlow / XGBoost / LightGBM など多数。 ただし基本的な動作確認は scikit-learn が一番速いので、 まず sklearn で動かしてから他に移植するのがおすすめ。
計算量・メモリの観点でアルゴリズムを切り替える必要があります。 mini-batch 版、 サブサンプリング、 近似アルゴリズムの利用を検討します。 47 県スケールで本質を理解した後の応用課題です。
古典的な定義は原典(教科書や著名論文)、 実装は使用ライブラリのバージョン情報を併記するのが標準。 「Murphy 2012」「Hastie et al. 2009」あたりが定番引用です。
下の「📚 関連グループ教材」セクションのリストが、 推奨される学習順序の一つです。 上位概念から入って詳細に降りる「トップダウン」と、 1 つの具体例から始めて他に広げる「ボトムアップ」、 どちらも一長一短。 自分の学び方に合わせて。
「教師なし学習」を理解した次に何を学ぶか、 5 ステップで提案します。 順序は厳密ではなく、 興味のあるところから飛び入りで OK。
| 項目 | 内容 |
|---|---|
| 用語 | 教師なし学習(Unsupervised Learning) |
| 1 行定義 | 正解ラベルなしで、 データ自体の構造(クラスタ・低次元表現など)を見つける枠組み。 |
| 数式 | $\arg\min_{C_1,\dots,C_K} \sum_{k=1}^K \sum_{x \in C_k} \|x - \mu_k\|^2$ |
| SSDSE 適用例 | 47 都道府県を K-means で 5 クラスタに分け、 地域類型を発見する |
| 主要ライブラリ | scikit-learn, pandas, numpy |
| 典型的な落とし穴 | スケーリング忘れ・データリーケージ・前提分布 |
| 次に学ぶ | 機械学習の基礎 グループ教材 |
※ このチートシートは「30 秒で復習」用。 詳しくは各セクションへ。
統計データ解析コンペティション過去論文で「教師なし学習」がどのように登場し、 どんな問題を解決したかを見てみます。 論文ページからリンクして本ページに来た方も、 ぜひもう一度自分の関心ある論文を見直してみてください。
| 論文の方向性 | 「教師なし学習」の役割 | 学べる点 |
|---|---|---|
| 人口動態の予測 | 将来予測モデルの構成要素として | 時系列との組み合わせ方 |
| 地域格差の分析 | 都道府県をクラスタリング・分類する基盤 | 教師なし/教師ありの切り替え |
| 経済指標の関係性 | 特徴量間の関係を可視化・解釈 | 解釈可能性とのトレードオフ |
| 健康・福祉データ | 少数派ラベルに対する頑健性 | 不均衡データの扱い方 |
| テキスト解析 | 前処理・後処理の枢要 | NLP との接続 |
💡 論文を読むときのコツ:「この論文では『教師なし学習』を何のために使っているか?」「もし使わなかったら何が問題だったか?」を意識すると、 技術選定の判断軸が身に付きます。
同じ「教師なし学習」を使うにも、 データの形・規模・目的によって書き方が変わります。 4 つの典型パターンを示します。
1 2 3 4 5 6 7 8 9 | import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) Xs = StandardScaler().fit_transform(df[['A1101', 'A1301', 'A1303', 'A4101']].astype(float)) df['cluster'] = KMeans(n_clusters=4, n_init=10, random_state=0).fit_predict(Xs) print(df.groupby('cluster')['Prefecture'].apply(list)) |
1 2 3 4 5 6 7 8 9 10 11 | from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans # 標準化とクラスタリングを 1 本のパイプラインにまとめる pipe = Pipeline([ ('scaler', StandardScaler()), ('kmeans', KMeans(n_clusters=4, n_init=10, random_state=0)), ]) labels = pipe.fit_predict(df[['A1101', 'A1301', 'A1303', 'A4101']].astype(float)) print('cluster sizes =', pd.Series(labels).value_counts().sort_index().to_dict()) |
1 2 3 4 5 6 7 8 9 10 11 12 | from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score # 教師なしには検証スコアが無いため、シルエット係数で K を選ぶ best = None for k in range(2, 9): lab = KMeans(n_clusters=k, n_init=10, random_state=0).fit_predict(Xs) sil = silhouette_score(Xs, lab) print(f'K={k}: silhouette={sil:.3f}') if best is None or sil > best[1]: best = (k, sil) print('best K =', best[0], ' silhouette =', round(best[1], 3)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import matplotlib.pyplot as plt import json from sklearn.decomposition import PCA from sklearn.metrics import silhouette_score Z = PCA(n_components=2).fit_transform(Xs) # 2次元へ射影して可視化 plt.figure(figsize=(7, 5)) plt.scatter(Z[:, 0], Z[:, 1], c=df['cluster'], cmap='tab10', edgecolor='k') plt.xlabel('PC1'); plt.ylabel('PC2'); plt.title('教師なし学習 結果(K-means クラスタ)') plt.tight_layout(); plt.savefig('result_unsupervised-learning.png', dpi=150) with open('result_unsupervised-learning.json', 'w', encoding='utf-8') as f: json.dump({'n_clusters': 4, 'silhouette': round(float(silhouette_score(Xs, df['cluster'])), 3), 'cluster_sizes': df['cluster'].value_counts().sort_index().to_dict()}, f, ensure_ascii=False, indent=2) |
「教師なし学習」を中央に置いて、 周辺概念を 5 つの方向に整理します。 これは記憶の足場になります。
| 方向 | 隣接概念 | 関係性 |
|---|---|---|
| 北 (上位) | 機械学習 (3 大分類のひとつ) | 教師あり / 強化学習と並ぶ大枠 |
| 南 (下位) | k-means / 階層クラスタリング / PCA / t-SNE / UMAP | 教師なし学習の代表アルゴリズム |
| 東 (発展) | 自己教師あり学習 / 対照学習 / オートエンコーダ | ラベルなしから表現を学ぶ発展形 |
| 西 (前提) | 距離尺度 / 線形代数 (固有値) / 確率分布 | クラスタ・次元削減の数学的土台 |
| 中央 | 教師なし学習 | 本ページの主役 |
マインドマップは「学んだ用語を整理する道具」として優秀。 紙にこの 5 方向を書き、 自分なりの隣接概念を埋めると、 暗黙的にあった理解構造が可視化されます。
「教師なし学習」を本当に理解できたか、 自分でテストできるクイズです。 答えは展開で確認。
模範回答:上の「💡 30秒結論」を参照。 ポイントは「何のために使うか」を最初に言うこと。 定義や数式から入ると相手が引きます。
模範回答:データは観測値で固定、 パラメータは学習で動かす、 出力は計算結果。 上の「📐 数式の構造をもう一度」を参照。
模範回答:47 都道府県の特徴量を入力にすると、 結果が地理的に解釈しやすくなる、 一方でサンプル数が少ないため信頼区間は広めに出る、 など。
模範回答:上の「🌐 似た概念との比較」表を参照。 1 文で言える違いを持っておくと、 「なぜこっちを選んだか」を説明できます。
模範回答:上の「⚠️ 落とし穴」と「⚠️ さらに 5 つの落とし穴」セクションから、 自分のプロジェクトに最も関連するものを 1 つ選んで言語化してみましょう。
「教師なし学習」は単独で学ぶよりも、 関連する複数の用語をセットで学ぶ方が効率的です。 関連グループ教材へのリンクを整理します。
| グループ教材 | 含まれる主な用語 | 「教師なし学習」の位置 |
|---|---|---|
| 機械学習の基礎 | 教師あり/なし、 損失、 汎化、 過学習 | 中核 |
| モデル選択 | CV、 ハイパーパラメータ、 交差検証 | 関連 |
| 評価指標 | R²、 RMSE、 ROC-AUC、 confusion matrix | 関連 |
| 決定木 | 情報利得、 エントロピー、 ジニ | 特定の応用 |
| 分類 | 2 値・多値・不均衡 | タスク |
| クラスタリング | K-means、 階層型、 DBSCAN | 教師なし側 |
💡 勧めの学習スタイル:1 つのグループ教材を読破してから次へ、 ではなく、 「気になる用語を起点に近所を巡る」スタイルが、 ジャストインタイム学習のコツです。 興味の連鎖に従って深掘りしましょう。
教師なし学習で「クラスタを見つける」と言っても、 アルゴリズムの世界観はそれぞれ違う。 K-means は「球形のかたまり」を仮定し、 中心からの距離でグループを切る。 DBSCAN は「密度の高い領域」がクラスタだと考え、 密度が薄い部分は noise として捨てる。 階層クラスタリングは「下から積み上げる/上から割る」順序で樹形図を作る。 同じ 47 都道府県を入力しても、 アルゴリズムが違えば違うクラスタが出る。
| 観点 | K-means | DBSCAN | 階層型 (Ward) |
|---|---|---|---|
| クラスタの形 | 球状・等方 | 任意の形状(密度依存) | 凝集・分割の連鎖 |
| 必要な事前指定 | K(クラスタ数) | eps, min_samples | 距離 + 連結基準 |
| 外れ値の扱い | 必ず最寄りクラスタに収容 | 明示的に noise (=-1) ラベル | 単独クラスタとして表示 |
| スケーリング感度 | 非常に高い(必須) | 非常に高い(eps が無意味化) | 高い |
| 計算量 | O(nKd) / iter | O(n log n) / O(n²) | O(n²) ~ O(n³) |
| 初期化依存 | あり(k-means++ で緩和) | なし(決定的) | なし |
「球状クラスタなら K-means、 形がいびつなら DBSCAN、 階層関係を読みたいなら Ward」と覚えると判断しやすい。 47 都道府県のように サンプル数が少なく、 経済規模で連続的に並ぶ データでは、 K-means が直感的な「都市規模グループ」を返しやすい。
教師なし学習は「正解」がないので、 アルゴリズム自身が 内的な目的関数 を最小化(最大化)する。 代表的なものを並べる。
K-means の Within-Cluster Sum of Squares (WCSS):
$$ J_{\mathrm{WCSS}} = \sum_{k=1}^{K} \sum_{\mathbf{x} \in C_k} \|\mathbf{x} - \boldsymbol{\mu}_k\|_2^2 $$
シルエット係数 (sample i):
$$ s_i = \frac{b_i - a_i}{\max(a_i,\, b_i)},\quad a_i = \text{同一クラスタ内の平均距離},\; b_i = \text{最近隣クラスタの平均距離} $$
Davies-Bouldin 指数(小さいほど良い):
$$ \mathrm{DB} = \frac{1}{K} \sum_{i=1}^{K} \max_{j \ne i} \frac{\sigma_i + \sigma_j}{d(\mu_i, \mu_j)} $$
PCA の最大化目的(第一主成分):
$$ \max_{\|\mathbf{w}\|=1} \mathbf{w}^\top \boldsymbol{\Sigma} \mathbf{w} \quad\Longleftrightarrow\quad \boldsymbol{\Sigma} \mathbf{w} = \lambda \mathbf{w} $$
オートエンコーダの再構成損失:
$$ \mathcal{L}_{\mathrm{AE}}(\theta) = \frac{1}{n}\sum_{i=1}^n \| \mathbf{x}_i - g_\theta(f_\theta(\mathbf{x}_i)) \|_2^2 $$
K-means の WCSS は「各点とその所属クラスタ重心との距離の二乗和」。 つまり クラスタの中心からどれくらい点が散らばっているか を測る。 アルゴリズムは「重心を計算 → 最近傍クラスタに再割当」を繰り返し、 この値を単調に下げていく。 ただし大局最適は保証されない(局所最適にハマる)。
シルエット係数 $s_i$ は「自分の所属クラスタとどれだけ仲が良いか(小さい $a_i$)」と「隣のクラスタとどれだけ離れているか(大きい $b_i$)」のバランスを取る。 $-1 \le s_i \le 1$ で、 1 に近いほど明確に分離。 0 は境界線上、 マイナスは「むしろ隣のクラスタに属すべき」点。
Davies-Bouldin は「各クラスタについて、 最も似ている他クラスタとの比率」を取る。 $\sigma_i$ は自分の散らばり、 $d(\mu_i, \mu_j)$ は中心間距離。 散らばりが小さく中心が遠ければ DB は小さい = 良い分離。 ただし K-means 同様、 球状クラスタを暗黙に仮定するため DBSCAN の評価には不向き。
PCA の式は固有値問題そのもの。 共分散行列 $\boldsymbol{\Sigma}$ の固有ベクトル $\mathbf{w}$ が「データの分散を最大化する方向」、 固有値 $\lambda$ がその方向の分散量。 直感的には「データの細長い方向」を見つけて新しい軸にする操作。
オートエンコーダは「入力を圧縮する関数 $f$(エンコーダ)」と「圧縮表現から復元する関数 $g$(デコーダ)」を同時に学習。 入力と再構成の二乗距離を最小化することで、 本質的な情報だけ残す圧縮表現 が得られる。 中間層の次元を小さくすれば非線形 PCA に近づく。
SSDSE-B-2026 から「総人口(A1101)・15歳未満人口(A1301)・出生数(A4101)・死亡数(A4200)」の 4 変数で 47 都道府県を K-means (K=4) クラスタリングする。 全体の流れ:(1) read_csv、 (2) 4 変数を標準化、 (3) K-means、 (4) シルエット係数で品質確認、 (5) 各クラスタの代表県を確認。
このコードでやること:SSDSE-B-2026 から 47 都道府県を読み込み、 4 変数で K-means (K=4) を実行、 シルエット係数とクラスタ代表県を出力する。
📥 入力データ (SSDSE-B-2026 抜粋 head):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.metrics import silhouette_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) latest = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) X = latest[['A1101', 'A1301', 'A4101', 'A4200']].astype(float).values # A1101総人口/A1301年少/A4101出生/A4200死亡 Xs = StandardScaler().fit_transform(X) km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Xs) latest['cluster'] = km.labels_ sil = silhouette_score(Xs, km.labels_) print(f'シルエット係数 = {sil:.3f}') for k in range(4): pref = latest[latest['cluster']==k]['Prefecture'].tolist() print(f'cluster {k} (n={len(pref)}): {pref[:6]} ...') |
📤 実行すると次の出力が得られる:
💬 シルエット 0.720 はクラスタ構造が明確であることを示す(0.5 以上で「合理的」、 0.7 以上で「強い構造」)。 東京都は単独クラスタ(cluster 3)となり 外れ値級の規模 であることが定量的に確認できる。 cluster 1(埼玉・神奈川・愛知・大阪)は大都市圏、 cluster 2(北海道・千葉ほか 5 県)は地方中核圏、 cluster 0(37 県)は地方圏。 正解ラベルを与えていないのに、 人口規模の階層が自然に再現される のが教師なし学習の威力。
このコードでやること:同じ 47 都道府県データを DBSCAN で処理し、 K-means との違い(東京都の noise 判定、 密度ベース)を確認する。
📥 入力データ: 上記 K-means と同じ標準化済み Xs (47×4)。
1 2 3 4 5 6 7 8 9 10 11 12 13 | from sklearn.cluster import DBSCAN import numpy as np # eps は近傍距離、 min_samples は core point の閾値 db = DBSCAN(eps=0.8, min_samples=3).fit(Xs) labels = db.labels_ n_clusters = len(set(labels)) - (1 if -1 in labels else 0) n_noise = list(labels).count(-1) print(f'クラスタ数 = {n_clusters}, ノイズ点 = {n_noise}') for k in sorted(set(labels)): pref = latest['Prefecture'][labels==k].tolist() tag = 'noise' if k == -1 else f'cluster {k}' print(f'{tag} (n={len(pref)}): {pref[:5]} ...') |
📤 実行例:
💬 DBSCAN は eps=0.8 で 2 つの密度クラスタを作り、 人口規模が突出した 3 都府県(東京・神奈川・大阪)を ノイズ点 として分離。 K-means が「全員必ずどこかに属する」のに対し、 DBSCAN は 「該当しない点は noise」 と明示する点が違う。 eps を変えれば挙動が大きく変わるため、 NearestNeighbors で k-距離プロットを描いてから決めるのが定石。
このコードでやること:4 変数を PCA で 2 次元に圧縮し、 寄与率と第一主成分の負荷(重み)を出力。 教師なしで「経済規模軸」が抽出できることを確認する。
📥 入力データ: 標準化済み Xs (47×4)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from sklearn.decomposition import PCA import pandas as pd pca = PCA(n_components=2).fit(Xs) print('寄与率:', pca.explained_variance_ratio_) print('累積寄与率:', pca.explained_variance_ratio_.cumsum()) loadings = pd.DataFrame(pca.components_.T, index=['A1101','A1301','A4101','A4200'], columns=['PC1','PC2']) print(loadings.round(3)) Z = pca.transform(Xs) top5 = latest.assign(PC1=Z[:,0]).nlargest(5, 'PC1')[['Prefecture','PC1']] print(top5) |
📤 実行例:
💬 第一主成分(PC1)が 99.3% の分散を説明 = 4 変数は実質「1 次元の人口規模」で大半が表せる。 PC1 の重みは 4 変数とも 0.50 前後で同符号 → 「総合的な規模指標」と解釈できる。 PC2(0.6%)は死亡数の重みが正、 出生数が負 → 「死亡数 vs 出生数(人口動態の老若)」の対立軸。 東京都の PC1=7.92 は全 47 県中で突出。
このコードでやること:K=2〜10 に対して WCSS とシルエット係数を計算し、 最適 K を選ぶ「客観的指標」を可視化する。
📥 入力データ: 標準化済み Xs (47×4)。
1 2 3 4 5 6 7 8 9 10 | from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score results = [] for k in range(2, 11): km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(Xs) wcss = km.inertia_ sil = silhouette_score(Xs, km.labels_) results.append((k, wcss, sil)) print(f'K={k}: WCSS={wcss:6.2f}, silhouette={sil:.3f}') |
📤 実行例:
💬 WCSS は K=2→3→4 で大きく減り(エルボー)、 以降は緩やかに減少。 シルエットは K=2 で最大 (0.788)、 K=4 でも 0.720 と十分高い。 エルボー法的には K=3 or 4、 シルエット最大は K=2。 教師なし学習では「正解の K」は本来存在せず、 用途で選ぶ(粗い分類なら K=2、 細かいなら K=4)。
このコードでやること:Ward 法で 47 都道府県の階層構造を計算し、 任意の高さで切ることでクラスタ数を選ぶ。 K-means と違い 「クラスタ間の入れ子関係」 が見える。
📥 入力データ: 標準化済み Xs (47×4)。
1 2 3 4 5 6 7 8 9 | from scipy.cluster.hierarchy import linkage, fcluster import pandas as pd Z = linkage(Xs, method='ward') labels = fcluster(Z, t=4, criterion='maxclust') out = pd.DataFrame({'Prefecture': latest['Prefecture'].values, 'cluster': labels}) for k in sorted(out['cluster'].unique()): members = out[out['cluster']==k]['Prefecture'].tolist() print(f'cluster {k} (n={len(members)}): {members[:6]} ...') |
📤 実行例:
💬 結果は K-means とほぼ一致し(ARI=0.917)、 大きな違いは中核圏の数県(静岡・埼玉など)がどちらの群に入るかの境界だけ。 階層型は 樹形図(dendrogram) を描けるのが利点。 「どの 2 県が最も似ているか」「都道府県間の遠近を視覚化したい」場合は階層型が直感的。 計算量 O(n²) のためサンプル数が増えると重くなる。
n_init=10(v1.4 で n_init='auto')で複数回走らせ、 最小 inertia を採用するのが定石。| 指標 | 範囲 | 良い値 | 必要なもの | 特徴 |
|---|---|---|---|---|
| WCSS / inertia | ≥ 0 | 小 | クラスタ + データ | K が大きいほど必ず小さい(エルボー判定) |
| Silhouette | [-1, 1] | 大 | クラスタ + データ | 距離計算 O(n²)、 球状仮定 |
| Davies-Bouldin | ≥ 0 | 小 | クラスタ + データ | 凸クラスタ向き |
| Calinski-Harabasz | ≥ 0 | 大 | クラスタ + データ | 分散比(F 統計量風) |
| ARI (Adjusted Rand) | [-1, 1] | 1 | 2 つのクラスタリング結果 | 外的指標。 ラベルの順序に依存しない |
| NMI | [0, 1] | 1 | 2 つのクラスタリング結果 | 情報量で類似度を測る |
内的指標(WCSS, Silhouette など)は「データだけで計算可能」。 外的指標(ARI, NMI)は「正解クラスタ or 別手法の結果」が必要。 教師なし学習の現場では 複数指標 + 解釈可能性 で総合判断する。
教師なし学習は「正解ラベルがないデータから、 似たもの同士をまとめたり、 隠れた構造を見つけたりする」手法群です。 この節では、 SSDSE-B-2026(都道府県別社会経済指標)を題材に、 K-means / 階層クラスタリング / PCA(主成分分析)/ DBSCAN / 異常検知 の 5 つのアルゴリズムを「同じデータに通したらどんな違いが出るか」 を可視化と数値で比べます。 教師あり学習(supervised-learning.html)との対比、 そして「ラベルがない時に何を評価指標にすればよいか」 という実務上もっとも悩ましい論点も整理します。
SSDSE-B-2026 は 47 都道府県 × 約 130 指標(人口・産業・教育・医療・財政)の CSV です。 教師なし学習で特に重要なのが「標準化」(standardization.html)。 人口(万単位)と犯罪認知件数(数百単位)をそのまま使うと、 距離計算が人口に支配されてしまうためです。
このコードでやること:SSDSE-B-2026 から総人口(A1101)・65歳以上人口(A1303)・出生数(A4101)・合計特殊出生率(A4103)・転入者数(A5101)・消費支出(L3221)・延べ宿泊者数(G7101)の 7 指標を抜き出し、 Z-score 標準化して以後のクラスタリングや PCA の入力にする。
📥 入力データ(SSDSE-B-2026 の冒頭):
1 2 3 4 5 6 7 8 | import pandas as pd from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) cols = ['A1101', 'A1303', 'A4101', 'A4103', 'A5101', 'L3221', 'G7101'] Xz = StandardScaler().fit_transform(df[cols].astype(float)) print('shape =', Xz.shape, ' mean ≒ 0, std ≒ 1') |
📤 実行結果:
💬 7 次元の正規化済み行列ができました。 「総人口」(10⁶ オーダー)と「合計特殊出生率」(1.0 オーダー)が同じスケールに揃ったので、 ユークリッド距離で公平に比べられます。 標準化を忘れると、 K-means は「ほぼ人口だけで決まる」 という退屈なクラスタリングを出力します。
K-means は「事前に K を決め、 各クラスタの重心と各点の距離平均を最小化する」反復アルゴリズムです(→ k-means.html)。 K の選び方は エルボー法 と シルエット係数(→ 評価指標)が定番。
このコードでやること:K=2〜8 までで inertia(クラスタ内分散)とシルエット係数を計算し、 妥当な K を選んで分類結果を得る。
1 2 3 4 5 6 7 8 9 10 11 12 | from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score for k in range(2, 9): km = KMeans(n_clusters=k, n_init='auto', random_state=0).fit(Xz) sil = silhouette_score(Xz, km.labels_) print(f'k={k} inertia={km.inertia_:.1f} silhouette={sil:.3f}') # K=4 を採用して再フィット km4 = KMeans(n_clusters=4, n_init='auto', random_state=0).fit(Xz) df['cluster_km'] = km4.labels_ print(df.groupby('cluster_km')['Prefecture'].apply(list)) |
📤 実行結果:
💬 シルエットは K=2 が最高(0.560)、 inertia の折れ曲がりは K=4 付近。 解釈のしやすさを優先して K=4 を採用。 東京が単独クラスタ に分離されるのが特徴で、 これは「東京は他都道府県と質的に異なる」 という事実を、 ラベルなしで自動的に発見した好例です。
図 1:K-means(K=4) のクラスタリング結果を PCA で 2 次元化した散布図。 東京が単独クラスタとして右上に孤立し、 大都市圏・地方中核・小規模地方が左下方向に並ぶ。
K-means は「K を決め打ちで一発分類」しますが、 階層クラスタリング(→ hierarchical-clustering.html)はデンドログラム(樹形図)として「どの順で結合されたか」を可視化できます。 47 県を 1 個ずつバラバラの状態から少しずつ結合していき、 最後に 1 つの大クラスタになるまでの過程を木で表現。 これにより「K=3, 4, 5 のどれが最適か」 を目で見て決められます。
このコードでやること:Ward 法で階層クラスタリングを行い、 デンドログラムを描いてからカット高で 4 クラスタに切り分ける。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import os os.makedirs('html/figures', exist_ok=True) # 保存先のフォルダを作っておく from scipy.cluster.hierarchy import linkage, fcluster, dendrogram import matplotlib.pyplot as plt Z = linkage(Xz, method='ward') labels_h = fcluster(Z, t=4, criterion='maxclust') df['cluster_hc'] = labels_h plt.figure(figsize=(12, 5)) dendrogram(Z, labels=df['Prefecture'].values, leaf_font_size=9) plt.title('Ward Hierarchical Clustering of 47 Prefectures') plt.savefig('html/figures/dendrogram_pref.png', dpi=120, bbox_inches='tight') |
📤 実行結果(K-means との一致度):
図 2:Ward 法によるデンドログラム概念図。 結合高(縦軸)が低いほど似ている。 高さ 5〜7 で水平線を引くと 4 クラスタ、 高さ 8〜10 で 3 クラスタに切り分けられる。 階層の任意の位置で切れる柔軟さが K-means にはない強み。
💬 K-means と階層クラスタリングは ARI=0.926、 ほぼ同じ分類結果。 大きな違いは地方県の一部(青森・秋田など)がどちらの群に入るかだけ。 2 つの異なるアルゴリズムが似た解を返す ということは、 データ自体に強い構造があることの証拠でもあります。
7 次元のデータは目で見られない。 そこで 主成分分析(PCA → pca.html) で 2 次元に圧縮し、 散布図にします。 PCA は「分散をもっとも保存する直交軸(主成分)」を順に取り出す線形教師なし手法。 第 1・第 2 主成分の累積寄与率が 70 % を超えていれば「2 次元で十分構造が見える」と判断できます。
1 2 3 4 5 6 7 8 9 10 11 | from sklearn.decomposition import PCA pca = PCA(n_components=3).fit(Xz) Y = pca.transform(Xz) print('寄与率:', pca.explained_variance_ratio_.round(3)) print('累積:', pca.explained_variance_ratio_.cumsum().round(3)) # 主成分の意味を読み解く(loadings) import pandas as pd loadings = pd.DataFrame(pca.components_.T, index=cols, columns=['PC1', 'PC2', 'PC3']) print(loadings.round(2)) |
📤 実行結果:
💬 PC1(74 %)は「規模の総合軸=総人口・65歳以上人口・出生数・転入者数・宿泊施設が同符号」 を表す軸(合計特殊出生率だけ逆符号)、 PC2(15 %)は「消費支出 vs 合計特殊出生率」 の対比軸、 PC3(7 %)は「出生率・消費」 の残差。 累積 88.5 % で 2 次元プロットが意味を持つ水準に到達。 PCA の loadings を見ることは、 教師なし学習を「ブラックボックス」ではなく「解釈可能な発見」 に変える鍵です。
K-means は「クラスタは球状で同じ大きさ」 と暗黙に仮定するため、 細長いクラスタや密度が違うクラスタを苦手とします。 DBSCAN(→ dbscan.html) は「半径 ε 内に min_samples 以上の点があれば core point」 と定義し、 core 同士を連結してクラスタを作る密度ベース法。 どのクラスタにも属さない点を自動で noise(-1) としてラベル付け するため、 異常検知としても使えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from sklearn.cluster import DBSCAN from sklearn.neighbors import NearestNeighbors import numpy as np # ε の目安: k-distance plot で「肘」を探す nn = NearestNeighbors(n_neighbors=4).fit(Xz) d, _ = nn.kneighbors(Xz) d4 = np.sort(d[:, 3])[::-1] print('k=4 距離の降順上位5件:', d4[:5].round(2)) db = DBSCAN(eps=1.6, min_samples=3).fit(Xz) df['cluster_db'] = db.labels_ print('DBSCAN クラスタ数:', len(set(db.labels_)) - (1 if -1 in db.labels_ else 0)) print('noise(-1) として検出された県:', df.loc[db.labels_ == -1, 'Prefecture'].tolist()) |
📤 実行結果:
💬 ε=1.6 設定では地方圏が 1 つの大きな密集クラスタになり、 大都市圏の 4 県+北海道(面積が突出)が外れ値として検出されました。 東京は K-means と DBSCAN の両方で「孤立点」 と判定 されており、 「東京の特異性」 がアルゴリズムを変えても揺るがない事実だと分かります。 ε と min_samples の調整は dbscan.html 参照。
Isolation Forest は「ランダムに変数と切断点を選んで木を作り、 点を孤立させるのに必要な分割数(path length)が短いほど異常」 と判定するアンサンブル法。 ラベルなしで「いつもと違う」 を検出できるので、 不正取引・サーバ監視・センサー異常で広く使われます。
1 2 3 4 5 6 7 | from sklearn.ensemble import IsolationForest iso = IsolationForest(contamination=0.1, random_state=0).fit(Xz) df['anomaly_score'] = iso.score_samples(Xz) df['is_anomaly'] = (iso.predict(Xz) == -1) print(df.sort_values('anomaly_score').head(7)[['Prefecture', 'anomaly_score', 'is_anomaly']]) |
📤 実行結果:
💬 contamination=0.1 (10 %) 設定で「異常」 と判定された 5 県のうち 4 県(東京・大阪・神奈川・埼玉)は DBSCAN の noise と一致しました。 異なる 2 つの教師なしアルゴリズムが 大都市圏をそろって外れ値と判定 したのは、 構造の頑健な発見の根拠になります。
図 3:K-means / 階層 / DBSCAN それぞれのクラスタについて、 標準化済み総人口(青)・出生数(橙)・65歳以上人口(緑)の分布を箱ひげ図で並べたもの。 大都市クラスタは人口・出生数が高く、 小規模クラスタは高齢化が進む、 という構造が 3 手法で共通して現れる。
| 手法 | K 事前指定 | 外れ値検出 | 形状の柔軟性 | 計算量 | 本データでの結果 |
|---|---|---|---|---|---|
| K-means | 必要 | × | 球状想定 | O(nki) | 4 クラスタ、 東京が単独 |
| 階層 (Ward) | 事後 | △ 末端で表現 | 球状想定 | O(n²log n) | K-means と ARI=0.93 |
| DBSCAN | 不要 | ○(noise=-1) | 任意形状 | O(n log n)* | 1 クラスタ + 5 noise |
| PCA | 主成分数のみ | 残差で間接的 | 線形 | O(np²) | PC1+PC2 で 88.5 % 説明 |
| Isolation Forest | contamination | ◎(メイン目的) | 非線形可 | O(n log n) | 5 県を異常判定 |
教師なし学習の最大の悩みは「正解がないので、 良し悪しを客観的に判定しにくい」 こと。 そのため、 以下の 内部指標(データだけで計算)と 外部指標(補助ラベルと比較)の併用が推奨されます。
| 分類 | 指標 | 計算式の要旨 | 範囲 | 判定 |
|---|---|---|---|---|
| 内部指標 | シルエット係数 | (b - a) / max(a, b) | [-1, 1] | 1 に近いほど良い |
| Calinski-Harabasz | クラスタ間分散 / クラスタ内分散 | [0, ∞) | 大きいほど良い | |
| Davies-Bouldin | クラスタ間距離の倒数の平均 | [0, ∞) | 小さいほど良い | |
| 外部指標 | Adjusted Rand Index | 期待値補正の Rand 指数 | [-1, 1] | 1 に近いほど良い |
| Normalized Mutual Info | 相互情報量 / エントロピー平均 | [0, 1] | 1 に近いほど良い | |
| Homogeneity / Completeness | クラス純度・取りこぼし度 | [0, 1] | 1 に近いほど良い |
| 業界・分野 | タスク | 使われる手法 | 期待効果 |
|---|---|---|---|
| 小売・EC | 顧客セグメンテーション (RFM) | K-means / GMM | セグメント別マーケティング |
| 金融 | 不正取引検知 | Isolation Forest / Autoencoder | 損失防止・顧客信頼 |
| 医療 | 患者サブタイプ発見 | 階層クラスタリング / UMAP | 個別化医療への展開 |
| 製造 | 設備異常検知 | One-class SVM / Autoencoder | 予知保全コスト削減 |
| 自然言語 | トピック抽出 | LDA / NMF / BERTopic | 大量文書の俯瞰 |
| 画像 | 特徴学習(事前学習) | SimCLR / MoCo | ラベル少データで分類精度向上 |
| 行政・公共 | 地域類型化 | 階層クラスタ / PCA | 政策横展開の根拠 |
StandardScaler や RobustScaler を通す。 standardization.html 参照。random_state 固定、 複数 seed の安定性検証、 アンサンブル平均を活用。K-means の目的関数は $$J = \sum_{k=1}^{K} \sum_{x \in C_k} \| x - \mu_k \|^2$$ 「全クラスタの平均からの 2 乗距離の総和」 を最小化します。 最適解は NP 困難ですが、 Lloyd アルゴリズム(割当てと重心更新の反復)で局所最適に到達。 一方、 階層クラスタリング(Ward 法)は $$\Delta J = \frac{n_A n_B}{n_A + n_B} \| \mu_A - \mu_B \|^2$$ 「2 クラスタを結合したときの分散増加量」 を最小化する貪欲的な凝集型。 両者とも「クラスタ内分散最小化」 という同じ哲学を持つため、 結果が近くなる傾向があります。
3 つの異なる教師なし手法(重心ベース・密度ベース・分散ベース)で同じ結論が出る → データに頑健な構造があり、 「東京は他都道府県と質的に異なる」 ことが偶然ではないと示唆される。 アルゴリズムの選択ではなく、 データ自体の性質。
統計量は参考値であり、 解釈可能性・業務上の意味・後続施策との整合性が優先される。 K=2 の「都市 vs 地方」 は粗すぎ、 K=4 の「東京/大都市/中核/過疎」 は施策設計に有用。 ただし K=4 でもシルエットが 0.20 を下回ると「クラスタ境界が曖昧」 のサインで、 他手法の併用や特徴量再設計を検討。
PC2 は「1 世帯あたり消費支出が大きいが出生率は低い地域 (+ 側)」 vs「消費は控えめで出生率が高い地域 (- 側)」 を分ける軸。 1 次元の連続スコアとして「消費と出生のトレードオフ」 を表すと解釈できる。 PCA は「変数の組み合わせとして潜在因子を浮かび上がらせる」 ことに価値がある。
(1) 内部指標で安定性確認、 (2) 別アルゴリズムでも似た結果か(頑健性)、 (3) ドメイン専門家の評価(「腑に落ちる分類か」)、 (4) 下流タスクの改善(クラスタを特徴量化して教師あり学習に投入したら精度が上がるか)。 4 つの視点を組み合わせる。
変数が 30 個を超えるなら次元削減を推奨。 距離計算が安定し、 可視化もできる。 ただし PCA で削った成分に重要情報があると失われるリスクもあるので、 累積寄与率 80 % 程度を目安に。 UMAP/t-SNE は非線形構造の保存に強いが、 距離保存性は弱いため可視化目的に限定する。
教師なし学習は「正解ラベルなしのデータから構造を抽出する」総称であり、目的によって使うべき手法が大きく変わります。 ここでは「やりたいこと」を起点に手法をマッピングし、 SSDSE-B-2026 の都道府県データを軸に各手法の使いどころを言語化します。 教師あり学習が「未来の値を当てる」 ことに最適化されているのに対し、 教師なし学習は「データに潜む構造を可視化・要約・圧縮・異常検出する」 ために存在します。 同じ「教師なし」 でもクラスタリングと次元削減と密度推定では、 想定する問題設定・評価軸・前処理・後処理がまったく異なります。
| やりたいこと | 主な手法 | SSDSE-B-2026 での例 | 評価指標 |
|---|---|---|---|
| グループ分け(似た者同士をまとめる) | K-means / 階層 / DBSCAN / GMM | 47 都道府県を「都市型/地方型/過疎型」 などに自動分割 | シルエット係数・Davies-Bouldin |
| 変数を減らす・可視化する | PCA / t-SNE / UMAP / オートエンコーダ | 30 指標 → 2 軸に圧縮し、都道府県を地図状に配置 | 累積寄与率・再構成誤差 |
| 異常値・外れ値の検出 | Isolation Forest / LOF / One-Class SVM | 東京を「47 県の中で特異な存在」 として自動検知 | PR-AUC(ラベルがあれば)・可視化 |
| 変数間の関係性発見 | アソシエーション分析 / 相関ネットワーク | 「人口が多い → 出生数も多い → 高齢者数も多い」 連鎖を抽出 | 支持度・確信度・リフト値 |
| 確率分布の推定 | GMM / KDE / フローモデル | 人口分布の混合成分(大都市/中都市/小都市)を推定 | 尤度・AIC・BIC |
| トピック抽出(テキスト) | LDA / NMF / BERTopic | 県別観光 PR テキストから「自然」「歴史」「グルメ」 を抽出 | パープレキシティ・トピック一貫性 |
| 表現学習・特徴量化 | 自己符号化器 / 自己教師あり / 対比学習 | 都道府県をベクトルにし、 後続の教師あり学習の特徴量として注入 | 下流タスクの精度向上 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans from sklearn.decomposition import PCA from sklearn.ensemble import IsolationForest df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) Xs = StandardScaler().fit_transform(df[['A1101', 'A1301', 'A1303', 'A4101', 'A4200']].astype(float)) # 目的1: クラスタリング (4分割) labels = KMeans(n_clusters=4, n_init=10, random_state=0).fit_predict(Xs) # 目的2: 次元削減 (5変数 → 2軸) pcs = PCA(n_components=2).fit_transform(Xs) # 目的3: 異常検知 (contamination=0.05 で外れ値を 2-3 県抽出) anomaly = IsolationForest(contamination=0.05, random_state=0).fit_predict(Xs) result = pd.DataFrame({'pref': df['Prefecture'], 'cluster': labels, 'PC1': pcs[:,0], 'PC2': pcs[:,1], 'is_anomaly': anomaly == -1}) print(result[result.is_anomaly].to_string(index=False)) |
📤 実行例:
💬 同じ標準化済みデータから 3 つの異なる視点(グループ・軸・異常度)を一気に得ている。 教師なし学習の本質は「ラベルなしでも、 こんなに多面的にデータを語れる」 ことにある。
教師なし学習はビジネス現場のあらゆる場所に潜んでいます。 「顧客セグメンテーション」 「異常検知」 「レコメンド」 「自然言語処理」 「画像分析」 — どれも教師なしの考え方が中核にあります。 ここでは 6 つの代表的なケーススタディを、 課題設定 → 手法選択 → 評価 → 落とし穴の順で整理し、 公的データでの類似演習に置き換えられる形にします。
課題: 数万人の顧客を、 購買行動の似た者同士のグループに分けたい。 マーケティング施策を「全員一律」 から「セグメント別」 に切り替えたい。
手法: RFM 分析(Recency, Frequency, Monetary)の 3 指標を標準化 → K-means で 4-6 グループに分割 → 各グループに「優良顧客」 「離反予備軍」 「新規」 等のラベルを人手で命名。
評価: シルエット係数で内部整合性、 各セグメントの平均購買額・継続率の差で外部妥当性を確認。 最終的にはセグメント別キャンペーンの CVR で実務評価。
落とし穴: 「セグメント数を増やせば細かく狙える」 と思い K=20 等にすると、 1 セグメント数十人になり施策コストが回収できない。 「実務的に意味のある K の上限」 を施策設計から逆算する。
課題: 工場の機械から毎秒取得されるセンサーデータ(温度・振動・電流)から、 故障の前兆を検出したい。 故障データは少なく、 教師あり学習が難しい。
手法: Isolation Forest または One-Class SVM で「正常データの典型から外れたもの」 を検出。 オートエンコーダで「正常データを再構成できる範囲」 を学習し、 再構成誤差で異常度を測る方法も有力。
評価: 過去の故障事例で陽性率を確認、 偽陽性率を許容範囲(例: 1 日 1 件以内)に収める。 異常スコアの閾値はビジネスコストで決定。
落とし穴: 「正常」 の定義が時間とともに変わる(季節変動・経年劣化)。 モデルを定期的に再学習する仕組みが不可欠。
課題: クレジットカード取引から不正利用を検出したい。 不正は全取引の 0.1 % 未満で、 ラベル付きデータが圧倒的に少ない。
手法: 教師なしと教師ありのハイブリッド。 まず Isolation Forest や DBSCAN で「外れ値」 を抽出し人手確認、 ラベルを蓄積したら XGBoost 等の教師あり学習に切り替える。
評価: PR-AUC(precision-recall AUC)。 リアルタイム判定のため推論レイテンシも KPI。
落とし穴: 不正手法は日々進化するため、 「過去の不正パターン」 だけ学習すると新型に弱い。 教師なし側で「未知のパターン」 を継続して拾い続ける役割が必要。
課題: 数万件のコールセンター問い合わせを、 内容の似たものごとに自動分類したい。
手法: BERT で各文書をベクトル化 → UMAP で 2-10 次元に圧縮 → HDBSCAN でクラスタリング。 各クラスタの代表ワードを TF-IDF で抽出して「テーマ命名」。
評価: トピック一貫性スコア(Cv, Umass)、 人手レビューでの妥当性。
落とし穴: 「とりあえずクラスタリングしてみる」 と意味の薄い結果が出る。 「何のためにグループ分けするか」(FAQ 自動化? オペレータ教育?) を先に固めること。
課題: 何百万点の商品から、 個々のユーザに「次に買いそうな商品」 を推薦したい。
手法: 協調フィルタリング(行列分解 SVD/ALS)、 アイテム埋め込み(word2vec の応用版 item2vec)。 教師なし学習でアイテムを潜在空間に配置し、 近傍探索で類似アイテムを取得。
評価: HitRate@K, NDCG@K, MAP@K。 オンライン A/B テストで CVR を比較。
落とし穴: 「コールドスタート問題」(新規ユーザ・新規アイテムには行動履歴がない)。 メタデータベースのコンテンツフィルタリングとのハイブリッドが定石。
課題: 1700 を超える市区町村を、 人口動態・産業構造・財政状況の観点で類型化し、 施策のテンプレートを設計したい。
手法: SSDSE 等の公的データで 20-30 指標を標準化 → PCA で 5 軸程度に圧縮 → 階層クラスタリングで樹形図を描き、 妥当な分割位置で K を決定。 各クラスタの代表自治体を「ペルソナ」 として可視化。
評価: 既存の総務省カテゴリ(指定都市/中核市/一般市) との一致度、 施策テンプレートとの親和性。
落とし穴: 「平均」 で類型化すると東京特別区のような外れ値が全体平均を歪める。 ロバストスケーリング(中央値・IQR) や対数変換が必須。
| ケース | 代表手法 | 教師ありと併用? | 再学習頻度 |
|---|---|---|---|
| 顧客セグメンテーション | K-means + RFM | 後段で施策効果予測 | 四半期 |
| 工場異常検知 | Isolation Forest / AE | 教師なし主体 | 月次 |
| 不正取引検知 | Isolation Forest + XGB | ハイブリッド | 週次 |
| 文書クラスタリング | BERT+UMAP+HDBSCAN | 後段で文書分類 | 月次 |
| レコメンド | SVD / item2vec | 後段で CTR 予測 | 日次 |
| 地域類型化 | PCA + 階層 | 教師なし主体 | 年次 |
6 つのケースに共通するのは「教師なし学習は単独で完結しない」 という点です。 必ず「何のための分析か」(ビジネス課題) と「人間の解釈」(命名・閾値設定) を伴います。 教師なし学習は人間の認知を補助するレンズであり、 自動判断装置ではありません。
教師なし学習で最大のハマりポイントが「ハイパーパラメータをどう決めるか」 です。 教師あり学習なら検証データの精度で機械的に決められますが、 教師なしには「正解」 がないため、 複数の指標と可視化を組み合わせて意思決定する必要があります。 ここでは代表的 5 手法について、 「決め方の型」 を整理します。
K-means で唯一の重要パラメータは「クラスタ数 K」。 これを決める王道が次の 4 ステップ:
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023]; X = StandardScaler().fit_transform(df[['A1101', 'A1301', 'A4101', 'A4200']].astype(float)) for k in range(2, 9): km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(X) sse = km.inertia_ sil = silhouette_score(X, km.labels_) print(f'K={k}: SSE={sse:.1f}, Silhouette={sil:.3f}') |
📤 実行例:
💬 シルエットは K=2 が最高だが、 SSE の下がりが K=3 → 4 で大きい。 業務解釈が許せば K=4(東京/大都市圏/中核/過疎) が実務的選択。
DBSCAN の悩みは 2 つのパラメータ eps(近傍半径)と min_samples(コア点の最小近傍数)。 定石は:
PCA は「何成分残すか」 が肝。 判定基準は:
GMM では成分数 K に加え、 各成分の共分散行列の仮定(full / tied / diag / spherical) も選ぶ必要があります。 判定は AIC と BIC で:
可視化目的の非線形次元削減では、 「近傍をどの範囲とみなすか」 の調整が必要。
| 手法 | 主パラメータ | 決定方法 | SSDSE-B での例 |
|---|---|---|---|
| K-means | K | エルボー + シルエット + 解釈 | K=4 |
| DBSCAN | eps, min_samples | k近傍距離プロット + 次元×2 | eps=1.6, min=3 |
| PCA | n_components | 累積寄与率80% | n=2 (累積寄与率 88.5%) |
| GMM | n_components, covariance_type | BIC 最小 | n=3, diag |
| UMAP | n_neighbors, min_dist | サンプル数の平方根 | n_nbrs=7 |
教師なし学習はラベルなしで構造を発見する強力な道具ですが、 同時に「人間の解釈・前処理・後処理」 への依存度が極めて高い手法群でもあります。 ツールに振り回されず、 「データの何を知りたいのか」 を常に問い直しながら使うことが、 実務で価値を出すコツです。
教師なし学習の成否を決める要素のうち、 半分以上は前処理にあると言っても過言ではありません。 また、 評価指標も教師あり学習と異なり、 内部指標(データだけから計算) と外部指標(既知ラベルと照合) の使い分けが必要です。 ここでは前処理 6 種類と評価指標 8 種類を一気に整理します。
| 前処理 | 目的 | 適用ケース | 注意点 |
|---|---|---|---|
| 標準化(z-score) | 変数のスケールを揃える | K-means/PCA/距離計算 | 外れ値があると平均/分散が歪む |
| Min-Max 正規化 | 0-1 範囲に押し込む | 距離が境界依存の手法 | 外れ値で全体が押しつぶされる |
| ロバストスケーリング | 中央値/IQR で正規化 | 外れ値が多いデータ | 分散の情報は失われる |
| 対数変換 | 右に長い分布を正規化 | 金額・人口・面積など | 0/負の値の扱いに注意 |
| 欠損値補完 | 距離計算を可能にする | 実データの大半 | 単純平均で済まないことが多い |
| カテゴリエンコード | 数値化して距離計算可能に | 混合データ | One-Hot で次元が爆発する |
教師なし学習の評価は次の 2 タイプに大別されます:
| 指標 | タイプ | 範囲 | 良い値 | 補足 |
|---|---|---|---|---|
| シルエット係数 | 内部 | -1 〜 +1 | +1 に近いほど良い | 0.5 以上で強構造 |
| Davies-Bouldin | 内部 | 0 〜 ∞ | 小さいほど良い | 球状クラスタを仮定 |
| Calinski-Harabasz | 内部 | 0 〜 ∞ | 大きいほど良い | 分散比に基づく |
| SSE(慣性) | 内部 | 0 〜 ∞ | 小さいほど良い | K に強く依存 |
| ARI | 外部 | -1 〜 +1 | +1 で完全一致 | 乱数より良いか確認 |
| NMI | 外部 | 0 〜 1 | 1 で完全一致 | 情報理論ベース |
| Homogeneity | 外部 | 0 〜 1 | 1 が理想 | 純度に対応 |
| Completeness | 外部 | 0 〜 1 | 1 が理想 | 再現率に対応 |
「精度 92 %」 のように教師あり学習らしい単一指標で語れないのが教師なしの宿命です。 そのため、 「シルエット係数 0.45 で中程度の構造を示し、 別アルゴリズム DBSCAN でも同じ 4 グループ分割が再現された。 各グループの中央自治体を地図上で可視化したところ、 専門家の直感(都市圏/地方中核/半都市半農/過疎) と一致した」 のように、 内部指標・頑健性・解釈の 3 点セットで語る習慣が必要です。
教師なし学習は機械学習というよりも、 古典的な多変量解析・統計学・情報理論を起源として発展してきました。 1900 年代初頭の主成分分析、 1960 年代の階層クラスタリング、 1970 年代の K-means、 そして 2000 年代以降のニューラル系(オートエンコーダ・自己教師あり学習) まで、 時代ごとの代表手法を俯瞰すると、 教師なし学習が単なる「ラベルなし学習」 ではなく、 「データの隠れた構造を明らかにする科学」 として育ってきたことが分かります。
| 年代 | 出来事 | 意義 |
|---|---|---|
| 1901 | Pearson が主成分分析の原型を提案 | 次元削減の出発点 |
| 1933 | Hotelling が PCA の現代形を定式化 | 統計理論として確立 |
| 1958 | Sokal & Michener が階層クラスタリング | 生物分類への応用 |
| 1965 | Ward 法(凝集型階層クラスタリング) | 分散最小化の原理 |
| 1967 | MacQueen が K-means 命名 | 最も使われるクラスタリング |
| 1977 | EM アルゴリズム(Dempster ら) | GMM 等の基盤 |
| 1996 | DBSCAN(Ester ら) | 密度ベースの萌芽 |
| 2003 | LDA(Blei ら)でトピックモデル普及 | テキスト教師なし |
| 2008 | t-SNE(van der Maaten) | 非線形可視化の革命 |
| 2013 | word2vec が単語埋め込み確立 | 表現学習の幕開け |
| 2018 | UMAP, BERT の自己教師あり学習 | 大規模事前学習の時代 |
| 2020 | SimCLR/MoCo の対比学習 | 画像の自己教師あり |
系譜を理解することで「なぜこの手法はこの構造を持つのか」 が腑に落ち、 新しい手法に出会ったときも「ああ、 これは GMM の派生だな」 「これは対比学習のフレームだな」 と整理できます。 教師なし学習はラベルなしという制約を逆手に、 統計・幾何・情報理論・最適化を総動員する豊かな分野です。
2020 年代後半の教師なし学習は、 自己教師あり学習と基盤モデル(foundation model) を中心に再編されつつあります。 「ラベルなしの膨大なデータから一般的な表現を獲得し、 後段のタスクは少量データでファインチューニングする」 という流れが、 言語・画像・音声・時系列・テーブルデータすべての領域に広がっています。 そして、 マルチモーダル(複数種類のデータを同じ空間に埋め込む) や、 因果推論との融合(観察データだけから因果構造を抽出) といった発展形も急速に進化中です。 教師なし学習はもはや「ラベルがないときの代用品」 ではなく、 機械学習の主役の一翼を担う領域として位置づけ直されています。
この順序で学ぶと、 教師なし学習の歴史的発展と理論的深さを自然に追体験できます。 単なる「ラベルなし学習のテクニック集」 ではなく、 「データから世界を読み解く科学」 として教師なし学習に向き合う土台ができます。
これらの問題に取り組むと、 教師なし学習の各手法が「補完しあって 1 つのストーリーを作る」 ことが体感できます。 単独の K-means、 単独の PCA、 単独の異常検知では見えない構造が、 組み合わせて初めて浮かび上がります。 「教師なし学習はストーリーテリングの道具」 という視点が、 ここに来てようやく腹落ちするはずです。
合成 K=2 のクラスタリング結果で純度を計算する。
| クラスタ | A | B | 多数派 |
|---|---|---|---|
| C1 | 40 | 10 | A (40) |
| C2 | 5 | 45 | B (45) |
1 2 3 4 5 | import numpy as np c1 = np.array([40, 10]) c2 = np.array([5, 45]) purity = (c1.max() + c2.max()) / (c1.sum() + c2.sum()) print(f"Purity: {purity}") |
💬 手計算 (Step 2) 0.85 と Python 出力が完全一致。
教師なし学習は「正解ラベルなし」でデータの構造を抽出する一群の手法で、 前処理・モデル選定・結果解釈の各段階で他手法と密に連携する。
教師なし学習は「正解がない」ため評価が本質的に困難。 必ず可視化・ドメイン知識との照合・複数手法での結果比較 (アンサンブル評価) を組み合わせ、 単一の指標やアルゴリズムだけに頼らないこと。
「教師なし学習」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。
このフローに沿って判断することで、 「教師なし学習」を中核とした適切な手法選択ができる。
教師なし学習は「正解ラベルがないデータから、自分で構造 (かたまり) を見つける」手法です。 下の白いキャンバスをクリック (スマホはタップ) して点を自由に置いてください。 点には色 (=グループ) が付いていません。 そこで クラスタ数 k をスライダーで決めて「クラスタリング実行」を押すと、 K-means がラベルなしのまま点をグループ分けし、 各グループの中心 (★) が動いていく様子が見えます。 正解を一切与えていないのに、 データの「かたまり」が浮かび上がることを体感してください。
★ = クラスタ中心 (セントロイド)。 K-means は「① 各点を最も近い中心に割り当て → ② 各中心をそのグループの平均位置へ移動」を、 中心が動かなくなる (収束) まで繰り返します。 WCSS は各点と自グループ中心の距離の二乗和で、 小さいほど各かたまりが密です。 同じデータでも初期値次第で結果が変わるため、 何度か「サンプル配置」や実行を試すと 局所解 の存在が体感できます。
教師あり学習が「問題と正解のペア」で学ぶのに対し、 教師なし学習は正解 (ラベル) が一切ないデータだけを見て、 似たもの同士を集めたり (クラスタリング)、 少ない軸で要約したり (次元削減) します。 上の体験で、 あなたは点に色を付けていません。 それでも K-means は距離の近さだけを手がかりに「ここが 1 つのかたまり」と判断しました。 これが「データ自身に語らせる」教師なし学習の核心です。
関連: クラスタリング / K-means / DBSCAN / PCA / t-SNE / 標準化 (次元削減・異常検知・シルエット係数・エルボー法の専用ページは未整備のため本文内で解説)
この節は既存の各節(K-means / DBSCAN / PCA / 階層 / Isolation Forest の実演)とは角度を変え、「同じデータでも、前処理・乱数シード・手法を変えると結論が動く」という教師なし学習の本質を、SSDSE-B-2026(2023 年・47 都道府県)の実測値で 定量的に 突きつけます。使用列は A1101 総人口 / A1301 15歳未満人口 / A4101 出生数 / A5101 転入者数。数値は scikit-learn で実際に計算した実測値です(合成データは使っていません)。
教師あり学習には「答え合わせ」ができる正解ラベル(y)があります。教師なし学習にはそれが無い。だからアルゴリズムが出した「グループ」は、正しい答えではなく、あなたが選んだ設定が作り出した一つの見え方にすぎません。カメラのレンズを変えれば同じ風景が違って写るのと同じで、標準化するか・乱数の種を何にするか・どの手法を使うか、というレンズを変えると、同じ 47 都道府県が別々のグループに振り分けられます。この節では「レンズを変えると結果がどれだけ動くか」を、2 つの分割の一致度を測る指標 調整ランド指数(ARI)(1.0=完全一致、0 付近=でたらめと同程度)で数値化します。
① 前処理(標準化)ひとつで、分け方が別物になる。 特徴量を「総人口」と「15歳未満人口比率(=A1301/A1101×100, 単位 %)」の 2 つにして K-means(K=3)を回すと──
| 前処理 | 各クラスタの県数 | 各クラスタの子ども比率平均 | 読み取れること |
|---|---|---|---|
| 標準化なし(生値) | 1 / 8 / 38 | 10.74% / 11.47% / 11.49% | 3 群でほぼ差が無く、比率は無視された。単独クラスタは東京都(総人口 14,086,000)で、実質人口の大小で並べただけ。 |
| 標準化あり | 7 / 13 / 27 | 11.40% / 12.68% / 10.90% | 子ども比率が群ごとにはっきり分かれ、比率がクラスタ形成に効いた。 |
この 2 つの分割の一致度は ARI = 0.355。前処理を切り替えただけで、半分以上の県が別グループに移っています。桁の大きい変数(総人口, 約 10⁶)が桁の小さい変数(比率, 約 10¹)を距離計算で圧倒するためで、標準化は「おまけ」ではなく結論そのものを決める工程です。標準化を参照。
② 同じ手法・同じデータでも、乱数シードで結果がばらつく。 4 変数(総人口・15歳未満人口・出生数・転入者数)を標準化し、K-means(K=5, n_init=1)をシードだけ変えて 10 回実行し、最初の結果と比べると:
n_init を増やす(複数回試して最良を採る)・random_state を固定して再現性を担保するのが必須。論文に「K-means でクラスタリングした」とだけ書いてシードを書かないと、他人が再現できません。③ 手法(リンケージ)を変えると、一致したり大崩れしたりする。 同じ標準化済み 4 変数・K=5 で:
「クラスタリングした」という一言の裏に、これだけ結論を左右する選択が隠れています。教師なしの結果は“発見”ではなく“設計”の産物だと自覚し、複数設定で頑健性(どの設定でも一緒に固まる県はどこか)を確かめるのが正攻法です。
📝 最大の罠は「後づけ解釈」。 出たクラスタに「これは都市型」「これは高齢化地域」と後から物語を貼ると、どんな分割でももっともらしく見えてしまう(人間は乱数にも意味を見出す)。ラベルが無い=反証できないので、解釈は「仮説」に留め、外部指標(別データ・専門知識)で裏を取るまで結論にしないこと。
教師あり学習(正解ラベルの有無という対比) / クラスタリング(グループ教材) / クラスタリング / K-means / 階層クラスタリング / DBSCAN / 次元削減 / 標準化