おのおののひとりごと

徒然に、日々の小さな備忘録

※当サイトにはアフィリエイトリンクが含まれています

はじめに

確率1/10と降水確率10%の誤解:Pythonで検証してみた話

この記事は、Pythonを学習するなかで発生した確率の疑問を、
Pythonを使用して解決した事を纏めたものです。



Pythonで作ったコード

はじめに

G検定の受験を終え、発表までの間、Pythonを覚えようと自習している。
その演習問題を実践している時、いつものごとく疑問が立ち上がった。

それ、気になりますと。


降水確率10%

天気予報で、降水確率が10%という。

降水確率10%とは、10日続けば「1回は雨が降る」と言われることがある。
しかし実際には、1日目の降水確率は10%、2日目も10%であり、
「10日に1回雨が降るくらい確率が低い日が毎日続くだけ」である。

10日に1回雨が降るわけではない。


確率1/10

サイコロの出目は、1〜6。
どの数字も、出る確率は1/6である。

この出目の数字を1〜10に広げると、確率は1/10に低下する。
どの数字も、出る確率は同じである。

Pythonの演習問題の中で、この確率1/10が物議を巻き起こす。


Pythonの演習問題

問題
while と random モジュールを使って、コンピュータが選んだ 1〜10 のランダムな数を当てるゲームを作れ。
数字が当たれば処理終了。ハズレた場合は繰り返す。

要は処理の繰り返し(while)と乱数(random)の使い方を覚えろという問題である。

自分が作ったコードは以下の通りである。

import random
while True:
    num = random.randint(1,10)
    kazu = int(input('数を入力(1-10)'))
    if num == kazu :
        print('一致!  処理を終わります')
        break
    else:
        print('残念不一致:', num)

処理の概要は以下の通りだ。

以下の処理を繰り返す
- 1〜10 の範囲でランダムな数字を1つ選ぶ
- 数字を入力する
- ランダムな数字と入力した数字が一致したら処理終了
- 不一致の場合は、ランダムに選んだ数字(正解)を表示

つまり、数字が一致しない限り、処理が終了しない仕組みだ。

ところが、このコードを見せた生成AIが、いちゃもんをつけてきた。

  1. random を使用するのはループの外じゃないと駄目
  2. 不正解の時に答えを教えたらゲームにならない

こいつ、何いちゃもんつけているんだ。
「いや、1/10 の確率なら、毎回答えが変わっても変わるでしょ。」
「選んだ数字固定だったら、それこそゲーム性がないじゃん。」
「降水確率10%と一緒だと。」

ところが、演習問題の模範回答も生成AI寄りで、
自分の回答は「間違い」とされてしまった。

納得いかない。
問題(仕様)通りに作ったのに、なぜ間違いなのか。
問題(仕様)が曖昧で悪いというなら仕様変更をよこせと。


仕様あるある

仕事でもよくある話だ。

  • 仕様が曖昧なのが原因なのに、作った側が責められる
  • 「なぜ問い合わせしなかった」と追及される
  • 仕様通りに作ったのに「意図と違う」と言われる

今回の演習問題も、まさにその縮図だった。

この数字が 1〜100 だとするならば、私もランダムに選ぶ数字は1回だけ選ぶようにしただろう。
しかし、1/10の確率であれば、あたりも出るはず。
ゲーム性もあり、問題ない。

と考えた訳だ。


数字が一致する確率

このゲーム、1〜10の数字が出る確率は、1/10。
だから選ぶ数字を固定すれば、数字が一致する確率も 1/10になることはわかる。

この選ぶ数字を毎回変えたら確率はどうなるだろう?
疑問に思った。
なんとなく、1/10 の確率は変わらないという気もする。
しかし、直感が、確率が下がると言っている。

せっかくPythonのコードが書けるようになったので、調べてみることにした。


実験コード

そこで、演習問題から離れて「当たる確率」について考えた。

固定で数字を選んだ場合は、出目の数が当選確率になるはず。
毎回数字を変えた場合は、一致した回数が当選確率になるはず。

Python で検証してみた。

import random

deme = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
ok = 0

print('start')
for i in range(100000):
    num1 = random.randint(1,10)
    num2 = random.randint(1,10)
    deme[num1 -1] += 1
    if num1 == num2:
        ok += 1
print(deme)
print('ok=', ok)
print('end')

処理の概要は、以下の通り。

  • num1は、コンピュータが選ぶ 1〜10 の数字。
    出た数字をそれぞれカウントする。(deme)
    num1のカウントした数が、数字を固定で選んだ時の確率となる。

  • num2は、入力する数字を毎回変えた時。
    コンピュータが選んだ数字と一致した時だけ、okをカウントする。

この処理を10万回実行する。


検証結果

結果:

start
[9909, 9976, 9944, 9899, 9976, 10035, 9919, 9995, 10124, 10223]
ok= 10015
end

num1の数字は、10万回の 1/10 となる約1万回。
そして、okのカウント数も約1万回。

どちらも、確率は変わらず1/10という事がわかった。
確率とはそういうものだと理解した。


まとめ

簡単なプログラムである。

コードの書き方も稚拙である。

でも動く。
疑問を解決してくれる。

Pythonの乱数が、ほぼ確率通りに数字を選ぶ事がわかる。

Python のコードと確率、二つを学んだ日だった。
そして、投稿記事のネタを提供してくれた日でもあった。


関連投稿