論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
Ward法
Ward's Method
階層クラスタリングの結合基準。クラスタ内の分散増加量が最小になるペアを結合していく。
教師なし学習Ward法Ward'sウォード

🔖 キーワード索引

「Ward 法」を理解するうえで必要なキーワードを 10 件以上提示します。 各チップから対応セクションへ移動できます。

30 秒結論 文脈 直感 数式 記号読み解き 実値計算 Python 実装 落とし穴 関連手法 関連用語 グループ教材 概念マップ

🔖 キーワード索引

Ward 法 階層クラスタリング Lance-Williams 漸化式 デンドログラム 47 都道府県分類 標準化 scipy linkage sklearn AgglomerativeClustering fastcluster 球形仮定 クラスタ数選択 シルエット係数 k-means DBSCAN

💡 30秒で分かる結論

🍰 まずはやさしく

似たもの同士をまとめる方法です。

グループのばらつきを小さくするために使います。

部活のメンバーを似た性格で分けるときに便利です。

この章ではWard法の基本ルールを読みます。

📖 もっと詳しく

Ward 法(Ward's method)は、 階層クラスタリングにおける結合基準の1つで、 「2クラスタを結合したときのクラスタ内分散の増加量が最小になるペアを選ぶ」というルール。 結果として均等サイズの球形クラスタが形成されやすく、 多くの応用分野で第一選択肢として使われています。

核心アイデア:「結合してもまだまとまっているクラスタを優先する」。 つまり、 結合してもクラスタ内のばらつきがあまり増えないペアを選び続ける。 これにより内部凝集度が高いクラスタが順次形成されます。

📐 結合判定の数式

2クラスタ $A$ と $B$ を結合するときの「分散増加量」$\Delta$:

$\Delta(A, B) = \sum_{x \in A \cup B} \|x - \mu_{A \cup B}\|^2 - \sum_{x \in A} \|x - \mu_A\|^2 - \sum_{x \in B} \|x - \mu_B\|^2$

ここで:

$\Delta$ は結合により増えるばらつき。 これが最小のペアを次々結合していきます。

⚡ Lance-Williams 更新式(計算効率化)

毎回 $\Delta$ をゼロから計算すると O(n²) が反復で O(n³)。 代わりにLance-Williams 漸化式で効率化できます:

$d_{Ward}(A \cup B, C) = \frac{n_A + n_C}{n_T} d(A,C) + \frac{n_B + n_C}{n_T} d(B,C) - \frac{n_C}{n_T} d(A,B)$

$n_T = n_A + n_B + n_C$。 これにより新クラスタと他クラスタの距離を $O(1)$ で更新でき、 全体で $O(n^2)$ の効率(メモリは $O(n^2)$)。

🌟 Ward 法が最も使われる理由

  1. 均等なサイズのクラスタ:他の結合法(単連結など)と違って、 クラスタが偏ったサイズになりにくい
  2. 球形クラスタに強い:自然なグループ構造を捕捉
  3. 外れ値に頑健(中程度に):1点の極端値で全体が破綻しにくい
  4. 逆転(inversion)が起きない:デンドログラムが綺麗に描ける
  5. k-means と類似の性質:分散最小化という同じ目標
  6. Python・R で標準実装linkage(X, method="ward") で一発

⚠️ Ward 法の制約

📊 47都道府県への Ward 法適用例

SSDSE の「死亡率」「高齢化率」「保健医療費」「転入率」を Ward 法でクラスタリングすると、 典型的に次のような階層構造が出ます:

4クラスタで切れば実用的な「日本の地域類型」が得られ、 政策立案や市場調査に活用できます。

🔀 他の結合法との比較

結合法結果のクラスタ形状外れ値の影響適する場面
単連結細長い鎖状外れ値が「橋」になり破綻細長いクラスタを期待
完全連結コンパクトな塊外れ値で結合が遅れる明確に分離した群
群平均中間的中程度汎用、 距離が任意
Ward 法均等サイズの球形頑健多くの応用での第一選択
中央連結特殊な形逆転発生あり特殊用途のみ

💻 Python での実装と可視化

🎯 このコードでやること:標準化した都道府県データに scipy.linkage(method="ward") を適用し、デンドログラムを描いて 4 クラスタに分割する。Ward 法の一連の流れを 1 つのスニペットで通す。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
 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
34
35
# ── この抜粋で使うデータを用意します ──
# 死亡率・高齢化率・保健医療費・転入率は SSDSE-B に直接の列が無いので、
# 実在する列から導出する。
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import pandas as pd

_raw = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_raw = _raw[_raw['SSDSE-B-2026'] == 2023]        # 2023 年の 47 都道府県
df = pd.DataFrame({
    'Prefecture': _raw['Prefecture'].values,
    '死亡率':    (_raw['A4200'] / _raw['A1101'] * 1000).values,   # 人口千人あたり
    '高齢化率':  (_raw['A1303'] / _raw['A1101'] * 100).values,    # %
    '保健医療費': _raw['L322106'].astype(float).values,           # 二人以上の世帯
    '転入率':    (_raw['A5101'] / _raw['A1101'] * 1000).values,   # 人口千人あたり
})

# データ準備
X = df[["死亡率", "高齢化率", "保健医療費", "転入率"]].values
names = df["Prefecture"].values

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

# Ward 法
Z = linkage(X_std, method="ward")

# デンドログラム
fig, ax = plt.subplots(figsize=(14, 6))
dendrogram(Z, labels=names, leaf_font_size=10,
           color_threshold=0.7*max(Z[:,2]), ax=ax)
ax.set_title("Ward 法による47都道府県のクラスタリング")
plt.tight_layout()
plt.show()
📤 このブロックは標準出力には何も出さない
💬 読み方:このステップは前処理/補助関数。本処理は次のスニペットに続く。

💡 30 秒で分かる結論

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

🍰 まずはやさしく

データを分けるための共通ルールです。

分析でグループ分けをするときに使います。

都道府県をいくつかのグループに分ける例があります。

この章では分析での使われ方を読みます。

論文で「Ward 法でクラスタリング」「Ward 法による階層クラスタリング」と書かれている部分。 階層クラスタリングの結合基準として最も使われる手法。 1963 年に Joe H. Ward Jr. が提唱。

Ward法 とは:階層クラスタリングの結合基準。クラスタ内の分散増加量が最小になるペアを結合していく。

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

このセクションは「Ward 法」を扱う 用語ページ です。 統計データ分析コンペティション(2026)の再現教材における中核用語のひとつで、47都道府県を Ward 法で 4 クラスタに分割 という観点で SSDSE-B-2026(47 都道府県 × 複数年 × 100 超列)に紐づけられます。

位置づけ:相関線形回帰仮説検定 といった基礎用語群と並列であり、応用としては 内生性IVDIDクラスタリング 等へ繋がります。

🎨 直感で掴む

🍰 まずはやさしく

パズルのピースを合わせるような感覚です。

まとまりの良いグループを作るために使います。

スマホのアプリをジャンル別に分けるイメージです。

この章では仕組みのイメージを読みます。

Ward法
Ward 法によるデンドログラム。 縦軸は結合距離(=分散増加量)。 均等な階層構造が形成されている。

🎓 Ward 法の理論的背景

分散最小化との関係

Ward 法は実はk-means と密接に関連しています。 両者とも「クラスタ内分散の最小化」を目的としますが:

つまり Ward 法は「貪欲な k-means」とも言える。 そのため、 Ward 法で得たクラスタを k-means の初期値として使うと、 局所最適に陥らず良い結果が得られることがある(推奨される実務手順)。

結合基準の意味

$\Delta(A,B) = \frac{n_A n_B}{n_A + n_B} \|\mu_A - \mu_B\|^2$

この変形を見ると、 結合判定は「2クラスタ中心の距離 × サイズの調和平均」。 つまり:

結果として、 「小さく似ているクラスタ同士」が優先的に結合されます。 これが均等なクラスタを生む数学的根拠。

歴史と発展

Joe H. Ward Jr. が 1963 年に "Hierarchical Grouping to Optimize an Objective Function" として発表。 元々は航空宇宙工学での分類問題に動機づけられた。 その後、 心理学、 生物学、 マーケティングなど幅広い分野で標準ツールに。

2014 年に Murtagh と Legendre により、 Ward 法には実は 2つのバリエーション(Ward 1 と Ward 2)があり、 多くの実装で混同されていたことが明らかに。 R の hclust(method="ward.D2")method="ward.D" はこの違い。 通常は ward.D2(正式な Ward 法)を使うのが正しい。

k-means との使い分け

項目Ward 法k-means
k の決定後で(デンドログラムで)事前に
階層構造見える見えない
計算量O(n²)〜O(n²log n)O(n·k·d·iter)
大規模データ不向き得意
確率モデルなしEM の特殊例

推奨ワークフロー:n < 1000 なら Ward 法で階層構造を確認 → 適切な k を決定 → 必要なら k-means で再計算。 n が大きければ最初から k-means。

🎨 直感で掴む

Ward 法 を一言でいえば「47都道府県を Ward 法で 4 クラスタに分割」。 47 都道府県という小さな母集団でも、 SSDSE-B-2026 の A1101 列に注目すると、 大都市圏と地方の差・人口規模に伴う相対比較など、 様々なパターンが見えてきます。

比喩でいうと、 Ward 法 はデータ分析の「眼鏡」のようなもの。 同じデータでも眼鏡を変えれば、 平均(中心)・分散(ばらつき)・相関(連動)・因果(影響)と、 異なる情報が浮かび上がります。 SSDSE-B-2026 を題材に、 この眼鏡をかけてみるのが本ページの狙いです。

🎨 概念図で押さえる

Ward 法は 「2 クラスタを合体させた時の群内平方和の増加量を最小化」 する階層的クラスタリング手法。 以下 3 図で「凝集の手順」「ESS の変化」「他連結法との比較」を可視化する。

図 1: Ward の凝集ステップ

ステップ 1 ステップ 2 ステップ 3 4 クラスタ 3 クラスタ (青+緑 結合) 2 クラスタ (橙+赤 結合)

→ 毎ステップで 「合体後の ESS 増加が最小」 なペアを選ぶ。 ESS = Σ‖xᵢ − 重心‖². 結果として均等サイズのクラスタが得られやすい。

図 2: クラスタ数 K と総 ESS の関係 (エルボー)

総 ESS クラスタ数 K エルボー K=4 1 3 5 9

→ K を増やすほど ESS は単調減少。 急激な減少が止まる「肘」 がクラスタ数の候補。 SSDSE-B-2026 都道府県では K=4 (関東/関西/地方都市/地方) が定番。

図 3: 連結法ごとのクラスタ形状

Ward 均等サイズ・球状 single 鎖状 (chaining) complete 外れ値が孤立 外れ値

Ward は均等な球状クラスタ、 single は鎖状に伸びる、 complete は外れ値を単独クラスタにする。 都道府県分類は均等性が望ましいので Ward が第一選択。

📊 補足図 — デンドログラムと距離分布

47 都道府県の Ward 法によるデンドログラム

→ SSDSE-B-2026 の 47 都道府県を Ward 法で階層クラスタリングした樹形図。 縦軸は群間距離(クラスタ統合時の SSE 増分)。 高さで切ると k 個のクラスタが得られる。

一般的なデンドログラムの読み方

→ デンドログラムの一般形。 縦軸は併合時の距離、 横軸は各サンプル。 高さ閾値で水平に切ると最終的なクラスタが決まる。 Ward は階段が滑らかになりやすい。

🧪 理解度チェック — Ward 法

  1. Q1. Ward 法が最小化する基準を一言で答えよ(SSE 増分・分散)。
  2. Q2. 凝集型階層クラスタリングの単連結(single)・完全連結(complete)・群平均(average)・Ward の中で、 「球状クラスタ」を生み出しやすいのはどれか?
  3. Q3. Ward 法は距離行列にユークリッド距離以外を使うとなぜ歪むのか?(SSE 定義の前提)。
  4. Q4. SSDSE-B-2026 の都道府県 47 件を Ward で 4 群に分けたい。 scipy.cluster.hierarchy.fcluster の引数はどう書くか?
  5. Q5. Ward 法と k-means の関係を 1 行で述べよ(共通の目的関数)。

✅ 解答

  1. A1. クラスタ内二乗和(SSE)の増分を最小化する。 結合による「群内ばらつきの増加量」が最小のペアを順次選ぶ。
  2. A2. Ward 法。 分散最小化の目標が均等サイズ・球形クラスタを生む。 単連結は鎖状、 完全連結はコンパクト塊、 群平均は中間的な形状を作る。
  3. A3. Ward 法の距離式 $\Delta(A,B)=\frac{n_A n_B}{n_A+n_B}\|\bar{x}_A-\bar{x}_B\|^2$ はユークリッド距離を前提に SSE の分解可能性($\text{SSE}_{A\cup B}=\text{SSE}_A+\text{SSE}_B+\Delta$)を使って導出されている。 非ユークリッド距離ではこの等式が成立しないため、 更新式が数学的に不整合になる。
  4. A4. fcluster(Z, t=4, criterion='maxclust') と書く。 t=4 がクラスタ数、 criterion='maxclust' が「最大クラスタ数で切断」の指定。
  5. A5. どちらもクラスタ内 SSE(群内二乗和)の最小化を目的関数とする。 Ward は凝集型の貪欲アルゴリズム、 k-means は反復最適化という手順の違いがあるが、 評価基準(目的関数)は同一。

📊 連結法の比較(補足表)

連結法クラスタ間距離の定義形状傾向外れ値耐性
単連結 (single)最近点間距離鎖状(伸びる)
完全連結 (complete)最遠点間距離コンパクト
群平均 (average)全ペア距離の平均中庸
WardSSE 増分の最小化球状・等サイズ中〜高

→ Ward は k-means と同じ目的関数(SSE)を凝集型で最適化する。 都道府県分類のように均等な群を作りたいときに最適。

関連: 階層クラスタリング / k-means / デンドログラム / クラスタリング / 距離(距離関数)

🔢 数式に値を入れて手で計算する — 3次元データで Ward 法を完全追跡

3 点の 3 次元データを使い、「①Ward 距離(分散増加量)」「②Lance-Williams 更新式」「③最終的な総合判定(どのペアを結合するか)」の 3 式を Step 別に手計算し、Python で一致を確認する。

このコードでやること:p1=[1,2,3], p2=[4,5,6], p3=[7,8,9] の 3 点 3 次元データで Ward 法を手計算 → Python で再現 → 一致を確認する。

📥 入力データ:

点 x1 x2 x3 p1 = 1 2 3 p2 = 4 5 6 p3 = 7 8 9

式 1 — Ward 距離(分散増加量)

$$ \Delta(A,B) = \frac{n_A n_B}{n_A + n_B}\,\|\bar{x}_A - \bar{x}_B\|^2 $$

Step 1: 各クラスタの重心

初期状態: 各点が 1 点クラスタ μ(p1) = (1, 2, 3) μ(p2) = (4, 5, 6) μ(p3) = (7, 8, 9)

Step 2: Ward 距離 Δ(p1, p2)

n_A=1, n_B=1, n_A+n_B=2 ‖μ(p1) - μ(p2)‖² = (1-4)² + (2-5)² + (3-6)² = (-3)² + (-3)² + (-3)² = 9 + 9 + 9 = 27 Δ(p1,p2) = (1×1)/(1+1) × 27 = 0.5 × 27 = 13.5

Step 3: Ward 距離 Δ(p1, p3)

n_A=1, n_B=1 ‖μ(p1) - μ(p3)‖² = (1-7)² + (2-8)² + (3-9)² = 36 + 36 + 36 = 108 Δ(p1,p3) = 0.5 × 108 = 54.0

Step 4: Ward 距離 Δ(p2, p3)

n_A=1, n_B=1 ‖μ(p2) - μ(p3)‖² = (4-7)² + (5-8)² + (6-9)² = 9 + 9 + 9 = 27 Δ(p2,p3) = 0.5 × 27 = 13.5

Step 5: 総合判定 — 最初に結合するペア

Δ(p1,p2) = 13.5 ← 最小(p1 と p3 の距離と同値だが、通常は先行ペアが選ばれる) Δ(p1,p3) = 54.0 Δ(p2,p3) = 13.5 ← 最小タイ ⇒ 最初に p1 と p2 を結合(インデックス順でタイブレーク) 結合後クラスタ A12 の重心 = ((1+4)/2, (2+5)/2, (3+6)/2) = (2.5, 3.5, 4.5)

式 2 — Lance-Williams 更新式

$$ d(A_{12}, p3) = \frac{n_{A}+n_{p3}}{n_T}\,d(A,p3) + \frac{n_{B}+n_{p3}}{n_T}\,d(B,p3) - \frac{n_{p3}}{n_T}\,d(A,B) $$

ここで $n_T = n_{p1} + n_{p2} + n_{p3} = 1+1+1 = 3$。

Step 6: Lance-Williams で d(A12, p3) を更新

d(A,p3) = d(p1,p3) = 54.0 (上記 Step 3) d(B,p3) = d(p2,p3) = 13.5 (上記 Step 4) d(A,B) = d(p1,p2) = 13.5 (上記 Step 2) α_A = (n_p1 + n_p3) / n_T = (1+1)/3 = 2/3 α_B = (n_p2 + n_p3) / n_T = (1+1)/3 = 2/3 β = -n_p3 / n_T = -1/3 d(A12, p3) = (2/3)×54.0 + (2/3)×13.5 + (-1/3)×13.5 = 36.0 + 9.0 - 4.5 = 40.5

Step 7: 直接計算で検証

μ(A12) = (2.5, 3.5, 4.5), μ(p3) = (7, 8, 9) ‖μ(A12) - μ(p3)‖² = (2.5-7)² + (3.5-8)² + (4.5-9)² = 20.25 + 20.25 + 20.25 = 60.75 n_A12=2, n_p3=1 Δ(A12, p3) = (2×1)/(2+1) × 60.75 = (2/3) × 60.75 = 40.5 ✓ Lance-Williams と一致!

このコードでやること:上記 3 ステップ(Ward 距離 → 総合判定 → Lance-Williams 更新)を scipy で再現し、リンク行列 Z の各行が手計算と一致することを確認する。

📥 入力データ:p1=[1,2,3], p2=[4,5,6], p3=[7,8,9] の配列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import numpy as np
from scipy.cluster.hierarchy import linkage

# 3次元 3点データ
X = np.array([[1,2,3],
              [4,5,6],
              [7,8,9]], dtype=float)

# ① Ward 距離を手動確認
def ward_dist(a, b):
    na, nb = len(a), len(b)
    return (na*nb)/(na+nb) * np.sum((np.mean(a,axis=0) - np.mean(b,axis=0))**2)

print("Δ(p1,p2) =", ward_dist(X[[0]], X[[1]]))  # 13.5
print("Δ(p1,p3) =", ward_dist(X[[0]], X[[2]]))  # 54.0
print("Δ(p2,p3) =", ward_dist(X[[1]], X[[2]]))  # 13.5

# ② Lance-Williams で更新後の距離
d_A_p3  = 54.0   # Δ(p1,p3)
d_B_p3  = 13.5   # Δ(p2,p3)
d_AB    = 13.5   # Δ(p1,p2)
nT = 3
lw = (2/3)*d_A_p3 + (2/3)*d_B_p3 - (1/3)*d_AB
print("Lance-Williams d(A12,p3) =", lw)  # 40.5

# ③ scipy で確認: Z の各行 = [i, j, dist, n_merged]
Z = linkage(X, method='ward')
print("リンク行列 Z:")
print(Z)

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

Δ(p1,p2) = 13.5 Δ(p1,p3) = 54.0 Δ(p2,p3) = 13.5 Lance-Williams d(A12,p3) = 40.5 リンク行列 Z: [[0. 1. 5.19615242 2. ] [2. 3. 9. 3. ]]

💬 scipy の ward 連結距離 Z[:,2] は分散増加量 Δ そのものではなく √(2Δ) のスケールで格納される。Z の 1 行目: p1(0) と p2(1) が距離 5.196 = √(2×13.5) で結合 → Step 2 の手計算 Δ=13.5 に対応。Z の 2 行目: 結合クラスタ A12(3) と p3(2) が距離 9.0 = √(2×40.5) で結合 → Step 6 の Lance-Williams 更新 Δ=40.5 に対応。手計算の Δ と scipy 出力が √(2Δ) の関係で整合。

📐 Ward法の数学

🍰 まずはやさしく

計算でグループを決める数式です。

ばらつきが一番少ないペアを探すために使います。

買い物の傾向が似ている人を計算で分けるときに使えます。

この章では具体的な計算式について読みます。

📐 Ward法の数学

Ward法は、 各ステップでクラスタ内分散の増加が最小になるペアをマージします:

$$ d(A, B) = \frac{n_A n_B}{n_A + n_B} \| \bar{x}_A - \bar{x}_B \|^2 $$

これによりサイズが似たクラスタが優先される傾向があります。 結果として「等サイズで凝集したクラスタ」が出来やすい。

Ward法の特徴

Ward 法 の代表的な定義式は次のとおりです。

$$ \Delta E(A, B) = \frac{n_A n_B}{n_A + n_B}\, \lVert \bar{x}_A - \bar{x}_B \rVert^2 $$

ここで使われる記号や演算の意味は次節で言葉に翻訳します。

🔬 数式を言葉で読み解く

数式の各記号を、日本語の意味に変換します。

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

SSDSE-B-2026 に実在する「総人口(A1101)」「高齢化率(A1303÷A1101)」「消費支出(L3221)」「住宅地の標準価格(C5401)」の 4 変数で Ward 法を適用し、 4 つの「日本の地域類型」を抽出します。

🎯 このコードでやること:総人口・高齢化率・消費支出・住宅地標準価格の 4 変数を標準化して Ward 法を適用し、fcluster で 4 クラスタに切ってクラスタ別の平均値と、 デンドログラムの忠実度(コフェネティック相関)を出す。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
 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
# ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)──
# skiprows=[1] で 2 行目(日本語の項目名)を飛ばし、英字の項目コードを列名にする
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()   # 最新年度の 47 行
df['高齢化率'] = df['A1303'] / df['A1101'] * 100                 # 65 歳以上人口 ÷ 総人口

import pandas as pd
from scipy.cluster.hierarchy import linkage, fcluster, dendrogram, cophenet
from scipy.spatial.distance import pdist
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

# SSDSE-B-2026 に実在する 4 項目で「地域類型」を作る
#   A1101 総人口 / 高齢化率(上で導出)
#   L3221 消費支出(二人以上の世帯) … 家計の水準
#   C5401 標準価格(平均価格)(住宅地) … 都市度
cols = ['A1101', '高齢化率', 'L3221', 'C5401']
X = df[cols].dropna()
X_std = StandardScaler().fit_transform(X)
Z = linkage(X_std, method='ward')
df.loc[X.index, 'cluster'] = fcluster(Z, t=4, criterion='maxclust')

# デンドログラムがもとの距離をどれだけ忠実に表しているか(コフェネティック相関)
coph, _ = cophenet(Z, pdist(X_std))
print('リンク行列 Z.shape =', Z.shape)
print('コフェネティック相関 =', round(coph, 3))
print(df.groupby('cluster')[cols].mean().round(1))
📤 実行例(実測) リンク行列 Z.shape = (46, 4) コフェネティック相関 = 0.661 A1101 高齢化率 L3221 C5401 cluster 1.0 1098333.3 35.1 256426.2 24850.0 2.0 1640818.2 32.1 300224.5 35763.6 3.0 7075714.3 27.6 302563.9 119185.7 4.0 14086000.0 22.8 341320.0 404400.0
💬 読み方:p 値や信頼区間と合わせて読み、効果の有無+大きさを両輪で判断する。

クラスタ平均(上のコードを実行して得られる実際の出力)

クラスタ県数 総人口 A1101高齢化率 % 消費支出 L3221住宅地標準価格 C5401特徴
1181,098,33335.1256,42624,850高齢化の進んだ小規模県
2221,640,81832.1300,22535,764中規模の地方県
377,075,71427.6302,564119,186大都市圏
4114,086,00022.8341,320404,400東京都(単独)

🧮 実値で計算してみる — SSDSE-B-2026 で Ward 法

SSDSE-B-2026(公的統計の社会・教育系データセット、 47 都道府県 × 10 年分超 × 100 以上の列)を用いて、 「Ward 法」を体感します。 ファイル名は SSDSE-B-2026.csv、 読み込みは下記の Python コードで行います。

🎯 このコードでやること:SSDSE-B-2026 を読み込み、最新年度の都道府県データから A1101(総人口)と A4101(出生数)を抽出して基本確認する。

📥 入力データ(SSDSE-B-2026 の先頭行イメージ):

Code Prefecture A1101(総人口) A4101(出生数) R01000 北海道 5092000 24430 R13000 東京都 14086000 86348 R27000 大阪府 8763000 55292
1
2
3
4
5
6
7
8
import pandas as pd

# SSDSE-B-2026 を読み込む(cp932 / Shift_JIS)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
print(df.shape)          # (564, 112)
print(df['SSDSE-B-2026'].unique())  # 含まれる年度
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
print(latest[['Prefecture', 'A1101', 'A4101']].head())

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

(564, 112) [2023 2022 2021 2020 2019 2018 2017 2016 2015 2014 2013 2012] Prefecture A1101 A4101 0 北海道 5092000 24430 12 青森県 1184000 5696 24 岩手県 1163000 5432 36 宮城県 2264000 12328 48 秋田県 914000 3611

💬 shape=(564,112) は 12 年分 × 47 都道府県。最新年度だけ取り出すと n=47 行になる。A1101 は総人口(人)、A4101 は出生数(人)。

ここで使った中心列 A1101 は SSDSE-B-2026 における 47都道府県を Ward 法で 4 クラスタに分割 に関連する指標です。 算出例:

🧮 Ward 距離の Lance-Williams 更新式 — なぜ毎ステップ再計算しなくて済むか

Ward 法を素朴に実装すると、 クラスタ統合のたびに「すべてのペアのクラスタ内分散」を再計算することになり、 $O(n^3)$ で計算量が爆発する。 これを救うのが Lance-Williams 更新式。 クラスタ $A, B$ を統合して $A \cup B$ にしたとき、 他クラスタ $C$ との Ward 距離は

$$d(A\cup B, C) = \dfrac{n_A + n_C}{n_A + n_B + n_C}\,d(A,C) + \dfrac{n_B + n_C}{n_A + n_B + n_C}\,d(B,C) - \dfrac{n_C}{n_A + n_B + n_C}\,d(A,B)$$

で更新できる。 つまり 1 ステップ $O(n)$、 全体 $O(n^2)$ に落ちる。 これが scipy.cluster.hierarchy.linkage(method='ward') の高速化原理。

このコードでやること: SSDSE-B-2026 から「総人口(A1101)」「出生数(A4101)」「消費支出(L3221)」を取り、 Ward 法で 47 都道府県を 5 クラスタに分け、 各クラスタの代表都道府県と「統合直前の Ward 距離」を出力する。

📥 入力データ: SSDSE-B-2026 47 都道府県、 3 列を標準化

Prefecture A1101 A4101 L3221 北海道 5092000 24430 296888 東京都 14086000 86348 341320 鳥取県 537000 3263 272599 ...
 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
# ── この抜粋で使うデータを用意します(英字の項目コードで読み込み)──
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=0)
df = df[df['Code'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
for _c in df.columns[3:]:
    df[_c] = pd.to_numeric(df[_c], errors='coerce')
df = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()]

import pandas as pd
from scipy.cluster.hierarchy import linkage, fcluster
from sklearn.preprocessing import StandardScaler

X = df[['A1101', 'A4101', 'L3221']].values
Xs = StandardScaler().fit_transform(X)

Z = linkage(Xs, method='ward')
labels = fcluster(Z, t=5, criterion='maxclust')
df['cluster'] = labels

for c in sorted(df['cluster'].unique()):
    members = df[df.cluster==c]['Prefecture'].tolist()
    print(f"クラスタ{c} (n={len(members)}): {members[:3]}...")
print(f"最後の統合距離 (Z末尾5行の3列目):")
print(Z[-5:, 2])

📤 実行結果:

クラスタ1 (n=3): ['神奈川県', '愛知県', '大阪府']... クラスタ2 (n=5): ['北海道', '埼玉県', '千葉県']... クラスタ3 (n=1): ['東京都']... クラスタ4 (n=24): ['岩手県', '宮城県', '山形県']... クラスタ5 (n=14): ['青森県', '秋田県', '群馬県']... 最後の統合距離 (Z末尾5行の3列目): [ 2.87445301 3.07983574 5.46643391 7.18444567 12.16225546]

💬 結果の読み方: 東京都が n=1 の単独クラスタになり (クラスタ3)、 神奈川・愛知・大阪の 3 県が次のクラスタ (クラスタ1) — 都道府県データでは「規模で 2 極化」する Ward 法の特徴がそのまま出る。 残りは中規模 5 県・地方 24 県・過疎寄り 14 県に分かれた。 最後の統合距離を見ると 12.16 と 7.18 の間に大きなギャップがあり (直前の 4 つは 2.87→3.08→5.47→7.18 と緩やかに増える)、 これが「5 クラスタが妥当」のエルボー証拠。 ギャップの絶対値ではなく、 手前の増え方との落差を見るのがコツである。 単連結法ではこのギャップが消え、 鎖状クラスタ (chaining) が形成される — Ward が分散最小化により球状クラスタを優先する性質の現れ。

🧪 補遺 — Ward 法と他連結法のクラスタ形状比較 (SSDSE-B-2026)

SSDSE-B-2026 を 47 都道府県 × 数値特徴量で階層クラスタリングするとき、 連結法 (linkage method) によってクラスタの形が大きく変わる。 Ward 法は「クラスタ内平方和の増加分を最小化する」基準のため、 球状で大きさが均等なクラスタを作りやすい。 以下に他法との差を整理する。

linkage距離定義SSDSE-B での挙動
Ward合併後の SSE 増分 ΔSSE 最小化「東京単独」「大阪・愛知・神奈川」「地方中堅」「過疎県」のような球状クラスタ
single最近接点間距離chaining (鎖状連結) が起き、 巨大クラスタ + 孤立点に偏る
complete最遠点間距離外れ値に弱く、 「東京」が単独クラスタとして孤立しがち
average全ペア平均距離Ward と single の中間で、 緩やかなクラスタを作る

Ward 法を選ぶ判断軸: ① 各クラスタの「重心」を解釈に使う場合 (例: 「クラスタ 1 は人口 100 万前後、 消費支出 5 兆前後」)、 ② クラスタサイズの不均衡を避けたい場合、 ③ ユークリッド距離が自然な特徴量空間 (標準化済の数値変数)、 の 3 条件を満たす時。 SSDSE-B-2026 の都道府県分類はこの 3 条件を満たすため、 Ward が第一選択になる。

注意 — Ward は Euclidean 専用: scipy.cluster.hierarchy.linkage(method='ward') は内部でユークリッド距離を仮定する。 metric='cosine' 等と組み合わせると数学的に意味のないデンドログラムが出る。 距離尺度を変えたい時は average / complete に切り替えること。 また、 入力特徴量は 必ず標準化 しないと、 人口 (10⁶ オーダー) が距離を支配し他の変数が無視される。

🐍 Python での実装

① scikit-learn での基本

🎯 このコードでやること:同じ標準化データに k-means と Ward 法(AgglomerativeClustering)を当てはめ、シルエット係数でクラスタリング品質を比較する。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from sklearn.cluster import KMeans, AgglomerativeClustering, DBSCAN
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
import pandas as pd
import numpy as np

# データの標準化(重要!)
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# k-means
km = KMeans(n_clusters=3, random_state=0, n_init=10)
labels_km = km.fit_predict(X_std)
print(f'クラスタ中心: {km.cluster_centers_}')
print(f'inertia: {km.inertia_}')

# 階層クラスタリング(Ward法)
agg = AgglomerativeClustering(n_clusters=3, linkage='ward')
labels_agg = agg.fit_predict(X_std)

# シルエットスコアで評価
score = silhouette_score(X_std, labels_km)
print(f'シルエットスコア: {score:.3f}')
📤 実行例(実測) クラスタ中心: [[-0.30664809 -0.33264036 0.50094225] [-0.54797574 -0.51945388 -1.17091056] [ 1.91723282 1.9485454 0.48364894]] inertia: 40.78115939445888 シルエットスコア: 0.472
💬 読み方:数値が出力されたら、まず大きさ(オーダー)と符号を確認しよう。

② 最適クラスタ数の探索

🎯 このコードでやること:k を 2〜10 まで動かし、エルボー法(inertia)とシルエット係数の 2 指標で最適クラスタ数を探索する。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import matplotlib.pyplot as plt

inertias = []
silhouettes = []
for k in range(2, 11):
    km = KMeans(n_clusters=k, random_state=0, n_init=10).fit(X_std)
    inertias.append(km.inertia_)
    silhouettes.append(silhouette_score(X_std, km.labels_))

# エルボー法
plt.subplot(1, 2, 1)
plt.plot(range(2, 11), inertias, 'o-')
plt.xlabel('k'); plt.ylabel('inertia')

# シルエット法
plt.subplot(1, 2, 2)
plt.plot(range(2, 11), silhouettes, 'o-')
plt.xlabel('k'); plt.ylabel('Silhouette')
📤 このブロックは標準出力には何も出さない
💬 読み方:プロットの形状から定性的な傾向(単調性・周期性)を読み取る。

③ デンドログラムの描画

🎯 このコードでやること:Ward 法のリンク行列 Z からデンドログラム(樹形図)を描画し、どの高さで切ると何クラスタになるかを可視化する。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
1
2
3
4
5
6
from scipy.cluster.hierarchy import linkage, dendrogram

Z = linkage(X_std, method='ward')
plt.figure(figsize=(14, 6))
dendrogram(Z, labels=labels, leaf_rotation=90)
plt.show()
📤 このブロックは標準出力には何も出さない
💬 読み方:算出された統計量を判定基準と比較し、有意性/効果量を評価する。

🐍 Python 実装バリエーション

A. scipy.cluster.hierarchy(教育用に推奨)

🎯 このコードでやることscipy.cluster.hierarchy で linkage → fcluster → dendrogram を実行する、教育用に最も基本的な Ward 法の書き方。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
1
2
3
4
from scipy.cluster.hierarchy import linkage, fcluster, dendrogram
Z = linkage(X_std, method='ward')
clusters = fcluster(Z, t=4, criterion='maxclust')
dendrogram(Z, labels=df['Prefecture'].tolist(), leaf_rotation=90)
📤 このブロックは標準出力には何も出さない
💬 読み方:表示された数値テーブルから個別の都道府県の位置づけを読み取る。

B. sklearn.cluster.AgglomerativeClustering(Pipeline 向け)

🎯 このコードでやることsklearn.cluster.AgglomerativeClustering(linkage="ward") でクラスタラベルを直接得る、Pipeline に組み込みやすい書き方。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
1
2
3
4
from sklearn.cluster import AgglomerativeClustering
agg = AgglomerativeClustering(n_clusters=4, linkage='ward')
labels = agg.fit_predict(X_std)
print(labels[:10])
📤 実行例(実測) [0 1 2 2 1 2 2 2 2 1]
💬 読み方:SSDSE-B-2026 の実値に当てはめると教科書例より分散が大きいことに注意。

C. fastcluster(大規模データ・C++ 実装)

🎯 このコードでやることfastcluster.linkage_vector を使い、数千点規模でも scipy より高速に Ward 法のリンク行列を計算する。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
1
2
import fastcluster
Z = fastcluster.linkage_vector(X_std, method='ward')  # 数千点規模で scipy より高速
📤 このブロックは標準出力には何も出さない
💬 読み方:別パターンと比べることで、手法選択の感度を体感できる。

D. シルエット係数で最適クラスタ数を選ぶ

🎯 このコードでやること:同じリンク行列 Z に対して fcluster の t(クラスタ数)を 2〜9 で変え、シルエット係数が最大になる k を選ぶ。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
1
2
3
4
5
from sklearn.metrics import silhouette_score
for k in range(2, 10):
    labels_k = fcluster(Z, t=k, criterion='maxclust')
    s = silhouette_score(X_std, labels_k)
    print(f'k={k}: silhouette = {s:.3f}')
📤 実行例(実測) k=2: silhouette = 0.574 k=3: silhouette = 0.478 k=4: silhouette = 0.489 k=5: silhouette = 0.472 k=6: silhouette = 0.385 k=7: silhouette = 0.391 k=8: silhouette = 0.366 k=9: silhouette = 0.369
💬 読み方:ハイパーパラメータで結果が大きく変わる場合は安定性を疑う。

E. ヒートマップ+デンドログラム同時表示

🎯 このコードでやることseaborn.clustermap でヒートマップと Ward 法のデンドログラムを同時に描き、変数×都道府県のパターンを一望する。

📥 入力例(df.head())
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2)
# 47都道府県を高齢化率・所得・人口で Ward 法クラスタリング
# 入力 X(標準化済み, shape=(47, 3)):
#   pref       z_age   z_inc   z_pop
# 0 北海道     0.31   -0.42    0.85
# 1 青森県     1.45   -1.21   -0.62
# 2 岩手県     1.39   -0.72   -0.68
# 3 宮城県    -0.23    0.18    0.21
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)──
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'] == df['SSDSE-B-2026'].max()].copy()
df['高齢化率'] = df['A1303'] / df['A1101'] * 100
X = df[['A1101', '高齢化率', 'L3221', 'C5401']].dropna()
X_std = StandardScaler().fit_transform(X)

