python - libreria - numpy 1.13 3
Numpy donde funcionan mĂșltiples condiciones (5)
Tengo una variedad de distancias llamadas dists. Quiero seleccionar dists que están entre dos valores. Escribí la siguiente línea de código para hacer eso:
dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]
Sin embargo, esto selecciona solo para la condición
(np.where(dists <= r + dr))
Si hago los comandos secuencialmente usando una variable temporal, funciona bien. ¿Por qué el código anterior no funciona y cómo lo hago funcionar?
Aclamaciones
Dado que la respuesta aceptada explicó el problema muy bien. también puede usar las funciones lógicas numpy que es más adecuada aquí para múltiples condiciones:
np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))
He resuelto este simple ejemplo
import numpy as np
ar = np.array([3,4,5,14,2,4,3,7])
print [X for X in list(ar) if (X >= 3 and X <= 6)]
>>>
[3, 4, 5, 4, 3]
La mejor manera en su caso particular sería simplemente cambiar sus dos criterios a un criterio:
dists[abs(dists - r - dr/2.) <= dr/2.]
Solo crea una matriz booleana, y en mi opinión es más fácil de leer porque dice: ¿ está dist
dentro de un dr
o r
? (Aunque redefiniría r
para que sea el centro de su región de interés en lugar del principio, entonces r = r + dr/2.
) Pero eso no responde a su pregunta.
La respuesta a tu pregunta:
En realidad, no necesita where
si solo está tratando de filtrar los elementos de los dists
que no se ajustan a sus criterios:
dists[(dists >= r) & (dists <= r+dr)]
Porque el &
le dará un elemento and
(los paréntesis son necesarios).
O bien, si desea utilizar where
por alguna razón, puede hacer:
dists[(np.where((dists >= r) & (dists <= r + dr)))]
Por qué:
La razón por la que no funciona es porque np.where
devuelve una lista de índices, no una matriz booleana. Está tratando de obtener and
entre dos listas de números, que por supuesto no tiene los valores True
/ False
que espera. Si a
y b
son ambos valores True
, entonces a and b
devuelve b
. Así que decir algo como [0,1,2] and [2,3,4]
te dará [2,3,4]
. Aquí está en acción:
In [230]: dists = np.arange(0,10,.5)
In [231]: r = 5
In [232]: dr = 1
In [233]: np.where(dists >= r)
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)
In [234]: np.where(dists <= r+dr)
Out[234]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),)
In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
Out[235]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),)
Lo que esperabas comparar era simplemente la matriz booleana, por ejemplo
In [236]: dists >= r
Out[236]:
array([False, False, False, False, False, False, False, False, False,
False, True, True, True, True, True, True, True, True,
True, True], dtype=bool)
In [237]: dists <= r + dr
Out[237]:
array([ True, True, True, True, True, True, True, True, True,
True, True, True, True, False, False, False, False, False,
False, False], dtype=bool)
In [238]: (dists >= r) & (dists <= r + dr)
Out[238]:
array([False, False, False, False, False, False, False, False, False,
False, True, True, True, False, False, False, False, False,
False, False], dtype=bool)
Ahora puede llamar a np.where
en la matriz booleana combinada:
In [239]: np.where((dists >= r) & (dists <= r + dr))
Out[239]: (array([10, 11, 12]),)
In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
Out[240]: array([ 5. , 5.5, 6. ])
O simplemente indexe la matriz original con la matriz booleana usando la indexación sofisticada
In [241]: dists[(dists >= r) & (dists <= r + dr)]
Out[241]: array([ 5. , 5.5, 6. ])
Me gusta usar np.vectorize
para tales tareas. Considera lo siguiente:
>>> # function which returns True when constraints are satisfied.
>>> func = lambda d: d >= r and d<= (r+dr)
>>>
>>> # Apply constraints element-wise to the dists array.
>>> result = np.vectorize(func)(dists)
>>>
>>> result = np.where(result) # Get output.
También puede usar np.argwhere
lugar de np.where
para obtener un resultado claro. Pero esa es tu llamada :)
Espero eso ayude.
Tratar:
np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0])