論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
DBSCAN(密度ベースクラスタリング)
Density-Based Spatial Clustering of Applications with Noise
「点が密集しているところを 1 つのかたまり」とみなし、まばらな点は雑音 (noise) として扱うクラスタリング手法。
k-means と違い クラスタ数を指定不要外れ値を自動で識別 できる。
教師なし学習 クラスタリング 密度ベース 外れ値検出

🔖 キーワード索引

💡 30 秒で分かる結論

🍰 まずはやさしく

データの密度でグループを作る方法です。

自然なまとまりを見つけるために使います。

スマホのGPSで人の集まりを探すようなものです。

この手法の特徴と設定について読みましょう。

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

🍰 まずはやさしく

データの密度に注目する手法です。

不規則な形のグループを見つけるために使います。

部活のメンバーがバラバラに集まる様子に似ています。

他の手法と何が違うのかを詳しく解説します。

論文の手法欄で、こんな記述を見たことがあるはずです:

本研究では DBSCAN (eps=0.5, min_samples=4) を用い、 47 都道府県を密度ベースでクラスタリングした。
その結果、 3 つの主要クラスタ4 県の外れ値(東京・大阪・神奈川・愛知) が検出された。

この DBSCAN は、 k-means や階層的クラスタリングとは 発想がまったく違うクラスタリング手法 です。 「データ点の密度」だけで自然なまとまりを見つけ、 例外的に孤立した点を「noise」として除外 します。 GPS 軌跡・画像解析・地理空間データ・ソーシャルネットワーク分析など、 不規則な形状や外れ値を含むデータで特に強力です。

🎨 直感で掴む — 「人だかり」を見つける魔法

🍰 まずはやさしく

人だかりを見つける魔法のような仕組みです。

密集している場所をグループにするために使います。

駅前広場に人が集まっている様子を想像してください。

点を3つの種類に分ける考え方を学びましょう。

夜の繁華街を上空から見るところを想像してください。 ある場所には人が密集しています(駅前広場、 ライブ会場、 屋台)。 別の場所はぽつぽつとしか歩いていません(住宅街、 公園の隅)。 DBSCAN は「人がたくさんいる場所」を 1 つのかたまりと認識し、 「ぽつんと孤立した人」は「群衆ではない」と分離する アルゴリズムです。

3 種類の「点」 ― これだけ覚えればよい

DBSCAN は、 すべてのデータ点を次の 3 種類に分類します:

種類定義例えるなら
コア点
(Core point)
半径 ε 以内に minPts 個以上 の点が存在する点 「人だかりの真ん中で、 周りが密集している人」
境界点
(Border point)
コア点ではないが、 あるコア点の ε 以内 にいる点 「人だかりの周縁にいて、 中の人と肩が触れている人」
雑音点
(Noise point)
コア点でも境界点でもない点(誰のクラスタにも属さない) 「ぽつんと一人で離れて立っている人」 → 外れ値扱い

クラスタ形成のイメージ

コア点同士で「半径 ε 以内」に到達できる関係を全部つないでいくと、 1 つのクラスタが浮かび上がります。 その周りに境界点をくっつければ完成。 残った点はすべて noise です。

k-means との根本的違い
  • k-means は 「重心からの距離」で割り当てる → クラスタは 球形に近い形しか作れない
  • DBSCAN は 「密度のつながり」で割り当てる → 三日月型・らせん型でも OK
  • k-means は クラスタ数 K を事前指定、 DBSCAN は 自動決定
  • k-means は 全点をどこかに割り当てる、 DBSCAN は 外れ値を雑音として除外できる

🎮 触って理解する — ε と minPts を動かして DBSCAN を体感

下の散布図は 非凸(三日月)形状の2つのかたまり+孤立点 を初期配置しています。 ε(近傍半径)minPts(コア点に必要な近傍点数・自分含む)の2本のスライダーを動かすと、 各点が コア点境界点ノイズ点 に再分類され、 クラスタの着色がリアルタイムに変わります。 図の上でマウスを動かすと、 その近くの点を中心とした 半径 ε の円 が表示されます。 クリックまたはドラッグで点を追加できます(スマホはタッチ/なぞりで追加)。

クラスタ数: コア点: 境界点: ノイズ点: 総点数:
コア点(濃い縁) 境界点(破線・半透明) ノイズ点(灰・外れ値)
ヒント: 図をクリック/ドラッグで点追加。マウスを動かすと最寄り点の ε 円が出ます。

試してみてほしい操作:(1) ε を小さくすると近傍が痩せてコア点が減り、 ノイズが増える(クラスタが細切れに)。 (2) ε を大きくすると2つの三日月がつながって「1クラスタ」に融合する。 (3) minPts を上げるとコア判定が厳しくなり、 まばらな縁が境界点→ノイズへ転落する。 (4) 2つの塊の間にドラッグで「橋」を架けると、 密度連結によって別々だったクラスタが1つに合体する(=密度でつながる、というDBSCANの核心)。

🎯 直感:ここが k-means と決定的に違う
  • 三日月配置のまま適切な ε・minPts を選ぶと、 DBSCAN は 2つの曲がった帯を別クラスタとして分離できる。 k-means(重心距離)では三日月を正しく割れない。
  • 孤立点は どんな ε・minPts でも無理にクラスタへ押し込まれない。 これが「外れ値を自動でノイズに分ける」性質。
  • クラスタ数を指定していないのに、 密度のつながりだけで数が自動的に決まるのが読み取れる。
⚠️ よくある落とし穴(この図で再現できる)
  • 密度差問題:密な塊と疎な塊を同時に置くと、 疎な塊を拾える大きな ε では密な塊同士がくっつき、 密な塊を分ける小さな ε では疎な塊が丸ごとノイズになる。 単一の ε では密度の異なるクラスタを同時にうまく扱えない(→ HDBSCAN が有効。 本サイトに単独ページは未整備のため用語のみ)。
  • ε 選択の難しさ:最適な ε は目視では決めにくい。 実務では k-distance graph(各点の第 minPts 近傍距離をソートした「肘」)で当たりをつける。
  • 高次元での ε 選択難:次元が増えると点間距離が一様に近づき(次元の呪い)、 「近い/遠い」の差が消えて ε の意味が薄れる。 事前に 標準化PCA次元削減 を行うのが定石。
  • スケール依存:変数ごとに単位が違うと ε が一方の軸に支配される。 距離を使う手法なので標準化はほぼ必須。
🚀 発展
  • HDBSCAN:ε を1つに固定せず、 密度の階層を辿って可変密度に対応。 ノイズ判定も確率的に扱える。
  • OPTICS:到達可能距離を並べた reachability plot を作り、 後から任意の密度しきい値でクラスタを切り出せる。
  • 近似最近傍(ball-tree / KD-tree / HNSW)で近傍探索を高速化すれば大規模データにも適用可能。

関連ページ: k-means(重心ベースとの対比)クラスタリング全体像外れ値ノイズ標準化PCA次元削減

📐 数式と厳密な定義

🍰 まずはやさしく

密度を数式で決めるルールです。

グループの境界線を厳密に決めるために使います。

買い物客がどれくらい近くにいるかを測るようなものです。

半径や点数の条件について詳しく説明します。

データ集合 $D = \{x_1, x_2, \dots, x_n\} \subset \mathbb{R}^d$ と 2 つのパラメータ ($\varepsilon, \text{minPts}$) を考えます。

【ε 近傍 (epsilon-neighborhood)】
$$N_\varepsilon(x) = \{y \in D \mid \mathrm{dist}(x, y) \le \varepsilon\}$$
点 $x$ から半径 $\varepsilon$ 以内に存在するすべての点の集合。$\mathrm{dist}$ は通常ユークリッド距離。
【コア点 (core point) の条件】
$$x \text{ がコア点} \iff |N_\varepsilon(x)| \ge \text{minPts}$$
自分自身を含めて minPts 以上の点が ε 近傍にあれば、 その点はコア点。
【密度到達可能 (density-reachable)】
$$y \text{ は } x \text{ から密度到達可能} \iff \exists\, x = p_1, p_2, \dots, p_k = y \text{ s.t. } p_{i+1} \in N_\varepsilon(p_i)\, \land\, p_i \text{ はコア点}$$
コア点を「踏み石」のように経由して y にたどり着けるかどうか。
【密度連結 (density-connected) によるクラスタ】
$$C = \{x \mid \exists z \in D \text{ s.t. } x \text{ と } z \text{ がともに } z \text{ から密度到達可能}\}$$
この同値類で 1 つのクラスタを形成する。 どのクラスタにも属さない点が noise。

🔬 数式を「言葉」で読み解く

$\varepsilon$ (eps)
近い」と判定する距離のしきい値。 小さくすると 1 クラスタが細切れになりやすく、 noise が増える。 大きくすると逆に「全部 1 つ」になりがち。
minPts (min_samples)
コア点と認めるのに必要な近傍点数(自分を含む)。 経験則として 2 次元データでは minPts = 4 程度、 一般的には minPts ≥ d + 1($d$ は特徴量の次元数)を推奨。
$N_\varepsilon(x)$
点 $x$ から距離 $\varepsilon$ 以内にある点の集合(自分自身も含む)。 「近所付き合いの範囲」と思えばよい。
$\mathrm{dist}(x, y)$
距離関数。 デフォルトは ユークリッド距離。 sklearn では metric 引数でマンハッタン距離・コサイン距離なども選択可。
密度到達可能
コア点を経由した「連鎖的な近さ」。 これにより、 細長い形状や曲線状のクラスタも 1 つにまとめられる。
noise (ラベル −1)
どのクラスタにも属せない点。 sklearn の labels_ 配列で -1 として返される。
📝 確認演習(数式直後)
Q. 点 $p$ の座標が $(2, 3)$、 $\varepsilon = 1.5$、$\text{minPts} = 3$ のとき、 $p$ が「コア点」になる条件は?

$N_{1.5}(p) = \{q \in D \mid \mathrm{dist}(p, q) \le 1.5\}$ の要素数が $\ge 3$ であること(自分 $p$ を含む)。つまり $p$ から半径 1.5 以内に自分含め 3 点以上が存在すれば、$p$ はコア点となりクラスタの起点になれる。

Q. $\varepsilon$ を大きくすると noise 点の数はどうなる?

$\varepsilon$ が大きくなると各点の $N_\varepsilon(p)$ が広がり、より多くの点が $\text{minPts}$ 条件を満たしコア点になる。その結果 noise に分類される点は減少する。極端に大きいと全点が 1 クラスタになる。

🧮 SSDSE-B 47 都道府県データで計算してみる

SSDSE-B(2026 年版・2023 年)の 「総人口 A1101」 ($x$)「着工新設住宅戸数 H1800」 ($y$) の 2 変数で、 47 都道府県を DBSCAN でクラスタリングします。 住宅着工戸数は都市の規模・経済活動を反映する量で、 人口とは完全には比例しないため 2 次元の散らばりが生まれます。 まずは 7 県だけのサンプルで手計算してみましょう(値は 47 県全体で標準化した z 得点)。

📝 より正確な分析(教材補足)
SSDSE-B-2026 には「県内総生産(県内 GDP)」の列は存在しません。 本ページの数値例は、 実在する 2 列 A1101 総人口H1800 着工新設住宅戸数(2023 年)を StandardScaler で標準化し、 実際に DBSCAN を回して得た値です。 住宅着工戸数は人口とは別の「都市の建設・経済活動」の量なので、 単純な人口の比例関係にならず 2 次元散布として意味を持ちます。 表・出力・ラベル配列はすべて実 CSV から再計算した実測値です。
都道府県総人口 $z_x$(標準化)住宅着工戸数 $z_y$(標準化)位置イメージ
東京+4.13+4.73右上の極端な外れ値
神奈川+2.38+2.09右上中央
大阪+2.21+2.14右上中央
愛知+1.75+1.75右上中央
福岡+0.89+0.84中央付近
広島+0.03−0.04中央付近
島根−0.72−0.61左下小規模県
STEP 1 パラメータ設定
$\varepsilon = 0.8$, $\text{minPts} = 3$ とする。 標準化済み座標(z 得点)を使う。
STEP 2 各点の ε 近傍を列挙
・東京:最も近い神奈川でも距離 ≈ √((4.13−2.38)²+(4.73−2.09)²) ≈ 3.17 > 0.8 → 近傍 0 個
・神奈川:大阪 (dist=√((2.38−2.21)²+(2.09−2.14)²)≈0.18)、 愛知 (dist≈0.72) → ともに 0.8 以内
・大阪:神奈川 (0.18)、 愛知 (dist≈0.61) → 近傍 3 個(自分含む) → コア
・愛知:大阪 (0.61)、 神奈川 (0.72) → 近傍 3 個(自分含む) → コア
・福岡:最寄りの広島 (dist≈1.23)・愛知 (dist≈1.25) がいずれも 0.8 超 → 近傍 0 個
・広島:島根 (dist≈0.94)、 福岡 (1.23) → いずれも 0.8 超 → 近傍 0 個
・島根:広島 (0.94) のみ、 0.8 超 → 単独
STEP 3 コア点・境界点・noise を判定
コア点:神奈川、 大阪、 愛知(3 県とも ε 近傍に自分含め 3 点以上 → minPts=3 を満たす)
境界点:なし(この 7 県サンプルでは該当なし)
noise (−1)東京、 福岡、 広島、 島根(コアの ε 近傍に入れない)
STEP 4 結果
クラスタ 0:{神奈川、 大阪、 愛知} / noise:{東京、 福岡、 広島、 島根}
解釈:たった 7 県ではほとんど noise になる。 47 県全部で回すと(後述の実装参照)、 「地方圏」が 1 大クラスタにまとまり、 東京・大阪・神奈川・愛知など大都市圏が noise として浮かび上がる構造になります。