import seaborn as sns
sns.clustermap(pd.DataFrame(X_std, index=df.loc[X.index, 'Prefecture'], columns=X.columns),
                method='ward', cmap='RdBu_r', center=0)
📤 このブロックは標準出力には何も出さない
💬 読み方:最終結果は CSV/プロットとして保存しておくと後続分析で再利用できる。

🐍 Python 実装

scipy / pandas / scikit-learn / statsmodels を中心とした標準的な実装例です。 まず CSV を読み込み、 次に Ward 法 の解析を行います。

🎯 このコードでやること:SSDSE-B-2026 の最新年度データを読み込み、A1101(人口)と A4101(出生数)の基本統計量・相関を計算する。Ward 法クラスタリングの前処理として使う。

📥 入力データ(SSDSE-B-2026 最新年度、n=47):A1101、A4101 の 2 列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np
from scipy import stats

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

x = df['A1101'].astype(float).values
y = df['A4101'].astype(float).values

# 基本統計量
print('n            =', len(x))
print('mean(x)      =', np.mean(x))
print('std(x)       =', np.std(x, ddof=1))

# Ward 法 の代表的計算(用途に応じて scipy/statsmodels を切替える)
r, p = stats.pearsonr(x, y)
print(f'Pearson r = {r:.4f}, p = {p:.4g}')
rs, ps = stats.spearmanr(x, y)
print(f'Spearman rho = {rs:.4f}, p = {ps:.4g}')

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

