一致地创建相同的随机 numpy 数组

Posted

技术标签:

【中文标题】一致地创建相同的随机 numpy 数组【英文标题】:Consistently create same random numpy array 【发布时间】:2011-08-15 17:35:16 【问题描述】:

我正在等待另一位开发人员完成一段代码,该代码将返回一个形状为 (100,2000) 的 np 数组,其值为 -1,0 或 1。

与此同时,我想随机创建一个具有相同特征的数组,这样我就可以在我的开发和测试中抢占先机。问题是我希望这个随机创建的数组每次都相同,这样我就不会针对每次重新运行我的进程时不断改变其值的数组进行测试。

我可以像这样创建我的数组,但是有没有办法创建它,以便每次都一样。我可以腌制对象并取消腌制,但想知道是否还有其他方法。

r = np.random.randint(3, size=(100, 2000)) - 1

【问题讨论】:

【参考方案1】:

根据Random sampling 中的最新更新,首选方法是使用Generators 而不是RandomState。请参阅What's new or different 来比较这两种方法。其中一个关键变化是慢 Mersenne Twister 伪随机数生成器 (RandomState) 和基于新方法 (Generators) 中使用的不同算法 (BitGenerators) 的随机比特流之间的区别。

否则,生成随机numpy数组的步骤非常相似:

    初始化随机发生器

您将初始化随机生成器,而不是 RandomStatedefault_rng 是随机生成器的推荐构造函数,但您可以尝试其他方式。

import numpy as np

rng = np.random.default_rng(42)
# rng -> Generator(PCG64)
    生成 numpy 数组

除了randint 方法,还有Generator.integers 方法,它现在是从离散均匀分布生成整数随机数的规范方法(参见已经提到的What's new or different 总结)。请注意,endpoint=True 使用 [low, high] 间隔进行采样,而不是默认的 [low, high)。

arr = rng.integers(-1, 1, size=10, endpoint=True)
# array([-1,  1,  0,  0,  0,  1, -1,  1, -1, -1])

如前所述,您必须每次初始化随机生成器(或随机状态)以生成相同的数组。因此,最简单的事情是定义类似于@mari756h 答案的自定义函数:

def get_array(low, high, size, random_state=42, endpoint=True):
    rng = np.random.default_rng(random_state)
    return rng.integers(low, high, size=size, endpoint=endpoint)

当您使用相同的参数调用函数时,您将始终得到相同的 numpy 数组。

get_array(-1, 1, 10)
# array([-1,  1,  0,  0,  0,  1, -1,  1, -1, -1])

get_array(-1, 1, 10, random_state=12345)  # change random state to get different array
# array([ 1, -1,  1, -1, -1,  1,  0,  1,  1,  0])

get_array(-1, 1, (2, 2), endpoint=False)
# array([[-1,  0],
#        [ 0, -1]])

根据您的需要,您可以使用get_array(-1, 1, size=(100, 2000))

【讨论】:

【参考方案2】:

简单地为随机数生成器设定一个固定值,例如

numpy.random.seed(42)

这样,您将始终获得相同的随机数序列。

此函数将为全局默认随机数生成器播种,任何对numpy.random 中函数的调用都将使用并更改其状态。这对于许多简单的用例来说都很好,但它是一种全局状态的形式,具有全局状态带来的所有问题。如需更清洁的解决方案,请参阅下面 Robert Kern 的回答。

【讨论】:

有人在我不注意的时候偷偷进入了numpy.random.seed() 函数。 :-) 我故意将它排除在原始模块之外。我建议人们使用自己的 RandomState 实例并传递这些对象。 Robert 是 numpy 的主要贡献者。我认为我们应该给他的意见一些分量。 @deprecated:我很感谢 Robert 的工作,但他的工作并不能代替给出推荐理由。此外,如果不鼓励使用numpy.random.seed(),则应在the documentation 中提及。显然,NumPy 的其他贡献者不同意 Robert 的观点。完全没有冒犯的意思,我只是好奇。 这与在 Python 标准库中使用 random.seed 与使用 random.Random 对象相同。如果您使用random.seednumpy.random.seed,您将在您的代码和您正在调用的任何代码或在与您的同一会话中运行的任何代码中播种所有 个随机实例。如果这些事情取决于这些事情实际上是随机的,那么你就会开始遇到问题。如果您部署设置随机种子的代码,则可能会引入安全漏洞。 @asmeurer 任何出于安全目的使用伪随机数生成器的人都可能不知道他们在做什么。【参考方案3】:

