論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
Isomap(等長写像)
Isometric Mapping
次元削減 多様体学習

🔖 キーワード索引

このページに登場する主要キーワード。 クリックで該当セクションへ。

💡 30 秒結論 📍 文脈 🎨 直感 📐 定義・数式 🔬 数式を言葉で 🧮 実値で計算 🎮 触って理解する 🐍 Python 実装 ⚠️ 落とし穴 🧠 さらに深掘り 🌐 関連手法 🔗 関連用語 🔗 橋渡し 🌳 手法選択フロー

💡 30秒で分かる結論

🍰 まずはやさしく

曲がったデータを平らに広げる道具です。

データの本当の距離を保つために使います。

都道府県ごとの特徴を地図にする例があります。

この章では計算の手順と注意点を読みます。

Isomap は、高次元データが乗っている「曲がった多様体」の上の測地距離(曲面に沿った最短距離)を保ったまま低次元に落とす、非線形の次元削減法。

本記事は SSDSE-B-2026(教育用標準データセット、独立行政法人統計センター提供)の 47 都道府県データを題材に、10 の社会指標から Isomap で 2 次元埋め込みを作り、大都市/北日本/南日本が滑らかに並ぶ様子を再現する。

📍 文脈ボックス — あなたが今見ているもの

🍰 まずはやさしく

データの次元を減らす手法の解説ページです。

複雑なデータの形を正しく捉えるために使います。

47都道府県の統計データを使って学びます。

このページでは3つの学習プランを提示します。

あなたは Isomap(Isometric Mapping) の用語ページを読んでいる。 これは「次元削減 / 多様体学習」カテゴリに属し、 PCA の次に学ぶ非線形次元削減の入口となる手法である。 本ページは 3 つの読み方を提供する:

  1. 15 分で全体像:「30 秒結論」→「直感で掴む」→「定義」だけを通読する。
  2. 60 分で実装まで:「Python 実装」を写経し、 SSDSE-B-2026 で手元の埋め込みを再現する。
  3. じっくり理解:「落とし穴」「関連手法」「実務メモ」で t-SNE / UMAP との使い分けまで押さえる。

本記事の計算は data/raw/SSDSE-B-2026.csv(cp932、2 行目に単位行、564 行 × 112 列 = 2012〜2023 年の 12 年分 × 47 都道府県)を用い、 2023 年断面の 47 行に絞って行う。 合成データ・乱数生成は使わない(KMeans の初期化のみ random_state 固定)。

🎨 直感で掴む

🍰 まずはやさしく

丸まった紙をシワなく広げるイメージです。

表面に沿った正しい距離を測るために使います。

ロールケーキの上をアリが歩く例で考えます。

この章では距離の測り方の違いを読みます。

Isomap のイメージは 「丸めた紙をシワを保ったまま広げる」。 高次元空間で曲がって配置されたデータを、 曲面に沿った距離(測地距離)を壊さずに平らな低次元へ広げ直す。

🎨 3 つの比喩

🌀 スイスロール比喩
巻いたロールケーキの表面にアリが歩く道のりを測りたい。 直線距離(PCA)は生地を貫通してしまうが、 測地距離(Isomap)は生地に沿って歩く。 Isomap はロールをほどいて平らなシートに戻す。
🗺 地図の描き直し比喩
47 都道府県を緯度経度ではなく「社会指標の類似度」で並べ直すと、 東京と沖縄が遠く、 青森と秋田が近い地図になる。 Isomap は「見たい関係に応じて地図を描き直す」視点の切替である。
🕸 飛び石比喩
川を渡るとき、 遠い岸へ一足飛び(直線距離)はできない。 近い飛び石(k 近傍)を伝って渡る道のりの合計が測地距離。 Isomap はこの「石伝いの距離」で全都道府県の位置関係を測る。

もう一歩深い直感 — 測地距離とユークリッド距離

同じ 2 点でも「距離の測り方」で位置関係が変わる。 これが Isomap と PCA の分かれ道である。

測り方意味SSDSE-B-2026 での例
ユークリッド距離(PCA)空間を直線で貫く最短距離東京と沖縄を「指標の差の二乗和」で直接測る
測地距離(Isomap)近傍グラフを伝ったときの道のり東京→(神奈川→愛知→大阪→…)→沖縄と、 似た県を経由して測る

データが「都市規模の連続体」のような 1 本の曲がった帯の上に乗っているとき、 測地距離はその帯に沿って伸び、 PCA が潰す構造を Isomap は保てる。

📐 定義

🍰 まずはやさしく

曲面上の距離を保つ計算方法のことです。

直線では測れないデータの構造を知るために使います。

スマホのデータなど複雑な数値に活用できます。

この章では使う条件や仕組みについて読みます。

Isomap(Isometric Mapping、等長写像)は、 データが低次元の多様体(曲面)上に乗っているという多様体仮説のもとで、 多様体上の測地距離をできるだけ保つように低次元へ埋め込む非線形次元削減法。 2000 年に Tenenbaum・de Silva・Langford が Science 誌で発表した。

🎯 いつ・どこで使うか

📋 前提条件・適用範囲

📐 アルゴリズムと数式

入力を $n$ 個の高次元点 $\{x_1,\dots,x_n\}$、 $x_i\in\mathbb{R}^D$ とする。 Isomap は次の 3 ステップで低次元座標 $\{y_1,\dots,y_n\}$、 $y_i\in\mathbb{R}^d$(通常 $d=2,3$)を求める。

