📚 背景知識(読んでから問題へ)
標準偏差とは?(直感的理解)
「平均からどれくらいズレているか」の平均的な大きさ。
例えばテストで、クラスの平均点が70点のとき:
- Aクラス: 全員68〜72点 → 標準偏差が小さい(みんな似たスコア)
- Bクラス: 40点〜100点がバラバラ → 標準偏差が大きい(散らばりが大きい)
外れ値とは?
他のデータと比べて極端に大きい/小さい値。
外れ値を放置するとモデルの精度が下がる ため、発見と対処が重要。
外れ値の検出方法
- IQR法(四分位範囲): データの中央50%の範囲(IQR)を計算し、その1.5倍を超えるものを外れ値とみなす
- 下限: Q1 - 1.5 × IQR
- 上限: Q3 + 1.5 × IQR
- Zスコア法: 平均から何標準偏差離れているか。|Zスコア| > 3 なら外れ値
- Z = (値 - 平均) / 標準偏差
📝 問題
以下のデータは、あるECサイトの「1日の注文件数」を20日間記録したものです。
import numpy as np
import pandas as pd
orders = pd.Series([
45, 52, 48, 51, 49,
47, 53, 50, 46, 48,
52, 49, 51, 47, 50,
48, 200, 45, 53, 1 # 200と1が含まれている
])
次の分析タスクを行ってください:
- 平均、中央値、標準偏差を求める
- 外れ値を IQR法 で検出し、外れ値のインデックスと値を出力する
- 外れ値を除いた後の平均・中央値・標準偏差と比較し、「外れ値が与える影響」を日本語でコメントとして記述する
- ボックスプロット(箱ひげ図)を描いて外れ値を視覚的に確認する
🔍 ヒント(段階的開示)
ヒント1(方向性)
まず基本統計量を求め、次にIQRを計算して外れ値の上限/下限を求めます。その後、外れ値を除外したデータと比べましょう。
ヒント2(アプローチ)
orders.describe()で基本統計量が一気に確認できます- IQR = Q3 - Q1 (
quantile(0.75) - quantile(0.25)) - ボックスプロットは
plt.boxplot()またはseaborn.boxplot()で描ける
ヒント3(コード骨格)
# 基本統計量
mean = orders.mean()
median = orders.median()
std = orders.std()
# IQR法
Q1 = orders.quantile(0.25)
Q3 = orders.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
# 外れ値の抽出
outliers = orders[(orders < lower) | (orders > upper)]
# 外れ値除外後
clean = orders[(orders >= lower) & (orders <= upper)]
✅ 模範解答
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
orders = pd.Series([
45, 52, 48, 51, 49,
47, 53, 50, 46, 48,
52, 49, 51, 47, 50,
48, 200, 45, 53, 1
])
# --- 1. 基本統計量 ---
print("=== 全データ ===")
print(f"平均: {orders.mean():.2f}")
print(f"中央値: {orders.median():.2f}")
print(f"標準偏差: {orders.std():.2f}")
# --- 2. IQR法で外れ値検出 ---
Q1 = orders.quantile(0.25)
Q3 = orders.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
print(f"\n=== IQR法 ===")
print(f"Q1={Q1}, Q3={Q3}, IQR={IQR}")
print(f"外れ値の範囲: [{lower:.1f}, {upper:.1f}]")
outliers = orders[(orders < lower) | (orders > upper)]
print(f"\n外れ値:\n{outliers}")
# --- 3. 外れ値除外後の比較 ---
clean = orders[(orders >= lower) & (orders <= upper)]
print("\n=== 外れ値除外後 ===")
print(f"平均: {clean.mean():.2f}")
print(f"中央値: {clean.median():.2f}")
print(f"標準偏差: {clean.std():.2f}")
# コメント
# 平均は 200(高い外れ値)と 1(低い外れ値)に大きく引っ張られるが、
# 中央値はほとんど変化しない。
# → 外れ値が存在する場合、平均より中央値の方が「代表値」として信頼できる。
# --- 4. ボックスプロット ---
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
axes[0].boxplot(orders, vert=True)
axes[0].set_title("全データ(外れ値あり)")
axes[0].set_ylabel("1日の注文件数")
axes[1].boxplot(clean, vert=True)
axes[1].set_title("外れ値除外後")
axes[1].set_ylabel("1日の注文件数")
plt.tight_layout()
plt.savefig("boxplot_orders.png")
plt.show()
print("ボックスプロットを保存しました。")
出力例:
▶ 出力を見る
=== 全データ ===
平均: 53.35
中央値: 49.50
標準偏差: 39.37
=== IQR法 ===
Q1=47.25, Q3=51.75, IQR=4.50
外れ値の範囲: [40.5, 58.5]
外れ値:
16 200
19 1
dtype: int64
=== 外れ値除外後 ===
平均: 49.39
中央値: 49.00
標準偏差: 2.55🪜 Step-by-Step 解説
1
基本統計量で全体像をつかむ
orders.mean() と orders.median() を比較する。外れ値がある場合、平均 > 中央値 になる(正の歪み)か 平均 < 中央値(負の歪み)になる。今回は200という大きい外れ値があるため平均が中央値より高い。
2
IQRで外れ値の境界を計算する
IQR(四分位範囲)= Q3 - Q1。この1.5倍を超えたら外れ値とみなす。
今回: IQR = 51.75 - 47.25 = 4.5
- 下限: 47.25 - 6.75 = 40.5
- 上限: 51.75 + 6.75 = 58.5
→ 200と1の両方が外れ値と判定される
3
外れ値除外後の変化を確認する
- 平均: 53.35 → 49.39(大きく変化)
- 中央値: 49.50 → 49.00(ほぼ変化なし)
- 標準偏差: 39.37 → 2.55(劇的に変化)
→ 標準偏差は外れ値に非常に敏感。データの「ばらつき」を論じる前に外れ値チェックが必須。
4
ボックスプロットで視覚確認
箱(ボックス)の上下端がQ3/Q1、中の線が中央値、ひげ(whisker)の外の点が外れ値として表示される。視覚的に一瞬で外れ値の位置がわかる。
📐 数学・統計の補足(文系向け)
なぜ1.5倍なのか?
正規分布(ベルカーブ)に従うデータでは、IQRの1.5倍の外側に入るデータは全体の約0.7%しかない。つまり「100個のうち1個未満しか出ない珍しい値」を外れ値と定義している。(2.0や3.0倍を使うこともある)
IQR法 vs Zスコア法
- IQR法: 中央値・四分位数を使うので外れ値の影響を受けにくい(ロバスト)
- Zスコア法: 平均・標準偏差を使うので外れ値が多いと検出精度が落ちる
→ 外れ値があるかもしれない時はIQR法が推奨
🏆 Kaggleでの実践的な使い方
- House Prices コンペ: 住宅価格に超高額物件(外れ値)が含まれることがある。外れ値を除去 or log変換することで線形モデルの精度が上がる
- log変換の活用:
np.log1p(price)で価格データの歪みを補正するテクニックはKaggle上位解で頻出 - 外れ値の除去 or 維持: 「本物の異常値(データ入力ミス)」は除去。「自然に起きる稀な出来事」は維持すべきケースもある
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| 外れ値は常に削除すべき | 「ノイズ」と思い込む | 外れ値が重要な情報の場合もある(詐欺検出など) |
| 平均だけで代表値を判断 | 平均を「普通」と思い込む | 外れ値があれば中央値の方が信頼できる |
| 標準偏差が大きい = データが悪い | 直感的誤解 | 外れ値があるだけかもしれない。まず外れ値チェックを |
🚀 次のステップ
- 発展:
scipy.stats.zscore()でZスコア法による外れ値検出を実装する - 次回予告: 確率の基礎(確率とは何か・条件付き確率)