疑似乱数の生成
Python標準ライブラリの randomモジュールには様々な種類の 疑似乱数 を生成する関数が用意されています。疑似乱数とは seed によって値が確定的に決まる数字の列で、0 ~ 9 が均一の割合で分布しています。疑似乱数は一定の周期をもちますが、この周期が長いほど高品質の疑似乱数であることを意味します。Pythonではメルセンヌツイスタ (Mersenne twister) とよばれる周期 2**19937-1 の生成器(ジェネレータ)を使用して疑似乱数を作りだしていきます。
random.random()
random.random() は 0.0 以上、1 未満の 浮動小数点数型の一様乱数を生成します。
# PYTHON_RANDOM_01
# randomモジュールをインポート
import random
# 0~1の乱数を3個生成
for k in range(3):
x = random.random()
print(x)
0.8792205530080683 0.0006700208569692112 0.04848366552796579
random.uniform(a, b)
random.uniform(a, b) は a ≦ b であるときは、a ≦ N ≦ b の範囲で浮動小数点数型の一様乱数 N を返します。a > b であるときは、b ≦ N ≦ a の範囲で浮動小数点数型の乱数 N を返します。
# PYTHON_RANDOM_02
# randomモジュールをインポート
import random
# 1~10の乱数を3個生成
for k in range(3):
x = random.uniform(1, 10)
print(x)
4.672361143198837 2.7458475789026497 7.883862872788563
random.randrange(start, stop [, step])
random.randrange(start, stop [, step]) は start から stop-1 まで step 刻みで並んだ数字の中から1つをランダムに選んで返します。たとえば
と記述した場合、1 から 15 まで 2 刻みで並んだ数字
の中から1つを無作為に選んで x に格納します。実際には、この関数は range(start, stop, step) で生成された数字のシーケンスから1つの要素を抜き出すという処理を行なっています。
# PYTHON_RANDOM_03
# randomモジュールをインポート
import random
# 0~9 の整数乱数を生成
a = random.randrange(10)
# 1~9 の整数乱数を生成
b = random.randrange(1, 10)
# 1~9 の奇数乱数を生成
c = random.randrange(1, 10, 2)
my_list = [a, b, c]
print(my_list)
[8, 1, 5]
random.randint(a, b)
random.randint(a, b) は、a ≦ N ≦ b の範囲で無作為な整数 N を返します。この関数は randrange(a, b+1) のエイリアスです。すなわち、実際にはこの関数の内部で randrange() に引数 a と b+1 を渡して呼び出すという処理を行なっています。引数の指定の仕方が randrange() とは異なっていることに注意してください。
# PYTHON_RANDOM_04
# randomモジュールをインポート
import random
# 空白のリストを用意
my_list = []
# 1~100の乱数を5個生成してリストの要素に追加
for k in range(5):
x = random.randint(1, 100)
my_list.append(x)
print(my_list)
[38, 44, 98, 83, 34]
東京大学のデータサイエンティスト育成講座 ~Pythonで手を動かして学ぶデ―タ分析~ 新品価格 | ![]() |

