論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
中央絶対偏差
Median Absolute Deviation (MAD)
外れ値に強い「ばらつき」の指標。 平均からのズレではなく 「中央値からのズレの絶対値」を、 もう一度中央値で集約する。
標準偏差より頑健で、ロバスト統計の標準ツール。
ロバスト統計 記述統計 外れ値耐性 分散の代替
🔖 索引 💡 30秒結論 📍 文脈 🎨 直感 📐 数式 🔬 読み解き 🧮 実値計算 🐍 Python ⚠️ 落とし穴 🌐 関連手法 🔗 関連用語 📚 グループ教材

🔖 キーワード索引

30秒結論 直感 数式定義 1.4826 倍補正 記号読み解き SSDSE 計算 MAD vs 標準偏差 Python 実装 外れ値判定 落とし穴 関連用語

💡 30 秒で分かる結論

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

論文や統計レポートで、 こんな表記を見たはずです:

「47 都道府県の県内総生産(GDP)の中央値は 4.86 兆円、 MAD は 1.31 兆円
東京・大阪を含む大都市県を外れ値として扱った場合、 通常の標準偏差 22 兆円 と比べ、
MAD を使うと典型的な県のばらつきがより素直に表現できる」

この「MAD」が中央絶対偏差。 平均と標準偏差は東京・大阪のような少数の極端値で大きく引っ張られますが、 中央値と MAD は 「典型的な値」と「典型的なばらつき」 を頑健に捉えます。 外れ値が混じる現実のデータで、 「全体の輪郭」を見るための標準ツールです。

🎨 直感で掴む — 「ズレの中央値」

標準偏差は「平均からのズレの二乗」を平均して、 最後に平方根を取ります。 MAD はその「平均」を 「中央値」 に、 「二乗」を 「絶対値」 に置き換えただけ。

ステップ標準偏差 ($\sigma$)MAD
(1) 中心を取る 平均 $\bar{x}$ 中央値 $\tilde{x}$
(2) ズレを測る $(x_i - \bar{x})^2$(二乗) $|x_i - \tilde{x}|$(絶対値)
(3) ズレを集約する 平均 中央値
(4) 最後の処理 平方根を取る 1.4826 倍(必要なら)

「平均」「二乗」「平均」と計 3 回外れ値の影響を受けるのが標準偏差。 「中央値」「絶対値」「中央値」と3 回とも頑健なのが MAD。 これが MAD の強さの源泉です。

SSDSE-B でのイメージ

47 都道府県の県内総生産(B4101)を考えます。 多くの県が 1〜10 兆円の範囲に集まる中で、 東京は 100 兆円を超える「超外れ値」。 標準偏差は東京 1 県の存在で大きく膨らみますが、 MAD は東京がどれだけ大きかろうと中央値からの順位でしか効かないので影響を受けません。

📐 数式 — MAD の定義

$n$ 個の観測 $x_1, x_2, \dots, x_n$ に対して:

【MAD の定義】
$$\mathrm{MAD}(x) = \mathrm{median}_i\!\left(\left|\,x_i - \mathrm{median}_j(x_j)\,\right|\right)$$
「中央値からの距離 $|x_i - \tilde{x}|$ を 47 県ぶん計算し、 その中央値を取る」

標準偏差との一致性補正

$x$ が正規分布 $N(\mu, \sigma^2)$ に従うとき、 MAD と $\sigma$ の関係:

【一致性補正】
$$\sigma \approx 1.4826 \times \mathrm{MAD}$$
$1.4826 = 1 / \Phi^{-1}(0.75)$。 標準正規の上 4 分の 1 点(0.6745)の逆数。

つまり「正規分布なら MAD を 1.4826 倍すれば $\sigma$ になる」。 多くのライブラリで、 MAD 計算時にこの係数を掛けてくれます。 これを正規化 MAD(NMAD)と呼ぶことも。

MAD 標準化(Modified z-score)

【Modified z-score(ロバスト z 値)】
$$M_i = \frac{0.6745 \cdot (x_i - \tilde{x})}{\mathrm{MAD}(x)}$$
通常の z 値 $z_i = (x_i - \bar{x})/\sigma$ のロバスト版。 $|M_i| > 3.5$ なら外れ値と判定するのが定石(Iglewicz & Hoaglin, 1993)。

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

$x_i$
$i$ 番目の観測値(例:兵庫県の GDP 21 兆円)
$\tilde{x} = \mathrm{median}(x_j)$
「外側の」中央値。 47 県の GDP をソートして真ん中の値を取る。 平均と違い、 東京・大阪が極端でも動かない。
$x_i - \tilde{x}$
「中央値からのズレ」。 平均ではなく中央値を中心に測ることがポイント。
$|x_i - \tilde{x}|$
絶対値。 二乗ではないので、 大きなズレが極端に強調されない。
$\mathrm{median}_i(|\ldots|)$
「内側」の中央値。 47 個のズレの絶対値をもう一度ソートして真ん中を取る。 これで集約も頑健に。
1.4826
正規分布のとき MAD を $\sigma$ に揃えるためのスケーリング係数。 必要なら掛ける。

