2010-11-13 38 views
64

Me gustaría crear una lista aleatoria de enteros para propósitos de prueba. La distribución de los números no es importante. Lo único que cuenta es tiempo. Sé que generar números aleatorios es una tarea que consume tiempo, pero debe haber una mejor manera.Crear lista aleatoria de enteros en Python

aquí está mi solución actual:

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 es más rápido que v1, pero no funciona tan gran escala. Se da el siguiente error: 'ValueError: muestra más grande que la población '

¿Sabe usted una solución rápida y eficiente que trabaja en esa escala?

Editar:

de Andrew: ,000290962934494

de gnibbler: 0.0058455221653

de KennyTM: 0.00219276118279

NumPy vino, vio, venció

Gracias!

+4

Por supuesto que no funciona. 'random.sample()' agota la población, haciendo que los números sean cada vez menos aleatorios. Una vez que toda la población se agota, es imposible seguir probando. –

+0

Cuando dice que es para fines de prueba, ¿cuánto tiempo durará la prueba? –

+0

Para simulaciones, donde el tiempo es un requisito (pero la criptografía y la seguridad no lo son), a menudo se usa [Generador congruente lineal (LCG)] (https://en.wikipedia.org/wiki/Linear_congruential_generator). Creo que [Mersenne Twister] (https://en.wikipedia.org/wiki/Mersenne_Twister) es rápido (pero más lento que LCG) y proporciona una distribución uniforme, si no recuerdo mal. – jww

Respuesta

56

No es del todo claro lo que quiere, pero me gustaría utilizar 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 

que da en mi máquina

0.0233682730198 
0.00781716918945 
0.000147947072983 

Tenga en cuenta que es randint muy diferente de random.sample (en Para que funcione en tu caso, tuve que cambiar los 1,000 a 10,000 como señaló uno de los comentaristas, si realmente los quieres de 0 a 1,000, puedes dividir por 10). Y si realmente no te importa qué distribución estás obteniendo, entonces es posible que no entiendas tu problema muy bien, o números aleatorios, con disculpas si eso suena grosero ...

+3

+1 para numpy, si Stiggo necesita tantos números aleatorios, probablemente valga la pena instalar numpy solo para este –

+0

Andrew, tiene toda la razón en cuanto a la distribución. Pero esto no es real. Sólo un desafío entre amigos. : D ¡Salud! – Stiggo

30

Todo al azar métodos terminan llamando random.random() por lo que la mejor manera es llamar directamente

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

por ejemplo.

random.randint llamadas random.randrange
random.randrange tiene un montón de gastos generales para comprobar la gama antes de regresar istart + istep*int(self.random() * n)

Editar: numpy es mucho más rápido aún, por supuesto

+0

+1 Estaba cavando todo antes y terminé pensando que 'randrange' finalmente llevó a una llamada a' getrandbits'. Eché de menos que tienes que instanciar 'SystemRandom' para que ese sea el comportamiento. Gracias por hacerme mirar más de cerca. – aaronasterling

+0

Has batido mi versión, pero la solución de Andrew es claramente la ganadora. – Stiggo

+1

@Stiggo, de seguro, la única razón por la que puedo pensar en no usar numpy sería si numpy no es compatible con su plataforma. p.ej. google app engine –

2

En primer lugar, se debe utilizar randrange(0,1000) o randint(0,999), no randint(0,1000) . El límite superior de randint es inclusivo.

Para eficiente, randint es simplemente un envoltorio de randrange que exige random, por lo que sólo debe utilizar random.Además, use xrange como argumento para sample, no range.

Usted podría utilizar

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

para generar 10.000 números en el rango utilizando sample 10 veces.

(Por supuesto, esto no va a vencer a 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 

Pero ya que no se preocupan por la distribución de los números, ¿por qué no usar:

range(1000)*(10000/1000) 

?

+0

'randrange (1000)' tarda más del doble que '1000 * int (random())' en mi computadora –

5

Su pregunta sobre el rendimiento es irrelevante: ambas funciones son muy rápidas. La velocidad de su código estará determinada por lo que haga con los números aleatorios.

Sin embargo, es importante que entienda la diferencia en comportamiento de esas dos funciones. Uno hace un muestreo aleatorio con reemplazo, el otro toma muestras al azar sin reemplazo.

Cuestiones relacionadas