ステップ1:近傍グラフ構築。 各点 $x_i$ について最も近い $k$ 個の点を辺で結び、 辺の重みをユークリッド距離 $\lVert x_i-x_j\rVert$ とする重み付きグラフ $G$ を作る。

ステップ2:測地距離の推定。 グラフ $G$ 上の最短経路長 $d_G(i,j)$ を Dijkstra 法または Floyd-Warshall 法で全点対に計算する。 これが多様体上の測地距離の近似となる:

$$D_{ij} = d_G(i,j) = \min_{\text{path }i\to j}\ \sum_{(u,v)\in\text{path}} \lVert x_u - x_v\rVert$$

ステップ3:古典的 MDS。 測地距離行列 $D$(各要素は二乗して用いる)を二重中心化した行列 $B=-\tfrac{1}{2}HD^{(2)}H$($H=I-\tfrac{1}{n}\mathbf{1}\mathbf{1}^\top$ は中心化行列)を固有分解し、 上位 $d$ 個の固有値・固有ベクトルから低次元座標を得る。 これは次の応力(stress)を最小化することに相当する:

$$\min_{y_1,\dots,y_n}\ \sum_{i

つまり「高次元での測地距離 $D_{ij}$ を、 低次元でのユークリッド距離 $\lVert y_i-y_j\rVert$ でできるだけ再現する」座標を探す。 PCA が距離行列にユークリッド距離を使うのに対し、 Isomap はそこだけを測地距離に差し替えた——これが「線形 MDS を非線形に拡張した」と言われる理由である。

📜 Isomap をめぐる系譜

出来事Isomap との関係
1952Torgerson: 古典的 MDS距離行列から座標を復元する土台。 Isomap のステップ3そのもの
1962Shepard / Kruskal: 非計量 MDS「距離を保つ埋め込み」という発想の源流
1998Schölkopf ら: Kernel PCA非線形次元削減の別系統(カーネルで高次元化)
2000Tenenbaum・de Silva・Langford: IsomapMDS に「測地距離」を持ち込み多様体学習を創始
2000Roweis・Saul: LLE同年発表。 局所線形性を保つ姉妹手法
2003Belkin・Niyogi: Laplacian Eigenmapsグラフラプラシアンで局所構造を保存
2008van der Maaten・Hinton: t-SNE可視化で事実上の標準に。 局所構造を強調
2018McInnes・Healy: UMAP大域構造の保持と速度を改善、 大規模データ向け

🔬 数式を言葉で読み解く(3 ステップ・ナレーション)

🎬 ナレーション 1:近傍グラフ $G$ の意味

最初に作る $k$ 近傍グラフは「どの県とどの県が直接似ているか」の地図だ。 各県から最も近い $k$ 県へ線を引く。 このとき遠い県どうしには直接の線を引かないのがポイント。 東京と沖縄の間には線がなく、 東京→神奈川→…→鹿児島→沖縄のように、 似た県を伝わないと辿り着けない。 この「伝い歩き」の構造こそ多様体の形を写している。

🎬 ナレーション 2:測地距離 $D_{ij}$ と最短経路

$D_{ij}=d_G(i,j)$ は「グラフ上を石伝いに歩いた最短の道のり」。 直線で測れば近く見える 2 点でも、 多様体が曲がっていれば道のりは長くなる。 SSDSE-B-2026 では、 東京と沖縄はユークリッド距離でも遠いが、 測地距離ではさらに「大都市の連続体をぐるっと回る」ぶん相対的に伸びる。 この伸びが後の 2 次元配置で「東京と沖縄をより遠くに置く」効果を生む。

🎬 ナレーション 3:古典 MDS と応力最小化

最後に $\min_{y}\sum_{ireconstruction_error はこの応力の残差に対応し、 小さいほど測地距離をよく再現できている。

🧮 実値で計算してみる(SSDSE-B-2026 2023 年 47 都道府県)

data/raw/SSDSE-B-2026.csv2023 年の 47 行に絞り、 主要指標を眺めてから、 測地距離の計算を手で追う。

STEP 1: データを眺める(2023 年の抜粋・実値)

Prefecture A1101(総人口) A1303(65歳以上) A4200(死亡数) A9101(婚姻件数) B4101(年平均気温) 北海道 5,092,000 1,681,000 75,120 17,281 11.0 東京都 14,086,000 3,205,000 137,241 71,774 17.6 大阪府 8,763,000 2,424,000 104,964 38,513 18.0 愛知県 7,477,000 1,923,000 80,557 31,759 17.5 沖縄県 1,468,000 350,000 15,110 6,316 23.8 鳥取県 537,000 179,000 8,290 1,810 16.6 … (全 47 県)

STEP 2: 基本統計(実測)

意味minmedianmaxstd
A1101総人口537,000 (鳥取)1,549,00014,086,000 (東京)2.80e6
A130365歳以上人口179,000 (鳥取)524,0003,205,000 (東京)6.94e5
A4200死亡数8,290 (鳥取)23,744137,241 (東京)2.91e4
A9101婚姻件数1,810 (鳥取)5,59971,774 (東京)1.31e4
B4101年平均気温(℃)11.0 (北海道)17.423.8 (沖縄)2.05

STEP 3: 主要指標間の相関(Isomap 前の多重共線性チェック)

ペアPearson r解釈
A1101 vs A91010.989総人口と婚姻件数はほぼ完全相関 → 規模の軸に強く支配される
A1101 vs A13030.991総人口と高齢者数もほぼ完全相関
A1101 vs A42000.989総人口と死亡数もほぼ完全相関
B4101 vs A13030.084気温と高齢者数はほぼ無相関 → 規模とは独立な軸

人口系の指標は強く相関し「規模」という 1 本の軸を作る。 気温はそれと独立。 標準化後に Isomap を掛けると、 この「規模の軸」と「気候(南北)の軸」が第 1・第 2 軸として現れやすい。

🧮 手で追う: 測地距離(グラフ最短経路)

4 点だけの小さな近傍グラフで、 測地距離が直線距離と食い違う様子を確認する。

Step A: 隣接(辺の重み)

辺: 1-2 (重み1), 2-3 (重み1), 3-4 (重み1), 1-4 (重み5) 点1→点4 の直線的な辺の重み: 5 点1→2→3→4 と伝った道のり: 1+1+1 = 3

Step B: Floyd 後(全点対最短経路)

d(1,2)=1, d(1,3)=2, d(1,4)=3 ← グラフ最短を採用 直線の辺では 1-4=5 だが、多様体上の道のりは 3 → Isomap は「曲面に沿った距離」を保持する

🐍 Python で再現

①目的:上の手計算($d(1,4)=3$)を scipy の最短経路で確かめる。 ②橋渡し:隣接行列を渡し Floyd-Warshall を回すだけ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import numpy as np
from scipy.sparse.csgraph import shortest_path
# 4点の近傍グラフ(辺の重み=つないだ点の間のユークリッド距離)
adj = np.array([
  [0, 1, 0, 5],
  [1, 0, 1, 0],
  [0, 1, 0, 1],
  [5, 0, 1, 0]
], dtype=float)
# Floyd-Warshall で全点対の最短経路(=測地距離)を求める
dist = shortest_path(adj, method='FW', directed=False)
print(dist)

📤 実行結果

[[0. 1. 2. 3.] [1. 0. 1. 2.] [2. 1. 0. 1.] [3. 2. 1. 0.]]

💬 読み取り:$d(1,4)=3$ と手計算が完全一致。 直線の辺重み 5 ではなく、 グラフを伝った 3 が採用されている。 Isomap はこの測地距離行列を MDS に渡す。

🎮 触って理解する — 測地線距離 vs ユークリッド距離(合成デモ)

下の渦巻きは合成デモ用データ(2 次元スパイラル上の 60 点、SSDSE-B-2026 とは無関係の人工データ)。 点をタップまたはドラッグすると、 近いほうの端点 AB がその位置の点に移動する。 2 点間のユークリッド距離(赤破線)と、 k 近傍グラフ上を Dijkstra 法で辿った最短経路=測地線距離の近似(青折れ線)が同時に表示される。 スライダーで近傍数 $k$ を動かし、 グラフの形と 2 つの距離がどう変わるかを見てほしい。

1 次元への展開(unrolling):下の帯は、 渦巻きの内端の点からの測地線距離を横軸にして全点を 1 直線上に並べ直したもの。 1 本の曲線ではこれが古典 MDS の 1 次元解と一致する(弧長座標=等長な展開)。 $k=3$〜$5$ では色(渦巻き上の順番)が左から右へ滑らかに並び、 スパイラルが 1 本の直線に伸びる。 $k$ を上げてショートカットが入ると順番が崩れて折り畳まれ、 $k$ を下げてグラフが切れると置けない点(灰色)が現れる。

初期状態($k=4$、 A=内端付近・B=外端付近)の代表値(本デモの実装で検証済み・単位は画面座標 px):

kグラフユークリッド距離 A–B測地線距離 A–B(Dijkstra)読み取り
1〜2非連結217.0∞(経路なし)k が小さすぎて渦巻きの途中でグラフが切れる
4連結217.0995.4(27 ホップ、直線の約 4.6 倍)渦に沿って歩く「正しい」測地線
6連結217.0328.1(6 ホップ)腕をまたぐショートカット辺が入り測地線が崩壊
12連結217.0246.6(3 ホップ)ほぼ直線距離に退化= Isomap が PCA 化する

💡 デモから学ぶ直感 — 多様体の上を「歩く」

渦巻きの上のアリは紙面から離れられない。 A から B へ「空中を直線で飛ぶ」のがユークリッド距離、 「渦に沿って歩く」のが測地線距離である。 このデモでは直線 217 px に対し道のりは 995 px——データが曲がった多様体に乗っているとき、 2 つの距離は何倍も食い違う。 Isomap の本質は、 この「歩く距離」を k 近傍グラフの最短経路で近似し(内端から外端まで全長約 1,060 px)、 それを保ったまま低次元に置き直すことに尽きる。 下の帯がまさにその結果で、 巻かれていた 1 次元構造が直線として取り出される。

⚠️ デモが示す落とし穴 — k の 3 つの顔

スライダーを往復すると、 $k$ には「小さすぎ・ちょうど良い・大きすぎ」の 3 状態しかないことが体感できる。 (1) 小さすぎ(k=1〜2):点がまばらな区間でグラフが非連結になり、 測地線距離が定義できず Isomap は破綻する(本デモは渦の中腹に意図的に隙間を入れてある)。 (2) ちょうど良い(k=3〜5):辺が渦に沿ってのみ張られ、 最短経路が本当の「巻きに沿った道のり」をなぞる。 (3) 大きすぎ(k≥6):内側の腕と外側の腕を直接つなぐショートカット辺(short-circuit)が混入し、 測地線が 995→328→247 px と一気に潰れて直線距離側へ退化する。 さらに実データでは、 密度が場所によって違うため同じ $k$ でも領域ごとに (1) と (3) が同時に起きうること、 多様体に穴や凹み(非凸性)があると測地線がそれを迂回して距離が歪むこと、 そして学習後に新しい点を追加できない(近傍グラフと最短経路の再計算が必要で out-of-sample 埋め込みが苦手)ことも押さえておきたい。

🌐 発展 — MDS との関係、LLE / t-SNE / UMAP との違い

このデモの「測地線距離行列」に古典 MDS(距離行列の二重中心化+固有分解)を掛けたものが Isomap の全てである。 つまり Isomap = MDS の距離だけを測地線距離に差し替えた手法で、 下の 1 次元展開はその最小構成(曲線なら弧長座標がそのまま MDS 解になる)。 一方 LLE は最短経路を計算せず「各点を近傍の線形結合で再構成する重み」を保ち、 t-SNEUMAP は距離そのものではなく「近傍である確率・位相」を保つ。 このため t-SNE/UMAP はデモのような大域の道のり(A–B が直線の 4.6 倍遠い、 という情報)を再現する保証がなく、 逆に Isomap はショートカット 1 本で大域構造が壊れる敏感さを持つ。 全体像は 多様体学習、 線形側の対照は PCA を参照。

🐍 Python での実装

まず SSDSE-B-2026 の読み込み定型を確認する。 ①目的:cp932・単位行スキップ・年フィルタを正しく行う。

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
1
2
3
4
5
6
7
8
import pandas as pd
# SSDSE-B-2026 は cp932、2行目が日本語の単位行なので skiprows=[1] で外す
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
print(df.shape)                     # (564, 112)  = 12年 x 47県
print(df['SSDSE-B-2026'].unique())  # [2012 ... 2023]
# 分析はある年の断面(47行)を取り出して行う
df_2023 = df[df['SSDSE-B-2026']==2023].copy()
print(df_2023.shape)                # (47, 112)
📤 実行例(実測) (564, 112) [2023 2022 2021 2020 2019 2018 2017 2016 2015 2014 2013 2012] (47, 112)

実装 1: 47 都道府県を Isomap で 2 次元に埋め込む

①目的:10 指標から Isomap の 2 次元座標を作り、 各県がどこに並ぶかと再構成誤差を見る。 ②橋渡し:標準化 → Isomap(n_neighbors=5, n_components=2)fit_transform するだけ。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数) A9101(婚姻件数) B4101(年平均気温) 北海道 5,092,000 1,681,000 75,120 17,281 11.0 東京都 14,086,000 3,205,000 137,241 71,774 17.6 沖縄県 1,468,000 350,000 15,110 6,316 23.8 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
from sklearn.manifold import Isomap
from sklearn.preprocessing import StandardScaler

# cp932(=shift_jis)・2行目(日本語の単位行)を skiprows=[1] で除外
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df_2023 = df[df['SSDSE-B-2026']==2023].copy().reset_index(drop=True)

# 10 指標: 総人口/65歳以上/死亡数/婚姻件数/気温/降水日数/幼小中学校数/消費支出
feats = ['A1101','A1303','A4200','A9101','B4101','B4106','E1101','E2101','E3101','L3221']
X = df_2023[feats].fillna(df_2023[feats].median()).values
Xs = StandardScaler().fit_transform(X)   # 桁の違う指標を平均0・分散1に揃える(必須)

iso = Isomap(n_neighbors=5, n_components=2)
emb = iso.fit_transform(Xs)
df_2023['iso1'], df_2023['iso2'] = emb[:,0], emb[:,1]

print("47 都道府県を Isomap 2D に埋め込み (先頭10県):")
print(df_2023[['Prefecture','iso1','iso2']].head(10).to_string(index=False))
print(f"\nreconstruction_error = {iso.reconstruction_error():.3f}")

📤 実行結果

47 都道府県を Isomap 2D に埋め込み (先頭10県): Prefecture iso1 iso2 北海道 6.895788 -0.046130 青森県 -4.457848 -3.469026 岩手県 -2.185579 -2.574948 宮城県 0.163313 -0.481540 秋田県 -4.548545 -2.639744 山形県 -2.097401 -1.830515 福島県 0.103943 -0.418408 茨城県 0.811598 -0.147080 栃木県 -0.369301 -0.996791 群馬県 -0.495620 1.116669 reconstruction_error = 1.592

💬 読み取り:第 1 軸 iso1 は概ね「規模(大都市 ↔ 地方)」を表し、 総人口・婚姻件数の大きい北海道が右端(正の大きな値)、 人口の小さい東北の県が左側(負)に並ぶ。 第 2 軸 iso2 は南北・気候に対応する。 reconstruction_error=1.592 は k=5 のときの測地距離の再現残差で、 単独では良否を判断せず、 次の実装 3 で $k$ を振って相対比較する。

実装 2: Isomap(測地距離)と PCA(直線距離)を比べる

①目的:同じデータに Isomap と PCA を掛け、 「測地距離を使うと距離がどう伸びるか」を数値で見る。 ②橋渡し:実装 1 の埋め込みに PCA を並べ、 最も離れた東京-沖縄の距離を比較する。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数) A9101(婚姻件数) B4101(年平均気温) 北海道 5,092,000 1,681,000 75,120 17,281 11.0 東京都 14,086,000 3,205,000 137,241 71,774 17.6 沖縄県 1,468,000 350,000 15,110 6,316 23.8 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Isomap(測地距離) vs PCA(直線距離) を同じデータの 2D 埋め込みで比較
import pandas as pd
import numpy as np
from sklearn.manifold import Isomap
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

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

