|x - median| > 3 × MAD なら外れ値候補(3 シグマ則のロバスト版)scipy.stats.median_abs_deviation() または statsmodels.robust.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 の強さの源泉です。
47 都道府県の県内総生産(B4101)を考えます。 多くの県が 1〜10 兆円の範囲に集まる中で、 東京は 100 兆円を超える「超外れ値」。 標準偏差は東京 1 県の存在で大きく膨らみますが、 MAD は東京がどれだけ大きかろうと中央値からの順位でしか効かないので影響を受けません。
$n$ 個の観測 $x_1, x_2, \dots, x_n$ に対して:
$x$ が正規分布 $N(\mu, \sigma^2)$ に従うとき、 MAD と $\sigma$ の関係:
つまり「正規分布なら MAD を 1.4826 倍すれば $\sigma$ になる」。 多くのライブラリで、 MAD 計算時にこの係数を掛けてくれます。 これを正規化 MAD(NMAD)と呼ぶことも。
中央値 → 絶対値 → 中央値、 と三段階すべてが頑健な計算なので、 MAD は外れ値に対して極めて強いのです。
SSDSE-B-2026 の B4101(県内総生産)47 県の MAD を手計算で追います。
47 県の GDP をソートすると、 真ん中(24 番目)の県は奈良県の約 3.9 兆円付近。 正確には:
| 都道府県 | $x_i$(兆円) | $x_i - \tilde{x}$ | $|x_i - \tilde{x}|$ |
|---|---|---|---|
| 東京 | 113.7 | +108.84 | 108.84 |
| 大阪 | 41.2 | +36.34 | 36.34 |
| 愛知 | 40.9 | +36.04 | 36.04 |
| 神奈川 | 36.0 | +31.14 | 31.14 |
| 奈良 | 3.9 | −0.96 | 0.96 |
| 島根 | 2.7 | −2.16 | 2.16 |
| 鳥取 | 1.9 | −2.96 | 2.96 |
| …(残り 40 県)… | |||
| 指標 | 値 | 解釈 |
|---|---|---|
| 平均 $\bar{x}$ | 13.4 兆円 | 東京・大阪が引っ張り上げる |
| 中央値 $\tilde{x}$ | 4.86 兆円 | 「典型的な県」の実像 |
| 標準偏差 $\sigma$ | 22.3 兆円 | 東京 1 県でほぼ決まる |
| MAD | 1.31 兆円 | 典型的な県のばらつき |
| $1.4826 \times \mathrm{MAD}$ | ≈1.94 兆円 | 外れ値除外後の「擬似 $\sigma$」 |
解釈:標準偏差 22 兆円 vs MAD 由来の擬似 $\sigma$ 約 1.94 兆円 — 10 倍以上の差! 「都道府県 GDP の典型的なばらつきは何兆円か」と聞かれたら、 標準偏差は東京 1 県の影響を全面に押し出して 22 兆円と答え、 MAD は外れ値を排除して 1〜2 兆円と答えます。 どちらが「正しい」かは目的次第ですが、 「典型的な県の姿」を知りたいなら MAD が圧倒的に妥当。
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}")
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)")
# 東京を除いた場合、 どれだけ動くか? 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 は東京を抜いてもほぼ変わらない(数%以内)
# 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']])
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))
scipy.stats.median_abs_deviation(x) → 生(デフォルト)scipy.stats.median_abs_deviation(x, scale='normal') → 1.4826 倍statsmodels.robust.mad(x) → 1.4826 倍(デフォルト)MAD は「ロバスト統計」と呼ばれる分野の基本ツールです。 ロバスト統計の哲学は次の通り:
「データの中に少数の異常(外れ値・記入ミス・極端なケース)が混じっていても、 結果が大崩れしないような統計量を使おう。」
「データの何パーセントが汚染されたら統計量が壊れるか」を表す指標:
| 統計量 | 崩壊点 | 意味 |
|---|---|---|
| 平均 $\bar{x}$ | 0% | 1 点でも外れ値があれば任意の値に動かせる |
| 標準偏差 $\sigma$ | 0% | 同上 |
| 分散 | 0% | 同上 |
| 10% トリム平均 | 10% | 両端 10% を切り落とす |
| 中央値 | 50% | 理論的最大値 |
| MAD | 50% | 理論的最大値 |
| IQR | 25% | 第 1・第 3 四分位点が両端 25% に依存 |
MAD は理論的に最高の崩壊点(50%)を持つ統計量で、 「データの半数が偽物でも壊れない」のが強み。 これより高い崩壊点は数学的に不可能です。
「1 つの外れ値が統計量にどれだけ影響するか」を表す関数:
これが「MAD は外れ値に強い」を厳密に定式化したものです。
「外れ値の比率を変えたとき、 標準偏差と MAD がどう動くか」をシミュレーションで確認します。
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()
これが「MAD は最大 50% の汚染に耐える」の数値的証明。 実データでこの実験を行うことで、 ロバスト統計の威力を体感できます。
「外れ値に強いばらつき指標」は 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 が圧勝。
「MAD を $\sigma$ に変換するには 1.4826 を掛ければよい」 — このマジックナンバーの正体を導出します。
標準正規分布 $X \sim N(0, 1)$ について:
よって標準正規では MAD = 0.6745。 一般の $N(\mu, \sigma^2)$ では:
| 分布 | 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 そのものを報告する方が誤解を生まない。
「47 都道府県の県内総生産(GDP)の分布を、 ロバスト統計で要約する」フル工程:
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}")
# 「東京を取り除いたとき」「東京を 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 は不変
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()
# 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']])
# 主要 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))
ばらつきの指標
├── 非頑健(平均・二乗ベース)
│ ├── 分散($\sigma^2$)
│ ├── 標準偏差($\sigma$)
│ └── 変動係数($CV = \sigma/\mu$)
├── 頑健(中央値・絶対値・分位点ベース)◀ ロバスト統計
│ ├── 中央絶対偏差(MAD)◀ このページ
│ │ ├── 生の MAD
│ │ ├── 1.4826 × MAD(σ 推定)
│ │ └── Modified z-score(外れ値検出)
│ ├── 四分位範囲(IQR)
│ ├── 平均絶対偏差(MeanAD、 別概念)
│ ├── Sn 推定量・Qn 推定量
│ └── トリム標準偏差
└── 応用
├── 外れ値検出(Modified z > 3.5)
├── ロバスト回帰の初期値
├── KDE の頑健バンド幅
└── 異常検知・データクリーニング
RobustScaler は中央値と IQR を使うが、 MAD ベースのスケーリングも有効。 外れ値が多いビジネスデータ・金融データで有用。統計実務では Median Absolute Deviation(中央絶対偏差) が圧倒的に主流。 統計入門書では「Mean Absolute Deviation(平均絶対偏差)」が出ることもあるが、 ロバスト性で劣るので実用ではあまり使われない。
標準正規分布 $N(0,1)$ で、 中央値からの絶対偏差の中央値(理論値)は約 0.6745。 これは標準正規の上 4 分の 1 点(75 パーセンタイル)と一致する。 1.4826 = 1/0.6745 で、 これを掛けると正規分布のとき MAD ≈ $\sigma$。
慣例的に「中央 2 つの平均」を取る。 例えば 47 県なら奇数なので問題ないが、 46 県データなら 23 番目と 24 番目の平均が中央値。 MAD の計算でも同じ処理。
持ちません。 分散には $\mathrm{Var}(X+Y) = \mathrm{Var}(X) + \mathrm{Var}(Y) + 2\,\mathrm{Cov}(X,Y)$ という美しい性質があるが、 MAD には同様の関係はない。 これがロバスト統計が「数学的に扱いにくい」と言われる理由の一つ。
ブートストラップで計算するのが標準:データから $B = 1000$ 回再標本化し、 各回の MAD を計算、 その分布から信頼区間を取る。 解析的な公式もあるが、 実用ではブートストラップで十分。
素朴には「マハラノビス距離のロバスト版」として、 MCD(Minimum Covariance Determinant)推定量を使う。 各変数の MAD を独立に取ることもあるが、 相関を無視するため一般的でない。
(1) データに外れ値が混じる可能性、 (2) 分布が正規から大きく外れる(歪み・裾の重さ)、 (3) データクリーニング段階、 (4) ロバスト回帰のスケール推定。 「典型的な値の周りのばらつき」を知りたいときは MAD。
R では mad(x) 関数が組み込み。 デフォルトで 1.4826 倍されている。 生の MAD が欲しければ mad(x, constant=1)。
名前が紛らわしいですが別概念。 MAE(平均絶対誤差)は予測モデルの評価指標で $\frac{1}{n}\sum|y_i - \hat{y}_i|$。 MAD(中央絶対偏差)は単一変数のばらつき指標。 「絶対値の平均」と「絶対偏差の中央値」で大きく違う。
分位偏差(QD)は $(Q_3 - Q_1)/2$、 つまり IQR の半分。 MAD と並ぶロバストばらつき指標だが、 MAD のほうが理論的に扱いやすく標準的。 IQR / 1.349 ≈ $\sigma$ という近似もある(正規分布前提)。
時系列で「直近 $w$ 期の MAD」を窓スライドで計算するもの。 pandas なら series.rolling(window=20).apply(lambda x: np.median(np.abs(x - np.median(x))))。 異常検知でよく使う。
はい、 普通に定義できる。 中央値からの絶対偏差なので、 元の値の符号は関係ない。 例:気温データ(−10〜+35℃)でも問題なく計算可能。
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 は中央値ベースなので「典型県のばらつき」を反映します。
| 指標 | 計算 | 破壊点 | 効率(正規) | 解釈 |
|---|---|---|---|---|
| SD | $\sqrt{\sum(x-\bar x)^2/(n-1)}$ | 1/n | 100% | 二乗平均ベース |
| 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 による外れ値検出:
$$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 = $\sqrt{\sum(x-\bar x)^2/(n-1)}$ は外れ値自身を計算に含めるので、 「外れ値があると SD が大きくなり、 すると外れ値が z スコア的に普通に見える」。 これが masking。 MAD は外れ値の影響を有界に抑えるので、 SD ベースで隠れた外れ値も検出できます。
SSDSE-B-2026 では、 もし「東京は外れ値か?」を SD ベースで判定すると、 東京の存在が SD を吊り上げるため、 通常の閾値(3σ)に収まることがあります。 一方 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 のロバスト性の実証です。
多変量への拡張:
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 が優位。
金融
ロバストリスク指標、 ボラティリティの頑健推定。
品質管理
ロバスト管理限界、 工程能力の頑健評価。
医療検査
基準範囲の設定(中央値 ± 2.5 × MAD)。
遺伝子発現
マイクロアレイデータの正規化、 ロバスト Z 変換。
画像処理
ノイズ推定(特に MAD は Wavelet 領域で標準)。
天文学
バックグラウンドスペクトル推定のロバスト分散。
社会調査
所得格差指標の頑健版。
機械学習
RobustScaler、 外れ値検出の標準前処理。
$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 が頻発します。 対策として: