論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
k-means法
k-Means Clustering
事前に決めた k 個のクラスタ中心からの距離が最小になるように、反復的にクラスタを更新するアルゴリズム。
教師なし学習k-meanskmeansK平均法

🔖 キーワード索引

🔖 キーワード索引(拡張)

直感 計算 🎓 設計判断 🧮 SSDSE-B 実例 🐍 実装バリエーション ⚠️ 落とし穴集 kの決定 DBSCAN代替 関連用語マップ

k-means」は SSE (クラスタ内二乗距離和) を目的関数とする非階層クラスタリング手法。 本ページの中核キーワードを以下に整理する。

k-meanscentroid (クラスタ中心)SSE / inertia_Lloyd アルゴリズムk-means++ 初期化エルボー法シルエット係数標準化前提球形クラスタ仮定Mini-Batch K-MeansDBSCAN / GMM 代替SSDSE-B-2026 47 都道府県

これらのキーワードは「assignment step → update step → 収束判定」と「k 選択 → 初期化 → 形状判定」の 2 軸で k-means 実務を構成する。

💡 30秒で分かる結論

🍰 まずはやさしく

似たもの同士を分けるグループ分けです。

データを自動でいくつかの集団にまとめます。

スマホのアプリで好みの人を分けるようなものです。

この手法の結論を短くまとめます。

📖 もっと詳しく

k-means は機械学習の教師なし学習の代表手法。 「事前に決めた k 個のグループに、 似ているサンプル同士を集める」反復アルゴリズム。 1957年に Lloyd が提案し、 1967年に MacQueen が "k-means" と命名。 シンプルかつ高速で、 現在も クラスタリング手法の標準

「means(平均)」が名前の由来:各クラスタの「中心(centroid)」を、 そのクラスタに属するサンプルの平均位置で表すから。 「k 個の中心」を探すアルゴリズム、 と言えます。

k-means は探索的データ分析の万能ツール。 顧客セグメンテーション、 地域類型化、 異常検知、 画像圧縮(色のクラスタリング)まで幅広く使われます。

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

🍰 まずはやさしく

データを分けるための定番の道具です。

似ているグループを自動で作るために使います。

都道府県を特徴で分けるときに便利です。

この手法がどこで使われるかを紹介します。

論文で「k-means クラスタリング」「k=4 でクラスタリングした」「エルボー法で k を決定」のように登場する手法。 47都道府県を「似ている県のグループ」に自動分類するときの定番ツール。

k-means法 とは:事前に決めた k 個のクラスタ中心からの距離が最小になるように、反復的にクラスタを更新するアルゴリズム。

🎨 直感で掴む

🍰 まずはやさしく

点と中心の距離で分けるイメージです。

自然なグループ構造を見つけるために使います。

部活のメンバーを能力で分けるような感覚です。

仕組みを直感的に理解するための例を見ます。

k-means法
47都道府県を「高齢化率×死亡率」の2次元空間で k=4 にクラスタリングした例。 × が各クラスタの中心(centroid)。 右上=高齢化進行、左下=若年層多。

図を見ると、 4色の点群(クラスタ)と各クラスタの × 印(中心)が見えます。 k-meansは「各点が、 自分が属するクラスタ中心に最も近い」状態に収束した結果。

右上のオレンジのクラスタは「高齢化進行・死亡率高」(秋田・島根・高知)、 左下の緑のクラスタは「若年層多・死亡率低」(東京・神奈川・沖縄)と解釈可能な構造に分かれています。 「データに自然なグループ構造があれば、 k-means はそれを発見してくれる」ことが体感できる。

反復のイメージ — 「中心 → 割り当て」を交互に:(1) ランダムに k 個の中心を置く、 (2) 各点を「最も近い中心」に割り当てる、 (3) 各クラスタ内の点の平均位置に中心を移動、 (4) 中心が動かなくなるまで (2)-(3) を繰り返す。 これは E ステップ(割り当て)と M ステップ(中心更新)を交互に行う EM 法の一種で、 必ず単調に SSE が減少して収束します。 ただし初期値依存のため、 異なる初期値で 10 回走らせて最良の解を採用する n_init=10 が sklearn の標準動作です。

「平均」が中心の名前の由来:k-means の「means」は文字通り mean = 平均。 各クラスタの中心は所属点の 算術平均 です。 中央値(メドイド)を使う k-medoids、 確率分布で割り当てる GMM、 階層構造を作る 階層クラスタリング など、 「中心の定義」と「割り当て方」を変えることで様々な派生手法が生まれます。

🎮 点を置いてクラスタリング(触って理解する k-means)

下のキャンバスをクリックして点を配置し、 スライダーで k(クラスタ数)を決めて、 「▶ 1ステップ」で 割り当て(assignment)→ 重心更新(update) を1手ずつ、 「⏩ 自動収束」で最後まで動かせます。 各点が所属クラスタの色に塗られ、 ✕ 印の重心が平均位置へ移動していく様子を観察できます。 「🎲 初期値ランダム」を何度も押すと、 同じ点配置でも初期重心しだいで結果が変わる(初期値依存)ことが体感できます。 右上の WCSS(=SSE, クラスタ内二乗和)が反復のたびに単調に減るのがエルボー法の直感です。

状態クリックで点を置いてください
反復回数0
点の数 n0
WCSS (SSE)

✕ = 重心(centroid, 所属点の平均座標)/ ● = データ点(所属クラスタ色)。 割り当て手番では点の色が、 更新手番では ✕ の位置が変わります。

