Muszę znaleźć unikalne wiersze w numpy.array
.
Na przykład:
>>> a # I have
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 0]])
Wiem, że mogę utworzyć zestaw i zapętlić tablicę, ale szukam wydajnego czystego numpy
rozwiązania. Uważam, że istnieje sposób, aby ustawić typ danych jako nieważny, a następnie mógłbym po prostu użyć numpy.unique
, ale nie mogłem wymyślić, jak to zrobić.
Odpowiedzi:
Od NumPy 1.13 można po prostu wybrać oś do wyboru unikalnych wartości w dowolnej tablicy N-dim. Aby uzyskać unikalne wiersze, możesz:
unique_rows = np.unique(original_array, axis=0)
źródło
np.unique(list_cor, axis=0)
dostaje tablicę ze zduplikowanymi wierszami ; nie filtruje tablicy do elementów unikalnych w oryginalnej tablicy . Zobacz tutaj , na przykład ..original_array.sort(axis=1)
Jeszcze inne możliwe rozwiązanie
źródło
np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]}))
FutureWarning: tablice na stos muszą być przekazywane jako typ „sekwencji”, taki jak lista lub krotka. Wsparcie dla iteracji niesekwencyjnych, takich jak generatory, jest przestarzałe od NumPy 1.16 i spowoduje błąd w przyszłości.Inną opcją użycia tablic strukturalnych jest użycie widoku
void
typu, który łączy cały wiersz w jeden element:EDYCJA Dodano
np.ascontiguousarray
zgodnie z zaleceniem @ seberg. Spowolni to metodę, jeśli tablica nie jest już ciągła.EDYCJA Powyższe można nieco przyspieszyć, być może kosztem przejrzystości, wykonując:
Ponadto, przynajmniej w moim systemie, pod względem wydajności jest na równi, a nawet lepiej, niż metoda lexsort:
źródło
b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
:?np.void
typie danych wielkości liczby bajtów w pełnym rzędzie. To dwa podobne, co dostajesz, jeśli masz tablicęnp.uint8
s i widzisz ją jakonp.uint16
s, która łączy co dwie kolumny w jedną, ale bardziej elastyczną.np.ascontiguousarray
podobnego, aby być ogólnie bezpiecznym (wiem, że jest to nieco bardziej restrykcyjne niż konieczne, ale ...). Wiersze muszą być ciągłe, aby widok działał zgodnie z oczekiwaniami.np.unique
na tablicynp.void
zwraca błąd związany z brakiem implementacji scalania dla tego typu. Jednak działa dobrze w 1.7.-0.
który nie będzie porównywany jako równy+0.
, podczas gdy porównanie elementu po elemencie miałoby-0.==+0.
(zgodnie z normą ieee float). Zobacz stackoverflow.com/questions/26782038/…Jeśli chcesz uniknąć kosztów pamięci związanych z konwersją do serii krotek lub innej podobnej struktury danych, możesz wykorzystać tablice strukturalne numpy.
Sztuką jest wyświetlenie oryginalnej tablicy jako tablicy strukturalnej, w której każdy element odpowiada rzędowi oryginalnej tablicy. To nie tworzy kopii i jest dość wydajne.
Jako szybki przykład:
Aby zrozumieć, co się dzieje, spójrz na wyniki pośrednie.
Gdy zobaczymy rzeczy jako tablicę strukturalną, każdy element w tablicy jest wierszem w oryginalnej tablicy. (Zasadniczo jest to struktura danych podobna do listy krotek).
Po uruchomieniu
numpy.unique
otrzymamy tablicę strukturalną:To, co musimy następnie zobaczyć jako „normalną” tablicę (
_
przechowuje wynik ostatniego obliczeniaipython
, dlatego właśnie widzisz_.view...
):A następnie przekształć z powrotem w tablicę 2D (
-1
jest symbolem zastępczym, który każe numpy obliczyć prawidłową liczbę wierszy, podać liczbę kolumn):Oczywiście, jeśli chcesz być bardziej zwięzły, możesz napisać to jako:
Co skutkuje w:
źródło
lexsort
. Myślałem, że masz na myśli listę krotek. Tak,lexsort
jest prawdopodobnie lepszą opcją w tym przypadku. Zapomniałem o tym i przeskoczyłem do zbyt złożonego rozwiązania.np.unique
kiedy go uruchomię,np.random.random(100).reshape(10,10)
zwraca wszystkie unikalne pojedyncze elementy, ale chcesz unikalnych wierszy, więc najpierw musisz je umieścić w krotki:To jedyny sposób, w jaki widzę, jak zmieniasz typy, aby robić to, co chcesz, i nie jestem pewien, czy iteracja listy do zamiany na krotki jest w porządku z twoim „nie powtarzaniem”
źródło
< 100
wiersze na wywołanie. To dokładnie opisuje, w jaki sposób przeprowadzane jest wykonywanie unikatowych wierszy.uniques
zawiera unikalne elementy. Potencjalnie nie rozumiem oczekiwanego kształtuarray
- czy mógłbyś być tutaj bardziej precyzyjny?uniques
jest sortowany (a zatem różni się od wierszy warray
).B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
np.unique działa poprzez sortowanie spłaszczonej tablicy, a następnie sprawdzenie, czy każdy element jest równy poprzedniemu. Można to zrobić ręcznie bez spłaszczania:
Ta metoda nie używa krotek i powinna być znacznie szybsza i prostsza niż inne metody tu podane.
UWAGA: poprzednia wersja tego nie miała ind bezpośrednio po [, co oznacza, że użyto niewłaściwych indeksów. Poza tym Joe Kington ma rację, że robi to wiele pośrednich kopii. Poniższa metoda zmniejsza, tworząc posortowaną kopię, a następnie używając jej widoków:
Jest to szybsze i zużywa mniej pamięci.
Ponadto, jeśli chcesz znaleźć unikalne wiersze w tablicy ndarray niezależnie od liczby wymiarów w tablicy, będą działać następujące czynności:
Ciekawym pozostałym problemem byłoby, gdybyś chciał posortować / unikalny wzdłuż dowolnej osi tablicy o dowolnym wymiarze, co byłoby trudniejsze.
Edytować:
Aby zademonstrować różnice prędkości, przeprowadziłem kilka testów w ipython trzech różnych metod opisanych w odpowiedziach. Z twoim dokładnym a nie ma zbyt dużej różnicy, chociaż ta wersja jest nieco szybsza:
Z większym a ta wersja kończy się jednak znacznie, znacznie szybciej:
źródło
a[ind[1:]]
jest kopią itp.) Z drugiej strony twoje rozwiązanie jest zazwyczaj 2-3 razy szybsze niż moje, dopóki nie zabraknie pamięci RAM.dtype
masz na myśli? Myślę, że źle to zrozumiałeś. W moim systemie wywołanienp.unique
zgodnie z opisem w mojej odpowiedzi jest nieco szybsze niż użycie jednego z dwóch smakównp.lexsort
. I jest około 5 razy szybsza, jeśli tablica do wyszukiwania unikalnych ma kształt(10000, 100)
. Nawet jeśli zdecydujesz się na ponowne zaimplementowanie tego, co skracanp.unique
niektóre (niewielkie) czasy wykonania, zwinięcie każdego wiersza w pojedynczy obiekt powoduje szybsze porównania niż konieczność wywoływanianp.any
porównania kolumn, szczególnie w przypadku większej liczby kolumn.dtype
jest to tylkoa.dtype
typ danych oglądanych danych, tak jak to zrobił Joe Kington w swojej odpowiedzi. Jeśli jest wiele kolumn, innym (niedoskonałym!) Sposobem na szybkie utrzymanielexsort
jest sortowanie tylko na kilku kolumnach. Jest to specyficzne dla danych, ponieważ trzeba wiedzieć, które kolumny zapewniają wystarczającą wariancję, aby idealnie sortować. Ega.shape = (60000, 500)
- sort na pierwszych 3 kolumny:ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0]))
. Oszczędności czasu są dość znaczne, ale ponownie zastrzeżenie: może nie obejmować wszystkich przypadków - zależy to od danych.Oto kolejna odmiana pythonicznej odpowiedzi @Greg
źródło
Porównałem sugerowaną alternatywę dla szybkości i odkryłem, że, co zaskakujące,
unique
rozwiązanie widoku pustki jest nawet nieco szybsze niż natywny numpyunique
zaxis
argumentem. Jeśli szukasz prędkości, będziesz chciałKod do odtworzenia fabuły:
źródło
vstack_dict
nigdy nie używa dykta, nawiasy klamrowe są ustalonym rozumieniem, a zatem jego zachowanie jest prawie identycznevstatck_set
. Ponieważvstack_dict
brakuje linii wydajności dla wykresu fro, wygląda na to, że jest ona objęta przezvstack_set
wykres wydajności, ponieważ są one bardzo podobne!vstack
wariant.Nie podobało mi się żadna z tych odpowiedzi, ponieważ żadna nie obsługuje tablic zmiennoprzecinkowych w algebrze liniowej lub w przestrzeni wektorowej, w której dwa wiersze będące „równe” oznaczają „w pewnym 𝜀”. Jedna odpowiedź, która ma próg tolerancji, https://stackoverflow.com/a/26867764/500207 , przyjęła próg zarówno pod względem elementarnym, jak i precyzji dziesiętnej , co działa w niektórych przypadkach, ale nie jest tak matematycznie ogólne jak prawdziwa odległość wektorowa.
Oto moja wersja:
Powyższa funkcja domeny publicznej służy
scipy.spatial.distance.pdist
do znajdowania odległości euklidesowej (konfigurowalnej) między każdą parą wierszy. Następnie porównuje każdą odległość zethresh
starą, aby znaleźć wiersze, które sąthresh
między sobą, i zwraca tylko jeden wiersz z każdej grupythresh
.Jak wskazano, odległość
metric
nie musi być euklidesowa -pdist
może obliczyć różne odległości, w tymcityblock
(normę Manhattanu) icosine
(kąt między wektorami).Jeśli
thresh=0
(domyślnie), wiersze muszą być bitowe, aby można je było uznać za „unikalne”. Inne dobre wartości dothresh
zastosowania skalowane precyzja maszyny, tjthresh=np.spacing(1)*1e3
.źródło
set
) jako reprezentatywne dla każdejthresh
wielkości sąsiedztwa, funkcja może pozwolić użytkownik, aby określić, jak wybrać ten punkt, np. użyć „mediany” lub punktu najbliższego środka ciężkości itp.thresh
, będzie losowy z powodu nieuporządkowanej naturyset
. Oczywiście, że to brainfart na mojej części,set
przechowuje krotki indeksów, które są wthresh
-neighborhood, więc tofindRows
robi w rzeczywistości zamian za każdymthresh
-cluster, pierwszy wiersz w nim.Dlaczego nie skorzystać
drop_duplicates
z pand:źródło
Numpy_indexed pakiet (disclaimer: Jestem jego autorem) owija rozwiązanie zamieszczonych przez Jaime w miłej i sprawdzony interfejs, a także wiele innych funkcji:
źródło
np.unique działa, mając listę krotek:
Z listą list podnosi
TypeError: unhashable type: 'list'
źródło
W oparciu o odpowiedź na tej stronie napisałem funkcję, która replikuje zdolność funkcji MATLAB
unique(input,'rows')
, z dodatkową funkcją akceptowania tolerancji dla sprawdzania unikalności. Zwraca również takie wskaźniki, żec = data[ia,:]
idata = c[ic,:]
. Zgłoś, jeśli zauważysz jakiekolwiek rozbieżności lub błędy.źródło
Oprócz doskonałej odpowiedzi @Jaime, innym sposobem zwinięcia wiersza jest użycie
a.strides[0]
(zakładając, żea
jest to ciągły C), który jest równya.dtype.itemsize*a.shape[0]
. Ponadtovoid(n)
jest skrót dodtype((void,n))
. docieramy w końcu do tej najkrótszej wersji:Dla
źródło
W przypadku ogólnych celów, takich jak wielowymiarowe tablice zagnieżdżone 3D lub wyższe, wypróbuj to:
który odpowiada Twojemu zestawowi danych 2D:
daje:
Ale także tablice 3D, takie jak:
daje:
źródło
unique
return_index
jak Jaime powinno uprościć tę ostatniąreturn
linię. Po prostu zindeksuj orginalar
na prawej osi.Żadna z tych odpowiedzi nie działała dla mnie. Zakładam, że moje unikalne wiersze zawierały ciągi, a nie liczby. Jednak ta odpowiedź z innego wątku działała:
Źródło: https://stackoverflow.com/a/38461043/5402386
Możesz użyć metod z listy .count () i .index ()
źródło
Możemy faktycznie zamienić tablicę liczbową mxn na tablicę ciągów liczbowych mx 1, spróbuj użyć następującej funkcji, która zapewnia count , inverse_idx i etc, podobnie jak numpy.unique:
Przykład:
źródło
Pobierzmy całą macierz liczbową jako listę, a następnie upuść duplikaty z tej listy, a na koniec zwróć naszą unikalną listę z powrotem do macierzy liczbowej:
źródło
Najprostszym rozwiązaniem jest uczynienie wierszy pojedynczym elementem poprzez utworzenie ciągów. Każdy wiersz może być następnie porównany jako całość za pomocą numpy. To rozwiązanie jest możliwe do uogólnienia, wystarczy przekształcić i przetransponować tablicę dla innych kombinacji. Oto rozwiązanie podanego problemu.
Da:
Wyślij moją nagrodę Nobla pocztą
źródło
źródło