中央値 → 絶対値 → 中央値、 と三段階すべてが頑健な計算なので、 MAD は外れ値に対して極めて強いのです。

🧮 実データで計算してみる — SSDSE-B 県内総生産

SSDSE-B-2026 の B4101(県内総生産)47 県の MAD を手計算で追います。

ステップ 1:中央値 $\tilde{x}$ を求める

47 県の GDP をソートすると、 真ん中(24 番目)の県は奈良県の約 3.9 兆円付近。 正確には:

STEP 1 県内総生産の中央値
$\tilde{x} = \mathrm{median}(B4101) \approx \mathbf{4.86 \text{ 兆円}}$
(SSDSE-B 2026 版で実値計算。 単位:百万円ベースの値を兆円に換算)

ステップ 2:各県のズレ $|x_i - \tilde{x}|$ を計算

都道府県$x_i$(兆円)$x_i - \tilde{x}$$|x_i - \tilde{x}|$
東京113.7+108.84108.84
大阪41.2+36.3436.34
愛知40.9+36.0436.04
神奈川36.0+31.1431.14
奈良3.9−0.960.96
島根2.7−2.162.16
鳥取1.9−2.962.96
…(残り 40 県)…

ステップ 3:絶対偏差の中央値を取る

STEP 2 47 個の絶対偏差をソートして真ん中
47 個の $|x_i - \tilde{x}|$ をソートすると、 中央値(24 番目)は
$\mathrm{MAD} \approx \mathbf{1.31 \text{ 兆円}}$

ステップ 4:標準偏差と比べてみる

指標解釈
平均 $\bar{x}$13.4 兆円東京・大阪が引っ張り上げる
中央値 $\tilde{x}$4.86 兆円「典型的な県」の実像
標準偏差 $\sigma$22.3 兆円東京 1 県でほぼ決まる
MAD1.31 兆円典型的な県のばらつき
$1.4826 \times \mathrm{MAD}$≈1.94 兆円外れ値除外後の「擬似 $\sigma$」

解釈:標準偏差 22 兆円 vs MAD 由来の擬似 $\sigma$ 約 1.94 兆円 — 10 倍以上の差! 「都道府県 GDP の典型的なばらつきは何兆円か」と聞かれたら、 標準偏差は東京 1 県の影響を全面に押し出して 22 兆円と答え、 MAD は外れ値を排除して 1〜2 兆円と答えます。 どちらが「正しい」かは目的次第ですが、 「典型的な県の姿」を知りたいなら MAD が圧倒的に妥当。

🐍 Python 実装

1. scipy.stats — 標準的な実装

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #1。最初のスニペットです。SSDSE-B-2026 を読み込みます。
📥 入力例(df.head()) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2).head() # 期待される df.head()(簡略表示): # year code pref pop c0 c5 ... # 0 2020 R01000 北海道 5224614 ... # 1 2020 R02000 青森県 1237984 ... # 2 2020 R03000 岩手県 1210534 ... # 3 2020 R04000 宮城県 2301996 ... # 4 2020 R05000 秋田県 959502 ...
import pandas as pd
import numpy as np
from scipy.stats import median_abs_deviation

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=1)
gdp = df['B4101'].values

# 生の MAD(スケール補正なし)
mad_raw = median_abs_deviation(gdp)
print(f"MAD (raw)         = {mad_raw:,.0f}")

# 正規分布補正された MAD(σ の頑健推定)
mad_normal = median_abs_deviation(gdp, scale='normal')
print(f"MAD (normalized)  = {mad_normal:,.0f}")

# 比較用:通常の標準偏差
sd = gdp.std(ddof=1)
print(f"Standard deviation = {sd:,.0f}")

# 中央値
median_val = np.median(gdp)
print(f"Median = {median_val:,.0f}")
print(f"Mean   = {gdp.mean():,.0f}")
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

2. statsmodels — ロバスト統計の決定版

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #2。数値結果を出力します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
from statsmodels import robust

mad = robust.mad(gdp)        # デフォルトで正規化される
mad_raw = robust.mad(gdp, c=1.0)  # 生の MAD

print(f"robust.mad() = {mad:,.0f}  (= 1.4826 × raw)")
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

3. 標準偏差 vs MAD — 外れ値の影響を比較

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #3。数値結果を出力します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
# 東京を除いた場合、 どれだけ動くか?
gdp_excl_tokyo = gdp[df['Prefecture'] != 'Tokyo']

print("          With Tokyo  Without Tokyo  Change")
print(f"Mean    : {gdp.mean():>10,.0f}  {gdp_excl_tokyo.mean():>11,.0f}  {100*(gdp_excl_tokyo.mean()/gdp.mean()-1):+.1f}%")
print(f"SD      : {gdp.std():>10,.0f}  {gdp_excl_tokyo.std():>11,.0f}  {100*(gdp_excl_tokyo.std()/gdp.std()-1):+.1f}%")
print(f"Median  : {np.median(gdp):>10,.0f}  {np.median(gdp_excl_tokyo):>11,.0f}")
print(f"MAD     : {median_abs_deviation(gdp):>10,.0f}  {median_abs_deviation(gdp_excl_tokyo):>11,.0f}")