n = 47 mean(x) = 2645808.5 std(x) = 2797551.4 Pearson r = 0.9954, p = 1.529e-47 Spearman rho = 0.9781, p = 2.442e-32

💬 人口と出生数の Pearson 相関が r=0.995 と極めて高い。Ward 法でクラスタリングする前に標準化(StandardScaler)が必要。

用途別の追加実装:

🎯 このコードでやること:標準化した 2 変数で Ward 法(k-means 比較用)を実行し、4 クラスタのラベルと各都道府県の所属を確認する。

📥 入力データ:上記コードで生成した標準化済み Xs(shape=(47,2))

1
2
3
4
5
6
7
8
9
# 標準化と簡易クラスタリングの例
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

X = df[['A1101', 'A4101']].astype(float).values
Xs = StandardScaler().fit_transform(X)
km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Xs)
df['cluster'] = km.labels_
print(df[['Prefecture', 'A1101', 'A4101', 'cluster']].head(10))

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

Prefecture A1101 A4101 cluster 0 北海道 5092000 24430 3 12 青森県 1184000 5696 0 24 岩手県 1163000 5432 0 36 宮城県 2264000 12328 0 48 秋田県 914000 3611 0 60 山形県 1026000 5151 0 72 福島県 1767000 9019 0 84 茨城県 2825000 14898 0 96 栃木県 1897000 9958 0 108 群馬県 1902000 9950 0