ポイント:DBSCAN の結果は ε と minPts の設定に強く依存します。 上の 7 県例では ε=0.8 で {神奈川・大阪・愛知} がまとまりましたが、 ε=0.5 まで狭めると近傍が 0.5 以内に収まるのは神奈川–大阪の 1 ペアだけになり、 minPts=3 を満たせず 7 県すべてが noise になります。 「最適な ε」を探すには次節の k-distance graph を使います。

最小例で手計算を完全再現する(6 点 × 2 次元)

都道府県データの前に、 より小さな 6 点で DBSCAN の動作を完全に追います。 クラスタリング対象 6 点(2 次元):

[0, 0], [1, 1], [1, 0], [2, 1], [8, 8], [9, 9]

パラメータ: $\varepsilon = 1.5$、 $\text{minPts} = 2$

STEP 1 各点の ε 近傍を列挙(ユークリッド距離)
点 A = [0, 0]:
 dist(A, [1, 1]) = √((1−0)²+(1−0)²) = √2 ≈ 1.414 < 1.5 → 近傍
 dist(A, [1, 0]) = √((1−0)²+(0−0)²) = √1 = 1.000 < 1.5 → 近傍
 dist(A, [2, 1]) = √((2−0)²+(1−0)²) = √5 ≈ 2.236 > 1.5 → 範囲外
 → A の ε 近傍: {[1,1], [1,0]}(自分含め 3 点)

点 B = [1, 1]:
 dist(B, [0, 0]) ≈ 1.414 < 1.5、 dist(B, [1, 0]) = 1.0 < 1.5、 dist(B, [2, 1]) = 1.0 < 1.5
 → B の ε 近傍: {[0,0], [1,0], [2,1]}(自分含め 4 点)

点 C = [1, 0]:
 dist(C, [0, 0]) = 1.0 < 1.5、 dist(C, [1, 1]) = 1.0 < 1.5、 dist(C, [2, 1]) ≈ 1.414 < 1.5
 → C の ε 近傍: {[0,0], [1,1], [2,1]}(自分含め 4 点)

点 D = [2, 1]:
 dist(D, [1, 1]) = 1.0 < 1.5、 dist(D, [1, 0]) ≈ 1.414 < 1.5
 → D の ε 近傍: {[1,1], [1,0]}(自分含め 3 点)

点 E = [8, 8]:
 dist(E, [9, 9]) = √2 ≈ 1.414 < 1.5 → 近傍
 → E の ε 近傍: {[9,9]}(自分含め 2 点)

点 F = [9, 9]:
 dist(F, [8, 8]) ≈ 1.414 < 1.5 → 近傍
 → F の ε 近傍: {[8,8]}(自分含め 2 点)
STEP 2 コア点・境界点・noise を判定(minPts = 2)
 [0, 0]:近傍 3 点 ≥ 2 → コア点
 [1, 1]:近傍 4 点 ≥ 2 → コア点
 [1, 0]:近傍 4 点 ≥ 2 → コア点
 [2, 1]:近傍 3 点 ≥ 2 → コア点
 [8, 8]:近傍 2 点 ≥ 2 → コア点
 [9, 9]:近傍 2 点 ≥ 2 → コア点
STEP 3 クラスタ形成(密度連結)
[0,0] → [1,1] → [1,0] → [2,1] がすべて密度連結 → クラスタ 0
[8,8] → [9,9] が密度連結 → クラスタ 1
noise: なし

手計算ラベル:[0, 0], [1, 1], [1, 0], [2, 1] → ラベル 0[8, 8], [9, 9] → ラベル 1
整列後ラベル列: [0, 0, 0, 0, 1, 1]

Python で同じ 6 点を DBSCAN にかけて確認する:

このコードでやること:上の手計算と同じ 6 点 [0,0],[1,1],[1,0],[2,1],[8,8],[9,9]sklearn.cluster.DBSCAN にかけ、 手計算ラベルと一致するかを検証する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
from sklearn.cluster import DBSCAN

# 6 点の座標(手計算と同じ)
X = np.array([
    [0, 0],  # 点 A
    [1, 1],  # 点 B
    [1, 0],  # 点 C
    [2, 1],  # 点 D
    [8, 8],  # 点 E
    [9, 9],  # 点 F
])
db = DBSCAN(eps=1.5, min_samples=2).fit(X)
labels = db.labels_
print("Python ラベル:", labels)
hand = np.array([0, 0, 0, 0, 1, 1])
print("手計算ラベル:", hand)
print("一致確認:", np.all(labels == hand))
Python ラベル: [0 0 0 0 1 1] 手計算ラベル: [0 0 0 0 1 1] 一致確認: True

💬 手計算ラベル [0, 0, 0, 0, 1, 1] と Python 出力が一致np.all(labels == hand) = True により、 Step 1〜3 の手計算が正しく、 sklearn の DBSCAN も同じ結果を返すことが確認できた。 6 点のうち noise 点はゼロで、 2 つの密なクラスタがきれいに分離された。

🐍 Python 実装 — SSDSE-B で 47 都道府県をクラスタリング

scikit-learn の DBSCAN クラスを使えば数行で実行できます。 標準化 を忘れないこと。

📥 入力:SSDSE-B-2026.csv から 47 都道府県の数値列(人口 A1101・面積 B1101・医師数 I521101 など)を選び、 StandardScaler で平均 0・分散 1 に標準化した 2D 配列 X(shape=(47, k))。 距離計算が単位(人・km² 等)に依存しないようにします。

📤 出力db.labels_ として 47 要素の整数配列。 値が -1 のサンプルは「ノイズ点」(クラスタに属さない孤立県)、 0・1・2... は順にクラスタ番号。 東京・大阪などの大都市は密度が低い領域に孤立するため -1 になりやすく、 地方の中規模県が同じクラスタに集まりやすい。

💬 narration:eps(近傍半径)と min_samples(コア点を成立させる隣接数)の決め方が最大の難所。 標準化後の SSDSE-B では eps=0.7〜1.5、 min_samples=3〜5 がしばしば適切。 NearestNeighbors で k 番目最近傍距離をプロット(k-distance graph)、 「肘」を取って eps を決めるのが王道。 シードを指定する必要がない(K-means と異なり乱数初期化に依存しない)ため再現性が高いのも特徴です。

1. 基本的な使い方

このコードでやること:SSDSE-B-2026 から総人口 (A1101) と着工新設住宅戸数 (H1800) の 2 列を読み込み、StandardScaler で標準化後に DBSCAN(eps=0.5, min_samples=4) を実行。クラスタ数・noise 件数と noise 県の一覧を表示する。

📥 入力データ(SSDSE-B-2026、 2023 年・先頭 5 県):

Code Prefecture A1101 H1800 0 R01000 北海道 5092000 28469 1 R02000 青森県 1184000 4680 2 R03000 岩手県 1163000 6427 3 R04000 宮城県 2264000 15661 4 R05000 秋田県 914000 3456
 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
import pandas as pd
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler

# SSDSE-B 2026 を読み込む(cp932・2 行目の日本語名は skiprows で除外)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])

# 2023 年だけに絞り、必要 2 変数を抜き出す(先頭列名は 'SSDSE-B-2026' = 年度)
df_23 = df[df['SSDSE-B-2026'] == 2023].copy()
X = df_23[['A1101', 'H1800']].values  # 総人口, 着工新設住宅戸数(戸)

# 標準化(必須!)
X_std = StandardScaler().fit_transform(X)

# DBSCAN 実行
db = DBSCAN(eps=0.5, min_samples=4).fit(X_std)
labels = db.labels_

# クラスタ数(noise=−1 は除く)と noise 数
n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
n_noise = list(labels).count(-1)
print(f'クラスタ数: {n_clusters}, noise: {n_noise}件')

# どの県が noise か
df_23['cluster'] = labels
print(df_23[df_23['cluster'] == -1][['Prefecture', 'A1101', 'H1800']])

📤 実行すると次の出力が得られる:

クラスタ数: 1, noise: 9件 Prefecture A1101 H1800 0 北海道 5092000 28469 10 埼玉県 7331000 53765 11 千葉県 6257000 43368 12 東京都 14086000 124810 13 神奈川県 9229000 64766 22 愛知県 7477000 56825 26 大阪府 8763000 65927 27 兵庫県 5370000 28662 39 福岡県 5103000 36074

💬 eps=0.5 では人口・住宅着工がともに突出する大都市圏 9 県(東京・神奈川・大阪・愛知・埼玉・千葉・兵庫・福岡・北海道)が noise(-1) となり、残る 38 県が cluster 0 にまとまる。eps を 0.8 に緩めると noise は東京 1 県だけに減り、他の大都市圏はクラスタに合流する。

2. 最適な ε を k-distance graph で決める

「ε をいくつにすればよいか」迷ったときは、 k-distance graph(k 番目最近傍点までの距離の昇順プロット)の 肘 (elbow) を ε に取るのが定石です。

このコードでやること:標準化済み X_std に NearestNeighbors(k=4) を当て、各点の 4 番目最近傍距離を昇順プロットする。急に立ち上がる「肘」の高さが eps の目安。

📥 入力データ(コード 1 で作成した X_std、標準化済み 47×2 行列の冒頭):

X_std (StandardScaler 適用後、 47 都道府県 × 2 変数): [[ 0.88 0.50], # 北海道 [-0.53 -0.54], # 青森県 [-0.54 -0.46], # 岩手県 [-0.14 -0.06], # 宮城県 [-0.63 -0.60]] # 秋田県(先頭 5 県) shape = (47, 2)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from sklearn.neighbors import NearestNeighbors
import matplotlib.pyplot as plt

k = 4  # minPts と同じ値が定番
nn = NearestNeighbors(n_neighbors=k).fit(X_std)
dist, _ = nn.kneighbors(X_std)
k_dist = np.sort(dist[:, k-1])  # k番目最近傍までの距離を昇順ソート

plt.figure(figsize=(8, 4))
plt.plot(k_dist)
plt.xlabel('Points sorted by distance')
plt.ylabel(f'{k}-NN distance')
plt.title('k-distance graph (elbow = eps)')
plt.grid(True, alpha=0.3)
plt.show()

# 急に立ち上がる点(肘)の y 座標を eps に採用する

📤 実行すると次の出力が得られる(グラフ表示):

k_dist の代表値(47 県、標準化後): 最小 0.025, 中央 0.063, 80 パーセンタイル 0.376, 最大 3.820 → グラフは 0.4〜0.5 付近で急に立ち上がる。この肘の値を eps に採用する。

💬 肘の位置が eps の目安。中央値付近(約 0.06)はクラスタ内部の密な間隔、急上昇する 0.4〜0.5 が「密な塊」と「孤立した大都市」の境目。0.5 以下では noise が急増し、0.8 以上では全体がほぼ 1 クラスタになる。47 県では eps=0.5〜0.8 が実用域。

3. 結果を散布図で可視化

このコードでやること:DBSCAN の labels_ を使い、クラスタ番号ごとに散布図を色分けして表示。noise(−1) は黒で描画し、どの県が外れ値かを視覚化する。

📥 入力データ(コード 1 の出力 labels を使用):

labels (47 要素の整数配列, eps=0.5 min_samples=4): [-1 0 0 0 0 0 0 0 0 0 -1 -1 -1 -1 0 0 0 0 0 0 0 0 -1 0 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0] ・cluster 0 (38 県) · noise -1 (9 県: 東京・神奈川・大阪・愛知・埼玉・千葉・兵庫・福岡・北海道) X_std.shape = (47, 2) ← 散布図の x, y に使用
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(9, 6))
colors = ['#1976D2', '#E64A19', '#388E3C', '#7B1FA2', '#FBC02D']
for lbl in set(labels):
    mask = labels == lbl
    color = '#333' if lbl == -1 else colors[lbl % len(colors)]
    name = 'noise' if lbl == -1 else f'cluster {lbl}'
    ax.scatter(X_std[mask, 0], X_std[mask, 1],
               c=color, s=90, alpha=0.85, label=name,
               edgecolor='white', linewidth=1.2)
