Konsekwentnie twórz tę samą losową tablicę numpy

89

Czekam, aż inny programista ukończy fragment kodu, który zwróci tablicę np kształtu (100,2000) z wartościami -1,0 lub 1.

W międzyczasie chcę losowo utworzyć tablicę o tych samych cechach, abym mógł uzyskać przewagę nad rozwojem i testowaniem. Chodzi o to, że chcę, aby ta losowo utworzona tablica była za każdym razem taka sama, aby nie testować z tablicą, która zmienia swoją wartość za każdym razem, gdy ponownie uruchamiam mój proces.

Mogę utworzyć moją tablicę w ten sposób, ale czy istnieje sposób na jej utworzenie, aby za każdym razem była taka sama. Mogę wytrawić przedmiot i wytrącić go, ale zastanawiam się, czy jest inny sposób.

r = np.random.randint(3, size=(100, 2000)) - 1
Idr
źródło

Odpowiedzi:

84

Po prostu zaszczep generator liczb losowych stałą wartością, np

numpy.random.seed(42)

W ten sposób zawsze otrzymasz tę samą sekwencję liczb losowych.

Sven Marnach
źródło
43
Ktoś wkradł się do numpy.random.seed()funkcji, kiedy nie zwracałem uwagi. :-) Celowo zostawiłem go poza oryginalnym modułem. Zalecam, aby ludzie używali własnych instancji RandomStatei przekazywali te obiekty.
Robert Kern
6
Robert jest głównym czynnikiem przyczyniającym się do numpy. Myślę, że powinniśmy nadać jego opinii trochę wagi.
wycofane
10
@deprecated: Jestem wdzięczny za pracę Roberta, ale jego praca nie zastąpi uzasadnienia rekomendacji. Ponadto, jeśli numpy.random.seed()odradza się używanie , należy o tym wspomnieć w dokumentacji . Najwyraźniej inni współtwórcy NumPy nie podzielają opinii Roberta. Bez urazy, jestem po prostu ciekawy.
Sven Marnach
13
To jest to samo, co używanie random.seedi używanie random.Randomobiektu w standardowej bibliotece Pythona. Jeśli używasz random.seedlub numpy.random.seed, wypełniasz wszystkie przypadkowe wystąpienia, zarówno w swoim kodzie, jak iw dowolnym kodzie, który wywołujesz, lub w dowolnym kodzie uruchamianym w tej samej sesji co Twoja. Jeśli te rzeczy zależą od tego, że te rzeczy są faktycznie przypadkowe, zaczniesz napotykać problemy. Jeśli wdrożysz kod, który ustawia losowe ziarno, możesz wprowadzić lukę w zabezpieczeniach.
asmeurer
3
@asmeurer Każdy, kto używa generatora liczb pseudolosowych do celów bezpieczeństwa, prawdopodobnie nie wie, co robi.
JAB
191

Utwórz własną instancję numpy.random.RandomState()z wybranym nasieniem. Nie używaj numpy.random.seed()z wyjątkiem, aby obejść nieelastyczne biblioteki, które nie pozwalają na przekazanie Twojej własnej RandomStateinstancji.

[~]
|1> from numpy.random import RandomState

[~]
|2> prng = RandomState(1234567890)

[~]
|3> prng.randint(-1, 2, size=10)
array([ 1,  1, -1,  0,  0, -1,  1,  0, -1, -1])

[~]
|4> prng2 = RandomState(1234567890)

