Python中numpy.random和random.random的区别

Posted

技术标签:

【中文标题】Python中numpy.random和random.random的区别【英文标题】:Differences between numpy.random and random.random in Python 【发布时间】:2011-10-25 04:36:12 【问题描述】:

我有一个很大的 Python 脚本。我在其他人的代码中启发了自己,所以我最终在某些事情上使用了 numpy.random 模块(例如,用于创建从二项分布中获取的随机数数组),而在其他地方我使用了模块 random.random

谁能告诉我两者之间的主要区别? 查看两者的文档网页,在我看来numpy.random 只是有更多方法,但我不清楚随机数的生成有何不同。

我问的原因是因为我需要为我的主程序播种以进行调试。但是除非我在我正在导入的所有模块中使用相同的随机数生成器,否则它不起作用,这是正确的吗?

另外,我在另一篇文章中读到了关于不使用numpy.random.seed() 的讨论,但我真的不明白为什么这是个坏主意。如果有人向我解释为什么会这样,我将不胜感激。

【问题讨论】:

【参考方案1】:

你已经做了很多正确的观察!

除非您想为两个随机生成器播种,否则从长远来看,选择一个或另一个生成器可能更简单。但是,如果您确实需要同时使用两者,那么是的,您还需要为它们提供种子,因为它们会相互独立地生成随机数。

对于numpy.random.seed(),主要困难在于它不是线程安全的——也就是说,如果你有many different threads of execution,使用它是不安全的,因为如果两个不同的线程在同时。如果您不使用线程,并且您可以合理地预期将来不需要以这种方式重写程序,numpy.random.seed() 应该没问题。如果有任何理由怀疑您将来可能需要线程,从长远来看,按照建议和make a local instance of the numpy.random.Random class 做会更安全。据我所知,random.random.seed() 是线程安全的(或者至少,我没有发现任何相反的证据)。

numpy.random 库包含一些在科学研究中常用的额外概率分布,以及一些用于生成随机数据数组的便利函数。 random.random 库更轻量级,如果您不从事科学研究或其他类型的统计工作,应该没问题。

否则,它们都使用Mersenne twister sequence 来生成随机数,而且它们都是完全确定的——也就是说,如果您知道一些关键信息,就可以绝对确定地预测what number will come next。出于这个原因,numpy.random 和 random.random 都不适合任何serious cryptographic uses。但是因为这个序列非常长,所以在你不担心人们试图对你的数据进行逆向工程的情况下,两者都可以生成随机数。这也是为什么需要播种随机值的原因——如果你每次都从同一个地方开始,你总是会得到相同的随机数序列!

附带说明,如果您确实需要加密级别的随机性,则应使用secrets 模块,如果您使用的是早于 Python 3.6 的 Python 版本,则应使用 Crypto.Random 之类的模块.

【讨论】:

作为一个遥远相关的注释,有时需要使用 nother,因为 Mersenne twister 不会产生足以用于加密(以及一些不寻常的科学)目的的随机熵序列。在这些罕见的情况下,您通常需要Crypto.Random,它能够使用操作系统特定的熵源来生成质量比单独的random.random 更高质量的非确定性随机序列。不过,您通常不需要这个。 谢谢汉妮尔。你的见解真的很有用!事实证明,我不能只使用一个随机数生成器(它需要是 numpy,因为 random 不会产生二项式分布),因为我的程序的一部分调用了另一个使用随机数的程序。我将不得不播种两个生成器。 “如果你知道你现在有哪个号码,就可以绝对确定地预测接下来会出现什么号码。”我认为这个声明可能需要一些澄清。这意味着如果您知道生成器的内部状态,您就可以重现该序列——这就是您在为生成器播种时所做的事情。给定生成器的单个数字输出,您无法预测下一个数字。周期是如此之大,您可能需要一长串数字才能计算出您在伪随机序列上的位置,从而预测下一个。【参考方案2】:

来自Python for Data Analysis,模块numpy.random 补充了Python random 的功能,可从多种概率分布中有效地生成整个样本值数组。

相比之下,Python 内置的random 模块一次只采样一个值,而numpy.random 可以更快地生成非常大的样本。使用 IPython 魔术函数%timeit 可以看到哪个模块执行得更快:

In [1]: from random import normalvariate
In [2]: N = 1000000

In [3]: %timeit samples = [normalvariate(0, 1) for _ in xrange(N)]
1 loop, best of 3: 963 ms per loop

In [4]: %timeit np.random.normal(size=N)
10 loops, best of 3: 38.5 ms per loop

【讨论】:

其他方法不是这样。将np.random.randint(2)random.randrange(2) 进行比较,NumPy 较慢一个。 NumPy:1.25 us,随机:891 ns。 np.random.rand()random.random() 的关系也相同。【参考方案3】:

种子的来源和使用的分布配置文件将影响输出 - 如果您正在寻找加密随机性,从 os.urandom() 播种将从设备抖动(即以太网或磁盘)中获得几乎真实的随机字节(即 BSD 上的 /dev/random)

这将避免您提供种子并因此生成确定性随机数。然而,随机调用然后允许您将数字拟合到分布(我称之为科学随机性 - 最终您想要的只是随机数的钟形曲线分布,numpy 最擅长于此。

所以是的,坚持使用一个生成器,但要决定你想要什么随机 - 随机,但明确地来自分布曲线,或者在没有量子设备的情况下尽可能随机。

【讨论】:

非常感谢保罗,您的回答真的很有用!我不是在寻找密码随机性,我在做数学建模,伪随机数对我来说就足够了。事实证明,我不能按照自己的意愿坚持使用一个生成器,因为我需要 numpy 来进行二项式分布,并且我的程序调用了另一个使用随机的程序:(【参考方案4】:

令我惊讶的是randint(a, b) 方法在numpy.randomrandom 中都存在,但它们的上限行为不同。

random.randint(a, b) 返回一个随机整数 N,使得a <= N <= brandrange(a, b+1) 的别名。它包含b。 random documentation

但是,如果您调用numpy.random.randint(a, b),它将返回低(包括)到高(不包括)。 Numpy documentation

【讨论】:

以上是关于Python中numpy.random和random.random的区别的主要内容,如果未能解决你的问题,请参考以下文章

python-3:numpy诸多random

numpy.random

Python基础之- Numpy 的 random 函数简介

转---Python——numpy random类

numpy.random

[Python] numpy.random.rand