La función de “Dónde” no puede evitar evaluar Sqrt (negativo)

Parece que la función np.where evalúa primero todos los resultados posibles, luego evalúa la condición más adelante. Esto significa que, en mi caso, evaluará la raíz cuadrada de -5, -4, -3, -2, -1 aunque no se utilizará más adelante.

Mi código corre y funciona. Pero mi problema es la advertencia. Evité usar un bucle para evaluar cada elemento, porque se ejecutará mucho más lento que np.where .

Así que aquí estoy preguntando

  1. ¿Hay alguna manera de hacer np.where evalúe la condición primero?
  2. ¿Puedo desactivar solo esta advertencia específica? ¿Cómo?
  3. Otra forma mejor de hacerlo si tienes una sugerencia mejor.

Aquí sólo un código de ejemplo corto correspondiente a mi código real que es gigantesco. Pero esencialmente tiene el mismo problema.

Entrada:

 import numpy as np c=np.arange(10)-5 d=np.where(c>=0, np.sqrt(c) ,c ) 

Salida:

 RuntimeWarning: invalid value encountered in sqrt d=np.where(c>=0,np.sqrt(c),c) 

Hay una manera mucho mejor de hacer esto. Echemos un vistazo a lo que está haciendo su código para ver por qué.

np.where acepta tres matrices como entradas. Las matrices no admiten la evaluación perezosa.

 d = np.where(c >= 0, np.sqrt(c), c) 

Esta línea es por lo tanto equivalente a hacer

 a = (c >= 0) b = np.sqrt(c) d = np.where(a, b, c) 

Observe que las entradas se calculan inmediatamente, antes de que se llame.

Por suerte, no es necesario usar en absoluto. En su lugar, simplemente use una máscara booleana:

 mask = (c >= 0) d = np.empty_like(c) d[mask] = np.sqrt(c[mask]) d[~mask] = c[~mask] 

Si espera muchos negativos, puede copiar todos los elementos en lugar de los negativos:

 d = c.copy() d[mask] = np.sqrt(c[mask]) 

Una solución aún mejor podría ser utilizar matrices enmascaradas:

 d = np.ma(c, c < 0) d = np.ma.sqrt(d) 

Para acceder a la matriz de datos completa, sin modificar la parte enmascarada, utilice d.data .

Esta es la respuesta a su segunda pregunta.

Sí, puedes desactivar las advertencias. Utilice el módulo de advertencias .

 import warnings warnings.filterwarnings("ignore") 

Una solución es no usar np.where , y usar la indexación en su lugar.

 c = np.arange(10)-5 d = c.copy() c_positive = c > 0 d[c_positive] = np.sqrt(c[c_positive]) 

np.sqrt es un ufunc y acepta un parámetro where . Se puede usar como máscara en este caso:

 In [61]: c = np.arange(10)-5.0 In [62]: d = c.copy() In [63]: np.sqrt(c, where=c>=0, out=d); In [64]: d Out[64]: array([-5. , -4. , -3. , -2. , -1. , 0. , 1. , 1.41421356, 1.73205081, 2. ]) 

En contraste con el caso np.where , esto no evalúa la función en los elementos ~ where.