feats = ['A1101','A1303','A4200','A9101','B4101','B4106','E1101','E2101','E3101','L3221']
X = StandardScaler().fit_transform(df_2023[feats].fillna(df_2023[feats].median()).values)

iso_emb = Isomap(n_neighbors=5, n_components=2).fit_transform(X)
pca_emb = PCA(n_components=2).fit_transform(X)

print(f"Isomap 第1軸 分散: {iso_emb[:,0].var():.3f}")
print(f"PCA    第1軸 分散: {pca_emb[:,0].var():.3f}")

# 東京と沖縄(社会構造が最も離れた2県)の 2D 上の距離
tk = df_2023.index[df_2023['Prefecture']=='東京都'][0]
ok = df_2023.index[df_2023['Prefecture']=='沖縄県'][0]
print(f"\n東京-沖縄 Isomap 距離: {np.linalg.norm(iso_emb[tk]-iso_emb[ok]):.3f}")
print(f"東京-沖縄 PCA    距離: {np.linalg.norm(pca_emb[tk]-pca_emb[ok]):.3f}")

📤 実行結果

Isomap 第1軸 分散: 12.424 PCA 第1軸 分散: 7.101 東京-沖縄 Isomap 距離: 15.786 東京-沖縄 PCA 距離: 12.550

