[Python] ランダムな数値(乱数)の生成について(randomモジュール)

Python標準ライブラリのrandomモジュールは、擬似乱数を生成することができます。
これを利用して、ランダムな数値を出力したり、リストの要素などをランダムにシャッフルすることもできます。
本記事は、このようなrandaomモジュールの基本的な使い方についてまとめます。
# 2019/2/8 記事更新

確認した環境

  • OS: Ubuntu 16.04LTS
  • Python: ver3.6.4

ところで、なぜ「擬似」乱数?

下記にあるとおり、計算機で確率的な計算によって乱数を求めているので「擬似」乱数とのこと。ちなみにPythonでは乱数生成器としてメルセンヌツイスタというものを使っているそうです。

擬似乱数(ぎじらんすう、pseudorandom numbers)は、乱数列のように見えるが、実際には確定的な計算によって求めている擬似乱数列による乱数。
(中略)
真の乱数列は本来、規則性も再現性もないものであるため、本来は確定的な計算によって求めることはできない(例:サイコロを振る時、今までに出た目から次に出る目を予測するのは不可能)。一方、擬似乱数列は確定的な計算によって作るので、その数列は確定的であるうえ、生成法と内部状態が既知であれば、予測可能でもある。

wikipedia「擬似乱数」

ランダムな整数値を生成

ランダムな整数値を生成するメソッドを2つ示します。

(1)random.randrange()

random.randrange(start, stop[, step])は、range(start, stop, step)で生成されるイテラブルからランダムに抽出された要素を返します。引数はrange()メソッドと同じです。
実際の使い方を以下に示します。最初にrandaomモジュールをインポートします。

# randomモジュールをインポート
>>> import random

>>> random.randrange(10, 50, 2)
44
>>> random.randrange(10, 50, 2)
32
>>> random.randrange(10, 50, 2)
42

(2)random.randint()

random.randint(a, b)はもう少し簡単に使えます。
引数で指定したa〜bの範囲のランダムな整数値を返します。 (randrange(a, b+1)と同じです)
実際の使い方を下記に示します。

>>> import random
>>> random.randint(10, 100)
63
>>> random.randint(10, 100)
15
>>> random.randint(10, 100)
18

乱数の初期化(seed)

乱数を初期化するには、random.seed()を使います。引数を省略するとシステム時刻が設定され、毎回異なる値が生成されます。引数に任意の数値を設定すると、毎回同じ値が生成されます。

例を以下に示します。random.seed()の引数の有無の影響も併せて確認する為、初期化→ランダム値生成を5回繰り返してみました。

seed()の引数を設定

引数を、例えば10に設定してみました。初期化した後はランダムな数値が生成されますが、再度初期化をすると、同じ値が毎回同じ値が生成されます。

#0〜100の整数値をランダムに生成。これを5回繰り返す
>>> for i in range(5):
...     random.seed(10)
...     random.randint(0, 100)
... 
73
73
73
73
73

seed()の引数を省略

初期化→ランダム値生成を繰り返すと、毎回異なる値が出力されます。

#0〜100の整数値をランダムに生成。これを5回繰り返す
>>> for i in range(5):
...     random.randint(0, 100)
... 
4
54
61
73
1

ランダムな実数値を生成

ランダムな実数値を求めるにあたっては、統計学を用いた数学的な分布(一様分布、ガウス分布、他にも知らないもの多数)が用いられます。
ここでは、一様分布を用いた基本的なメソッドを2つ記載します。

(1)random.uniform()

random.uniform(a, b)は、引数に設定したaとbの間の浮動小数点Nを返します。
(a ≦ bの場合は a ≦ N ≦ b、b ≦ aの場合は b ≦ N ≦ a)
下記に例を示します。

>>> import random
#[10.0, 20.0]の実数値
>>> random.uniform(10, 20)
11.941227599157115

(2)random.random()

random.random()は引数はとらず、0.0〜1.0の間の数値(浮動小数点)を返します。

>>> import random
# [0.0,1.0]の実数値
>>> random.random()
0.34355446189507477

ランダムに要素を抽出

シーケンス型データ(文字列、リスト、タプル、range)からランダムに要素を抽出するには、choice()メソッドを使います。抽出する元データを引数に設定します。

>>> import random
>>> random.choice('abcdefg')
'e'
>>> random.choice(range(10))
7

引数となるシーケンスデータseqが空の場合はIndexErrorを返します。

>>> random.choice([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/hibikisan/anaconda3/envs/python3.7/lib/python3.7/random.py", line 261, in choice
    raise IndexError('Cannot choose from an empty sequence') from None
IndexError: Cannot choose from an empty sequence

ランダムにk個抽出(重複あり)

ランダムにk個のデータを抽出する際に、値の重複を許す場合はchoices()メソッドを使います。

random.choices(population, k=1)

シーケンスまたは集合データpopulationから重複有りで選ばれた、サイズkのリストを返します。(※ここで記載した引数の他にウエイト設定のパラメータもありますがここでは割愛)
データが空の場合はIndexErrorを返します。

>>> random.choices('abcdefg', k=3)
['e', 'b', 'c']
>>> random.choices(range(10), k=3)
[3, 9, 3]

ランダムにk個抽出(重複なし)

ランダムにk個のデータを抽出する際に、重複を許さない場合はsample()メソッドを使います。

random.sample(population, k)

シーケンス型データpopulationから重複無しで選ばれたサイズkのリストを返します。元のリストは置き換えられません。例を以下に示します。

>>> s = 'abcdefg'
>>> random.sample(s, k=3)
['f', 'c', 'e']

#元のリストsは変わらない
>>> s
'abcdefg'

要素をランダムにシャッフル

データをシャッフルするには、shuffle()メソッドを使います。
引数に設定したミュータブル(変更可)なシーケンス(リスト等)をシャッフルします。インプレースで処理されるので、元のデータは新しいものに置き換わります。

>>> l = ['one', 'two', 'three', 'four', 'five']
>>> random.shuffle(l)
>>> l
['two', 'one', 'four', 'three', 'five']

イミュータブル(変更不可)なシーケンス(文字列、range、タプル等)の場合はエラーとなります。

>>> s = 'abcdefg'
>>> random.shuffle(s)
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/hibikisan/anaconda3/lib/python3.6/random.py", line 275, in shuffle
    x[i], x[j] = x[j], x[i]
TypeError: 'str' object does not support item assignment

ちなみに、このようなシーケンスをシャッフルしたい場合は、sample()メソッドを使います。

>>> s = 'abcdefg'
>>> ''.join(random.sample(s, k=len(s)))
'gdcaefb'

>>> r = range(6)
>>> random.sample(r, k=len(r))
[2, 3, 1, 0, 5, 4]

まとめ

randomモジュールを用いてランダムに数値を生成する方法、およびランダムに要素を抽出する方法についてまとめました。

Learn more...

書籍でもう少し詳しく学びたい場合はこちらもどうぞ。筆者もかなり参考にさせてもらっています!