💡 この操作で確かめられること
  • 収束の仕組み:割り当て→更新を繰り返すと WCSS が必ず単調減少し、 割り当てが変わらなくなった時点で収束(Lloyd アルゴリズム)。
  • 初期値依存:「🎲 初期値ランダム」で同じ点配置を何度も走らせると、 収束後の WCSS や色分けが変わることがある → 局所最適。 だから実務では n_init≥10 で複数初期値を試す(k-means++ は離れた点を初期重心に選んでこれを緩和)。
  • k とエルボー:k を増やすと WCSS は必ず下がるが、 下がり方が鈍る「肘」が最適 k の目安。
  • 球状仮定の限界:三日月・細長い形の点群を置くと、 k-means はうまく分割できない。 そうした形状は DBSCAN(密度ベース)や 階層クラスタリング が向く。

📐 数式

🍰 まずはやさしく

中心からの距離を計算する数式です。

グループ内のズレを最小にするために使います。

買い物で予算に近い商品を選ぶ計算に似ています。

計算のルールを数式を使って詳しく説明します。

【k-means の目的関数:SSE 最小化】
$$\arg\min_{S_1, \ldots, S_k} \sum_{i=1}^{k} \sum_{x \in S_i} \|x - \mu_i\|^2$$
各クラスタ $S_i$ の中心 $\mu_i$ までの距離の二乗和を、 全クラスタで合計した量(SSE = Sum of Squared Errors)。 これを最小化する分割を探す

📐 k-means の数学

損失関数

$$ J = \sum_{i=1}^{n} \sum_{j=1}^{k} z_{ij} \| x_i - \mu_j \|^2 $$

z_ij ∈ {0, 1}:i番目点がクラスタjに属するかどうか。 μ_j:クラスタjの中心。

アルゴリズム(Lloyd's algorithm)

  1. 初期中心をランダムに k個選ぶ
  2. 各点を最寄りの中心に割り当てる(assignment step)
  3. 各クラスタの中心を再計算(update step)
  4. 収束するまで 2-3 を繰り返す

計算量は O(n × k × d × iter)。 大規模データでは k-means++ や Mini-Batch k-means を使用。

k-means++ の初期化

「離れた点を初期中心に選ぶ」工夫。 通常のランダム初期化より速く・確実に良い解に収束。 sklearn のデフォルト。

🔬 数式を言葉で読み解く

$k$
クラスタ数:事前に決める。 通常 2〜10。 エルボー法・シルエット係数で決定
$S_i$
$i$ 番目のクラスタ(サンプルの集合)
$\mu_i$
$S_i$ の中心(centroid):$\mu_i = \frac{1}{|S_i|} \sum_{x \in S_i} x$(クラスタ内サンプルの平均)
$\|x - \mu_i\|$
サンプル $x$ から中心 $\mu_i$ までのユークリッド距離
$\|x - \mu_i\|^2$
二乗することで「遠いほど強くペナルティ」

🔬 k-means を実データで多角的に確認する(R283 補強)

k-means は 4 行のコードで動くが、 「標準化」「k の選択」「初期化のランダム性」「形状の前提」を理解せずに使うと無意味なクラスタが出る。 SSDSE-B-2026 で 4 角度から検証する。

① 標準化前後の SSE 比較 — 単位の影響

このコードでやること: SSDSE-B-2026 から「総人口 A1101」「年平均気温 B4101」を取り出し、 標準化なし/ありで k-means を実行、 各クラスタの内訳を比較する。

📥 入力: SSDSE-B-2026.csv。 総人口 A1101(百万単位)、 年平均気温 B4101(十数℃)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]          # 最新2023年・47都道府県
X_raw = df[['A1101', 'B4101']].fillna(df[['A1101', 'B4101']].mean()).values

# 標準化なし(総人口 A1101 は百万単位、年平均気温 B4101 は十数℃)
km_raw = KMeans(n_clusters=3, n_init=10, random_state=42).fit(X_raw)
# 標準化あり
X_std = StandardScaler().fit_transform(X_raw)
km_std = KMeans(n_clusters=3, n_init=10, random_state=42).fit(X_std)

vc = lambda km: dict(zip(*pd.Series(km.labels_).value_counts().sort_index().reset_index().values.T))
print('標準化なし: クラスタ別件数', vc(km_raw))
print('標準化あり: クラスタ別件数', vc(km_std))

📤 実行例:

標準化なし: クラスタ別件数 {0: 38, 1: 8, 2: 1} 標準化あり: クラスタ別件数 {0: 30, 1: 8, 2: 9}

💬 結果の読み方: 標準化なしでは「クラスタ 2 が東京 1 件だけ」になる(人口の桁が大きく、 距離計算が人口だけで決まる)。 標準化後は 30/8/9 に分かれ、 総人口の桁に潰されていた気温の情報も距離に効くようになる → 意味のあるクラスタリング。

② エルボー法で最適な k を決定

このコードでやること: k=1〜8 まで k-means を実行し、 SSE(inertia_)の推移から肘を探す。

📥 入力: ①の df から実在6列 A1101・A1303・A4101・B4101・L3221・C5401 を取り、 標準化した X_std。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from sklearn.cluster import KMeans

cols = ['A1101', 'A1303', 'A4101', 'B4101', 'L3221', 'C5401']
X = df[cols].fillna(df[cols].mean()).values
X_std = StandardScaler().fit_transform(X)

sse = []
for k in range(1, 9):
    km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(X_std)
    sse.append(km.inertia_)

for k, s in zip(range(1, 9), sse):
    print(f'k={k}: SSE={s:.2f}  減少={sse[k-2]-s if k>1 else 0:.2f}')

📤 実行例:

k=1: SSE=282.00 減少=0.00 k=2: SSE=145.24 減少=136.76 k=3: SSE=113.01 減少=32.22 k=4: SSE=79.18 減少=33.83 k=5: SSE=59.55 減少=19.63 k=6: SSE=50.70 減少=8.85 k=7: SSE=44.60 減少=6.10 k=8: SSE=37.43 減少=7.16

