numpy substituir valores negativos na matriz

88

Alguém pode aconselhar uma maneira simples de substituir todos os valores negativos em uma matriz por 0?

Estou tendo um bloco completo sobre como fazer isso usando uma matriz numpy

por exemplo

a = array([1, 2, 3, -4, 5])

eu preciso voltar

[1, 2, 3, 0, 5]

a < 0 dá:

[False, False, False, True, False]

É aqui que estou preso - como usar este array para modificar o array original

bph
fonte

Respostas:

135

Você está no meio do caminho. Experimentar:

In [4]: a[a < 0] = 0

In [5]: a
Out[5]: array([1, 2, 3, 0, 5])
NPE
fonte
89

Experimente numpy.clip:

>>> import numpy
>>> a = numpy.arange(-10, 10)
>>> a
array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,
         3,   4,   5,   6,   7,   8,   9])
>>> a.clip(0, 10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Você pode prender apenas a metade inferior com clip(0).

>>> a = numpy.array([1, 2, 3, -4, 5])
>>> a.clip(0)
array([1, 2, 3, 0, 5])

Você pode prender apenas a metade superior com clip(max=n). (Isso é muito melhor do que minha sugestão anterior, que envolvia passar NaNpara o primeiro parâmetro e usar outpara forçar o tipo.):

>>> a.clip(max=2)
array([ 1,  2,  2, -4,  2])

Outra abordagem interessante é usar where:

>>> numpy.where(a <= 2, a, 2)
array([ 1,  2,  2, -4,  2])

Finalmente, considere a resposta de aix . Eu prefiro clippara operações simples porque é autodocumentado, mas sua resposta é preferível para operações mais complexas.

remetente
fonte
1
a.clip (0) seria suficiente, pois o OP deseja apenas substituir os valores negativos. a.clip (0, 10) excluiria qualquer coisa acima de 10.
Usagi
1
@Hiett - Acabei de experimentar e o clipe levará um. Primeiro é assumido o mínimo.
Usagi
deve haver um problema de versão com numpy - aqui está minha saída: (Pdb) np.clip (w, 0) *** TypeError: clip () leva pelo menos 3 argumentos (2 fornecidos) - enquanto: (Pdb) np.clip ( w, 0,1e6) array ([[0., 0.605]])
bph
1
@Hiett, qual versão numpy? Você tentou o método de clipe de a? A função embutida numpy.clipme dá o mesmo erro, mas o método não.
remetente
sim, se você chamá-lo dessa forma, parece funcionar, por exemplo, p w.clip (0) array ([[0., 0.605]]) - quão estranho?
bph de
10

Outra solução minimalista do Python sem usar numpy:

[0 if i < 0 else i for i in a]

Não há necessidade de definir funções extras.

a = [1, 2, 3, -4, -5.23, 6]
[0 if i < 0 else i for i in a]

rendimentos:

[1, 2, 3, 0, 0, 6]
Levon
fonte
1
isso é bom - eu queria saber qual seria a sintaxe para colocar a instrução if dentro da compreensão da lista - eu estava errado ao colocá-la após o loop for e só então obter dois valores de volta, por exemplo, [0, 0] para o seu exemplo lista
bph
Eu fiz o mesmo quando aprendi originalmente sobre compreensão de listas e estava tentando coisas diferentes para testar minha compreensão - parecia mais intuitivo colocá-lo após o loop for para mim também. Agora, porém, isso faz :) Colocá-lo antes do foraplica-o a todos os elementos da lista, colocá-lo depois, significa que somente se a condição for atendida ele irá para a lista resultante.
Levon
2
@Hiett É apenas usar o operador ternário ( i < 0 ? 0 : iem C) dentro de uma compreensão de lista. Coloque colchetes para torná-lo mais claro [(0 if i < 0 else i) for i in a]. Colocar o if after está usando a parte do filtro da construção da expressão de lista. [(i) for i in a if i < 0]retornará apenas uma lista de itens que são menores que zero.
Paul S
2
O Numpy é poderoso porque faz muitos cálculos por código C compilado e, portanto, é mais rápido. Comparando este método com os outros, encontro uma diferença de fator de velocidade de quase 10 vezes (isso é mais lento). Portanto, embora seja intuitivo e fácil de ler, definitivamente não é para os que usam muita computação.
rspencer
4

E ainda outra possibilidade:

In [2]: a = array([1, 2, 3, -4, 5])

In [3]: where(a<0, 0, a)
Out[3]: array([1, 2, 3, 0, 5])
Ramon Crehuet
fonte
2

Aqui está uma maneira de fazer isso em Python sem entorpecer. Crie uma função que retorne o que você deseja e use uma compreensão de lista ou a função de mapa .

>>> a = [1, 2, 3, -4, 5]

>>> def zero_if_negative(x):
...   if x < 0:
...     return 0
...   return x
...

>>> [zero_if_negative(x) for x in a]
[1, 2, 3, 0, 5]

>>> map(zero_if_negative, a)
[1, 2, 3, 0, 5]
Kekoa
fonte
1
tinha seguido esse caminho, mas pensei que deveria haver uma maneira mais fácil, mais matlab e menos python de fazer isso com o numpy (já que eu estava usando arrays em vez de listas de qualquer maneira). o clipe é perfeito
bph de