2010-04-23 33 views
10

Tengo una matriz con dos columnas en numpy. Por ejemplo:eliminando pares de elementos de las matrices numpy que son NaN (u otro valor) en Python

a = array([[1, 5, nan, 6], 
      [10, 6, 6, nan]]) 
a = transpose(a) 

Quiero iterar eficientemente a través de las dos columnas, una [:, 0] y una [:, 1] y retire cualquier par que cumplen una determinada condición, en este caso si son NaN . La manera más obvia que puedo pensar es:

new_a = [] 
for val1, val2 in a: 
    if val2 == nan or val2 == nan: 
    new_a.append([val1, val2]) 

Pero eso parece torpe. ¿Cuál es la forma ridícula y pitón de hacer esto?

gracias.

Respuesta

29

Si usted quiere tomar sólo las filas que no tienen NAN, esto es la expresión que se necesita:

>>> import numpy as np 
>>> a[~np.isnan(a).any(1)] 
array([[ 1., 10.], 
     [ 5., 6.]]) 

Si desea que las filas que no tienen un número específico entre sus elementos, por ejemplo5:

>>> a[~(a == 5).any(1)] 
array([[ 1., 10.], 
     [ NaN, 6.], 
     [ 6., NaN]]) 

Este último es claramente equivalente a

>>> a[(a != 5).all(1)] 
array([[ 1., 10.], 
     [ NaN, 6.], 
     [ 6., NaN]]) 

Explicación: Let de primero crear su entrada ejemplo

>>> import numpy as np 
>>> a = np.array([[1, 5, np.nan, 6], 
...    [10, 6, 6, np.nan]]).transpose() 
>>> a 
array([[ 1., 10.], 
     [ 5., 6.], 
     [ NaN, 6.], 
     [ 6., NaN]]) 

Esto determina qué elementos son NAN

>>> np.isnan(a) 
array([[False, False], 
     [False, False], 
     [ True, False], 
     [False, True]], dtype=bool) 

Esto identifica las filas que tienen cualquier elemento que son verdaderas

>>> np.isnan(a).any(1) 
array([False, False, True, True], dtype=bool) 

Dado que no queremos que estos, que niegan la última expresión:

>>> ~np.isnan(a).any(1) 
array([ True, True, False, False], dtype=bool) 

Y finalmente utilizamos la matriz booleana para seleccionar las filas que queremos:

>>> a[~np.isnan(a).any(1)] 
array([[ 1., 10.], 
     [ 5., 6.]]) 
+2

+1: explicación súper clara y útil, y me gusta ~ np.isnan, ya que explica lo que estás haciendo. – tom10

+0

¡Qué gran respuesta! – Tjorriemorrie

2

Creo que list comprehensions debería hacer esto. Por ejemplo,

new_a = [(val1, val2) for (val1, val2) in a if math.isnan(val1) or math.isnan(val2)] 
+2

En realidad, necesitarías hacer que la prueba sea algo así como 'val1! = val1' porque' nan == nan' devuelve falso. Pero +1. –

+0

He editado lo anterior ... Honestamente, nunca he tenido necesidad de 'NaN', así que principalmente me refería a la forma de compilar una lista. Basado en la documentación aquí: http://docs.python.org/library/math.html#math.isnan, creo que esto debería funcionar ... – ig0774

+2

no debería ser: ... en un lugar donde no math isnan (val1) y no math.isnan (val2)? – user248237dfsf

3

Usted podría convertir la matriz en una masked array, y utilizar el compress_rows method:

import numpy as np 
a = np.array([[1, 5, np.nan, 6], 
      [10, 6, 6, np.nan]]) 
a = np.transpose(a) 
print(a) 
# [[ 1. 10.] 
# [ 5. 6.] 
# [ NaN 6.] 
# [ 6. NaN]] 
b=np.ma.compress_rows(np.ma.fix_invalid(a)) 
print(b) 
# [[ 1. 10.] 
# [ 5. 6.]] 
+2

+1: ¡guau! ¡No veo a menudo matrices enmascaradas que se usen y sugieran! ¡Bien! – EOL

3

no menoscabar la respuesta de ig0774, que es perfectamente válido y Pythonic y de hecho es la forma normal de hacer estas cosas en Python simple, pero: numpy admite un sistema de indexación booleano que también podría hacer el trabajo.

new_a = a[(a==a).all(1)] 

No estoy seguro de qué manera sería más eficiente (o más rápido de ejecutar).

Si desea utilizar una condición diferente para seleccionar las filas, esto tendría que cambiarse, y exactamente cómo depende de la condición. Si es algo que puede ser evaluado para cada elemento de la matriz de forma independiente, sólo podría reemplazar el a==a con la prueba apropiada, por ejemplo, para eliminar todas las filas con números mayores que 100 se podría hacer

new_a = a[(a<=100).all(1)] 

Pero si estás tratando de hacer algo elegante que involucre todos los elementos en una fila (como eliminar todas las filas que suman más de 100), podría ser más complicado. Si ese es el caso, puedo tratar de editar en una respuesta más específica si desea compartir su condición exacta.

+0

+1: para el enfoque vectorizado. esto es casi siempre más rápido y es una de las principales razones para usar numpy. – tom10

Cuestiones relacionadas