numpy全局随机种子和局部随机种子

前言
numpy伪随机数提供了设置随机种子的函数,seed和RandomState,本文对二者区别进行具体说明。

函数名描述
seed向随机数生成器传递随机状态种子,生成全局随机种子
RandomState创建随机数生成器,用该生成器生成的数组是在设定的随机种子下生成,设置的是局部随机种子

1. 同一随机种子会产生相同随机序列
#同一随机种子产生相同随机序列
In [230]: def run_seed(seed):
    ...:     np.random.seed(seed)
    ...:     for _ in range(3):
    ...:         print(np.random.rand(5))
    ...:

In [231]: run_seed(1)
[4.17022005e-01 7.20324493e-01 1.14374817e-04 3.02332573e-01
1.46755891e-01]
[0.09233859 0.18626021 0.34556073 0.39676747 0.53881673]
[0.41919451 0.6852195  0.20445225 0.87811744 0.02738759]
In [232]: run_seed(0)
[0.5488135  0.71518937 0.60276338 0.54488318 0.4236548 ]
[0.64589411 0.43758721 0.891773   0.96366276 0.38344152]
[0.79172504 0.52889492 0.56804456 0.92559664 0.07103606]
In [234]: run_seed(1)
[4.17022005e-01 7.20324493e-01 1.14374817e-04 3.02332573e-01
1.46755891e-01]
[0.09233859 0.18626021 0.34556073 0.39676747 0.53881673]
[0.41919451 0.6852195  0.20445225 0.87811744 0.02738759]

#利用随机种子可以产生完全相同的随机序列
In [236]: def run_seed(seed):
    ...:     for _ in range(3):
    ...:         np.random.seed(seed)
    ...:         print(np.random.rand(5))

In [237]: run_seed(1)
[4.17022005e-01 7.20324493e-01 1.14374817e-04 3.02332573e-01
1.46755891e-01]
[4.17022005e-01 7.20324493e-01 1.14374817e-04 3.02332573e-01
1.46755891e-01]
[4.17022005e-01 7.20324493e-01 1.14374817e-04 3.02332573e-01
1.46755891e-01]

观察以上输出:231行的输出和234行相同,232行和他们不同。这说明同一随机种子产生的随机序列相同。利用随机种子我们可以生成相同随机序列。

2. 证明seed方法改变了全局随机种子
In [8]: def run_without_RandomState():
  ...:     for _ in range(3):
  ...:         print(np.random.rand(5))
  ...:
   
In [9]: np.random.seed(1)

In [10]: run_without_RandomState()
[4.17022005e-01 7.20324493e-01 1.14374817e-04 3.02332573e-01
1.46755891e-01]
[0.09233859 0.18626021 0.34556073 0.39676747 0.53881673]
[0.41919451 0.6852195  0.20445225 0.87811744 0.02738759]

In [12]: run_without_RandomState()
[0.67046751 0.4173048  0.55868983 0.14038694 0.19810149]
[0.80074457 0.96826158 0.31342418 0.69232262 0.87638915]
[0.89460666 0.08504421 0.03905478 0.16983042 0.8781425 ]

In [17]: np.random.seed(1)
In [18]: run_without_RandomState() #此处函数内循环次数改为了6
[4.17022005e-01 7.20324493e-01 1.14374817e-04 3.02332573e-01
1.46755891e-01]
[0.09233859 0.18626021 0.34556073 0.39676747 0.53881673]
[0.41919451 0.6852195  0.20445225 0.87811744 0.02738759]
[0.67046751 0.4173048  0.55868983 0.14038694 0.19810149]
[0.80074457 0.96826158 0.31342418 0.69232262 0.87638915]
[0.89460666 0.08504421 0.03905478 0.16983042 0.8781425 ]

第17、18行重新设置随机种子为1并产生随机数组,正好是第10行和第12行输出的拼接,这说明在输出第12行的时候随机种子确实是1,全局随机种子被改变了。

3. 证明RandomState只改变局部随机种子
In [20]: np.random.seed(0)
#全局第1、2次
In [21]: for _ in range(6):
    ...:     print(np.random.rand(5))
    ...:
[0.5488135  0.71518937 0.60276338 0.54488318 0.4236548 ]
[0.64589411 0.43758721 0.891773   0.96366276 0.38344152]
[0.79172504 0.52889492 0.56804456 0.92559664 0.07103606]
[0.0871293  0.0202184  0.83261985 0.77815675 0.87001215]
[0.97861834 0.79915856 0.46147936 0.78052918 0.11827443]
[0.63992102 0.14335329 0.94466892 0.52184832 0.41466194]

In [22]: rnd = np.random.RandomState(0)
#局部第1次
In [23]: for _ in range(3):
    ...:     print(rnd.rand(5))
    ...:
[0.5488135  0.71518937 0.60276338 0.54488318 0.4236548 ]
[0.64589411 0.43758721 0.891773   0.96366276 0.38344152]
[0.79172504 0.52889492 0.56804456 0.92559664 0.07103606]
#局部第2次
In [24]: for _ in range(3):
    ...:     print(rnd.rand(5))
    ...:
[0.0871293  0.0202184  0.83261985 0.77815675 0.87001215]
[0.97861834 0.79915856 0.46147936 0.78052918 0.11827443]
[0.63992102 0.14335329 0.94466892 0.52184832 0.41466194]
#全局第3次
In [25]: for _ in range(3):
    ...:     print(np.random.rand(5))
    ...:
[0.26455561 0.77423369 0.45615033 0.56843395 0.0187898 ]
[0.6176355  0.61209572 0.616934   0.94374808 0.6818203 ]
[0.3595079  0.43703195 0.6976312  0.06022547 0.66676672]
#全局第4次
In [26]: for _ in range(3):
    ...:     print(np.random.rand(5))
    ...:
[0.67063787 0.21038256 0.1289263  0.31542835 0.36371077]
[0.57019677 0.43860151 0.98837384 0.10204481 0.20887676]
[0.16130952 0.65310833 0.2532916  0.46631077 0.24442559]
#局部第3次
In [27]: for _ in range(3):
    ...:     print(rnd.rand(5))
    ...:
[0.26455561 0.77423369 0.45615033 0.56843395 0.0187898 ]
[0.6176355  0.61209572 0.616934   0.94374808 0.6818203 ]
[0.3595079  0.43703195 0.6976312  0.06022547 0.66676672]

首先,通过例1我们已经知道,相同的随机种子会产生相同的序列,那么局部和全局的前两次输出已经可以证明,现在局部和全局的随机种子都是0。
其次,当全局已经输出第4次之后,再次输出局部,发现局部输出的第3次随机数组和全局第3次相同,这已经证明,全局和局部的随机种子是隔离的,因为如果不互相隔离,局部输出的应该是全局的第5次。

结论:当我们只是局部改变随机种子以产生相同随机数组的话,尽量使用RandomState,不要对全局随机种子进行改变,虽然通常情况下这种改变全局随机种子出错的机会很少。


版权声明:本文为buzhidao2333shuosha原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。