💬 結果の読み方: k=1→2 で 137 と大きく落ち、 k=2→3 は 32、 k=3→4 は 34、 k=4→5 で 20 と鈍りはじめる → 肘は k=4 前後。 SSE の減少幅が明確に小さくなる位置を目安に k=4 を採る。

③ シルエット係数で k を再検証

このコードでやること: k=2〜7 でシルエット係数を計算し、 エルボー法の結果と整合するか確認する。

📥 入力: ②の X_std。

 1
 2
 3
 4
 5
 6
 7
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

for k in range(2, 8):
    km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(X_std)
    sil = silhouette_score(X_std, km.labels_)
    print(f'k={k}: silhouette={sil:.3f}')

📤 実行例:

k=2: silhouette=0.555 k=3: silhouette=0.330 k=4: silhouette=0.302 k=5: silhouette=0.347 k=6: silhouette=0.267 k=7: silhouette=0.243

💬 結果の読み方: シルエット係数は k=2 が最大(0.555)→「大きく 2 群(大都市圏 vs その他)に分かれている」。 一方エルボーは k=4 前後を推奨。 基準が食い違う場合は分析目的で決める。 「2 群でざっくり」なら k=2、「地域類型を細かく」なら k=4。

④ 初期化のランダム性 — n_init による結果の安定性

このコードでやること: n_init=1 と n_init=20 で k-means を 5 回実行し、 SSE のばらつきを比較。 局所最適に陥るリスクを定量化する。

📥 入力: ②の X_std。 random_state は変化させる。

 1
 2
 3
 4
 5
 6
 7
 8
from sklearn.cluster import KMeans

for n_init in [1, 20]:
    sse_list = []
    for rs in range(5):
        km = KMeans(n_clusters=4, n_init=n_init, random_state=rs).fit(X_std)
        sse_list.append(km.inertia_)
    print(f'n_init={n_init:2d}: SSE = {[round(s, 2) for s in sse_list]}  最大-最小 = {max(sse_list)-min(sse_list):.2f}')

📤 実行例:

n_init= 1: SSE = [80.08, 83.54, 80.08, 95.43, 78.88] 最大-最小 = 16.56 n_init=20: SSE = [78.87, 78.88, 78.87, 78.74, 78.88] 最大-最小 = 0.14

💬 結果の読み方: n_init=1 では SSE が 78〜95 と大きくばらつく(初期値次第で局所最適に陥る試行がある)。 n_init=20 では毎回ほぼ 78.8 に収束し安定 → 大域最適に到達できている。 実務では必ず n_init≥10 を指定する。

k-means 4 つの実験のまとめ

🧮 計算してみる

6都道府県のデータ(高齢化率と死亡率)で、 k=2 の k-means が実際にどう動くか、 反復計算を追ってみます。

STEP 0 データと初期化
都道府県高齢化率 x死亡率 y
秋田3919
高知3617
大阪2813
神奈川2611
東京239
沖縄2311

初期中心をランダムに:C1 = (40, 20)C2 = (20, 10)(k-means++ では確率的に選びますが、 簡単のためここでは固定)

STEP 1 イテレーション1:各点を最も近い中心に割り当て

各点から両中心までのユークリッド距離を計算:

d(C1)d(C2)割当
秋田 (39,19)√(1+1) = 1.4√(361+81) = 21.0C1
高知 (36,17)√(16+9) = 5.0√(256+49) = 17.5C1
大阪 (28,13)√(144+49) = 13.9√(64+9) = 8.5C2
神奈川 (26,11)√(196+81) = 16.6√(36+1) = 6.1C2
東京 (23,9)√(289+121) = 20.2√(9+1) = 3.2C2
沖縄 (23,11)√(289+81) = 19.2√(9+1) = 3.2C2

C1 クラスタ:秋田、高知(2点)/C2 クラスタ:大阪、神奈川、東京、沖縄(4点)

STEP 2 イテレーション1:中心を更新

各クラスタの平均を新しい中心とする:

  • 新 C1 = (平均(39,36), 平均(19,17)) = (37.5, 18.0)
  • 新 C2 = (平均(28,26,23,23), 平均(13,11,9,11)) = (25.0, 11.0)

中心が大きく動きました:C1 は (40,20) → (37.5, 18)、 C2 は (20,10) → (25, 11)

STEP 3 イテレーション2:再割り当て

新しい中心で再度距離計算:

d(新C1)d(新C2)割当
秋田 (39,19)1.8016.1C1(変化なし)
高知 (36,17)1.8012.5C1(変化なし)
大阪 (28,13)10.73.6C2(変化なし)
神奈川 (26,11)13.51.0C2(変化なし)
東京 (23,9)17.12.8C2(変化なし)
沖縄 (23,11)16.12.0C2(変化なし)

すべての点の割当が前回と同じ!中心も動かない。 収束完了。 たった2イテレーションで終了しました。

STEP 4 結果の解釈

最終結果

  • クラスタ1(高齢化進行群):秋田、 高知。 中心 (37.5, 18.0)。 「高齢化率約37.5%、 死亡率約18‰の県」
  • クラスタ2(中・低齢化群):大阪、 神奈川、 東京、 沖縄。 中心 (25.0, 11.0)。 「高齢化率約25%、 死亡率約11‰の県」

SSE(残差二乗和) = (秋田からC1の距離²) + (高知からC1の距離²) + ... ≈ 1.8² + 1.8² + 3.6² + 1.0² + 2.8² + 2.0² ≈ 34.5。 これより小さい分割は存在しません(この初期値からは)。

k=3 にしたら?大阪・神奈川を1群、 東京・沖縄を別群、 秋田・高知を1群、 のように細分化されます。 SSEはさらに小さく。 でもどこかで「k を増やしても効率が悪い」境界(=エルボー)が来ます。

🎓 k-means の設計判断 — k の決定・初期化・距離

1. k(クラスタ数)の決め方

「いくつのクラスタに分けるか」は分析者が決める。 客観的指標の選択肢:

