論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説(ジャストインタイム型データサイエンス教育)
四分位・IQR・パーセンタイル
Quartiles, IQR & Percentiles
順位ベースのばらつき指標 — 外れ値に頑健
記述統計順位統計頑健可視化

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

本ページでは、 順位ベースの記述統計を統合的に解説します。 四分位四分位範囲 (IQR)パーセンタイル箱ひげ図外れ値検出を一気通貫で扱います。

これらは外れ値に頑健な指標で、 歪んだ分布や外れ値を含むデータの記述に最適です。 SSDSE-B のように地域差が大きいデータの可視化で頻出します。

🔖 🔖 キーワード索引(チップから該当箇所へジャンプ)

論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:

なぜ順位統計 パーセンタイル 四分位 5数要約 IQR MAD 箱ひげ図 ひげ 外れ値ルール Tukey フェンス バイオリンプロット 10分位 分位点回帰 分位点の計算方法

💡 30秒で分かる結論

🎨 直感で掴む — 1. なぜ順位ベース統計が必要か

SSDSE-B でも東京都の人口密度は他の46県と比べて極端な値で、 平均は引っ張られるが中央値は影響を受けにくい。

🌐 関連手法・派生:四分位は中央値を一般化したもの。 派生として 箱ひげ図、 上位概念として代表値、 並列概念として分散標準偏差があります。

📊 2. パーセンタイル(百分位点)

$p$-パーセンタイルとは「データの $p\%$ 以下にあたる値」。

2.1 パーセンタイルの計算方法

標本点の中間にあたるパーセンタイルは内挿で計算。 NumPy には 9 種類の方法。

1
2
3
4
5
6
import pandas as pd
import numpy as np
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
x = df['一人当たり県民所得']
print('10%, 25%, 50%, 75%, 90% パーセンタイル:')
print(np.percentile(x, [10, 25, 50, 75, 90]).round(0))

📐 3. 四分位

記号 名前 意味
$Q_1$第1四分位25パーセンタイル(下位 1/4)
$Q_2$第2四分位中央値
$Q_3$第3四分位75パーセンタイル(上位 1/4)

3.1 5数要約 (Five-Number Summary)

1
print(df['一人当たり県民所得'].describe()[['min','25%','50%','75%','max']])

3.2 実値計算

9 個のソート済みデータ [10, 20, 30, 40, 50, 60, 70, 80, 90] の四分位:

📏 4. IQR(四分位範囲)

$$\mathrm{IQR} = Q_3 - Q_1$$

4.1 MAD(Median Absolute Deviation)

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

中央値からの絶対偏差の中央値。 最も頑健な「ばらつき指標」。 1.4826·MAD で正規分布の σ を推定できる。

1
2
3
4
5
from scipy import stats
mad = stats.median_abs_deviation(df['一人当たり県民所得'])
print(f'MAD = {mad:.0f}')
print(f'σ推定 (1.4826·MAD) = {1.4826*mad:.0f}')
print(f'実 σ = {df["一人当たり県民所得"].std():.0f}')

📦 5. 箱ひげ図 (Boxplot)

5数要約と外れ値を 1 枚に集約する可視化。 群間比較に最適。

5.1 ひげの定義

ひげは「最大/最小 within フェンス」までで切る:

1
2
3
4
5
6
import seaborn as sns
import matplotlib.pyplot as plt
df['都市規模'] = pd.qcut(df['人口密度'], q=3, labels=['農村','中規模','都市'])
sns.boxplot(data=df, x='都市規模', y='一人当たり県民所得')
plt.title('都市規模別の一人当たり県民所得')
plt.show()

5.2 バイオリンプロット

箱ひげ + KDE(カーネル密度推定)。 分布形も同時に見える。

sns.violinplot(data=df, x='都市規模', y='一人当たり県民所得', inner='quartile') plt.show()

5.3 ノッチ付き箱ひげ図

中央値の信頼区間をノッチで表示。 ノッチが重ならないなら 5% で中央値に有意差あり(簡易検定)。

🚨 6. 外れ値検出ルール

6.1 Tukey のフェンス

$$\text{下限} = Q_1 - 1.5 \cdot \mathrm{IQR}, \quad \text{上限} = Q_3 + 1.5 \cdot \mathrm{IQR}$$

「3.0·IQR」を使うと「極端な外れ値」のみを検出。

1
2
3
4
5
6
q1, q3 = df['人口密度'].quantile([0.25, 0.75])
iqr = q3 - q1
lower, upper = q1 - 1.5*iqr, q3 + 1.5*iqr
outliers = df[(df['人口密度']  lower) | (df['人口密度'] > upper)]
print(f'外れ値: {len(outliers)} 件')
print(outliers[['都道府県', '人口密度']])

6.2 Z-score ルール

