論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
中央値
Median
データを大小に並べたときの真ん中の値。外れ値に強い「ロバストな中心」。
記述統計メジアンmedian

🔖 キーワード索引

中央値 はデータを大小順に並べたときの真ん中の値。 平均と異なり 外れ値の影響を受けにくい ため、 所得・住宅価格・人口のように右に歪んだ分布の「代表値」として推奨される。 SSDSE-B-2026 の都道府県人口で平均は東京の影響で大きく引っ張られるが、 中央値は影響を受けにくい。

中央値 メディアン 50 パーセンタイル $Q_2$ 頑健統計 外れ値耐性 平均値との比較 所得分布(右に歪む) IQR ($Q_3-Q_1$) 四分位数 $Q_1,Q_2,Q_3$ breakdown point 50% df.median() np.median() SSDSE-B-2026 都道府県

「平均 vs 中央値 → 外れ値の効き方 → 歪んだ分布での選択」が要点。

💡 30秒で分かる結論

🍰 まずはやさしく

中央値はデータの真ん中の値です。

全体の中心を正しく知るために使います。

クラスのテスト点数を並べて真ん中を探すようなものです。

ここでは中央値の基本ルールを学びます。

📖 もっと詳しく

中央値(median)は、 データを大小順に並べたときちょうど真ん中の値。 47都道府県データなら、 24番目(または 23-24番目の平均)の値です。

強み外れ値に強い。 1つの極端な値が混ざっても、 中央値はびくともしません。 「ロバストな中心」と呼ばれます。

使い場面:(i) 所得・支出・地価など歪んだ分布、 (ii) 外れ値が多いデータ、 (iii) 順位データ(順序尺度)。 「日本の平均年収」より「日本の中央値年収」の方が現実を反映することが多い。

箱ひげ図の中央線が中央値。 第2四分位(Q2)、 50%パーセンタイルとも同じ概念。 df.median() で計算。

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

🍰 まずはやさしく

中央値は代表的な数値のひとつです。

データの中心をあらわすために使います。

スマホの利用時間をみんなで比べる時に役立ちます。

このページでは中央値の意味を詳しく解説します。

論文中に 「中央値」として登場する用語。

中央値 とは:データを大小に並べたときの真ん中の値。外れ値に強い「ロバストな中心」。

このページの位置: 中央値は大分類「統計の基礎」配下の代表値 (中心傾向) カテゴリに属し、 直近上位は「中心傾向 (代表値)」「記述統計」。 並列概念として「平均」「最頻値」、 ロバスト統計の系統では「MAD (中央絶対偏差)」「四分位数」と接続する。 機械学習評価指標では「MAE」が中央値最適と関連する。

次の章への橋渡し: 章 4 では SSDSE-B-2026 の住居費データで「順位の中心」としての中央値を視覚化し、 章 5 で偶数個・奇数個の場合分け定義、 章 7 で 47 都道府県の住居費・人口の中央値を実計算、 章 8 で numpy.median / pandas.Series.median による実装を扱います。

本ページでは「median」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「median」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む — 中央値は「並べて真ん中」

🍰 まずはやさしく

中央値は順位のちょうど真ん中です。

極端に大きい数字に惑わされないために使います。

部活の練習時間を小さい順に並べて真ん中を見る例です。

図を使って直感的に仕組みを理解しましょう。

中央値(median)は、 データを小さい順に並べた時の真ん中の値。 平均が「重心」だったのに対し、 中央値は「順位の中心」を表します。 47都道府県の住居費(2023年・ SSDSE-B-2026)を例に見ましょう。

中央値の直感

各バーが1つの都道府県の住居費。 オレンジ色の24番目がちょうど中央 → これが中央値 18.47千円です。 赤い点線が平均(18.36千円)。 平均は住居費が高い少数の県(東京、 神奈川など)に引っ張られて高めに出ています。

ASCII で見る「並べて真ん中」

データ (奇数個: 5 個):    3,  5,  7, 11, 15
昇順並び:                 3 < 5 <[7]<11 <15
                                  ↑ 中央 = median = 7

データ (偶数個: 6 個):    3,  5,  7, 11, 15, 22
昇順並び:                 3 < 5 <[7, 11]<15 <22
                                  ↑↑ 中央 2 値の平均 = (7+11)/2 = 9

SSDSE-B-2026 の数値で実感する

SSDSE-B-2026 から代表 7 都道府県の住居費 (千円/月) を昇順に並べた例:

順位  都道府県   住居費(千円)
 1   神奈川県     11.64
 2   愛知県       13.44
 3   岡山県       13.91
 4   宮崎県       16.71   ← 中央値 (4 番目 = 真ん中)
 5   福岡県       21.15
 6   鹿児島県     22.96
 7   東京都       26.46   ← 最大

→ 平均 = (11.64+13.44+13.91+16.71+21.15+22.96+26.46)/7 = 18.04 千円。 中央値 = 16.71 千円。 東京都の高い値で平均は中央値より 1.3 千円高いが、 中央値はその影響を受けにくい。

平均 vs 中央値 — どちらを使う?

場面推奨理由
所得・住居費・地価中央値高所得層の外れ値で平均が歪む
身長・体重 (正規分布)平均対称分布なら両者ほぼ一致、 数理扱いが楽
回帰の損失関数用途次第MAE 最適 = 中央値、 MSE 最適 = 平均
外れ値検出後どちらも可クリーニング済なら平均で十分

比喩で覚える

中央値は選挙の中道議員。 極端な左右の議員 (外れ値) が増えても、 議員席を順番に並べた時の真ん中の人は変わりにくい。 平均は議員 1 人 1 人の主張の合計を頭数で割った値で、 極端な議員が 1 人いるだけで大きく動く。

💡 中央値は順序統計量と呼ばれる量の代表。 「データの値そのもの」ではなく「並び順での位置」を見るため、 外れ値や極端な値の影響を受けにくい性質があります。

📐 数式と読み方ガイド

🍰 まずはやさしく

中央値は計算で決まる真ん中の値です。

正確な値を導き出すために使います。

買い物の金額を並べて計算するイメージです。

数式を使った求め方を順番に説明します。

① 中央値の定義(数式)

データを並べたものを x_{(1)} ≤ x_{(2)} ≤ ... ≤ x_{(n)} とすると:

$$ \text{median}(x) = \begin{cases} x_{((n+1)/2)} & (n \text{ 奇数}) \\ \frac{x_{(n/2)} + x_{(n/2 + 1)}}{2} & (n \text{ 偶数}) \end{cases} $$

記号読み方意味
x_{(i)}エックス カッコ アイ並べた時の i 番目の値(順序統計量)
nエヌデータ数
(n+1)/2エヌ プラス いち わる に真ん中の位置(n奇数の場合)

🔬 数式を言葉で読み解く — ② 連続分布での中央値

連続的な確率分布の場合、 累積分布関数 F の0.5 になる点

$$ F(\text{median}) = 0.5 \quad \Leftrightarrow \quad P(X \le \text{median}) = 0.5 $$

「中央値以下の確率は50%、 以上の確率も50%」という最も基本的な性質。

③ 中央値の最小化問題

中央値はL1 損失を最小化する点として定義できます:

