Odpowiedzi:
Tak, oto odpowiedź na podaną tablicę NumPy array
i wartość item
, aby wyszukać:
itemindex = numpy.where(array==item)
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
array[itemindex[0][0]][itemindex[1][0]]
będzie równa twojemu przedmiotowi i tak też będzie
array[itemindex[0][1]][itemindex[1][1]]
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
(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 :
>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)
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:
>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)
r_
to jest?
r_
konkatenuje; lub, dokładniej, przekłada obiekty wycięte na konkatenację wzdłuż każdej osi. Mógłbym hstack
zamiast tego użyć ; to mogło być mniej mylące. Zobacz dokumentację uzyskać więcej informacji na temat r_
. 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,
l = [1,2,3,4,5] # Python list
a = numpy.array(l) # NumPy array
i = a.tolist().index(2) # i will return index of 2
print i
Wydrukuje 1.
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
go na tablicę NumPy object
(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:
from numba import njit
import numpy as np
@njit
def 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 :
>>> arr1 = np.ones((100, 100, 100))
>>> arr1[2, 2, 2] = 2
>>> index(arr1, 2)
(2, 2, 2)
>>> arr2 = np.ones(20)
>>> arr2[5] = 2
>>> index(arr2, 2)
(5,)
Może to być znacznie szybsze (ponieważ powoduje to zwarcie operacji) niż jakakolwiek metoda wykorzystująca np.where
lub np.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:
>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)
@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.
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 next
zwracają błąd, jeśli element nie zostanie znaleziony. Za next
pomocą 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
, where
i 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 where
i nonzero
zwracaj tablice, więc musisz wybrać pierwszy element, aby uzyskać indeks.
In [71]: np.argmax(a==2)
Out[71]: 2
In [72]: np.where(a==2)
Out[72]: (array([2], dtype=int64),)
In [73]: np.nonzero(a==2)
Out[73]: (array([2], dtype=int64),)
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):
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
To jest otwarty problem NumPy GitHub .
Zobacz także: Numpy: szybko znajdź pierwszy indeks wartości
%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
i where
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,
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")
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 >= 120
In [5]: pts = hsplit(locs, len(locs[0]))
In [6]: for pt in pts:
.....: print(', '.join(str(p[0]) for p in pt))
4, 4, 0
4, 4, 1
4, 4, 2
4, 4, 3
4, 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:
pass
else:
for i, subarray in enumerate(ndarray):
try:
return [i] + ndindex(subarray, item)
except:
pass
In [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.
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:
numpy.nonzero(array - item)
Następnie możesz wziąć pierwsze elementy list, aby uzyskać pojedynczy element.
Numpy_indexed pakiet (Zastrzeżenie, jestem jego autorem) zawiera wektorowy równowartość list.index dla numpy.ndarray; to jest:
sequence_of_arrays = [[0, 1], [1, 2], [-5, 0]]
arrays_to_query = [[-5, 0], [1, 0]]
import numpy_indexed as npi
idx = npi.indices(sequence_of_arrays, arrays_to_query, missing=-1)
print(idx) # [2, -1]
To rozwiązanie ma wektoryzację wydajności, uogólnia do ndarrays i ma różne sposoby radzenia sobie z brakującymi wartościami.
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.
your_list = [11, 22, 23, 44, 55]
result = filter(lambda x:your_list[x]>30, range(len(your_list)))
#result: [3, 4]
import numpy as np
your_numpy_array = np.array([11, 22, 23, 44, 55])
result = filter(lambda x:your_numpy_array [x]>30, range(len(your_list)))
#result: [3, 4]
I możesz użyć
result[0]
aby uzyskać pierwszy indeks filtrowanych elementów.
W przypadku python 3.6 użyj
list(result)
zamiast
result
<filter object at 0x0000027535294D30>
Python 3 (testowany na Python 3.6.3). Być może aktualizacja dla Python 3?