📚 背景知識(読んでから問題へ)
条件付き確率とは?
「ある事象が起きたと分かっているとき、別の事象が起きる確率」のことです。
日常の例:
- 「今日が雨だった(条件)なら、明日も雨が降る確率は?」
- 「スパムメールだった(条件)なら、"無料"という単語が含まれている確率は?」
記号と式:
P(A|B) = P(AとBが同時に起きる確率) / P(Bが起きる確率)
= P(A ∩ B) / P(B)
日本語で言うと: 「B が起きたという条件のもとで、A が起きる確率」
ベイズの定理とは?
条件付き確率を「逆向きに」計算する公式です。
直感的な理解:
- 普通: 「スパムメール → "無料"が含まれる確率」(原因→結果)
- ベイズ: 「"無料"が含まれている → スパムメールである確率」(結果→原因)
式(怖くない!):
P(スパム|"無料"という単語) = P("無料"|スパム) × P(スパム) / P("無料")
これは「後から新しい証拠を見て、最初の予測を更新する」考え方です。
Kaggleでの重要性
- スパムフィルター: ナイーブベイズ分類器(最も有名なML手法の1つ)
- 医療AI: 「陽性反応が出た → 実際に病気である確率」
- A/Bテスト: ベイズ統計による意思決定
📝 問題
Part 1: 条件付き確率の計算(理論)
ECサイトの顧客データを分析しています。以下の情報が分かっています:
- 全顧客の30%が「プレミアム会員」
- プレミアム会員の60%が「先月購入あり」
- 非プレミアム会員の20%が「先月購入あり」
Q1: プレミアム会員かつ先月購入ありの確率は?
Q2: 先月購入があった顧客のうち、プレミアム会員である確率は?(ベイズの定理を使う)
Part 2: Pythonで確率を計算する(コーディング)
以下のデータを使って、Q1・Q2をPythonで確認してください:
import pandas as pd
import numpy as np
np.random.seed(42)
n = 10000 # 顧客数
# データ生成
is_premium = np.random.choice([True, False], size=n, p=[0.3, 0.7])
purchased = np.where(
is_premium,
np.random.choice([True, False], size=n, p=[0.6, 0.4]),
np.random.choice([True, False], size=n, p=[0.2, 0.8])
)
df = pd.DataFrame({'is_premium': is_premium, 'purchased': purchased})
タスク:
P(premium AND purchased)を計算するP(premium | purchased)を計算する(ベイズの定理の確認)- クロス集計表(
pd.crosstab)を作成して、直感的に確認する
🔍 ヒント(段階的開示)
ヒント1(方向性)
条件付き確率は「絞り込み」のイメージ。「先月購入あり」の人だけに絞って、その中でプレミアム会員の割合を計算する。
ヒント2(アプローチ)
理論:
- Q1: P(premium) × P(purchased|premium) = 0.3 × 0.6 = ?
- Q2: ベイズ定理: P(premium|purchased) = P(purchased|premium) × P(premium) / P(purchased)
- P(purchased) = P(purchased|premium)×P(premium) + P(purchased|非premium)×P(非premium)
コーディング:
df[条件][列名].mean()で条件付き確率を計算できるpd.crosstab(df['is_premium'], df['purchased'], normalize='all')で全体比率が出る
ヒント3(コード骨格)
# P(premium AND purchased)
p_premium_and_purchased = (df['is_premium'] & df['purchased']).mean()
# P(premium | purchased) — "purchased"が True の行に絞る
p_premium_given_purchased = df[df['purchased'] == True]['is_premium'].mean()
# クロス集計
print(pd.crosstab(df['is_premium'], df['purchased'], margins=True))
✅ 模範解答
Part 1: 理論計算
Q1: P(premium AND purchased)
P(premium AND purchased)
= P(purchased | premium) × P(premium)
= 0.6 × 0.3
= 0.18(全顧客の18%)
Q2: P(premium | purchased) — ベイズの定理
まず P(purchased) を全確率の公式で計算:
P(purchased)
= P(purchased|premium) × P(premium) + P(purchased|非premium) × P(非premium)
= 0.6 × 0.3 + 0.2 × 0.7
= 0.18 + 0.14
= 0.32
P(premium | purchased)
= P(purchased|premium) × P(premium) / P(purchased)
= 0.18 / 0.32
= 0.5625(約56.25%)
解釈: 「先月購入があった顧客」に絞ると、約56%がプレミアム会員。
全体のプレミアム会員比率(30%)より大幅に高い → プレミアム会員の方が購入意欲が高い!
Part 2: Pythonコード
import pandas as pd
import numpy as np
np.random.seed(42)
n = 10000
is_premium = np.random.choice([True, False], size=n, p=[0.3, 0.7])
purchased = np.where(
is_premium,
np.random.choice([True, False], size=n, p=[0.6, 0.4]),
np.random.choice([True, False], size=n, p=[0.2, 0.8])
)
df = pd.DataFrame({'is_premium': is_premium, 'purchased': purchased})
# 1. P(premium AND purchased)
p_premium_and_purchased = (df['is_premium'] & df['purchased']).mean()
print(f"P(premium AND purchased) = {p_premium_and_purchased:.4f}")
# 期待値: 0.18
# 2. P(premium | purchased)
purchased_only = df[df['purchased'] == True]
p_premium_given_purchased = purchased_only['is_premium'].mean()
print(f"P(premium | purchased) = {p_premium_given_purchased:.4f}")
# 期待値: 0.5625
# 3. クロス集計表
cross = pd.crosstab(df['is_premium'], df['purchased'], margins=True)
print("\nクロス集計(件数):")
print(cross)
cross_norm = pd.crosstab(df['is_premium'], df['purchased'], normalize='all') * 100
print("\nクロス集計(%):")
print(cross_norm.round(2))
出力例(n=10,000なので理論値に近い):
▶ 出力を見る
P(premium AND purchased) = 0.1813
P(premium | purchased) = 0.5638
クロス集計(件数):
purchased False True All
is_premium
False 5625 1372 6997
True 1213 1790 3003
All 6838 3162 10000
クロス集計(%):
purchased False True
is_premium
False 56.25 13.72
True 12.13 17.90🪜 Step-by-Step 解説
np.where(condition, x, y) は「conditionがTrueならx、FalseならY」を返す。
プレミアム会員(True)と非会員(False)で異なる購入確率を設定している。
& 演算子で「AND条件」を計算(df['is_premium'] & df['purchased']).mean()
TrueとTrueの組み合わせだけが True になる。.mean() でTrueの割合(確率)が出る。
.mean() を取るdf[df['purchased'] == True]['is_premium'].mean()
「購入あり」に絞った後、その中でのプレミアム会員の割合 = 条件付き確率。
pd.crosstab は2変数のクロス集計を作る。Kaggleのデータ探索(EDA)でよく使う。
📐 数学・統計の補足(文系向け)
ベイズの定理を「証拠の更新」として理解する:
- 最初の信念(事前確率): 「全員の中でプレミアム会員は30%」
- 新しい証拠: 「この人は先月購入した」
- 更新後の信念(事後確率): 「プレミアム会員である確率が56%に上がった」
これが「ベイズ更新」。機械学習全体の根底にある考え方です。
🏆 Kaggleでの実践的な使い方
- ナイーブベイズ分類器 (
sklearn.naive_bayes.MultinomialNB): テキスト分類・スパム判定 - クロス集計EDA: カテゴリ変数の関係性を把握する最初のステップ
- ターゲットエンコーディング: カテゴリ特徴量を「目的変数の条件付き確率」に変換する手法(上位手法)
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 | ||||
|---|---|---|---|---|---|---|
| P(A | B) = P(B | A) と思ってしまう | 直感的にひっくり返しても同じに見える | P(雨 | 傘を持っている) ≠ P(傘を持っている | 雨) |
df['A'] == True を忘れてフィルタリング | PandasのBoolean列の扱いに慣れていない | df[df['A']] でもOKだが == True で明示する方が分かりやすい | ||||
クロス集計の normalize 引数 | 'all'/'index'/'columns' で違う | 条件付き確率には normalize='columns' (列ごとに正規化) が直感的 |
🚀 次のステップ
- 発展: ナイーブベイズ分類器を
sklearnで実装し、テキスト分類に応用する - 次回予告: 確率分布(正規分布・二項分布)— 「データのばらつき方の型」を学ぶ