$$ \text{median}(x) = \arg\min_m \sum_i |x_i - m| $$

絶対値の和を最小化する m が中央値です。 これは平均が「二乗和」を最小化するのと対をなします。

④ 平均との対比

性質平均中央値
最小化する損失L2(二乗和)L1(絶対値和)
線形性✅ ある❌ ない
外れ値耐性弱い強い(崩壊点50%)
計算量O(n)O(n log n)(ソート)または O(n)(quickselect)
微分可能性✅ 可能❌ 不可能(不連続)

🛡️ 外れ値耐性 — 中央値の最大の強み

中央値が最も活躍するのは外れ値や歪んだ分布のとき。 平均との違いを実感する例を見ましょう。

中央値のロバスト性

左は正規分布のデータ。 平均と中央値はほぼ一致。
右は同じデータに外れ値(3000, 4500, 5000)を3つ追加。 平均は劇的に上昇するのに、 中央値はほとんど動かない

崩壊点(breakdown point)

「データの何%まで汚染しても推定値が壊れないか」を表す指標:

中央値の50%崩壊点は、 ロバスト統計量として理論的最高。 半分以上のデータが「正常」なら推定値は壊れない。

歪んだ分布での違い

歪んだ分布

所得分布、 株価変動、 都市人口、 地震被害額など、 多くの実データは右に裾の長い分布(対数正規、 Pareto等)。 平均は裾に引っ張られて「典型的でない」値になり、 中央値の方が「典型的な人」を表します。 「平均年収」より「中央値年収」を見るべき理由。

📏 中央絶対偏差 (MAD) — 中央値ベースのばらつき指標

平均にはペアとして「標準偏差」がありましたが、 中央値のロバスト版が MAD (Median Absolute Deviation)

$$ \text{MAD} = \text{median}(|x_i - \text{median}(x)|) $$

計算手順

  1. データの中央値を計算 → m
  2. 各データ点について |x_i - m| を計算(中央値からの絶対距離)
  3. その絶対距離の中央値を取る → MAD

標準偏差は外れ値に弱い(2乗するから極端値が支配的)ですが、 MAD は50%崩壊点を持つロバスト指標。 正規分布の場合、 σ ≈ 1.4826 × MAD という換算式があります。

Python での計算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import numpy as np
from scipy import stats

data = np.array([1, 2, 3, 4, 5, 6, 7, 100])  # 外れ値あり
median = np.median(data)
mad = np.median(np.abs(data - median))
print(f'中央値: {median}')
print(f'MAD: {mad}')

# scipy には組み込み関数がある
mad_scipy = stats.median_abs_deviation(data)
mad_scaled = stats.median_abs_deviation(data, scale='normal')  # 正規分布換算
📤 実行例(実測) 中央値: 4.5 MAD: 2.0

📦 四分位と箱ひげ図 — 中央値の自然な拡張

中央値はデータの50%点。 これを25%、 75%にも拡張したのが四分位(quartile)。 そして四分位を可視化した最強のグラフが箱ひげ図

箱ひげ図

四分位の定義

箱ひげ図の読み方

  1. :Q1からQ3まで(中央50%のデータ)
  2. 箱の中の太線:中央値(Q2)
  3. ひげ(whisker):通常 Q1 - 1.5×IQR から Q3 + 1.5×IQR の範囲
  4. 点(outlier):ひげの外側のデータ点 → 外れ値の候補

💡 箱ひげ図1枚で 中央値・四分位・データの散らばり・歪み・外れ値 全てが分かります。 探索的データ分析(EDA)の基本ツール。

⚙️ 中央値計算アルゴリズム

① ソートしてから取る(O(n log n))

最も単純:全データをソートして、 真ん中を取り出す。 numpy/pandas のデフォルト実装。

1
2
3
4
5
6
7
def median_sort(arr):
    sorted_arr = sorted(arr)  # O(n log n)
    n = len(sorted_arr)
    if n % 2 == 1:
        return sorted_arr[n // 2]
    else:
        return (sorted_arr[n // 2 - 1] + sorted_arr[n // 2]) / 2

② QuickSelect — O(n) 平均時間

クイックソートと同じ分割を、 必要な位置だけ続ける。 全部ソートしないので線形時間で中央値が求まる。

1
2
3
4
5
6
import numpy as np

# numpy の partition は内部で QuickSelect 系のアルゴリズム
arr = np.random.randn(10**6)
k = len(arr) // 2
np.partition(arr, k)[k]   # O(n) で k 番目の値

③ ストリーミングデータ — オンライン中央値

データが1個ずつ来る場合、 ヒープを2つ(max-heap と min-heap)使うと O(log n) で更新可能。 IoT センサーや金融取引の中央値追跡で使われます。

🤖 機械学習での中央値

① 中央値回帰 (Quantile Regression)

通常の線形回帰は平均(期待値)を予測しますが、 中央値を予測する回帰もあります。 外れ値に強いロバスト回帰の代表。 損失関数は L1(絶対値):

$$ L(\beta) = \sum_i |y_i - x_i^T \beta| $$

機械学習ライブラリ:sklearn.linear_model.QuantileRegressorstatsmodels.regression.quantile_regression

② 決定木の損失関数

決定木の回帰版で、 各葉ノードの「中央値」を予測値とする方法もあります(デフォルトは平均だが、 中央値ベースの方がロバスト)。

③ 欠損値の補完

欠損値を埋める時、 SimpleImputer(strategy='median')中央値補完。 外れ値の影響を受けないので、 平均補完より安全。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) L3221(消費支出(二人以上の世帯)) 北海道 5,092,000 1,681,000 24,430 296,888 東京都 14,086,000 3,205,000 86,348 341,320 沖縄県 1,468,000 350,000 12,549 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# ── この抜粋で使うデータを用意します ──
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split

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', 'L3221']].astype(float).values
y = df['A4101'].astype(float).values          # 出生数
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42)

from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='median')
X_imputed = imputer.fit_transform(X)

④ Robust Scaling

標準化(標準偏差で割る)の代わりに、 中央値と IQR を使うスケーリング。 外れ値の影響を受けない前処理:

$$ x_{\text{scaled}} = \frac{x - \text{median}(x)}{\text{IQR}(x)} $$

1
2
3
from sklearn.preprocessing import RobustScaler
scaler = RobustScaler()
X_scaled = scaler.fit_transform(X)

📐 中央値の定義と数式を言葉で読み解く

中央値(median)は順序統計量の中央に位置する値で、 並べ替えたデータの「半分が上、 半分が下」を分ける点です。 サンプル数 $n$ の偶奇で定義が異なります。

$$ \text{median}(X) = \begin{cases} x_{((n+1)/2)} & (n \text{ 奇数}) \\ \dfrac{1}{2}\left( x_{(n/2)} + x_{(n/2+1)} \right) & (n \text{ 偶数}) \end{cases} $$

$$ \text{median} = \arg\min_{m} \sum_{i=1}^{n} |x_i - m| $$

🔬 数式を言葉で読み解く