|z| > 3 を外れ値(正規分布なら 0.27%)。 ただし平均・σ が外れ値に引っ張られるため、 ロバスト Z-score(中央値・MAD)の方が良い。

6.3 IsolationForest(ML)

1
2
3
4
from sklearn.ensemble import IsolationForest
iso = IsolationForest(contamination=0.05, random_state=42)
df['outlier'] = iso.fit_predict(df[['一人当たり県民所得', '人口密度']])
print(df[df['outlier'] == -1][['都道府県']])

6.4 外れ値の扱い方

📈 7. 分位点回帰

OLS は条件付き「平均」を推定するが、 分位点回帰は条件付き「分位点」を推定。 不均一分散・歪んだ分布で有用。

$$\hat{\boldsymbol{\beta}}_\tau = \arg\min_{\boldsymbol{\beta}} \sum_i \rho_\tau(y_i - \mathbf{x}_i^\top \boldsymbol{\beta})$$

$\rho_\tau(u) = u(\tau - \mathbb{1}[u < 0])$(pinball loss)。

1
2
3
4
import statsmodels.formula.api as smf
for tau in [0.1, 0.5, 0.9]:
    m = smf.quantreg('持ち家比率 ~ 一人当たり県民所得 + 高齢化率', data=df).fit(q=tau)
    print(f'τ={tau}: 所得={m.params["一人当たり県民所得"]:.4f}')

📊 8. ばらつき指標の比較

指標 定義 頑健性 推奨
標準偏差$\sqrt{\mathbb{V}[X]}$弱い正規分布
IQR$Q_3 - Q_1$強い外れ値あり
MAD$\mathrm{median}(|x - \tilde{x}|)$最強外れ値多
範囲max - min最弱入門・簡易確認
変動係数$\sigma/\bar{x}$弱いスケール比較

⚠️ 9. よくある落とし穴

落とし穴 対処
パーセンタイル計算法の違いで結果ぶれinterpolation 引数を明示し、 同一の方法で比較。
外れ値を機械的に削除外れ値こそ重要情報のことも。 まず原因を調査。
小標本に Tukey ルールn < 20 では信頼性低い。 個別検討。
箱ひげ図のひげと範囲を混同ひげは「フェンス内の最小/最大」、 範囲全体ではない。
標準偏差と IQR を「同じ」扱い正規分布なら IQR ≈ 1.349σ だが歪んでいると関係性なし。
対数スケールで箱ひげ図変換後のスケールで作成し、 軸ラベルに明記。
5数要約だけで分布を語る同じ 5 数で異なる分布もある。 ヒストグラム併用。

🏋️ 10. 練習問題(SSDSE-B-2026)

Q1. すべての数値変数の 5数要約を作り、 平均と中央値が大きく乖離する変数を 3 つ挙げなさい。
1
2
3
4
5
6
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
num = df.select_dtypes(include='number')
summary = num.describe()
gap = (summary.loc['mean'] - summary.loc['50%']) / summary.loc['std']
print(gap.abs().sort_values(ascending=False).head())
Q2. 「人口密度」「一人当たり県民所得」について、 Tukey ルールで外れ値を検出し、 どの都道府県かを示しなさい。
1
2
3
4
5
6
7
8
for col in ['人口密度', '一人当たり県民所得']:
    q1, q3 = df[col].quantile([0.25, 0.75])
    iqr = q3 - q1
    lo, hi = q1 - 1.5*iqr, q3 + 1.5*iqr
    out = df[(df[col]  lo) | (df[col] > hi)]
    print(f'{col}: 外れ値 {len(out)} 件')
    print(out[['都道府県', col]])
    print()
Q3. 持ち家比率を被説明変数、 所得を説明変数として、 τ=0.1, 0.5, 0.9 の分位点回帰を行い、 係数の違いを解釈しなさい。
1
2
3
4
import statsmodels.formula.api as smf
for tau in [0.1, 0.5, 0.9]:
    m = smf.quantreg('持ち家比率 ~ 一人当たり県民所得', data=df).fit(q=tau)
    print(f'τ={tau}: β_所得 = {m.params["一人当たり県民所得"]:.4f}')

📝 11. 報告フォーマット

❌ NG例

「東京は外れ値なので除外しました。」

✅ OK例

「人口密度の 5数要約は (最小 62, Q1 178, 中央 264, Q3 421, 最大 6,402)、 IQR = 243。 Tukey の上限 786 を超える観測値が 1 件(東京都)。 ただし東京都の高密度はデータの構造的特徴であり、 削除は不適切と判断。 代わりに log 変換(変換後の歪度 0.2)し、 平均ではなく中央値・IQR で記述、 回帰は分位点回帰で頑健に推定した。」

🐍 12. ライブラリ早見表