💬 読み取り:Isomap は「多様体上の道のり」を保つため、 第 1 軸の分散も、 東京-沖縄の距離も PCA より大きくなる。 東京と沖縄は人口・気候・経済が大きく違い、 多様体上を似た県伝いに遠回りする必要があるので、 Isomap ではより遠くに配置される。 これが線形の PCA では出せない非線形の効き方である。

実装 3: 近傍数 $k$ の影響(再構成誤差と trustworthiness)

①目的:Isomap の最重要パラメータ $k$ を 3〜15 で振り、 埋め込み品質がどう動くかを測る。 ②橋渡し:ループで $k$ を変え、 reconstruction_errortrustworthiness を並べて出す。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数) A9101(婚姻件数) B4101(年平均気温) 北海道 5,092,000 1,681,000 75,120 17,281 11.0 東京都 14,086,000 3,205,000 137,241 71,774 17.6 沖縄県 1,468,000 350,000 15,110 6,316 23.8 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 近傍数 k を変えて再構成誤差と trustworthiness を観察する
import pandas as pd
from sklearn.manifold import Isomap, trustworthiness
from sklearn.preprocessing import StandardScaler

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

feats = ['A1101','A1303','A4200','A9101','B4101','B4106','E1101','E2101','E3101','L3221']
X = StandardScaler().fit_transform(df_2023[feats].fillna(df_2023[feats].median()).values)