[~]
|5> prng2.randint(-1, 2, size=10)
array([ 1,  1, -1,  0,  0, -1,  1,  0, -1, -1])
Robert Kern
źródło
7
Czy masz jakieś uzasadnienie dla swojej rekomendacji? Co jest nie tak numpy.random.seed()? Wiem, że to nie jest bezpieczne dla wątków, ale jest naprawdę wygodne, jeśli nie potrzebujesz zabezpieczenia wątkowego.
Sven Marnach
52
Chodzi głównie o kształtowanie dobrych nawyków. Być może nie potrzebujesz teraz niezależnych strumieni, ale Sven-6-miesięcy-od-teraz może. Jeśli napiszesz swoje biblioteki, aby używać metod bezpośrednio z numpy.random, nie możesz później tworzyć niezależnych strumieni. Łatwiej jest także pisać biblioteki z zamiarem kontrolowania strumieni PRNG. Zawsze istnieje wiele sposobów wejścia do biblioteki, a każdy z nich powinien mieć sposób na kontrolowanie nasion. Pomijanie obiektów PRNG jest na to czystszym sposobem niż poleganie na nich numpy.random.seed(). Niestety, to pole komentarza jest zbyt krótkie, aby zawierać więcej przykładów. :-)
Robert Kern
25
Inny sposób opisania uzasadnienia Roberta: użycie numpy.random.seed używa zmiennej globalnej do utrzymania stanu PRNG i te same standardowe powody, dla których zmienne globalne są złe, mają tutaj zastosowanie.
Robie Basak
9
Jeśli chcesz, aby PRNG były niezależne, nie zasiewaj ich niczym. Po prostu używaj numpy.random.RandomState()bez argumentów. Spowoduje to zapełnienie stanu unikalnymi wartościami pobranymi z udogodnień systemu operacyjnego dla takich rzeczy ( /dev/urandomna komputerach z systemem UNIX i tam, gdzie ich odpowiednik w systemie Windows). Jeśli numpy.random.RandomState(1234567890)to nie działa, pokaż dokładnie, co wpisałeś i dokładnie otrzymany komunikat o błędzie.
Robert Kern
5
Nie jest to dobry pomysł. Aby numpy.random.RandomState()uzyskać najlepsze wyniki, użyj bez argumentów.
Robert Kern
3

Jeśli używasz innych funkcji opierających się na losowym stanie, nie możesz po prostu ustawić i ogólnego ziarna, ale zamiast tego powinieneś utworzyć funkcję, aby wygenerować losową listę liczb i ustawić ziarno jako parametr funkcji. Nie zakłóci to żadnych innych losowych generatorów w kodzie:

# Random states
def get_states(random_state, low, high, size):
    rs = np.random.RandomState(random_state)
    states = rs.randint(low=low, high=high, size=size)
    return states

# Call function
states = get_states(random_state=42, low=2, high=28347, size=25)
mari756h
źródło
3

Ważne jest, aby zrozumieć, co jest zalążkiem generatora losowego i kiedy / jak jest ustawione w Twoim kodzie (sprawdź np. Tutaj aby uzyskać ładne wyjaśnienie matematycznego znaczenia tego ziarna).

W tym celu musisz ustawić ziarno, wykonując:

random_state = np.random.RandomState(seed=your_favorite_seed_value)

Ważne jest wtedy, aby generować liczby losowe z random_state, a nie z np.random. Czyli powinieneś zrobić:

random_state.randint(...)

zamiast

np.random.randint(...) 

który utworzy nową instancję RandomState () i po prostu użyje wewnętrznego zegara komputera do ustawienia ziarna.

t_sic
źródło
2

Chcę tylko wyjaśnić coś w odniesieniu do odpowiedzi @Robert Kern na wypadek, gdyby nie było to jasne. Nawet jeśli użyjesz metody, RandomStatebędziesz musiał ją zainicjować za każdym razem, gdy wywołasz metodę numpy losową, jak w przykładzie Roberta, w przeciwnym razie otrzymasz następujące wyniki.

Python 3.6.9 |Anaconda, Inc.| (default, Jul 30 2019, 19:07:31) 
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> prng = np.random.RandomState(2019)
>>> prng.randint(-1, 2, size=10)
array([-1,  1,  0, -1,  1,  1, -1,  0, -1,  1])
>>> prng.randint(-1, 2, size=10)
array([-1, -1, -1,  0, -1, -1,  1,  0, -1, -1])
>>> prng.randint(-1, 2, size=10)
array([ 0, -1, -1,  0,  1,  1, -1,  1, -1,  1])
>>> prng.randint(-1, 2, size=10)
array([ 1,  1,  0,  0,  0, -1,  1,  1,  0, -1])
Kirk Walla
źródło