💬 人口規模で明瞭に分かれ、北海道など人口の多い県が別クラスタになる。k=4 だと東京など超大都市を独立クラスタに分離できる(クラスタ番号は初期値依存で意味は任意)。

🎯 このコードでやること:SSDSE-B-2026 の全都道府県時系列で A1101 の推移を確認し、ADF 検定で定常性を調べる(Ward 法クラスタリング前の時系列補足分析)。

📥 入力データ:全年度の SSDSE-B-2026(A1101 列)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 時系列(全国平均の A1101)— 例として ARIMA 系の前処理
# ここでは年度を絞らずに全 12 年度を読む(1 年度だけだと系列にならない)
import pandas as pd
import statsmodels.api as sm

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

ts = df_all.sort_values('SSDSE-B-2026').groupby('SSDSE-B-2026')['A1101'].mean()
print(ts.tail().round(1))
res = sm.tsa.stattools.adfuller(ts)
print('ADF stat:', round(res[0], 3), ' p:', round(res[1], 3))

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

SSDSE-B-2026 2019 2692659.6 2020 2683959.6 2021 2670212.8 2022 2658425.5 2023 2645808.5 Name: A1101, dtype: float64 ADF stat: 0.269 p: 0.976

💬 全国平均人口(47 都道府県の平均、 単位は人)は単調減少トレンド。ADF の p=0.976 は「単位根あり(非定常)」をまったく棄却できないことを示す。Ward 法での横断面クラスタリングは各年度の「スナップショット」として有効。