用途 関数
パーセンタイルnp.percentile, pd.Series.quantile
5数要約df.describe()
IQRscipy.stats.iqr
MADscipy.stats.median_abs_deviation
箱ひげ図matplotlib.pyplot.boxplot, seaborn.boxplot
バイオリンseaborn.violinplot
分位点回帰statsmodels.formula.api.quantreg
IsolationForestsklearn.ensemble.IsolationForest
LOFsklearn.neighbors.LocalOutlierFactor
ウィンザライズscipy.stats.mstats.winsorize

📜 13. 順位統計・箱ひげ図の歴史

💼 14. 実務応用

📚 15. 補足:応用と理論

15.1 経験累積分布関数 (ECDF)

標本データの累積確率:

$$\hat{F}_n(x) = \frac{1}{n}\sum_{i=1}^{n} \mathbb{1}[X_i \le x]$$

ECDF をプロットすれば、 全ての分位点・パーセンタイルを視覚的に読み取れる。

1
2
3
4
5
6
7
8
import numpy as np, matplotlib.pyplot as plt
x = np.sort(df['一人当たり県民所得'].values)
ecdf = np.arange(1, len(x)+1) / len(x)
plt.step(x, ecdf, where='post')
plt.title('ECDF: 一人当たり県民所得')
plt.xlabel('値'); plt.ylabel('累積確率')
plt.grid(True)
plt.show()

15.2 Hyndman–Fan の 9 タイプ

パーセンタイル定義には複数あり、 NumPy/SciPy/R/Excel で結果が微妙に違う。

15.3 ノンパラ分位点の信頼区間

ブートストラップで分位点の 95% 信頼区間を推定:

1
2
3
4
import numpy as np
rng = np.random.default_rng(42)
boot = [np.median(rng.choice(df['持ち家比率'], size=len(df), replace=True)) for _ in range(1000)]
print(f'中央値 95% CI: [{np.percentile(boot, 2.5):.2f}, {np.percentile(boot, 97.5):.2f}]')

15.4 順位相関(Spearman)

順位ベースの相関係数。 外れ値・非線形関係に頑健。

1
print(df[['一人当たり県民所得','人口密度']].corr(method='spearman'))

✅ 16. 順位統計チェックリスト

🔬 17. パーセンタイル計算法の数値差

9種類のメソッドで結果がどのくらい違うかを比較:

1
2
3
4
5
6
import numpy as np
x = df["一人当たり県民所得"].values
for m in ['lower', 'higher', 'nearest', 'midpoint', 'linear']:
    q1 = np.percentile(x, 25, method=m)
    q3 = np.percentile(x, 75, method=m)
    print(f'method={m}: Q1={q1:.0f}, Q3={q3:.0f}, IQR={q3-q1:.0f}')

🔖 キーワード索引(拡張版 — 四分位・IQR)

分位点の定義・補間方法、 箱ひげ図、 外れ値検出を一気に把握。

SSDSE-B 実値 Q1/Q3 中央値 分位点補間法 Tukey の 1.5 IQR 箱ひげ図 外れ値 MAD 分位点定義差 小標本 numpy pandas scipy.stats

🧮 SSDSE-B-2026 実値計算例 — 「平均所得」の Q1/Q2/Q3 と IQR

47 都道府県の平均所得分布を四分位で記述し、 外れ値(Tukey フェンス)を抽出します。

指標 SSDSE-B 概算値 解釈
Q1(25%点)≈ 290 万円下位 1/4 県の境
Q2(中央値)≈ 310 万円中央 24 番目の県
Q3(75%点)≈ 340 万円上位 1/4 県の境
IQR≈ 50 万円中央 50% の幅
下フェンス Q1−1.5·IQR≈ 215 万円これ以下は外れ値候補
上フェンス Q3+1.5·IQR≈ 415 万円東京などが該当しがち
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
x = df['平均所得'].dropna()
q1, q2, q3 = x.quantile([0.25, 0.5, 0.75])
iqr = q3 - q1
low, high = q1 - 1.5 * iqr, q3 + 1.5 * iqr
print(f'Q1={q1:.0f}, Q2={q2:.0f}, Q3={q3:.0f}, IQR={iqr:.0f}')
print(f'下フェンス={low:.0f}, 上フェンス={high:.0f}')
outliers = df.loc[(x < low) | (x > high), ['都道府県','平均所得']]
print('外れ値県:'); print(outliers)

⚠️ 落とし穴(補強版 — 四分位・IQR で踏みやすい7つの罠)

