位生成器#
由 Generator
产生的随机值源自一个 BitGenerator.BitGenerators 不直接提供随机数,只包含用于种子设定、获取或设置状态、跳跃或推进状态的方法,以及用于访问由高效访问所提供函数的代码使用的低级包装器,例如 numba.
支持的 BitGenerators#
包含的 BitGenerators 有:
PCG-64 - 默认的.一个可以任意前进的快速生成器.请参阅文档中的
advance
.PCG-64 的周期为 \(2^{128}\) .有关此类 PRNG 的更多详细信息,请参阅 PCG 作者的页面 .PCG-64 DXSM - PCG-64 的升级版本,在并行环境下具有更好的统计属性.有关这些改进的更多信息,请参见 使用 PCG64DXSM 升级 PCG64.
MT19937 - 标准 Python BitGenerator.添加了一个
MT19937.jumped
函数,该函数返回一个新的生成器,其状态如同已进行了 \(2^{128}\) 次绘制.Philox - 一个基于计数器的生成器,能够前进任意步数或生成独立流.有关此类比特生成器的更多详细信息,请参见 Random123 页面.
SFC64 - 一个基于随机可逆映射的快速生成器.通常是这四个生成器中最快的.更多详情请参见 SFC 作者的页面.
|
用于通用 BitGenerators 的基类,它基于不同的算法提供随机比特流. |
种子和熵#
BitGenerator 提供了一串随机值.为了生成可重复的流,BitGenerators 支持通过种子设置它们的初始状态.所有提供的 BitGenerators 将接受任意大小的非负整数或此类整数的列表作为种子.BitGenerators 需要将这些输入处理成 BitGenerator 的高质量内部状态.numpy 中的所有 BitGenerators 都将该任务委托给 SeedSequence
,它使用哈希技术确保即使是低质量的种子也能生成高质量的初始状态.
from numpy.random import PCG64
bg = PCG64(12345678903141592653589793)
SeedSequence
旨在方便实施最佳实践.我们建议随机程序默认使用来自操作系统的熵,以便每次运行都不同.程序应打印或记录该熵.为了重现过去的值,程序应允许用户通过某种机制提供该值,命令行参数是常见的,这样用户就可以重新输入该熵以重现结果.`~SeedSequence` 可以处理除与用户通信之外的所有事情,这取决于你.
from numpy.random import PCG64, SeedSequence
# Get the user's seed somehow, maybe through `argparse`.
# If the user did not provide a seed, it should return `None`.
seed = get_user_seed()
ss = SeedSequence(seed)
print('seed = {}'.format(ss.entropy))
bg = PCG64(ss)
我们默认使用从操作系统收集的熵生成一个128位整数.这对于初始化我们在numpy中的所有生成器来说是一个很好的熵量.我们不建议在一般使用中使用低于32位的种子.仅使用一小部分种子来实例化更大的状态空间意味着有些初始状态是无法达到的.如果每个人都使用这些值,这会带来一些偏见.
从本质上讲,结果不会有任何 错误;即使种子值为0也是完全没问题的,这要归功于 SeedSequence
的处理.如果你只是需要 某个 固定值用于单元测试或调试,可以随意使用你喜欢的任何种子.但如果你想从结果中进行推断或发布它们,从更大的种子集中抽取是一个好的做法.
如果你需要生成一个好的种子 “离线”,那么 SeedSequence().entropy
或者使用标准库中的 secrets.randbits(128)
都是方便的方法.
如果你需要并行运行多个随机模拟,最佳实践是为每个模拟构建一个随机生成器实例.为了确保随机流具有不同的初始状态,你可以使用 SeedSequence
的 spawn 方法.例如,这里我们构建了一个包含12个实例的列表:
from numpy.random import PCG64, SeedSequence
# High quality initial entropy
entropy = 0x87351080e25cb0fad77a44a3be03b491
base_seq = SeedSequence(entropy)
child_seqs = base_seq.spawn(12) # a list of 12 SeedSequences
generators = [PCG64(seq) for seq in child_seqs]
如果你已经有一个初始的随机生成器实例,你可以通过使用 spawn
方法来简化上述操作:
from numpy.random import PCG64, SeedSequence
# High quality initial entropy
entropy = 0x87351080e25cb0fad77a44a3be03b491
base_bitgen = PCG64(entropy)
generators = base_bitgen.spawn(12)
另一种方法是利用 SeedSequence
可以通过元素元组进行初始化的特性.这里我们使用一个基础熵值和一个整数 worker_id
from numpy.random import PCG64, SeedSequence
# High quality initial entropy
entropy = 0x87351080e25cb0fad77a44a3be03b491
sequences = [SeedSequence((entropy, worker_id)) for worker_id in range(12)]
generators = [PCG64(seq) for seq in sequences]
请注意,后一种方法生成的序列将与通过 spawn
构造的序列不同.
|
SeedSequence 以可重复的方式混合熵源,为独立且很可能不重叠的 BitGenerators 设置初始状态. |