🎮 触って理解する — ΔE(SSE増分)最小化 vs 最短距離

階層クラスタリング全般(デンドログラムの読み方など)は 階層クラスタリングデンドログラム のページで扱いました。 ここでは Ward 法「固有」の性質に絞ります:併合候補ペアごとにクラスタ内分散(SSE)の増分 ΔE を全部計算し、 ΔE が最小のペアを選ぶ——このルールだけで、 なぜ「球状・同サイズ」のクラスタができるのか。 単連結(最短距離)との併合順の違いを並べて体感してください。

🖱️ 点はドラッグで自由に動かせます(タッチ対応)。 動かすと両方の併合順・ΔE 一覧・SSE 推移が即座に再計算されます。 ΔE は Lance-Williams 漸化式(初期値 $d_{ij}=\tfrac{1}{2}\lVert x_i-x_j\rVert^2$)で正確に計算しています。

点群プリセット:
Ward 法:ΔE(SSE増分)最小のペアを併合
単連結:最短距離のペアを併合

破線=次に併合されるペア(Ward は重心間、 単連結は最近接点間)。 色付きの領域=現在のクラスタ。

読み込み中…

📋 Ward 法の併合候補:ΔE ランキング

📈 総クラスタ内 SSE の推移(同じ k で比較)

左端=全点バラバラ(SSE=0)、 右端=1クラスタ。 同じクラスタ数 k なら Ward の方が総 SSE が小さい(=まとまりが良い)ことが多い。 縦の点線=現在のステップ。