print("  k | reconstruction_error | trustworthiness")
for k in [3, 5, 7, 10, 15]:
    iso = Isomap(n_neighbors=k, n_components=2)
    emb = iso.fit_transform(X)
    err = iso.reconstruction_error()
    tw = trustworthiness(X, emb, n_neighbors=5)
    print(f" {k:2d} |        {err:.3f}         |     {tw:.3f}")

📤 実行結果

k | reconstruction_error | trustworthiness 3 | 1.979 | 0.952 5 | 1.592 | 0.964 7 | 1.291 | 0.960 10 | 1.083 | 0.960 15 | 0.981 | 0.963

💬 読み取りreconstruction_error は $k$ を増やすほど単調に下がるが、 これは近傍が密になり測地距離がユークリッド距離に近づく(=多様体を跨ぐ近道が増え PCA に退化していく)ためで、 「小さいほど良い」と鵜呑みにできない。 一方 trustworthiness(高次元の近傍関係の保存度、 1.0 が最良)は $k=5$ で最大 0.964。 $n=47$ と小さい本データでは $k=5$〜7 が「グラフが連結し、 かつ近道が入りすぎない」バランス点。 誤差の絶対値ではなく trustworthiness と合わせて $k$ を選ぶ。

実装 4: Isomap → KMeans で 47 県を 4 グループに分ける

①目的:Isomap で 3 次元に圧縮してからクラスタリングし、 直接 10 次元で KMeans した場合と分離度を比べる。 ②橋渡しIsomap(n_components=3)KMeans(4) と、 素の 10 次元 KMeans の Silhouette を比較する。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数) A9101(婚姻件数) B4101(年平均気温) 北海道 5,092,000 1,681,000 75,120 17,281 11.0 東京都 14,086,000 3,205,000 137,241 71,774 17.6 沖縄県 1,468,000 350,000 15,110 6,316 23.8 …(全 47 行)
 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
# Isomap で 3D に圧縮 → KMeans、直接 KMeans(10D) と比較
import pandas as pd
from sklearn.manifold import Isomap
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])
df_2023 = df[df['SSDSE-B-2026']==2023].copy().reset_index(drop=True)

feats = ['A1101','A1303','A4200','A9101','B4101','B4106','E1101','E2101','E3101','L3221']
X = StandardScaler().fit_transform(df_2023[feats].fillna(df_2023[feats].median()).values)

