
武蔵野個別指導塾の特徴
高校情報I 確率モデルと乱数—試行条件を固定して理論上の割合と実験値を比べる|武蔵野個別指導塾

札を戻すくじを複数のシードで試し、当たり回数の揺れと理論値を区別して0回の割合も考えます。
よくあるのは、高校生がくじを数回引いた結果を見て、その割合が当たりの確率そのものだと考える場面です。3回当たったという記録は実験の事実ですが、次に引くときの確率をそれだけで決めることはできません。くじの中身と引き方を先に決め、どの数量を比べるのかを区別しましょう。
問題を読むときに決める条件
問われ方には、くじの構成から理論上の割合を求める型、決められた乱数列から当たりの回数を数える型、異なる実験結果の差を説明する型があります。どの型でも、当たりの条件と1回の試行を先に確認します。たとえば引いた札を戻すかどうかが変われば、次の試行の条件も変わります。
ここでは同じ大きさの5枚の札に0から4までの番号を1つずつ書きます。0と1を当たりとし、1回引くごとに札を戻して混ぜます。どの札も同じ確率で選ばれ、各回の選択は独立であるというモデルです。現実のくじが必ずその前提を満たすと主張するものではありません。出力は当たりの回数と試行回数の組とし、割合が必要なときは回数を試行回数で割ります。試行回数が0なら割合は定義せず、その旨を表示します。
くじを数字に置き換える
図1のように、札に対応する5通りの数字から1つを選び、数字が2未満なら当たりと判定します。0と1の2通りが当たりなので、理論上の当たりの確率は2/5、つまり0.4です。この値はモデルの条件から求めた値です。一方、実験値は実際の試行で当たった回数を実際の試行回数で割った値です。

図1の5通りは同じ確率という約束で数えています。札ごとの選ばれやすさが違う場合、単に当たり札の枚数を全枚数で割るだけでは計算できません。また、札を戻さずに引くと残りの札の構成が変わります。見た目が同じ「5枚のくじ」でも、試行の操作を変えれば別のモデルです。
コンピュータの疑似乱数は、初期状態から一定の手順で数字を作ります。シードはその初期化に使う値です。同じ実行環境、同じシード、同じ乱数の呼び出し方を用意すれば、結果を再現して検査できます。シードが違えば別の列を調べられますが、異なるシードが必ず異なる当たり回数を生むわけではありません。実行環境や呼び出し順も記録しなければ、シードの数字だけで再現を約束できません。
当たり回数は整数、割合は0以上1以下です。実験値と理論値が一致しないことは直ちにプログラムの誤りを意味しません。逆に、たまたま一致したことも正しい実装の証明にはなりません。試行回数を増やすと揺れの影響が小さくなる傾向を調べられますが、実験値が毎回必ず前回より理論値に近づくわけではありません。
基本例題:5回の記録を追う
先ほどのくじを5回引きます。乱数生成器のシードを7とし、当たり回数と試行回数を整数の組で出してください。Python 3.14.8を使用します。まず、乱数として得られた列が2、1、3、0、0だったときの期待値を手で求めます。2と3は外れ、1と2つの0は当たりなので、期待値は3、5です。
import random
def trial(seed, n):
if type(n) is not int or n < 0:
raise ValueError("n must be a nonnegative integer")
rng = random.Random(seed)
hits = 0
for i in range(n):
number = rng.randrange(5)
if number < 2:
hits = hits + 1
return hits, n
print(trial(7, 5))
実際の出力は次のとおりです。
(3, 5)
図2のように回ごとに判定を足し、5回目の終了後に3回と確定します。最初の行は乱数を扱う機能を読み込みます。関数の引数seedはシード、nは試行回数です。次の条件は整数以外や負の回数を拒否し、誤った入力を0回の結果として扱わないためにあります。rngはその関数内で使う乱数生成器、hitsは当たりの累計です。range(n)は0からn未満までのn個の値を作り、iは繰り返しの順番を表します。