記号意味具体例
$x_{(k)}$第 $k$ 順序統計量(小さい方から $k$ 番目)47 県人口で 24 番目に大きい県の値
$n$標本サイズ日本の都道府県なら $n=47$(奇数)
$(n+1)/2$奇数時の中央位置$n=47$ なら 24 番目(小さい方から)
$\arg\min_m \sum \|x_i - m\|$L1 損失最小化解「絶対値誤差の合計が最小になる m」が中央値
$\arg\min_m \sum (x_i - m)^2$L2 損失最小化(平均値)対照: 平均は二乗誤差を最小化

最後の最小化表現が重要:中央値は L1 損失の最小化解平均値は L2 損失の最小化解です。 これにより「中央値は外れ値の影響を受けにくい」という頑健性が数学的に説明できます。

🔬 数式を言葉で読み解く

前節の中央値の定義式 $\text{median}(x) = x_{((n+1)/2)}$(n 奇数)または $\frac{x_{(n/2)} + x_{(n/2+1)}}{2}$(n 偶数) を、 記号ごとに意味へ翻訳する。 中央値は「並べ替えて真ん中を取る」だけだが、 数式上は順序統計量という概念で表現される。

① 記号の意味 — 1 つずつ対応させる

記号読み方意味具体例(n=7 の場合)
$x$エックス元のデータ集合(並べる前){72, 85, 68, 91, 77, 80, 74}
$x_{(i)}$エックス カッコ アイ昇順に並べたときの i 番目(順序統計量)$x_{(1)}$=68, $x_{(2)}$=72, …, $x_{(7)}$=91
$n$エヌサンプル数7
$(n+1)/2$エヌ プラス 1 割る 2奇数のときの中央の位置インデックス(7+1)/2 = 4 → 4 番目
$n/2,\ n/2+1$エヌ割る 2、 と その次偶数のときに挟む 2 つの位置n=6 なら 3 番目と 4 番目
$\text{median}(x)$メディアン中央値(求めたい値)$x_{(4)}$ = 77

② 式全体を日本語で音読する

「データ $x$ を昇順に並べ、 並んだもの $x_{(1)} \le x_{(2)} \le \cdots \le x_{(n)}$ について、 サンプル数 $n$奇数なら ちょうど真ん中の $x_{((n+1)/2)}$ を、 偶数なら 真ん中を挟む 2 つ $x_{(n/2)}$ と $x_{(n/2+1)}$ の平均を取る。 これが中央値である」

③ 「並べて真ん中を取る」手順に翻訳

  1. Step 1: データ $x_1, \ldots, x_n$ を集める
  2. Step 2: 小さい順に並べ替え($x_{(1)} \le x_{(2)} \le \cdots \le x_{(n)}$ を作る)
  3. Step 3: $n$ が奇数なら $(n+1)/2$ 番目の値を取る
  4. Step 4: $n$ が偶数なら $n/2$ 番目と $n/2+1$ 番目の平均を取る

④ なぜ「順序統計量」という回りくどい表記が必要なのか

$x_i$(元の i 番目)と $x_{(i)}$(並べ替え後の i 番目)は別物。 例えば $x_3$ は「3 番目に観測した値」(=68)だが $x_{(3)}$ は「3 番目に小さい値」(=74)。 カッコの有無で意味が変わるため、 中央値の定義では必ず $x_{(i)}$ を使う。 これにより「並べ替えた後の真ん中」を厳密に指定できる。

🧮 計算ステップ — 7点抽出データで手計算

47都道府県データから等間隔で7県を抜き出して、 中央値を手で計算してみましょう。

1️⃣ 元のデータ(無秩序)

都道府県と住居費(千円/月):

2️⃣ 小さい順に並べ替える

順位都道府県住居費
1神奈川県11.64
2福井県13.60
3島根県15.88
4佐賀県18.47
5長崎県19.93
6鹿児島県22.96
7沖縄県27.52

3️⃣ 真ん中(4番目)が中央値

n = 7(奇数)なので、 真ん中はちょうど (n+1)/2 = 4番目。

中央値 = 18.47 千円

4️⃣ もし n が偶数だったら?

n=6(例:上の表から最後を除く)の場合、 真ん中が「ない」。 そこで 3番目と4番目の平均を取ります:

🧮 SSDSE-B を使った中央値の実例 — 総人口

SSDSE-B-2026(2023年)の「総人口 A1101」で平均と中央値を比較し、 中央値の有用性を確認します。 人口は東京都という強い外れ値をもつ右に歪んだ分布の典型例です。

① 平均 vs 中央値の比較

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
latest = df[df['SSDSE-B-2026'] == 2023]  # 最新年度
pop = latest['A1101'].dropna()  # 総人口

print(f'n = {len(pop)}')
print(f'平均   = {pop.mean():,.0f}')
print(f'中央値 = {pop.median():,.0f}')
print(f'最大値 = {pop.max():,.0f}(東京)')
print(f'最小値 = {pop.min():,.0f}(鳥取)')
print(f'歪度  = {pop.skew():.3f}')
📤 実行例(実測) n = 47 平均 = 2,645,809 中央値 = 1,549,000 最大値 = 14,086,000(東京) 最小値 = 537,000(鳥取) 歪度 = 2.293

結果:平均 = 2,645,809(約 265 万人)、 中央値 = 1,549,000(約 155 万人)、 歪度 = 2.29。 平均 > 中央値 で右に大きく歪んだ分布(東京都の人口が突出)。 「典型的な県の人口」を語るなら中央値の方が実態を反映する。

② 外れ値の影響シミュレーション

1
2
3
4
5
6
7
import numpy as np
# 仮に「東京都の人口が突然3倍になった」と仮定
pop_extreme = pop.copy()
pop_extreme[pop_extreme.idxmax()] *= 3
print(f'平均  (元) = {pop.mean():.1f} → (変動後) {pop_extreme.mean():.1f}{(pop_extreme.mean()-pop.mean()):.1f} 変動)')
print(f'中央値(元) = {pop.median():.1f} → (変動後) {pop_extreme.median():.1f}{(pop_extreme.median()-pop.median()):.1f} 変動)')
# 平均は約60万人変動、 中央値は1人も動かない → ロバスト性の真髄
📤 実行例(実測) 平均 (元) = 2645808.5 → (変動後) 3245212.8(599404.3 変動) 中央値(元) = 1549000.0 → (変動後) 1549000.0(0.0 変動)

③ 四分位・MAD で頑健な散布度

1
2
3
4
5
6
7
q1, q3 = pop.quantile([0.25, 0.75])
iqr = q3 - q1
mad = (pop - pop.median()).abs().median()  # 中央絶対偏差
print(f'Q1 = {q1:.1f}, Q3 = {q3:.1f}, IQR = {iqr:.1f}')
print(f'MAD = {mad:.1f}')
print(f'SD (比較) = {pop.std():.1f}')
# 散布度の頑健指標:MAD・IQR < SD < 分散 の順にロバスト性が低下
📤 実行例(実測) Q1 = 1034000.0, Q3 = 2636500.0, IQR = 1602500.0 MAD = 623000.0 SD (比較) = 2797551.4

🧮 SSDSE-B-2026 で 47 都道府県人口の中央値を計算

🎯 このコードでやること:SSDSE-B-2026 から最新年度の 47 都道府県人口を取り出し、 平均値と中央値を計算。 東京を除外した場合の影響を比較し、 「外れ値に対するロバスト性」を実証する。

📥 入力データ