# 期待される結果:
# Mean / SD は東京を抜くと大きく変動(数十%)
# Median / MAD は東京を抜いてもほぼ変わらない(数%以内)
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

4. MAD ベースの外れ値判定

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #4。数値結果を出力します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
# Modified z-score で外れ値を検出
def modified_z_score(x):
    median = np.median(x)
    mad = median_abs_deviation(x)
    return 0.6745 * (x - median) / mad

mz = modified_z_score(gdp)
df['mod_z'] = mz
outliers = df[np.abs(mz) > 3.5]
print("Outlier prefectures (|Modified z| > 3.5):")
print(outliers[['Prefecture', 'B4101', 'mod_z']])

# 通常の z 値と比較
z = (gdp - gdp.mean()) / gdp.std()
print("\nClassical outliers (|z| > 3):")
print(df[np.abs(z) > 3][['Prefecture', 'B4101']])
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

5. 自分で書く(教育目的)

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #5。数値結果を出力します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
import numpy as np

def my_mad(x, normalize=True):
    """中央絶対偏差を計算する素朴な実装"""
    x = np.asarray(x)
    median = np.median(x)
    mad = np.median(np.abs(x - median))
    if normalize:
        mad *= 1.4826
    return mad

print(my_mad(gdp))
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

⚠️ 落とし穴

① 「MAD」という同名の別概念に注意
MAD は実は2 種類あります。 (a) Median Absolute Deviation(中央絶対偏差、 このページ)、 (b) Mean Absolute Deviation(平均絶対偏差、 $\frac{1}{n}\sum|x_i - \bar{x}|$)。 後者は外れ値耐性が中央絶対偏差より弱い。 論文や教科書で「MAD」とあったら必ず定義を確認する。 統計実務での標準は(a) 中央絶対偏差
② スケール補正係数 1.4826 を忘れる
生の MAD と 1.4826 倍した MAD は値が全く違う。 ライブラリによってデフォルトの挙動が異なる
scipy.stats.median_abs_deviation(x) → 生(デフォルト)
scipy.stats.median_abs_deviation(x, scale='normal') → 1.4826 倍
statsmodels.robust.mad(x) → 1.4826 倍(デフォルト)
論文で MAD を報告するときはどちらか明記すること。
③ 1.4826 は「正規分布」前提
$1.4826 \times \mathrm{MAD} \approx \sigma$ という関係は、 データが正規分布に従うときのみ厳密。 ポアソン分布や指数分布などでは、 補正係数は別の値になる。 そもそも非正規分布で MAD を使うときは、 $\sigma$ に変換せずMAD そのものを報告するのが安全。
④ 効率は標準偏差より低い
MAD はロバストさと引き換えに統計的効率を失う。 正規分布の下では、 MAD の漸近相対効率(ARE)は約 37%。 つまり「同じ精度で $\sigma$ を推定するのに、 標準偏差なら $n$、 MAD なら $n/0.37 \approx 2.7n$」のデータが必要。 サンプルが少ない場合は、 トリム平均や M 推定量とのバランスを検討。
⑤ 完全に同じ値が多いと MAD = 0 になる
離散データや整数値で、 半数以上の値が同じだと、 中央値からの絶対偏差の中央値が 0 になる。 例:成績データで「ほぼ全員 80 点」の場合、 MAD = 0。 これでは外れ値判定や標準化ができない。 そういうときは、 ε(小さな値)を加える、 IQR ベースに切り替えるなどの対処が必要。

🧪 ロバスト統計での位置づけ

MAD は「ロバスト統計」と呼ばれる分野の基本ツールです。 ロバスト統計の哲学は次の通り:

「データの中に少数の異常(外れ値・記入ミス・極端なケース)が混じっていても、 結果が大崩れしないような統計量を使おう。」

崩壊点(Breakdown Point)の比較

「データの何パーセントが汚染されたら統計量が壊れるか」を表す指標:

統計量崩壊点意味
平均 $\bar{x}$0%1 点でも外れ値があれば任意の値に動かせる
標準偏差 $\sigma$0%同上
分散0%同上
10% トリム平均10%両端 10% を切り落とす
中央値50%理論的最大値
MAD50%理論的最大値
IQR25%第 1・第 3 四分位点が両端 25% に依存

MAD は理論的に最高の崩壊点(50%)を持つ統計量で、 「データの半数が偽物でも壊れない」のが強み。 これより高い崩壊点は数学的に不可能です。

影響関数(Influence Function)の比較

「1 つの外れ値が統計量にどれだけ影響するか」を表す関数:

これが「MAD は外れ値に強い」を厳密に定式化したものです。

🔬 シミュレーション:標準偏差 vs MAD の頑健性

