Jak mogę znaleźć indeks pierwszego wystąpienia liczby w tablicy Numpy? Szybkość jest dla mnie ważna. Nie interesują mnie następujące odpowiedzi, ponieważ skanują całą tablicę i nie zatrzymują się, gdy znajdą pierwsze wystąpienie:
itemindex = numpy.where(array==item)[0][0]
nonzero(array == item)[0][0]
Uwaga 1: żadna z odpowiedzi z tego pytania nie wydaje się trafna. Czy istnieje funkcja Numpy zwracająca pierwszy indeks czegoś w tablicy?
Uwaga 2: użycie metody skompilowanej w języku C jest preferowane niż pętla Pythona.
Chociaż dla ciebie jest o wiele za późno, ale do wykorzystania w przyszłości: użycie numba ( 1 ) jest najłatwiejszym sposobem, dopóki numpy go nie zaimplementuje. Jeśli używasz dystrybucji anaconda python, powinna być już zainstalowana. Kod zostanie skompilowany, więc będzie szybki.
i wtedy:
źródło
xrange
należy zmienić narange
.enumerate
, jak wfor i, v in enumerate(vec):
;if v == item: return i
. (To nie jest dobry pomysł w Pythonie <= 2.7, gdzieenumerate
tworzy listę zamiast podstawowego iteratora).Zrobiłem benchmark dla kilku metod:
argwhere
nonzero
jak w pytaniu.tostring()
jak w odpowiedzi @Rob ReilinkPython i Fortran kodu są dostępne. Pominąłem te mało obiecujące, jak konwersja na listę.
Wyniki w skali logarytmicznej. Oś X to pozycja igły (znalezienie, czy jest dalej w dół tablicy, zajmuje więcej czasu); ostatnia wartość to igła, której nie ma w tablicy. Oś Y to czas, aby ją znaleźć.
Tablica miała 1 milion elementów, a testy były wykonywane 100 razy. Wyniki wciąż nieco się wahają, ale trend jakościowy jest jasny: Python i f2py kończą pracę przy pierwszym elemencie, więc skalują się inaczej. Python działa zbyt wolno, jeśli igła nie znajduje się w pierwszym 1%, podczas gdy
f2py
jest szybki (ale musisz go skompilować).Podsumowując, f2py to najszybsze rozwiązanie , zwłaszcza jeśli igła pojawia się dość wcześnie.
Nie jest wbudowany, co jest denerwujące, ale to tylko 2 minuty pracy. Dodaj to do pliku o nazwie
search.f90
:Jeśli szukasz czegoś innego niż
integer
, po prostu zmień typ. Następnie skompiluj używając:po czym możesz zrobić (z Pythona):
źródło
f2py
wolniejszy w przypadku 1 przedmiotu niż 10?Możesz przekonwertować tablicę logiczną na ciąg znaków w języku Python za pomocą,
array.tostring()
a następnie używając metody find ():Wiąże się to jednak z kopiowaniem danych, ponieważ ciągi znaków w Pythonie muszą być niezmienne. Zaletą jest to, że możesz również wyszukać np. Zbocze narastające, znajdując
\x00\x01
źródło
W przypadku tablic posortowanych
np.searchsorted
działa.źródło
Myślę, że napotkałeś problem, w którym inna metoda i pewna wiedza a priori o tablicy naprawdę by pomogła. To coś, w przypadku którego istnieje prawdopodobieństwo X, że znajdziesz odpowiedź w pierwszych Y procentach danych. Rozdzielenie problemu z nadzieją na szczęście, a następnie zrobienie tego w Pythonie z zagnieżdżonym zrozumieniem list lub czymś podobnym.
Pisanie funkcji C wykonującej tę brutalną siłę nie jest zbyt trudne przy użyciu ctypów .
Kod C, który zhakowałem razem (index.c):
i python:
i otrzymuję 92.
Zapakuj Pythona w odpowiednią funkcję i gotowe.
Wersja C jest dużo (~ 20x) szybsza dla tego materiału siewnego (ostrzeżenie, że nie jestem dobry z czasem)
źródło
@tal przedstawił już
numba
funkcję znajdującą pierwszy indeks, ale działa ona tylko dla tablic 1D. Za pomocąnp.ndenumerate
możesz również znaleźć pierwszy indeks w tablicy dowolnie wymiarowej:Przykładowy przypadek:
Czasy pokazują, że jego wydajność jest podobna do rozwiązania tals :
źródło
array
przed wprowadzeniemnp.ndenumerate
, tak aby Twoja oś zainteresowania była pierwsza.np.argwhere
) do 717ns (twoje rozwiązanie), oba dla tablicy kształtów(3000000, 12)
).Jeśli Twoja lista jest posortowana , możesz uzyskać bardzo szybkie przeszukiwanie indeksu za pomocą pakietu „bisect”. To O (log (n)) zamiast O (n).
znajduje x w tablicy a, zdecydowanie szybciej w posortowanym przypadku niż jakakolwiek procedura C przeglądająca wszystkie pierwsze elementy (dla wystarczająco długich list).
Warto czasem wiedzieć.
źródło
>>> cond = "import numpy as np;a = np.arange(40)"
timeit("np.searchsorted(a, 39)", cond)
działa przez 3.47867107391 sekund.timeit("bisect.bisect(a, 39)", cond2)
działa przez 7.0661458969116 sekund. Wygląda na to, żenumpy.searchsorted
jest lepszy dla posortowanych tablic (przynajmniej dla int).O ile wiem tylko np.any i np. Wszystkie na tablicach boolowskich są zwarte.
W twoim przypadku numpy musi dwukrotnie przejść przez całą tablicę, raz, aby utworzyć warunek boolowski, a drugi raz, aby znaleźć indeksy.
Moją rekomendacją w tym przypadku byłoby użycie cython. Myślę, że dostosowanie przykładu do tego przypadku powinno być łatwe, zwłaszcza jeśli nie potrzebujesz dużej elastyczności dla różnych typów i kształtów.
źródło
Potrzebowałem tego do mojej pracy, więc nauczyłem się interfejsu C w języku Python i Numpy oraz napisałem własny. http://pastebin.com/GtcXuLyd Dotyczy tylko tablic 1-D, ale działa dla większości typów danych (int, float lub strings), a testy wykazały, że jest około 20 razy szybszy niż oczekiwane podejście w czystym Pythonie. tępy.
źródło
Ten problem można skutecznie rozwiązać w czystym numpy, przetwarzając tablicę w kawałkach:
Tablica jest przetwarzana w porcji o rozmiarze
step
. Imstep
dłuższy krok, tym szybsze jest przetwarzanie zerowanej tablicy (najgorszy przypadek). Im mniejszy, tym szybsze przetwarzanie tablicy z wartością niezerową na początku. Sztuczka polega na tym, aby zacząć od małegostep
i zwiększyć go wykładniczo. Ponadto nie ma potrzeby podwyższania go powyżej pewnego progu ze względu na ograniczone korzyści.Porównałem to rozwiązanie z czystym rozwiązaniem ndarary.nonzero i numba z 10 milionami tablic typu float.
I wyniki na moim komputerze:
Czysty
ndarray.nonzero
jest zdecydowanie luźniejszy. Rozwiązanie numba jest około 5 razy szybsze w najlepszym przypadku. W najgorszym przypadku jest około 3 razy szybsza.źródło
Jeśli szukasz pierwszego niezerowego elementu, możesz użyć następującego hacka:
Jest to bardzo szybkie rozwiązanie typu „numpy-pure”, ale zawodzi w niektórych przypadkach omówionych poniżej.
Rozwiązanie wykorzystuje fakt, że prawie cała reprezentacja zera dla typów liczbowych składa się z
0
bajtów. Dotyczy to również numpy'sbool
. W ostatnich wersjach numpy,argmax()
funkcja używa logiki zwarcia podczas przetwarzaniabool
typu. Rozmiarbool
to 1 bajt.Więc trzeba:
bool
. Żadna kopia nie jest tworzonaargmax()
aby znaleźć pierwszy niezerowy bajt za pomocą logiki zwarcia//
) przesunięcia o rozmiar pojedynczego elementu wyrażone w bajtach (x.itemsize
)x[idx]
faktycznie jest niezerowe, aby zidentyfikować przypadek, w którym nie ma wartości niezerowejZrobiłem test porównawczy w stosunku do rozwiązania numba i zbudowałem go
np.nonzero
.Wynik na moim komputerze to:
Rozwiązanie jest o 33% szybsze niż numba i jest „czyste-numpy”.
Wady:
object
float
lubdouble
źródło
x
zanim zadzwonisznonzero()
. Prawdopodobnie będzie wolniejszy niż numba, ale ** nie będzie ** przeszukiwał całej tablicy, szukając pierwszego wpisu zerowego, więc może być wystarczająco szybki dla twoich potrzeb.Jako wieloletni użytkownik Matlaba od dłuższego czasu szukałem skutecznego rozwiązania tego problemu. Na koniec, zmotywowany dyskusjami i propozycjami w tym wątku , starałem się wymyślić rozwiązanie, które implementuje API podobne do tego, co tu sugerowano , obsługujące na razie tylko tablice 1D.
Używałbyś tego w ten sposób
Obsługiwane operatory warunków to: cmp_equal, cmp_not_equal, cmp_larger, cmp_smaller, cmp_larger_eq, cmp_smaller_eq. Dla wydajności rozszerzenie jest napisane w c.
Źródło, testy porównawcze i inne szczegóły znajdziesz tutaj:
https://pypi.python.org/pypi?name=py_find_1st&:action=display
do użytku w naszym zespole (anaconda na linux i macos) Zrobiłem instalator anaconda, który upraszcza instalację, możesz go używać zgodnie z opisem tutaj
https://anaconda.org/roebel/py_find_1st
źródło
Tylko uwaga, że jeśli wykonujesz sekwencję wyszukiwań, wzrost wydajności wynikający z zrobienia czegoś sprytnego, takiego jak konwersja na ciąg znaków, może zostać utracony w zewnętrznej pętli, jeśli wymiar wyszukiwania nie jest wystarczająco duży. Zobacz, jak działa iteracja find1 wykorzystująca sztuczkę konwersji ciągów zaproponowaną powyżej i find2, która używa argmax wzdłuż osi wewnętrznej (plus korekta zapewniająca, że niedopasowanie zwraca wartość -1)
wyjścia
To powiedziawszy, znalezienie napisane w C byłoby co najmniej trochę szybsze niż którekolwiek z tych podejść
źródło
co powiesz na to
źródło
where(array==item)[0][0]
z pytania ...Możesz ukryć swoją tablicę w a
list
i użyć jejindex()
metody:O ile mi wiadomo, jest to metoda skompilowana w C.
źródło
timeit()
na tablicy 10000 liczb całkowitych - konwersja do listy była około 100 razy wolniejsza! Zapomniałem, że podstawowa struktura danych dla tablicy numpy jest bardzo różna od listy ..