NumPy proponuje sposób uzyskania indeksu maksymalnej wartości tablicy przez np.argmax
.
Chciałbym podobną rzecz, ale zwracanie indeksów N
wartości maksymalnych.
Na przykład, jeśli mam tablicę [1, 3, 2, 4, 5]
, function(array, n=3)
zwróciłby indeksy [4, 3, 1]
odpowiadające elementom [5, 4, 3]
.
python
numpy
max
numpy-ndarray
Alexis Métaireau
źródło
źródło
array([5, 1, 5, 5, 2, 3, 2, 4, 1, 5])
, odrobinan= 3
? Który z wszystkich alternatyw, jak[0, 2, 3]
,[0, 2, 9]
,...
byłaby prawidłowa? Proszę opracować więcej na temat konkretnych wymagań. Dziękiargsort
może być realną alternatywą, jeśli nie przejmujesz się kolejnością zwracanych nieczystości. Zobacz moją odpowiedź poniżej.Odpowiedzi:
Najprostszy, jaki udało mi się wymyślić, to:
Wymaga to pełnego rodzaju tablicy. Zastanawiam się, czy
numpy
zapewnia wbudowany sposób na częściowe sortowanie; jak dotąd nie udało mi się go znaleźć.Jeśli to rozwiązanie okaże się zbyt wolne (szczególnie w przypadku małych
n
), warto zastanowić się nad kodowaniem czegoś w Cython .źródło
arr.argsort()[-1:-4:-1]
? Próbowałem tego w tłumaczu i daje ten sam wynik, ale zastanawiam się, czy nie jest to zepsute przez jakiś przykład.np.argsort(-arr)[:3]
, co uważam za bardziej czytelne i do rzeczy.arr.argsort()[::-1][:n]
jest lepszy, ponieważ zwraca pustąn=0
zamiast pełnej tablicyNowsze wersje NumPy (1.8 i nowsze) mają funkcję
argpartition
do tego wywołaną . Aby uzyskać indeksy czterech największych elementów, wykonajW przeciwieństwie do
argsort
tej funkcji, w najgorszym przypadku, działa ona w czasie liniowym, ale zwrócone wskaźniki nie są sortowane, jak widać z wyniku ocenya[ind]
. Jeśli też tego potrzebujesz, posortuj je później:Uzyskanie w ten sposób elementów top- k w uporządkowanej kolejności zajmuje czas O ( n + k log k ).
źródło
argpartition
działa w czasie liniowym, O (n), przy użyciu algorytmu introselect . Kolejne sortowanie obsługuje tylko k elementów, więc działa w O (k log k).np.argpartition
jego algorytm siostrzany,np.partition
bardziej szczegółowe wyjaśnienie znajduje się w powiązanym pytaniu: stackoverflow.com/questions/10337533/…a=np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
ponieważ normalne listy python nie obsługują indeksowania według list, w przeciwieństwie donp.array
np.argpartition
przyjmuje opcjonalnyaxis
argument. Aby znaleźć indeksy najwyższych n wartości dla każdego wiersza:np.argpartition(a, -n, axis=1)[-n:]
Jeszcze prostsze:
gdzie n jest liczbą maksymalnych wartości.
źródło
arr[arr.argsort()[-n:]]
zamiast negować tablicę, po prostu weź kawałek ostatnich n elementówPosługiwać się:
W przypadku zwykłych list w języku Python:
Jeśli używasz Python 2, użyj
xrange
zamiastrange
.Źródło: heapq - algorytm kolejki sterty
źródło
heapq.nlargest(3, xrange(len(a)), a.take)
. Do list w języku Python możemy użyć.__getitem__
zamiast.take
.A
, ogólnie:heapq.nlargest(3, range(len(A.ravel())), A.ravel().take)
. (Mam nadzieję, że działa to tylko w widokach, zobacz także (ravel vs flatten
] ( stackoverflow.com/a/28930580/603003 )).Jeśli akurat pracujesz z tablicą wielowymiarową, musisz spłaszczyć i rozwikłać indeksy:
Na przykład:
źródło
Jeśli nie zależy ci na kolejności K-tych największych elementów, których możesz użyć
argpartition
, które powinny działać lepiej niż pełne sortowanieargsort
.Kredyty trafiają na to pytanie .
Przeprowadziłem kilka testów i wygląda to na
argpartition
lepsze niżargsort
rozmiar tablicy i wartość K wzrostu.źródło
W przypadku tablic wielowymiarowych można użyć
axis
słowa kluczowego, aby zastosować partycjonowanie wzdłuż oczekiwanej osi.I do chwytania przedmiotów:
Pamiętaj jednak, że nie zwróci to posortowanego wyniku. W takim przypadku możesz użyć
np.argsort()
wzdłuż zamierzonej osi:Oto przykład:
źródło
np.take_along_axis
(co prawdopodobnie nie istniało, kiedy odpowiedziałeś na to pytanie)Będzie to szybsze niż pełne sortowanie, w zależności od rozmiaru oryginalnej tablicy i rozmiaru zaznaczenia:
Polega to oczywiście na manipulowaniu oryginalną tablicą. Które można naprawić (w razie potrzeby), wykonując kopię lub zastępując oryginalne wartości. ... w zależności od tego, który wariant jest tańszy w twoim przypadku użycia.
źródło
argmax(.)
za jednoznaczne. (IMHO stara się zastosować pewną logikę zwarć, ale niestety nie zapewnia ogólnie akceptowalnego zachowania). DziękiMetoda
np.argpartition
zwraca tylko k największych indeksów, wykonuje sortowanie lokalne i jest szybsza niżnp.argsort
(przeprowadzanie pełnego sortowania), gdy tablica jest dość duża. Ale zwrócone indeksy NIE są w porządku rosnącym / malejącym . Powiedzmy na przykład:Widzimy, że jeśli chcesz ścisłego porządku rosnących indeksów k,
np.argpartition
nie zwróci tego, co chcesz.Oprócz ręcznego sortowania po np.argpartition, moim rozwiązaniem jest użycie PyTorch,
torch.topk
narzędzia do budowy sieci neuronowych, zapewniającego interfejsy API NumPy z obsługą zarówno CPU, jak i GPU. Jest tak szybki jak NumPy z MKL i oferuje przyspieszenie GPU, jeśli potrzebujesz dużych obliczeń macierzy / wektorów.Kod ścisłych indeksów k wzlotów / wzlotów będzie:
Zauważ, że
torch.topk
akceptuje tensor palnika i zwraca zarówno górne wartości k, jak i górne wskaźniki k typutorch.Tensor
. Podobnie z np. Torch.topk akceptuje również argument osi, dzięki czemu można obsługiwać tablice / tensory wielowymiarowe.źródło
Posługiwać się:
Teraz
result
lista będzie zawierać N krotek (index
,value
), gdzievalue
jest zmaksymalizowane.źródło
Posługiwać się:
Działa również z tablicami 2D. Na przykład,
źródło
bottleneck
ma funkcję częściowego sortowania, jeśli koszt sortowania całej tablicy tylko w celu uzyskania N największych wartości jest zbyt duży.Nic nie wiem o tym module; Właśnie googlowałem
numpy partial sort
.źródło
Poniżej przedstawiono bardzo łatwy sposób na sprawdzenie maksymalnej liczby elementów i ich pozycji. Oto
axis
domena;axis
= 0 oznacza maksymalną liczbę w kolumnie, aaxis
= 1 oznacza maksymalną liczbę w rzędzie dla przypadku 2D. A dla wyższych wymiarów to zależy od ciebie.źródło
Uznałem, że jest najbardziej intuicyjny w użyciu
np.unique
.Chodzi o to, że unikalna metoda zwraca wskaźniki wartości wejściowych. Następnie z maksymalnej unikalnej wartości i wskazań można odtworzyć pozycję oryginalnych wartości.
źródło
Myślę, że najbardziej efektywnym sposobem na oszczędność czasu jest ręczne iterowanie tablicy i utrzymywanie stosu min wielkości K, jak wspomnieli inni ludzie.
Wymyślam też podejście brutalnej siły:
Ustaw największy element na dużą wartość ujemną po użyciu argmax do uzyskania jego indeksu. A następnie następne wywołanie argmax zwróci drugi co do wielkości element. I możesz zapisać oryginalną wartość tych elementów i odzyskać je, jeśli chcesz.
źródło
Ten kod działa dla tablicy macierzy numpy:
Powoduje to wygenerowanie prawdziwie fałszywego największego indeksowania macierzy, które działa również w celu wyodrębnienia najliczniejszych elementów z macierzy macierzy
źródło