外れ値(outlier)を理解するための関連キーワードを、難易度・カテゴリで整理しました。学習順序の参考にしてください。
🍰 まずはやさしく
外れ値は、仲間から大きく離れた値のことです。
正しい分析結果を出すために使います。
テストで一人だけ点数が極端に高い人がいる例です。
外れ値の種類と、その扱い方を学びます。
外れ値(outlier)は、 他のデータから著しく離れた値です。 47都道府県データなら、 東京(人口密度が突出) や 沖縄(独自の人口構成) がしばしば外れ値として浮上します。
外れ値の正体は3パターン:(i) 入力ミス・測定エラー(除外すべき)、 (ii) システム的なエラー(要修正)、 (iii) 本当に特異な実体(東京、 沖縄 etc.、 重要な情報源)。 (iii) を機械的に除外するのは分析の改ざんに近い禁じ手です。
影響:外れ値は平均・分散・相関係数・回帰係数を強く歪めます。 一方で中央値・順位相関は外れ値に影響されにくい(ロバスト統計量)。
検出と対処:(i) 散布図と箱ひげ図で必ず可視化、 (ii) Tukey の基準(Q1−1.5·IQR より下、 Q3+1.5·IQR より上)、 (iii) Spearman 順位相関で頑健性を確認、 (iv) 外れ値含む結果と除外した結果の両方を提示する。
🍰 まずはやさしく
外れ値は、データの集まりから浮いた値です。
分析のミスを防ぐために確認します。
スマホの利用時間が極端に長い人がいる例です。
定義から具体的な使い方までを詳しく読みます。
論文中に 「外れ値」として登場する用語。
外れ値 とは:他のデータから著しく離れた値。相関係数や平均を大きく歪めることがあり、必ず散布図で確認すべき。
本ページでは「outlier」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「outlier」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
外れ値は、群れから離れた星のようなものです。
データの本当の姿を掴むために使います。
部活の練習時間だけ一人で違う人がいる例です。
図を使って、外れ値の見つけ方を考えます。
SSDSE-B-2026 の 47 都道府県人口を縦軸にプロットすると、 46 県は約 54 万〜920 万人の帯にまとまり、 東京都だけが 1,409 万人と「群れから離れた星」のように夜空に浮きます。 これが外れ値の典型像。「群れの位置(中央値)」と「群れの広がり(IQR)」を物差しにし、 そこから 1.5 倍以上離れている星を外れ値とみなす、 というのが Tukey の定義です。 ヒストグラムでは群れが山に、 外れ値が右端の小さな突起になります。
大事なのは「離れている=排除」ではない、 という思考。 東京の人口は誤入力ではなく真実です。 集計に含めると平均人口が約 265 万人と膨らみますが、 中央値 155 万人なら東京がいても揺らぎません。 つまり「平均派(外れ値の影響を受ける)」と「中央値派(影響を受けない)」を使い分けるのが、 外れ値時代の分析家の作法です。
外れ値の定義と検出方法を、 3 点の SVG で押さえる。
箱の外、 ひげの外側に出た点が外れ値候補(Q1−1.5IQR より下、 Q3+1.5IQR より上)。
標準正規分布で |Z|>3(または 2)の点を外れ値とみなす。 ただし元データが正規でないと過剰検出。
東京都が常に右上の極端値となる典型例。 平均・相関が東京 1 点に支配される。
下の数直線には説明用のサンプルデータ(11 点)が並んでいます(実測値ではなく操作体験のための架空値です)。 どれか 1 点をドラッグ(スマホは指でなぞる)して極端な位置へ動かすと、 平均・中央値・標準偏差・四分位範囲(IQR)がリアルタイムで再計算され、 外れ値と判定された点が色を変えます。 「平均は外れ値に引きずられるのに、 中央値と IQR はほとんど動かない」という頑健性(robustness)の違いを、 自分の手で確かめてください。
直感:外れ値は「群れから離れた 1 匹」。 中心を平均で測ると離れた 1 匹に手を引かれて中心がズレるが、 中央値で測れば多数派の位置が保たれます。 散らばりも同じで、 標準偏差は外れ値で膨張する一方、 IQR(真ん中 50% の幅)はほとんど動きません。 これが「頑健(robust)」という言葉の中身です。 ウィジェットで 1 点を右端へ動かすと、 赤い平均線が点を追いかけ、 緑の中央値線と青い IQR の箱がほぼ静止するのが見えます。
よくある落とし穴:外れ値 ≠ 誤りです。 SSDSE-B-2026 の東京都のように、 外れ値がむしろ最も重要な情報であることは珍しくありません。 「外れ値だから」と機械的に除去するのは、 分布を都合よく整形する改ざんに近い危険な操作です。 除去の前に必ず (1) 入力誤り・測定エラーか、 (2) 本当に特異な実体か を切り分け、 除去した場合は件数・理由・除去前後の結果を必ず併記します。 また z スコア法は、 極端な 1 点自身が平均と標準偏差を膨らませて境界を広げるため、 その点を取りこぼす(マスキング)ことがあります。 ±2σ / ±3σ を切り替えて、 IQR 法は捕まえるのに z 法が見逃す様子を確認してみてください。
発展(頑健統計):外れ値の影響を受けにくい統計量・手法を頑健統計と呼びます。 中央値・IQR・MAD(中央絶対偏差)・修正 z スコア・Huber 回帰・RANSAC などが代表例です。 「壊れにくさ」はブレークダウンポイントで測られ、 中央値は 50%(半分が外れ値でも耐える)、 平均は 0%(1 点で破綻)です。 上のウィジェットで平均線が動くのに中央値線が動じない様子は、 まさにこの差を可視化したものです。
🍰 まずはやさしく
外れ値は、数式で判定できる特別な値です。
客観的に外れ値を決めるために使います。
買い物の金額が平均よりずっと高い例です。
外れ値を判定するための3つの基準を読みます。
SSDSE-B-2026 の人口データは右に強く歪むため、 1 と 2 は東京を確実に拾うが地方の異常検出には甘い。 3 は中央値・MAD ベースで歪みに頑健、 4 は複数指標を組み合わせる際の標準。
| 記号 | 意味 | SSDSE-B-2026 での具体例 |
|---|---|---|
| $\bar{x}, s$ | 標本平均と標本標準偏差 | A1101 の 47 県平均 ≈ 265 万人、 SD ≈ 280 万人 |
| $\tilde{x}$ | 中央値(外れ値に頑健) | A1101 の中央値 ≈ 155 万人(鹿児島県あたり) |
| $Q_1, Q_3, \text{IQR}$ | 第 1 ・第 3 四分位とその差 | A1101 で IQR ≈ 160 万人。 1.5×IQR ≈ 240 万人 |
| MAD | 中央絶対偏差(ロバスト SD 代替) | A1101 の MAD ≈ 62 万人。 ÷0.6745 で SD 相当に正規化 |
| $\Sigma$ | 共分散行列(多変量の広がり) | 食料費・教育費・住居費の (3,3) 行列 |
読み方:「中央 ($\tilde{x}, Q$) からどれだけ離れているか」を「広がり (IQR, MAD)」で割って、 規格化された距離で判断する、 が外れ値検出の本質です。
describe() で外れ値判定の基本指標(平均・SD・四分位)を一望し、 さらに A1101(総人口)の箱ひげ図を眺めて視覚的に異常な県(東京都)を見つける。data/raw/SSDSE-B-2026.csv (CP932 エンコード、 2 行目に日本語見出し行があるので skiprows=[1])。 df['SSDSE-B-2026']==2023 で年度を 1 つに絞り 47 都道府県 × 1 年に整える。 注目列:A1101(総人口)。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # 基本パターン import pandas as pd import numpy as np from scipy import stats import matplotlib.pyplot as plt import seaborn as sns # データ読み込み(SSDSE-B は cp932。2 行目に日本語見出しがあるので skiprows) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 年度を 2023 年に絞る(47 行) # 基本統計量(A1101 = 総人口) print(df['A1101'].describe()) # 可視化:総人口の箱ひげ図で東京都の突出を確認 df.boxplot(column='A1101') plt.show() |
このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 関連手法を辿って学習を進めましょう。
統計データ活用コンペティションのSSDSE-B-2026データは、 47都道府県の社会経済データ。 この概念を使って以下のような分析ができます:
| 機能 | Python (pandas) | Python (scipy) |
|---|---|---|
| 要約統計 | df.describe() | stats.describe() |
| 平均 | df.mean() | np.mean() |
| 標準偏差 | df.std() | np.std() |
| 相関 | df.corr() | stats.pearsonr() |
| t検定 | — | stats.ttest_ind() |
| 回帰 | — | stats.linregress() |
| 分布フィッティング | — | stats.norm.fit() |
この概念は、 他の多くの統計概念と密接に関連しています。 ジャストインタイム型学習では、 必要に応じて関連用語へジャンプしながら全体像を構築します。
| グループ | 主要概念 |
|---|---|
| 記述統計 | 平均、 中央値、 最頻値、 分散、 標準偏差、 共分散、 相関係数 |
| 可視化 | ヒストグラム、 散布図、 箱ひげ図、 ヒートマップ |
| 推測統計 | 標本平均、 標準誤差、 信頼区間、 p値、 有意水準 |
| 確率分布 | 正規分布、 t分布、 χ²分布、 F分布、 二項分布 |
| 仮説検定 | t検定、 F検定、 χ²検定、 ノンパラ検定 |
| 回帰 | 単回帰、 重回帰、 OLS、 Ridge、 LASSO |
| 分類 | ロジスティック回帰、 決定木、 SVM、 k-NN |
| 教師なし学習 | クラスタリング、 PCA、 因子分析 |
| 時系列 | ARIMA、 VAR、 指数平滑法、 自己相関 |
| 因果推論 | DiD、 IV、 傾向スコア、 交絡変数 |
| 前処理 | 標準化、 正規化、 欠損値処理、 多重共線性対策 |
| 評価 | R²、 残差、 CV、 RMSE、 効果量 |
ここでは合成データではなく、SSDSE-B-2026 の実データ「総人口(A1101)」と、そこから導かれる「人口密度」を題材に、外れ値を見つける手順を具体的な数値で示します。
47 都道府県の人口(単位:万人、 概算値)をソートすると:
Tukey の基準で外れ値を計算:
# Q1 ≈ 103(25%点:山形・宮崎のあたり)
# Q3 ≈ 264(75%点:京都・広島のあたり)
# IQR = Q3 - Q1 ≈ 160
# 上限 = Q3 + 1.5 × IQR ≈ 264 + 240 = 504
# 下限 = Q1 - 1.5 × IQR ≈ 103 - 240 = -137 → 0 以下なので意味なし
外れ値の判定:人口 > 504 万人の都道府県
→ 東京(1409)、 神奈川(923)、 大阪(876)、 愛知(748)、 埼玉(733)、 千葉(626)、 兵庫(537)、 福岡(510)、 北海道(509)
→ 9 都道府県が「外れ値」
解釈:都市圏 9 都道府県が統計的に「外れ値」と判定されますが、これらは除外すべきではない真の特異点です。この場合、対数変換 log₁₀(人口) を施せば多くの都道府県が中央に収まり、外れ値は東京のみ(log₁₀ 1409 ≈ 7.15、 全体平均 ≈ 6.3)に縮減されます。
|Z|>3 の基準では、 東京・大阪が外れ値と判定されます。ただし、平均と標準偏差が東京自体に強く引きずられているため、 MAD ベースの修正 Z スコアで再計算すると東京の特異性がさらに鮮明になります。
1 2 3 4 5 6 7 8 9 10 | # A1101(総人口) に対する MAD ベースの修正Zスコア import numpy as np x = df['A1101'].to_numpy() med = np.median(x) mad = np.median(np.abs(x - med)) # 中央絶対偏差 mz = 0.6745 * (x - med) / mad # |修正Z| > 3.5 を外れ値とみなす flagged = df.loc[np.abs(mz) > 3.5, 'Prefecture'] print(flagged.tolist()) # 東京都が突出して検出される |
ここでは data/raw/SSDSE-B-2026.csv を実際に読み込み、 A1101(総人口)1 列に対して外れ値検出を 3 方式(IQR / Z スコア / MAD)で比較します。 同じデータでも手法によって外れ値リストがどう変わるかを 47 都道府県の固有名で確認することで、 「どの基準が業務に合うか」を直感で掴めます。
3 つのルール(IQR・Z スコア・MAD)が同じ列(総人口)に対して違う外れ値リストを返すことを実データで体感する。
data/raw/SSDSE-B-2026.csv の Prefecture 列と A1101(総人口)列。 encoding='cp932'・skiprows=[1] で読み込み、 df['SSDSE-B-2026']==2023 で年度を 1 つに絞る。
3 ルール別の外れ値フラグ表(True/False)と、 いずれかの基準で外れ値と挙がった都道府県の一覧。
東京都は総人口が突出しているため、 IQR・Z スコア・MAD のすべてで外れ値になる。 神奈川県・大阪府は平均・標準偏差ベース(Z・IQR)では挙がるが、 中央値・MAD ベースでは基準や年により境界線上になることがある。 こうした県固有の挙動を、 ルールの違いとして読み取れるようになるのが目標です。
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 | 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['SSDSE-B-2026'] == 2023] # 年度を 2023 年に固定 def by_iqr(s): q1, q3 = s.quantile([.25, .75]) iqr = q3 - q1 return (s < q1 - 1.5*iqr) | (s > q3 + 1.5*iqr) def by_z(s, k=2.5): return ((s - s.mean()) / s.std()).abs() > k def by_mad(s, k=3.5): med = s.median() mad = (s - med).abs().median() if mad == 0: return pd.Series(False, index=s.index) return (0.6745 * (s - med) / mad).abs() > k s = df['A1101'] # A1101 = 総人口 # by_* が返す Series の索引は df の行番号。そこへ index=都道府県名 を渡すと # 索引が一致せず全部 NaN になり、外れ値が 1 件も出なくなる。値だけを渡す。 flags = pd.DataFrame({ 'IQR': by_iqr(s).values, 'Zscore': by_z(s).values, 'MAD': by_mad(s).values, }, index=df['Prefecture'].values) print(flags[flags.any(axis=1)]) |
原則は「業務目的と外れ値の発生メカニズムの二軸で決める」。 計測誤差由来なら除外、 真に稀な現象なら保持。 SSDSE-B-2026 で東京都を除外するなら、 「全国を代表する分析である」と業務目的が明示できるときに限る。
標本サイズが小さく分布の歪みが大きいならMAD。 標本サイズが十分(n > 100 目安)で対称な分布なら Z スコアで良い。 IQR は読み手の直感に近く可視化との相性が良いため、 説明用にしばしば使われる。
Mahalanobis 距離 → Isolation Forest → LOF の順で試すのが効率的。 まず Mahalanobis で楕円外を抽出し、 非線形構造があれば Isolation Forest / LOF で再検査する。
外れ値を除外すると訓練 R^2 は通常上がるが、 汎化性能は下がる場合がある。 ホールドアウト test set に外れ値が含まれるなら、 訓練側だけ外しても本番では困るので「Winsorize」「ロバスト損失」を併用する。
右に裾の長い分布なら効果的。 ただし負値・ゼロを含む場合は log1p や Box-Cox を使う。 SSDSE-B-2026 の「観光客数」「事業所数」のような幅広い指標は対数化が有効。
木系(Random Forest・XGBoost)は分割で吸収するため比較的頑健。 一方、 距離ベース(k-NN・SVM)や勾配ベース(線形・ニューラル)は外れ値の影響を大きく受ける。
厳密には正規分布の仮定が前提。 SSDSE-B-2026 のように極端な歪みを持つ社会経済指標には不向きで、 IQR か MAD を使うべき。 ただし「ざっくり外れているか」のスクリーニングには手早い。
「使用した基準」「除外した観測の数と県名」「除外/保持で結論が変わるか感度分析した結果」の 3 点を最低限明示する。 これを書かない論文は再現できない。
除外せず、 むしろ主分析の主役に据える。 「東京都だけが特殊である」こと自体が政策的に重要なら、 全国平均との比較ではなく東京都を分離した分析を立てる。
n < 30 では Grubbs 検定や Dixon 検定など個別検定に頼り、 多重比較補正を入れる。 経験的ルール(IQR や 3σ)は標本数が少ないと信頼性が落ちる。
scikit-learn の Pipeline に IsolationForest や EllipticEnvelope を組み込み、 contamination パラメータを CV で選ぶ。 さらに「業務側のホワイトリスト」を併用して、 制度的に特殊な観測を自動除外しない仕組みを併設する。
常に必要というわけではない。 ロバスト回帰やランクベースの手法を使えば前処理不要。 「外れ値処理 + 通常モデル」と「外れ値処理なし + ロバストモデル」のどちらかを選ぶ、 と整理すると判断が早い。
合成データで平均 ± 3σ の範囲外を外れ値として検出する。
1 2 3 4 5 6 7 8 | import numpy as np x = np.array([50, 52, 48, 53, 49, 51, 100]) q1, q3 = np.percentile(x, [25, 75]) iqr = q3 - q1 upper = q3 + 1.5*iqr out = x[x > upper] print(f"Q1, Q3, IQR: {q1}, {q3}, {iqr}") print(f"外れ値: {out}") |
💬 手計算 (Step 3) 100 と Python 出力が完全一致。
外れ値検出には複数のライブラリが利用できます。 用途に応じて使い分けましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] x = df['A1101'].dropna() # A1101 = 総人口 # Z スコア(平均・標準偏差ベース) z = stats.zscore(x) outliers_z = df.loc[abs(z) > 3, 'Prefecture'] print('Z スコア外れ値:', outliers_z.tolist()) # Grubbs 検定(最大外れ値を 1 つ検定:scipy に直接実装がないので手計算) g = (x.max() - x.mean()) / x.std() n = len(x) t_crit = stats.t.ppf(1 - 0.05/(2*n), n-2) g_crit = (n-1)/n**0.5 * (t_crit**2/(n-2+t_crit**2))**0.5 print(f'G統計量={g:.3f}, 棄却限界={g_crit:.3f}') print('外れ値' if g > g_crit else '外れ値なし') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from sklearn.ensemble import IsolationForest 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] # 数値列(年度コード列を除く)をまとめて多変量入力に X = df.select_dtypes('number').drop(columns=['SSDSE-B-2026']) # contamination は外れ値の想定割合 clf = IsolationForest(contamination=0.1, random_state=0) clf.fit(X) out = pd.DataFrame({'Prefecture': df['Prefecture'].values}, index=X.index) out['outlier'] = clf.predict(X) # -1 = 外れ値、1 = 正常 out['score'] = clf.decision_function(X) print(out[out['outlier'] == -1].sort_values('score')) |
1 2 3 4 5 6 7 8 9 10 | from sklearn.neighbors import LocalOutlierFactor lof = LocalOutlierFactor(n_neighbors=5, contamination=0.1) labels = lof.fit_predict(X) neg_score = -lof.negative_outlier_factor_ # 大きいほど外れ値らしい result = X.copy() result['LOF_label'] = labels result['LOF_score'] = neg_score print(result.sort_values('LOF_score', ascending=False).head(10)) |
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 | import pandas as pd import statsmodels.api as sm df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] num = df.select_dtypes('number').drop(columns=['SSDSE-B-2026']).dropna() # A1101(総人口) を目的変数に、他の実在指標 2 列を説明変数として例示 y = num['A1101'] X = sm.add_constant(num.drop(columns=['A1101']).iloc[:, :2]) model = sm.OLS(y, X).fit() influence = model.get_influence() cook_d = influence.cooks_distance[0] # Cook の距離 std_resid = influence.resid_studentized_internal leverage = influence.hat_matrix_diag # レバレッジ diag = pd.DataFrame({ 'Prefecture': df.loc[num.index, 'Prefecture'].values, 'cook_d': cook_d, 'std_resid': std_resid, 'leverage': leverage, }) print(diag.sort_values('cook_d', ascending=False).head(5)) n = len(num) print(f'Cook閾値 4/n = {4/n:.4f}') print(f'Leverage閾値 2p/n = {2*3/n:.4f}') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import numpy as np import pandas as pd def modified_zscore(x): med = np.median(x) mad = np.median(np.abs(x - med)) return 0.6745 * (x - med) / mad if mad > 0 else np.zeros_like(x) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] x = df['A1101'].to_numpy() # A1101 = 総人口 mz = modified_zscore(x) result = pd.DataFrame({'Prefecture': df['Prefecture'].values, 'A1101': x, '修正Z': mz}) print(result[np.abs(result['修正Z']) > 3.5] .sort_values('修正Z', key=np.abs, ascending=False)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from sklearn.svm import OneClassSVM from sklearn.preprocessing import StandardScaler scaler = StandardScaler() Xs = scaler.fit_transform(X) oc = OneClassSVM(gamma='auto', nu=0.1) oc.fit(Xs) labels = oc.predict(Xs) # -1 = 外れ値 scores = oc.score_samples(Xs) import pandas as pd out = X.copy() out['OCSVM_label'] = labels out['OCSVM_score'] = scores print(out[out['OCSVM_label'] == -1].sort_values('OCSVM_score')) |
初学者が最も陥りやすい誤解です。外れ値には (i) 入力ミス、 (ii) 測定エラー、 (iii) 真に特異な現象、 の 3 種があり、 (iii) を機械的に除外することは 分析の改ざんに近い禁じ手 です。47 都道府県データで東京を除外すれば、 確かに数値は綺麗になりますが、 それは「日本」を分析していると言えるでしょうか。外れ値の正体を診断し、 含めた結果と除外した結果の両方を提示するのが正しい姿勢です。
「Q1 − 1.5·IQR より下、 Q3 + 1.5·IQR より上」は教科書的な目安ですが、 正規分布なら片側 0.35% 程度しか外れ値が出ない設定で、 裾の重い分布(人口、 所得、 売上)では大量の「正常な外れ値」が誤検出されます。47 都道府県の人口で 9 個も外れ値が出るのはそのためです。分布の形を確認し、 対数変換やロバスト指標と組み合わせることが必須です。
「|Z| > 3 を外れ値とする」とき、 平均と標準偏差そのものが外れ値の影響を受けています。たとえば東京を含む人口密度の平均は 660、 除外すると 540、 さらに大阪を除くと 450 と次々動きます。この循環を断ち切るのが 中央値と MAD です。修正 Z スコア(0.6745·(xᵢ − median)/MAD)は外れ値自身に汚染されない、 ロバストな検出基準です。
各変数を単独で見ると正常範囲なのに、 組み合わせて見ると異常な点が存在します。 たとえば「身長 170cm、 体重 50kg」はそれぞれ普通でも、 組み合わせとして痩せ過ぎ気味。 多変量の外れ値検出には Mahalanobis 距離 や Isolation Forest、 Local Outlier Factor など、 多変量空間での密度・距離を考慮する手法を使う必要があります。
回帰分析では「Y 方向の外れ値(残差が大きい)」と「X 方向の外れ値(説明変数が極端)」は別物です。 後者をレバレッジと呼びます。 レバレッジが高くても残差が小さければ影響は小さく、 逆にレバレッジと残差の両方が大きい点が Cook の距離 で警告される「影響点(influential point)」です。 残差プロットだけでは見つかりません。
p 値が有意にならないと外れ値を 1 個除外、 まだなら 2 個目を除外、 ……という逐次的な外れ値削除は p-hacking の典型です。事前に「Tukey の基準 + IQR 1.5 倍」など除外ルールを宣言し、 結果が変わっても固守する。 もしくは外れ値を含む結果と除外した結果の両方を併記する。 こうした透明性が再現性のある分析の要です。
時系列ではトレンド・季節性・自己相関を考慮せずに「平均 ± 3SD」を当てはめると、 トレンドの上昇局面が全部外れ値判定されたり、 季節ピークが見逃されたりします。 時系列の外れ値検出には STL 分解後の残差、 ARIMA の予測区間からの逸脱、 変化点検出(CUSUM、 PELT) など、 時間構造を扱う手法が必要です。
p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:
| 統計量 | 効果量 | 小 | 中 | 大 |
|---|---|---|---|---|
| 2群平均差 | Cohen's d | 0.2 | 0.5 | 0.8 |
| 相関 | r | 0.1 | 0.3 | 0.5 |
| 線形回帰 | R² | 0.02 | 0.13 | 0.26 |
| ANOVA | η² (eta²) | 0.01 | 0.06 | 0.14 |
| χ² | Cramér's V | 0.1 | 0.3 | 0.5 |
| ロジスティック | Odds Ratio | 1.5 | 2.5 | 4.0 |
外れ値 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 前処理 › データ品質 › 外れ値
中心に 外れ値 を置き、 そこから 箱ひげ図・標準偏差・ヒストグラム・散布図・分散・平均 など 計 7 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「外れ値」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「外れ値」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 外れ値 の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → データ品質 → 外れ値 という入れ子の位置を示します。 「データ品質には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。
「外れ値」は単独で完結せず、 前後の手法と組み合わさって価値が発揮される。 入力データの準備 (上流)・同目的の代替手法との比較 (並列)・結果の活用 (下流) という 3 軸で隣接領域を整理する。
この上流・並列・下流の対応を地図化することで、 「外れ値」を中核に据えた分析パイプライン (データ準備 → 手法選択 → 結果の検証と展開) の全体像が見えてくる。
分析レポート提出前の自己点検として、 以下の 12 項目すべてに「Yes」と答えられるかを確認してください。 一つでも「No」があれば、 そのセクションに戻って補強する必要があります。
このページは「外れ値」を SSDSE-B-2026 (47 都道府県 × 多変量) を題材に体系的に学ぶための一気通貫の教材です。 単なる用語定義集ではなく、 「直感 → 数式 → 実装 → 落とし穴 → 関連手法」 という流れで一周することで、 業務での意思決定にそのまま使える知識に組み上げます。
本ページで取り上げた手法・記号・コード例は、 すべて実データの 47 都道府県を入力として動作する形にしてあります。 合成データに依存しないため、 SSDSE-B-2026 を data/raw/SSDSE-B-2026.csv として配置するだけでコード片を再現できます。
関連グループ教材へのリンクを使い、 「この用語が属する大きな分野」を俯瞰してから戻ってくると、 知識が一段抽象化された形で定着します。 用語ページは点、 グループ教材は線、 概念マップは面 — 三層を往復しながら学習を進めてください。
本ページの内容に不足を感じたら、 相関ページ(correlation.html)を参照基準として、 ご自身の解釈を加筆していくことを推奨します。 教材の完成形ではなく、 学習者自身の理解の出発点として位置付けてください。
最後に、 SSDSE-B-2026 の 47 都道府県データは「N=47 と少ない」という構造的制約があります。 統計検定の漸近近似が崩れる場面、 単一の県(東京都・沖縄県)が全体傾向を支配する場面、 標準誤差が過小評価される場面 — これらは本ページの随所で繰り返し注意喚起しました。 「実データの小ささを軽視しない」 という姿勢が、 実務でのデータサイエンティストの基本姿勢です。
本ページの各節は検出法を個別に説明してきました。 ここでは角度を変え、 SSDSE-B-2026 の 2023 年(47 都道府県)・総人口 A1101 という 1 本の同じ列に対して、 IQR・z スコア・MAD の 3 法を実際に走らせた結果を突き合わせます(encoding='cp932'・skiprows=[1]・df['SSDSE-B-2026']==2023 での実測値)。 「どの手法が正しいか」ではなく「同じデータでも手法で結論が変わる」ことを、 県の固有名と件数で確かめるのが狙いです。
2023 年の総人口は 47 県で平均 約 265 万人、 中央値 約 155 万人。 平均が中央値より 110 万人も高いのは、 東京都(約 1,409 万人)を筆頭とする都市圏が右裾を引っ張るからです。 東京都1 点だけを除くと平均は約 240 万人へ下がります(約 9% の低下)。 47 分の 1 の観測が全体平均を 1 割動かす——これがブレークダウンポイント 0(平均は 1 点で破綻しうる)の実演で、 中央値がびくともしないのと好対照です。
| 検出法 | 基準 | 外れ値と判定された県数 | 顔ぶれ |
|---|---|---|---|
| Tukey IQR | Q3+1.5·IQR ≈ 504 万人 超 | 9 県 | 北海道・埼玉・千葉・東京・神奈川・愛知・大阪・兵庫・福岡 |
| 修正 z(MAD 基準) | |z*|>3.5(MAD ≈ 62.3 万人) | 9 県 | IQR と同一の 9 県(東京の z* ≈ 13.6 と突出) |
| z スコア | |z|>3 | 1 県 | 東京都のみ(z ≈ 4.09) |
| z スコア | |z|>2 | 3 県 | 東京・神奈川・大阪 |
同じ総人口 1 列でも、 IQR・MAD は 9 県を、 z スコア(|z|>3)はわずか 1 県を返します。 リストが 9 倍違うという事実こそ、 「外れ値検出は手法選択で答えが変わる」ことの動かぬ証拠です。
マスキング(masking):z スコアは平均と標準偏差を分母・分子に使いますが、 その平均(265 万人)と標準偏差(約 280 万人)自身が東京都に膨らまされています。 膨れた標準偏差のせいで境界が高く押し上げられ、 神奈川(約 923 万人)や大阪(約 876 万人)ですら |z| が 3 に届かず見逃されます。 一方、 中央値・MAD ベース(IQR / 修正 z)は外れ値自身に汚染されないため 9 県を捕捉します。 「極端な 1 点が、 他の外れ値を自分の陰に隠す」——これがマスキングです。
境界の任意性:同じ z スコア法でも閾値を |z|>2 にすると 3 県、 |z|>3 にすると 1 県。 「どこで線を引くか」だけで結論が 3 倍変わります。 閾値は自然法則ではなく約束事にすぎません。 だからこそ、 採用した基準・閾値・件数・県名を必ず明記し、 除外前後で結論が変わるかを感度分析する透明性が要になります(詳しくは 外れ値処理)。
外れ値を「消す(削除)」以外に、 影響を薄める選択肢があります。 Winsorization(極値を分位点の値で置き換える)やトリム平均(上下の一定割合を捨てる)は、 削除の恣意性を避けつつ頑健性を得る中間解です。 上のはしごは「どこまで外れ値の口出しを許すか」の連続的なダイヤルであり、 目的に応じて段を選びます。 さらに前処理を挟まず頑健推定そのものを使うなら 頑健統計(中央値・MAD・Huber 回帰)へ、 分布仮定を置かない多変量・非線形の検出なら Isolation Forest・LOF などの異常検知(本ページ「Python 実装」節参照)へ進みます。
総人口 1 変数ではなく、 総人口 A1101・出生数 A4101・転入者数 A5101 の 3 変数で Mahalanobis 距離を測ると($\chi^2_{3,\,0.975} \approx 9.35$ を境界)、 距離の大きい順は 東京(34.2)>北海道(19.9)>愛知(18.4)>大阪(11.2) の 4 県が境界超え。 注目すべきは神奈川(6.8)が境界内に沈むこと——総人口の単変量 IQR では外れ値だった県が、 出生・転入との関係の中では「人口相応」で埋もれます。 逆に北海道は総人口の z スコア(|z|>3)では拾えないのに、 多変量では 2 位に浮上します。 各変数では見えない/各変数では見えるはずが見えなくなる——多変量外れ値の両面性が実データで確認できます(Mahalanobis 距離・共分散を考慮した多変量距離)。
この補足と合わせて読むと理解が深まるページ: 箱ひげ図(IQR フェンスの可視化) / 四分位範囲(IQR) / MAD / 中央値 / 標準偏差 / 標準化・z スコア / 頑健統計 / 外れ値処理 / 分位点。 * z スコア専用ページ・Mahalanobis 距離専用ページ・異常検知(anomaly detection)専用ページ・Winsorization 専用ページは現時点で未作成のため、 それぞれ本ページ内の該当節と上記の関連ページを参照してください。