emb3 = Isomap(n_neighbors=7, n_components=3).fit_transform(X)   # 10D -> 3D
km_10 = KMeans(n_clusters=4, random_state=42, n_init=10).fit(X)
km_3  = KMeans(n_clusters=4, random_state=42, n_init=10).fit(emb3)

print(f"直接 KMeans (10D)    Silhouette = {silhouette_score(X, km_10.labels_):.3f}")
print(f"Isomap->KMeans (3D)  Silhouette = {silhouette_score(emb3, km_3.labels_):.3f}")

df_2023['c'] = km_3.labels_
print("\nIsomap+KMeans の 4 クラスタ:")
for k in range(4):
    mem = df_2023[df_2023['c']==k]['Prefecture'].tolist()
    print(f" c{k} ({(df_2023['c']==k).sum()}件): {mem[:6]}")

📤 実行結果

直接 KMeans (10D) Silhouette = 0.327 Isomap->KMeans (3D) Silhouette = 0.423 Isomap+KMeans の 4 クラスタ: c0 (9件): ['和歌山県', '香川県', '愛媛県', '高知県', '佐賀県', '長崎県'] c1 (18件): ['宮城県', '福島県', '茨城県', '栃木県', '群馬県', '山梨県'] c2 (9件): ['北海道', '埼玉県', '千葉県', '東京都', '神奈川県', '愛知県'] c3 (11件): ['青森県', '岩手県', '秋田県', '山形県', '新潟県', '富山県']

💬 読み取り:Isomap で 3 次元に圧縮してから KMeans を掛けると Silhouette が 0.327→0.423 に改善。 「次元削減でクラスタが見えやすくなる」典型例である。 得られた 4 群は c2=大都市圏、 c3=北日本の県、 c0=西日本・四国、 c1=中規模のその他、 と地理・規模で解釈できる。

⚠️ よくある落とし穴と誤解

❌ k 近傍グラフが連結しない
$k$ が小さすぎる(例 $k=3$)と近傍グラフが分断され、 測地距離が $\infty$ になる。 sklearn.manifold.IsomapDisconnected graph 警告を出し埋め込みが破綻するので、 $k$ を 5〜10 に増やすか連結成分を確認する。
❌ short-circuit(近道)の発生
$k$ が大きすぎると本来遠い 2 点が近傍として直接つながり、 多様体を「短絡」する。 $n$ が小さいほど起きやすく、 $k=15$ を超えるとほぼ全結合になり Isomap は PCA に近づく(実装 3 で誤差が下がり続けるのはこの兆候)。
❌ 標準化を忘れる
総人口(10⁶)と気温(10¹)を生のまま使うと、 距離が総人口だけで決まり気温の軸が消える。 StandardScaler で平均0・分散1に揃えてから Isomap を掛ける。
❌ 「測地距離=ユークリッド距離」という誤解
測地距離は近傍グラフを伝った道のりで、 直線距離とは別物。 平らな多様体では両者は一致するが、 曲がった多様体では測地距離のほうが長い。 この差こそ Isomap が PCA と違う結果を出す源泉。
❌ 曲がった構造を PCA で見ようとする
スイスロールや S 字のように「折り畳まれた」データは、 PCA だと表と裏が重なって潰れる。 こうした構造こそ Isomap(や LLE)の出番で、 逆に構造がほぼ平面ならわざわざ Isomap を使う必要はない。
❌ 学習後に新しい点を埋め込めると思い込む
Isomap の埋め込みは「学習に使った点全体の測地距離行列」から作られるため、 新規点の追加(out-of-sample 埋め込み)には近傍探索と最短経路の再計算が要る。 sklearntransform() は近似(学習点への距離から補間)であり厳密な再学習ではない。 逐次データや本番推論で埋め込みを使うなら、 transform が高速で一貫する UMAP やパラメトリックな手法を検討する。
❌ 非凸・穴あき多様体で測地線を過信する
Isomap の理論保証は多様体が「凸な領域を等長に曲げたもの」である場合の話。 ドーナツ状に穴が空いていたり、 くびれ・分岐がある多様体では、 最短経路が穴を迂回するぶん測地距離が本来の内在距離より長く歪み、 埋め込みが引き伸ばされる。 上の🎮デモで渦の中腹の隙間が $k$ 小で非連結を起こすのと同根の問題で、 データの「形」の確認が先決である。

🧠 さらに深掘り — 幾何・近似の正しさ・次元の呪い

ここまでの「30秒結論〜落とし穴」を踏まえ、 「なぜ測地距離でなければ展開できないのか」「グラフ最短経路は本当に測地距離なのか」「次元の呪いとどう関係するのか」という 3 つの問いを掘り下げる。 PCA との対照、 多様体学習全体の中での位置づけを意識して読み進めてほしい。

🎨 直感の深化 — 内在次元と「折り畳み」の幾何

Isomap の前提である多様体仮説は「$D$ 次元空間に散らばって見えるデータが、 実は $d\ll D$ 次元の曲がった面(多様体)の上にほぼ乗っている」というもの。 この $d$ を内在次元(intrinsic dimension)と呼ぶ。 合成例(架空・合成データ)のスイスロールは、 3 次元空間に置かれているが本質は 2 次元シート(内在次元 $d=2$)を丸めただけである。 PCA は「空間を貫く直線」しか引けないため、 丸まって重なったシートの表と裏を同一視して潰す——これが「線形手法は折り畳みに弱い」ことの正体だ。

