Compreendendo numpy.where

Oct 19 2020

Eu quero obter o primeiro índice do elemento de matriz numpy que é maior do que algum elemento específico dessa mesma matriz. Eu tentei seguir:

>>> Q5=[[1,2,3],[4,5,6]]
>>> Q5 = np.array(Q5)
>>> Q5[0][Q5>Q5[0,0]]
array([2, 3])
>>> np.where(Q5[0]>Q5[0,0])
(array([1, 2], dtype=int32),)
>>> np.where(Q5[0]>Q5[0,0])[0][0]
1

T1. Está acima a maneira correta de obter o primeiro índice de um elemento em Q5[0]maior que Q5[0,0]?

Estou mais preocupado em np.where(Q5[0]>Q5[0,0])retornar a tupla (array([1, 2], dtype=int32),)e, portanto, exigir que eu duplique o índice [0][0]no final de np.where(Q5[0]>Q5[0,0])[0][0].

2º trimestre. Por que essa tupla de retorno, mas abaixo, retorna a matriz numpy adequada?

>>> np.where(Q5[0]>Q5[0,0],Q5[0],-1)
array([-1,  2,  3])

Para que eu possa indexar diretamente:

>>> np.where(Q5[0]>Q5[0,0],Q5[0],-1)[1]
2

Respostas

hpaulj Oct 19 2020 at 21:42
In [58]: A = np.arange(1,10).reshape(3,3)
In [59]: A.shape
Out[59]: (3, 3)
In [60]: A
Out[60]: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

np.wherecom apenas a condição é realmente np.nonzero.

Gere uma matriz booleana:

In [63]: A==6
Out[63]: 
array([[False, False, False],
       [False, False,  True],
       [False, False, False]])

Descubra onde isso é verdade:

In [64]: np.nonzero(A==6)
Out[64]: (array([1]), array([2]))

O resultado é uma tupla, um elemento por dimensão da condição. Cada elemento é uma matriz de indexação, juntos eles definem a localização do (s) True (s)

Outro teste com vários True

In [65]: (A%3)==1
Out[65]: 
array([[ True, False, False],
       [ True, False, False],
       [ True, False, False]])
In [66]: np.nonzero((A%3)==1)
Out[66]: (array([0, 1, 2]), array([0, 0, 0]))

Usando a tupla para indexar a matriz original:

In [67]: A[np.nonzero((A%3)==1)]
Out[67]: array([1, 4, 7])

Usando o argumento 3 wherepara criar uma nova matriz com uma mistura de valores de AeA+10

In [68]: np.where((A%3)==1,A+10, A)
Out[68]: 
array([[11,  2,  3],
       [14,  5,  6],
       [17,  8,  9]])

Se a condição tiver múltiplos True, nonzeronão é a ferramenta de teste para encontrar o "primeiro", já que necessariamente encontra todos.

A tupla diferente de zero pode ser transformada em uma matriz 2d com a transpose. Na verdade, pode ser mais fácil obter o "primeiro" desta matriz:

In [73]: np.argwhere((A%3)==1)
Out[73]: 
array([[0, 0],
       [1, 0],
       [2, 0]])

Você está olhando em uma matriz 1d, uma linha de A:

In [77]: A[0]>A[0,0]
Out[77]: array([False,  True,  True])
In [78]: np.nonzero(A[0]>A[0,0])
Out[78]: (array([1, 2]),)            # 1 element tuple
In [79]: np.argwhere(A[0]>A[0,0])
Out[79]: 
array([[1],
       [2]])
In [81]: np.where(A[0]>A[0,0], 100, 0)     # 3 argument where
Out[81]: array([  0, 100, 100])

Portanto, se você estiver pesquisando um array 1d ou 2d (ou 3 ou 4), nonzeroretorna uma tupla com um elemento do array por dimensão. Dessa forma, ele sempre pode ser usado para indexar uma matriz de tamanho semelhante. A tupla 1d pode parecer redundante, mas é consistente com outros resultados dimensionais.

Ao tentar entender operações como essa, leia os documentos com atenção e observe as etapas individuais. Aqui, examino a matriz condicional, o nonzeroresultado e seus vários usos.

AsafH Oct 19 2020 at 22:05

numpy.where () é como um loop for com um if.

numpy.where(condition, values, new_value)

condição - assim como as condições if.
valores - os valores para iterar em
new_value - se a condição for verdadeira para um valor , ele mudará para new_value


Se quisermos escrevê-lo para um array unidimensional, ele deve ser parecido com isto:
[xv if c else yv 
for c, xv, yv in zip(condition, x, y)]

Exemplo:

>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.where(a < 5, a, 10*a)
array([ 0,  1,  2,  3,  4, 50, 60, 70, 80, 90])

Primeiro, criamos uma matriz com números de 0 a 9 (0, 1, 2 ... 7, 8, 9)
e, em seguida, verificamos todos os valores na matriz que são maiores de 5 e multiplicamos seus valores por 10.
Então agora todos os valores na matriz que são menores que 5 permaneceram os mesmos e todos os valores maiores multiplicados por 10

wwii Oct 19 2020 at 21:41

Usar argmaxcom um array booleano fornecerá o índice do primeiro True.

In [54]: q
Out[54]: 
array([[1, 2, 3],
       [4, 5, 6]])

In [55]: q > q[0,0]
Out[55]: 
array([[False,  True,  True],
       [ True,  True,  True]], dtype=bool)

argmax pode receber um argumento de eixo / dimensão.

In [56]: np.argmax(q > q[0,0], 0)
Out[56]: array([1, 0, 0], dtype=int64)

Isso diz que o primeiro True é o índice um para a coluna zero e o índice zero para as colunas um e dois.

In [57]: np.argmax(q > q[0,0], 1)
Out[57]: array([1, 0], dtype=int64)

Isso diz que o primeiro True é o índice um para a linha zero e o índice zero para a linha um.


T1. A maneira correta de obter o primeiro índice de um elemento em Q5 [0] é maior que Q5 [0,0]?

Não, eu usaria argmaxcom 1para o axisargumento e, em seguida, selecionaria o primeiro item desse resultado.

2º trimestre. Por que essa tupla de retorno

Você disse a ele para retornar -1para valores False e retornar Q5[0]itens para valores True.

Q2 ... mas abaixo retorna a matriz numpy adequada?

Você teve sorte e escolheu o índice correto.