2. 初期化:k-means++

ランダム初期化は局所最適に陥りやすい。 k-means++ は次の手順で賢く初期化:

  1. 1つ目の中心はランダム選択
  2. 2つ目以降は、 「既選択中心から遠い」サンプルほど高確率で選ぶ(距離の二乗に比例する確率)
  3. k 個の中心が分散して配置される

scikit-learn の KMeansデフォルトで k-means++。 さらに n_init 回試行して最良の SSE を採用。

3. 距離の選択

標準はユークリッド距離。 ただし他の選択肢もあります:

ただしユークリッド以外を使うと「平均」が幾何的に意味を失うので、 厳密には k-medoids(中心を実在サンプルに)が適切。

4. 計算量と収束性

計算量:$O(n \cdot k \cdot d \cdot \text{iter})$。 通常 iter は数十回。 n=100万 でも数秒で完了するのが強み。

収束性:k-means は必ず収束しますが、 大域最適解への収束は保証されません。 SSE は反復のたびに必ず減少(または同じ)となりますが、 局所最適に陥る可能性があります。 これが「複数回試行」が必要な理由。

NP困難性:k-means の大域最適解を求める問題は NP困難(k≥2 で)。 だから「最適解の近似」を反復で求めるしかない。

🧮 SSDSE-B-2026 で k-means を即実行

最新の SSDSE-B-2026 を使い、 47 都道府県を 4 クラスタに分けるコード。 教材標準パスを直書きしています。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) B4101(年平均気温) C5401(標準価格(平均価格)(住宅地)) 北海道 5,092,000 1,681,000 24,430 11.0 23,600 東京都 14,086,000 3,205,000 86,348 17.6 404,400 沖縄県 1,468,000 350,000 12,549 23.8 68,100 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]          # 最新2023年・47都道府県
X = df[['A1101', 'A1303', 'A4101', 'B4101', 'L3221', 'C5401']].dropna()
X_scaled = StandardScaler().fit_transform(X)

km = KMeans(n_clusters=4, n_init=10, random_state=42).fit(X_scaled)
print(km.labels_)        # 各都道府県のクラスタ番号
print(km.inertia_)       # SSE(小さいほど締まりが良い)
📤 実行例(実測) [1 1 1 1 1 1 1 1 1 0 3 3 2 3 1 1 1 0 1 1 1 1 3 1 1 1 3 3 1 0 0 1 1 1 0 0 0 0 0 3 0 0 0 1 0 0 0] 79.17867759057592

出力例: 東京・大阪は「人口規模グループ」、 秋田・高知は「高齢化グループ」、 沖縄は単独クラスタ寄りなど、 SSDSE-B-2026 の最新値で確かめられます。

🎯 理解度チェック — k-means 法

読み終えたら、 以下の練習問題で「自分で説明できるか」を確認しよう。 答えが詰まった箇所は対応する節に戻る。

  1. Q1. k-means の目的関数(クラスタ内 SSE)はどのように書ける? また、 なぜ 距離の二乗を使うのか 1 行で説明せよ。
  2. Q2. 初期セントロイドの選び方が結果に与える影響を述べ、 k-means++ がそれをどう緩和するか 2 行で説明せよ。
  3. Q3. SSDSE-B-2026 の「総人口 A1101(百万人)」と「年平均気温 B4101(十数℃)」を 標準化せずに k-means に投入すると何が起きるか。 標準化後と比べてクラスタ構成がどう変わるか 1 行で予想せよ。
  4. Q4. エルボー法とシルエット係数で最適 k を選ぶとき、 どちらがより信頼できるかとその理由を述べよ。
  5. Q5. k-means が 球形クラスタを前提とする理由を、 目的関数の形から説明せよ。 細長い・密度が異なるクラスタには何を使うべきか。

🛠 自分で手を動かす(5 分課題)

  1. SSDSE-B-2026.csv から「総人口 A1101」「65歳以上人口 A1303」「年平均気温 B4101」の 3 変数を抽出し、 StandardScaler で標準化。
  2. KMeans(n_clusters=k) を k=2〜8 で回し、 inertia_ の推移をプロットしてエルボーを目視する。
  3. 選んだ k で再度フィットし、 silhouette_score を計算してエルボーの選択と一致するか確認する。
  4. 各クラスタに属する都道府県名を print で出し、 「クラスタが何を意味するか」を 1 行で言語化する。

🧮 数式に値を入れて手で計算する: K-means 1 反復

合成 4 点 1D データで K=2 の 1 反復を手計算する。

Step 1: データと初期重心

x = [1, 2, 8, 10] 初期重心: c1=1, c2=10

Step 2: 割当 (最近傍)

x=1: |1-1|=0, |1-10|=9 → c1 x=2: |2-1|=1, |2-10|=8 → c1 x=8: |8-1|=7, |8-10|=2 → c2 x=10: |10-1|=9, |10-10|=0 → c2 クラスタ: c1={1,2}, c2={8,10}

Step 3: 重心更新

c1 新 = (1+2)/2 = 1.5 c2 新 = (8+10)/2 = 9.0 収束 (重心変化小)

🐍 Python で再現

1
2
3
4
5
6
import numpy as np
from sklearn.cluster import KMeans
X = np.array([[1],[2],[8],[10]])
km = KMeans(n_clusters=2, init=np.array([[1],[10]]), n_init=1, random_state=0).fit(X)
print(f"重心: {km.cluster_centers_.flatten()}")
print(f"ラベル: {km.labels_}")

📤 実行結果

重心: [1.5 9. ] ラベル: [0 0 1 1]

💬 手計算 (Step 3) [1.5, 9.0] と Python 出力が完全一致。

🐍 Python での実装

