誕生日被りの確率についてpythonで計算してみる

誕生日被りについて調べてみた。

思い付きと調査

ふと、二十数人のグループがあると、その中の二人は誕生日が被っていると耳にしたことがあるなと思って、どうなんだろうと調べてみることにした。

調べ方は、pythonでの数値計算。コードを書いて、結果を見てみた。その結果とネットで調べた結果を比べてみる。

n人のグループの中で2人の誕生日が被る確率を調べた。 その後、0人のグループに1人ずつ人を追加し、何人目の追加でグループ内の2人の誕生日が被るかを調べた。

ネットでの調査によると、23人いれば50%の確率で被るようです。誕生日のパラドックスというそう。参考サイト:

同じ誕生日の二人組がいる確率について | 高校数学の美しい物語
同じ誕生日の二人組がいる確率(誕生日のパラドックス)の求め方,具体的な確率の値,三人組の場合はどうなのか。

ちなみに閏年は考慮していない。

n人のグループでの被る確率

余事象を使って計算した。繰り返し実行するのも面倒なので、1から指定された数値までのすべての人数のグループで計算するようにした。 ソースは以下:

"""
入力された人数までのグループそれぞれの誕生日が被る確率を計算する
"""


def calc_probability(n):
    """
    n人のグループの中で2人の誕生日が被る確率を返す
    """
    m = 1
    for i in range(n):
        m *= (365-i)/365
    return 1-m


if __name__ == '__main__':
    n = int(input('人数を入力 --> '))
    if n < 1 or n > 365:
        print('1から365までの数字を指定してください')
        exit(1)
    print('人数 \t 確率')
    for i in range(1, n+1):
        print(i, '\t', calc_probability(i))

これを実行して、100を指定した時の結果はこちら:

人数を入力 --> 100
人数     確率
1        0.0
2        0.002739726027397249
3        0.008204165884781345
4        0.016355912466550215
5        0.02713557369979347
6        0.040462483649111425
7        0.056235703095975365
8        0.07433529235166902
9        0.09462383388916673
10       0.11694817771107768
11       0.14114137832173312
12       0.1670247888380645
13       0.19441027523242949
14       0.2231025120049731
15       0.25290131976368646
16       0.2836040052528501
17       0.3150076652965609
18       0.3469114178717896
19       0.37911852603153695
20       0.41143838358058027
21       0.443688335165206
22       0.4756953076625503
23       0.5072972343239857
24       0.538344257914529
25       0.568699703969464
26       0.598240820135939
27       0.6268592822632421
28       0.6544614723423995
29       0.6809685374777771
30       0.7063162427192688
31       0.7304546337286439
32       0.7533475278503208
33       0.7749718541757721
34       0.7953168646201543
35       0.8143832388747153
36       0.8321821063798795
37       0.8487340082163846
38       0.864067821082121
39       0.878219664366722
40       0.891231809817949
41       0.9031516114817354
42       0.9140304715618692
43       0.9239228556561199
44       0.9328853685514263
45       0.940975899465775
46       0.9482528433672548
47       0.9547744028332994
48       0.9605979728794225
49       0.9657796093226765
50       0.9703735795779884
51       0.9744319933344283
52       0.9780045093342753
53       0.9811381134839128
54       0.9838769627588515
55       0.9862622888164461
56       0.9883323548852008
57       0.9901224593411699
58       0.9916649793892612
59       0.992989448417817
60       0.994122660865348
61       0.9950887988052908
62       0.9959095748953655
63       0.9966043868309472
64       0.9971904789669755
65       0.9976831073124921
66       0.9980957046404045
67       0.9984400429793998
68       0.9987263912544141
69       0.9989636663083863
70       0.9991595759651571
71       0.9993207531773187
72       0.9994528806414568
73       0.9995608055560187
74       0.9996486444448149
75       0.9997198781738114
76       0.9997774374531652
77       0.999823779243739
78       0.9998609545813611
79       0.9998906683968511
80       0.9999143319493135
81       0.999933108508368
82       0.9999479529215796
83       0.9999596456898823
84       0.9999688221494433
85       0.9999759973260097
86       0.9999815869898157
87       0.9999859253976947
88       0.9999892801659155
89       0.9999918646738591
90       0.9999938483561236
91       0.9999953651998191
92       0.9999965207253437
93       0.9999973976932023
94       0.9999980607467152
95       0.9999985601708488
96       0.9999989349209019
97       0.9999992150512947
98       0.9999994236541013
99       0.9999995783990275
100      0.9999996927510721

ネット調査と同じになる。計算式は同じだから当然。57人で99%の確率で2人の誕生日が被ることがわかる。

何人目のグループ追加で被るか

違う視点で、グループに人を追加していくことを考えてみる。

ランダムに誕生日を与えた人を空のグループに1人ずつ追加していき、グループ内で2人の誕生日が被った時点で、追加をやめ、その時点のグループの人数を記録していく。これを1,000,000回ほど繰り返して、平均値(算術平均)や中央値、標準偏差を見てみることにした。

おそらく、23人辺りが平均値、中央値になりそう。上の確率で2人から順に確率判定をする感じになるだろうから。

ソースはこちら:

"""
誕生日被りについて
"""


from random import randrange
from statistics import mean, median, pstdev


def birthday_conflict():
    """部屋に人を追加していき、誕生日について何人目で衝突したかカウントする。閏年は対応してない"""
    count = 1
    days_store = {}
    while True:
        r = randrange(0, 365)
        if r in days_store:
            break
        else:
            days_store[r] = 1
        count += 1
    return count


if __name__ == '__main__':
    counts = []
    for _ in range(1_000_000):
        c = birthday_conflict()
        counts.append(c)
    print('size:\t', len(counts))
    print('max:\t', max(counts))
    print('min:\t', min(counts))
    print('mean:\t', mean(counts))
    print('median:\t', median(counts))
    print('pstdev:\t', pstdev(counts))

これを実行した結果はこちら:

size:    1000000
max:     101
min:     2
mean:    24.620545
median:  23.0
pstdev:  12.199354118270975

概ね予想通りな結果になった。標準偏差もまあそのくらいの値かなという感じ。

平均値が比較的大きいのは標準偏差が大きいためだろう。$-3\sigma$などは0以下になってしまう。おそらくこの辺りが要因だとは思うが確信はない。

おわり

何人くらいで被るのかについては解決できたからいいだろう。上の参考サイトでは、3人が被る場合の確率の計算もしている。結構複雑になるようで、実装はしてみてない。

23人いたら誕生日被りが50%でありそうというのは、面白い話だと思う。366人いてやっと誕生日が被るというのはほぼほぼ奇跡に近い事象だと改めて感じる。 23人グループを見かけたら誕生日が被ってないかチェックしてみるのは面白そうだ。いや個人情報なので、若干調べるのは難しい気がする。

以上です。


Amazonアソシエイト

https://amzn.to/3wR9jZm
タイトルとURLをコピーしました