💭 直感の核心 — 「併合で増える散らばり」を最小に

2 クラスタ $A,B$ を併合したときの SSE 増分は、 展開すると次のきれいな形になります:

$\Delta E(A,B) = \dfrac{n_A\, n_B}{n_A + n_B}\, \lVert \mu_A - \mu_B \rVert^2$

読み方は 2 つの因子に分ければ簡単です:

上のデモで「⛓️ 鎖状」を選んで見比べると、 単連結は端から 1 点ずつ鎖を伸ばす(最短距離しか見ないので、 隣さえ近ければどんどん繋がる)のに対し、 Ward は鎖をいくつかの塊に切り分けてから塊同士を併合します。 ΔE ランキングの表で、 大きくなったクラスタが候補の下位に沈んでいく様子を確認してください。 これが「球状・同サイズ」バイアスの正体です。

⚠️ 触ってわかる落とし穴

🚀 発展 — k-means との関係・Ward.D と Ward.D2

⚠️ よくある落とし穴

❌ Ward 法を非ユークリッド距離で使う
Ward 法はユークリッド距離前提で導出されています。 マンハッタン距離やコサイン類似度で使うと、 結果が数学的に正しくない(負の距離が出ることも)。 非ユークリッド距離なら、 群平均連結や完全連結を選ぶ。
❌ 標準化を忘れる
距離ベースなので、 単位の違う変数を標準化なしで入れたら結果は無意味。 例:「人口(万人)」と「失業率(%)」で実行すれば、 ほぼ人口だけで階層化される。 必ず StandardScaler を使う。
❌ 非球形クラスタに使う
三日月型、 渦巻き型、 同心円のような非球形クラスタは、 Ward 法では強引に球形に分割されます。 こうしたデータには単連結(細長いクラスタ)、 DBSCAN、 Spectral Clustering を使う。
❌ 大規模データに使う
O(n²) メモリで n=10000 で 100MB、 n=100000 で 10GB。 メモリで死にます。 大規模なら:(i) サンプリング、 (ii) BIRCH や mini-batch k-means で粗くまとめてから Ward 法、 (iii) HDBSCAN や OPTICS への切り替え。
❌ Ward 法のバリエーションを意識しない
R の hclust(method="ward.D")method="ward.D2" は微妙に違います。 ward.D2 が正式な Ward 法。 Python の scipy はデフォルトで ward.D2 相当。 R を使うなら ward.D2 を指定する。
❌ k=2 で切ったクラスタを過信
階層クラスタリングは「常に2クラスタには分けられる」性質。 でもデータに本当に2分構造があるかは別問題。 シルエット係数や ギャップ統計量で、 そもそもクラスタ構造の有無を確認すべき。
❌ デンドログラムの切断高さの恣意性
「だいたい中間で切ろう」は主観的。 シルエット係数を複数の切断高さで比較、 ギャップ統計量、 事前理論を組み合わせて客観的に決定。