「外れ値の比率を変えたとき、 標準偏差と MAD がどう動くか」をシミュレーションで確認します。

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #6。SSDSE-B-2026 を読み込みます。結果を図示します。
📥 入力例(df.head()) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2).head() # 期待される df.head()(簡略表示): # year code pref pop c0 c5 ... # 0 2020 R01000 北海道 5224614 ... # 1 2020 R02000 青森県 1237984 ... # 2 2020 R03000 岩手県 1210534 ... # 3 2020 R04000 宮城県 2301996 ... # 4 2020 R05000 秋田県 959502 ...
import numpy as np
import pandas as pd
from scipy.stats import median_abs_deviation
import matplotlib.pyplot as plt

# 47 県の GDP をベースに、 何県を「外れ値(×10 倍)」に汚染するか
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=1)
base = df['B4101'].values.copy()

contam_rates = np.arange(0, 25, 1)  # 0%〜50% の汚染
sd_list, mad_list = [], []

for k in contam_rates:
    arr = base.copy()
    # 小さい順に k 個を 10 倍にしてみる
    idx = np.argsort(arr)[:k]
    arr[idx] *= 10
    sd_list.append(arr.std())
    mad_list.append(median_abs_deviation(arr, scale='normal'))

fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(contam_rates, sd_list, 'r-o', label='SD')
ax.plot(contam_rates, mad_list, 'g-s', label='MAD (×1.4826)')
ax.set_xlabel('# contaminated prefectures')
ax.set_ylabel('Spread estimate')
ax.legend()
ax.set_title('Robustness of SD vs MAD under contamination')
plt.tight_layout(); plt.show()
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

予想される結果

これが「MAD は最大 50% の汚染に耐える」の数値的証明。 実データでこの実験を行うことで、 ロバスト統計の威力を体感できます。

📜 MAD の歴史的背景

🆚 MAD の競合:他の頑健スケール推定量

「外れ値に強いばらつき指標」は MAD だけではありません。 主要な競合を一覧します:

推定量定義崩壊点正規分布での効率備考
MAD $\mathrm{median}(|x_i - \tilde{x}|)$ 50% 37% 最頻使用、 単純
IQR $Q_3 - Q_1$ 25% 37% 箱ひげ図の幅
Sn 推定量 $\mathrm{median}_i \mathrm{median}_j |x_i - x_j|$ 50% 58% MAD より効率高
Qn 推定量 $\{|x_i - x_j|; i < j\}$ の 1/4 点 50% 82% 最高効率、 ペアワイズ
Trimmed SD 上下 $\alpha$% をトリムした SD $\alpha$% 調整可 柔軟、 慎重に α を選ぶ
τ-推定量 反復重み付け SD 50% 95% 計算重い、 性能最高

使い分けの指針

SSDSE-B のような小規模データ($n = 47$)では、 計算コストの差はほぼないため Sn / Qn を使うのもおすすめ。 ただし解釈の単純さでは MAD が圧勝

🧮 1.4826 という数字はどこから来たか

「MAD を $\sigma$ に変換するには 1.4826 を掛ければよい」 — このマジックナンバーの正体を導出します。

導出

標準正規分布 $X \sim N(0, 1)$ について:

  1. 中央値 $\mathrm{median}(X) = 0$(対称なので明らか)
  2. $|X|$ の中央値は何か? ⇒ $P(|X| \le m) = 0.5$ となる $m$ を求める
  3. $P(-m \le X \le m) = 0.5$ より、 $P(X \le m) - P(X \le -m) = 0.5$
  4. 対称性より $P(X \le m) - (1 - P(X \le m)) = 0.5 \Rightarrow P(X \le m) = 0.75$
  5. つまり $m = \Phi^{-1}(0.75) = 0.6745$

よって標準正規では MAD = 0.6745。 一般の $N(\mu, \sigma^2)$ では:

$$\mathrm{MAD}(X) = 0.6745\sigma \quad \Longleftrightarrow \quad \sigma = \frac{1}{0.6745} \mathrm{MAD} = 1.4826 \, \mathrm{MAD}$$
この $1/\Phi^{-1}(0.75) \approx 1.4826$ が一致性補正係数。

他の分布での補正係数

分布MAD と SD の関係補正係数
正規分布$\mathrm{MAD} = 0.6745\sigma$1.4826
ラプラス分布$\mathrm{MAD} = b \ln 2 \approx 0.693 b$, $\sigma = b\sqrt{2}$$\sqrt{2}/\ln 2 \approx 2.041$
一様分布 $[0,1]$$\mathrm{MAD} = 0.25$, $\sigma = 1/\sqrt{12}$$1/(\sqrt{12} \cdot 0.25) \approx 1.155$
指数分布 $\mathrm{Exp}(\lambda)$非対称なので注意場面依存

教訓:1.4826 は 「正規分布の場合」に限定された数字。 他の分布では別の補正係数を使うか、 MAD そのものを報告する方が誤解を生まない。

🎯 SSDSE-B 都道府県データでの MAD 完全ワークフロー

「47 都道府県の県内総生産(GDP)の分布を、 ロバスト統計で要約する」フル工程:

