numpy.random.RandomState() 是否在调用 rand() 时自动调用?

Is numpy.random.RandomState() automatically called whenever rand() is called?

像C++这样的语言要求程序员设置随机数生成器的种子,否则它的输出总是一样的。但是,像 numpy 这样的库不需要您手动初始化种子。

例如,代码如下:

from numpy.random import rand
rand()

每次都给出不同的结果。

这是否意味着每次调用 rand 时都会调用 numpy.random.RandomState(seed=None)

Does that mean numpy.random.RandomState(seed=None) is called every time you call rand?

不,这意味着 RandomState 在启动时被播种一次。如果每次调用 rand 时都重新播种,那么将无法明确地 询问 可重复的模式。

Python stdlib 的 random 模块也是如此。

而且,不管你怎么说 C++,对于 C++ stdlib 的 <random> 函数来说,也是正确的。

所有这些文件表明,如果您什么都不做,默认种子来自系统时间或系统熵生成器(如大多数 *nix 系统上的 /dev/random)。

C 的 rand 不是这种情况(在 C++ 中仍然存在,尽管您应该将其视为已弃用*),但这只是因为 C 去特意要求启动必须执行与调用 srand(1).

相同的操作

如果您对 "once at startup" 在 NumPy 中的工作原理感兴趣:

  • numpy.random 模块的顶层(当您第一次在您的代码中 import numpy.randomfrom numpy.random import something 时,它会得到 运行),它构建了一个全局 RandomState,使用默认参数(意思是 seed=None)。
  • RandomState 的初始化程序只是将 seed 参数传递给 seed 方法。
  • RandomState.seed,当使用 None 调用时,使用适合您的平台的系统熵源(如 /dev/urandom)。
  • 当您调用顶级 rand 时,它使用全局 RandomState

* 不是因为这个问题;很容易记住在程序开始时调用 srand 。但是一个 PRNG 明确地不保证循环长度长于 32767,无偏分布等对几乎任何事情来说都是一个坏主意......

numpy.random 模块类似于 Python 标准库中的 random 模块,因为 numpy.random 中的函数是隐藏生成器对象的绑定方法,导入模块时实例化。这个隐藏的 numpy.random.RandomState 实例目前存在于 np.random.mtrand._rand 中(尽管你不应该依赖它在未来版本的 numpy 中总是存在):

print(np.random.rand)
# <built-in method rand of mtrand.RandomState object at 0x7f50ced03660>

# note the same memory address of the RandomState object:
print(np.random.mtrand._rand)
# <mtrand.RandomState object at 0x7f50ced03660>

当您导入模块时,隐藏的 RandomState 实例只会被播种 一次 (除非您随后使用 np.random.seed() 显式设置种子)。如果每次调用 rand() 时都选择了一个新种子,那么将无法创建可重现的伪随机数序列。

情况看起来像这样:

# implicit RandomState created and seeded
from numpy import random

# # we could subsequently re-seed the hidden RandomState, e.g.:
# random.seed(None)

# different random variates
r1 = random.rand(1)
r2 = random.rand(1)
r3 = random.rand(1)
# ...

自动播种相当于 np.random.RandomState(None),它使用一些依赖于平台的随机源(通常是 /dev/urandom on *nix)来设置种子。