Reemplazar valores negativos en una matriz numpy

90

¿Existe una forma sencilla de reemplazar todos los valores negativos en una matriz con 0?

Tengo un bloqueo completo sobre cómo hacerlo usando una matriz NumPy.

P.ej

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

Necesito regresar

[1, 2, 3, 0, 5]

a < 0 da:

[False, False, False, True, False]

Aquí es donde estoy atascado: cómo usar esta matriz para modificar la matriz original.

bph
fuente

Respuestas:

137

Estás a mitad de camino. Tratar:

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

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

Prueba 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])

Puede recortar solo la mitad inferior con clip(0).

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

Puede recortar solo la mitad superior con clip(max=n). (Esto es mucho mejor que mi sugerencia anterior, que implicaba pasar NaNal primer parámetro y usar outpara forzar el tipo):

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

Otro enfoque interesante es utilizar where:

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

Finalmente, considere la respuesta de aix . Prefiero clipoperaciones simples porque se autodocumenta, pero su respuesta es preferible para operaciones más complejas.

remitente
fuente
1
a.clip (0) sería suficiente ya que el OP solo quiere reemplazar los valores negativos. a.clip (0, 10) excluiría cualquier cosa por encima de 10.
Usagi
1
@Hiett - Lo acabo de probar y el clip tomará uno. Primero se asume min.
Usagi
debe ser un problema de versión con numpy - aquí está mi salida: (Pdb) np.clip (w, 0) *** TypeError: clip () toma al menos 3 argumentos (2 dados) - mientras que: (Pdb) np.clip ( w, 0,1e6) matriz ([[0., 0.605]])
bph
1
@Hiett, ¿qué versión de numpy? ¿Probaste el método de clip de a? La función incorporada numpy.clipme da el mismo error, pero el método no.
senderle
sí, si lo llamas así, parece funcionar, por ejemplo, p w.clip (0) array ([[0., 0.605]]) - ¿qué tan raro?
bph
10

Otra solución minimalista de Python sin usar numpy:

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

No es necesario definir funciones adicionales.

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

rinde:

[1, 2, 3, 0, 0, 6]
Levon
fuente
1
eso es bueno - me preguntaba cuál sería la sintaxis para poner la instrucción if dentro de la comprensión de la lista - me estaba equivocando al pegarla después del bucle for y solo luego recuperar dos valores, por ejemplo, [0, 0] para su ejemplo list
bph
Hice lo mismo cuando aprendí originalmente sobre la comprensión de listas y estaba probando cosas diferentes para probar mi comprensión; me pareció más intuitivo ponerlo después del ciclo for para mí también. Ahora, sin embargo, esto sí :) Ponerlo antes de foraplicarlo a cada elemento de la lista, ponerlo después, significa que solo si se cumple la condición, entrará en la lista resultante.
Levon
2
@Hiett Solo está usando el operador ternario ( i < 0 ? 0 : ien C) dentro de una lista de comprensión. Coloque corchetes para que quede más claro [(0 if i < 0 else i) for i in a]. Poner el if después es usar la parte de filtro de la construcción de expresión de lista. [(i) for i in a if i < 0]solo devolverá una lista de elementos que sean menores que cero.
Paul S
2
Numpy es poderoso porque realiza gran parte del cálculo mediante código c compilado y, por lo tanto, es más rápido. Al comparar este método con los demás, encuentro una diferencia de factor de velocidad de casi 10 veces (esto es más lento). Entonces, si bien es intuitivo y fácil de leer, definitivamente no es para los que requieren mucha computación.
rspencer
4

Y otra posibilidad más:

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
fuente
2

Aquí hay una forma de hacerlo en Python sin NumPy. Cree una función que devuelva lo que desea y use una lista de comprensión o la función 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
fuente
1
había seguido esta ruta, pero pensé que debía haber una forma más fácil, más matlab menos python de hacerlo con numpy (ya que estaba usando matrices en lugar de listas de todos modos). clip es perfecto
bph