① scikit-learn での基本

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #1。最初のスニペットです。SSDSE-B-2026 を読み込みます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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.71756088] [-0.97849211] [ 1.23942334]] inertia: 0.03404255319148934 シルエットスコア: 0.423
💬 読み方:このステップは前処理/補助関数。本処理は次のスニペットに続く。

② 最適クラスタ数の探索

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #2。基本統計量を計算します。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 SSDSE-B-2026(年度) A1303(65歳以上人口) A1101(総人口) L3221(消費支出(二人以上の世帯)) Prefecture(都道府県) 北海道 2,023 1,681,000 5,092,000 296,888 北海道 東京都 2,023 3,205,000 14,086,000 341,320 東京都 沖縄県 2,023 350,000 1,468,000 251,222 沖縄県 …(全 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)──
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df = df[df['年度'] == df['年度'].max()]
for _c in df.columns[3:]:
    df[_c] = pd.to_numeric(df[_c], errors='coerce')
df['高齢化率'] = df['65歳以上人口'] / df['総人口'] * 100

# 見本でよく使われる仮の列名を、実データから作っておく
df['income'] = df['消費支出(二人以上の世帯)']
df['population'] = df['総人口']
_region = {'北海道': '北海道', '青森県': '東北', '岩手県': '東北', '宮城県': '東北',
           '秋田県': '東北', '山形県': '東北', '福島県': '東北', '茨城県': '関東',
           '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東',
           '東京都': '関東', '神奈川県': '関東'}
df['region'] = df['都道府県'].map(_region).fillna('その他')
df['地域'] = df['region']

_feats = ['総人口', '出生数', '死亡数', '婚姻件数']
df = df.dropna(subset=_feats + ['消費支出(二人以上の世帯)'])
X = df[_feats].to_numpy(dtype=float)
y = df['消費支出(二人以上の世帯)'].to_numpy(dtype=float)
x = df['総人口'].to_numpy(dtype=float)

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

# この抜粋の X_std は 47 都道府県 × 4 指標(上で作った X を標準化)
X_std = StandardScaler().fit_transform(X)

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')
💬 読み方:数値が出力されたら、まず大きさ(オーダー)と符号を確認しよう。

③ デンドログラムの描画

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #3。可視化(散布図/樹形図/時系列プロット)を描きます。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) L3221(消費支出(二人以上の世帯)) 北海道 5,092,000 514,000 1,681,000 24,430 296,888 東京都 14,086,000 1,513,000 3,205,000 86,348 341,320 沖縄県 1,468,000 236,000 350,000 12,549 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pandas as pd

# ── この抜粋だけで動くように、47 都道府県・最新年度を読み込む ──
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from scipy.cluster.hierarchy import linkage, dendrogram

# ── この抜粋だけで動くように、標準化した行列と葉のラベルを用意する ──
X_std = StandardScaler().fit_transform(
    _d[['A1101', 'A1301', 'A1303', 'A4101', 'L3221']].astype(float).values)
labels = _d['Prefecture'].tolist()

Z = linkage(X_std, method='ward')
plt.figure(figsize=(14, 6))
dendrogram(Z, labels=labels, leaf_rotation=90)
plt.show()
💬 読み方:プロットの形状から定性的な傾向(単調性・周期性)を読み取る。

🐍 実装バリエーション — scikit-learn / scipy / faiss

(A) scikit-learn KMeans — 標準

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #8。比較・別パターンを検討します。

1
2
3
4
5
6
from sklearn.cluster import KMeans
km = KMeans(n_clusters=4, init='k-means++', n_init='auto', max_iter=300,
            random_state=42).fit(X)
print(km.labels_)        # 各サンプルのクラスタ番号
print(km.cluster_centers_)  # 中心
print(km.inertia_)        # SSE
📤 実行例(実測) [1 0 0 2 0 0 2 2 2 2 1 1 3 1 2 0 0 0 0 2 2 2 1 2 0 2 1 1 0 0 0 0 2 2 0 0 0 0 0 1 0 0 2 0 0 0 0] [[1.03408333e+06 5.99995833e+03 1.55322917e+04 3.41237500e+03] [6.82775000e+06 4.08047500e+04 8.05385000e+04 2.70861250e+04] [2.20192857e+06 1.21774286e+04 3.00542857e+04 7.45578571e+03] [1.40860000e+07 8.63480000e+04 1.37241000e+05 7.17740000e+04]] 24124424920057.312
💬 読み方:別パターンと比べることで、手法選択の感度を体感できる。

(B) scikit-learn MiniBatchKMeans — 大規模データ向け

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #9。ハイパーパラメータを変えて再計算します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import numpy as np
from sklearn.cluster import MiniBatchKMeans

# ── この抜粋だけで動くように、大きめのデータを作る ──
# MiniBatchKMeans は「1 度に全件を見ない」ので大規模でも速い、という例
rng = np.random.default_rng(0)
X_large = rng.normal(size=(100_000, 4))    # 10 万件 × 4 次元(合成データ)

mbk = MiniBatchKMeans(n_clusters=4, batch_size=100, n_init=10, random_state=42)
mbk.fit(X_large)  # 件数が増えても数秒
print('クラスタ中心の形:', mbk.cluster_centers_.shape)
📤 実行例(実測) クラスタ中心の形: (4, 4)
💬 読み方:ハイパーパラメータで結果が大きく変わる場合は安定性を疑う。

(C) scipy.cluster.vq — 低レベル

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #10。最終結果のまとめ・保存を行います。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 SSDSE-B-2026(年度) A1303(65歳以上人口) A1101(総人口) L3221(消費支出(二人以上の世帯)) Prefecture(都道府県) 北海道 2,023 1,681,000 5,092,000 296,888 北海道 東京都 2,023 3,205,000 14,086,000 341,320 東京都 沖縄県 2,023 350,000 1,468,000 251,222 沖縄県 …(全 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
26
27
28
29
30
31
# ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)──
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df = df[df['年度'] == df['年度'].max()]
for _c in df.columns[3:]:
    df[_c] = pd.to_numeric(df[_c], errors='coerce')
