(119) 重複無しで一様分布の乱数を生成する。

投稿者: | 2024年1月18日

228 views

この記事は最終更新から 397日 が経過しています。

【1】やりたいこと

Pythonで乱数を生成したい。

ただし、以下の条件を満たすこと。
・重複しないこと
・一様分布であること

【2】やってみる

1) numpyを使わない場合

まずは、普通に乱数を生成してみる。

>>> import random
>>>
>>> [random.randint(1, 100) for _ in range(5)]
[54, 28, 87, 63, 62]
>>> [random.randint(1, 5) for _ in range(3)]
[2, 4, 5]
>>> [random.randint(1, 5) for _ in range(3)]
[5, 1, 2]
>>> [random.randint(1, 5) for _ in range(3)]
[1, 2, 5]
>>> [random.randint(1, 5) for _ in range(3)]
[4, 4, 4]

重複する可能性がある。

重複を回避するには random.sample を使う。

>>> random.sample([1,2,3,4,5], 3)
[2, 3, 4]
>>> random.sample([1,2,3,4,5], 3)
[2, 3, 5]
>>> random.sample([1,2,3,4,5], 3)
[3, 5, 1]
>>> random.sample([1,2,3,4,5], 3)
[2, 4, 3]
>>> random.sample([1,2,3,4,5], 3)
[1, 2, 4]
>>> random.sample([1,2,3,4,5], 3)
[3, 1, 2]
>>> random.sample([1,2,3,4,5], 3)
[2, 4, 5]
>>> random.sample([1,2,3,4,5], 3)
[5, 1, 4]
>>> random.sample([1,2,3,4,5], 3)
[4, 1, 2]
>>> random.sample([1,2,3,4,5], 3)
[5, 4, 2]

重複しない。

念のために 1~5の範囲で 5個の乱数を生成させてみる。

>>> random.sample([1,2,3,4,5], 5)
[4, 5, 3, 1, 2]
>>> random.sample([1,2,3,4,5], 5)
[5, 4, 2, 3, 1]
>>> random.sample([1,2,3,4,5], 5)
[4, 2, 1, 3, 5]
>>> random.sample([1,2,3,4,5], 5)
[5, 2, 3, 1, 4]
>>> random.sample([1,2,3,4,5], 5)
[1, 3, 2, 4, 5]
>>> random.sample([1,2,3,4,5], 5)
[5, 2, 1, 4, 3]
>>> random.sample([1,2,3,4,5], 5)
[4, 3, 5, 1, 2]
>>> random.sample([1,2,3,4,5], 5)
[5, 1, 3, 4, 2]
>>> random.sample([1,2,3,4,5], 5)
[3, 4, 1, 5, 2]
>>> random.sample([1,2,3,4,5], 5)
[3, 1, 2, 4, 5]

確かに重複しない!

範囲が大きい場合は range を使えばよい。

>>> random.sample(range(1,1000), 5)
[582, 820, 778, 67, 785]
>>> random.sample(range(1,1000), 5)
[602, 27, 896, 161, 186]
>>> random.sample(range(1,1000), 5)
[220, 284, 887, 182, 905]

2) numpyを使う場合

まずは普通に整数乱数を生成してみる。

>>> import numpy as np
>>>
>>> np.random.randint(1,5,3)
array([1, 4, 1])

いきなり重複した。

重複を回避するには numpy.random.choicereplace=False 指定で使う。

>>> np.random.choice([1,2,3,4,5], 3, replace=False)
array([3, 2, 5])
>>> np.random.choice([1,2,3,4,5], 3, replace=False)
array([2, 4, 3])
>>> np.random.choice([1,2,3,4,5], 3, replace=False)
array([4, 2, 1])
>>> np.random.choice([1,2,3,4,5], 5, replace=False)
array([3, 2, 4, 1, 5])
>>> np.random.choice([1,2,3,4,5], 5, replace=False)
array([5, 4, 3, 1, 2])
>>> np.random.choice([1,2,3,4,5], 5, replace=False)
array([2, 4, 3, 1, 5])
>>> np.random.choice([1,2,3,4,5], 5, replace=False)
array([2, 1, 4, 3, 5])
>>> np.random.choice([1,2,3,4,5], 5, replace=False)
array([2, 1, 4, 3, 5])

重複しない。

範囲が大きい場合は range を使えばよい。

>>> np.random.choice(range(1,1000), 3, replace=False)
array([139, 356, 666])
>>> np.random.choice(range(1,1000), 3, replace=False)
array([304,   3, 512])
>>> np.random.choice(range(1,1000), 3, replace=False)
array([247, 752, 744])
>>> np.random.choice(range(1,1000), 3, replace=False)
array([976, 821, 382])
>>> np.random.choice(range(1,1000), 3, replace=False)
array([960, 376, 934])

replace=False を外すと重複する可能性がある。

>>> np.random.choice([1,2,3,4,5], 3)
array([1, 5, 3])
>>> np.random.choice([1,2,3,4,5], 3)
array([2, 2, 4])

重複した。

【3】応用

(1) 配列の中からランダムに要素を抽出したい。

配列を作る。

>>> import numpy as np
>>>
>>> a = np.random.randint(100, 999, [5,2])
>>> a
array([[846, 394],
       [166, 615],
       [380, 439],
       [390, 236],
       [853, 882]])

配列要素を指し示す indexを乱数で作る。

>>> i = np.random.choice(range(5), 3, replace=False)
>>> i
array([2, 4, 0])

indexで指定した配列要素だけを抽出し、新しい配列を作る。

>>> c = a[i]
>>> c
array([[380, 439],
       [853, 882],
       [846, 394]])

使うたびに思うけど、これが便利だなぁ…


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です