🔑 鍵となる非対称性
ユークリッド距離は「局所」では信頼でき、 「大域」では信頼できない。 曲面上の十分近い 2 点なら、 曲がりが無視でき直線距離=測地距離とみなせる。 だが遠い 2 点では曲面に沿った道のりが直線を大きく上回る。 Isomap はこの性質を逆手に取り、 「近い所(k 近傍)ではユークリッド距離を信じ、 遠い所はそれを継ぎ足して測る」。 継ぎ足しの経路探索がステップ 2 の最短経路計算である。 SSDSE-B-2026 で東京-沖縄が Isomap では 15.79、 PCA では 12.55 と伸びた(上の実装 2)のは、 まさにこの「近い県を伝う継ぎ足し」の効果だ。

📐 グラフ最短経路は本当に測地距離か — 近似の収束保証

「k 近傍グラフの最短経路 $d_G$」はあくまで真の測地距離 $d_M$ の近似である。 では、 どんな条件でこの近似は正しくなるのか。 Isomap の原著と同時期の理論(Bernstein・de Silva・Langford・Tenenbaum, 2000, "Graph approximations to geodesics on embedded manifolds")は、 標本数 $n\to\infty$ かつ近傍半径を適切に縮めていけば、 $d_G$ が真の測地距離 $d_M$ に(任意の精度で)収束することを示した。 つまり Isomap は「データが十分密なら測地距離を正しく復元できる」という漸近的な保証を持つ、 数学的に裏付けられた手法である。

この保証が破れるのが落とし穴の温床になる。 (1) 標本が疎だと継ぎ足しの刻みが粗く、 経路が真の曲面から浮いて距離が過大になる。 (2) 近傍が広すぎると局所でも曲がりを無視できず、 多様体を貫く弦(chord)で距離が過小になる——これが 🎮 デモで見た short-circuit の数理的な説明だ。 $k$ の調整とは、 この「疎による過大」と「広すぎによる過小」の綱引きの最適点を探す作業に他ならない。 有限標本の実データ($n=47$ の SSDSE-B-2026 など)では収束の前提が満たされないため、 trustworthiness のような別指標での検証(上の実装 3)が欠かせない。

⚠️ 落とし穴の深層 — ノイズ・穴・密度・計算コスト

上の「⚠️ よくある落とし穴」を、 発生機序まで踏み込んで整理する。

落とし穴何が起きるか機序(なぜ)対処
ノイズ感度多様体から浮いた点が最短経路を歪める測地距離は最小を取るため、 外れ値が作った「近道の橋」を経路が選んでしまう(min 演算はノイズに対し非対称に効く)事前の外れ値除去、 C-Isomap、 頑健な近傍選択
穴あき・非凸多様体距離が引き伸ばされ埋め込みが歪む収束保証は多様体が凸領域を等長に曲げたものである前提。 穴があると経路が迂回し内在距離より長くなる多様体の「形」を先に確認、 局所を保つ LLE 系を併用
密度の不均一同じ $k$ でも領域ごとに分断と近道が同時発生密な領域では近傍が近すぎ、 疎な領域では届かない。 固定 $k$ は密度を仮定している密度で辺重みを再スケールする C-Isomap、 半径固定の $\varepsilon$-近傍
計算コスト$n$ が大きいと急激に遅い・メモリを食う全点対最短経路が $O(n^2\log n)$〜$O(n^3)$、 距離行列 $D$ が $O(n^2)$ メモリ。 固有分解も $O(n^3)$Landmark Isomap、 近似最近傍、 $n{>}10^4$ なら UMAP

とくにノイズと穴は「距離を min で測る」という Isomap の設計に由来する構造的弱点で、 パラメータ調整だけでは消えない。 データが本当に滑らかな低次元多様体に乗っているかどうかの吟味が、 $k$ の微調整より先に来る。

🌐 発展 — 測地距離の近似手法とスケール対策

標準 Isomap の $O(n^3)$ を緩める、 あるいは弱点を補う派生が複数ある。 いずれも「ステップ 2・3 をどう軽く/頑健にするか」の工夫である。

派生変えた点効果
Landmark Isomap (L-Isomap)少数の代表点(landmark)だけで測地距離を計算し Landmark MDS で埋め込む計算量を $O(n^3)$ から概ね $O(mnk)$($m$=landmark 数)へ削減。 大規模化の定石
C-Isomap(Conformal)各辺の重みを局所密度で割って再スケール密度が場所で変わる多様体(等角写像)に対応。 密度不均一の落とし穴を緩和
Kernel Isomap測地距離行列に定数シフトを加え半正定値(PSD)を保証固有値が負になる破綻を防ぎ、 新規点の out-of-sample 埋め込みを与える

なお sklearn.manifold.Isomappath_method='auto' で規模に応じ Floyd-Warshall(小)/Dijkstra(大)を切り替え、 近傍探索も neighbors_algorithmball_treekd_tree を選べる。 SSDSE-B-2026 の 47 行なら標準実装で一瞬だが、 市区町村(約 1,700)へ広げると landmark 化や近似が現実的になる。

🔬 発展 — LLE / t-SNE / UMAP との「数理的な分かれ道」

関連手法の表(下の「🌐 関連手法・派生」)を、 「何を保存し、 何を最小化するか」という数理の芯で対比する。 Isomap が大域の測地距離を保つのに対し、 他手法は「保存する量」自体を差し替えている。

