Numero casuale non ripetitivo in numpy


92

Come posso generare numeri casuali non ripetitivi in ​​numpy?

list = np.random.random_integers(20,size=(10))

Cosa intendi per "non ripetitivo"? Che la sequenza di numeri casuali non ricorre mai? Ciò non è possibile, poiché lo stato del generatore di numeri casuali deve adattarsi alla memoria finita di un computer. O vuoi dire che nessun numero singolo compare due volte?
Sven Marnach

5
Non ripetitivo significa che hai un elenco senza duplicati.
Polinomio

2
Forse hai bisogno di una permutazione casuale? docs.scipy.org/doc/numpy/reference/generated/…
cyborg

Risposte:


112

numpy.random.Generator.choiceoffre un replaceargomento per campionare senza sostituzione:

from numpy.random import default_rng

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

Se sei su NumPy precedente alla 1.17, senza GeneratorAPI, puoi utilizzare random.sample()dalla libreria standard:

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

Puoi anche usare numpy.random.shuffle()e affettare, ma questo sarà meno efficiente:

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

C'è anche un replaceargomento nella numpy.random.choicefunzione legacy , ma questo argomento è stato implementato in modo inefficiente e quindi lasciato inefficiente a causa delle garanzie di stabilità del flusso di numeri casuali, quindi il suo utilizzo non è raccomandato. (Fondamentalmente fa la cosa shuffle-and-slice internamente.)


1
print random.sample (range (20), 10) non funziona con python 2.6 ?!
Academia

Il problema era dovuto a una cattiva configurazione di Pydev. Thks
Academia

1
E se il mio n non è 20, ma come 1000000, ma ho bisogno solo di 10 numeri univoci da esso, esiste un approccio più efficiente in termini di memoria?
mrgloom

2
@mrgloom In Python 3, random.sample(range(n), 10))sarà efficiente anche per le dimensioni molto grandi n, poiché un rangeoggetto è solo un piccolo wrapper che memorizza i valori di avvio, arresto e passaggio, ma non crea l'elenco completo degli interi. In Python 2, puoi sostituire rangecon xrangeper ottenere un comportamento simile.
Sven Marnach,

110

Penso numpy.random.sampleche non funzioni adesso. Questo è il mio modo:

import numpy as np
np.random.choice(range(20), 10, replace=False)

26
Invece di range(n)(o arange(n)) come primo argomento di choice, è equivalente a passare n, ad es choice(20, 10, replace=False).
Josh Bode

1
Nota che np.random.choice(a, size, replace=False)è molto lento per i grandi a: sulla mia macchina, circa 30 ms per a = 1M.
Matthew Rahtz

3
Per evitare problemi di tempo e memoria per un nuso molto ampio numpy.random.Generator.choice(a partire da numpy v1.17)
benbo

1
Lo svantaggio principale che vedo è che np.random.choice non ha un parametro dell'asse -> è solo per gli array 1d.
Moosefeather

3

Anni dopo, alcuni tempi per scegliere 40000 su 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

(Perché scegliere 40000 di 10000 ^ 2 per generare grandi? Scipy.sparse.random matrici - SciPy 1.4.1 usi np.random.choice( replace=False )., Slooooow)

Punta del cappello a numpy.random people.


1

Puoi ottenerlo anche ordinando:

random_numbers = np.random.random([num_samples, max_int])
samples = np.argsort(random_numbers, axis=1)

0

È possibile utilizzare la conversione di set list in Python. 10 numeri univoci compresi tra 0 e 20 possono essere ottenuti come:

import numpy as np
import random
unique_numbers=set()
while(len(unique_numbers)<10):
    unique_numbers.add(np.random.randint(0,20))

unique_numbers=list(unique_numbers)
random.shuffle(unique_numbers)
print(unique_numbers)

-3

Genera semplicemente un array che contiene l'intervallo di numeri richiesto, quindi mescolali scambiandone ripetutamente uno casuale con l'elemento 0 nell'array. Questo produce una sequenza casuale che non contiene valori duplicati.


2
Un'altra proprietà della sequenza casuale risultante è che non è particolarmente casuale .
Sven Marnach

@SvenMarnach - Per la maggior parte degli scopi, tuttavia, è abbastanza casuale. Potrebbe usare l'approccio del doppio casuale se lo volesse più casuale.
Polinomio

Questo è inutile. L'OP può utilizzare le chiamate di libreria per farlo bene. Sono più facili da usare, funzionano più velocemente e sono più leggibili di una versione personalizzata. Non riesco a pensare a nessuna ragione per cui dovrei usare un algoritmo sbagliato qui solo perché probabilmente è "abbastanza casuale", quando usare l'algoritmo giusto non ha alcuno svantaggio.
Sven Marnach

@SvenMarnach - Abbastanza giusto. Non conosco numpy, quindi stavo solo offrendo una potenziale soluzione.
Polinomio
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.