NumPy propõe uma maneira de obter o índice do valor máximo de uma matriz via np.argmax
.
Gostaria de algo semelhante, mas retornando os índices dos N
valores máximos.
Por exemplo, se tiver uma matriz, [1, 3, 2, 4, 5]
, function(array, n=3)
iria retornar os índices [4, 3, 1]
, que correspondem aos elementos [5, 4, 3]
.
python
numpy
max
numpy-ndarray
Alexis Métaireau
fonte
fonte
array([5, 1, 5, 5, 2, 3, 2, 4, 1, 5])
, comn= 3
? Qual de todas as alternativas, como[0, 2, 3]
,[0, 2, 9]
,...
seria o correto? Por favor, elabore mais sobre seus requisitos específicos. Obrigadoargsort
pode ser uma alternativa viável se você não se importar com a ordem dos indeces retornados. Veja minha resposta abaixo.Respostas:
O mais simples que pude apresentar é:
Isso envolve uma classificação completa da matriz. Gostaria de saber se
numpy
fornece uma maneira interna de fazer uma classificação parcial; até agora não consegui encontrar um.Se esta solução for muito lenta (especialmente para pequenas
n
), pode valer a pena codificar algo no Cython .fonte
arr.argsort()[-1:-4:-1]
? Eu tentei isso no intérprete e aparece com o mesmo resultado, mas estou me perguntando se não está quebrado por algum exemplo.np.argsort(-arr)[:3]
, o que eu acho mais legível e direto ao ponto.arr.argsort()[::-1][:n]
é melhor porque retorna vazio para emn=0
vez de toda a matrizAs versões mais recentes do NumPy (1.8 e superior) têm uma função chamada
argpartition
para isso. Para obter os índices dos quatro maiores elementos, façaDiferentemente
argsort
, essa função é executada em tempo linear no pior dos casos, mas os índices retornados não são classificados, como pode ser visto no resultado da avaliaçãoa[ind]
. Se você precisar também, classifique-os depois:Obter os elementos top- k em ordem classificada dessa maneira leva tempo O ( n + k log k ).
fonte
argpartition
é executado em tempo linear, O (n), usando o algoritmo introselecionado . A classificação subsequente manipula apenas os elementos k, para que seja executado em O (k log k).np.argpartition
e seu algoritmo irmãnp.partition
trabalho, há uma explicação mais detalhada na questão ligada: stackoverflow.com/questions/10337533/...a=np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
porque as listas normal do Python não suportam indexação por listas, ao contrárionp.array
np.argpartition
usa umaxis
argumento opcional . Para encontrar os índices dos n principais valores para cada linha:np.argpartition(a, -n, axis=1)[-n:]
Mais simples ainda:
onde n é o número de valores máximos.
fonte
arr[arr.argsort()[-n:]]
em vez de negar a matriz, basta levar uma fatia dos últimos n elementosUsar:
Para listas regulares de Python:
Se você usa o Python 2, use em
xrange
vez derange
.Fonte: heapq - Algoritmo de fila da pilha
fonte
heapq.nlargest(3, xrange(len(a)), a.take)
. Para listas Python, podemos usar em.__getitem__
vez de.take
.A
em geral:heapq.nlargest(3, range(len(A.ravel())), A.ravel().take)
. (Espero que isso funcione apenas emravel vs flatten
Se estiver trabalhando com uma matriz multidimensional, será necessário achatar e desvendar os índices:
Por exemplo:
fonte
Se você não se importa com a ordem dos K-ésimas maiores elementos que pode usar
argpartition
, deve ter um desempenho melhor do que uma classificação completaargsort
.Os créditos vão para esta pergunta .
Fiz alguns testes e parece ter um
argpartition
desempenho superior àargsort
medida que o tamanho da matriz e o valor de K aumentam.fonte
Para matrizes multidimensionais, você pode usar a
axis
palavra - chave para aplicar o particionamento ao longo do eixo esperado.E para pegar os itens:
Mas observe que isso não retornará um resultado classificado. Nesse caso, você pode usar
np.argsort()
ao longo do eixo pretendido:Aqui está um exemplo:
fonte
np.take_along_axis
(o que provavelmente não existia quando você respondeu a esta pergunta)Isso será mais rápido que uma classificação completa, dependendo do tamanho da sua matriz original e do tamanho da sua seleção:
Evidentemente, isso envolve adulterar sua matriz original. Que você pode corrigir (se necessário) fazendo uma cópia ou substituindo novamente os valores originais. ... o que for mais barato para o seu caso de uso.
fonte
argmax(.)
também não ambígua. (IMHO tenta seguir algum tipo de lógica de curto-circuito, mas infelizmente falha em fornecer um comportamento universalmente aceitável). ObrigadoO método
np.argpartition
retorna apenas os k maiores índices, executa uma classificação local e é mais rápido quenp.argsort
(executando uma classificação completa) quando a matriz é bastante grande. Mas os índices retornados NÃO estão em ordem crescente / decrescente . Digamos com um exemplo:Podemos ver que, se você deseja uma ordem ascendente estrita dos principais k índices,
np.argpartition
não retornará o que deseja.Além de fazer uma classificação manualmente após o np.argpartition, minha solução é usar o PyTorch,
torch.topk
uma ferramenta para construção de redes neurais, fornecendo APIs do tipo NumPy com suporte a CPU e GPU. É tão rápido quanto o NumPy com MKL e oferece um aumento de GPU se você precisar de grandes cálculos de matriz / vetor.O código estrito de subida / descida dos índices principais k será:
Observe que
torch.topk
aceita um tensor da tocha e retorna os valores de k top e os índices de k top no tipotorch.Tensor
. Semelhante ao np, o torch.topk também aceita um argumento de eixo para que você possa manipular matrizes / tensores multidimensionais.fonte
Usar:
Agora a
result
lista conterá N tuplas (index
,value
) ondevalue
é maximizada.fonte
Usar:
Também funciona com matrizes 2D. Por exemplo,
fonte
bottleneck
possui uma função de classificação parcial, se a despesa de classificar toda a matriz apenas para obter os N maiores valores for muito grande.Não sei nada sobre este módulo; Eu apenas pesquisei no Google
numpy partial sort
.fonte
A seguir, é uma maneira muito fácil de ver o máximo de elementos e suas posições. Aqui
axis
está o domínio;axis
= 0 significa o número máximo em colunas eaxis
= 1 significa o número máximo em linhas para o caso 2D. E para dimensões mais altas depende de você.fonte
Eu achei mais intuitivo de usar
np.unique
.A idéia é que o método exclusivo retorne os índices dos valores de entrada. Então, a partir do valor único máximo e das indicações, a posição dos valores originais pode ser recriada.
fonte
Eu acho que a maneira mais eficiente em termos de tempo é iterar manualmente através da matriz e manter uma pilha mínima de tamanho k, como outras pessoas mencionaram.
E também proponho uma abordagem de força bruta:
Defina o maior elemento para um grande valor negativo depois de usar argmax para obter seu índice. E então a próxima chamada de argmax retornará o segundo maior elemento. E você pode registrar o valor original desses elementos e recuperá-los, se desejar.
fonte
Este código funciona para uma matriz matricial numpy:
Isso produz uma indexação de matriz n_largest true-false que também funciona para extrair n_largest elementos de uma matriz de matriz
fonte