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


100

我在Python中有一个大脚本。我从其他人的代码中获得启发,因此最终我将该numpy.random模块用于某些方面(例如,创建从二项式分布中获取的随机数数组),而在其他地方则使用该模块random.random

有人可以告诉我两者之间的主要区别吗?在这两个文档的文档网页上,我似乎numpy.random都拥有更多的方法,但是我不清楚随机数的生成方式有何不同。

我问的原因是因为我需要为调试目的播种我的主程序。但是,除非我在要导入的所有模块中使用相同的随机数生成器,否则它将无法正常工作?

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

Answers:


120

您已经做出了许多正确的观察!

除非您希望为两个随机生成器都作为种子,否则从长远来看选择一个或另一个生成器可能更简单。但是,如果您确实需要同时使用两者,那么是的,您还需要同时对两者进行播种,因为它们彼此独立地生成随机数。

对于numpy.random.seed(),主要的困难是它不是线程安全的-也就是说,如果您有许多不同的执行线程,则使用它是不安全的,因为如果两个不同的线程同时执行该函数,则不能保证它能正常工作。如果您不使用线程,并且可以合理地期望将来不需要以这种方式重写程序,那numpy.random.seed()应该很好。如果有任何理由怀疑您将来可能需要线程,那么从长远来看,按照建议进行操作并创建numpy.random.Random该类的本地实例会更加安全。据我所知,它random.random.seed()是线程安全的(或者至少没有找到相反的证据)。

numpy.random库包含一些科学研究中常用的额外概率分布,以及用于生成随机数据数组的几个便捷函数。该random.random库要轻巧一些,如果您不从事科学研究或其他统计工作,那应该很好。

否则,它们都使用Mersenne扭曲序列生成它们的随机数,并且它们都是完全确定性的-也就是说,如果您知道一些关键信息,则可以绝对确定地预测下一个数字。因此,numpy.random和random.random都不适合任何严重的加密用途。但是因为序列非常长,所以在您不必担心有人试图对数据进行反向工程的情况下,两者都适合生成随机数。这也是必须播种随机值的原因-如果每次都从同一位置开始,那么您将始终获得相同的随机数序列!

附带说明一下,如果您确实需要加密级别的随机性,则应该使用secrets模块,或者如果使用的是Python 3.6之前的Python版本,则应使用Crypto.Random之类的东西。


14
作为一个遥远的相关说明,有时不需要使用两者,因为梅森扭曲器不会产生足以用于加密(和一些非常规的科学)目的的熵的随机序列。在极少数情况下,您通常需要Crypto.Random,它能够使用OS特定的熵源来生成非确定性随机序列,其质量要比random.random单独获得的随机序列高得多。不过,您通常不需要这个。
SingleNegationElimination

谢谢Hannnele。您的见解确实非常有用!事实证明,我不能只使用一个随机数生成器(因为随机数不会产生二项式分布,所以它必须是numpy),因为我的程序的一部分调用了另一个使用随机数的程序。我将必须播种这两个生成器。
劳拉

2
“如果您知道现在有哪个数字,就可以绝对确定地预测下一个数字。” 我认为这句话可能需要澄清。意思是,如果您知道生成器的内部状态,则可以重现序列-这是在生成生成器时执行的操作。给定发生器生成的单个数字,您将无法预测下一个数字。周期如此之大,您可能需要很长的数字序列才能计算出伪随机序列的位置,从而预测下一个序列。
Kaushik Ghose 2014年

12

Python的数据分析中,该模块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

1
其他方法则不然。相比np.random.randint(2)random.randrange(2)和NumPy的是较慢的一个。NumPy:1.25 us,随机:891 ns。同时还为同样的关系np.random.rand()random.random()
Shayan Amani

3

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

这样可以避免您提供种子,从而避免生成确定的随机数。但是,随机调用然后允许您将数字拟合为一个分布(我称之为科学随机性-最终,您想要的只是一个随机数的钟形曲线分布,numpy最擅长于解决这个问题。

所以,是的,坚持使用一个生成器,但要确定您想要的随机数-随机,但是会偏离分布曲线,或者在没有量子设备的情况下尽可能地随机。


保罗,非常感谢您,您的回答非常有用!我不是在寻找密码随机性,而是在做数学建模,伪随机数对我来说足够了。事实证明,我不能随心所欲地使用一个生成器,因为我需要numpy进行二项式分布,并且我的程序调用了另一个使用random的程序:(
Laura
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.