pythonで乱数を生成するとき、pythonのrandomや、numpyのnp.random、scipyのscipy.statsを使用することがあると思います。
この記事では、乱数生成の再現性で重要となる乱数シード(seed, 種)の設定方法を紹介します。
この記事でできること
pythonで疑似乱数を生成することは多々あると思いますが、この記事では乱数シード(seed, 種)の設定方法を紹介します。
疑似乱数を使用するプログラムをプログラミングする目的は、文字通りランダムな値を使った結果を得るためです。しかし、ランダムな値を使用するという目的上、同じソースコード(スクリプト)を実行しても毎回同じ結果が得られるとは限りません。
乱数シードを設定すると毎回同じ疑似乱数が得られ、再現性のあるプログラムにすることができます。乱数シードを設定する一文をソースコード/スクリプトに記載しておくと、次回に同じスクリプトを実行した際に同じ結果が得られるので、コードの再現性を確認するのに役立ちます。
乱数シードを設定せずに他の人にソースコードを渡した場合、もしくは共有した場合、渡した方のPC環境で同じ処理結果が得られるかわかりません。その場合、ソースコードが正しく動作しているか確認しづらいです。乱数シードを設定しておくことは、ソフトウェアの開発で重要となります。
この記事では、pythonでよく使われる乱数生成方法である次の3つについて乱数シードの設定の仕方を紹介します。
- pythonの、randomモジュール
- numpyの、numpy.randomモジュール(np.random)
- scipyの、scipy.statsモジュール
pythonの、randomモジュール
pythonのrandomモジュールでは、関数ramdom.seed(seed_value)でシードを設定します。”seed_value”が乱数シードの値です。
import random
random.seed(314) # 乱数シードを314に設定
乱数シードの値”seed_value”には任意の整数を指定します。
古くからある疑似乱数生成法の関数では、乱数シードに0を指定すると適切に乱数が得られないという問題のある可能性がありました。例えば、C言語のrand()関数で使われているような線形合同法による疑似乱数生成器の場合です。
ですが、メルセンヌツイスタと呼ばれる疑似乱数生成法が使用されているpythonでは問題ないとは思います。正確には、メルセンヌツイスタの提案者が初期値を適切に設定する方法も含めて手法として提案しているためです。(ただ、私を含め古い人は乱数シードに0を指定することを避ける傾向にあるので、年上の方を忖度してなるべく0は避けた方がましょう。余談でした。)
乱数シードの設定と、乱数生成を行うサンプルコードの例は次の通りです。
import random
random.seed(314) # 乱数シードを314に設定
a = random.random() # 0~1の乱数aを生成
print("a:", a) # 乱数aを標準出力で表示
aa = random.random() # 0~1の乱数aaを生成
print("aa:", aa) # 乱数aaを標準出力で表示(aaはaと異なる値)
# 何度も乱数を生成し、標準出力で表示
random.seed(314)
b = random.random()
print("b:", b)
random.seed(314)
c = random.random()
print("c:", c)
random.seed(314)
d = random.random()
print("d:", d)
dd = random.random()
print("dd:", dd)
このコードを実行すると、乱数aとaaは異なる値が生成されます。random.random()で乱数を生成しているので当たり前です。一方で、乱数シードを都度、毎回ramdom.seed(314)で設定することで、乱数a, b, c, dは同じ値が生成されます。
上のサンプルコードを実行した結果は次の通りです(私の環境では)。上で説明したように、a, b, c, dは同じ値となり、かつ、aaとddも同じ値となります。
a: 0.19643127513153125
aa: 0.11146576088475146
b: 0.19643127513153125
c: 0.19643127513153125
d: 0.19643127513153125
dd: 0.11146576088475146
このように、乱数を生成するメソッドrandom.random()で毎回同じ値を生成させるには、
random.seed()で乱数シードを設定します。
numpyの、numpy.random(np.random)モジュール
numpyのnumpy.random/np.randomモジュールでは、numpy.random.seed(seed)で乱数シードを指定します。”seed”が乱数シードの値です。
import numpy as np
np.random.seed(314) # 乱数シードを314に設定
乱数シードの設定と、乱数生成を行うソースコードの例は次の通りです。
import numpy as np
np.random.seed(314) # 乱数シードを314に設定
a = numpy.random.rand() # 0~1の乱数aを生成
print("a:", a)
np.random.seed(314)
b =numpy.random.rand()
print("b:", b)
このコードを実行すると次の通りになります(私の環境では)。
a: 0.9168735814929675
b: 0.9168735814929675
scipyの、scipy.statsモジュール
様々な確率分布や統計量を扱えるscipyパッケージのscipy.statsモジュールで疑似乱数の生成を行うこともあるかと思います。
scipy.statsでは、乱数の生成にnumpy.randomを()使用しているそうです。そのため、scipy.statsでの乱数シードの設定も、numpy.randomと同様に、numpy.random.seed/np.random.seedを使用します。
import numpy as np
from scipy import stats
np.random.seed(314) # 乱数シードを314に設定
参考URL。
stack overflow: scipy.stats seed?
おわりに
今回は乱数シードの設定方法を紹介しました。
少しやっかいなのは、モジュールやライブラリごとに乱数シードの設定方法が異なることです。他にも、pandasのdataframeのsample()や、tensorflow、pytorchなど、それぞれのライブラリで疑似乱数を生成することがあるかと思いますが、それぞれで乱数シードを設定する方法があります。
どうでもいいですけど、ランダムシードとガンダムシードって響きが似てますよね。機動戦士ガンダムSEEDの製作者はこれを意図したのではないかと思ってしまいます。余談でした。
コメント