Se você está procurando a primeira linha na qual um item existe na primeira coluna, isso funciona (embora ele irá lançar um erro índice se inexistente)rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
BrT
29
E se você deseja que ele pare de pesquisar depois de encontrar o primeiro valor? Eu não acho que () é comparável a find ()
np.argwhereseria um pouco mais útil aqui:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
Eric
3
Vale a pena notar que esta resposta assume que a matriz é 2D. wherefunciona em qualquer matriz, e retornará um tuplo de comprimento 3, quando utilizado em uma matriz 3D, etc.
P. Camilleri
70
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 :
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 tpara obter o que deseja:
>>> st = sorted(t)>>> nonzero(r_[1, diff(st)[:-1]])(array([0,3,5,7]),)
@ Geoff, r_concatena; ou, mais precisamente, converte objetos de fatia em concatenação ao longo de cada eixo. Eu poderia ter usado em seu hstacklugar; isso pode ter sido menos confuso. Consulte a documentação para obter mais informações sobre r_. Há também um c_.
Vebjorn Ljosa 24/03
+1, bom! (vs NP.where) sua solução é muito mais simples (e provavelmente mais rápida) no caso em que é apenas a primeira ocorrência de um determinado valor em uma matriz 1D que precisamos
doug
3
O último caso (para encontrar o primeiro índice de todos os valores) é dada porvals, locs = np.unique(t, return_index=True)
askewchan
@askewchan sua versão é funcionalmente equivalente, mas muito, muito, muito mais lenta
Jivan
50
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 2print i
Pode ser que a biblioteca tenha mudado desde que foi escrita pela primeira vez. Mas essa foi a primeira solução que funcionou para mim.
Amracel 03/04/19
1
Eu fiz bom uso deste encontrar vários valores em uma lista usando uma compreensão da lista:[find_list.index(index_list[i]) for i in range(len(index_list))]
Matt Wenham
1
@ MattWenham Se for grande o suficiente, você pode converter o seu find_listem uma matriz NumPy object(ou qualquer coisa mais específica que seja apropriada) e apenas fazer find_arr[index_list].
Narfanar 30/04/19
Totalmente fora de tópico, mas é a primeira vez que vejo a frase "no ar" - o que mais vi, em seu lugar, é provavelmente "on the fly".
flow2k
18
Apenas para adicionar um desempenho muito útil numbaalternativa baseada em np.ndenumeratepara encontrar o primeiro índice:
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.
Isso é muito rápido e lida naturalmente com matrizes multidimensionais :
Isso pode ser muito mais rápido (porque está causando um curto-circuito na operação) do que qualquer abordagem usando np.whereou 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:
@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.
22320 bartolo-otrit #
14
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 nextretornam 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, wheree 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 wheree nonzeroretorne matrizes, portanto, você precisa selecionar o primeiro elemento para obter o índice.
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 %timeitno 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
Acho que você também deve incluir um momento para o pior caso (último elemento), apenas para que os leitores saibam o que acontece com eles no pior caso, quando usam sua abordagem.
MSeifert
@MSeifert eu não posso obter um tempo razoável para a solução pior caso iterador - eu vou apagar esta resposta até eu descobrir o que há de errado com ele
user2314737
1
não %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.
MSeifert
@MSeifert não, eu não sabia disso, mas eu também estou intrigado com o fato de que argmaxe wheresão muito mais rápidos neste caso (procurou elemento no final do array)
user2314737
Eles devem ser tão rápidos como se o elemento estivesse no começo. Eles sempre processam toda a matriz para sempre levar o mesmo tempo (pelo menos deveriam).
MSeifert
9
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")
searchsorted não é nlog (n), uma vez que não classifica a matriz antes da pesquisa, assume que a matriz de argumentos já está classificada. confira a documentação de numpy.searchsorted (link acima)
Alok Nayak
6
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 >= 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
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:passelse:for i, subarray in enumerate(ndarray):try:return[i]+ ndindex(subarray, item)except:passIn[1]: ndindex(x,103)Out[1]:[4,0,3]
Para arrays 1D, eu recomendo np.flatnonzero(array == value)[0], o que equivale a ambos np.nonzero(array == value)[0][0]e np.where(array == value)[0][0], mas evita a feiúra do unboxing a 1 elemento de tupla.
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.
Caso não haja uma correspondência na matriz, esse método também permite especificar convenientemente um valor de fallback. Se o primeiro exemplo retornasse Nonecomo um substituto, ele se tornaria next((i for i, x_i in enumerate(x) if x_i == 2), None).
Erlend Magnus Viggen
4
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.
Respostas:
Sim, aqui está a resposta dada a uma matriz NumPy,,
array
e um valor ,,item
para procurar: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,
seria igual ao seu item e por isso seria
numpy.where
fonte
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
(ouwhere
, o que equivale à mesma coisa neste caso):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 :
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:fonte
r_
é?r_
concatena; ou, mais precisamente, converte objetos de fatia em concatenação ao longo de cada eixo. Eu poderia ter usado em seuhstack
lugar; isso pode ter sido menos confuso. Consulte a documentação para obter mais informações sobrer_
. Há também umc_
.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,
Ele imprimirá 1.
fonte
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
em uma matriz NumPyobject
(ou qualquer coisa mais específica que seja apropriada) e apenas fazerfind_arr[index_list]
.Apenas para adicionar um desempenho muito útil numbaalternativa baseada em
np.ndenumerate
para encontrar o primeiro índice:Isso é muito rápido e lida naturalmente com matrizes multidimensionais :
Isso pode ser muito mais rápido (porque está causando um curto-circuito na operação) do que qualquer abordagem usando
np.where
ounp.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:fonte
@njit
é uma abreviação dejit(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.
Qualquer operação booleana funciona:
O método diferente de zero também aceita booleanos:
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.
fonte
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 ).
Matriz NumPy:
Observe que ambos os métodos
index()
enext
retornam um erro se o elemento não for encontrado. Comnext
, pode-se usar um segundo argumento para retornar um valor especial caso o elemento não seja encontrado, por exemploExistem outras funções no NumPy (
argmax
,where
enonzero
) 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 issowhere
enonzero
retorne matrizes, portanto, você precisa selecionar o primeiro elemento para obter o índice.Comparação de tempo
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):Este é um problema aberto do NumPy GitHub .
Veja também: Numpy: encontre o primeiro índice de valor rapidamente
fonte
%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
ewhere
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,
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.
fonte
Para indexar em qualquer critério, você pode fazer algo como o seguinte:
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.
fonte
Para arrays 1D, eu recomendo
np.flatnonzero(array == value)[0]
, o que equivale a ambosnp.nonzero(array == value)[0][0]
enp.where(array == value)[0][0]
, mas evita a feiúra do unboxing a 1 elemento de tupla.fonte
Uma alternativa para selecionar o primeiro elemento de np.where () é usar uma expressão geradora junto com enumerate, como:
Para uma matriz bidimensional, seria necessário:
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.
fonte
None
como um substituto, ele se tornarianext((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:
Você pode pegar os primeiros elementos das listas para obter um único elemento.
fonte
O pacote numpy_indexed (exoneração de responsabilidade, eu sou seu autor) contém um equivalente vetorizado de list.index para numpy.ndarray; isso é:
Essa solução tem desempenho vetorizado, generaliza para ndarrays e possui várias maneiras de lidar com valores ausentes.
fonte
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.
E você pode usar
para obter o primeiro índice dos elementos filtrados.
Para python 3.6, use
ao invés de
fonte
<filter object at 0x0000027535294D30>
Python 3 (testado no Python 3.6.3). Talvez atualizar para Python 3?