numberには0以上5未満の整数が入ります。ifの条件は0または1に対応し、当たりのときだけhitsを1増やします。returnは累計と試行回数を組にして返し、printはそれを表示します。図2の累計は0、1、1、2、3です。各回の数字は0から4の範囲内で、3回の当たりと2回の外れを合わせると5回になり、元の場面に戻しても整合します。
繰り返しを始める前の累計は0です。各回を終えた時点で、それまでに見た数字のうち当たりの個数がhitsに入るという関係が保たれます。次の数字が当たりなら1を足し、外れならそのままにするからです。rangeが有限のn個の値を順に渡すので、n回後に反復は止まります。この説明は、検査した1つの列に限らない数え上げの理由です。ただし、乱数の統計的な性質をこの説明だけで証明したことにはなりません。
標準例題:条件をそろえて列を変える
同じ札と戻し方で20回試行し、シード7、19、31について回数と割合を比べます。出力は先ほどの関数を使って求めます。期待値の確認には、乱数列を記録して0と1の出現を別に数える方法を使います。
for seed in (7, 19, 31):
hits, n = trial(seed, 20)
print(seed, hits, n, hits / n)
Python 3.14.8での実際の出力と、列を数えた期待値は一致します。
7 11 20 0.55
19 6 20 0.3
31 13 20 0.65
シード7では11回当たり、9回外れです。19では6回当たり、14回外れ、31では13回当たり、7回外れです。各行で当たりと外れの合計が20回になります。理論上の0.4との距離は順に0.15、0.1、0.25です。これらは3回の実行結果であって、どのシードでも同じ揺れ方をするという結論ではありません。
比較で固定したのは札の構成、戻す操作、試行回数、当たりの判定とPythonの版です。変えたのはシードです。シードと同時に札の枚数や試行回数を変えると、結果の差がどの変更に由来するか切り分けにくくなります。記録には当たり回数も残します。割合が同じでも、2回中1回と200回中100回では試行の量が異なるからです。
発展例題:0回を結果として扱う
試行回数の境界を調べます。上の関数にシード7、回数0を渡すと、繰り返しは1回も実行されず、期待値と実際の出力はともに(0, 0)です。これは当たりがなかったという回数の記録であり、当たりの割合が0という意味ではありません。分母が0の割り算はできないので、割合を出す部分に分岐を置きます。
hits, n = trial(7, 0)
if n == 0:
print("割合なし")
else:
print(hits / n)
入力はシード7、0回です。期待する表示は「割合なし」、実際の出力も「割合なし」です。0回なら乱数を取り出さず、当たりと外れの合計も0です。1回の場合も確認しましょう。シード7で最初の数字は2なので、期待値は(0, 1)、実際も(0, 1)です。2は当たりの範囲の直外にあり、境界判定の検査になります。
この関数の入力は数字の配列ではありませんが、手元の記録から数え直す際には空の列なら0回、1個の列なら1回として扱います。同じ数字が複数現れた場合も、各回を別々に数えます。当たりが見つからない列なら当たり回数は0で、位置を探す処理ではないため未発見の位置は返しません。入力の意味を明示すると、端の条件を取り違えにくくなります。
誤答を直して再実行する
図3のように、当たりを2以下と誤って判定すると、番号2まで当たりに含まれます。基本例題の列2、1、3、0、0では、誤った条件の期待値は4回です。正しくは0と1の2種類だけを数えるので、最初の2は外れです。