我只是想澄清一些关于@Robert Kern 的回答,以防万一不清楚。即使您确实使用了RandomState,您也必须在每次调用像 Robert 示例中那样的 numpy 随机方法时对其进行初始化,否则您将得到以下结果。

Python 3.6.9 |Anaconda, Inc.| (default, Jul 30 2019, 19:07:31) 
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> prng = np.random.RandomState(2019)
>>> prng.randint(-1, 2, size=10)
array([-1,  1,  0, -1,  1,  1, -1,  0, -1,  1])
>>> prng.randint(-1, 2, size=10)
array([-1, -1, -1,  0, -1, -1,  1,  0, -1, -1])
>>> prng.randint(-1, 2, size=10)
array([ 0, -1, -1,  0,  1,  1, -1,  1, -1,  1])
>>> prng.randint(-1, 2, size=10)
array([ 1,  1,  0,  0,  0, -1,  1,  1,  0, -1])

【讨论】:

【参考方案4】:

了解什么是随机生成器的种子以及何时/如何在您的代码中设置它很重要(例如,查看 here 以获得对种子数学含义的很好解释)。

为此,您需要设置种子:

random_state = np.random.RandomState(seed=your_favorite_seed_value)

然后从 random_state 而不是从 np.random 生成随机数很重要。 IE。你应该这样做:

random_state.randint(...)

而不是

np.random.randint(...) 

这将创建一个新的 RandomState() 实例,并且基本上使用您的计算机内部时钟来设置种子。

【讨论】:

【参考方案5】:

如果您使用其他依赖于随机状态的函数,则不能只设置整体种子,而应创建一个函数来生成随机数字列表并将种子设置为函数的参数。这不会干扰代码中的任何其他随机生成器:

# Random states
def get_states(random_state, low, high, size):
    rs = np.random.RandomState(random_state)
    states = rs.randint(low=low, high=high, size=size)
    return states

# Call function
states = get_states(random_state=42, low=2, high=28347, size=25)

【讨论】:

【参考方案6】:

使用您选择的种子创建您自己的numpy.random.RandomState() 实例。请勿使用 numpy.random.seed(),除非解决不允许您传递自己的 RandomState 实例的不灵活库。

[~]
|1> from numpy.random import RandomState

[~]
|2> prng = RandomState(1234567890)

[~]
|3> prng.randint(-1, 2, size=10)
array([ 1,  1, -1,  0,  0, -1,  1,  0, -1, -1])

[~]
|4> prng2 = RandomState(1234567890)

[~]
|5> prng2.randint(-1, 2, size=10)
array([ 1,  1, -1,  0,  0, -1,  1,  0, -1, -1])

【讨论】:

您的推荐有什么理由吗? numpy.random.seed() 有什么问题?我知道它不是线程安全的,但是如果您不需要线程安全,它真的很方便。 主要是为了养成好习惯。您现在可能不需要独立的流,但 Sven-6 个月后可能需要。如果您编写库以直接使用 numpy.random 中的方法,则以后无法创建独立的流。编写具有受控 PRNG 流的库也更容易。进入你的图书馆总是有多种方式,每一种方式都应该有控制种子的方式。传递 PRNG 对象是一种比依赖numpy.random.seed() 更简洁的方法。不幸的是,此评论框太短,无法包含更多示例。:-) 另一种描述 Robert 基本原理的方式:使用 numpy.random.seed 使用全局变量来保持 PRNG 状态,与全局变量不好的相同标准原因在这里适用。 如果您希望 PRNG 独立,请不要为它们添加任何内容。只需使用不带参数的numpy.random.RandomState()。这将使用从您的操作系统设施中提取的唯一值来为状态播种此类事物(UNIX 机器上的/dev/urandom 和那里的 Windows 等效项)。如果numpy.random.RandomState(1234567890) 不适合您,请准确显示您输入的内容以及您收到的错误消息。 不是一个好主意。使用不带参数的 numpy.random.RandomState() 以获得最佳结果。

以上是关于一致地创建相同的随机 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章

保存在磁盘上的 numpy 数组中的随机访问

数据分析2 numpy(ndarray数组,属性,创建,索引切片,运算,函数,随机数), Pandas(Series创建,缺失值处理,特性,索引,DataFrame)

numpy的随机数组

numpy模块的基本使用

使用随机放置的 NaN 创建示例 numpy 数组

使用列表中的随机元素创建 numpy 数组