ax.set_xlabel('総人口(標準化)')
ax.set_ylabel('着工新設住宅戸数(標準化)')
ax.legend(loc='lower right')
ax.set_title('DBSCAN: 47 都道府県の密度ベースクラスタリング')
plt.tight_layout()
plt.show()

📤 実行すると次の出力が得られる(散布図表示):

散布図が表示される。 ・cluster 0(青):青森・岩手・宮城・広島・熊本など 38 県 ・noise (黒×):東京・神奈川・大阪・愛知・埼玉・千葉・兵庫・福岡・北海道(人口・住宅着工が突出して高い 9 県)

💬 東京は標準化後でも (x=+4.13, y=+4.73) と極端に離れており、noise として明確に分離される。散布図で「孤立した点 = 異質な県」が一目でわかる。

4. パラメータの感度分析

同じデータでも (ε, minPts) を変えると結果は大きく変わります。 感度を確認しましょう。

このコードでやること:eps=[0.3, 0.5, 0.8, 1.0] × minPts=[3, 4, 5] のグリッドで DBSCAN を全試行し、各設定のnoise 数をピボット表で比較する。

📥 入力データ(コード 1 の X_std を継続使用):

X_std ← 47×2 の標準化済み numpy 配列(コード 1 から継続) 試行グリッド: eps : [0.3, 0.5, 0.8, 1.0] min_samples: [3, 4, 5] 合計 12 通りの DBSCAN を実行する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from itertools import product

results = []
for eps, mp in product([0.3, 0.5, 0.8, 1.0], [3, 4, 5]):
    db = DBSCAN(eps=eps, min_samples=mp).fit(X_std)
    lab = db.labels_
    n_cl = len(set(lab)) - (1 if -1 in lab else 0)
    n_no = int((lab == -1).sum())
    results.append({'eps': eps, 'minPts': mp,
                    'クラスタ数': n_cl, 'noise数': n_no})

print(pd.DataFrame(results).pivot(index='eps', columns='minPts', values='noise数'))

📤 実行すると次の出力が得られる:

minPts 3 4 5 eps 0.3 10 10 10 0.5 6 9 9 0.8 1 1 1 1.0 1 1 1

💬 eps=0.3 では地方の中規模県まで noise に落ちて 10 件、eps=0.8 以上では東京だけが noise として残り 1 件に収束する。eps=0.5 は minPts の増加に敏感(3→6 件、4→9 件)で、外れ値をどこまで拾うかを minPts で調整できる。eps=0.5〜0.8 が「大都市圏を外れ値として検出しつつ地方圏を 1 クラスタに保つ」バランスの良い範囲。

5. シルエット係数でクラスタリングの質を評価

このコードでやること:noise(−1) を除いたクラスタ点だけを対象に silhouette_score を計算し、クラスタの内部結束と分離度を数値化する。

📥 入力データ(コード 1 の X_std と labels を継続使用):

X_std (47×2 標準化済み配列) labels (47 要素の整数配列、 -1=noise, 0,1,...=クラスタ番号) eps=0.5, min_samples=4 では labels=-1 が 9 件 → 有効クラスタは 1 個だけ (総人口・住宅着工の 2 変数では地方圏が 1 つの密な塊になり、複数クラスタは生じない)
1
2
3
4
5
6
7
8
9
from sklearn.metrics import silhouette_score

# noise を除く点だけで評価する
mask = labels != -1
if len(set(labels[mask])) >= 2:
    s = silhouette_score(X_std[mask], labels[mask])
    print(f'silhouette = {s:.3f}')
else:
    print('クラスタ数が 2 未満: シルエット計算不可')

📤 実行すると次の出力が得られる(eps=0.5, min_samples=4 のとき):

クラスタ数が 2 未満: シルエット計算不可

💬 このデータ(総人口・住宅着工の 2 変数)では eps を変えても地方圏が 1 つの密な塊にまとまるため、有効クラスタは常に 1 個で silhouette は計算できない。複数クラスタを得たい場合は、 人口当たりの指標(合計特殊出生率 A4103・高齢化率など)や気候(年平均気温 B4101)といった「規模とは独立した軸」を特徴量に加える。 そうすれば地方圏が複数の性格別クラスタに分かれ、 silhouette で分離の質を評価できるようになる。 いずれの場合も noise(−1) を除いて計算するのが鉄則。

⚠️ 5 つの「DBSCAN 落とし穴」

① 標準化を忘れて ε の意味が崩壊する
総人口(単位:人、 桁数:100 万〜1400 万)と着工新設住宅戸数(単位:戸、 桁数:数千〜12 万)を そのまま 入れると、 距離は人口の差だけで決まり、 住宅着工戸数は無視されます。 必ず StandardScalerMinMaxScaler で同じスケールに揃える こと。 ε もスケール後の単位で考える。
② 密度が場所によって違うデータが苦手
DBSCAN は 全空間で同じ ε を使うため、 「中心は密、 端は疎」のような密度が不均一な分布では、 端のクラスタが noise に潰れたり、 中心が大きすぎる 1 つに合体したりします。
対処:拡張版の HDBSCAN(階層的 DBSCAN、 局所密度を考慮)や OPTICS を試す。 sklearn にも OPTICS がある。
③ 高次元では距離が劣化する(curse of dimensionality)
特徴量 d ≧ 10〜20 を超えると、 「すべての点がほぼ等距離」 になり、 ε 近傍が壊れます。
対処:先に PCA・UMAP などで次元削減してから DBSCAN を適用。 もしくは類似度メトリック(コサイン距離など)を使う。
④ ε と minPts の選び方が結果を決定する
ε が小さすぎる → ほぼ全部 noise、 大きすぎる → 全部 1 クラスタ。 k-distance graph の肘シルエット係数 を使って客観的に決める。 デフォルト値を盲信しない。 minPts は最小 3、 一般的に min_samples ≈ 2d(d は次元数)。
⑤ 大規模データでは遅い ― O(n²) の壁
naive 実装では計算量が $O(n^2)$。 1 万点以上で実用上厳しい。 sklearn の algorithm='ball_tree'kd_tree を指定すると $O(n \log n)$ に近くなる。 さらに大規模なら GPU 版 cuML、 分散版 ELKI を検討。

🌐 関連手法・派生

手法特徴DBSCAN との関係
OPTICS 各点の到達可能距離をプロットし、 「ε を 1 つに決めずに」階層的に密度クラスタを抽出 密度が不均一なデータに強い。 sklearn にあり
HDBSCAN 階層的 DBSCAN。 局所的に最適な ε を自動で見つける 近年の実務での 第一選択hdbscan パッケージ
Mean Shift 密度の山(モード)に向かって点を移動させる 密度ベースだが、 noise 概念は持たない
Gaussian Mixture Model (GMM) 混合ガウス分布で確率的にクラスタ割り当て パラメトリック。 球形〜楕円形クラスタに向く
k-means 重心ベース、 K を事前指定 球形クラスタに最適。 DBSCAN とよく比較される
階層的クラスタリング 樹形図(dendrogram)で階層を可視化 小規模データで構造を可視化したいとき有用

📚 関連グループ教材

DBSCAN を含むクラスタリング手法を体系的に学ぶには、 以下のグループ教材が役立ちます:

🗺 概念マップ — DBSCAN の位置づけ

DBSCAN が機械学習・クラスタリングの体系の中でどこに位置し、他の手法・概念とどう繋がっているかを関係図で示す。

教師なし学習 Unsupervised Learning クラスタリング Clustering 総称 DBSCAN 密度ベースクラスタリング k-means 重心ベース・K 指定 階層的クラスタリング 樹形図で可視化 標準化 StandardScaler 必須 距離計算 ユークリッド・他 HDBSCAN 階層的・密度不均一対応 OPTICS eps 不要・到達可能距離 外れ値検出 noise ラベルを活用 GPS・異常検知 時空間・IoT データ 上位概念 並列手法 前提 発展・応用

💬 DBSCAN(赤)はクラスタリング体系の一員で、 k-means・階層的クラスタリングと並列する手法。 標準化・距離計算が前提となり、 HDBSCAN・OPTICS へ発展、 外れ値検出・GPS 分析への応用につながる。

位置づけ早見表

階層 概念 関係
上位教師なし学習 → クラスタリングDBSCAN はこのカテゴリの 1 手法
同列k-means, 階層的, GMM, Mean Shift同じ「クラスタリング」だが原理が異なる
下位(発展)OPTICS, HDBSCANDBSCAN の弱点(密度不均一性)を改良
前提距離計算、 標準化、 ハイパーパラメータどれが欠けても結果が崩れる
応用外れ値検出、 異常検知、 GPS 軌跡分析noise ラベルをそのまま活用

🎬 学習の総まとめ

本ページで扱った DBSCAN の知識を 1 つに集約:

📝 まとめ:DBSCAN を使う前に確認すべきこと

DBSCAN は適切に使えば本当に強力な手法です。 SSDSE-B-2026 を題材に、 自分の手で何度も実行することが、 真の習得への近道です。

🚨 異常検知パイプラインとしての DBSCAN 活用

SSDSE のような統計データに限らず、 業務システムの異常検知でも DBSCAN は強力:

  1. ① ベースラインデータ:正常時の特徴量を 1 ヶ月分収集
  2. ② DBSCAN 学習:標準化 → DBSCAN で密集領域を「正常パターン」と定義
  3. ③ 新データ判定:新着点の k 近傍距離を測り、 eps を超えたら異常フラグ
  4. ④ アラート:閾値超えで通知、 ダッシュボード更新
  5. ⑤ フィードバック:誤検知を集めて閾値・特徴量を改善
  6. ⑥ モデル更新:四半期ごとに新しい正常パターンで再学習

📈 拡張ケース:SSDSE 12 年経時データの分析

SSDSE-B-2026 の 12 年分(2012-2023)を時間スライスごとに DBSCAN し、 都道府県の「クラスタ系列」を作る分析:

  1. ① データ準備:12 年 × 47 県 = 564 行を Year ごとに 12 セットに分割
  2. ② 各年で DBSCAN:同じ eps、 min_samples で実行(比較可能性のため)
  3. ③ クラスタの対応付け:年間でクラスタ番号は変わるので、 重心の最近傍で対応
  4. ④ Sankey 図で可視化:都道府県のクラスタ遷移を流れ図で表示
  5. ⑤ 安定県・変動県の特定:12 年同じクラスタ=安定、 複数遷移=変動
  6. ⑥ 解釈:「○○県は 2018 年以降ノイズ化」「△△県は安定的に中規模クラスタ」

🎨 可視化ツール集

🌲 HDBSCAN アルゴリズムの概要

HDBSCAN は DBSCAN を「複数の eps で同時実行」した結果を階層化したもの:

  1. ① 相互到達可能距離の計算:core_distance を考慮した距離行列。
  2. ② 最小スパニングツリー (MST) 構築
  3. ③ MST から階層クラスタツリーを生成
  4. ④ 安定性が最大のクラスタを抽出:各クラスタの「存続期間」をスコアリング。
  5. ⑤ 確率付きで各点を割当

SSDSE-B-2026 47 都道府県では min_cluster_size=3 程度を起点に試すと、 DBSCAN より安定したクラスタが得られることが多いです。

🔬 OPTICS アルゴリズムの擬似コード

OPTICS は eps を 1 つに固定せず、 「到達可能性距離」で全点を順序付けることで、 任意の eps に対応できる点で DBSCAN を超えています:

OPTICS(D, eps, MinPts):
  for each point p in D:
    p.reachability = UNDEFINED
  ordered_list = []
  for each unprocessed point p:
    Neighbors = regionQuery(p, eps)
    p.processed = TRUE
    ordered_list.append(p)
    if core_distance(p, eps, MinPts) != UNDEFINED:
      seeds = empty priority queue
      update(Neighbors, p, seeds)
      while seeds is not empty:
        q = seeds.pop_min()
        Neighbors' = regionQuery(q, eps)
        q.processed = TRUE
        ordered_list.append(q)
        if core_distance(q, eps, MinPts) != UNDEFINED:
          update(Neighbors', q, seeds)
  return ordered_list  // 各点の到達可能性距離付き

結果として得られる「reachability plot」を見ると、 谷の数 = クラスタ数、 谷の深さ = クラスタの密度が一目瞭然です。

🧮 密度推定の数学的背景

DBSCAN の局所密度概念は、 確率密度関数 $p(x)$ のカーネル密度推定 (KDE) と等価です:

$$\hat{p}(x) = \frac{1}{n h^d} \sum_{i=1}^{n} K\left(\frac{x - x_i}{h}\right)$$

ここで $K$ はカーネル関数、 $h$ はバンド幅、 $d$ は次元数。 DBSCAN の eps は KDE の $h$ に相当し、 min_samples は閾値 $\theta$ に対応します。 局所密度が閾値を超える領域=クラスタ、 という単純なルールが、 DBSCAN の数学的根拠です。

HDBSCAN ではこの $\theta$ を連続的に変化させて階層構造を抽出。 統計的に「確率密度の上位レベル集合」の階層を取り出すことに対応します。

🗾 日本のデータ分析事例

🚦 SSDSE-B-2026 で DBSCAN を実行する完全コードフロー(説明)

本ページ「🐍 Python 実装」の数行コードを補足する詳細フロー:

  1. pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) で読み込み
  2. 必要列を選択:df[['Prefecture','A1101','B1101','I521101']]
  3. 標準化:from sklearn.preprocessing import StandardScaler; X = StandardScaler().fit_transform(df.drop('Prefecture', axis=1))
  4. k-distance graph:from sklearn.neighbors import NearestNeighbors; nbrs = NearestNeighbors(n_neighbors=5).fit(X); dist, _ = nbrs.kneighbors(X); import matplotlib.pyplot as plt; plt.plot(sorted(dist[:,-1]))
  5. eps 決定:肘から例えば 1.0
  6. DBSCAN:from sklearn.cluster import DBSCAN; labels = DBSCAN(eps=1.0, min_samples=5).fit_predict(X)
  7. 結果保存:df['cluster'] = labels; df.to_csv('outputs/ssdse_clusters.csv', index=False)
  8. 可視化:plt.scatter(X[:,0], X[:,1], c=labels) で散布図、 都道府県名を annotate