df['高齢化率'] = df['65歳以上人口'] / df['総人口'] * 100

# 見本でよく使われる仮の列名を、実データから作っておく
df['income'] = df['消費支出(二人以上の世帯)']
df['population'] = df['総人口']
_region = {'北海道': '北海道', '青森県': '東北', '岩手県': '東北', '宮城県': '東北',
           '秋田県': '東北', '山形県': '東北', '福島県': '東北', '茨城県': '関東',
           '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東',
           '東京都': '関東', '神奈川県': '関東'}
df['region'] = df['都道府県'].map(_region).fillna('その他')
df['地域'] = df['region']

_feats = ['総人口', '出生数', '死亡数', '婚姻件数']
df = df.dropna(subset=_feats + ['消費支出(二人以上の世帯)'])
X = df[_feats].to_numpy(dtype=float)
y = df['消費支出(二人以上の世帯)'].to_numpy(dtype=float)
x = df['総人口'].to_numpy(dtype=float)

from scipy.cluster.vq import kmeans, vq
centroids, distortion = kmeans(X, 4)
clusters, _ = vq(X, centroids)
# シンプルだが n_init などのオプションが少ない
💬 読み方:最終結果は CSV/プロットとして保存しておくと後続分析で再利用できる。

(D) k-medoids (PAM) — ロバスト代替

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #11。可視化を仕上げ、レポートに統合します。

1
2
3
from sklearn_extra.cluster import KMedoids
kmed = KMedoids(n_clusters=4, metric='manhattan', random_state=42).fit(X)
# 中心が「実在サンプル」になる。 外れ値に強い
💬 読み方:レポート用には数値だけでなく可視化と注釈をセットで提示する。

(E) Gaussian Mixture — 確率的拡張

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #12。追加検証・感度分析を実行します。

1
2
3
4
from sklearn.mixture import GaussianMixture
gmm = GaussianMixture(n_components=4, covariance_type='full', random_state=42).fit(X)
proba = gmm.predict_proba(X)  # 各クラスタへの所属確率
# 楕円体クラスタOK、 ソフトクラスタリング
💬 読み方:感度分析の結果が安定していれば、結論の信頼性が高まる。

(F) FAISS — 数億規模の超高速

🎯 このコードでやること:k-means — 重心型分割クラスタリングに関連するステップ #13。応用パターン(別データ・別手法)に拡張します。

1
2
3
4
5
import faiss
kmeans_faiss = faiss.Kmeans(d=X.shape[1], k=4, niter=20, verbose=False)
kmeans_faiss.train(X.astype('float32'))
_, labels = kmeans_faiss.index.search(X.astype('float32'), 1)
# GPU 対応、 大規模ベクトル検索(埋め込み)に必須
💬 読み方:応用パターンの結果を比較すると、手法の適用範囲が見える。

⚠️ よくある落とし穴

❌ k を恣意的に決める
「とりあえず k=3 でやりました」は通用しない。 必ずエルボー法シルエット係数で客観的に決定。 さらに事前理論(「3地域に分けたい」)と整合性を確認。 複数の k で結果を比較するのも頑健性チェックとして有効。 実例:n=47 都道府県なら、 k=2〜7 が現実的範囲。 k=10 など細かすぎると各クラスタが少数で意味を失う。
❌ 標準化なしで実行(致命的)
「人口」(億単位)と「失業率」(%)を標準化せずに距離を計算すると、 桁の大きい変数だけで距離が決まり、 無意味なクラスタになります。 必ず StandardScaler で平均0・分散1に揃えてから。

具体例:人口100万人の差は、 失業率5%の差より桁が6つ違う。 ユークリッド距離はほぼ「人口の差」になり、 失業率の情報がほぼ消える。
❌ 1回だけ実行して採用
初期化のランダム性に依存するので、 通常は異なる初期値で複数回実行し、 最良の SSE を持つ結果を採用。 scikit-learn の KMeans(n_init=10) は10回試行して最良を返す("auto" なら自動調整)。 学術論文では random_state を固定し再現可能にする。
❌ 非球形クラスタに無理やり
三日月型、 渦巻き型、 同心円のような複雑な形状は、 k-means では分割できません。 「球形クラスタ前提」の手法だから。 こうしたデータには DBSCAN(密度ベース)、 Spectral Clustering(グラフ理論)、 GMM(楕円体クラスタOK)などへ。

判定方法:PCA で2次元プロットして、 クラスタの形状を視覚的に確認。
❌ 外れ値の影響を無視
k-means の中心は平均なので、 1個の極端な値で中心が大きく動きます。 例えば「東京」が他から離れていると、 東京を含むクラスタの中心が東京寄りになり、 他県との関係が歪む。 対処:(i) 外れ値を別クラスタにする(k+1で実行)、 (ii) k-medians や k-medoids を使う、 (iii) 外れ値を事前除外。
❌ クラスタ結果を「客観的真実」と思う
k-means は「与えた指標と距離の枠組みで似ているもの」を集めるだけ。 違う指標で実行すれば違うクラスタが出ます。 結果は分析者の選択の反映。 「このデータをこう分類した」という形で報告すべき。 「真のクラスタ」が存在する前提自体が幻想のことも。
✅ クラスタの解釈をしっかり
「k=4 でクラスタリングしました」だけでは研究にならない。 各クラスタの変数の平均値・標準偏差・代表サンプルを確認し、 「クラスタ1は何の特徴を持つ群か」を解釈・命名する。 ここが分析者の腕の見せどころ。 例:クラスタA=「大都市」、 B=「地方中核」、 C=「地方過疎」のように。

📊 SSDSE実データでの応用

47都道府県の家計5項目データに k-means (k=3) を適用しました:

k-means結果