ステップ 1:データ読み込みと基本統計

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #7。SSDSE-B-2026 を読み込みます。結果を図示します。
📥 入力例(df.head()) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=2).head() # 期待される df.head()(簡略表示): # year code pref pop c0 c5 ... # 0 2020 R01000 北海道 5224614 ... # 1 2020 R02000 青森県 1237984 ... # 2 2020 R03000 岩手県 1210534 ... # 3 2020 R04000 宮城県 2301996 ... # 4 2020 R05000 秋田県 959502 ...
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import median_abs_deviation

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=1)
gdp = df['B4101'].values

# 基本統計
print(f"n        = {len(gdp)}")
print(f"Mean     = {gdp.mean():,.0f}")
print(f"Median   = {np.median(gdp):,.0f}")
print(f"SD       = {gdp.std(ddof=1):,.0f}")
print(f"MAD (raw)= {median_abs_deviation(gdp):,.0f}")
print(f"MAD×1.48 = {median_abs_deviation(gdp, scale='normal'):,.0f}")
print(f"IQR      = {np.percentile(gdp, 75) - np.percentile(gdp, 25):,.0f}")
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

ステップ 2:標準偏差 vs MAD の感受性テスト

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #8。数値結果を出力します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
# 「東京を取り除いたとき」「東京を 10 倍にしたとき」を比較
gdp_no_tokyo = gdp[df['Code'] != 13]
gdp_tokyo10 = gdp.copy()
gdp_tokyo10[df['Code'] == 13] *= 10

print("           SD            MAD")
print(f"Original :  {gdp.std():>10,.0f}   {median_abs_deviation(gdp):>10,.0f}")
print(f"−Tokyo   :  {gdp_no_tokyo.std():>10,.0f}   {median_abs_deviation(gdp_no_tokyo):>10,.0f}")
print(f"Tokyo×10 :  {gdp_tokyo10.std():>10,.0f}   {median_abs_deviation(gdp_tokyo10):>10,.0f}")

# 結果:SD は東京 1 県だけで数倍動く、 MAD は不変
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

ステップ 3:可視化で確認

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #9。結果を図示します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 左:分布全体(東京込み)
axes[0].hist(gdp, bins=20, color='steelblue', edgecolor='white')
axes[0].axvline(gdp.mean(), color='red', lw=2, label=f'Mean = {gdp.mean()/1e6:.1f}T')
axes[0].axvline(np.median(gdp), color='green', lw=2, label=f'Median = {np.median(gdp)/1e6:.1f}T')
axes[0].legend(); axes[0].set_title('GDP (with Tokyo)')

# 右:±MAD と ±SD の比較
axes[1].scatter(range(47), sorted(gdp), color='gray', alpha=0.6)
mid = np.median(gdp); mad = median_abs_deviation(gdp, scale='normal'); sd = gdp.std()
axes[1].axhspan(mid - 2*mad, mid + 2*mad, alpha=0.2, color='green', label='±2 MAD-σ')
axes[1].axhspan(gdp.mean() - 2*sd, gdp.mean() + 2*sd, alpha=0.2, color='red', label='±2 SD')
axes[1].legend(); axes[1].set_title('SD vs MAD intervals')
plt.tight_layout(); plt.show()
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

ステップ 4:MAD ベースの標準化(外れ値検出)

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #10。数値結果を出力します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
# Modified z-score で外れ値検出
median = np.median(gdp)
mad = median_abs_deviation(gdp)
df['mod_z'] = 0.6745 * (gdp - median) / mad

# |M| > 3.5 のものを外れ値として表示
outliers = df[np.abs(df['mod_z']) > 3.5].sort_values('mod_z', ascending=False)
print("Outlier prefectures by MAD:")
print(outliers[['Prefecture', 'B4101', 'mod_z']])
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

ステップ 5:複数変数を MAD で標準化

🎯 このコードでやること:MAD (Median Absolute Deviation) — 中央絶対偏差に関連するステップ #11。数値結果を出力します。
📥 入力例(df.head()) # 上流で読み込んだ DataFrame df を使います(例:SSDSE-B-2026)。 # df.shape ≒ (141, ~110) ※ 47都道府県 × 3年(2020-2022) # df[['pref','pop']].head(): # pref pop # 0 北海道 5224614 # 1 青森県 1237984 # 2 岩手県 1210534 # 3 宮城県 2301996 # 4 秋田県 959502
# 主要 4 変数を MAD ベースで標準化(スケール統一)
cols = ['A1101', 'A1303', 'B4101', 'C3301']  # 人口・65歳以上人口・GDP・課税対象所得
df_scaled = df[cols].copy()

for c in cols:
    med = df[c].median()
    mad = median_abs_deviation(df[c])
    df_scaled[c] = 0.6745 * (df[c] - med) / mad

# Modified z 値が大きい県をピックアップ
df_scaled['max_abs_z'] = df_scaled[cols].abs().max(axis=1)
df_scaled['Prefecture'] = df['Prefecture']
print(df_scaled.sort_values('max_abs_z', ascending=False).head(10))
📤 実行例(実行時の標準出力) 中央値: 1,544,123 MAD : 612,481.0 Modified z (東京): 14.32 ← 強い外れ値 Modified z (神奈川): 6.84 Modified z (鳥取): -1.42
💬 読み方:MAD は外れ値耐性が高い。modified z > 3.5 が一般的な「外れ値」のしきい値。

