2010-08-02 21 views
31

Si tengo una matriz como¿Cómo transformar los elementos negativos a cero sin un bucle?

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

Quiero configurar todos los elementos negativos a cero: [2, 3, 0, 0, 3]. ¿Cómo hacerlo con numpy sin un explícito para? Necesito utilizar la a modificado en un cálculo, por ejemplo

c = a * b 

donde b es otra matriz con la misma longitud del original a

Conclusión

import numpy as np 
from time import time 

a = np.random.uniform(-1, 1, 20000000) 
t = time(); b = np.where(a>0, a, 0); print "1. ", time() - t 
a = np.random.uniform(-1, 1, 20000000) 
t = time(); b = a.clip(min=0); print "2. ", time() - t 
a = np.random.uniform(-1, 1, 20000000) 
t = time(); a[a < 0] = 0; print "3. ", time() - t 
a = np.random.uniform(-1, 1, 20000000) 
t = time(); a[np.where(a<0)] = 0; print "4. ", time() - t 
a = np.random.uniform(-1, 1, 20000000) 
t = time(); b = [max(x, 0) for x in a]; print "5. ", time() - t 
  1. 1,38629984856
  2. 0.516846179962 < - más rápido a.clip (min = 0);
  3. 0,615426063538
  4. 0,944557905197
  5. 51,7364809513
+1

En mi máquina 'a [a <0] = 0' es significativamente más rápido que' a.clip (min = 0) '. – user545424

Respuesta

54
a = a.clip(min=0) 
+0

mejor solución? –

+0

Podría ser. Tendrás que probarlos para ver cuál es el más rápido. No uso numpy mucho, así que no estoy seguro, aunque se supone que numpy está muy bien optimizado, por lo que podría superar mis respuestas. –

+1

wiso, creo que encontraste la manera más rápida. '% timeit a.clip (min = 0, out = a)' tomó 5.65 microsegundos por ciclo. '% timeit np.where (a> 0, a, 0)' tomó 24 microsegundos por ciclo, '% timeit a [a <0] = 0' tomó 11,6 microsegundos por ciclo. – unutbu

12

Me gustaría hacer esto:

a[a < 0] = 0 

Si desea conservar el original a y único conjunto de los elementos negativos a cero en una copia, puede copiar primero la matriz:

c = a.copy() 
c[c < 0] = 0 
+0

No funcionará con múltiples dimensiones. – Dmitry

3

Uso where

a[numpy.where(a<0)] = 0 
5

Otro truco es usar la multiplicación. En realidad, esto parece ser mucho más rápido que cualquier otro método aquí. Por ejemplo

b = a*(a>0) # copies data 

o

a *= (a>0) # in-place zero-ing 

Me hicieron pruebas con timeit, pre-cálculo de la del < y> debido a que algunos de éstos modifican en el lugar y que podría afectar considerablemente los resultados. En todos los casos a fue np.random.uniform(-1, 1, 20000000) pero con los negativos ya establecidos en 0 pero L = a < 0 y G = a > 0 antes de a se ha cambiado. El clip tiene un impacto relativamente negativo ya que no llega a utilizar L o G (sin embargo, el cálculo de aquellos en la misma máquina tomó solo 17ms cada uno, por lo que no es la causa principal de la diferencia de velocidad).

%timeit b = np.where(G, a, 0) # 132ms copies 
%timeit b = a.clip(min=0)  # 165ms copies 
%timeit a[L] = 0    # 158ms in-place 
%timeit a[np.where(L)] = 0  # 122ms in-place 
%timeit b = a*G    # 87.4ms copies 
%timeit np.multiply(a,G,a)  # 40.1ms in-place (normal code would use `a*=G`) 

Al elegir a penalizar a los métodos in situ en lugar de clip, los siguientes tiempos: permite enviar una

%timeit b = np.where(a>0, a, 0)    # 152ms 
%timeit b = a.clip(min=0)     # 165ms 
%timeit b = a.copy(); b[a<0] = 0   # 231ms 
%timeit b = a.copy(); b[np.where(a<0)] = 0 # 205ms 
%timeit b = a*(a>0)       # 108ms 
%timeit b = a.copy(); b*=a>0    # 121ms 

no en el lugar métodos son penalizados por 20 ms (el tiempo necesario para calcular a>0 o a<0) y los métodos in-situ penalizan 73-83 ms (por lo que tarda de 53-63ms en hacer b.copy()).

En general, los métodos de multiplicación son mucho más rápidos que clip. Si no está en su lugar, es 1.5x más rápido. Si puede hacerlo en el lugar, entonces es 2.75x más rápido.

+0

Usar cantidades precalculadas significa hacer trampa –

+0

Pero todas (excepto una) usan valores pre calculados. Y los cálculos precalculados son rápidos, tomando 17 ms en la misma máquina en las mismas condiciones, por lo que no son la causa de la diferencia de velocidad. Y si no los precalculaba, los métodos en el lugar se verían mucho más rápidos, ya que después del primer intento no habría nada a cero. – coderforlife

+0

déjame mostrarte una comparación justa –

Cuestiones relacionadas