Mam dwie tablice numpy o różnych kształtach, ale o tej samej długości (wymiar wiodący). Chcę przetasować każdy z nich, tak aby odpowiadające mu elementy nadal korespondowały - tj. Potasować je zgodnie zgodnie z ich wiodącymi indeksami.
Ten kod działa i ilustruje moje cele:
def shuffle_in_unison(a, b):
assert len(a) == len(b)
shuffled_a = numpy.empty(a.shape, dtype=a.dtype)
shuffled_b = numpy.empty(b.shape, dtype=b.dtype)
permutation = numpy.random.permutation(len(a))
for old_index, new_index in enumerate(permutation):
shuffled_a[new_index] = a[old_index]
shuffled_b[new_index] = b[old_index]
return shuffled_a, shuffled_b
Na przykład:
>>> a = numpy.asarray([[1, 1], [2, 2], [3, 3]])
>>> b = numpy.asarray([1, 2, 3])
>>> shuffle_in_unison(a, b)
(array([[2, 2],
[1, 1],
[3, 3]]), array([2, 1, 3]))
Jednak wydaje się to niezręczne, nieefektywne i powolne, i wymaga wykonania kopii tablic - wolałbym je przetasować w miejscu, ponieważ będą dość duże.
Czy jest lepszy sposób, aby to zrobić? Szybsze wykonanie i mniejsze zużycie pamięci to moje główne cele, ale elegancki kod również byłby miły.
Jeszcze jedna myśl, którą miałem, to:
def shuffle_in_unison_scary(a, b):
rng_state = numpy.random.get_state()
numpy.random.shuffle(a)
numpy.random.set_state(rng_state)
numpy.random.shuffle(b)
Działa to ... ale jest trochę przerażające, ponieważ widzę niewielką gwarancję, że będzie nadal działać - nie wygląda to na coś, co gwarantuje na przykład przetrwanie w różnych wersjach.
Odpowiedzi:
Twoje „przerażające” rozwiązanie nie wydaje mi się przerażające. Wywołanie
shuffle()
dwóch sekwencji o tej samej długości skutkuje taką samą liczbą wywołań do generatora liczb losowych, a są to jedyne „losowe” elementy w algorytmie odtwarzania losowego. Resetując stan, upewniasz się, że wywołania generatora liczb losowych dadzą takie same wyniki w drugim wywołaniushuffle()
, więc cały algorytm wygeneruje tę samą permutację.Jeśli ci się to nie podoba, innym rozwiązaniem byłoby przechowywanie danych w jednej tablicy zamiast w dwóch od samego początku i utworzenie dwóch widoków w tej jednej tablicy, symulując dwie macierze, które masz teraz. Możesz użyć pojedynczej tablicy do tasowania i widoków do wszystkich innych celów.
Przykład: Załóżmy tablice
a
ib
wyglądamy następująco:Możemy teraz zbudować jedną tablicę zawierającą wszystkie dane:
Teraz tworzymy widoki symulujące oryginał
a
ib
:Dane
a2
ib2
są udostępnianec
. Aby przetasować obie tablice jednocześnie, użyjnumpy.random.shuffle(c)
.W kodzie produkcyjnym oczywiście starałbyś się unikać tworzenia oryginału
a
ib
w ogóle i od razu tworzyćc
,a2
ib2
.To rozwiązanie można dostosować do przypadku
a
ib
mieć różne typy.źródło
numpy.random.shuffle()
działa na dowolnych sekwencjach, takich jak listy Python lub tablice NumPy. Kształt tablicy nie ma znaczenia, tylko długość sekwencji. Moim zdaniem jest to bardzo mało prawdopodobne.Możesz użyć indeksowania tablic NumPy :
Spowoduje to utworzenie oddzielnych, potasowanych tablic.
źródło
>>> t = timeit.Timer(stmt = "<function>(a,b)", setup = "import numpy as np; a,b = np.arange(4), np.arange(4*20).reshape((4,20))")>>> t.timeit()
i dostałem 38 sekund dla wersji OP i 27,5 sekundy dla mojej, na 1 milion połączeń każdego.a.shape
jest(31925, 405)
ib.shape
jest(31925,)
.Aby dowiedzieć się więcej, zobacz http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html
źródło
Bardzo proste rozwiązanie:
obie tablice x, y są teraz losowo tasowane w ten sam sposób
źródło
James napisał w 2015 r. Rozwiązanie sklearn , które jest pomocne. Ale dodał losową zmienną stanu, która nie jest potrzebna. W poniższym kodzie automatycznie przyjmuje się losowy stan z numpy.
źródło
źródło
Przetasuj dowolną liczbę tablic razem, na miejscu, używając tylko NumPy.
I może być używany w ten sposób
Kilka rzeczy do zapamiętania:
Po przetasowaniu dane można podzielić za
np.split
pomocą wycinków lub odwołać się do nich za pomocą wycinków - w zależności od aplikacji.źródło
RandomState
go użyć poza pętlą. Zobacz Adama Snaider za odpowiedźfor
pętli, polega na tym, czy ponownie przypisać lub ponownie wybrać stan losowy. Ponieważ liczba tablic przekazywanych do funkcji tasowania powinna być niewielka, nie spodziewałbym się różnicy w wydajności między nimi. Ale tak, rstate można przypisać poza pętlę i ponownie wprowadzić w pętli na każdej iteracji.możesz zrobić tablicę taką jak:
następnie potasuj:
teraz użyj tego jako argumentu swoich tablic. te same tasowane argumenty zwracają te same tasowane wektory.
źródło
Jednym ze sposobów tasowania w miejscu dla połączonych list jest użycie zarodka (może być losowy) i użycie numpy.random.shuffle do wykonania tasowania.
Otóż to. Spowoduje to przetasowanie zarówno aib dokładnie w ten sam sposób. Odbywa się to również w miejscu, co zawsze stanowi plus.
EDYCJA, nie używaj np.random.seed () zamiast tego użyj np.random.RandomState
Podczas wywoływania wystarczy podać dowolne ziarno, aby podać stan losowy:
Wynik:
Edycja: Naprawiono kod do ponownego inicjowania stanu losowego
źródło
RandomState
zmienia stan na pierwsze wezwanie ia
ib
nie tasuje unisono.Istnieje dobrze znana funkcja, która może to obsłużyć:
Samo ustawienie test_size na 0 pozwoli uniknąć podziału i da tasowane dane. Chociaż zwykle służy do dzielenia danych pociągu i testowania, tasuje je również.
Z dokumentacji
źródło
Powiedzmy, że mamy dwie tablice: a i b.
Możemy najpierw uzyskać indeksy wierszy poprzez permutację pierwszego wymiaru
Następnie użyj zaawansowanego indeksowania. W tym przypadku używamy tych samych wskaźników, aby wspólnie tasować obie tablice.
Jest to równoważne z
źródło
Jeśli chcesz uniknąć kopiowania tablic, sugerowałbym, aby zamiast generować listę permutacji, przejrzałeś każdy element w tablicy i losowo zamieniłeś go na inną pozycję w tablicy
To implementuje algorytm tasowania Knutha-Fishera-Yatesa.
źródło
len(a)
nareversed(range(1, len(a)))
. Ale i tak nie będzie to bardzo wydajne.To wydaje się bardzo prostym rozwiązaniem:
źródło
Na przykład to, co robię:
źródło
combo = zip(images, labels); shuffle(combo); im, lab = zip(*combo)
, tylko wolniej. Ponieważ i tak używasz Numpy, jeszcze szybszym rozwiązaniem byłoby skompresowanie tablic za pomocą Numpycombo = np.c_[images, labels]
, losowe i rozpakowanie ponownieimages, labels = combo.T
. Zakładając, żelabels
iimages
są jednowymiarowe tablice numpy o tej samej długości, aby rozpocząć, to będzie łatwo najszybszym rozwiązaniem. Jeśli są wielowymiarowe, zobacz moją odpowiedź powyżej.Rozszerzyłem random.shuffle () Pythona, aby pobrać drugi argument:
W ten sposób mogę mieć pewność, że tasowanie odbywa się w miejscu, a funkcja nie jest zbyt długa ani skomplikowana.
źródło
Po prostu użyj
numpy
...Najpierw połącz dwie tablice wejściowe Tablica 1D to etykiety (y), a tablica 2D to dane (x) i przetasuj je
shuffle
metodą NumPy . Na koniec podziel je i wróć.źródło