💬 拡張 FAQ

Q. eps と min_samples のどちらが結果に効きますか?
eps の方が結果を大きく左右します。 min_samples は「コア点判定の厳しさ」程度。 まず eps を決めてから min_samples を微調整。
Q. クラスタ番号の意味は?
0, 1, 2, ... と続きますが、 数値の順序に意味はありません。 「クラスタ 0」と「クラスタ 1」のどちらが大事かは結果から判断。
Q. SSDSE 全部の指標を使うべきですか?
絶対だめ。 130 列全部は次元の呪いで意味なし。 仮説に応じて 3-7 列を選ぶ。
Q. 標準化以外の前処理は?
対数変換(人口など右に裾を引く分布)、 ロバストスケーリング、 PCA で次元削減、 などを併用。
Q. K-means と DBSCAN、 結果が違うときどちらを採用?
正解はない。 ドメイン解釈で「より腑に落ちる」方を採用するか、 両方併記して読者の判断に委ねる。

🏃‍♂️ 競技で勝つための DBSCAN 活用

統計・データ解析コンペティションで DBSCAN を使った分析を成功させるコツ:

  1. ① 仮説駆動:「○○指標で△△な県を発見したい」と先に仮説。 結果論にしない。
  2. ② 複数手法併用:DBSCAN 単独ではなく K-means、 HDBSCAN とも比較。 結論の頑健性を主張。
  3. ③ 経年比較:SSDSE の 12 年分を使い、 クラスタの安定性 / 遷移を分析。
  4. ④ ノイズの掘り下げ:「ノイズは失敗ではなく発見」。 個別事情を 1 つずつ説明。
  5. ⑤ 可視化品質:日本地図 + 散布図 + 樹形図(HDBSCAN)で多角的に。 タイトルに結論を書く。
  6. ⑥ 政策示唆:「地域類型ごとに別戦略」など、 実務にどう繋がるかを明示。
  7. ⑦ 再現性:GitHub にコード + データ処理手順を公開、 採点者が追試できるように。

⚠️ 落とし穴拡張版(DBSCAN 中級者の罠)

📚 SSDSE-B 系研究での DBSCAN 利用文献

これらは仮想的な研究テーマ例ですが、 SSDSE-B-2026 を用いた論文・卒業研究で DBSCAN が活用される典型的場面です。

🔭 最新クラスタリング手法との位置づけ

📆 経年クラスタリング:SSDSE 多年版

SSDSE-B-2026 は 2012-2023 の 12 年分を含む。 各年で独立に DBSCAN し、 都道府県のクラスタ遷移を追跡することで、 「地域構造の変化」が見える:

経年クラスタ遷移は地方政策の効果検証にも使えます。 「2020 年の移住支援強化以降、 過疎クラスタから抜けた県があるか」など、 政策評価の根拠データに。

🚀 上級トピック:研究フロンティア

🎓 学習ロードマップ

  1. Week 1:本ページ通読 + sklearn DBSCAN を SSDSE-B で実行
  2. Week 2:K-means、 階層的クラスタリングとの比較、 シルエットスコア計算
  3. Week 3:k-distance graph で eps 決定、 パラメータ感度分析
  4. Week 4:HDBSCAN を試す、 比較表を自分で作成
  5. Week 5:オリジナル論文 (Ester 1996) を読む
  6. Week 6:自分のデータ(業務 or 趣味)に適用
  7. Week 7:可視化を磨く、 BIツールに統合
  8. Week 8:論文・レポート作成、 ピアレビュー

🛤 完全パイプライン:データ取得から結果報告まで

  1. ① データ取得:SSDSE-B-2026.csv を 統計センター から DL、 data/raw/ に配置。
  2. ② 探索的分析(EDA)df.describe() で分布確認、 ペアプロットで関係性を把握。
  3. ③ 変数選択:分析目的に応じて 3-7 変数を選ぶ。 多重共線性を VIF で確認。
  4. ④ 前処理:欠損補完、 対数変換(必要なら)、 RobustScaler 標準化。
  5. ⑤ k-distance graph:eps の候補値を視覚的に決定。
  6. ⑥ DBSCAN 実行:複数 eps で試行、 結果の比較。
  7. ⑦ 評価:シルエット、 DBCV、 ドメイン解釈で総合判断。
  8. ⑧ HDBSCAN との比較:別アプローチでも同様の構造が出るか確認。
  9. ⑨ 可視化:散布図、 都道府県名アノテーション、 日本地図塗り分け。
  10. ⑩ 報告:上記テンプレに従って文書化、 ピアレビューを受ける。

📑 レポートテンプレート(DBSCAN 結果の文書化)

DBSCAN 結果を論文・レポートに書くときの定型:

1. データ

使用:SSDSE-B-2026 / 期間:2023 年 / 観測数 n=47 / 特徴量 p=5(人口・面積・所得・医師数・失業率)。

2. 前処理

欠損なし。 RobustScaler で標準化。 多重共線性確認(VIF<5)。

3. パラメータ決定

k-distance graph(k=10)で eps=1.0 を採用。 min_samples=5(次元数×1)。

4. 結果

3 クラスタ(n=20, 14, 8)+ ノイズ 5 件を抽出。 シルエットスコア=0.34、 DBCV=0.42。

5. 解釈

各クラスタの特徴を表で示し、 政策示唆を 3 点。 ノイズ県は個別事情を説明。

6. 限界

2023 年単年。 5 指標のみ。 DBSCAN は形状自由だが eps 感度あり。 経年変化や別指標での再検証が必要。

7. 再現性

scikit-learn 1.4 / Python 3.11 / 入力データの行は county_code 昇順固定。

🇯🇵 SSDSE-B-2026 で見える「47 都道府県の地図」

DBSCAN を実行すると現れる典型的クラスタ構造の解釈:

クラスタ A(首都圏・近畿圏の大都市)

東京・神奈川・大阪・愛知・埼玉・千葉・兵庫。 人口密度が高く、 第 3 次産業比率が高い。 ただし東京は人口で突出してノイズ判定されることが多い

クラスタ B(地方中核都市群)

北海道(札幌中心)・宮城・新潟・静岡・京都・広島・福岡。 県人口 200-500 万、 県庁所在地に機能集中。

クラスタ C(中規模県)

群馬・栃木・茨城・岐阜・三重・岡山・熊本など。 人口 100-200 万、 地方都市と農業のミックス。

クラスタ D(小規模県)

島根・鳥取・徳島・高知・佐賀・福井・山梨など。 人口 100 万以下、 高齢化進行。

ノイズ群

東京(巨大)、 沖縄(離島)、 北海道(広大な面積)など、 単独で「外れ」になる県。

これらは恣意的な分類ではなく、 SSDSE-B-2026 の客観的な数値から DBSCAN が自動抽出する構造です。 政策議論の土台に使えます。

🌳 密度ベース手法ファミリー全体像

📊 SSDSE-B-2026 におけるアルゴリズム別結果比較

47 都道府県を 5 指標でクラスタリングしたときの、 各アルゴリズムの典型的結果:

手法 クラスタ数 ノイズ/外れ値 シルエット 解釈性
K-means (k=3)3なし0.30〜0.35★★
階層的 (Ward)3-4なし0.32〜0.40★★★(樹形図)
DBSCAN2-45-8 件0.25〜0.40★★★★
HDBSCAN2-35-7 件0.30〜0.45★★★★★
GMM3確率付き0.28〜0.38★★★

SSDSE-B-2026 のような外れ値県を含む小規模データでは、 DBSCAN・HDBSCAN がノイズ判定で本質を捉えます。 解釈性と理論的根拠を兼ね備えた手法選択を。

🏗 大規模データ運用戦略

SSDSE-B-2026 は楽勝ですが、 顧客ログ 1 億行などでは戦略が必要:

データ規模 推奨手法 所要時間
〜1 万行sklearn DBSCAN数秒
10 万行sklearn + KD-tree数分
100 万行HDBSCAN + UMAP10-30 分
1000 万行cuML(GPU)数分
1 億行以上Spark MLlib / サブサンプリング数十分〜

✅ DBSCAN 実行前チェックリスト

💼 実務 Tips:チームでの DBSCAN 運用

🧠 理論的背景:密度推定との関連

DBSCAN は本質的にカーネル密度推定 (KDE) の離散版と見なせます。 KDE では各点周りにガウシアン等を置いて連続密度関数を構成しますが、 DBSCAN は eps 半径の「箱」を置き、 箱内の点数で局所密度を測ります。 局所密度が閾値(min_samples / 体積)を超える領域が「クラスタ」と判定されるわけです。

HDBSCAN はこの「閾値」を連続的に変化させ、 階層的にクラスタ構造を抽出することで、 DBSCAN の固定 eps の弱点を克服しています。 統計的にはパーシステントホモロジーと呼ばれる位相幾何学とも関連が深く、 「データの形」を抽出する技術として理論研究が続いています。

🎯 包括的事例:SSDSE-B-2026 で「過疎県」を自動定義

地方創生の政策ターゲットを定量的に決める想定の事例:

目的

「過疎県」を客観的に定義したい。 主観的に「東北 4 県」と決めるのではなく、 複数指標から DBSCAN で自動同定。

変数選択

手順

  1. SSDSE-B-2026 から該当列抽出、 標準化(RobustScaler 推奨)
  2. k-distance graph で eps を決定(おおむね 1.0〜1.2)
  3. DBSCAN(eps=1.0, min_samples=4) を実行
  4. 結果は通常 2-3 クラスタ + ノイズ 5-8 件
  5. 「人口減少率が高い・高齢化率が高い・所得が低い」クラスタを「過疎県群」と命名
  6. ノイズに分類された県は個別事情(離島、 大都市等)を別途調査

政策示唆

過疎県群(10-15 県)には移住支援・地域おこし協力隊・遠隔医療など共通支援、 ノイズ県(北海道、 沖縄等)には個別最適化された政策を適用、 という二段階アプローチが可能に。

📝 テキストデータへの DBSCAN 応用

文書クラスタリングに DBSCAN を使う手順:

  1. ① 文書埋め込み:TF-IDF(古典)か Sentence-BERT(現代)。 SSDSE 関連の論文を集めて Embedding。
  2. ② 次元削減:UMAP で 2-10 次元に圧縮。
  3. ③ DBSCAN or HDBSCAN:Cosine 距離で実行。 トピッククラスタが現れる。
  4. ④ クラスタ命名:各クラスタの代表文書を読んでトピック名を付ける。 c-TF-IDF で自動候補抽出も。
  5. ⑤ BERTopic:上記をパッケージ化したライブラリ。 1 行で文書トピック抽出可能。

🧭 DBSCAN が向かない場合の代替

🔁 クラスタの安定性検証

1 回の DBSCAN 結果を信じすぎず、 安定性を検証する手順:

  1. ① ブートストラップ:47 県から復元抽出で 100 回サンプリング、 各回の結果を比較。
  2. ② 摂動分析:データに小さなノイズを加えて再実行。 結果が大きく変わるなら不安定。
  3. ③ パラメータグリッド:eps を ±20% 動かし、 クラスタ構造が頑健か確認。
  4. ④ Jaccard 指標:複数回の結果で同じクラスタに入る確率を計算、 安定度指標に。
  5. ⑤ 経年比較:SSDSE-B-2026 を 2020 / 2021 / 2022 / 2023 でそれぞれ DBSCAN、 経年でクラスタが変動するか観察。

🗺 GPS・時空間データでの DBSCAN

DBSCAN が最も活躍するのは GPS 軌跡データの分析。 SSDSE-B-2026 とは別領域ですが、 学んでおくと応用力が上がります:

