web-dev-qa-db-fra.com

Créer une liste aléatoire d’entiers dans Python

Je voudrais créer une liste aléatoire de nombres entiers à des fins de test. La distribution des nombres n'est pas importante. La seule chose qui compte est time. Je sais que générer des nombres aléatoires est une tâche fastidieuse, mais il doit y avoir un meilleur moyen.

Voici 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

la v2 est plus rapide que la v1, mais elle ne fonctionne pas à une aussi grande échelle. Cela donne l'erreur suivante:

ValueError: échantillon supérieur à la population

Existe-t-il une solution rapide et efficace qui fonctionne à cette échelle?

Quelques résultats de la réponse

Andrew's: 0.000290962934494

gnibbler: 0.0058455221653

KennyTM: 0.00219276118279

NumPy est venu, a vu et a conquis.

68
Stiggo

Ce que vous voulez n’est pas tout à fait clair, mais j’utiliserais 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

ce qui donne sur ma machine:

0.0233682730198
0.00781716918945
0.000147947072983

Notez que randint est très différent de random.sample (pour que cela fonctionne dans votre cas, je devais changer le nombre de 1 000 à 10 000 comme l'un des les commentateurs ont souligné - si vous les voulez vraiment de 0 à 1 000, vous pouvez les diviser par 10).

Et si vous ne vous souciez pas vraiment de la distribution que vous obtenez, il est possible que vous ne compreniez pas très bien votre problème, ou que vous choisissiez des nombres aléatoires - avec des excuses si cela vous semble impoli ...

60
Andrew Jaffe

Toutes les méthodes aléatoires finissent par appeler random.random(). Le meilleur moyen est donc de l'appeler directement:

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

Par exemple,

  • random.randint Appelle random.randrange.
  • random.randrange A un tas de temps système pour vérifier la plage avant de renvoyer istart + istep*int(self.random() * n).

NumPy est bien plus rapide encore.

30
John La Rooy

Votre question sur les performances est sans objet. Les deux fonctions sont très rapides. La vitesse de votre code sera déterminée par ce que vous faites avec les nombres aléatoires.

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

5
Colonel Panic

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

Pour être efficace, randint est simplement un wrapper de randrange qui appelle random, vous devez donc simplement utiliser random. En outre, utilisez xrange comme argument de sample, et non de range.

Vous pourriez utiliser

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

générer 10 000 nombres dans la plage en utilisant sample 10 fois.

(Bien sûr, cela ne battra pas 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 vous souciez pas de la distribution des nombres, pourquoi ne pas simplement utiliser:

range(1000)*(10000/1000)

?

2
kennytm