Rで モンティ・ホール問題 を試みます。
モンティ・ホール問題の説明
モンティ・ホール問題は、アメリカのゲームショー番組「Let’s Make a Deal」に由来する確率論の問題です。司会者の名前がモンティ・ホールだったことから、この名前がついています。
問題のシナリオは以下の通りです。
- 設定
- あなたの前には3つの閉じたドアがあります。
- 1つのドアの後ろには景品(車)があり、他の2つのドアの後ろにはハズレ(ヤギ)があります。
- あなたはどのドアの後ろに何があるか知りません。
- 挑戦者の最初の選択
- あなたは景品が入っていると思うドアを1つ選びます。
- 司会者の行動
- 司会者は、どのドアに景品があるかを知っています。
- 司会者は、あなたが選ばなかった残りの2つのドアのうち、必ずハズレ(ヤギ)が入っているドアを1つ開けて見せます。
- 最後の選択
- ここで司会者はあなたに問いかけます。
- 「最初に選んだドアのままにしますか? それとも、残っているもう一方のドアに変更しますか?」
【問題】
このとき、あなたはドアを変更するべきでしょうか? それとも変更しないべきでしょうか? どちらが景品を当てる確率が高いでしょうか?
【結論と解説】
直感的には「残ったドアは2つだから、どちらを選んでも確率は1/2(50%)だろう」と考えがちですが、これは間違いです。
正解は「ドアを変更した方が、当たる確率が2倍になる」です。
- 変更しない場合:当たる確率は 1/3
- 変更する場合:当たる確率は 2/3
なぜそうなるのかを説明します。
- 最初に当たり(車)のドアを選ぶ確率は 1/3 です。
- 最初にハズレ(ヤギ)のドアを選ぶ確率は 2/3 です。
この2つのシナリオを考えてみましょう。
- シナリオ1:最初に当たりのドアを選んでいた場合(確率1/3)
- この場合、司会者は残りの2つのハズレのドアのどちらかを開けます。
- あなたが変更すると、必ずハズレになります。
- あなたが変更しないと、当たります。
- シナリオ2:最初にハズレのドアを選んでいた場合(確率2/3)
- この場合、残りのドアは「当たり」と「ハズレ」が1つずつです。
- 司会者はハズレのドアを開けなければならないので、必ずもう一方のハズレのドアを開けます。
- その結果、残っている閉まったドアは必ず当たりのドアになります。
- あなたが変更すると、必ず当たります。
- あなたが変更しないと、ハズレになります。
まとめると、
- 変更して勝つのは、最初にハズレを選んでいた場合です(確率2/3)。
- 変更せずに勝つのは、最初に当たりを選んでいた場合です(確率1/3)。
したがって、ドアを変更する方が有利な戦略と言えます。
R言語によるシミュレーション
この直感に反する結果を確かめるために、R言語でシミュレーションを行ってみましょう。多数の試行を繰り返すことで、確率が理論値(1/3 と 2/3)に近づく様子を確認できます。
Rコード
set.seed(20250712)
options(scipen = 999)
# シミュレーションの試行回数を設定
<- 100000
n_simulations
# 結果を記録するための変数を初期化
<- 0 # ドアを変更せずに勝った回数
stay_wins <- 0 # ドアを変更して勝った回数
switch_wins
# シミュレーションのループ
for (i in 1:n_simulations) {
# 1. ドアの設定
<- 1:3
doors
# 2. 当たりのドアをランダムに決める
<- sample(doors, 1)
car_door
# 3. 挑戦者の最初の選択をランダムに決める
<- sample(doors, 1)
player_choice
# 4. 司会者が開けるドアを決める
# 司会者は「挑戦者が選んでいない」かつ「当たりではない」ドアを開ける
<- setdiff(doors, c(player_choice, car_door))
host_can_open
# 司会者が開けるドアを確定する
if (length(host_can_open) == 1) {
<- host_can_open
host_opens else {
} # 候補が複数ある場合は、その中からランダムに1つ選ぶ
<- sample(host_can_open, 1)
host_opens
}
# 5. 挑戦者が変更した場合に選ぶことになるドアを決める
# 挑戦者の選択でもなく、司会者が開けたドアでもないドア
<- setdiff(doors, c(player_choice, host_opens))
switch_door
# 6. 結果の判定
# a. 変更しなかった場合 (stay)
if (player_choice == car_door) {
<- stay_wins + 1
stay_wins
}
# b. 変更した場合 (switch)
if (switch_door == car_door) {
<- switch_wins + 1
switch_wins
}
}
# 7. 結果の表示
cat("シミュレーション試行回数:", n_simulations, "\n")
cat("-----------------------------------\n")
# 変更しなかった場合の勝率
<- stay_wins / n_simulations
stay_win_rate cat("ドアを変更しなかった場合の勝利数:", stay_wins, "\n")
cat("ドアを変更しなかった場合の勝率:", sprintf("%.4f", stay_win_rate), "(理論値: 1/3 ≈ 0.3333)\n\n")
# 変更した場合の勝率
<- switch_wins / n_simulations
switch_win_rate cat("ドアを変更した場合の勝利数:", switch_wins, "\n")
cat("ドアを変更した場合の勝率:", sprintf("%.4f", switch_win_rate), "(理論値: 2/3 ≈ 0.6667)\n")
シミュレーション試行回数: 100000
-----------------------------------
ドアを変更しなかった場合の勝利数: 33181
ドアを変更しなかった場合の勝率: 0.3318 (理論値: 1/3 ≈ 0.3333)
ドアを変更した場合の勝利数: 66819
ドアを変更した場合の勝率: 0.6682 (理論値: 2/3 ≈ 0.6667)
結論
シミュレーション結果が示す通り、「ドアを変更しない」戦略の勝率は約33.2%(約1/3)に、「ドアを変更する」戦略の勝率は約66.8%(約2/3)に収束します。これにより、モンティ・ホール問題ではドアを変更する方が2倍有利であることが経験的に確認できました。
Rコードの解説
-
n_simulations <- 100000
:シミュレーションを100,000回繰り返す設定です。回数が多いほど、結果は理論値に近づきます。 -
doors <- 1:3
:3つのドアを1, 2, 3
という数値のベクトルとして表現します。 -
car_door <- sample(doors, 1)
:3つのドアからランダムに1つを「当たり」のドアとして選びます。 -
player_choice <- sample(doors, 1)
:挑戦者がランダムに1つのドアを選びます。 -
host_can_open <- setdiff(doors, c(player_choice, car_door))
:司会者が開ける可能性のあるドアの候補を計算します。setdiff()
関数は、第1引数の集合から第2引数の集合の要素を取り除いたものを返します。- 挑戦者が当たりを選んだ場合、
host_can_open
にはハズレのドアが2つ入ります。 - 挑戦者がハズレを選んだ場合、
host_can_open
には残りのハズレのドアが1つだけ入ります。
- 挑戦者が当たりを選んだ場合、
-
if (length(host_can_open) == 1) { ... } else { ... }
:司会者が開けるドアを確定させます。-
if (length(host_can_open) == 1)
: 候補が1つしかない場合(挑戦者が最初にハズレを選んだ場合)は、sample()
を使わずにその値を直接host_opens
に代入します。 -
else
: 候補が2つある場合(挑戦者が最初に当たりを選んだ場合)は、sample()
を使ってその2つの候補からランダムに1つを選びます。
-
-
switch_door <- setdiff(doors, c(player_choice, host_opens))
:挑戦者が「変更する」場合に選ぶことになるドアを特定します。これは、全てのドアから「最初の選択」と「司会者が開けたドア」を除いた、残りの1つのドアです。 -
if (player_choice == car_door)
:【変更しない】戦略の勝利条件です。挑戦者の最初の選択が当たりなら、勝利カウントを1増やします。 -
if (switch_door == car_door)
:【変更する】戦略の勝利条件です。変更先のドアが当たりなら、勝利カウントを1増やします。 -
cat(...)
:最後に、それぞれの戦略での総勝利数と勝率を計算して出力します。
以上です。