都道府県 A1101 (総人口, 2023) 東京都 14,086,000 ← 突出した外れ値 神奈川県 9,229,000 大阪府 8,763,000 愛知県 7,477,000 鳥取県 537,000 ← 最小
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
latest = latest[~latest['Prefecture'].str.contains('全国')]

pop = latest['A1101']
print(f'47 県全体  平均 = {pop.mean():>12,.0f}')
print(f'47 県全体  中央値 = {pop.median():>12,.0f}')

without_tokyo = latest[latest['Prefecture'] != '東京都']['A1101']
print()
print(f'東京除外46県 平均  = {without_tokyo.mean():>12,.0f}')
print(f'東京除外46県 中央値 = {without_tokyo.median():>12,.0f}')

print()
print(f'平均  変化率: {(without_tokyo.mean() - pop.mean()) / pop.mean() * 100:+.2f}%')
print(f'中央値 変化率: {(without_tokyo.median() - pop.median()) / pop.median() * 100:+.2f}%')

📤 実行結果

47 県全体 平均 = 2,645,809 47 県全体 中央値 = 1,549,000 東京除外46県 平均 = 2,397,109 東京除外46県 中央値 = 1,508,500 平均 変化率: -9.40% 中央値 変化率: -2.61%

💬 結果の読み方:東京(1,409 万人)を除くと平均は 9.4% も下落するが、 中央値はわずか 2.6% しか動かない。 これが中央値のロバスト性。 47 県のような「1 県だけ突出して大きい」分布では、 代表値として中央値の方が「典型的な県」を表す。 全国レベルの政策議論で平均人口を語る危険性がここに表れる。

🧮 数式に値を入れて手で計算する: 中央値の頑健性

合成データで平均と中央値を比較し外れ値の影響を計算する。

Step 1: 元データ

x = [2, 4, 7, 5, 3] 平均 = 4.2, 中央値 = 4

Step 2: 外れ値追加

x = [2, 4, 7, 5, 3, 100] 平均 = 121/6 ≈ 20.2 (跳ね上がる) 中央値 = (4+5)/2 = 4.5 (安定)

🐍 Python で再現

1
2
3
4
5
import numpy as np
x1 = np.array([2, 4, 7, 5, 3])
x2 = np.array([2, 4, 7, 5, 3, 100])
print(f"x1 平均: {x1.mean()}, 中央値: {np.median(x1)}")
print(f"x2 平均: {x2.mean():.1f}, 中央値: {np.median(x2)}")

📤 実行結果

x1 平均: 4.2, 中央値: 4.0 x2 平均: 20.2, 中央値: 4.5

💬 手計算 (Step 2) 中央値の頑健性と Python 出力が完全一致。

🐍 Python での計算

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 L322102(住居費(二人以上の世帯)) 北海道 26,730 東京都 26,457 沖縄県 27,521 …(全 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
import pandas as pd
import numpy as np
from scipy import stats

# pandas(skiprows=[1] で日本語見出し行を除外、 L322102=住居費)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
median_housing = df['L322102'].median()
print(f'住居費の中央値: {median_housing:.2f}')

# numpy
arr = np.array([1, 3, 5, 7, 9, 11])
print(np.median(arr))         # 6.0(4と8の平均)

# 軸指定
mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(np.median(mat, axis=0))  # [4, 5, 6] - 列ごと
print(np.median(mat, axis=1))  # [2, 5, 8] - 行ごと

# 欠損値を無視
arr_nan = np.array([1, 2, np.nan, 4])
print(np.nanmedian(arr_nan))   # 2.0

# 四分位
q1, q2, q3 = np.percentile(df['L322102'], [25, 50, 75])
print(f'Q1={q1:.2f}, Median={q2:.2f}, Q3={q3:.2f}')

# pandas describe(要約)
print(df['L322102'].describe())  # count/mean/std/min/25%/50%/75%/max
📤 実行例(実測) 住居費の中央値: 17722.50 6.0 [4. 5. 6.] [2. 5. 8.] 2.0 Q1=14560.75, Median=17722.50, Q3=21081.50 count 564.000000 mean 18050.629433 std 4492.240859 min 6220.000000 25% 14560.750000 50% 17722.500000 75% 21081.500000 max 34372.000000 Name: L322102, dtype: float64

箱ひげ図の描画

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) L322102(住居費(二人以上の世帯)) 北海道 5,092,000 1,681,000 26,730 東京都 14,086,000 3,205,000 26,457 沖縄県 1,468,000 350,000 27,521 …(全 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
# ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)──
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
# 「地方」は SSDSE に無い列なので、都道府県名から 8 地方区分を作る
_BLOCKS = {
    '北海道': ['北海道'],
    '東北': ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県'],
    '関東': ['茨城県', '栃木県', '群馬県', '埼玉県', '千葉県', '東京都', '神奈川県'],
    '中部': ['新潟県', '富山県', '石川県', '福井県', '山梨県', '長野県',
             '岐阜県', '静岡県', '愛知県'],
    '近畿': ['三重県', '滋賀県', '京都府', '大阪府', '兵庫県', '奈良県', '和歌山県'],
    '中国': ['鳥取県', '島根県', '岡山県', '広島県', '山口県'],
    '四国': ['徳島県', '香川県', '愛媛県', '高知県'],
    '九州・沖縄': ['福岡県', '佐賀県', '長崎県', '熊本県', '大分県', '宮崎県',
                   '鹿児島県', '沖縄県'],
}
_R = {p: g for g, ps in _BLOCKS.items() for p in ps}
df['地方'] = df['Prefecture'].map(_R)
import seaborn as sns
import matplotlib.pyplot as plt

df['地域'] = df['地方']

# 1変数の箱ひげ図
sns.boxplot(y=df['L322102'])

# カテゴリ別の箱ひげ図('地域'列は都道府県から事前に付与しておく)
sns.boxplot(x='地域', y='L322102', data=df)

# violin plot(分布の形も見える進化版)
sns.violinplot(x='地域', y='L322102', data=df, inner='quartile')

🐍 実装バリエーション — pandas / numpy / scipy / statsmodels

(A) pandas / numpy — 基本

1
2
3
4
5
6
7
import pandas as pd
import numpy as np
s = pd.Series([1, 2, 3, 100])
print(s.median())  # 2.5
print(np.median(s))  # 2.5
print(np.percentile(s, 50))  # 2.5(中央値 = 50%パーセンタイル)
print(np.quantile(s, 0.5))  # 2.5
📤 実行例(実測) 2.5 2.5 2.5 2.5

(B) scipy.stats — トリム平均・幾何平均など

1
2
3
4
5
6
from scipy import stats
data = [1, 2, 3, 4, 100]
print(stats.tmean(data, limits=(2, 50)))  # 切断平均(範囲内のみ)
print(stats.trim_mean(data, 0.1))         # 上下10%トリム
print(stats.gmean(data))                   # 幾何平均(対数正規分布向け)
print(stats.hmean(data))                   # 調和平均(比率の集約向け)
📤 実行例(実測) 3.0 22.0 4.742881219558623 2.3885350318471343

(C) statsmodels — 分位点回帰

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) 北海道 5,092,000 1,681,000 24,430 東京都 14,086,000 3,205,000 86,348 沖縄県 1,468,000 350,000 12,549 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# ── この抜粋で使うデータを用意します ──
import pandas as pd
import statsmodels.formula.api as smf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]          # 2023 年の 47 都道府県
df = df.rename(columns={'A4101': 'y', 'A1101': 'x1', 'A1303': 'x2'})
# y=出生数 を x1=総人口・x2=65歳以上人口 で説明する