SSDSE 47 都道府県の緯度経度を Haversine 距離で DBSCAN しても面白い実験になります。

🎯 評価指標:シルエットスコア vs DBCV

シルエットスコアは K-means などの球状クラスタを前提にしているため、 DBSCAN の任意形状クラスタを正当に評価できないことがあります。 DBCV(Density-Based Clustering Validation)が密度ベース手法に特化した評価指標で、 HDBSCAN 論文と同時期に提案されました。

SSDSE-B-2026 のような小規模データでは、 シルエットも DBCV も両方計算してみて、 ドメイン解釈と整合する方を採用するのが実用的。

💡 クラスタ結果の意味づけ

「3 クラスタ + ノイズ」が出たとして、 そこから示唆を引き出す手順:

  1. ① 各クラスタの統計サマリdf.groupby(cluster).describe() で平均・分散・中央値を確認。
  2. ② 特徴的な変数を特定:クラスタ間で大きく差が出る変数を抽出(F 検定や Effect size)。
  3. ③ クラスタにラベル付け:「大都市群」「過疎県群」「中規模県群」など意味のある名前を付ける。
  4. ④ ノイズの個別解釈:「東京は人口が突出」「沖縄は離島で所得低」など、 ノイズ点 1 つずつ理由を述べる。
  5. ⑤ 政策示唆:「過疎クラスタには移住支援」「ノイズ東京には混雑対策」など、 実効的な提言に。
  6. ⑥ 限界の明示:「2023 年単年のデータ」「5 指標のみ」「DBSCAN のパラメータ依存」など、 結論の射程を明確に。

📚 主要ライブラリの DBSCAN 実装

ライブラリ 言語 特徴 使い所
scikit-learnPython標準実装、 ドキュメント充実学習・小〜中規模
hdbscanPythonHDBSCAN 専用、 確率付き密度不均一データ
cuMLPython/GPURAPIDS、 10-100倍高速大規模・GPU 環境
ELKIJava研究用、 多数のバリエーションアカデミア
dbscan (R)RR 統計エコシステム統計研究
Spark MLlibScala/Python分散処理超大規模

📖 SSDSE-B-2026 と DBSCAN の親和性

本サイトの題材 SSDSE-B-2026 は都道府県 × 年次 × 130 指標の小規模だが情報密度の高いデータです。 DBSCAN がここで効く理由:

🆚 DBSCAN と HDBSCAN の徹底比較

HDBSCAN は DBSCAN の改良版で、 SSDSE-B のような密度が不均一なデータに圧倒的に強い:

特徴 DBSCAN HDBSCAN
パラメータ数2 (eps, min_samples)1 (min_cluster_size)
密度不均一弱い強い
階層構造無しあり(dendrogram)
所属確率無しあり (membership_strength)
外れ値スコアバイナリ (noise/non-noise)連続値 (GLOSH)
新点の予測不可approximate_predict 可

🪤 実プロジェクトで出会う 8 つの罠

  1. ① クラスタが分かれすぎる:eps を少し大きく。 min_samples を少し小さく。
  2. ② 全部 1 クラスタ:eps が大きすぎ。 k-distance graph を見直す。
  3. ③ ノイズが多すぎる:データに本当にクラスタ構造があるか疑う。 PCA で目視確認。
  4. ④ クラスタが意味不明:標準化前に対数変換が必要かも。 ドメイン知識で変数選択を見直す。
  5. ⑤ 大量データで遅い:cuML や HDBSCAN を検討。 サンプリングで近似。
  6. ⑥ 結果が再現しない:データの行順序が変わると境界点割当てが微変動。 順序を固定。
  7. ⑦ 評価指標が高くならない:シルエットスコアは球状仮定。 DBCV を使う。
  8. ⑧ 新データ追加で再学習が必要:DBSCAN は predict なし。 HDBSCAN の approximate_predict を使う。

🧹 前処理が結果を左右する

DBSCAN は前処理の質に強く依存します。 SSDSE-B-2026 で守るべき手順:

  1. ① 欠損値処理:DBSCAN は NaN を受け付けない。 列平均補完、 KNN 補完、 または欠損のある県を削除。
  2. ② 外れ値の検討:標準化前に対数変換(人口など右に裾を引く分布に有効)。 np.log1p(A1101)
  3. ③ スケーリング:StandardScaler(平均0・分散1)または RobustScaler(中央値・IQR)。 外れ値が多いなら Robust。
  4. ④ カテゴリ変数:region などは One-hot 化、 または Gower 距離を使う。
  5. ⑤ 多重共線性:相関の高い変数(人口と男性人口など)は片方を除く。
  6. ⑥ 単位変換:「人口 10 万人当たり」などの相対化で大都市バイアスを軽減。
  7. ⑦ 重み付け:重要な変数を 2 倍するなど、 ドメイン知識で重み付け。

👻 次元の呪いと対処法

DBSCAN(および距離ベース手法全般)は高次元で性能が劣化します。 数学的な理由:

$d$ 次元空間でランダムな 2 点間のユークリッド距離は、 平均が $\sqrt{d}$、 標準偏差はほぼ一定。 つまり次元が増えるほど「全部の点が似たような距離」になり、 密度の濃淡が消えます。 SSDSE-B-2026 の 130 列全部を使うのは典型的な失敗例。

♻️ 再現性確保のチェックリスト

🎨 DBSCAN の派生・拡張アルゴリズム

📈 結果可視化の具体テクニック

  1. ① クラスタ別カラーマップmatplotlibtab10Set2。 ノイズは黒×でマーキング。
  2. ② 都道府県名アノテーション:散布図に plt.annotate(prefecture, (x, y))。 重なる場合 adjust_text で自動調整。
  3. ③ クラスタ重心の表示:各クラスタの平均位置に星印を打つと、 クラスタ間の関係性が見える。
  4. ④ ノイズだけハイライト:ノイズ点を大きい星マーカーで強調、 「外れている県」を視覚的に強調。
  5. ⑤ 確率密度の等高線:seaborn の kdeplot で背景に密度等高線を重ねると、 「なぜここがクラスタか」が一目瞭然。
  6. ⑥ インタラクティブ可視化:plotly で散布図、 ホバーで都道府県名表示。
  7. ⑦ 日本地図塗り分け:japanmap で 47 都道府県をクラスタ番号で色分け。 地理的傾向が明確に。

🔍 DBSCAN vs Isolation Forest(異常検知比較)

外れ値検出という観点で、 DBSCAN と Isolation Forest を比較:

観点 DBSCAN Isolation Forest
原理密度の低い点を異常少ない分岐で隔離できる点を異常
パラメータeps, min_samplescontamination, n_estimators
出力クラスタ + ノイズラベル異常スコア(連続値)
高次元弱い(次元の呪い)強い
速度O(n log n)O(n log n)
SSDSE 適合クラスタリング目的スコアリング目的

📊 SSDSE-B-2026 完全解析例

47 都道府県を 5 つの指標(人口・面積・所得・医師数・失業率)で密度クラスタリングする実例:

準備

SSDSE-B-2026 から該当年(2023)のデータを抽出、 欠損のない 47 行を確保。 標準化(StandardScaler)。

k-distance graph

k=10(次元数 × 2)で実行、 ソートしてプロット。 約 1.0 あたりに肘が現れる。 eps=1.0 を採用。

DBSCAN 実行

DBSCAN(eps=1.0, min_samples=5)。 結果は概ね 3 クラスタ + ノイズ 5-7 件になる:

K-means k=4 と比較すると、 DBSCAN は東京を強引にどこかに入れずノイズとして識別する点で優位。 地理学的な異質性が自動で見える化されます。

🔬 実際の研究での DBSCAN 利用例

🛠 実装上の Tips

  1. algorithm パラメータ:通常は 'auto'。 高次元なら 'brute'、 低次元なら 'kd_tree' or 'ball_tree'。
  2. n_jobs=-1:近傍探索の並列化(一部の処理のみ)。
  3. leaf_size:KD-tree のリーフサイズ。 メモリ vs 速度のトレードオフ。
  4. ④ メモリ節約:100 万点超なら sparse 距離行列、 または cuML / HDBSCAN を使用。
  5. ⑤ 乱数シード不要:DBSCAN は決定論的アルゴリズム。 K-means と違って再現性は標準確保。
  6. ⑥ predict が無い:DBSCAN は fit_predict のみ。 新点には別途近傍判定が必要。
  7. ⑦ 結果の安定性:データ順序に弱依存。 ソート方法を変えると境界点の割当てが微変動。

📐 k-distance graph による eps 決定法(詳細)

DBSCAN 成功の 80% は eps 選択に左右されます。 標準的な手順:

  1. ① k = min_samples を選ぶ(例:4)
  2. ② 全点に対し k 番目最近傍距離を計算。 sklearn の NearestNeighbors(n_neighbors=k).kneighbors(X) で得られる。
  3. ③ ソートしてプロット。 x 軸 = 点のインデックス(距離降順)、 y 軸 = k 番目最近傍距離。
  4. ④ 「肘 (knee)」を視覚で特定。 曲線が急に立ち上がる場所。 そこが eps の良い候補。
  5. ⑤ 自動肘検出kneed ライブラリの KneeLocator。 curve='convex', direction='increasing'。
  6. ⑥ 周辺で試行:肘の前後 ±20% で複数試し、 シルエットや解釈可能性で比較。

SSDSE-B-2026 の 47 都道府県を標準化後、 k=4 で k-distance graph を描くと、 通常 0.8〜1.2 あたりに肘が現れます。 この近辺で eps を試すのが安定。

📊 クラスタリング品質の評価指標

指標 範囲 良い値 DBSCAN での注意
シルエットスコア-1〜+1+1 に近いノイズを除外して計算
Calinski-Harabasz0以上大きい程よい球状仮定があるため DBSCAN にはやや不向き
Davies-Bouldin0以上小さい程よいノイズあると不安定
DBCV-1〜+1+1 に近い密度ベースに特化(推奨)
ARI-1〜+1+1 に近い正解ラベルが必要(教師あり評価)

📅 DBSCAN の歴史と背景

⚡ 大規模データへの拡張

SSDSE-B-2026 の 47 都道府県は楽勝ですが、 数十万〜数億点になると工夫が必要:

🧬 DBSCAN アルゴリズムの内部動作(疑似コード)

1996 年に Martin Ester らが発表した DBSCAN のオリジナルアルゴリズムを擬似コードで再構成:

DBSCAN(D, eps, MinPts):
  C = 0  // クラスタ番号
  for each point P in D:
    if P is visited: continue
    mark P as visited
    Neighbors = regionQuery(P, eps)
    if |Neighbors| < MinPts:
      mark P as NOISE
    else:
      C = C + 1
      expandCluster(P, Neighbors, C, eps, MinPts)

expandCluster(P, Neighbors, C, eps, MinPts):
  add P to cluster C
  for each point P' in Neighbors:
    if P' is not visited:
      mark P' as visited
      Neighbors' = regionQuery(P', eps)
      if |Neighbors'| >= MinPts:
        Neighbors = Neighbors ∪ Neighbors'
    if P' is not yet in any cluster:
      add P' to cluster C

SSDSE-B-2026 の 47 都道府県を眺めながら動作を追うと、 「ある県をシードに密度連結でクラスタが成長していく」過程が直感的に理解できます。 visited フラグで O(n) を保証し、 regionQuery が KD-tree なら全体で O(n log n)。

🌊 密度とは何か:3 種類の点の定義

点の種類 条件 SSDSE 例
コア点 (core)eps 近傍に min_samples 個以上愛知・福岡(中規模都市の集まり中央)
境界点 (border)コア点の eps 近傍にいるがコア条件は満たさない広島・宮城など中規模県の縁
ノイズ (noise)どのコア点の近傍にもいない東京(極端な大都市)・鳥取(小規模)

📏 距離尺度の選び方

DBSCAN の metric 引数で距離関数を変えられます。 デフォルトはユークリッド距離ですが、 用途で使い分けを:

🔬 数式を言葉で読み解く(拡張)

DBSCAN は密度という概念を「点 p から半径 $\varepsilon$(eps)内に min_samples 個以上の他点が存在する」と定義します。 この条件を満たす点をコア点 (core point)、 コア点の $\varepsilon$ 近傍にあるがコア条件を満たさない点を境界点 (border point)、 どちらでもない点をノイズ (noise) と呼びます。 47 都道府県を 2 つの標準化済み指標(例:人口・面積)でプロットしたとき、 中規模県が集まる「真ん中の塊」がコア点群となり、 東京や鳥取のような外れた点はノイズ判定されやすい、 というわけです。

形式的には、 点 $q$ が点 $p$ から「密度直接到達可能」 (directly density-reachable) であるとは、 $q \in N_\varepsilon(p)$ かつ $p$ がコア点であること。 「密度到達可能」 (density-reachable) は、 中間にコア点を介して連鎖的に到達できる関係で、 これにより 1 つのクラスタが伸びていきます。 さらに「密度連結」 (density-connected) とは、 ある共通のコア点を介して 2 点が密度到達可能であることを意味します。 1 つのクラスタは「密度連結同値類」として定義され、 K-means のような球状仮定なしで任意の形状を抽出できるのが DBSCAN の本質的優位性です。