ジェネレータの初期化と seed の固定
randomモジュールのジェネレータ(メルセンヌツイスタ)は seed とよばれる初期値をもとに疑似乱数列を生成しています。seed は「種」という意味の英語です(数字を次々と生み出すのでこのようによばれています)。seed値が与えられると疑似乱数列は一意に定まります(つまり疑似乱数列 R は seed の関数 R(seed) です)。random.seed(a) を使うと、この seed値を固定してジェネレータを初期化することができます。具体例を下のサンプルコードで説明します。
# PYTHON_RANDOM_05
# randomモジュールをインポート
import random
# 疑似乱数ジェネレータを初期化して乱数シードを固定
random.seed(1)
# 1~10の乱数を3個生成
for k in range(3):
x = random.random()
print(x)
# 1行開ける
print("")
# 疑似乱数ジェネレータを初期化して乱数シードを固定
random.seed(1)
# 1~10の乱数を3個生成
for k in range(3):
x = random.random()
print(x)
0.13436424411240122 0.8474337369372327 0.763774618976614 0.13436424411240122 0.8474337369372327 0.763774618976614
最初の random.seed(1) という記述によって、次の for文では seed を 1 として
0.847433736937232
0.763774618976614
というように乱数を順に生成(ジェネレート)しています。そのあとに、もう一度 random.seed(1) と記述することによって、ジェネレータが初期化され、次の for文で再び seed = 1 の乱数列の 1 番目から
0.847433736937232
0.763774618976614
というように数字が並びます。random.seed(a) の引数 a が省略された場合には、seed として現在のシステム時刻が指定されます。
内包表記を用いた乱数リストの作成
いくつかの乱数をまとめて作りたいケースも多いはずです。先ほどの randint() のサンプルコードのように for文を使っても可能ですが、リスト内包表記 (comprehention) を使うと、たった1行で乱数リストをつくることができます。
# PYTHON_RANDOM_06
# randomモジュールをインポート
import random
# 0 から 9 までの整数乱数のリストを作成
num_list = [random.randrange(10) for i in range(10)]
print(num_list)
[5, 8, 5, 0, 3, 9, 8, 8, 2, 9]
NumPy 乱数配列
NumPy の random モジュールには乱数を要素とする配列を生成するための関数が用意されています。
numpy.random.rand()
numpy.random.rand() は 0 以上 1 未満の一様乱数を要素にもつ配列を返します。
引数には配列の形を指定します。たとえば、2, 3 を渡すと、2行3列の乱数配列を返します。
# PYTHON_RANDOM_07
import numpy as np
# seedを設定
np.random.seed(10)
# 2行3列の乱数配列
x = np.random.rand(2, 3)
print(x)
[[0.77132064 0.02075195 0.63364823] [0.74880388 0.49850701 0.22479665]]
numpy.random.uniform()
numpy.random.uniform() は指定した範囲内の一様乱数を要素にもつ配列を返します。
引数の low は乱数の下限値、high は乱数の上限値です。
size で戻り値の配列の形状を指定することもできます。
# PYTHON_RANDOM_08
import numpy as np
# seedを設定
np.random.seed(11)
# 1~5の乱数を要素にもつ2×2サイズの配列を生成
x = np.random.uniform(1, 5, (2, 2))
print(x)
[[1.72107876 1.07790097] [2.85287411 3.89973572]]
numpy.random.randint()
numpy.random.randint() は指定範囲内で整数型の一様乱数配列を返します。
引数の low は乱数の下限値、high は乱数の上限値です。
size で戻り値の配列の形状を指定することもできます。
# PYTHON_RANDOM_09
import numpy as np
# seedを設定
np.random.seed(10)
# 1~9の一様整数乱数を要素にもつ3×3配列を生成
x = np.random.randint(1, 9, (3, 3))
print(x)
[[2 6 5] [8 1 2] [4 5 2]]
random_integers は非推奨です
Jupyter Notebook でコードを書いてnumpy モジュールの random_integers という関数を呼び出そうと思ったら、
Please call randint(1, 100 + 1) instead.
という警告メッセージが表示されました。日本語に訳しておきます:
この関数は廃止されます(非推奨です)。
代わりに randint(1, 100 + 1) を呼び出してください。
警告文が表示されるだけで、まだ使えることは使えるので、Python 本体 (現在の最新版は 3.6.5) から消えたわけではないようです。しかし、こんなに嫌われるには何か理由があるのだろうと思案してみると ...... 確かに、この関数が非推奨になるのも当然かもしれないと思えてきました。
random_integers はランダムな整数を呼びだす関数です。
たとえば "random_integers(100)" と記述すると、1 から 100 までの乱数を生成します。
しかし、上の忠告にもある通り、randint関数があるので、わざわざこんな関数を作る必要もないはずです。「似たような機能は極力重複しないようにする」という Python の哲学にも明らかに反しています。
そもそも、random_integers() は引数の指定の仕方が不自然です。Range関数は Range(100) と書けば 0 から 99 の数字を返し、リストやタプルなどのイテラブルオブジェクトの要素のインデックスのつけ方も同様です。だから他の人が random_integers() を使ったコードを読むと、いらぬ誤解を与えてしまう可能性もあるわけです。う~む。これはいけませんね(← 使おうとしたくせに)。結論としては非推奨な関数は使わないほうが良いということです(← そんなことは誰でもわかる)。
それにしても最近のエディタは親切ですね。
「これを使ってはいけないよ」
と警告するだけでなく、
「代わりにこの関数を使おうね」
とアドバイスまでくれるのですから。私がプログラミングを学び始めた頃 (つまり大昔) は、コンピュータというものは、こちらが間違えると無愛想なエラーを返すだけなので、必死にどこが間違っているかを目で追っていました。本当に良い時代になったものです。
コメントを書く