Nombre aléatoire non répétitif dans numpy

88

Comment puis-je générer des nombres aléatoires non répétitifs dans numpy?

list = np.random.random_integers(20,size=(10))
Académie
la source
Qu'entendez-vous par «non répétitif»? Que la séquence de nombres aléatoires ne se répète jamais? Cela n'est pas possible, car l'état du générateur de nombres aléatoires doit tenir dans la mémoire finie d'un ordinateur. Ou voulez-vous dire qu'aucun nombre unique n'apparaît deux fois?
Sven Marnach
5
Non répétitif signifie que vous avez une liste sans doublons.
Polynomial du
2
Peut-être avez-vous besoin d'une permutation aléatoire? docs.scipy.org/doc/numpy/reference/generated/…
cyborg

Réponses:

106

numpy.random.Generator.choiceoffre un replaceargument pour échantillonner sans remplacement:

from numpy.random import default_rng

rng = default_rng()
numbers = rng.choice(20, size=10, replace=False)

Si vous utilisez un NumPy antérieur à la version 1.17, sans l' GeneratorAPI, vous pouvez utiliser à random.sample()partir de la bibliothèque standard:

print(random.sample(range(20), 10))

Vous pouvez également utiliser numpy.random.shuffle()et trancher, mais ce sera moins efficace:

a = numpy.arange(20)
numpy.random.shuffle(a)
print a[:10]

Il y a aussi un replaceargument dans la numpy.random.choicefonction héritée , mais cet argument a été implémenté de manière inefficace puis laissé inefficace en raison des garanties de stabilité du flux de nombres aléatoires, son utilisation n'est donc pas recommandée. (Il fait essentiellement la chose shuffle-and-slice en interne.)

Sven Marnach
la source
1
print random.sample (range (20), 10) ne fonctionne pas avec python 2.6?!
Academia
Avez-vous import random?
Sven Marnach
Le problème était dû à une mauvaise configuration Pydev. Thks
Academia
1
Et si mon n n'est pas 20, mais comme 1000000, mais que je n'ai besoin que de 10 nombres uniques, y a-t-il une approche plus efficace en mémoire?
mrgloom
2
@mrgloom En Python 3, random.sample(range(n), 10))sera efficace même pour les très gros n, puisqu'un rangeobjet n'est qu'un petit wrapper stockant les valeurs de démarrage, d'arrêt et d'étape, mais ne crée pas la liste complète des entiers. Dans Python 2, vous pouvez remplacer rangepar xrangepour obtenir un comportement similaire.
Sven Marnach
108

Je pense que numpy.random.sampleça ne marche pas bien maintenant. C'est mon chemin:

import numpy as np
np.random.choice(range(20), 10, replace=False)
Strnam
la source
25
Au lieu de range(n)(ou arange(n)) comme premier argument de choice, cela équivaut à simplement passer n, par exemple choice(20, 10, replace=False).
Josh Bode
1
Notez que np.random.choice(a, size, replace=False)c'est très lent pour les gros a- sur ma machine, environ 30 ms pour a = 1M.
Matthew Rahtz
3
Pour éviter les problèmes de temps et de mémoire pour une très grande nutilisation numpy.random.Generator.choice(à partir de numpy v1.17)
benbo
1
Le principal inconvénient que je vois est que np.random.choice n'a pas de paramètre d'axe -> c'est uniquement pour les tableaux 1d.
Moosefeather
3

Des années plus tard, il est temps de choisir 40000 sur 10000 ^ 2 (Numpy 1.8.1, imac 2.7 GHz):

import random
import numpy as np

n = 10000
k = 4
np.random.seed( 0 )

%timeit np.random.choice( n**2, k * n, replace=True )  # 536 µs ± 1.58 µs
%timeit np.random.choice( n**2, k * n, replace=False ) # 6.1 s ± 9.91 ms

# https://docs.scipy.org/doc/numpy/reference/random/index.html
randomstate = np.random.default_rng( 0 )
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=False )  # 766 µs ± 2.18 µs
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=True )   # 1.05 ms ± 1.41 µs

%timeit random.sample( range( n**2 ), k * n )          # 47.3 ms ± 134 µs

(Pourquoi choisir 40000 sur 10000 ^ 2? Pour générer de grandes matrices scipy.sparse.random - scipy 1.4.1 utilise np.random.choice( replace=False ), slooooow.)

Astuce du chapeau pour les gens numpy.random.

denis
la source
1

Vous pouvez également obtenir cela en triant:

random_numbers = np.random.random([num_samples, max_int])
samples = np.argsort(random_numbers, axis=1)
Ben
la source
-3

Générez simplement un tableau contenant la plage de nombres requise, puis mélangez-les en échangeant à plusieurs reprises un tableau aléatoire avec le 0e élément du tableau. Cela produit une séquence aléatoire qui ne contient pas de valeurs en double.

Polynôme
la source
2
Une autre propriété de la séquence aléatoire résultante est qu'elle n'est pas particulièrement aléatoire .
Sven Marnach
@SvenMarnach - Dans la plupart des cas, cependant, c'est assez aléatoire. Il pourrait utiliser l'approche double-aléatoire s'il le voulait plus aléatoire.
Polynomial
C'est inutile. L'OP peut utiliser les appels de bibliothèque pour le faire correctement. Ils sont plus faciles à utiliser, s'exécutent plus rapidement et sont plus lisibles qu'une version personnalisée. Je ne peux penser à aucune raison pour laquelle je devrais utiliser un mauvais algorithme ici simplement parce qu'il est probablement "assez aléatoire", lorsque l'utilisation du bon algorithme n'a aucun inconvénient.
Sven Marnach
@SvenMarnach - Très bien. Je ne sais pas stupide, alors je proposais juste une solution potentielle.
Polynomial du