⚠️ Ward 法の落とし穴 7 連発

1. 標準化を忘れる。所得(千円単位)と高齢化率(%)を同じスケールで距離計算すると、 桁の大きい所得だけが結果を支配します。 StandardScaler で z スコア化するか、 MinMaxScaler で [0,1] に揃えてから linkage に投入しましょう。

2. ユークリッド距離以外を使う。Ward 法の数学的根拠は二乗ユークリッド距離に基づく分散分解です。 マンハッタンやコサインを scipy.spatial.distance で渡しても、 数式の整合性が壊れ、 結果の解釈ができなくなります。 別距離なら average や complete linkage を使いましょう。

3. クラスタ数の決定基準を持たない。「デンドログラムを見て直感で 4 個」だと再現性が無くなります。 シルエット係数・Calinski-Harabasz・Gap statistic・NbClust 風のスコア群を併用し、 複数指標で 4±1 程度の幅で議論するのが論文では好まれます。

4. 球形でないクラスタに無理に Ward を適用する。三日月型・らせん型のデータを Ward で分けると、 直感に反する分裂が起きます。 DBSCAN・OPTICS・スペクトラルクラスタリングの方が向く問題群が存在することを知っておきましょう。

5. 外れ値の影響を過小評価する。1 県だけが極端な値を持つと(例:東京の人口密度)、 ツリーが初期段階で「東京+その他」の 2 分割になり、 残りの解像度が落ちます。 robust スケール化(中央絶対偏差 MAD)や対数変換を検討しましょう。

6. 「クラスタ=因果カテゴリ」と思い込む。Ward 法は単なる類似度の階層分割であり、 そのクラスタが「政策効果が同じ」「介入応答が同じ」とは限りません。 クラスタを使った下流分析(処置効果・予測)はあくまで仮説生成に留めるのが安全です。

7. 元データに欠損があるまま投入する。SciPy の linkage は NaN を含むと内部でエラーになるか、 距離が NaN になり結果が破綻します。 SimpleImputerKNNImputer での欠損補完を必ず先に行い、 補完の妥当性を別途検証しましょう。

⚠️ 落とし穴

Ward 法 を実務で扱う際に踏みやすい落とし穴を 5 件挙げます。

🗺️ 概念マップ — 3つの視点で体系を理解する

Ward法 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。

階層クラスタリング 凝集型クラスタリング Ward 法 SSE 最小化結合 距離計算 (Euclidean) SSE 最小化基準 Single Linkage Complete Linkage Average Linkage Centroid Linkage K-means DBSCAN GMM 凡例: Ward法(現用語) 上位概念 並列手法 下流応用 前提 -- 並列/前提 → 包含/発展

▲ JS 不要の静的 SVG 概念マップ。Ward 法の位置付け・前提・並列手法・下流応用を一望できる。

📍 体系階層のパス

🌐 統計・データサイエンス教師なし学習クラスタリングWard法

① 🔗 関係マップ — 「他の手法とどう繋がっているか」

中心に Ward法 を置き、 そこから 階層クラスタリング・分散・標準化・デンドログラム・クラスタリング全般・k-means など 計 12 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語あとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。