# 「中央値」を目的とした回帰(外れ値に強い)
mod = smf.quantreg('y ~ x1 + x2', data=df).fit(q=0.5)
print(mod.summary())
# 通常の OLS(平均回帰)の頑健代替。 q=0.25, 0.75 で他分位点も推定可
📤 実行例(実測) QuantReg Regression Results ============================================================================== Dep. Variable: y Pseudo R-squared: 0.9061 Model: QuantReg Bandwidth: 1116. Method: Least Squares Sparsity: 2288. Date: Sun, 16 Aug 2026 No. Observations: 47 Time: 19:45:22 Df Residuals: 44 Df Model: 2 ==================================================================== …(以下略)

(D) scikit-learn — Huber 回帰(ロバスト)

1
2
3
from sklearn.linear_model import HuberRegressor
hr = HuberRegressor(epsilon=1.35).fit(X, y)
# 中央値ベースではないが、 外れ値に強い線形回帰

(E) scipy.stats による中央値検定(Mood's median test)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A4101(出生数) A4103(合計特殊出生率) B4101(年平均気温) 北海道 5,092,000 24,430 1.06 11.0 東京都 14,086,000 86,348 0.99 17.6 沖縄県 1,468,000 12,549 1.6 23.8 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# ── この抜粋で使うデータを用意します ──
# 検定の書き方を並べた早見表なので、そのまま押せるように
# SSDSE-B-2026 から 2 群・対応あり・3 群のサンプルを作る。
import numpy as np
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]          # 2023 年の 47 都道府県
temp = df['B4101'].astype(float).values          # 年平均気温
group1 = g1 = temp[:24]                          # 北海道〜静岡
group2 = g2 = temp[24:]                          # 愛知〜沖縄
group3 = g3 = df['A4103'].astype(float).values   # 合計特殊出生率
data = temp                                      # 1 標本検定用
mu0 = float(temp.mean())
# 対応のあるデータ(同じ 47 県の 2012 年と 2023 年)
_all = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
before = _all[_all['SSDSE-B-2026'] == 2012]['A1101'].astype(float).values
after = _all[_all['SSDSE-B-2026'] == 2023]['A1101'].astype(float).values
cond1, cond2, cond3 = before, after, (before + after) / 2
x = df['A1101'].astype(float).values
y = df['A4101'].astype(float).values
observed = np.array([[20, 15], [12, 18]])        # クロス集計の例

from scipy.stats import median_test
stat, p, m, table = median_test(group1, group2)
print(f'統計量 = {stat:.3f}, p = {p:.4f}')
# 2群の中央値が等しいかを検定(χ²ベース)
📤 実行例(実測) 統計量 = 9.399, p = 0.0022

🐍 中央値の信頼区間をブートストラップで推定

中央値の標本分布は理論的には複雑(順序統計量に基づく)です。 実務的にはブートストラップで信頼区間を推定するのが最も簡単で頑健です。

🎯 このコードでやること:47 都道府県人口の中央値の 95% 信頼区間を 10,000 回のブートストラップで推定し、 平均の信頼区間と比較する。

📥 入力データ:上記コードと同じ pop シリーズ(47 県人口)。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
latest = latest[~latest['Prefecture'].str.contains('全国')]
pop = latest['A1101'].values

rng = np.random.default_rng(42)
B = 10000
boot_med  = np.empty(B)
boot_mean = np.empty(B)
for b in range(B):
    sample = rng.choice(pop, size=len(pop), replace=True)
    boot_med [b] = np.median(sample)
    boot_mean[b] = sample.mean()

ci_med  = np.quantile(boot_med , [0.025, 0.975])
ci_mean = np.quantile(boot_mean, [0.025, 0.975])
print(f'中央値 95% CI: [{ci_med [0]:>12,.0f}, {ci_med [1]:>12,.0f}]  幅 {ci_med [1]-ci_med [0]:,.0f}')
print(f'平均  95% CI: [{ci_mean[0]:>12,.0f}, {ci_mean[1]:>12,.0f}]  幅 {ci_mean[1]-ci_mean[0]:,.0f}')

📤 実行結果

中央値 95% CI: [ 1,184,000, 1,931,000] 幅 747,000 平均 95% CI: [ 1,924,124, 3,503,093] 幅 1,578,969

💬 結果の読み方:中央値の CI 幅(74.7 万)は平均の CI 幅(157.9 万)の半分以下。 外れ値(東京・神奈川など)が再サンプリングのたびに含まれる/含まれないで平均は大きく振動するが、 中央値は「真ん中の県」が変わるだけで影響が小さい。 これがブートストラップで見える「中央値の標本分布が引き締まる」現象。

🐍 Wilcoxon 符号順位検定で中央値の差を検定

2 群の中央値が等しいかを検定したいとき、 正規性を仮定しないノンパラメトリック検定として Mann-Whitney U 検定(独立 2 群)や Wilcoxon 符号順位検定(対応のある 2 群)が使われます。 中央値の差をターゲットにする実務必須ツールです。

🎯 このコードでやること:SSDSE-B-2026 の 47 県を「関東 7 都県」と「東北 6 県」に分け、 人口の中央値に差があるかを Mann-Whitney U 検定で確認する。

📥 入力データ

関東 7 都県: 茨城, 栃木, 群馬, 埼玉, 千葉, 東京, 神奈川 東北 6 県: 青森, 岩手, 宮城, 秋田, 山形, 福島
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pandas as pd
from scipy.stats import mannwhitneyu

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
latest = latest[~latest['Prefecture'].str.contains('全国')]

kanto  = ['茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県']
tohoku = ['青森県','岩手県','宮城県','秋田県','山形県','福島県']

g1 = latest[latest['Prefecture'].isin(kanto )]['A1101']
g2 = latest[latest['Prefecture'].isin(tohoku)]['A1101']

print(f'関東 中央値 = {g1.median():,.0f}')
print(f'東北 中央値 = {g2.median():,.0f}')

U, p = mannwhitneyu(g1, g2, alternative='two-sided')
print(f'U 統計量 = {U}, p = {p:.4f}')

📤 実行結果

関東 中央値 = 6,257,000 東北 中央値 = 1,173,500 U 統計量 = 40, p = 0.0047

💬 結果の読み方:p = 0.0047 < 0.05 で帰無仮説(両群の分布は同じ)は棄却される。 中央値の差は 508 万人。 t 検定では東京の外れ値で平均が引っ張られるが、 Mann-Whitney U は順位ベースなのでロバストに「関東は東北より人口が大きい」と検定できる。

🐍 消費支出の中央値(時系列)と外れ年の検出

🎯 このコードでやること:SSDSE-B-2026 の年次データから、 47 都道府県の「年度ごとの消費支出中央値」を計算し、 中央絶対偏差(MAD)で外れ年度を検出する。