① 分位点の定義差を意識しない(Type 1〜9)
分位点の計算には Hyndman & Fan (1996) の 9 種類の定義があり、 numpy のデフォルトは Type 7(線形補間)、 R のデフォルトも Type 7、 SPSS は Type 6、 SAS は Type 5 とソフトごとに違います。 同じデータでも Q1 の値が微妙に変わるので、 論文では method='linear' など使用法を明示すること。 numpy 1.22 以降は numpy.quantile(method=...) で 9 種類全部選べます。
② Tukey の 1.5·IQR を「絶対の外れ値基準」と思う
1.5·IQR は正規分布なら約 99.3% を覆う経験則で、 「これ以下/以上は必ず異常」ではありません。 歪んだ分布、 ロングテール、 多峰性のあるデータでは正常な観測まで「外れ値」とラベルされてしまう。 SSDSE-B の所得分布は右裾の長い対数正規型なので、 Tukey フェンスは構造的に上側で多めに引っかかる。 外れ値検出の規準は分布の形状に合わせて選ぶべきです。
③ 小標本(n < 10)で四分位を信用する
サンプル数が少ないと、 分位点の推定誤差が大きく、 補間法の選択で値が大きく変わります。 n < 10 の四分位は「目安」程度に。 n=4〜5 だと「中央値と最大・最小しか実質情報がない」状態になります。 SSDSE-B(n=47)程度なら分位点は信頼できますが、 サブグループ分析(例:北海道地方 7 県)では注意が必要。 必ず n を併記しましょう。
④ IQR と SD を「同じばらつき指標」と等価扱い
IQR と標準偏差(SD)はどちらも分布の広がりを測りますが、 性質が違います。 正規分布なら IQR ≈ 1.349·SD ですが、 ロングテール分布では IQR は SD よりずっと小さい(外れ値の影響を受けない)。 「IQR=10、 SD=30 だからおかしい」は誤った直感で、 むしろ「SD が大きいのは外れ値の影響、 IQR がコア構造」と読むのが正しい。
⑤ 箱ひげ図のひげの定義を統一しない
ひげの定義はソフト・流派ごとに違います:(i) Tukey 流(最後の非外れ値)、 (ii) Min/Max(外れ値概念なし)、 (iii) ±1.5·IQR(厳密フェンス)。 同じ「箱ひげ図」でも見え方が違います。 論文に箱ひげ図を載せるなら、 凡例にひげの定義を明記。 matplotlib の whis= 引数で挙動を制御できます。
⑥ 外れ値を「機械的に削除」する
「IQR フェンス外を削除」は乱暴で、 重要な信号(東京のような構造的特徴)まで捨ててしまうことがあります。 削除する前に「なぜその値か」を調べ、 計測ミスなのか、 真の極値なのかを判別する。 真の極値なら、 ロバスト回帰(quantile regression、 Huber)で対応し、 削除はしない。 「データクリーニング」と称した情報の喪失は分析者の責任です。
⑦ 加重データに通常の四分位を使う
調査ウェイト付きデータ(標本調査の都道府県別人口比例等)に、 ウェイト無視の numpy.quantile を使うと不偏推定になりません。 加重分位点(weighted quantile)が必要。 statsmodels.stats.weightstats.DescrStatsWnumpy.percentile は加重対応不十分なので、 pandas.Series.quantile(weights=...) (pandas 2.x 以降)または自前で計算する必要があります。

🐍 Python 実装バリエーション(numpy / pandas / scipy / statsmodels)

🅰️ numpy.quantile — 9 種類の補間法

1
2
3
4
5
import numpy as np
x = df['平均所得'].dropna().values
for m in ['linear', 'lower', 'higher', 'midpoint', 'nearest']:
    q1, q3 = np.quantile(x, [0.25, 0.75], method=m)
    print(f'{m}: Q1={q1:.1f}, Q3={q3:.1f}, IQR={q3-q1:.1f}')

🅱️ pandas の quantile / describe

1
2
3
import pandas as pd
print(df['平均所得'].describe())   # min/Q1/Q2/Q3/max
print(df['平均所得'].quantile([0.1, 0.25, 0.5, 0.75, 0.9]))

🅲 scipy.stats.iqr

1
2
3
from scipy import stats
print('IQR:', stats.iqr(x))
print('IQR(rng=10-90):', stats.iqr(x, rng=(10, 90)))  # 範囲を変えられる

🅳 ロバストな外れ値判定(MAD ベース)

1
2
3
4
5
6
7
import numpy as np
median = np.median(x)
mad = np.median(np.abs(x - median))
# MAD ベースの外れ値判定(Hampel 法、 |z| > 3.5 を外れ値)
modified_z = 0.6745 * (x - median) / mad
outlier_idx = np.where(np.abs(modified_z) > 3.5)[0]
print('外れ値インデックス:', outlier_idx)

📦 分位点・ばらつき指標早見表

指標 特徴 外れ値感度
分散・SD数値計算が易高(弱い)
IQR (Q3−Q1)中央50%低(強い)
MAD中央値からの中央絶対偏差最低(最強)
範囲(max−min)直感的最高(最弱)
十分位範囲(P90−P10)中央 80%
変動係数 CV単位なしの相対指標