Jeśli szukasz pierwszego wiersza, w którym element istnieje w pierwszej kolumnie, to działa (chociaż spowoduje błąd indeksu, jeśli nie istnieje)rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
BrT
27
Co jeśli chcesz, aby przestał szukać po znalezieniu pierwszej wartości? Nie sądzę, że where () jest porównywalne do find ()
np.argwherebyłby nieco bardziej przydatny tutaj:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
Eric
3
Warto zauważyć, że ta odpowiedź zakłada, że tablica jest 2D. wheredziała na dowolnej macierzy i zwróci krotkę o długości 3, gdy zostanie użyta na macierzy 3D itp.
P. Camilleri
69
Jeśli potrzebujesz indeksu pierwszego wystąpienia tylko jednej wartości , możesz użyć nonzero(lub where, co w tym przypadku odpowiada tej samej rzeczy):
>>> t = array([1,1,1,2,2,3,8,3,8,8])>>> nonzero(t ==8)(array([6,8,9]),)>>> nonzero(t ==8)[0][0]6
Jeśli potrzebujesz pierwszego indeksu każdej z wielu wartości , możesz oczywiście zrobić to samo, co powyżej wielokrotnie, ale istnieje pewna sztuczka, która może być szybsza. Poniżej znajduje się indeks pierwszego elementu każdego podsekwencji :
Zauważ, że znajduje początek zarówno podsekwencji 3, jak i obu podsekwencji 8:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Jest to więc nieco inne niż znalezienie pierwszego wystąpienia każdej wartości. W swoim programie możesz pracować z posortowaną wersją, taby uzyskać to, czego chcesz:
>>> st = sorted(t)>>> nonzero(r_[1, diff(st)[:-1]])(array([0,3,5,7]),)
@Geoff, r_konkatenuje; lub, dokładniej, przekłada obiekty wycięte na konkatenację wzdłuż każdej osi. Mógłbym hstackzamiast tego użyć ; to mogło być mniej mylące. Zobacz dokumentację uzyskać więcej informacji na temat r_. Istnieje również c_.
Vebjorn Ljosa
+1, fajny! (w porównaniu z NP. gdzie indziej) Twoje rozwiązanie jest o wiele prostsze (i prawdopodobnie szybsze) w przypadku, gdy potrzebujemy tylko pierwszego wystąpienia danej wartości w tablicy 1D
doug
3
Ten drugi przypadek (znalezienie pierwszego indeksu wszystkich wartości) podajevals, locs = np.unique(t, return_index=True)
askewchan,
50
Możesz także przekonwertować tablicę NumPy na listę w powietrzu i uzyskać jej indeks. Na przykład,
l =[1,2,3,4,5]# Python list
a = numpy.array(l)# NumPy array
i = a.tolist().index(2)# i will return index of 2print i
Być może biblioteka uległa zmianie od czasu jej napisania. Ale to było pierwsze rozwiązanie, które zadziałało dla mnie.
amracel
1
Dobrze to wykorzystałem, aby znaleźć wiele wartości na liście, używając zrozumienia listy:[find_list.index(index_list[i]) for i in range(len(index_list))]
Matt Wenham
1
@MattWenham Jeśli jest wystarczająco duży, możesz przekonwertować find_listgo na tablicę NumPy object(lub cokolwiek bardziej szczegółowego, który jest odpowiedni) i po prostu zrobić find_arr[index_list].
Narfanar,
Zupełnie nie na temat, ale po raz pierwszy widzę wyrażenie „w powietrzu” - to, co widziałem najbardziej, na swoim miejscu, to prawdopodobnie „w locie”.
flow2k
18
Wystarczy dodać bardzo wydajny i poręczny numbaalternatywa oparta na np.ndenumerateznalezieniu pierwszego indeksu:
from numba import njit
import numpy as np
@njitdef index(array, item):for idx, val in np.ndenumerate(array):if val == item:return idx
# If no item was found return None, other return types might be a problem due to# numbas type inference.
Jest to dość szybkie i naturalnie zajmuje się tablicami wielowymiarowymi :
Może to być znacznie szybsze (ponieważ powoduje to zwarcie operacji) niż jakakolwiek metoda wykorzystująca np.wherelub np.nonzero.
Jednak np.argwheremoże również z wdziękiem poradzić sobie z tablicami wielowymiarowymi (musisz ręcznie rzucić go na krotkę i nie jest zwarty), ale nie powiedzie się, jeśli nie zostanie znalezione dopasowanie:
@njitjest skrótem, jit(nopython=True)tj. funkcja zostanie w pełni skompilowana w locie podczas pierwszego uruchomienia, tak aby wywołania interpretera Pythona zostały całkowicie usunięte.
bartolo-otrit
14
Jeśli zamierzasz użyć tego jako indeksu do czegoś innego, możesz użyć indeksów boolowskich, jeśli tablice są nadające; nie potrzebujesz wyraźnych wskaźników. Absolutnie najprostszym sposobem na to jest po prostu indeksowanie na podstawie wartości prawdy.
other_array[first_array == item]
Każda operacja logiczna działa:
a = numpy.arange(100)
other_array[first_array >50]
Metoda niezerowa przyjmuje również logiczne:
index = numpy.nonzero(first_array == item)[0][0]
Dwa zera oznaczają krotkę indeksów (zakładając, że first_array to 1D), a następnie pierwszy element w tablicy indeksów.
l.index(x)zwraca najmniejsze i, tak że i jest indeksem pierwszego wystąpienia x na liście.
Można bezpiecznie założyć, że index()funkcja w Pythonie jest zaimplementowana tak, że zatrzymuje się po znalezieniu pierwszego dopasowania, a to skutkuje optymalną średnią wydajnością.
Aby znaleźć element zatrzymujący się po pierwszym dopasowaniu w tablicy NumPy, użyj iteratora ( ndenumerate ).
In[67]: l=range(100)In[68]: l.index(2)Out[68]:2
Tablica NumPy:
In[69]: a = np.arange(100)In[70]: next((idx for idx, val in np.ndenumerate(a)if val==2))Out[70]:(2L,)
Zauważ, że obie metody index()i nextzwracają błąd, jeśli element nie zostanie znaleziony. Za nextpomocą drugiego argumentu można zwrócić specjalną wartość na wypadek, gdyby element nie został znaleziony, np
In[77]: next((idx for idx, val in np.ndenumerate(a)if val==400),None)
Istnieją inne funkcje w NumPy ( argmax, wherei nonzero), których można użyć do znalezienia elementu w tablicy, ale wszystkie mają tę wadę, że przechodzą przez całą tablicę w poszukiwaniu wszystkich wystąpień, a zatem nie są zoptymalizowane pod kątem znalezienia pierwszego elementu. Zwróć także uwagę na to wherei nonzerozwracaj tablice, więc musisz wybrać pierwszy element, aby uzyskać indeks.
Wystarczy sprawdzić, czy w przypadku dużych tablic rozwiązanie korzystające z iteratora jest szybsze, gdy szukany element znajduje się na początku tablicy (używając %timeitw powłoce IPython):
In[285]: a = np.arange(100000)In[286]:%timeit next((idx for idx, val in np.ndenumerate(a)if val==0))100000 loops, best of 3:17.6µs per loop
In[287]:%timeit np.argmax(a==0)1000 loops, best of 3:254µs per loop
In[288]:%timeit np.where(a==0)[0][0]1000 loops, best of 3:314µs per loop
Myślę, że powinieneś również podać czas na najgorszy przypadek (ostatni element), aby czytelnicy wiedzieli, co się z nimi dzieje w najgorszym przypadku, gdy zastosują twoje podejście.
MSeifert
@MSeifert Nie mogę znaleźć rozsądnego terminu na najgorsze rozwiązanie iteratora - zamierzam usunąć tę odpowiedź, dopóki nie dowiem się, co jest z nią nie tak
user2314737
1
nie %timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))działa? Jeśli zastanawiasz się, dlaczego jest to 1000 razy wolniej - dzieje się tak dlatego, że pętle pythonowe nad tablicami liczb są bardzo powolne.
MSeifert
@MSeifert no ja nie wiem, ale jestem zaskoczony również przez fakt, że argmaxi wheresą znacznie szybsze w tym przypadku (poszukiwanej elementu na końcu tablicy)
user2314737
Powinny być tak szybkie, jakby element znajdował się na początku. Zawsze przetwarzają całą tablicę, więc zawsze zajmują tyle samo czasu (przynajmniej powinny).
MSeifert
9
W przypadku tablic sortowanych jednowymiarowo byłoby znacznie prostsze i wydajniejsze O (log (n)), aby użyć numpy.searchsorted, która zwraca liczbę całkowitą NumPy (pozycja). Na przykład,
arr = np.array([1,1,1,2,3,3,4])
i = np.searchsorted(arr,3)
Upewnij się tylko, że tablica jest już posortowana
Sprawdź także, czy zwrócony indeks i rzeczywiście zawiera szukany element, ponieważ głównym celem searchsorted jest znalezienie indeksów, w których należy wstawić elementy, aby zachować porządek.
if arr[i]==3:print("present")else:print("not present")
searchsorted nie jest nlog (n), ponieważ nie sortuje tablicy przed wyszukiwaniem, zakłada, że tablica argumentów jest już posortowana. sprawdź dokumentację numpy.searchsorted (link powyżej)
Alok Nayak
6
Aby indeksować według dowolnych kryteriów, możesz wykonać następujące czynności:
In[1]:from numpy import*In[2]: x = arange(125).reshape((5,5,5))In[3]: y = indices(x.shape)In[4]: locs = y[:,x >=120]# put whatever you want in place of x >= 120In[5]: pts = hsplit(locs, len(locs[0]))In[6]:for pt in pts:.....:print(', '.join(str(p[0])for p in pt))4,4,04,4,14,4,24,4,34,4,4
A oto krótka funkcja pozwalająca zrobić to, co robi list.index (), z wyjątkiem tego, że nie zgłasza wyjątku, jeśli go nie znaleziono. Uwaga - na dużych tablicach jest to prawdopodobnie bardzo wolne. Prawdopodobnie możesz załatać to na tablice, jeśli wolisz użyć jej jako metody.
def ndindex(ndarray, item):if len(ndarray.shape)==1:try:return[ndarray.tolist().index(item)]except:passelse:for i, subarray in enumerate(ndarray):try:return[i]+ ndindex(subarray, item)except:passIn[1]: ndindex(x,103)Out[1]:[4,0,3]
Alternatywą dla wyboru pierwszego elementu z np.where () jest użycie wyrażenia generatora wraz z wyliczeniem, takiego jak:
>>>import numpy as np
>>> x = np.arange(100)# x = array([0, 1, 2, 3, ... 99])>>> next(i for i, x_i in enumerate(x)if x_i ==2)2
W przypadku tablicy dwuwymiarowej można zrobić:
>>> x = np.arange(100).reshape(10,10)# x = array([[0, 1, 2,... 9], [10,..19],])>>> next((i,j)for i, x_i in enumerate(x)...for j, x_ij in enumerate(x_i)if x_ij ==2)(0,2)
Zaletą tego podejścia jest to, że przestaje on sprawdzać elementy tablicy po znalezieniu pierwszego dopasowania, podczas gdy np. Gdzie sprawdza wszystkie elementy pod kątem dopasowania. Wyrażenie generatora byłoby szybsze, gdyby dopasowanie było wczesne w tablicy.
W przypadku, gdy w tablicy może nie być żadnego dopasowania, ta metoda pozwala również wygodnie określić wartość rezerwową. Gdyby pierwszy przykład powrócił Nonejako rezerwowy, stałby się next((i for i, x_i in enumerate(x) if x_i == 2), None).
Erlend Magnus Viggen
4
Istnieje wiele operacji w NumPy, które mogą być połączone, aby to osiągnąć. Zwróci to indeksy elementów równe itemowi:
numpy.nonzero(array - item)
Następnie możesz wziąć pierwsze elementy list, aby uzyskać pojedynczy element.
Odpowiedzi:
Tak, oto odpowiedź na podaną tablicę NumPy
array
i wartośćitem
, aby wyszukać:Wynikiem jest krotka z najpierw wszystkimi indeksami wierszy, a następnie wszystkimi indeksami kolumn.
Na przykład, jeśli tablica ma dwa wymiary i zawierała twój przedmiot w dwóch lokalizacjach
będzie równa twojemu przedmiotowi i tak też będzie
numpy.where
źródło
rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
np.argwhere
byłby nieco bardziej przydatny tutaj:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
działa na dowolnej macierzy i zwróci krotkę o długości 3, gdy zostanie użyta na macierzy 3D itp.Jeśli potrzebujesz indeksu pierwszego wystąpienia tylko jednej wartości , możesz użyć
nonzero
(lubwhere
, co w tym przypadku odpowiada tej samej rzeczy):Jeśli potrzebujesz pierwszego indeksu każdej z wielu wartości , możesz oczywiście zrobić to samo, co powyżej wielokrotnie, ale istnieje pewna sztuczka, która może być szybsza. Poniżej znajduje się indeks pierwszego elementu każdego podsekwencji :
Zauważ, że znajduje początek zarówno podsekwencji 3, jak i obu podsekwencji 8:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Jest to więc nieco inne niż znalezienie pierwszego wystąpienia każdej wartości. W swoim programie możesz pracować z posortowaną wersją,
t
aby uzyskać to, czego chcesz:źródło
r_
to jest?r_
konkatenuje; lub, dokładniej, przekłada obiekty wycięte na konkatenację wzdłuż każdej osi. Mógłbymhstack
zamiast tego użyć ; to mogło być mniej mylące. Zobacz dokumentację uzyskać więcej informacji na tematr_
. Istnieje równieżc_
.vals, locs = np.unique(t, return_index=True)
Możesz także przekonwertować tablicę NumPy na listę w powietrzu i uzyskać jej indeks. Na przykład,
Wydrukuje 1.
źródło
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
go na tablicę NumPyobject
(lub cokolwiek bardziej szczegółowego, który jest odpowiedni) i po prostu zrobićfind_arr[index_list]
.Wystarczy dodać bardzo wydajny i poręczny numbaalternatywa oparta na
np.ndenumerate
znalezieniu pierwszego indeksu:Jest to dość szybkie i naturalnie zajmuje się tablicami wielowymiarowymi :
Może to być znacznie szybsze (ponieważ powoduje to zwarcie operacji) niż jakakolwiek metoda wykorzystująca
np.where
lubnp.nonzero
.Jednak
np.argwhere
może również z wdziękiem poradzić sobie z tablicami wielowymiarowymi (musisz ręcznie rzucić go na krotkę i nie jest zwarty), ale nie powiedzie się, jeśli nie zostanie znalezione dopasowanie:źródło
@njit
jest skrótem,jit(nopython=True)
tj. funkcja zostanie w pełni skompilowana w locie podczas pierwszego uruchomienia, tak aby wywołania interpretera Pythona zostały całkowicie usunięte.Jeśli zamierzasz użyć tego jako indeksu do czegoś innego, możesz użyć indeksów boolowskich, jeśli tablice są nadające; nie potrzebujesz wyraźnych wskaźników. Absolutnie najprostszym sposobem na to jest po prostu indeksowanie na podstawie wartości prawdy.
Każda operacja logiczna działa:
Metoda niezerowa przyjmuje również logiczne:
Dwa zera oznaczają krotkę indeksów (zakładając, że first_array to 1D), a następnie pierwszy element w tablicy indeksów.
źródło
l.index(x)
zwraca najmniejsze i, tak że i jest indeksem pierwszego wystąpienia x na liście.Można bezpiecznie założyć, że
index()
funkcja w Pythonie jest zaimplementowana tak, że zatrzymuje się po znalezieniu pierwszego dopasowania, a to skutkuje optymalną średnią wydajnością.Aby znaleźć element zatrzymujący się po pierwszym dopasowaniu w tablicy NumPy, użyj iteratora ( ndenumerate ).
Tablica NumPy:
Zauważ, że obie metody
index()
inext
zwracają błąd, jeśli element nie zostanie znaleziony. Zanext
pomocą drugiego argumentu można zwrócić specjalną wartość na wypadek, gdyby element nie został znaleziony, npIstnieją inne funkcje w NumPy (
argmax
,where
inonzero
), których można użyć do znalezienia elementu w tablicy, ale wszystkie mają tę wadę, że przechodzą przez całą tablicę w poszukiwaniu wszystkich wystąpień, a zatem nie są zoptymalizowane pod kątem znalezienia pierwszego elementu. Zwróć także uwagę na towhere
inonzero
zwracaj tablice, więc musisz wybrać pierwszy element, aby uzyskać indeks.Porównanie czasu
Wystarczy sprawdzić, czy w przypadku dużych tablic rozwiązanie korzystające z iteratora jest szybsze, gdy szukany element znajduje się na początku tablicy (używając
%timeit
w powłoce IPython):To jest otwarty problem NumPy GitHub .
Zobacz także: Numpy: szybko znajdź pierwszy indeks wartości
źródło
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
działa? Jeśli zastanawiasz się, dlaczego jest to 1000 razy wolniej - dzieje się tak dlatego, że pętle pythonowe nad tablicami liczb są bardzo powolne.argmax
iwhere
są znacznie szybsze w tym przypadku (poszukiwanej elementu na końcu tablicy)W przypadku tablic sortowanych jednowymiarowo byłoby znacznie prostsze i wydajniejsze O (log (n)), aby użyć numpy.searchsorted, która zwraca liczbę całkowitą NumPy (pozycja). Na przykład,
Upewnij się tylko, że tablica jest już posortowana
Sprawdź także, czy zwrócony indeks i rzeczywiście zawiera szukany element, ponieważ głównym celem searchsorted jest znalezienie indeksów, w których należy wstawić elementy, aby zachować porządek.
źródło
Aby indeksować według dowolnych kryteriów, możesz wykonać następujące czynności:
A oto krótka funkcja pozwalająca zrobić to, co robi list.index (), z wyjątkiem tego, że nie zgłasza wyjątku, jeśli go nie znaleziono. Uwaga - na dużych tablicach jest to prawdopodobnie bardzo wolne. Prawdopodobnie możesz załatać to na tablice, jeśli wolisz użyć jej jako metody.
źródło
Dla tablic 1D, polecam
np.flatnonzero(array == value)[0]
, co jest równoważne zarównonp.nonzero(array == value)[0][0]
anp.where(array == value)[0][0]
jednak unika brzydotę unboxing 1-elementu krotki.źródło
Alternatywą dla wyboru pierwszego elementu z np.where () jest użycie wyrażenia generatora wraz z wyliczeniem, takiego jak:
W przypadku tablicy dwuwymiarowej można zrobić:
Zaletą tego podejścia jest to, że przestaje on sprawdzać elementy tablicy po znalezieniu pierwszego dopasowania, podczas gdy np. Gdzie sprawdza wszystkie elementy pod kątem dopasowania. Wyrażenie generatora byłoby szybsze, gdyby dopasowanie było wczesne w tablicy.
źródło
None
jako rezerwowy, stałby sięnext((i for i, x_i in enumerate(x) if x_i == 2), None)
.Istnieje wiele operacji w NumPy, które mogą być połączone, aby to osiągnąć. Zwróci to indeksy elementów równe itemowi:
Następnie możesz wziąć pierwsze elementy list, aby uzyskać pojedynczy element.
źródło
Numpy_indexed pakiet (Zastrzeżenie, jestem jego autorem) zawiera wektorowy równowartość list.index dla numpy.ndarray; to jest:
To rozwiązanie ma wektoryzację wydajności, uogólnia do ndarrays i ma różne sposoby radzenia sobie z brakującymi wartościami.
źródło
Uwaga: dotyczy wersji Python 2.7
Do rozwiązania problemu możesz użyć funkcji lambda, która działa zarówno na tablicy NumPy, jak i na liście.
I możesz użyć
aby uzyskać pierwszy indeks filtrowanych elementów.
W przypadku python 3.6 użyj
zamiast
źródło
<filter object at 0x0000027535294D30>
Python 3 (testowany na Python 3.6.3). Być może aktualizacja dla Python 3?