PC1 と PC2 の散布図上で、 3つのクラスタが綺麗に分離されているのが見えます。 各クラスタの特徴を解釈することで「家計タイプ」が見出せます。

🎯 k の選び方

クラスタ数判定

エルボー法とシルエット法で最適な k を探します。

⚠️ k-means の限界

これらの限界を超えるには、 GMM、 DBSCAN、 スペクトラルクラスタリングなどを検討。

⚠️ 追加の落とし穴 — k-means の実務(既存に追加)

❌ 高次元データに素朴に適用
次元数 d > 50-100 になると次元の呪いで距離の差が縮まり、 クラスタ構造が見えなくなる。 対策:(i) 事前に PCA で次元削減(10-20次元へ)、 (ii) UMAP・t-SNE で2-3次元化(可視化用)、 (iii) ドメイン知識で重要変数のみ選択、 (iv) スパースな高次元なら別アプローチ(NMF 等)。 SSDSE-B でも全100変数を入れるのは推奨せず、 6-12 変数に絞るのが現実的。
❌ 「クラスタ数 = 自然な真の数」と思い込む
エルボー法・シルエットで「最適 k」を求めても、 それは数学的最適にすぎない。 データに真のクラスタ構造があるとは限らない。 連続的に分布するデータでも k-means は強制的に k 個に分割する。 ギャップ統計量で「クラスタ構造の有無」を事前検定するか、 結果を別の k で複数試して頑健性を確認する。 「分割結果」と「自然な群」を混同しない。
❌ クラスタサイズの不均衡を無視
k-means は「球形クラスタかつ等サイズ」を暗黙に仮定する目的関数を最小化する。 実データではクラスタが大小さまざまで、 小クラスタが大クラスタに吸収されたり、 大クラスタが不自然に分割されることがある。 サイズ不均衡を考慮するなら、 GMM、 重み付き k-means、 階層クラスタリング、 DBSCAN(密度ベース)などを検討。
❌ クラスタラベルを「順序」と扱う
k-means の出力ラベル(0, 1, 2, ...)は名義尺度であり、 順序や大小に意味はない。 「クラスタ0より2が良い」のような比較は無意味。 また実行ごとにラベル番号が変わるため、 報告時にはクラスタ特性で命名(「都市型」「過疎型」など)するのが標準。 ラベル番号での集計や可視化は誤解を生む。
❌ 新サンプルの分類を考慮しない
k-means は訓練時に決まった中心に新サンプルを割り当てる(最近隣中心)。 これを「分類モデル」と思い込むのは要注意:新サンプルが既存どのクラスタにもフィットしない場合、 強制的に最寄りクラスタに入れられる。 異常検知が必要な場面では、 距離の閾値超過を「クラスタ外」として扱う実装が必要。
❌ カテゴリ変数を素のまま入れる
k-means はユークリッド距離ベースなので、 カテゴリ変数(性別・地域・色など)には適用できない。 one-hot エンコード後でも、 高次元でスパースになり距離が無意味化する。 カテゴリ混在データには k-modes(カテゴリ用)、 k-prototypes(混在用)を使う。 距離尺度に Gower 距離を採用した階層クラスタリングも代替候補。
❌ 結果の再現性を担保しない
k-means の初期化はランダムなので、 random_state を固定しないと毎回違う結果になる。 学術論文・本番運用では必ず random_state=42 等を明示。 また n_init(複数初期化試行回数)の指定も再現性に影響する。 さらに、 ハイパーパラメータ・前処理 (標準化方法) も全て記録し、 完全な再現性確保が責任。

📝 補足解説(直感・落とし穴・発展の深掘り)

既存の各節を壊さずに、 k-means の「なぜ動くか(直感)」「どこで壊れるか(落とし穴)」「どう拡張するか(発展)」を一枚に凝縮した追記ノート。 数値はいずれも SSDSE-B-2026(2023年・47都道府県、 標準化済み6変数)の実測。

🎨 直感の芯 — Lloyd 法は「割当」と「平均」の往復

k-means の反復(Lloyd 法)は 2 手番の往復に尽きる。 (1) 割当ステップ:各点を最も近い重心に割り当てる(=空間を重心ごとのボロノイ領域に分割)。 (2) 更新ステップ:各クラスタの重心を、 所属点の平均座標へ動かす。 これを重心が動かなくなるまで繰り返す。

なぜ必ず収束するのか:目的関数は「クラスタ内平方和(inertia=慣性)」=各点から自分の重心までの二乗距離の総和。 割当ステップは「より近い重心へ移す」ので inertia を増やさない。 更新ステップも inertia を増やさない — なぜなら「二乗距離の和を最小にする点」は、 その集合の平均そのものだから。 平均に動かすこと自体が SSE を必ず下げる。 両ステップとも単調に inertia を減らす(または不変)ので、 取りうる割当が有限である以上、 有限回で収束する。 これが「means(平均)」が中心の定義に選ばれた数学的理由でもある。

※ 単調収束するのは「ある局所最適へ」であって、 大域最適とは限らない(後述)。 これが初期値依存と n_init の伏線になる。

⚠️ 落とし穴チェックリスト(要点の凝縮)

🚀 発展① k-means++ 対 random 初期化(SSDSE-B-2026 実測)

このコードでやること:単一初期化(n_init=1)を 30 通りの乱数で走らせ、 k-means++ と素朴な random(Forgy)で inertia の平均・最良を比較。 初期化の賢さが「良い解に届く確率」に効くことを定量化する。

📥 入力: 本ページ ② の X_std(実在6変数 A1101・A1303・A4101・B4101・L3221・C5401、 標準化済み、 47都道府県)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import numpy as np
from sklearn.cluster import KMeans

def stat(init):
    v = [KMeans(4, init=init, n_init=1, random_state=rs).fit(X_std).inertia_
         for rs in range(30)]
    return round(float(np.mean(v)), 2), round(float(np.min(v)), 2)