計算量は素朴実装で $O(n^2)$、 KD-tree や Ball tree などの空間索引を併用すれば平均 $O(n \log n)$。 SSDSE-B-2026 の 47 都道府県程度なら無視できるオーダー差ですが、 GPS 軌跡(10 万点)や顧客行動(100 万点)になると索引の有無が数十倍の速度差になります。 scikit-learn の DBSCAN(algorithm='auto') はサンプル数と次元から自動選択しますが、 高次元(次元 ≥ 20)では木索引が「次元の呪い」で劣化するため、 PCA で次元圧縮してから DBSCAN を実行するのが定石です。

🏭 産業別の活用事例(6 件)

DBSCAN の最大の強みは「クラスタ数を事前指定不要ノイズ自動検出」。 これが業界で重宝される理由です。

⚖️ DBSCAN vs K-means vs 階層 vs HDBSCAN:徹底比較

手法 クラスタ数 形状仮定 ノイズ検出 計算量 SSDSE-B 適合
K-means事前指定 (k)球状なしO(n·k·d·t)★★★(k 決め必要)
階層的事後決定凝集 / 分割なしO(n²-n³)★★★★(樹形図で見やすい)
DBSCAN自動決定任意ありO(n log n)★★★★★(外れ値県の発見)
HDBSCAN自動決定任意・階層あり・確率付O(n log n)★★★★★(密度不均一に強い)
GMM事前指定楕円体なし(確率低)O(n·k·d²·t)★★★(柔軟)

📝 演習問題(5 問)

Q1. SSDSE-B-2026 の 47 都道府県を、 人口 (A1101) と面積 (B1101) でクラスタリングしてください

標準化後 DBSCAN(eps=1.0, min_samples=3) で実行。 北海道は面積で外れ、 東京は人口で外れるためノイズになりがち。

Q2. eps を 0.5, 1.0, 2.0 と変えたとき、 クラスタ数とノイズ数はどう変化する?

eps を増やすとクラスタが結合してクラスタ数↓・ノイズ数↓。 極端に大きいと全部 1 クラスタに。

Q3. min_samples を増やすとどうなる?

コア点条件が厳しくなり、 ノイズが増える。 通常は 2*次元数 を起点に調整。

Q4. 標準化をしないと何が起こる?

人口(1000 万単位)が面積(万 km²)を圧倒し、 距離計算がほぼ人口だけで決まる。 標準化は必須。

Q5. K-means と DBSCAN の結果が大きく違うのはどんな場面?

クラスタが非球状・密度差があるとき。 SSDSE-B-2026 のように外れ値(東京)が混ざる場合、 K-means は東京を強引にどこかに入れるが DBSCAN は noise 判定する。

💥 DBSCAN 失敗事例(7 件)

📔 拡張ミニ用語集(10 語)

eps(ε)
近傍半径。 SSDSE-B 標準化後では 0.5〜2.0 を試行
min_samples
コア点判定の最小近傍数。 2*次元数を起点に
コア点
eps 近傍に min_samples 以上の点を持つ点
境界点
コア点の近傍だがコア条件を満たさない
ノイズ点
どのクラスタにも属さない孤立点(label = -1)
密度到達可能
コア点の連鎖を介して到達できる関係
k-distance graph
k 番目最近傍までの距離をプロット、 肘から eps を推定
OPTICS
DBSCAN の eps 不要版。 密度の連続的な変化を扱える
HDBSCAN
階層的 DBSCAN。 密度不均一に強く確率付きで割当
シルエットスコア
クラスタの内部結束と分離度の指標。 評価に使う

📖 参考文献

🎛 パラメータチューニング詳細手順

「eps と min_samples をどう決めるか」が DBSCAN の最重要論点。 SSDSE-B-2026 を題材にした実践手順:

  1. ① 標準化StandardScaler または RobustScaler(外れ値県の影響を抑える)。
  2. ② min_samples の初期値:2 * 特徴量次元数を目安。 2 次元なら 4。
  3. ③ k-distance graph 描画NearestNeighbors(n_neighbors=min_samples) で k 番目最近傍距離を全点に対して計算、 ソートしてプロット。
  4. ④ 肘の検出:曲線が急に立ち上がる点を eps として採用。 視覚で十分、 自動なら kneedle ライブラリ。
  5. ⑤ クラスタ数とノイズ率を確認:適切な範囲か(SSDSE 47 県で 3-7 クラスタ・ノイズ 1-5 件あたりが目安)。
  6. ⑥ シルエットスコアで評価:ノイズを除外したクラスタの結束・分離度を確認。
  7. ⑦ 結果のドメイン解釈:「東京単独クラスタ」「北海道がノイズ」など、 既知知見と整合するか。

🌳 OPTICS と HDBSCAN:DBSCAN の進化系

DBSCAN の弱点「密度の異なるクラスタが混在すると失敗する」を克服する派生手法:

OPTICS(Ordering Points To Identify the Clustering Structure)

1999 年 Ankerst らが提案。 eps を固定しない点が革新的。 「到達可能性距離」を計算し、 任意の eps で事後的にクラスタを切り出せる。 scikit-learn では sklearn.cluster.OPTICS で利用可能。

HDBSCAN(Hierarchical DBSCAN)

2013 年 Campello らが提案。 階層的に密度クラスタを抽出し、 「最も安定なクラスタ」を自動選択。 SSDSE-B-2026 のような密度が場所により異なるデータには HDBSCAN が圧倒的に強い。 hdbscan パッケージ(pip install hdbscan)でアクセス。 ハイパーパラメータが min_cluster_size のみで運用が楽。

🚨 異常検知としての DBSCAN 活用

クラスタリング目的を超え、 DBSCAN は異常検知のシンプルかつ強力な手法でもあります。 ノイズ(label=-1)= 異常 と読み替えるだけ:

K-means と違い「異常も無理にどこかのクラスタに押し込む」現象がないため、 異常検知用途では DBSCAN / HDBSCAN / Isolation Forest が定番です。

📊 結果の可視化テクニック

  1. ① 2D 散布図:標準化後の 2 軸でプロット、 クラスタ番号で色分け、 ノイズは黒×印。
  2. ② PCA で 2D 圧縮:SSDSE-B の高次元データを PCA で 2 軸化、 DBSCAN 結果を重ねる。
  3. ③ 都道府県名ラベル:散布図に prefecture 名を annotate。 「ノイズは東京と沖縄」が一目で分かる。
  4. ④ クラスタ別の指標分布:各クラスタで人口・所得・医師数の平均を棒グラフ化、 クラスタの「人物像」を明確に。
  5. ⑤ 日本地図に塗り分け:japanmap / folium で、 クラスタごとに色分け。 地理的なまとまりがあるかを視覚化。
  6. ⑥ k-distance graph:eps 選択の根拠図として論文・レポートに必須。

🛠 30 分ハンズオン:SSDSE-B で 47 都道府県クラスタリング

  1. Step 1(5 分)pip install pandas scikit-learn matplotlib、 SSDSE-B-2026.csv を data/raw/ に配置。
  2. Step 2(5 分):人口・面積・所得・医師数の 4 列を読み込み、 StandardScaler で標準化。
  3. Step 3(5 分)NearestNeighbors(n_neighbors=4) で k-distance graph を描画、 肘から eps を決定。
  4. Step 4(5 分)DBSCAN(eps=決定値, min_samples=4) で実行、 labels_ を確認。
  5. Step 5(5 分):2D 散布図に都道府県名 + クラスタ色で可視化。
  6. Step 6(5 分):HDBSCAN でも実行、 結果比較。 安定クラスタの違いを観察。

🎯 このページの要点

🎓 研究応用:地域類型化への DBSCAN

SSDSE-B-2026 を用いた研究で DBSCAN がよく使われる場面:

💭 拡張 Q&A(6 件)

Q1. DBSCAN は何次元まで使える?
2-10 次元が現実的。 それ以上は「次元の呪い」で距離が均一化、 PCA / UMAP で次元圧縮を。
Q2. K-means より遅い?
素朴実装は O(n²) で遅いが、 KD-tree 索引で平均 O(n log n)。 SSDSE 47 県なら無視できる。
Q3. ノイズが多すぎる、 どうする?
eps を大きく、 min_samples を小さく。 それでもダメなら HDBSCAN に。
Q4. クラスタが 1 つにまとまってしまう
eps が大きすぎる。 k-distance graph を見直して、 もっと小さい eps を試す。
Q5. クラスタを K-means の k=3 のように指定したい
DBSCAN ではできない。 階層的クラスタリング(dendrogram を切る)か K-means を使う。
Q6. 新しいデータ点が来たとき、 既存クラスタに割り当てたい
DBSCAN には predict 機能なし。 nearest neighbor で割当るか、 HDBSCAN の approximate_predict を使う。

🎨 概念図と総まとめ表(補遺)

本セクションは キーワード索引 として記事全体の構造を 3 図 + 6 表で再整理し、 「どこに何が書いてあるか」と「DBSCAN の意思決定」を一望できるようにしたものである。 図は <img> 要素として埋め込んでおり、 画像ビューア・スクリーンリーダ・印刷でも崩れない。

🖼 図 1: DBSCAN の 3 種類の点 — コア点 / 境界点 / ノイズ

DBSCAN を理解する最初の鍵は、 すべての点が「コア点」「境界点」「ノイズ点」のいずれかに分類されることである。 下の図は、 半径 ε の円の中に minPts 以上の近傍が入っているか否かで分岐していく様子を表したものだ。

DBSCAN のコア点・境界点・ノイズ点の関係図%E3%82%B3%E3%82%A2%E7%82%B9 (core)%CE%B5 %E5%86%85%E3%81%AB minPts %E4%BB%A5%E4%B8%8A%E5%A2%83%E7%95%8C%E7%82%B9 (border)%CE%B5 %E5%86%85 minPts %E6%9C%AA%E6%BA%80%E3%80%81%E3%81%A0%E3%81%8C%E3%82%B3%E3%82%A2%E3%81%AB%E5%B1%9E%E3%81%99%E3%83%8E%E3%82%A4%E3%82%BA (noise)%E3%81%A9%E3%81%93%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%81%AB%E3%82%82%E5%B1%9E%E3%81%95%E3%81%9A%CE%B5 = %E8%BF%91%E5%82%8D%E5%8D%8A%E5%BE%84%E3%80%81minPts = %E3%82%B3%E3%82%A2%E5%88%A4%E5%AE%9A%E3%81%97%E3%81%8D%E3%81%84%E5%80%A4" style="max-width:680px;width:100%;height:auto;border:1px solid #CFD8DC;border-radius:8px;">

💬 読み方:左の青円が コア点、 中央のオレンジが 境界点、 右の灰色が ノイズ。 境界点はコア点とつながっていてクラスタの一員になれるが、 ノイズ点はどのコアからも到達不能で −1 ラベルになる。

🖼 図 2: k-distance graph で ε を決める手順

DBSCAN で最も悩ましいパラメータは ε だが、 経験則として 「k-distance graph の肘」 を見れば概ね当てが付く。 横軸を点の番号(k 番目の近傍距離でソート)、 縦軸を k-番目近傍距離としたとき、 急激に立ち上がる位置が外れ値とクラスタ点の境目になる。

k-distance graph による ε 選択の概念図%E7%82%B9 (k-%E8%BF%91%E5%82%8D%E8%B7%9D%E9%9B%A2%E3%81%A7%E6%98%87%E9%A0%86%E3%82%BD%E3%83%BC%E3%83%88)k-%E8%BF%91%E5%82%8D%E8%B7%9D%E9%9B%A2%E3%80%8C%E8%82%98%E3%80%8D = %CE%B5 %E5%80%99%E8%A3%9C%E5%AF%86%E3%81%AA%E9%83%A8%E5%88%86%E5%A4%96%E3%82%8C%E5%80%A4%E3%83%BB%E3%83%8E%E3%82%A4%E3%82%BA" style="max-width:680px;width:100%;height:auto;border:1px solid #CFD8DC;border-radius:8px;">

💬 読み方:曲線が急に立ち上がる位置が ε の候補。 早すぎると微小クラスタが乱立し、 遅すぎると 1 つの巨大クラスタになる。 minPts は次元 d に対し 2d 程度から試すのが定番。

🖼 図 3: アルゴリズムの分岐フロー

未訪問の点を起点に「近傍数 ≥ minPts なら BFS で密度連結成分を拡張、 そうでなければ一旦ノイズに置く」を繰り返す。 後で他のコア点の近傍に入ってくれば境界点に格上げされる。