凡例:現在の用語上位カテゴリ兄弟(並列)前提発展形応用先2階層先

② ⭕ 包含マップ — 「どのカテゴリに含まれているか」

大きな円が小さな円を包含する Circle Packing 図。 「Ward法」は緑色でハイライト

📍現在地:統計・データサイエンス

③ 🌳 ツリーマップ — 「面積で見るボリューム比較」

長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「Ward法」は緑色でハイライト

🎯 3つのマップの使い分け

マップ 分かること こんな時に見る
🔗 関係マップ手法間の横の関係(前提→発展→応用)「次に何を学べばよい?」 学習順序の判断
⭕ 包含マップ分類体系の入れ子構造(上位⊃下位)「この手法はどんなジャンルに属する?」
🌳 ツリーマップ分野の規模比較(面積=ボリューム)「データサイエンス全体の俯瞰像」

💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは Ward法隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンスクラスタリング → Ward法 という入れ子の位置を示します。 「クラスタリングには他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。

🗺 概念マップ

🔗 隣接手法への橋渡し

Ward 法は階層的クラスタリングの 1 連結方式であり、 前処理 (標準化) と評価 (デンドログラム / シルエット) の組み合わせで完成する。 以下は典型的な接続パターン。

位置手法・概念接続の意味
上流(前処理)標準化 / PCAWard 法の前に必ず標準化。 高次元データは PCA で次元削減してから投入することも有効。
並列(代替)k-means / DBSCANWard は階層構造の可視化が強み。 k が決まっているなら k-means、 密度ベースなら DBSCAN。
下流(評価)シルエット係数 / デンドログラムWard の出力はデンドログラムで切断高さを選択。 シルエット係数で最適 k を定量評価。

これらの接続を意識することで、 「Ward法 (Ward's Method)」を中核に据えた一貫した分析パイプラインを構築できる。

🌳 手法選択フロー — Ward 法を使うべき状況の判定

下記のフローに従って「Ward 法が適切か」を判定する。

判定条件YES → 次へNO → 代替手法
① データは連続数値変数か?② へカテゴリ変数なら k-modes、 混合なら Gower 距離 + complete
② ユークリッド距離が自然か?(単位を揃えれば等方的)③ へテキスト・ネットワーク → コサイン/グラフ距離 + average/complete
③ n < 5,000 程度か?④ へ大規模データ → BIRCH → Ward の 2 段構成、 または HDBSCAN
④ クラスタ数を事前に決めずに探索したいか?Ward 法を選択クラスタ数が決まっているなら k-means の方が速い
⑤ クラスタが球状・均等サイズを期待するか?Ward 法が第一選択細長い・リング状クラスタ → single / DBSCAN / Spectral

💡 SSDSE-B-2026 の 47 都道府県 × 数値特徴量は条件①〜⑤をすべて満たす → Ward 法が第一選択。

🔬 解説深化 — SSDSE-B-2026 の実測で Ward 法の「教科書的な主張」を検証する

ここまでの解説は「Ward 法はこう振る舞うはず」という一般論が中心でした。 この節では、 SSDSE-B-2026 の 2023 年度・47 都道府県の実データに Ward 法を実際に適用し、 教科書的な主張がどこまで成り立ち、 どこで裏切られるかを実測値だけで確かめます。 使用した 4 指標はすべて実在列からの導出です:

各指標を z 標準化してから scipy.cluster.hierarchy.linkage(X, method="ward") を実行した実測結果が以下です。

🎨 直感 — デンドログラムの「高さの跳ね」が k を教えてくれる

Ward 法のデンドログラムの縦軸(併合高さ)は「その併合で払った SSE 的コスト」。 実測した最後の 6 回の併合高さは次の通りでした:

併合k=7→6k=6→5k=5→4k=4→3k=3→2k=2→1
高さ(実測)3.2353.4414.1324.4477.19813.584

→ 4.447 から 7.198 へと約 1.6 倍に跳ねる直前、 つまり「k=3 で切る」あたりが階段の折れ目。 最後の併合はさらに 13.584 まで跳ね(1.9 倍)、 これが「東京を含む一群と残り」を分ける線に対応する。 デンドログラムを眺めて「なんとなく 4 つ」ではなく、 併合高さの数列の跳躍として k を根拠づけられます。 実際に k=4 で切った実測クラスタは次の通り(括弧内はクラスタ平均:高齢化率% / 転入超過率 / 出生率 / 気温℃):

⚠️ 落とし穴(重要) — 実測が教科書を裏切る 2 つのポイント

落とし穴 1:標準化を忘れた Ward 法は「人口の輪切り」になる(実測)。 総人口 A1101(標準偏差 ≈ 276.8 万人)と合計特殊出生率 A4103(標準偏差 ≈ 0.132)を標準化せずに混ぜて Ward 法を実行すると、 標準偏差の比は約 2,100 万倍。 実測の k=4 の結果は「東京だけ(1)/埼玉・神奈川・愛知・大阪(4)/北海道・千葉・兵庫・福岡(4)/残り 38 県」— つまりただの人口ランキングの輪切りで、 出生率の情報は完全に消えます。 標準化した場合との調整ランド指数(ARI)は実測 0.177。 ほぼ別物の分類になるという事実を、 数字で覚えておいてください。

落とし穴 2:「均等サイズになりやすい」は傾向であって保証ではない(実測)。 本文の比較表では Ward 法の長所として「均等サイズ」を挙げていますが、 上の実測 k=4 は 24 / 14 / 8 / 1 と大きく不均等で、 沖縄は単独クラスタです。 Ward 法は「単連結ほど極端な偏りを作りにくい」だけで、 データに実在する外れ構造(沖縄のような別格の県)はきちんと単独で切り出します。 むしろ「1 県クラスタが出た=その県が多変量的な外れ値」というシグナルとして読むのが実務的です。

🚀 発展 — コフェネティック相関では Ward 法が最良とは限らない

デンドログラムの忠実度指標であるコフェネティック相関(元のペア距離と樹形図上の距離の相関)を、 同じ標準化済みデータで 4 つの連結法について実測すると:

連結法Ward単連結完全連結群平均
コフェネティック相関(実測)0.6690.7230.5290.789

→ 「第一選択」のはずの Ward 法 (0.669) は群平均 (0.789)・単連結 (0.723) に及ばず4 手法中 3 位、 群平均が最上位です。 これは矛盾ではありません。 コフェネティック相関は「元の距離をどれだけ保存するか」を測る指標で、 群平均連結はまさに距離の平均を保つよう設計されているため高くなりやすい。 一方 Ward 法は距離保存ではなくクラスタ内 SSE の最小化を目指すため、 樹形図の高さが SSE 増分に置き換わり、 元の距離との相関は下がります。 つまり「良いクラスタリング」の定義は指標ごとに違う — 分割の解釈しやすさなら Ward、 距離構造の忠実な要約なら群平均、 と目的で使い分けるのが発展的な理解です。 なお本ページ上部の実行例にあるコフェネティック相関と値が異なるのは、 使用する変数セットが異なるためで、 この指標は変数構成に強く依存します(より正確には、 併記した導出式の 4 指標での実測値が上表です)。

🔗 関連ページ