📥 入力データ:L3221(消費支出・二人以上の世帯)の年次系列。

 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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[~df['Prefecture'].str.contains('全国')]

# 年度ごとの消費支出中央値
yearly = df.groupby('SSDSE-B-2026')['L3221'].median()

# 中央絶対偏差 (MAD) によるロバスト外れ値検出
m   = yearly.median()
mad = (yearly - m).abs().median()
modified_z = 0.6745 * (yearly - m) / mad
outliers = yearly[modified_z.abs() > 3.5]

print('年度別 中央値 (消費支出):')
print(yearly.tail(8).to_string())
print()
print(f'中央値 {m:,.0f}, MAD {mad:,.0f}')
print(f'外れ年度: {list(outliers.index)}')

📤 実行結果

年度別 中央値 (消費支出): 2016 287325 2017 287746 2018 284659 2019 289882 2020 281343 2021 283246 2022 287781 2023 300652 中央値 287,536, MAD 1,830 外れ年度: [2023]

💬 結果の読み方:MAD ベースの修正 Z スコアでは、 2023 年度が「外れ年度」として検出される(消費支出中央値が約 30.1 万円へ急伸し |Z| > 3.5)。 一方コロナ禍の 2020 年度はむしろ低めだが |Z| < 3.5 で異常とはされない。 平均 + 標準偏差より遥かに頑健で、 時系列の異常検知では実務標準。

🎮 触って理解する — 外れ値頑健性と分布形状

このページのテーマ「中央値のロバスト性」を、 3 つの実験で手を動かして確かめます。 姉妹ページ(平均=重心の体感、 外れ値=1 点ドラッグでの検出、 四分位数=Q1/Q3 の連動)とは角度を変え、 ここでは (1) breakdown point 50% の実証(2) 歪んだ分布での「典型値」選択(3) 中央値がどの点に乗るかのステップ体感 に絞ります。 マウスでもタッチ(スマホ)でも操作できます。

① breakdown point 50% を体感 — 何点まで「汚染」に耐えるか

数直線上に架空の 9 点(10〜20 に対称配置、 初期状態では平均 = 中央値 = 15.0)が並んでいます。 点をドラッグして 1 点だけ極端な位置へ動かすと、 平均(赤実線)はズルズル引きずられるのに、 中央値(青点線)はほぼ動きません。 さらに「汚染 +1点」ボタンで大きい方の点から順に 120 へ飛ばしていくと、 4 点(44.4%)までは中央値が不動で、 5 点目(55.6%)で初めて崩壊する——これが崩壊点(breakdown point)50% の意味です。

平均 x̄
中央値
汚染数 k / n
0 / 9

読み込み中…

💬 平均の崩壊点は 0%(1 点の汚染で任意に動く)。 中央値の 50% は理論的な最大値で、 「データの半分が壊れていても中心の推定が生き残る」ことを意味します。 本文の SSDSE-B 実測例(総人口 A1101、 2023 年)でも、 東京都という 1 点の突出に対し平均は 265 万人 vs 中央値 155 万人と大きく乖離しました。

② 歪んだ分布での平均 vs 中央値 — どちらが「典型」か

右裾の長い所得型分布(架空データ、 対数正規・n=200)のヒストグラムです。 ボタンで対称分布(架空)と切り替えて、 平均中央値の位置関係、 そして「平均未満の世帯の割合」がどう変わるかを見比べてください。 この架空所得データでは平均 ≈ 502 万円に対し中央値 ≈ 399 万円で、 約 62% の世帯が「平均未満」——平均は少数の高所得に引き上げられ、 典型値としては中央値が適切です。

分布の形(いずれも架空):
平均(万円)
中央値(万円)
平均未満の割合

読み込み中…

③ 中央値の綱引き — 点を 1 つずつ追加して「どの点に乗るか」を見る

空の数直線をタップ/クリックして点を 1 つずつ置いてください(「自動で 1 点追加」でも可)。 奇数個のときは中央値が実在するデータ点そのもの(青い点)に乗り、 偶数個になるとどの点にも乗らず中央 2 点の中点へ移る——点を追加するたびに中央値が「綱引き」のように隣の点へ乗り移る様子をステップ体感できます。

現在 n = 0、 中央値 =

読み込み中…

🧠 深掘り① — なぜ動かないのか:順序だけを見る統計量

実験①で中央値が不動だった理由は、 中央値が値の大きさではなく順位だけを使うからです。 端の点をどれだけ遠くへ飛ばしても「その点が端にある」という順序情報は変わらないため、 真ん中の点は入れ替わりません。 数式で言えば、 中央値は L1 損失 $\sum_i |x_i - m|$ の最小化解であり、 その勾配は各点について $\pm 1$(点が $m$ より上か下かの符号だけ)。 外れ値がどれだけ遠くても寄与は「1 票」のままです。 一方、 平均は L2 損失 $\sum_i (x_i - m)^2$ の最小化解で、 勾配が距離に比例するため、 遠い点ほど強く平均を引っ張ります。 実験①の「引きずられる赤線」と「動かない青線」は、 この損失関数の形の違いの可視化です。

⚠️ 深掘り② — 中央値の落とし穴 2 つ

(1) 多峰分布では中央値も「典型値」にならない。 実験②は単峰の歪みでしたが、 例えば 20 代と 60 代に山が分かれる二峰の年収分布では、 中央値は 2 つの山の谷間(誰も「典型的」でない値)に落ちることがあります。 分布形状の確認(ヒストグラム・最頻値との併記)を省略して中央値だけ報告するのは危険です。

(2) グループ併合時の非加法性。 中央値はグループごとの値から全体の値を再構成できません。 架空の例:グループ A = {1, 2, 3}(中央値 2)、 グループ B = {10, 20, 30, 40}(中央値 25)を併合すると、 全体 {1, 2, 3, 10, 20, 30, 40} の中央値は 10。 サイズ加重平均 (2×3 + 25×4)/7 ≈ 15.1 とは一致しません(平均なら厳密に一致します)。 都道府県別の中央値から「全国の中央値」を合成する、 といった集計は原データに戻って計算し直す必要があります。

🚀 深掘り③ — 発展:0% と 50% の間を埋める推定量

平均(崩壊点 0%)と中央値(崩壊点 50%)は両極端で、 その中間にトリム平均(上下 α% を捨てて平均、 崩壊点 α)があります。 α=0 で平均、 α→50% で中央値に一致し、 「頑健性と効率のトレードオフ」を連続的に調整できます(体操採点の最高・最低カットが α=1/審査員数 のトリム平均)。 また実験②の発想を回帰に持ち込んだのが分位点回帰で、 条件付き平均ではなく条件付き中央値(や任意の分位点)を予測するため、 歪んだ目的変数や外れ値に強いモデルになります。 これらの体系はロバスト統計、 ばらつき側の頑健指標は MAD、 可視化は箱ひげ図を参照してください。

⚠️ 追加の落とし穴 — 中央値の実務

