【NumPy】np.randomじゃなくてRandomStateを使いたい理由


結論から

np.randomは広範囲に影響があるので、RandomStateを使いましょう。

はじめに

hoge君が以下のようなコードを作りました。

import numpy as np

np.random.seed(1234)

# 処理Aのブロック
for i in range(1,5):
    arr1 = np.random.randint(1,10,10)

    #------------------------------------
    # ...(略:arr1を使った具体的な処理)...
    #------------------------------------

後日、hoge君は処理Aの前に処理Bを実装する必要が出てきました。

import numpy as np
np.random.seed(1234)

# 処理B
arr2 = np.random.randint(1,10,10)

#------------------------------------
# ...(略:arr2を使った具体的な処理)...
#------------------------------------

# 処理Aのブロック
for i in range(1,5):
    arr = np.random.randint(1,10,10)
    print(aaa)

    #------------------------------------
    # ...(略:arr1を使った具体的な処理)...
    #------------------------------------

A君「ああ、まずい。これでは処理Aの結果が以前と変わってしまう。。。」

A君「あ!でももう一度シード設定すればいっか」(安易)

import numpy as np

# 処理B
np.random.seed(2345) # 一応別のシードにした
arr2 = np.random.randint(1,10,10)

#------------------------------------
# ...(略:arr2を使った具体的な処理)...
#------------------------------------

# 処理Aのブロック
np.random.seed(1234) # こっちはさっきと同じシード
for i in range(1,5):
    arr = np.random.randint(1,10,10)
    print(aaa)

    #------------------------------------
    # ...(略:arr1を使った具体的な処理)...
    #------------------------------------

A君「これで一安心~」

数日後

先輩「この前作ってもらった処理、ユーザー毎にマルチスレッドで処理したいんだよね」

A君「」

結論

要はnp.random.seed()はグローバルにいろんな範囲に影響あるからやめようねって話です。
一人での開発ならばなんとか管理できるかもしれないけど、複数人の開発や
並列処理や関数化・クラス化などの実装を進めると、どこで再現性が取れなくなっているか追えなくなります。

RandomStateを使えば、ほかの処理に影響を与えずに乱数生成ができる。

import numpy as np

# 処理B
rs2 = np.random.RandomState(2345)
arr2 = rs2.randint(1,10,10)
# ...(略:具体的な処理)...

# 処理Aのブロック
rs1 = np.random.RandomState(1234)
for i in range(1,5):
    arr = rs1.randint(1,10,10)
    print(aaa)
    # ...(略:具体的な処理)...

補足

ちなみに以下は同じ乱数列を返します。
グローバルなseed=1234と、RandomStateのseed=1234は同じ乱数を生成する。

import numpy as np

np.random.seed(1234)
print(np.random.randint(1,10,10))

rs = np.random.RandomState(1234)
print(rs.randint(1,10,10))