Risposte:
Sì, ecco la risposta fornita da un array NumPy array
e da un valore item
per cercare:
itemindex = numpy.where(array==item)
Il risultato è una tupla con prima tutti gli indici di riga, quindi tutti gli indici di colonna.
Ad esempio, se un array ha due dimensioni e conteneva il tuo articolo in due posizioni, allora
array[itemindex[0][0]][itemindex[1][0]]
sarebbe uguale al tuo articolo e così sarebbe
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
sarebbe leggermente più utile qui:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
funziona su qualsiasi array e restituirà una tupla di lunghezza 3 se utilizzato su un array 3D, ecc.
Se hai bisogno dell'indice della prima occorrenza di un solo valore , puoi usare nonzero
(o where
, che equivale alla stessa cosa in questo caso):
>>> 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
Se hai bisogno del primo indice di ciascuno di molti valori , puoi ovviamente fare lo stesso come sopra ripetutamente, ma c'è un trucco che potrebbe essere più veloce. Di seguito sono riportati gli indici del primo elemento di ogni sottosequenza :
>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)
Si noti che trova l'inizio sia della sottosequenza di 3 secondi sia delle sottosequenze di 8 secondi:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Quindi è leggermente diverso dal trovare la prima occorrenza di ciascun valore. Nel tuo programma, potresti essere in grado di lavorare con una versione ordinata di t
per ottenere ciò che desideri:
>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)
r_
?
r_
concatenati; o, più precisamente, traduce gli oggetti fetta in concatenazione lungo ciascun asse. Avrei potuto usare hstack
invece; che potrebbe essere stato meno confuso. Vedere la documentazione per ulteriori informazioni su r_
. C'è anche un c_
.
vals, locs = np.unique(t, return_index=True)
Puoi anche convertire un array NumPy in un elenco in aria e ottenere il suo indice. Per esempio,
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
Stampa 1.
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
in un array NumPy di object
(o qualcosa di più specifico che è appropriato) e semplicemente fare find_arr[index_list]
.
Solo per aggiungere un molto performante e utile numbaalternativa basata su np.ndenumerate
per trovare il primo indice:
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.
Questo è piuttosto veloce e si occupa naturalmente di array multidimensionali :
>>> 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,)
Questo può essere molto più veloce (perché sta cortocircuitando l'operazione) rispetto a qualsiasi approccio che utilizza np.where
o np.nonzero
.
Tuttavia, np.argwhere
potrebbe anche gestire con grazia array multidimensionali (è necessario eseguirne il cast manualmente su una tupla e non è in cortocircuito) ma fallirebbe se non viene trovata alcuna corrispondenza:
>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)
@njit
è una scorciatoia di jit(nopython=True)
cioè la funzione sarà completamente compilata al volo al momento della prima esecuzione in modo che le chiamate dell'interprete Python vengano completamente rimosse.
Se lo utilizzerai come indice in qualcos'altro, puoi utilizzare gli indici booleani se le matrici sono trasmissibili; non hai bisogno di indici espliciti. Il modo più semplice per farlo è semplicemente indicizzare in base a un valore di verità.
other_array[first_array == item]
Qualsiasi operazione booleana funziona:
a = numpy.arange(100)
other_array[first_array > 50]
Anche il metodo diverso da zero prende i booleani:
index = numpy.nonzero(first_array == item)[0][0]
I due zeri sono per la tupla di indici (supponendo che first_array sia 1D) e quindi il primo elemento nella matrice di indici.
l.index(x)
restituisce il più piccolo i tale che io sia l'indice della prima occorrenza di x nell'elenco.
Si può tranquillamente presumere che la index()
funzione in Python sia implementata in modo che si arresti dopo aver trovato la prima corrispondenza, e ciò si traduce in una prestazione media ottimale.
Per trovare un elemento che si interrompe dopo la prima corrispondenza in un array NumPy, utilizzare un iteratore ( ndenumerato ).
In [67]: l=range(100)
In [68]: l.index(2)
Out[68]: 2
Matrice NumPy:
In [69]: a = np.arange(100)
In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2))
Out[70]: (2L,)
Si noti che entrambi i metodi index()
e next
restituiscono un errore se l'elemento non viene trovato. Con next
, si può usare un secondo argomento per restituire un valore speciale nel caso in cui l'elemento non venga trovato, ad es
In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)
Ci sono altre funzioni in NumPy ( argmax
, where
e nonzero
) che può essere utilizzato per trovare un elemento in un array, ma tutti presentano l'inconveniente di passare attraverso l'intero array cercando tutte le occorrenze, quindi non ottimizzata per reperire il primo elemento. Notare anche che where
e nonzero
restituire le matrici, quindi è necessario selezionare il primo elemento per ottenere l'indice.
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),)
Basta verificare che per array di grandi dimensioni la soluzione utilizzando un iteratore sia più veloce quando l'elemento cercato è all'inizio dell'array (utilizzando %timeit
nella shell 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
Questo è un problema di NumPy GitHub aperto .
Vedi anche: Numpy: trova velocemente il primo indice di valore
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
funziona? Se ti stai chiedendo perché è 1000 volte più lento - è perché i loop di pitone su array intorpiditi sono notoriamente lenti.
argmax
e where
sono molto più veloci in questo caso (cercato elemento alla fine di array)
Per le matrici ordinate unidimensionali , sarebbe molto più semplice ed efficiente O (log (n)) utilizzare numpy.searchsorted che restituisce un numero intero NumPy (posizione). Per esempio,
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
Assicurati solo che l'array sia già ordinato
Controlla anche se l'indice restituito contiene effettivamente l'elemento cercato, poiché l'obiettivo principale di searchsorted è trovare indici in cui gli elementi devono essere inseriti per mantenere l'ordine.
if arr[i] == 3:
print("present")
else:
print("not present")
Per indicizzare su qualsiasi criterio, puoi fare qualcosa di simile al seguente:
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
Ed ecco una rapida funzione per fare ciò che fa list.index (), tranne che non genera un'eccezione se non viene trovata. Attenzione: questo è probabilmente molto lento su array di grandi dimensioni. Probabilmente puoi applicare questa patch alle matrici se preferisci usarla come metodo.
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]
Un'alternativa alla selezione del primo elemento da np.where () consiste nell'utilizzare un'espressione di generatore insieme a enumerate, come:
>>> 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
Per un array bidimensionale uno dovrebbe fare:
>>> 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)
Il vantaggio di questo approccio è che smette di controllare gli elementi dell'array dopo aver trovato la prima corrispondenza, mentre np.where controlla tutti gli elementi per una corrispondenza. Un'espressione del generatore sarebbe più veloce se c'è una corrispondenza all'inizio dell'array.
None
come fallback, lo sarebbe next((i for i, x_i in enumerate(x) if x_i == 2), None)
.
Ci sono molte operazioni in NumPy che potrebbero forse essere messe insieme per raggiungere questo obiettivo. Ciò restituirà indici di elementi uguali all'elemento:
numpy.nonzero(array - item)
È quindi possibile prendere i primi elementi degli elenchi per ottenere un singolo elemento.
Il pacchetto numpy_indexed (dichiarazione di non responsabilità, sono il suo autore) contiene un equivalente vettoriale di list.index per numpy.ndarray; questo è:
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]
Questa soluzione ha prestazioni vettoriali, generalizza a ndarrays e ha vari modi di gestire i valori mancanti.
Nota: questo è per la versione 2.7 di Python
È possibile utilizzare una funzione lambda per gestire il problema e funziona sia sull'array che sull'elenco NumPy.
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]
E puoi usare
result[0]
per ottenere il primo indice degli elementi filtrati.
Per python 3.6, utilizzare
list(result)
invece di
result
<filter object at 0x0000027535294D30>
Python 3 (testato su Python 3.6.3). Forse l'aggiornamento per Python 3?