DBSCAN の判定フローチャート%E7%82%B9 p %E3%82%92%E9%81%B8%E3%81%B6%CE%B5 %E5%86%85 %E2%89%A5 minPts ?YesNo%E3%82%B3%E3%82%A2%E7%82%B9%E5%8C%96%E3%80%81%E8%BF%91%E5%82%8D%E3%82%92BFS%E3%81%A7%E6%8B%A1%E5%BC%B5%E4%B8%80%E6%97%A6%E3%83%8E%E3%82%A4%E3%82%BA (-1) %E3%81%AB%E3%81%99%E3%82%8B%E5%88%B0%E9%81%94%E5%8F%AF%E8%83%BD%E7%82%B9%E3%82%92%E5%85%A8%E9%83%A8%E3%83%A9%E3%83%99%E3%83%AB%E4%BB%98%E3%81%91%E4%BB%96%E3%81%AE%E3%82%B3%E3%82%A2%E3%81%AE%E8%BF%91%E5%82%8D%E3%81%AB%E5%85%A5%E3%82%8C%E3%81%B0%E5%A2%83%E7%95%8C%E7%82%B9%E3%81%AB" style="max-width:680px;width:100%;height:auto;border:1px solid #CFD8DC;border-radius:8px;">

💬 読み方:「ノイズ扱いになった点」が後で他のコア点から到達可能になれば 境界点に再分類される(左下から右下への矢印)。 この再分類が DBSCAN の「形状自由」の鍵である。

📊 表 1: コア点・境界点・ノイズ点の判定基準まとめ

分類ε 近傍点数クラスタ参加ラベル例
コア点≥ minPts同じクラスタの中心メンバー0, 1, 2, ...
境界点< minPts かつ コア点の ε 内最寄りコアと同じクラスタ0, 1, 2, ...
ノイズ< minPts かつ どのコアの ε にも入らないどこにも所属しない−1

📊 表 2: ε と minPts の標準的なグリッド範囲

データ規模推奨 minPtsε 探索開始調整方針
小規模 (n < 100)3 〜 5k-距離 70 〜 80 パーセンタイルノイズを許容しないなら minPts を下げる
中規模 (100 〜 10,000)2d 〜 4d(d は次元)k-距離の「肘」ノイズが多すぎたら ε を緩める
大規模 (> 10,000)10 〜 50サブサンプルで決定HDBSCAN の方が安定

📊 表 3: 他クラスタリングとの比較(密度・形状・パラメータ)

手法クラスタ数指定扱える形状ノイズ判定
DBSCAN不要任意形状あり (−1)
K-means必要 (k)球形(凸)なし
階層的事後 (dendrogram)連結成分次第なし
HDBSCAN不要任意形状あり

📊 表 4: SSDSE-B-2026 県別データに DBSCAN を当てたときの典型結果

入力標準化代表 ε典型出力
総人口, 住宅着工戸数必須0.5東京・大阪・神奈川・愛知など大都市圏 9 県が −1、 地方圏 1 クラスタ
高齢化率, 出生率必須0.4沖縄が −1、 東北・四国が同じクラスタ
3 産業比率(1次/2次/3次)不要(合計100%)5.0第 1 次産業県が独立クラスタとして抽出

📊 表 5: scikit-learn の DBSCAN 主要引数

引数既定値意味調整ポイント
eps0.5近傍とみなす半径k-distance graph で決定
min_samples5コア判定に必要な近傍数次元 d の 2 倍が目安
metric"euclidean"距離関数テキストなら cosine、 緯度経度なら haversine
algorithm"auto"近傍探索の索引大規模なら "ball_tree"

📊 表 6: DBSCAN が向く / 向かない場面

場面向き不向き理由
外れ値検出を兼ねたいノイズラベル −1 が標準
バナナ・リング状クラスタ密度連結で形状自由
密度が大きく違うクラスタ混在単一 ε では分けにくい → HDBSCAN へ
高次元(d ≥ 20)×距離が均一化、 ε が機能しない
クラスタ数を事前指定したい×k 指定の概念がない → K-means へ

📝 セクション横断のチェックリスト

本記事を一通り読み終えた後、 自分の理解を 8 項目で点検したい。 1 つでも答えに詰まる場所があれば、 該当セクションへ戻って読み直すのが安全である。

🧪 実務での「失敗事例」と回避策

DBSCAN は「魔法のように形を捉える」反面、 設定を誤ると全データが 1 クラスタ、 あるいは全データがノイズになる極端な結果を生むことがある。 代表的な失敗 3 つと、 即座に効く対策を整理しておく。

  1. 失敗 1:標準化を忘れて売上 (円) と件数 (個) を同時に渡した。 ε の意味が完全に壊れ、 売上だけで近傍が決まる。 → StandardScaler をパイプラインに必ず挟む。
  2. 失敗 2:minPts を大きすぎる値(30 など)にして、 全データがノイズに。 中規模データでは minPts = 2 × 次元 から探し、 ノイズ率が 30 % を超えていたら下げる。
  3. 失敗 3:高次元(d = 50)の埋め込みベクトルに直接 DBSCAN。 距離が均一化し、 ε がほぼ機能しない。 → 先に UMAP / PCA で 2 〜 5 次元に圧縮してから当てる。

🔁 DBSCAN を回す前後でやることまとめ(実務テンプレート)

SSDSE-B-2026 等の県別データに DBSCAN を当てるとき、 単に fit_predict を呼ぶだけでは「期待した結果が出ない」「再現できない」事故が起きやすい。 以下の前処理・本実行・後処理の 3 段階を踏むのが安全である。

前処理(データを密度議論に乗せる)

本実行(パラメータ探索)

後処理(結果を読み・伝える)

📜 DBSCAN の歴史と派生アルゴリズム年表

DBSCAN は密度ベースクラスタリングの最初期の成功例であり、 そこからいくつもの派生が生まれた。 代表的なものを年代順に並べると、 自分が扱おうとしている問題にどの派生が向くかを判断しやすい。

🌐 SSDSE-B-2026 における別の応用例(補足)

本記事の本編では (総人口, 住宅着工戸数) の例を扱ったが、 SSDSE-B-2026 には DBSCAN を活かせる他の軸もある。 ここでは「軸の選び方」と「結果の解釈」を簡潔にまとめる。

📖 用語の対応表(日本語・英語・略号)

DBSCAN を読み書きするときに頻出する用語の対応関係を、 日英・略号で整理しておく。 論文・公式ドキュメント・実装ソースコードを跨いで読むときに役立つ。

日本語英語略号 / コード上の名前
密度ベースクラスタリングDensity-Based ClusteringDBSCAN, HDBSCAN, OPTICS
近傍半径neighborhood radiuseps (ε)
最小近傍点数minimum samplesmin_samples (minPts)
コア点core pointcore_sample_indices_
境界点border pointnon-core, labels_ ≠ −1
ノイズ点noise pointlabels_ = −1
密度到達可能density-reachable— (概念のみ)
密度連結density-connected— (概念のみ)

❓ FAQ 補遺(読者から想定される追加質問)

本編の Q&A に含まれなかった、 やや細かい質問を 4 件補足する。 いずれも実務でつまずきやすいポイントである。

Q. DBSCAN は再現性があるか — アルゴリズム自体は決定論的だが、 sklearn の実装ではタイブレーク順が入力順に依存する。 つまり入力の並び順を変えると、 境界点の所属クラスタが入れ替わることがある。 厳密な再現性が必要なら、 入力 DataFrame をソート固定してから渡す。

Q. NaN を含む列があるとどうなるか — sklearn の DBSCAN は NaN を許容しない。 SimpleImputer で median 補完するか、 NaN 行をドロップしてから渡すこと。 ドロップする場合は「外れ値疑い」と「欠損」の区別を意識する。

Q. クラスタごとの代表点を取りたい — sklearn の DBSCAN は重心を返さない。 core_sample_indices_ から各クラスタのコア点を取り出し、 平均ベクトルを別途計算するのが定石。 境界点を含めるかは目的に応じて決める。

Q. クラスタの大小に意味はあるか — 大きさ自体は単にデータ密度を反映するだけで、 「重要性」を示すわけではない。 小さなクラスタが業務上重要なセグメント(例: ハイバリュー顧客)を表すこともよくある。 サイズではなく「何で構成されるか」で読むこと。

🧩 K-means との「使い分けフローチャート」 (テキスト版)

新しいデータが手元に来たとき、 DBSCAN と K-means のどちらを使うべきか迷う場面は多い。 以下の質問を順に答えていけば、 概ね妥当な選択ができる。

  1. 「クラスタ数 K は事前に決められるか?」 — Yes なら K-means、 No なら 2 へ。
  2. 「クラスタは大体丸い (凸) と仮定して良いか?」 — Yes なら K-means / GMM、 No なら 3 へ。
  3. 「外れ値をクラスタとは別扱いにしたいか?」 — Yes なら DBSCAN / HDBSCAN、 No なら 4 へ。
  4. 「密度がクラスタ間で大きく違うか?」 — Yes なら HDBSCAN、 No なら DBSCAN。
  5. 「次元 d は 20 未満か?」 — Yes ならそのまま、 No なら先に PCA / UMAP で次元削減。

この 5 つの質問を 30 秒で答えれば、 SSDSE-B-2026 のような中規模の県別データなら DBSCAN かどうかをすぐ判断できる。 業務データで密度が大きく不均一な場合は HDBSCAN を第一候補にすると失敗が少ない。

以上、 キーワード索引として図 3 点・表 6 点・チェックリスト 8 項目・失敗事例 3 点・前処理〜後処理テンプレート・歴史と派生年表・SSDSE-B での追加応用例・日英対応表・FAQ 補遺・使い分けフローチャートで記事全体の要点を再収録した。 個別の詳細はそれぞれのセクションを参照のこと。 DBSCAN は「密度連結」というシンプルな発想で外れ値検出とクラスタリングを同時にこなす、 きわめて実用的な道具である。 次に進むなら HDBSCAN・OPTICS の各記事へ、 また入力データの距離計量を考え直したいときは「標準化」「距離尺度」「次元の呪い」の各記事を参照すると、 DBSCAN を一段深く理解できる。 探索段階では小さな ε から始め、 ノイズ率の振る舞いを見ながら緩めていくのが安全策である。 最終的にどの ε と minPts に落ち着いたか、 そしてその選択を業務上どう説明したかを、 必ず再現可能な形で記録しておくことを強く推奨する。

🎨 概念図で押さえる DBSCAN の本質

DBSCAN を最短で腹落ちさせる 3 枚の図。 ① k-means が苦手な非凸クラスタを密度連結で拾う、 ② Core/Border/Noise の 3 役割、 ③ ε と minPts のチューニング感覚 (k-distance plot)。

DBSCAN 概念図1: 非凸クラスタを密度連結で拾う DBSCAN 概念図2: Core / Border / Noise の3ラベル DBSCAN 概念図3: k-distance plot で ε を決める

k-means: 非凸を分割できない DBSCAN: 密度連結で形を問わない 直線で割るため C 字や三日月では破綻 密度連結なら三日月でも 1 つのクラスタ、 孤立点はノイズ扱い
図 A: 非凸クラスタへの強さ。 k-means は直線分割なので C 字を割れないが、 DBSCAN は密度がつながっていれば形に依存しない。
Core / Border / Noise の 3 役割 (minPts=4) Core 点 ε 内に minPts 以上 Border 点 Core の ε 内にあるが 自分は minPts 未満 Noise (外れ値) どの Core にも届かない 独立点
図 B: Core (ε 内に minPts 以上) / Border (Core の ε に入るが自分は少数) / Noise (孤立) の 3 役割が DBSCAN の出力ラベルすべてである。
k-distance plot による ε 選定 点を k 距離でソート (k = minPts-1) k-最近傍距離 推奨 ε 膝 (elbow) 急に立ち上がる「膝」の高さを ε に取れば、 ほとんどの点が高密度領域内に収まる
図 C: ε の決め方は k-distance plot の膝。 急変点を ε にすると Core 点率が安定し、 ノイズ率が暴れにくくなる。

💬 ①密度連結なら非凸でも切れる、 ②出力は Core/Border/Noise の 3 ラベルだけ、 ③ ε は k-distance plot の膝で決める — この 3 点を押さえれば DBSCAN の挙動はほぼ説明できる。

🧮 数式に値を入れて手で計算する: DBSCAN のコア点判定

2 次元の数値ベクトル 6 点 [0, 0], [1, 1], [1, 0], [2, 1], [8, 8], [9, 9] に eps=2.0, minPts=3 を適用し、各点がコア点か境界点かノイズかを手計算で判定する。

Step 1: 入力データ(数値ベクトル)

入力点群(2 次元ベクトル): p1=[0, 0], p2=[1, 1], p3=[1, 0], p4=[2, 1], p5=[8, 8], p6=[9, 9]

パラメータ: ε (eps) = 2.0、 minPts = 3(自身を含む)