❌ 「中央値 = 真ん中の値」と機械的に説明
中央値の数学的定義は「累積分布関数が 0.5 となる値」または「全体を二分する値」。 単に「真ん中」と言うと、 偶数個の場合(隣接2値の平均)や同点値が多い場合の取り扱いが曖昧になる。 numpy のデフォルトは interpolation='linear' で線形補間、 statsmodels や R では他の補間法もある。 報告時には「中央値(線形補間)」のように方法を明示する。
❌ 中央値だけ報告して分布を見せない
「中央値は X」だけでは分布の形が分からない。 必ず四分位(Q1, Q3)・IQR・最大最小を併記、 さらに箱ひげ図・ヒストグラムを描く。 「平均と中央値の差」を見せると分布の歪みが伝わる。 例:「平均年収300万、 中央値280万、 IQR=200-400万」のように 5数要約 (Tukey の5番組) で報告するのが標準。
❌ 中央値同士を足したり差をとったり
中央値は線形性を満たさない。 median(X+Y) ≠ median(X) + median(Y) が一般的。 平均は線形だが、 中央値はそうでない。 例:所得の中央値と支出の中央値の差を「中央値貯蓄」と呼ぶのは数学的に誤り。 個別レコードで「所得−支出」を計算してから中央値を取る、 が正しい手順。 SQL や Excel の集計でやりがちなミス。
❌ 標準誤差の計算を忘れる
中央値も標本統計量だから不確実性がある。 中央値の SE は「$1.253 \sigma/\sqrt{n}$」が正規分布での近似。 一般にはブートストラップで信頼区間を計算する:scipy.stats.bootstrapsklearn.utils.resample。 中央値を点推定でだけ報告するのは不十分。 「中央値 280 万(95% CI [260, 295])」のように区間も併記。
❌ サンプルサイズ小での過信
n が小さい(n < 30)と中央値の SE は大きく不安定。 さらに離散値が多い場合は同点値で中央値が「飛び」を見せる。 n=47 都道府県でも、 中央値は外れ値1個では動かないが、 中央付近の値の小さな変動で動く。 平均値より安定するとはいえ、 n が小さければ信頼区間が広いことを忘れずに。
❌ 順序尺度で平均を使う
5段階リッカート尺度(1=とても不満〜5=とても満足)のような順序尺度には、 厳密には平均は使えない(間隔が等しい保証がない)。 中央値・モード・分位点を使うのが推奨。 ただし実務では「平均でいい」と慣習化されており、 学術論文でも両論ある。 報告時には「中央値(平均)」と両方並記する折衷案も。
❌ 多変量データで「中央値ベクトル」を計算
列ごとに中央値を取った結果はベクトルだが、 「多変量中央値」ではない。 多変量データには Spatial Median(幾何中央値・Weiszfeld 算法)、 Tukey の Half-space Median、 Oja Median などの拡張がある。 平均はベクトルでも自然だが、 中央値の多変量拡張は奥が深い。 「列ごとの中央値」と「真の多変量中央値」の区別が必要。

⚠️ 中央値の落とし穴(深掘り 6 件)

① 多峰分布での誤誘導
「20 代と 60 代の二峰」の年収分布の中央値は「40 代の代表値」ではなく、 ただの数学的真ん中。 ヒストグラム + 中央値の併記で誤読を防ぐ。
② 同値多数の不安定性
「アンケート 5 段階評価で 3 が 100 人」だと中央値は厳密に 3。 1 人増減するだけで動かない反面、 微小な変化を反映できない欠点も。
③ 小サンプル時の不安定
$n=5$ の中央値は 3 番目の値そのもの。 1 値変わると中央値も急変。 「ロバスト ≠ 安定」。 必ずブートストラップで CI を出す。
④ 偶数 $n$ の補間方法
$n=4$ なら 2 番目と 3 番目の平均、 が標準だが、 「2 番目の値そのもの」を採る派閥もある(lower median)。 numpy.median と statistics.median で挙動が違うので確認。
⑤ 「中央値の差」≠「個別差の中央値」
$\text{median}(X) - \text{median}(Y) \ne \text{median}(X - Y)$ が一般成立。 ペア比較が必要なら Wilcoxon 符号順位を使い、 差の中央値を直接推定する。
⑥ 加重中央値の落とし穴
頻度ウェイト付きの中央値(人口加重所得中央値など)は累積頻度 50% 点。 numpy.median では対応せず、 自前または statsmodels で重み付き計算が必要。

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

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

📍 体系階層のパス

🌐 統計・データサイエンス記述統計中心傾向中央値

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

中心に 中央値 を置き、 そこから 平均・四分位・箱ひげ図・ノンパラ検定・外れ値検出・分散 など 計 11 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語あとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。

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

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

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

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

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

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

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

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

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

🗺 中央値の周辺概念マップ

中央値は順序統計量族の中央メンバーであり、 四分位数・百分位数・最頻値・分位回帰へと自然に拡張されます。

🔗 隣接手法への橋渡し

中央値は単独で使うより、 上流のソート操作、 並列の平均・最頻値・四分位、 下流の IQR・MAD・箱ひげ図と組み合わせて使う。 外れ値に頑健な代表値として、 平均と必ずペアで報告するのが安全。 ここでは 接続 / 統合 / 比較 の 3 視点で隣接手法 5 件との関係を整理する。

① 接続 — 中央値が処理パイプラインのどこに入るか

前後関係隣接手法中央値との接続適用シーン
上流データクレンジング欠損除去・型変換が前提SSDSE 列に NaN がある場合まず除去
上流分位点中央値は q=0.5 の特殊例Q1・Q3 と組で要約統計
下流箱ひげ図中央値線を中心に IQR を描画県別人口の分布可視化
下流MAD中央値からの絶対偏差の中央値外れ値に頑健なばらつき測定
下流分位点回帰中央値回帰 (τ=0.5) として一般化所得・家賃など歪んだ目的変数

② 統合 — 中央値を他手法と組み合わせる典型レシピ

③ 比較 — 中央値と類似手法はどう違うか

手法中央値との違いいつ中央値より優先するか
平均全データの加重和÷n、 外れ値に敏感対称分布・合計に意味がある時
最頻値最も多い値、 カテゴリでも定義可名義尺度・多峰分布
トリム平均上下 k% を捨てて平均、 中央値と平均の中間外れ値が少数で大きさ既知

SSDSE-B-2026 の県別人口の中央値は約 140 万人で、 平均 269 万人と大きく異なる。 上流でソート、 中段で median + Q1 + Q3 計算、 下流で箱ひげ図に描いて東京・神奈川を外れ値マーカーで強調、 という流れがレポートの基本。

🌳 平均 vs 中央値 — 使い分けフロー

  1. 分布の形をヒストグラムで確認
    • 対称・正規分布に近い → 平均が最適
    • 歪んでいる、 裾が長い → 中央値が安全
  2. 外れ値の存在
    • なし → 平均
    • あり、 真のデータと判断 → 中央値(または変換後の平均)
    • あり、 ノイズと判断 → 外れ値除去後の平均
  3. 目的別
    • 合計が意味を持つ(売上、 給料総額)→ 平均(× n = 合計)
    • 「典型的な値」→ 中央値
    • 不確実性評価 → 平均 + 信頼区間 or 中央値 + IQR

💡 報告では両方を併記するのが最も誠実。 「平均500万円、 中央値450万円」と書けば、 分布の歪みも示唆できる。

📜 中央値の歴史

