2010-11-13 9 views
64

Je voudrais créer une liste aléatoire d'entiers à des fins de test. La distribution des nombres n'est pas importante. La seule chose qui compte est temps. Je sais que la génération de nombres aléatoires est une tâche qui prend beaucoup de temps, mais il doit y avoir un meilleur moyen.Créer une liste aléatoire d'entiers en Python

Voilà ma solution actuelle:

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 est plus rapide que v1, mais ne fonctionne pas une si grande échelle. Il donne l'erreur suivante: « ValueError: plus grand échantillon de population »

Connaissez-vous une solution rapide et efficace qui fonctionne à cette échelle?

Edit:

Andrew: ,000290962934494

gnibbler de: ,0058455221653

KennyTM de: ,00219276118279

NumPy est venu, a vu, conquis

Merci!

+4

Bien sûr, cela ne fonctionne pas. 'random.sample()' épuise la population, rendant les nombres de moins en moins aléatoires. Une fois que la population entière est épuisée, il est impossible d'échantillonner davantage. –

+0

Quand vous dites que c'est à des fins de test, combien de temps dureront les tests? –

+0

Pour les simulations, où le temps est une exigence (mais la cryptographie et la sécurité ne le sont pas), un [Générateur de congruence linéaire (LCG)] (https://en.wikipedia.org/wiki/Linear_congruential_generator) est souvent utilisé. Je crois qu'un [Mersenne Twister] (https://en.wikipedia.org/wiki/Mersenne_Twister) est rapide (mais plus lent que LCG), et il fournit une distribution uniforme, si je me souviens bien. – jww

Répondre

56

Pas tout à fait clair ce que vous voulez, mais je voudrais utiliser 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 

qui donne sur est très différent ma machine

0.0233682730198 
0.00781716918945 
0.000147947072983 

Notez que randint de random.sample (en Pour que cela fonctionne dans votre cas, j'ai dû changer les 1000 à 10.000 comme l'a fait remarquer l'un des commentateurs - si vous voulez vraiment les faire passer de 0 à 1000, vous pouvez diviser par 10). Et si vous ne vous souciez pas vraiment de la distribution que vous obtenez, alors il est possible que vous ne compreniez pas très bien votre problème, ou des nombres aléatoires - avec des excuses si cela semble impoli ...

+3

+1 pour numpy, si Stiggo a besoin de tant de nombres aléatoires ça vaut probablement la peine d'installer numpy juste pour ça –

+0

Andrew, vous avez absolument raison à propos de la distribution. Mais ce n'est pas une chose réelle. Juste un challange entre amis. : D À la votre! – Stiggo

30

Tout le hasard méthodes finissent par appeler random.random() donc la meilleure façon est d'appeler directement

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

par exemple.

random.randint appelle random.randrange
random.randrange a un tas de frais généraux pour vérifier la plage avant de retourner istart + istep*int(self.random() * n)

Edit: numpy est beaucoup plus rapide encore bien sûr

+0

+1 Je creusais tout cela plus tôt et j'ai fini par penser que 'randrange' a fini par appeler' getrandbits'. J'ai manqué que vous deviez instancier 'SystemRandom' pour que ce soit le comportement. Merci de m'avoir fait regarder de plus près. – aaronasterling

+0

Vous avez battu ma version, mais la solution d'Andrew est clairement le gagnant. – Stiggo

+1

@Stiggo, bien sûr, la seule raison pour laquelle je ne pense pas utiliser numpy serait si numpy n'est pas supporté sur votre plate-forme. par exemple. google app engine –

2

Tout d'abord, vous devez utiliser randrange(0,1000) ou randint(0,999), non randint(0,1000) . La limite supérieure de randint est incluse.

Pour efficacement, randint est tout simplement une enveloppe de randrange qui appelle random, donc vous devriez simplement utiliser random.En outre, utilisez xrange comme argument à sample, pas range.

Vous pouvez utiliser

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

pour générer 10.000 numéros dans la gamme en utilisant sample 10 fois.

(Bien sûr, cela ne sera pas battu 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 

Mais puisque vous ne se soucient pas de la distribution des nombres, pourquoi ne pas utiliser:

range(1000)*(10000/1000) 

?

+0

'randrange (1000)' prend plus de deux fois plus de temps que '1000 * int (random())' sur mon ordinateur –

5

Votre question sur la performance est discutable: les deux fonctions sont très rapides. La vitesse de votre code sera déterminée par ce que vous faire avec les nombres aléatoires.

Cependant, il est important que vous compreniez la différence comportement de ces deux fonctions. L'un effectue un échantillonnage aléatoire avec remplacement, l'autre effectue un échantillonnage aléatoire sans remplacement.

Questions connexes