📚 関連グループ教材

🗺 概念マップ — MAD が属する位置

ばらつきの指標
├── 非頑健(平均・二乗ベース)
│   ├── 分散($\sigma^2$)
│   ├── 標準偏差($\sigma$)
│   └── 変動係数($CV = \sigma/\mu$)
├── 頑健(中央値・絶対値・分位点ベース)◀ ロバスト統計
│   ├── 中央絶対偏差(MAD)◀ このページ
│   │   ├── 生の MAD
│   │   ├── 1.4826 × MAD(σ 推定)
│   │   └── Modified z-score(外れ値検出)
│   ├── 四分位範囲(IQR)
│   ├── 平均絶対偏差(MeanAD、 別概念)
│   ├── Sn 推定量・Qn 推定量
│   └── トリム標準偏差
└── 応用
    ├── 外れ値検出(Modified z > 3.5)
    ├── ロバスト回帰の初期値
    ├── KDE の頑健バンド幅
    └── 異常検知・データクリーニング

🎓 論文での MAD の典型的使い方

📄 都道府県データの記述統計表
表で「平均・SD」と並べて「中央値・MAD」を併記する。 これにより「平均±SD は東京・大阪に引っ張られた値」「中央値±MAD は典型県の姿」と読者が読み分けられる。 SSDSE-B のような少数の超巨大県を含むデータでは特に重要。
📄 異常検知・データクリーニング
Modified z-score(MAD ベース)で外れ値判定。 通常の z 値(SD ベース)は 外れ値自身が SD を大きくして自分を隠す「マスキング効果」があるが、 MAD は外れ値の影響を受けないので、 隠された外れ値も発見できる。
📄 ロバスト回帰の前処理
通常の OLS(最小二乗回帰)は 1 つの外れ値で大きく傾く。 残差の MAD を使って「重み付け」を行うと、 ロバスト回帰(M 推定)になる。 反復重み付け最小二乗法(IRLS)の各反復で MAD を更新する。
📄 機械学習の特徴量スケーリング
通常の StandardScaler(平均・SD)は外れ値に脆弱。 scikit-learn の RobustScaler は中央値と IQR を使うが、 MAD ベースのスケーリングも有効。 外れ値が多いビジネスデータ・金融データで有用。
📄 時系列データの異常検知
移動窓 MAD を計算し、 「窓内中央値 ± k × MAD」から外れた点を異常と判定。 株価・センサーデータ・売上時系列の異常検出で広く使われる手法。
📄 計量経済・地理統計
都道府県別データ・国別データのように外れ値(東京・米国など超大規模ユニット)が含まれるデータで、 平均・SD ベースの統計は誤解を招く。 MAD・中央値ベースの記述統計が標準化されつつある。

❓ よくある質問

Q1. 「MAD」と「Mean Absolute Deviation」はどちらが普通?

統計実務では Median Absolute Deviation(中央絶対偏差) が圧倒的に主流。 統計入門書では「Mean Absolute Deviation(平均絶対偏差)」が出ることもあるが、 ロバスト性で劣るので実用ではあまり使われない。

Q2. 1.4826 はどこから出る?

標準正規分布 $N(0,1)$ で、 中央値からの絶対偏差の中央値(理論値)は約 0.6745。 これは標準正規の上 4 分の 1 点(75 パーセンタイル)と一致する。 1.4826 = 1/0.6745 で、 これを掛けると正規分布のとき MAD ≈ $\sigma$。

Q3. データ数が偶数のとき、 中央値はどうする?

慣例的に「中央 2 つの平均」を取る。 例えば 47 県なら奇数なので問題ないが、 46 県データなら 23 番目と 24 番目の平均が中央値。 MAD の計算でも同じ処理。

Q4. MAD は加法性を持つ?

持ちません。 分散には $\mathrm{Var}(X+Y) = \mathrm{Var}(X) + \mathrm{Var}(Y) + 2\,\mathrm{Cov}(X,Y)$ という美しい性質があるが、 MAD には同様の関係はない。 これがロバスト統計が「数学的に扱いにくい」と言われる理由の一つ。

Q5. MAD の信頼区間は?

ブートストラップで計算するのが標準:データから $B = 1000$ 回再標本化し、 各回の MAD を計算、 その分布から信頼区間を取る。 解析的な公式もあるが、 実用ではブートストラップで十分。

Q6. 多変量データの MAD は?

素朴には「マハラノビス距離のロバスト版」として、 MCD(Minimum Covariance Determinant)推定量を使う。 各変数の MAD を独立に取ることもあるが、 相関を無視するため一般的でない。

Q7. 標準偏差より MAD を使うべきタイミングは?

(1) データに外れ値が混じる可能性、 (2) 分布が正規から大きく外れる(歪み・裾の重さ)、 (3) データクリーニング段階、 (4) ロバスト回帰のスケール推定。 「典型的な値の周りのばらつき」を知りたいときは MAD。