平均よりも歴史は若いですが、 「外れ値に強い代表値」として近代統計の発展に欠かせない概念に。

📝 補足:直感・落とし穴・発展をさらに深く

本ページの既存の解説に対する追記の補足です。 「直感」「落とし穴」「平均との対比」を一段深めつつ、 分位数MAD分位点回帰ロバスト統計へ橋渡しします。 数値はすべて SSDSE-B-2026(2023 年・47 都道府県・総人口 A1101)の実測、 一部の説明用データは「架空」と明記します。

🎨 直感の再確認 — 「重心」対「順位の中心」

平均はてこの支点(重心):各データを距離に比例した重みで引っ張るので、 遠い 1 点が全体を動かせます。 中央値は順位の中心:値の大小ではなく「上下どちらの側か」という 1 票だけを数えるので、 端の点がどれだけ遠くても真ん中の順位は変わりません。 これが「中央値は外れ値に頑健」「歪んだ分布の代表値に向く」ことの核心です。 対称な分布では両者はほぼ一致し(例:本ページの左右対称ウィジェット②)、 右に歪むほど 平均 > 中央値 の差が開きます(SSDSE 総人口では平均 265 万人 > 中央値 155 万人、 歪度 2.29)。 「平均と中央値の差」そのものが分布の歪みの簡易指標になります。

⚠️ 落とし穴の深掘り(重要)

① 偶数個の定義と「どの中央値か」

$n$ が偶数だと真ん中が存在しないため中央 2 値の平均を取るのが標準(例:$n=4$ なら 2・3 番目の平均)。 ただしこれは唯一の定義ではありません。 numpy.median / pandas.median は中央 2 値の平均、 Python 標準 statistics.median_low は下側の値(lower median)、 median_high は上側を返します。 関数によって偶数 $n$ の結果が変わりうるため、 報告時は「中央値(2 値平均)」のように方式を明示します。 なお SSDSE の 47 都道府県は $n=47$(奇数)なので中央値は 24 番目の県の値そのもの=この曖昧さは生じません。

② 非加法性 — 群の中央値から全体は作れない

平均は $\text{mean}(A\cup B)$ をサイズ加重平均で厳密に再構成できますが、 中央値にはこの加法性がありません。 SSDSE 実測での確認:47 都道府県全体の総人口中央値は 154.9 万人。 一方これを「三大都市圏(架空の区分でグルーピング)」ごとに中央値を出して加重平均しても、 一般にこの 154.9 万には戻りません。 「都道府県別中央値の平均 = 全国中央値」と考えるのは誤りで、 全国の中央値が欲しければ原データ 47 件に戻して計算し直すのが唯一正しい手順です(本ページウィジェット深掘り②(2)も参照)。

③ 標準誤差 — 正規近似式は歪んだ分布で過大評価

中央値の標準誤差(SE)には正規分布を仮定した近似式 $\mathrm{SE}\approx 1.2533\,\sigma/\sqrt{n}$ があります(落とし穴で既出)。 しかし右に歪んだ SSDSE 総人口では、 $\sigma$ が東京・神奈川の裾で膨らむため、 この式はSE を過大に見積もります。 実測での対比:

推定法中央値の SEコメント
正規近似 $1.2533\,\sigma/\sqrt{n}$約 51.1 万人σ が外れ値で膨張 → 過大
ブートストラップ(10,000 回)約 22.1 万人分布を仮定せず頑健。 実質半分以下
(参考)平均の SE $\sigma/\sqrt{n}$約 40.8 万人ブートSEは約 40.4 万でほぼ一致

教訓:歪んだデータの中央値には正規近似 SE を使わず、 ブートストラップで区間推定する。 本ページ「Python での計算」のブートストラップ CI(中央値 95%CI 幅 74.7 万 < 平均 157.9 万)も同じ現象を別角度で示しています。

④ 順序尺度・離散データでは中央値が主役

中央値は順序関係さえあれば定義でき、 間隔が等しい保証のない順序尺度(5 段階リッカート等)でも使えます(平均は本来使えない)。 一方、 同値が大量にある離散データでは中央値が特定の階級に「貼り付き」、 1 件の増減では動かない反面、 微小な変化を映せない硬さがあります(落とし穴②・⑥)。 尺度水準の判断は 順序尺度 を参照。

🚀 発展 — 中央値から広がる頑健統計の地図

① 分位数への一般化($Q(\tau)$)

中央値は $\tau=0.5$ の分位点 $Q(0.5)$ という特殊例に過ぎません。 $\tau=0.25,0.75$ が四分位 $Q_1,Q_3$、 一般の $\tau$ が百分位点。 累積分布関数 $F$ の逆関数 $Q(\tau)=F^{-1}(\tau)$ として統一的に定義され、 箱ひげ図はこの $Q_1,Q_2,Q_3$ を可視化したものです。

② L1 最小化 — 中央値は「絶対誤差の合計」を最小にする点

中央値は $\arg\min_m \sum_i |x_i-m|$(数式③既出)。 SSDSE 総人口で実測すると、 $m$=中央値のとき絶対偏差の総和は 約 7,627 万、 $m$=平均のときは 約 9,215 万。 中央値の方が約 1,589 万小さく、 確かに L1 損失を最小化しています。 対照的に平均は L2 損失 $\sum(x_i-m)^2$ を最小化する点で、 この損失の違いが「中央値=MAE 最適/平均=MSE 最適」という機械学習側の対応にそのまま繋がります。

③ ばらつきの頑健指標 MAD

中央値からの絶対偏差の中央値が MAD $=\text{median}(|x_i-\text{median}(x)|)$。 SSDSE 総人口の実測は MAD = 62.3 万。 正規換算 $1.4826\times$MAD = 約 92.4 万で、 外れ値に膨らんだ標準偏差 SD = 約 279.8 万の約 1/3 に収まります。 「中央値 + MAD」は「平均 ± SD」の頑健版で、 修正 Z スコア $0.6745\,(x-\text{median})/\text{MAD}$ による異常値検出は実務標準(本ページ時系列 MAD 検出で 2023 年度を検出)。

④ Hodges-Lehmann 推定量 — 中央値と平均の「良いとこ取り」

全ペア平均(Walsh 平均 $(x_i+x_j)/2$)の中央値が Hodges-Lehmann (HL) 推定量。 SSDSE 総人口の実測 HL は 約 178.1 万人で、 中央値 154.9 万と平均 264.6 万の間、 中央値寄りに位置します。 HL は中央値より統計的に効率が高い(正規分布下で漸近相対効率 ≈ 0.955、 単純中央値の 0.637 を上回る)一方、 崩壊点は約 29% と依然として頑健です。 Wilcoxon 符号順位検定に対応する位置推定量で、 ロバスト統計の古典。

⑤ 分位点回帰・ロバスト統計への発展

「条件付き中央値」を予測するのが分位点回帰($\tau=0.5$ で中央値回帰、 損失は L1)。 平均(崩壊点 0%)と中央値(崩壊点 50%)の中間を連続的に埋めるのがトリム平均・M 推定量で、 これらの体系がロバスト統計です。 中央値は「外れ値に頑健な代表値」の入口であり、 ここから MAD・分位点回帰・HL 推定・ノンパラ検定という頑健統計の地図全体へ繋がります。