print('k-means++ (平均, 最良):', stat('k-means++'))
print('random    (平均, 最良):', stat('random'))

📤 実行例:

k-means++ (平均, 最良): (87.59, 78.88) random (平均, 最良): (96.41, 80.08)

💬 結果の読み方: 1 回きりの初期化だと、 k-means++ は平均 inertia 87.59・最良 78.88 に届きやすいのに対し、 random は平均 96.41 と局所最適に留まりがち。 k-means++ が「離れた点を初期重心に選ぶ」ぶん良い解へ寄る。 それでも 1 回では最良に届かない試行があるため、 実務では n_init≥10 の複数初期化が保険になる(本ページ ④ の安定性検証と対応)。

🚀 発展② GMM のソフト割当と k-means のハード割当の対比(実測)

このコードでやること:同じ X_stdGMM(ガウス混合モデル)を当て、 各県の「所属確率」を出す。 k-means が全県を 1 クラスタにハード割当するのに対し、 GMM は確率でソフト割当し、 境界にいる県を数値で炙り出せる。

📥 入力: 本ページ ② の X_stddf(Prefecture 列)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.mixture import GaussianMixture

# 途中のブロックで df を日本語列名で読み直しているので、ここで英字コード版に読み直す
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True)   # 2023 年の 47 都道府県
X_std = StandardScaler().fit_transform(
    df[['A1101', 'A1303', 'A4101', 'L3221']].astype(float))

gmm = GaussianMixture(n_components=4, covariance_type='full',
                      random_state=42).fit(X_std)
proba = gmm.predict_proba(X_std)          # 各県 × 各クラスタの所属確率
maxp = proba.max(axis=1)                   # 最も確からしいクラスタの確率
i = maxp.argmin()                          # 最も「迷っている」県
print('境界県:', df['Prefecture'].values[i], round(float(maxp[i]), 3))
print('確率:', [round(float(p), 2) for p in proba[i]])
print('確率0.9未満の県数:', int((maxp < 0.9).sum()), '/ 47')

📤 実行例:

境界県: 富山県 0.84 確率: [0.84, 0.0, 0.16, 0.0] 確率0.9未満の県数: 1 / 47

💬 結果の読み方: 富山県は 2 つのクラスタに 0.84 対 0.16 でまたがる「境界県」。 k-means のハード割当ではこの曖昧さは 0/1 に潰れて見えないが、 GMM のソフト割当なら数値化できる。 残る 46 県は最大確率がほぼ 0.99 で、 データがよく分離していることの裏付けにもなる。 「割当の硬さ」と「楕円体クラスタ(共分散)を許すか」が k-means と GMM の設計差。

🔗 関連ページ(相対リンク・実在ファイルのみ)

クラスタリング(総論)
教師なしグループ化の枠組み。 k-means はその代表。
標準化
距離を単位差から守る必須前処理。
距離尺度
ユークリッド/マンハッタン/コサイン。
GMM(ガウス混合)
ソフト割当・楕円体クラスタの確率的拡張。
階層クラスタリング
k を後から選べる。 デンドログラム/Ward法。
デンドログラム
結合過程の樹形図。 任意の高さで切って k を決める。
Ward法
分散増加最小で結合。 k-means と相性が良い。
DBSCAN
密度ベース。 非球状・外れ値に強い。
スペクトラルクラスタリング
グラフ構造で非凸クラスタを分離。
主成分分析(PCA)
前段の次元削減・後段の可視化。
次元削減
次元の呪いを避け距離を意味あるものに。

※ 「シルエット係数」「エルボー法」「k-means++」「k-medoids」は本用語集に単独ページが未整備のため、 リンクにせず本文(本ページ ③④、 数式節落とし穴節)内の解説を参照。

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

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

📍 体系階層のパス

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

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

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

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

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

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

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

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

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

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

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

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

🔗 隣接手法への橋渡し

k-means 法は中心点更新 → 割り当て更新の反復で動作し、 単独で意味を成すには上流の標準化と下流の k 選定・解釈が不可欠である。

上流の標準化が距離計算の前提となり、 並列の階層クラスタリング/DBSCAN で形状仮定 (球状) の妥当性を逆検証し、 下流の PCA 可視化と組み合わせて初めて「k-means が見つけたクラスタ」が解釈可能になる。

🌳 手法選択フロー

クラスタリング手法は「クラスタ形状の前提」「k を事前に決められるか」「データ規模」「外れ値の多さ」で選び分ける。 以下の判断フローで k-means が適切かを確認する。

  1. Step 1 (k は決められるか): 業務要件や事前知識で k が決まっている → k-means / k-means++ が第一候補。 k が不明 → DBSCAN・階層クラスタリングを優先。
  2. Step 2 (クラスタ形状): 球状・等サイズに見える → k-means OK。 細長い・三日月型・ノイズ多 → DBSCAN / spectral clustering。
  3. Step 3 (データ規模): 数万件超え・高次元 → mini-batch k-means。 数百件で精度優先 → 標準 k-means + n_init=10〜50。
  4. Step 4 (外れ値): 外れ値が無視できないほど多い → k-medoids (中央値ベース)。 少ない → 事前除去 + k-means で十分。
  5. Step 5 (検証): 標準化済か / シルエット係数 0.3 以上か / エルボー曲線で k が妥当か / 異なる random_state で再現するか、 を必ず確認する。

「とりあえず k=3」ではなく、 上記 5 ステップを経た選択であれば、 結果のクラスタを業務判断や次工程 (顧客セグメント別施策、 都道府県分類など) に渡せる根拠が立つ。

🔖 キーワード索引(拡張)

直感 計算 🎓 設計判断 🧮 SSDSE-B 実例 🐍 実装バリエーション ⚠️ 落とし穴集 kの決定 DBSCAN代替 関連用語マップ