手法保存する量最小化する目的関数Isomap との決定的な差
Isomap大域の測地距離 $d_G$応力 $\sum_{i—(基準)
LLE局所の線形再構成重み $W$$\sum_i\lVert y_i-\sum_j W_{ij}y_j\rVert^2$(疎な固有問題)距離を一切使わず局所線形性のみ。 最短経路計算が不要でスケールしやすい
t-SNE近傍である確率(高次元 Gauss/低次元 Student-t)KL ダイバージェンス(勾配降下)大域距離を保証しない。 重い裾で「詰め込み問題」を回避し局所を強調
UMAPファジィな位相(近傍グラフの構造)交差エントロピー(確率的最適化)局所+中間の大域を両立、 高速で transform も速い

要点は 2 つ。 第一に、 LLE は Isomap の「測地距離+MDS」を「局所重み+疎固有分解」に置き換えたもので、 大域距離を捨てる代わりに計算を軽くしている。 第二に、 t-SNE / UMAP は距離そのものではなく「近傍らしさ(確率・位相)」を保つため、 「東京-沖縄が直線の何倍遠いか」といった大域の量は原理的に再現しない。 逆に Isomap はショートカット 1 本で大域が崩れる敏感さを持つ。 次元削減の目的が「距離を下流に渡す」なら Isomap、 「クラスタを目で見る」なら t-SNE/UMAP、 という使い分けはこの数理の差から必然的に導かれる。

🌀 発展 — 次元の呪いと多様体仮説

Isomap のステップ 1(k 近傍グラフ構築)は、 高次元での次元の呪い(curse of dimensionality)と正面から向き合う。 次元 $D$ が上がると、 ランダムな点どうしのユークリッド距離は互いに似通っていく(距離集中)——最近傍と最遠点の距離の比が 1 に近づき、 「近い/遠い」の区別が曖昧になる。 距離に基づく最近傍探索が土台の Isomap にとって、 これは足元を崩す現象である。

それでも Isomap(や多様体学習全般)が機能しうるのは、 多様体仮説が次元の呪いへの「逃げ道」を与えるから。 データが内在次元 $d\ll D$ の多様体に乗っているなら、 距離集中が効くのは無関係な $D-d$ 方向のノイズであって、 多様体に沿った局所の近傍構造は保たれる。 だからこそ Isomap は「局所だけユークリッド距離を信じる」設計にしている。 裏を返すと、 多様体から浮いた高次元ノイズが大きいほど、 近傍グラフが誤り、 次元の呪いが表面化する——これが「ノイズ感度」の落とし穴の根っこでもある。 SSDSE-B-2026 は 47 サンプル×約 110 列という「サンプル数 < 次元」の極端な高次元小標本で、 事前の標準化と、 相関の高い人口系指標が作る低い内在次元(上の実値計算 STEP 3 参照)が、 Isomap を成立させている前提条件になっている。

📝 補足 — 「呪い」と「祝福」は表裏
高次元は距離集中で最近傍を曖昧にする(呪い)一方、 内在次元が低ければ多様体上の構造は逆に安定して見える(祝福=blessing of dimensionality)。 Isomap を含む次元削減は、 この「呪いを避けつつ祝福を取り出す」営みである。 現代の表現学習(埋め込み・自己教師あり学習)も同じ多様体仮説の上に立っており、 Isomap はその古典的かつ最も透明な出発点にあたる。 なお「次元の呪い」の独立ページは本用語集には未整備のため、 ここでは本文中で扱う。

🗺 概念マップ(Isomap の位置づけ)

Isomap は「線形の PCA / MDS」から「非線形の多様体学習」への橋渡しに位置する。 中心に Isomap を置くと、 周辺に測地距離・k 近傍グラフ・MDS・t-SNE / UMAP・発表者 Tenenbaum(2000) が並ぶ。

isomap 多様体学習 測地距離 (geodesic) k 近傍グラフ MDS / PCA UMAP / t-SNE Tenenbaum 2000

🔗 隣接手法への橋渡し

Isomap (Isometric Mapping) は非線形次元削減手法。 高次元データの「多様体構造 (manifold)」を測地距離で保ったまま低次元に埋め込む。 PCA や t-SNE と並ぶ次元削減の主要手法。

Isomap の強みは「測地距離 (manifold 上の最短経路)」を保つこと。 例: スイスロール状のデータで PCA は内側と外側を混同するが、 Isomap は巻きをほどいて 2 次元に展開できる。 弱点は k 近傍グラフが疎すぎる/密すぎると埋め込みが破綻する点。

🌳 手法選択フロー

次元削減手法を、 データ性質と目的で 3 段階で判定する。

  1. 線形構造で十分か? Yes → PCA (高速・解釈容易)、 No (曲がった多様体) → 非線形手法 (Isomap / UMAP / t-SNE) へ
  2. 目的は? 可視化のみ → t-SNE / UMAP (クラスタが目立つ)、 距離保持で下流分析 → Isomap (測地距離保持)、 速度重視 → UMAP (Isomap より 10 倍速い)
  3. データ規模は? n < 1000 → Isomap で OK、 n = 1000-10000 → 近似 Isomap or UMAP、 n > 10000 → UMAP / PCA + UMAP の 2 段階

scikit-learn の sklearn.manifold.Isomap(n_neighbors=10, n_components=2) から始めるのが定石。 n_neighbors はデータの「滑らかさ」に依存し、 5-20 で試行錯誤する。