コア点判定式: dist(pi, pj) = √((xi−xj)² + (yi−yj)²) ≤ ε で近傍を列挙し、近傍数 ≥ minPts なら「コア点」。

Step 2: 距離計算と近傍列挙

座標ベクトル近傍 (eps=2.0、自含)近傍数コア?
p1[0, 0]p2(√2≈1.41), p3(√1=1.0)3 (自+p2+p3)○ コア
p2[1, 1]p1(√2), p3(√1), p4(√1)4 (自+p1+p3+p4)○ コア
p3[1, 0]p1(√1), p2(√1), p4(√2)4 (自+p1+p2+p4)○ コア
p4[2, 1]p2(√1), p3(√2)3 (自+p2+p3)○ コア
p5[8, 8]p6(√2≈1.41)2 (自+p6)× ノイズ
p6[9, 9]p5(√2)2 (自+p5)× ノイズ

Step 3: クラスタ割り当て

コア点: p1, p2, p3, p4 (近傍数 ≥ 3) 密度連結チェック: p1—p2—p3—p4 は全員互いに ε=2.0 圏内 → 1 クラスタ クラスタ 0: {p1, p2, p3, p4} ノイズ (-1): p5=[8,8], p6=[9,9] (近傍数 2 < minPts=3) 手計算ラベル: [ 0 0 0 0 -1 -1]、 コアindex: [0 1 2 3]

🐍 Python で再現

このコードでやること:手計算した数値ベクトル 6 点 [[0,0],[1,1],[1,0],[2,1],[8,8],[9,9]] を numpy 配列で定義し、DBSCAN(eps=2.0, min_samples=3) を実行。 labels_ とコアインデックスが手計算 Step 3 の結果と一致することを確認する。

📥 入力データ(Step 1 の 6 つの数値ベクトル):

X = [[0, 0], [1, 1], [1, 0], [2, 1], [8, 8], [9, 9]] eps=2.0, min_samples=3 (自身を含む近傍数) 手計算期待: ラベル [ 0 0 0 0 -1 -1]、 コアindex [0 1 2 3]
1
2
3
4
5
6
import numpy as np
from sklearn.cluster import DBSCAN
X = np.array([[0,0],[1,1],[1,0],[2,1],[8,8],[9,9]])
db = DBSCAN(eps=2.0, min_samples=3).fit(X)
print(f"ラベル: {db.labels_}")
print(f"コア index: {db.core_sample_indices_}")

📤 実行結果

ラベル: [ 0 0 0 0 -1 -1] コア index: [0 1 2 3]

💬 手計算 (Step 3) の結果 ラベル=[ 0 0 0 0 -1 -1]、コアindex=[0 1 2 3] と Python 出力が完全に一致。 数値ベクトル [0,0],[1,1],[1,0],[2,1] が同じクラスタ 0 に、 [8,8],[9,9] がノイズ (-1) になることが手計算と Python 実装で同じ結果であることを確認した。

🔗 隣接手法への橋渡し

「DBSCAN」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。

これらの接続を意識することで、 「DBSCAN」を中核に据えた一貫した分析パイプライン(前処理 → DBSCAN → 評価・解釈)を構築できる。

🌳 手法選択フロー

「DBSCAN (密度ベースクラスタリング)」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。

  1. Step 1: 目的は記述か予測か?
    • 記述 (現状把握・要約) → 集計・可視化・要約統計量で全体像を掴む
    • 予測 (未知データへの推定) → モデル構築・検証フェーズへ移行
  2. Step 2: データの種類・規模は?
    • 数値データ・小〜中規模 → 「DBSCAN (密度ベースクラスタリング)」やその拡張手法を直接適用
    • カテゴリデータ → カテゴリ専用の手法(k-means + One-hot, クラスタリング + Gower 距離)と組み合わせ
    • 大規模・高次元 → PCA で次元削減後に DBSCAN を適用、または HDBSCAN / ハイパーパラメータ調整 を検討
  3. Step 3: 結果の解釈・共有は?
    • 専門家向け → 数値指標・統計検定で精緻に評価
    • 非専門家向け → 可視化・自然言語での要約を重視

このフローに沿って判断することで、 「DBSCAN (密度ベースクラスタリング)」を中核とした適切な手法選択ができる。

🧩 補足解説(深掘り)— 密度到達グラフ・境界点の非決定性・eps 全域スイープ

既存の各節を一切変えずに、 このページでまだ正面から扱っていない 3 つの角度を追記する。 数値はいずれも SSDSE-B-2026(2023 年・47 都道府県) の 6 変数 A1101・A1303・A4101・B4101・C5401・L3221StandardScaler で標準化した実測(pd.read_csv(encoding='cp932', skiprows=[1])df[df['SSDSE-B-2026']==2023])。 合成データは使わない。

🎨 直感 — DBSCAN は「密度到達グラフの連結成分」であり、 コア点だけが幹

DBSCAN を一言で言い直すと、 点をノード、 「コア点から ε 以内」を有向辺としたグラフの連結成分を取る操作である。 ここで決定的なのは 辺の向きが非対称な点だ。 コア点 $p$ から近傍点 $q$ へは常に辺が伸びる($q$ を $p$ のクラスタへ引き込む)が、 $q$ がコア点でなければ $q$ からは辺が出ない。 つまり コア点はクラスタを外へ伝播させる「幹」、 境界点は幹にぶら下がるだけの「葉」で、 葉から先へは密度が伝わらない。

この非対称性が DBSCAN のすべての挙動の源になっている。 (1) クラスタの骨格(コア点の集合)と、 どの点がノイズかは、 密度到達可能性だけで決まるので データの並び順に一切依存しない(2) ところが「2 つの幹の両方に葉として届く境界点」は、 どちらの幹に付くかが決まらない — ここに次の落とし穴が生まれる。

⚠️ 落とし穴(重要)— 境界点はデータの並び順で所属クラスタが変わる(非決定性)

「同じデータ・同じ ε・同じ min_samples なら DBSCAN の結果は完全に一意」と思い込むと事故る。 クラスタ数・ノイズ集合・コア集合は一意だが、 境界点の所属クラスタだけは行の並び順で変わりうる。 2 つのコア点群の両方から ε 以内に届く境界点は、 「先に処理されたコア点」の側へ吸い込まれるため、 fit に渡す行順が変われば割当も変わる(scikit-learn の実装は行順に処理する)。

📥 入力: 標準化済み X(47 県 × 6 変数)。 47 行をランダムに並べ替えて DBSCAN(eps=0.7, min_samples=4) を 1000 回実行し、 各回で コア点集合を不変アンカーにしてクラスタ名を固定し、 各県の所属を数える。

 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
31
32
33
import pandas as pd, numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import DBSCAN

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d  = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True)
cols = ['A1101','A1303','A4101','B4101','C5401','L3221']
X = StandardScaler().fit_transform(d[cols].values)
pref = d['Prefecture'].values; n = len(X)

def run(order):
    m = DBSCAN(eps=0.7, min_samples=4).fit(X[order])
    lab = np.full(n, -99); lab[order] = m.labels_
    core = np.zeros(n, bool); core[order[m.core_sample_indices_]] = True
    return lab, core

lab0, core0 = run(np.arange(n))          # 素の行順
coreidx = np.where(core0)[0]             # コア集合は並び順不変 → アンカーに使う
print('clusters=%d noise=%d core=%d border=%d' % (
    len(set(lab0[lab0>=0])), (lab0==-1).sum(), core0.sum(), ((lab0>=0)&~core0).sum()))

def cluname(lab, i):                     # クラスタを「含まれるコア点の先頭県」で命名
    if lab[i] < 0: return 'ノイズ'
    cm = sorted(set(np.where(lab==lab[i])[0]) & set(coreidx))
    return 'C[' + pref[cm[0]] + ']'

rng = np.random.RandomState(7)
for name in ['佐賀県','宮崎県','奈良県']:
    t = list(pref).index(name); cnt = {}
    for _ in range(1000):
        lab, _ = run(rng.permutation(n)); k = cluname(lab, t)
        cnt[k] = cnt.get(k, 0) + 1
    print(name, '->', cnt)

📤 実行例:

clusters=3 noise=25 core=12 border=10 佐賀県 -> {'C[石川県]': 907, 'C[長崎県]': 93} 宮崎県 -> {'C[長崎県]': 1000} 奈良県 -> {'C[石川県]': 1000}

💬 結果の読み方: eps=0.7・min_samples=4 では 3 クラスタ・ノイズ 25 県・コア 12 県・境界 10 県。 別途 300 回のシャッフルで確認すると クラスタ数(3)・ノイズ集合(25 県)・コア集合(12 県)は 1000 回すべて完全一致(不変)だった。 ところが 佐賀県だけは行順しだいで石川県クラスタ(907 回)にも長崎県クラスタ(93 回)にも割り当たる。 佐賀は両クラスタのコア点から ε 以内に届く「両属の葉」で、 先に処理された側へ吸われるからだ。 宮崎・奈良は片側のコア点にしか届かないので安定。 教訓: 境界点の所属を根拠に議論するときは、 (a) random_state や行順を固定して再現性を担保し、 (b) 境界点かどうか(core_sample_indices_ に無い割当点か)を明示し、 (c) 本質的に一意なコア骨格とノイズ判定の方を主結論に据えるのが安全。 これは k-means の初期値依存とは別種の、 DBSCAN 固有の「境界の曖昧さ」である。

🚀 発展 — eps 全域スイープ:47 県では「全ノイズ ↔ ほぼ 1 クラスタ」を数値で往復する

47 県は点数が少なく標準化空間での密度が低いため、 eps を動かすだけで結果が「全点ノイズ」から「ほぼ 1 塊」まで極端に振れる。 min_samples=4 に固定して eps を掃引した実測が下表。

1
2
3
4
5
6
7
8
9
for eps in [0.3,0.5,0.7,0.9,1.1,1.3,1.6,2.0,2.5,3.0]:
    lab = DBSCAN(eps=eps, min_samples=4).fit(X).labels_
    print('eps=%.1f clusters=%d noise=%d'
          % (eps, len(set(lab[lab>=0])), (lab==-1).sum()))

# 標準化を外すと(生の実数値のまま)
labr = DBSCAN(eps=0.7, min_samples=4).fit(d[cols].values).labels_
print('未標準化 eps=0.7 -> clusters=%d noise=%d'
      % (len(set(labr[labr>=0])), (labr==-1).sum()))

📤 実行例:

eps=0.3 clusters=0 noise=47 eps=0.5 clusters=0 noise=47 eps=0.7 clusters=3 noise=25 eps=0.9 clusters=1 noise=16 eps=1.1 clusters=1 noise=13 eps=1.3 clusters=2 noise=7 eps=1.6 clusters=1 noise=5 eps=2.0 clusters=1 noise=3 eps=3.0 clusters=1 noise=1 未標準化 eps=0.7 -> clusters=0 noise=47

💬 結果の読み方: (1) 極端な感度 — eps≤0.5 では全 47 県がノイズ(クラスタ 0 個)、 eps=3.0 では 46 県が 1 クラスタでノイズは 1 県だけ。 実用的に「意味のある構造」が見えるのは eps=0.7〜1.3 の狭い窓に限られる。 (2) 非単調 — クラスタ数は 0→3→1→1→2→1 と単調でない。 eps を広げると密なコア群が先に融合して数が減り、 さらに広げると別の疎な群がコア化して一時的に増える、 が繰り返されるためで、 「eps を上げれば必ず塊が減る」わけではない。 ただしノイズ数は 47→25→16→…→1 と 単調減少する(本ページ数式節の「ε を大きくすると noise は減少」と整合)。 (3) 標準化は必須 — 同じ eps=0.7 でも 未標準化だと全 47 県がノイズになる。 生値では A1101(総人口、 数百万オーダー)がユークリッド距離を独占し、 どの 2 県も 0.7 以内に入らないからだ。 DBSCAN は距離の絶対値を閾値 ε で切るぶん、 k-means 以上にスケールへ敏感で、 標準化を外すと結果が壊滅する。

クラスタリング(総論)
教師なしグループ化の枠組み。 DBSCAN は密度ベースの代表。
k-means法
中心ベース。 初期値依存 ↔ DBSCAN の境界非決定性を対比。
階層クラスタリング
k を後から選べる。 単連結法は密度連結と発想が近い。
標準化
未標準化だと eps=0.7 で全県ノイズ。 DBSCAN では必須前処理。
距離尺度
ε は距離の閾値。 尺度が変われば近傍の意味も変わる。
GMM(ガウス混合)
確率的ソフト割当。 DBSCAN のハードな境界と対照的。
主成分分析(PCA)
密度が低い高次元を圧縮し、 ε を効かせやすくする前処理。
次元削減
次元の呪いで距離が均される問題への対処。

※ 「シルエット係数」「HDBSCAN」「OPTICS」「異常検知」は本用語集に単独ページが未整備のため、 リンクにせず本ページ内の該当節(評価指標・派生手法・異常検知の各節)を参照。