在Python中创建随机整数列表

74

我想为测试目的创建一个随机整数列表。数字的分布不重要,唯一重要的是时间。我知道生成随机数字是一项耗时的任务,但一定有更好的方法。

这是我的当前解决方案:

import random
import timeit

# Random lists from [0-999] interval
print [random.randint(0, 1000) for r in xrange(10)] # v1
print [random.choice([i for i in xrange(1000)]) for r in xrange(10)] # v2

# Measurement:
t1 = timeit.Timer('[random.randint(0, 1000) for r in xrange(10000)]', 'import random') # v1
t2 = timeit.Timer('random.sample(range(1000), 10000)', 'import random') # v2

print t1.timeit(1000)/1000
print t2.timeit(1000)/1000

v2比v1更快,但在大规模数据量时无法工作。它会出现以下错误:

ValueError:样本超出总体

是否有一种快速、高效的解决方案适用于该规模?

一些答案的结果

安德鲁的: 0.000290962934494

gnibbler的: 0.0058455221653

KennyTM的: 0.00219276118279

NumPy已经来了,看到了,并且征服了。


4
当然不起作用。random.sample()会消耗种群,使数字变得越来越不随机。一旦整个种群被消耗完,就无法进一步进行采样。 - Ignacio Vazquez-Abrams
当您说这是用于测试目的时,测试需要多长时间? - Mike Dunlavey
对于模拟,时间是一个要求(但加密和安全性不是),通常使用线性同余生成器(LCG)。我相信Mersenne Twister很快(但比LCG慢),如果我没记错的话,它提供了均匀分布。 - jww
4个回答

63

你想要什么不是完全清楚,但我会使用 numpy.random.randint

import numpy.random as nprnd
import timeit

t1 = timeit.Timer('[random.randint(0, 1000) for r in xrange(10000)]', 'import random') # v1

### Change v2 so that it picks numbers in (0, 10000) and thus runs...
t2 = timeit.Timer('random.sample(range(10000), 10000)', 'import random') # v2
t3 = timeit.Timer('nprnd.randint(1000, size=10000)', 'import numpy.random as nprnd') # v3

print t1.timeit(1000)/1000
print t2.timeit(1000)/1000
print t3.timeit(1000)/1000

在我的机器上执行该命令会得到:

0.0233682730198
0.00781716918945
0.000147947072983

请注意,randint与random.sample非常不同(为了使其在您的情况下工作,我不得不将1,000更改为10,000,因为其中一个评论者指出 - 如果您真的希望它们从0到1,000,则可以除以10)。

如果您真的不关心您得到的分布,那么可能是您不太了解您的问题,或者随机数 - 如果这听起来很无礼,请原谅...


3
如果Stiggo需要这么多随机数,就算只是为了这个目的,安装NumPy也是值得的。对于NumPy,点赞加一。 - John La Rooy
安德鲁,你对分发的观点完全正确。但这只是一场朋友之间的挑战,而非真正的事情。 :D 干杯! - Stiggo

34

所有的随机方法最终都会调用random.random(),所以最好直接调用它:

[int(1000*random.random()) for i in xrange(10000)]

例如,

  • random.randint 调用了 random.randrange
  • random.randrange 在返回 istart + istep*int(self.random() * n) 之前需要进行大量的范围检查。

当然,NumPy 仍然更快。


+1 我之前刚刚仔细研究了这些内容,最终发现 randrange 最终会调用 getrandbits。我错过了你必须实例化 SystemRandom 才能出现这种行为的事实。感谢让我更加仔细地观察。 - aaronasterling
1
@Stiggo,当然,我能想到不使用numpy的唯一原因就是numpy在你的平台上不受支持。例如,谷歌应用引擎。 - John La Rooy
4
在Python3中,random.randrange(1000)的设计旨在产生比random.random()*1000更均匀的分布。请参阅此处的9.6.2节:https://docs.python.org/3/library/random.html - Alexey Polonsky
1
@AlexeyPolonsky,不错的发现。如果我们可以接受最高到1023的数字,那么[getrandbits(10) for r in range(10000)]比我回答中的列表推导式快9倍。 - John La Rooy
1
@JohnLaRooy 谢谢!这真的更有用了! - Alexey Polonsky
显示剩余2条评论

6
你对性能的问题是无意义的——这两个函数都非常快。你的代码速度将由你使用随机数的方式决定。
然而,了解这两个函数的行为差异很重要。其中一个使用替换进行随机抽样,另一个则不使用替换进行随机抽样。

3

首先,你应该使用randrange(0,1000)randint(0,999),而不是randint(0,1000)randint的上限是包含在内的。

为了效率,randint只是调用randrange并调用random的包装器,因此你应该直接使用random。此外,将xrange用作sample的参数,而不是range

你可以使用

[a for a in sample(xrange(1000),1000) for _ in range(10000/1000)]

使用sample函数10次生成范围内的10000个数字。

(当然这不如NumPy。)

$ python2.7 -m timeit -s 'from random import randrange' '[randrange(1000) for _ in xrange(10000)]'
10 loops, best of 3: 26.1 msec per loop

$ python2.7 -m timeit -s 'from random import sample' '[a%1000 for a in sample(xrange(10000),10000)]'
100 loops, best of 3: 18.4 msec per loop

$ python2.7 -m timeit -s 'from random import random' '[int(1000*random()) for _ in xrange(10000)]' 
100 loops, best of 3: 9.24 msec per loop

$ python2.7 -m timeit -s 'from random import sample' '[a for a in sample(xrange(1000),1000) for _ in range(10000/1000)]'
100 loops, best of 3: 3.79 msec per loop

$ python2.7 -m timeit -s 'from random import shuffle
> def samplefull(x):
>   a = range(x)
>   shuffle(a)
>   return a' '[a for a in samplefull(1000) for _ in xrange(10000/1000)]'
100 loops, best of 3: 3.16 msec per loop

$ python2.7 -m timeit -s 'from numpy.random import randint' 'randint(1000, size=10000)'
1000 loops, best of 3: 363 usec per loop

但既然你不关心数字的分布,为什么不直接使用:
range(1000)*(10000/1000)

?


在我的电脑上,randrange(1000)1000*int(random()) 要慢两倍以上。 - John La Rooy
10000/1000 的目的是什么? - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接