Respostas:
Sim, aqui está a resposta dada a uma matriz NumPy,, array
e um valor ,, item
para procurar:
itemindex = numpy.where(array==item)
O resultado é uma tupla com primeiro todos os índices de linha, depois todos os índices de coluna.
Por exemplo, se uma matriz tiver duas dimensões e contiver seu item em dois locais,
array[itemindex[0][0]][itemindex[1][0]]
seria igual ao seu item e por isso seria
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
seria um pouco mais útil aqui:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
funciona em qualquer matriz, e retornará um tuplo de comprimento 3, quando utilizado em uma matriz 3D, etc.
Se você precisar do índice da primeira ocorrência de apenas um valor , poderá usar nonzero
(ou where
, o que equivale à mesma coisa neste 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 você precisar do primeiro índice de cada um dos muitos valores , obviamente poderá fazer o mesmo acima, repetidamente, mas há um truque que pode ser mais rápido. A seguir, são encontrados os índices do primeiro elemento de cada subsequência :
>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)
Observe que ele encontra o início das subsequências de 3s e das subsequências de 8s:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Portanto, é um pouco diferente de encontrar a primeira ocorrência de cada valor. No seu programa, você poderá trabalhar com uma versão classificada t
para obter o que deseja:
>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)
r_
é?
r_
concatena; ou, mais precisamente, converte objetos de fatia em concatenação ao longo de cada eixo. Eu poderia ter usado em seu hstack
lugar; isso pode ter sido menos confuso. Consulte a documentação para obter mais informações sobre r_
. Há também um c_
.
vals, locs = np.unique(t, return_index=True)
Você também pode converter uma matriz NumPy para listar no ar e obter seu índice. Por exemplo,
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
Ele imprimirá 1.
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
em uma matriz NumPy object
(ou qualquer coisa mais específica que seja apropriada) e apenas fazer find_arr[index_list]
.
Apenas para adicionar um desempenho muito útil numbaalternativa baseada em np.ndenumerate
para encontrar o primeiro índice:
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.
Isso é muito rápido e lida naturalmente com matrizes multidimensionais :
>>> 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,)
Isso pode ser muito mais rápido (porque está causando um curto-circuito na operação) do que qualquer abordagem usando np.where
ou np.nonzero
.
No entanto np.argwhere
, também poderia lidar graciosamente com arrays multidimensionais (você precisará lançá-lo manualmente para uma tupla e ele não está em curto-circuito), mas que iria falhar se nenhuma correspondência for encontrada:
>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)
@njit
é uma abreviação de jit(nopython=True)
ie a função será totalmente compilada em tempo real no momento da primeira execução, para que as chamadas do interpretador Python sejam completamente removidas.
Se você usar isso como um índice em outra coisa, poderá usar índices booleanos se as matrizes forem transmissíveis; você não precisa de índices explícitos. A maneira mais simples e absoluta de fazer isso é simplesmente indexar com base em um valor verdadeiro.
other_array[first_array == item]
Qualquer operação booleana funciona:
a = numpy.arange(100)
other_array[first_array > 50]
O método diferente de zero também aceita booleanos:
index = numpy.nonzero(first_array == item)[0][0]
Os dois zeros são para a tupla de índices (assumindo que first_array é 1D) e, em seguida, o primeiro item na matriz de índices.
l.index(x)
retorna o menor i, de modo que i é o índice da primeira ocorrência de x na lista.
Pode-se supor com segurança que a index()
função no Python é implementada para que pare após encontrar a primeira correspondência, e isso resulta em um desempenho médio ideal.
Para localizar um elemento que para após a primeira correspondência em uma matriz NumPy, use um iterador ( ndenumerate ).
In [67]: l=range(100)
In [68]: l.index(2)
Out[68]: 2
Matriz NumPy:
In [69]: a = np.arange(100)
In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2))
Out[70]: (2L,)
Observe que ambos os métodos index()
e next
retornam um erro se o elemento não for encontrado. Com next
, pode-se usar um segundo argumento para retornar um valor especial caso o elemento não seja encontrado, por exemplo
In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)
Existem outras funções no NumPy ( argmax
, where
e nonzero
) que pode ser usado para encontrar um elemento em uma matriz, mas todos eles têm a desvantagem de passar por todo o conjunto em busca de todas as ocorrências, portanto, não sendo otimizado para encontrar o primeiro elemento. Observe também isso where
e nonzero
retorne matrizes, portanto, você precisa selecionar o primeiro elemento para obter o índice.
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),)
Apenas verificando se, para matrizes grandes, a solução usando um iterador é mais rápida quando o item pesquisado está no início da matriz (usando %timeit
no 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
Este é um problema aberto do NumPy GitHub .
Veja também: Numpy: encontre o primeiro índice de valor rapidamente
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
funciona? Se você está se perguntando por que é 1000 vezes mais lento - é porque os loops python sobre matrizes numpy são notoriamente lentos.
argmax
e where
são muito mais rápidos neste caso (procurou elemento no final do array)
Para matrizes unidimensionais classificadas , seria muito mais simples e eficiente O (log (n)) usar numpy.searchsorted que retorna um número inteiro NumPy (posição). Por exemplo,
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
Apenas verifique se a matriz já está classificada
Verifique também se o índice retornado i realmente contém o elemento pesquisado, já que o principal objetivo do searchsorted é encontrar índices onde os elementos devem ser inseridos para manter a ordem.
if arr[i] == 3:
print("present")
else:
print("not present")
Para indexar em qualquer critério, você pode fazer algo como o seguinte:
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
E aqui está uma função rápida para fazer o que list.index () faz, exceto que não gera uma exceção se não for encontrada. Cuidado - isso provavelmente é muito lento em matrizes grandes. Provavelmente, você pode aplicar o patch em matrizes se preferir usá-lo como método.
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]
Uma alternativa para selecionar o primeiro elemento de np.where () é usar uma expressão geradora junto com enumerate, como:
>>> 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
Para uma matriz bidimensional, seria necessário:
>>> 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)
A vantagem dessa abordagem é que ela para de verificar os elementos da matriz após a primeira correspondência ser encontrada, enquanto o np.where verifica todos os elementos em busca de uma correspondência. Uma expressão de gerador seria mais rápida se houver correspondência no início da matriz.
None
como um substituto, ele se tornaria next((i for i, x_i in enumerate(x) if x_i == 2), None)
.
Existem muitas operações no NumPy que talvez possam ser reunidas para isso. Isso retornará índices de elementos iguais ao item:
numpy.nonzero(array - item)
Você pode pegar os primeiros elementos das listas para obter um único elemento.
O pacote numpy_indexed (exoneração de responsabilidade, eu sou seu autor) contém um equivalente vetorizado de list.index para numpy.ndarray; isso é:
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]
Essa solução tem desempenho vetorizado, generaliza para ndarrays e possui várias maneiras de lidar com valores ausentes.
Nota: isto é para a versão python 2.7
Você pode usar uma função lambda para lidar com o problema e funciona tanto na matriz quanto na lista 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 você pode usar
result[0]
para obter o primeiro índice dos elementos filtrados.
Para python 3.6, use
list(result)
ao invés de
result
<filter object at 0x0000027535294D30>
Python 3 (testado no Python 3.6.3). Talvez atualizar para Python 3?