📚 背景知識(読んでから問題へ)
標準偏差の「意味」をもう一度確認
標準偏差は「データのバラつき具合」を示す数値です。
- 標準偏差が小さい → データが平均の近くに集まっている(バラつき少)
- 標準偏差が大きい → データが広く散らばっている(バラつき大)
外れ値とは?
外れ値(Outlier)は「他のデータから大きく外れた値」のことです。
よく使われる判定方法:
- IQR法(四分位範囲): Q1-1.5×IQR より小さい / Q3+1.5×IQR より大きい値
- Zスコア法: 平均から標準偏差の3倍以上離れた値(|Z| > 3)
Zスコア = (データ値 - 平均) ÷ 標準偏差
Zスコアが「3以上」なら「平均から3σ(シグマ)以上離れている」= 通常では0.3%以下の確率しか出ない値。
📝 問題
以下のコードを完成させ、外れ値を検出して除去してください。
import numpy as np
import pandas as pd
# テストデータ(サラリーデータ・単位: 万円)
np.random.seed(42)
salary = np.random.normal(loc=500, scale=50, size=100).tolist()
salary.extend([5, 2000, 1]) # 外れ値を追加
salary = pd.Series(salary)
# ── タスク1 ──
# salary の平均・標準偏差・中央値を計算して表示する
mean_val = ___
std_val = ___
median_val = ___
print(f"平均: {mean_val:.1f}, 標準偏差: {std_val:.1f}, 中央値: {median_val:.1f}")
# ── タスク2 ──
# Zスコア法で外れ値を検出する(|Zスコア| > 3 のものを外れ値とする)
z_scores = ___
outliers = salary[___] # 外れ値を抽出
print(f"\n外れ値の数: {len(outliers)}")
print(f"外れ値: {outliers.values}")
# ── タスク3 ──
# 外れ値を除去したデータで平均と標準偏差を再計算する
salary_clean = salary[___] # 外れ値以外を抽出
print(f"\n除去後 → 平均: {salary_clean.mean():.1f}, 標準偏差: {salary_clean.std():.1f}")
期待出力(例):
▶ 出力を見る
平均: 490.5, 標準偏差: 176.2, 中央値: 499.8
外れ値の数: 3
外れ値: [ 5. 2000. 1.]
除去後 → 平均: 500.3, 標準偏差: 49.8🔍 ヒント(段階的開示)
ヒント1(方向性)
numpy と pandas の基本的な統計関数(.mean(), .std())を使います。Zスコアは「各値から平均を引いて標準偏差で割る」だけです。
ヒント2(アプローチ)
# Zスコアの計算式
z = (salary - salary.mean()) / salary.std()
# 外れ値の条件
abs(z) > 3
ヒント3(コード骨格)
mean_val = salary.mean()
std_val = salary.std()
median_val = salary.median()
z_scores = (salary - mean_val) / std_val
outliers = salary[abs(z_scores) > 3]
salary_clean = salary[abs(z_scores) <= 3]
✅ 模範解答
import numpy as np
import pandas as pd
np.random.seed(42)
salary = np.random.normal(loc=500, scale=50, size=100).tolist()
salary.extend([5, 2000, 1])
salary = pd.Series(salary)
# タスク1: 基本統計量
mean_val = salary.mean()
std_val = salary.std()
median_val = salary.median()
print(f"平均: {mean_val:.1f}, 標準偏差: {std_val:.1f}, 中央値: {median_val:.1f}")
# タスク2: Zスコア法で外れ値を検出
z_scores = (salary - mean_val) / std_val
outliers = salary[abs(z_scores) > 3]
print(f"\n外れ値の数: {len(outliers)}")
print(f"外れ値: {outliers.values}")
# タスク3: 外れ値を除去して再計算
salary_clean = salary[abs(z_scores) <= 3]
print(f"\n除去後 → 平均: {salary_clean.mean():.1f}, 標準偏差: {salary_clean.std():.1f}")
🪜 Step-by-Step 解説
1
基本統計量の計算
mean_val = salary.mean() # pandas Series の平均
std_val = salary.std() # 標準偏差(ddof=1、不偏標準偏差がデフォルト)
median_val = salary.median() # 中央値
外れ値がある場合、平均は大きく影響を受けるが中央値は影響を受けにくい。
→ 実際の出力で 平均 490.5 vs 中央値 499.8 のズレがその証拠。
2
Zスコアの計算
z_scores = (salary - mean_val) / std_val
これは「各データが平均から何σ離れているか」を表します。
- 正規分布では 99.7% のデータが |Z| ≤ 3 の範囲に収まる
- |Z| > 3 のデータは「統計的に異常に離れている」= 外れ値候補
3
外れ値の抽出と除去
outliers = salary[abs(z_scores) > 3] # 外れ値
salary_clean = salary[abs(z_scores) <= 3] # 外れ値以外
abs() で絶対値を取ることで、平均より高い外れ値も低い外れ値も両方検出できます。
📐 数学・統計の補足(文系向け)
なぜ「3σ」が閾値なの?
正規分布(データが釣り鐘型に分布している場合)では:
- 平均 ± 1σ の範囲 → データの約 68% が入る
- 平均 ± 2σ の範囲 → データの約 95% が入る
- 平均 ± 3σ の範囲 → データの約 99.7% が入る
つまり「3σを超える値は 1000件に3件以下」という確率的に珍しい値 → 外れ値と判断する。
🏆 Kaggleでの実践的な使い方
実際のKaggleコンペでは:
# 外れ値を IQR 法で検出(より頑健な方法)
Q1 = df['price'].quantile(0.25)
Q3 = df['price'].quantile(0.75)
IQR = Q3 - Q1
df_clean = df[(df['price'] >= Q1 - 1.5 * IQR) & (df['price'] <= Q3 + 1.5 * IQR)]
House Prices コンペ(実例): 住宅価格の外れ値を除去することで、線形回帰モデルのRMSEが大幅に改善するケースが多い。
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| 外れ値は常に除去すべき | データの正確さへの過信 | ドメイン知識で判断。本物の高額物件なら残す |
abs(z_scores) > 3 の abs を忘れる | 正の外れ値だけ検出してしまう | 両側(高すぎ・低すぎ)を検出するため必須 |
std() の ddof を意識しない | numpy.std はデフォルト ddof=0(母標準偏差)、pandas.std はddof=1(不偏) | サンプルデータは pandas の .std() を使う |
🚀 次のステップ
- 発展問題: IQR 法で同じデータの外れ値を検出し、Zスコア法と結果を比較する
- 次回予告: 確率の基礎(確率とは何か)