在Python中生成多个独立的随机流
我想在Python中生成多个随机数流。
我正在写一个模拟排队系统的程序,需要一个随机数流来表示到达时间,另一个随机数流来表示服务时间,依此类推。
numpy.random()
会从一个全局的随机数流中生成随机数。
在Matlab中,有一个叫做RandStream的东西,可以让我创建多个随机数流。
在Python中有没有办法创建类似RandStream的东西呢?
5 个回答
numpy
新增了一个功能,可以生成独立的随机数流,这个功能是通过 SeedSequence
实现的。简单来说,用户提供一个种子,通常是一个整数,然后这个种子会被转换成一个比特生成器的初始状态。这个过程使用了哈希技术,确保即使是质量不高的种子,也能转化为高质量的初始状态(至少有很高的概率是这样)。
from numpy.random import SeedSequence, default_rng
ss = SeedSequence(12345)
# Spawn off 10 child SeedSequences to pass to child processes.
child_seeds = ss.spawn(10)
streams = [default_rng(s) for s in child_seeds]
每个随机数流都是 PCG64 生成器。随机数可以按顺序生成,方法如下 -
for i in 1:K
instance[i] = [s.uniform() for s in streams]
还有更多生成独立随机数流的方法,详细信息可以查看 numpydocs。
Veedrac的回答没有提到如何生成独立的随机流。
我找到的生成独立随机流的最好方法是用一个替代品来代替numpy的RandomState。这个替代品是由RandomGen包提供的。
它支持独立的随机流,不过这些随机流是基于三种随机数生成器之一:PCG64、ThreeFry或Philox。如果你想使用更传统的MT19937,可以选择跳跃的方法。
为了确保结果可以重复,你可以直接给random.Random()
传一个种子,然后从这个实例中调用变量。每个创建的实例都会独立运行,不会互相影响。比如,如果你运行:
import random
rg1 = random.Random(1)
rg2 = random.Random(2)
rg3 = random.Random(1)
for i in range(5): print(rg1.random())
print('')
for i in range(5): print(rg2.random())
print('')
for i in range(5): print(rg3.random())
你会得到:
0.134364244112
0.847433736937
0.763774618977
0.255069025739
0.495435087092
0.956034271889
0.947827487059
0.0565513677268
0.0848719951589
0.835498878129
0.134364244112
0.847433736937
0.763774618977
0.255069025739
0.495435087092
你不需要使用RandomGen这个包。只要启动两个流就可以了。比如:
import numpy as np
prng1 = np.random.RandomState()
prng2 = np.random.RandomState()
prng1.seed(1)
prng2.seed(1)
现在如果你用prngX.rand()
来推进这两个流,你会发现这两个流会给你相同的结果,这意味着它们是独立的流,但种子是一样的。
要使用random
这个包,只需把np.random.RandomState()
换成random.Random()
就行了。
Numpy和内部的随机数生成器都有可以实例化的类。
对于简单的random
:
import random
random_generator = random.Random()
random_generator.random()
#>>> 0.9493959884174072
而对于Numpy来说:
import numpy
random_generator = numpy.random.RandomState()
random_generator.uniform(0, 1, 10)
#>>> array([ 0.98992857, 0.83503764, 0.00337241, 0.76597264, 0.61333436,
#>>> 0.0916262 , 0.52129459, 0.44857548, 0.86692693, 0.21150068])