原因は「2種類」と「2以下」を混同したことです。0から数えると2以下は0、1、2の3種類になります。修正はnumber < 2にすることです。上の関数でシード7、5回を再実行すると(3, 5)でした。元の列に戻って確認すると、当たりは1、0、0の3個です。乱数が変わっていないことをシードと呼び出し回数で確かめたうえで、判定だけを直しています。
表示が期待どおりでも、試行回数が負なら結果として受け取ってはいけません。たとえばtrial(7, -1)はValueErrorを出します。trial(7, 1.5)も同じ例外です。例外は失敗の通知であり、当たり0回の成功結果ではありません。呼び出す側は入力を見直してから再実行します。入力の読み取りや外の道具が失敗した場合も、途中までの記録を20回分の完成結果として表示せず、失敗を知らせて条件を確認する必要があります。
制限時間を設けて外部の処理を呼ぶ仕組みでは、時間切れを成功扱いしない設計が必要です。たとえば10回の予定で4回しか完了していないなら、分母を10として割合を出すのは誤りです。ここに示した関数は外部通信や時間制限を持たないので、そのような失敗を自動処理する機能はありません。実際に追加する際は、完了件数と失敗の通知を別々に検査します。
練習:条件を言葉と数字に戻す
次の5問はそれぞれ独立です。割り切れる割合は分数または小数で答え、回数は整数で答えてください。どの札も同じ確率で選ばれ、引いた札は毎回戻して混ぜるものとします。
- 8枚の札のうち3枚が当たりです。1回の当たりの理論上の確率を答えてください。
- 6枚の札のうち2枚が当たりです。12回引いて当たりが7回でした。実験値と外れの回数を答えてください。
- 0から6の7種類の数字のうち、0、1、2を当たりとします。記録が6、2、2、4、0、5のとき、当たりの回数と実験値を答えてください。重複した数字も出た回ごとに数えます。
- 4枚の札のうち1枚が当たりです。シードを固定した実験で、試行回数を0、1、10としたとき、割合を計算できない場合を答えてください。
- 9枚の札のうち4枚が当たりです。18回中8回当たった記録と、18回中10回当たった記録があります。それぞれの実験値を分数で示し、理論値と一致する記録を答えてください。
練習の答えと照合
- 3/8です。全8通りに対して当たりが3通りです。残り5枚を外れとして加えると8枚に戻ります。
- 実験値は7/12、外れは5回です。7回と5回で12回になります。理論上の2/6と実験値は役割の異なる値です。
- 当たりは2、2、0の3回、実験値は3/6で1/2です。残りの6、4、5は外れなので合計6回です。同じ2を1回にまとめると、試行回数に対応しません。
- 0回です。1回と10回なら分母が正なので、当たり回数が0でも割合は計算できます。0回では当たりも外れも0回で、比較に使う割合は定義しません。
- 理論値は4/9です。8/18は約分すると4/9、10/18は5/9なので、前者が一致します。前者の外れは10回、後者の外れは8回で、いずれも合計18回です。一致した記録があることは、今後の実験でも毎回一致する保証にはなりません。
分数と数え上げはPython 3.14.8でも照合しました。入力した札と記録は各問題の条件どおりで、期待値と実際の値は順に3/8、7/12と5、3と1/2、0回、4/9と5/9です。計算結果を場面へ戻し、当たりと外れが指定の回数に合うことも確認しています。
覚えておくこと
- 理論値はモデルの条件から、実験値は観測した回数から求めます。
- 戻す操作、当たりの範囲、試行回数を固定して比較します。
- シードと実行環境、乱数の呼び出し方を記録します。
- 0回の割合は定義せず、入力の失敗は成功結果と区別します。
- 試行を増やしても、毎回必ず理論値に近づくわけではありません。
つまずいたときの確認
割合を求める前に「何を1回と数えたか」を説明してみましょう。札の枚数を分母にするのか、実際に引いた回数を分母にするのかが混ざっている場合は、理論値と実験値を別の行に書きます。条件の違う数字を同じ表に並べたときは、どの操作が変わったかを記録に戻って探します。
個別指導では、数字を1つずつ指しながら当たりの判定と累計を説明できるかを確かめます。とくに境界の2を含めていないか、重複を別の試行として数えたか、0回を割り算に渡していないかが手がかりです。結果の数字だけでなく、そこに至る条件と途中の状態がそろえば、実験の揺れを根拠を持って読めます。
読んで終わりにするか、ここから変えるか。
武蔵境駅徒歩30秒、講師1人に生徒1人の完全1対1。授業のあいだ、先生は隣を離れません。いまの詰まりを、無料相談でそのまま話してください。
まず15分だけ電話で話したい方は、無料電話相談(15分)から。塾からお電話を差し上げます。
本気になった日が、入塾の日。
お子様の教育、迷ったら「丸投げ」してください。必ず、期待以上の結果で返します。武蔵野で育む、武蔵境で学ぶ。
電話は年中無休。365日、24時間、お電話可能。




