Niepowtarzalna liczba losowa w numpy


88

Jak mogę wygenerować niepowtarzalne liczby losowe w numpy?

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

Co rozumiesz przez „niepowtarzalność”? Że sekwencja liczb losowych nigdy się nie powtarza? Nie jest to możliwe, ponieważ stan generatora liczb losowych musi mieścić się w skończonej pamięci komputera. Czy masz na myśli to, że żadna pojedyncza liczba nie występuje dwukrotnie?
Sven Marnach

5
Niepowtarzalność oznacza, że ​​masz listę bez duplikatów.
Wielomian

2
Może potrzebujesz losowej permutacji? docs.scipy.org/doc/numpy/reference/generated/ ...
cyborg

Odpowiedzi:


106

numpy.random.Generator.choiceoferuje replaceargument do próbkowania bez wymiany:

from numpy.random import default_rng

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

Jeśli Generatorkorzystasz random.sample()z NumPy w wersji starszej niż 1.17, bez API, możesz użyć z biblioteki standardowej:

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

Możesz także użyć numpy.random.shuffle()i pokroić, ale będzie to mniej wydajne:

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

Istnieje również replaceargument w starszej numpy.random.choicefunkcji, ale ten argument został zaimplementowany nieefektywnie, a następnie pozostawił nieefektywny ze względu na gwarancje stabilności strumienia liczb losowych, więc jego użycie nie jest zalecane. (Zasadniczo robi to wewnętrznie tasuj i pokrój).


1
print random.sample (range (20), 10) nie działa z Pythonem 2.6 ?!
Academia,

Zrobiłeś import random?
Sven Marnach

Problem był spowodowany złą konfiguracją Pydeva. Dzięki
Academia,

1
A jeśli moje n nie jest równe 20, ale takie jak 1000000, ale potrzebuję tylko 10 unikalnych liczb, czy istnieje podejście wydajniejsze pod względem pamięci?
mrgloom,

2
@mrgloom W Pythonie 3 random.sample(range(n), 10))będzie wydajne nawet dla bardzo dużych n, ponieważ rangeobiekt jest tylko małym opakowaniem przechowującym wartości start, stop i step, ale nie tworzy pełnej listy liczb całkowitych. W Pythonie 2, można wymienić rangez xrangeaby uzyskać podobne zachowanie.
Sven Marnach

107

Myślę, że numpy.random.sampleteraz nie działa dobrze. To jest mój sposób:

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

25
Zamiast range(n)(lub arange(n)) jako pierwszego argumentu choice, jest to równoznaczne z przekazaniem n, np choice(20, 10, replace=False).
Josh Bode

1
Zauważ, że np.random.choice(a, size, replace=False)jest to bardzo wolne dla dużych a- na moim komputerze około 30 ms dla a = 1M.
Matthew Rahtz

3
Aby uniknąć problemów z czasem i pamięcią przy bardzo dużych nzastosowaniach numpy.random.Generator.choice(począwszy od numpy v1.17)
benbo

1
Główną wadą, którą widzę, jest to, że np.random.choice nie ma parametru osi -> jest to tylko dla tablic 1d.
Moosefeather

3

Lata później, trochę czasu na wybranie 40000 z 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

(Dlaczego 40000 z 10000 ^ 2 do generowania dużych? Scipy.sparse.random matryce - scipy 1.4.1 niej korzysta np.random.choice( replace=False )., Slooooow)

Końcówka kapelusza dla numpy.random people.


1

Możesz to również uzyskać, sortując:

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

-3

Po prostu wygeneruj tablicę zawierającą wymagany zakres liczb, a następnie przetasuj je, wielokrotnie zamieniając losową z zerowym elementem tablicy. Daje to losową sekwencję, która nie zawiera zduplikowanych wartości.


2
Inną właściwością wynikowej sekwencji losowej jest to, że nie jest ona szczególnie losowa .
Sven Marnach

@SvenMarnach - w większości przypadków jest jednak wystarczająco losowy. Mógłby zastosować podejście podwójnie losowe, gdyby chciał, żeby było bardziej losowe.
Wielomian

To jest bezcelowe. OP może użyć wywołań biblioteki, aby zrobić to dobrze. Są łatwiejsze w użyciu, działają szybciej i są bardziej czytelne niż wersje niestandardowe. Nie przychodzi mi do głowy żaden powód, dla którego miałbym używać złego algorytmu, tylko dlatego, że jest on prawdopodobnie „wystarczająco losowy”, a użycie właściwego algorytmu nie ma żadnej wady.
Sven Marnach,

@SvenMarnach - W porządku. Nie wiem, numpy, więc oferowałem tylko potencjalne rozwiązanie.
Wielomian
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.