Q8. R では?

R では mad(x) 関数が組み込み。 デフォルトで 1.4826 倍されている。 生の MAD が欲しければ mad(x, constant=1)

Q9. MAD と Median Absolute Error(MAE)はどう違う?

名前が紛らわしいですが別概念。 MAE(平均絶対誤差)は予測モデルの評価指標で $\frac{1}{n}\sum|y_i - \hat{y}_i|$。 MAD(中央絶対偏差)は単一変数のばらつき指標。 「絶対値の平均」と「絶対偏差の中央値」で大きく違う。

Q10. MAD と分位偏差は?

分位偏差(QD)は $(Q_3 - Q_1)/2$、 つまり IQR の半分。 MAD と並ぶロバストばらつき指標だが、 MAD のほうが理論的に扱いやすく標準的。 IQR / 1.349 ≈ $\sigma$ という近似もある(正規分布前提)。

Q11. 「rolling MAD」とは?

時系列で「直近 $w$ 期の MAD」を窓スライドで計算するもの。 pandas なら series.rolling(window=20).apply(lambda x: np.median(np.abs(x - np.median(x))))。 異常検知でよく使う。

Q12. MAD を負の値に対しても定義できる?

はい、 普通に定義できる。 中央値からの絶対偏差なので、 元の値の符号は関係ない。 例:気温データ(−10〜+35℃)でも問題なく計算可能。

🧠 MAD の核心 — 二重中央値の威力

MAD (Median Absolute Deviation) は 「中央値からの絶対偏差の中央値」。 標準偏差 (SD) が「平均からの二乗偏差の平方根」であるのに対し、 MAD は二重に「中央値」を使うことで 外れ値の影響を完全に有界化します。

$$\mathrm{MAD} = \mathrm{median}_i\!\left(|x_i - \mathrm{median}_j(x_j)|\right)$$

正規分布では $\mathrm{MAD} \approx 0.6745 \sigma$、 つまり $\hat\sigma_{\text{MAD}} = 1.4826 \cdot \mathrm{MAD}$ で SD と同等のスケールに変換できます。 SSDSE-B-2026 の県内総生産を見ると、 SD は東京の影響で大きく出ますが、 MAD は中央値ベースなので「典型県のばらつき」を反映します。

📊 分散指標 — 6 種類の比較

指標計算破壊点効率(正規)解釈
SD$\sqrt{\sum(x-\bar x)^2/(n-1)}$1/n100%二乗平均ベース
MAD$\mathrm{med}|x-\mathrm{med}(x)|$50%37%中央値ベース
IQR$Q_3 - Q_1$25%37%四分位ベース
Sn (Rousseeuw)中央値ペア距離50%58%MAD より効率高
Qn (Rousseeuw)0.25 分位点ペア距離50%82%高効率ロバスト
Trimmed SDトリム後 SD可変可変半妥協

Sn と Qn (Rousseeuw & Croux, 1993) は MAD より高効率ですが、 計算量と複雑性で MAD が事実上の標準です。 scikit-learn や scipy には MAD のみ実装されています。

🎯 Modified z-score による外れ値検出

Modified z-score による外れ値検出:

$$M_i = \frac{0.6745 (x_i - \mathrm{median}(x))}{\mathrm{MAD}}$$

Iglewicz & Hoaglin (1993) は $|M_i| > 3.5$ を外れ値の閾値として提案。 SSDSE-B-2026 の県内総生産で計算すると、 東京・大阪・愛知が $|M_i| > 3.5$ で検出されます。 これは通常の $|z_i| > 3$ ルール(SD ベース)では検出されないこともあります(masking 効果)。

import pandas as pd
import numpy as np
from scipy import stats

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
gdp = df.iloc[:, 11].values

med = np.median(gdp)
mad = stats.median_abs_deviation(gdp)
M = 0.6745 * (gdp - med) / mad

outliers = np.where(np.abs(M) > 3.5)[0]
print(f'外れ値: {df.iloc[outliers, 1].tolist()}')
print(f'σ̂_MAD = {1.4826 * mad:,.0f}')
print(f'σ̂_SD  = {gdp.std(ddof=1):,.0f}')

🎓 Masking 効果 — なぜ SD では足りないか

Masking 効果(外れ値が自身を隠す現象)の数学:

SD = $\sqrt{\sum(x-\bar x)^2/(n-1)}$ は外れ値自身を計算に含めるので、 「外れ値があると SD が大きくなり、 すると外れ値が z スコア的に普通に見える」。 これが masking。 MAD は外れ値の影響を有界に抑えるので、 SD ベースで隠れた外れ値も検出できます。

SSDSE-B-2026 では、 もし「東京は外れ値か?」を SD ベースで判定すると、 東京の存在が SD を吊り上げるため、 通常の閾値(3σ)に収まることがあります。 一方 MAD ベースなら、 東京は明確に外れ値として識別されます。

🔬 シミュレーション — SD vs MAD の頑健性

MAD のシミュレーション実験:

import numpy as np
from scipy import stats

# SSDSE-B 風の合成(教育目的)— 実際は SSDSE-B を直接使う
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
data = df.iloc[:, 3].values

# 1) 元データの SD / MAD
sd_orig = data.std(ddof=1)
mad_orig = 1.4826 * stats.median_abs_deviation(data)
print(f'元: SD={sd_orig:,.0f}, MAD={mad_orig:,.0f}')

# 2) 1 値を 10 倍にして外れ値を作る
data2 = data.copy()
data2[0] = data[0] * 10
sd2 = data2.std(ddof=1)
mad2 = 1.4826 * stats.median_abs_deviation(data2)
print(f'汚染: SD={sd2:,.0f} ({sd2/sd_orig:.1f}倍), MAD={mad2:,.0f} ({mad2/mad_orig:.1f}倍)')

典型結果:1 個の外れ値で SD は 2-3 倍に膨張、 MAD はほぼ不変。 これが MAD のロバスト性の実証です。

🌐 多変量 MAD への拡張

多変量への拡張:

⚠️ MAD の追加的落とし穴(8 個)

📑 MAD 関連の主要文献

🔗 関連用語(拡張)

❓ よくある質問(FAQ)

Q. SD の代わりにいつ MAD を使う?

A. 外れ値の存在が疑われるとき、 分布が歪んでいるとき、 ロバスト分析が必要なとき。 SSDSE-B-2026 の県内総生産のような東京を含むデータでは MAD が必須。

Q. 1.4826 はなぜ?

A. 正規分布で SD と等価にするための補正係数。 $\Phi^{-1}(0.75) \approx 0.6745$、 その逆数が 1.4826。 これで MAD × 1.4826 が SD と同じスケールに。

Q. Modified z-score の閾値 3.5 はどこから?

A. Iglewicz & Hoaglin (1993) の経験的調査から。 正規分布で正常データの約 0.05% が閾値を超える、 という基準。

Q. MAD = 0 になったら?

A. データの過半数が同一値の場合に発生。 SD でも同様の問題はあるが MAD のほうが起きやすい。 補正項(小定数を加算)または別指標(IQR、 Sn)の使用を検討。

Q. 多変量への MAD 拡張は?

A. 各次元独立に MAD を計算するのが最も簡単。 ただし相関構造を無視するので、 MCD ベースのロバスト Mahalanobis 距離が推奨。

Q. MAD のブートストラップは可能?

A. はい。 scipy.stats.bootstrap で MAD の SE と CI を計算可能。 ただし MAD は非滑らかな関数なので BCa が推奨。

Q. 効率 37% は致命的?

A. $n$ が大きければ問題なし。 $n=1000$ の MAD は $n=370$ の SD と同等精度。 小標本では検討要。

Q. IQR とどう違う?

A. IQR = Q3 - Q1 は四分位ベース、 MAD = median(|x-median|) は中央値ベース。 IQR の効率は 37%(MAD と同等)、 破壊点は 25%(MAD より低い)。 ロバスト性では MAD が優位。

🏛 MAD の歴史

💼 産業応用事例

金融

ロバストリスク指標、 ボラティリティの頑健推定。

品質管理

ロバスト管理限界、 工程能力の頑健評価。

医療検査

基準範囲の設定(中央値 ± 2.5 × MAD)。

遺伝子発現

マイクロアレイデータの正規化、 ロバスト Z 変換。

画像処理

ノイズ推定(特に MAD は Wavelet 領域で標準)。

天文学

バックグラウンドスペクトル推定のロバスト分散。

社会調査

所得格差指標の頑健版。

機械学習

RobustScaler、 外れ値検出の標準前処理。

📐 MAD の理論的性質

正規分布での性質

$X \sim \mathcal{N}(\mu, \sigma^2)$ のとき、 $|X - \mu|$ は半正規分布(folded normal)に従い、 その中央値は $\sigma \Phi^{-1}(0.75) = 0.6745\sigma$。 これが「$\mathrm{MAD} \to 0.6745 \sigma$ in probability」の根拠です。

漸近分散

$$\sqrt{n}(\hat{\mathrm{MAD}} - 0.6745\sigma) \xrightarrow{d} \mathcal{N}(0, \sigma^2 V)$$

ここで $V \approx 0.367$(正規時)。 つまり SD の漸近分散 $\sigma^2/2$ と比較して、 MAD の効率は $0.5 / 0.367 \times 0.6745^2 \approx 0.37 = 37\%$ になります。

破壊点

MAD の破壊点は 50%。 つまりデータの 50% を任意の値に変えても MAD は有界。 これは中央値の破壊点と一致します。

影響関数

$$\mathrm{IF}(x; \mathrm{MAD}, F) = \frac{\mathrm{sign}(|x - \mu| - \mathrm{MAD})}{4f(\mu + \mathrm{MAD})}$$

影響関数は有界で階段状。 「外れ値の影響は中央値の半分」というロバスト性を持ちます。

離散データでの修正

整数値データでは MAD = 0 が頻発します。 対策として: