Eliminar valores nan de una matriz

223

Quiero descubrir cómo eliminar los valores nan de mi matriz. Mi matriz se parece a esto:

x = [1400, 1500, 1600, nan, nan, nan ,1700] #Not in this exact configuration

¿Cómo puedo eliminar los nanvalores de x?

Dax Feliz
fuente
Para ser claros, por "eliminar NaNs" te refieres a filtrar solo el subconjunto de valores no nulos . No "llenar los NaN con algún valor (cero, constante, media, mediana, etc.)"
smci

Respuestas:

362

Si está usando numpy para sus matrices, también puede usar

x = x[numpy.logical_not(numpy.isnan(x))]

Equivalentemente

x = x[~numpy.isnan(x)]

[Gracias a chbrown por la taquigrafía añadida]

Explicación

La función interna, numpy.isnandevuelve una matriz booleana / lógica que tiene el valor en Truetodas partes que xno es un número. Como queremos lo contrario, usamos el operador lógico-no, ~para obtener una matriz con Trues en todas partes que x sea un número válido.

Por último, usamos esta matriz lógica para indexar en la matriz original x, para recuperar solo los valores que no son NaN.

jmetz
fuente
31
Ox = x[numpy.isfinite(x)]
perezoso1
14
O x = x[~numpy.isnan(x)], que es equivalente a la respuesta original de mutzmatron, pero más corto. En caso de que quiera mantener sus infinitos alrededor, sepa eso numpy.isfinite(numpy.inf) == False, por supuesto, pero ~numpy.isnan(numpy.inf) == True.
chbrown
8
Para las personas que buscan resolver esto con un ndarray y mantener las dimensiones, use numpy donde :np.where(np.isfinite(x), x, 0)
BoltzmannBrain
1
TypeError: solo las matrices escalares enteras se pueden convertir a un índice escalar
remolque
1
@towry: esto está sucediendo porque su entrada, xno es una matriz numpy. Si desea utilizar la indexación lógica, debe ser una matriz, por ejemplox = np.array(x)
jmetz el
50
filter(lambda v: v==v, x)

funciona tanto para las listas como para la matriz numpy ya que v! = v solo para NaN

udibr
fuente
55
Un truco pero especialmente útil en el caso de que esté filtrando nans de una matriz de objetos con tipos mixtos, como cadenas y nans.
Austin Richardson
Solución muy limpia.
Moondra
2
Esto puede parecer inteligente, pero si oscurece la lógica y, en teoría, otros objetos (como las clases personalizadas) también pueden tener esta propiedad
Chris_Rands
También es útil porque solo necesita xespecificarse una vez en lugar de soluciones del tipo x[~numpy.isnan(x)]. Esto es conveniente cuando xse define mediante una expresión larga y no desea saturar el código creando una variable temporal para almacenar el resultado de esta expresión larga.
Christian O'Reilly
34

Prueba esto:

import math
print [value for value in x if not math.isnan(value)]

Para más información, lea en Lista de comprensiones .

liori
fuente
55
Si está usando numpy, tanto mi respuesta como la de @ lazy1 son casi un orden de magnitud más rápidas que la comprensión de la lista: la solución de lazy1 es un poco más rápida (aunque técnicamente tampoco devolverá ningún valor infinito).
jmetz
No olvides los corchetes :)print ([value for value in x if not math.isnan(value)])
hypers
Si está usando numpy como la respuesta principal, puede usar esta respuesta de comprensión de la lista con el nppaquete: Entonces devuelve su lista sin las nans:[value for value in x if not np.isnan(value)]
yeliabsalohcin
23

Para mí, la respuesta de @jmetz no funcionó, sin embargo, el uso de pandas isnull () sí.

x = x[~pd.isnull(x)]
Daniel Kislyuk
fuente
6

Haciendo lo anterior:

x = x[~numpy.isnan(x)]

o

x = x[numpy.logical_not(numpy.isnan(x))]

Descubrí que restablecer la misma variable (x) no eliminaba los valores reales de nan y tenía que usar una variable diferente. Establecerlo en una variable diferente eliminó los nans. p.ej

y = x[~numpy.isnan(x)]
melissaOu
fuente
Esto es extraño; De acuerdo con los documentos , la indexación de matriz booleana (que es esto), está bajo indexación avanzada que aparentemente "siempre devuelve una copia de los datos", por lo que debería xsobrescribir con el nuevo valor (es decir, sin los NaNs ...) . ¿Puede proporcionar más información sobre por qué esto podría estar sucediendo?
jmetz
5

Como lo demuestran otros

x[~numpy.isnan(x)]

trabajos. Pero arrojará un error si el tipo de archivo numpy no es un tipo de datos nativo, por ejemplo, si es un objeto. En ese caso puedes usar pandas.

x[~pandas.isna(x)] or x[~pandas.isnull(x)]
koliyat9811
fuente
4

La respuesta aceptada cambia de forma para las matrices 2d. Presento una solución aquí, usando la funcionalidad Pandas dropna () . Funciona para matrices 1D y 2D. En el caso 2D, puede elegir el clima para soltar la fila o columna que contiene np.nan.

import pandas as pd
import numpy as np

def dropna(arr, *args, **kwarg):
    assert isinstance(arr, np.ndarray)
    dropped=pd.DataFrame(arr).dropna(*args, **kwarg).values
    if arr.ndim==1:
        dropped=dropped.flatten()
    return dropped

x = np.array([1400, 1500, 1600, np.nan, np.nan, np.nan ,1700])
y = np.array([[1400, 1500, 1600], [np.nan, 0, np.nan] ,[1700,1800,np.nan]] )


print('='*20+' 1D Case: ' +'='*20+'\nInput:\n',x,sep='')
print('\ndropna:\n',dropna(x),sep='')

print('\n\n'+'='*20+' 2D Case: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna (rows):\n',dropna(y),sep='')
print('\ndropna (columns):\n',dropna(y,axis=1),sep='')

print('\n\n'+'='*20+' x[np.logical_not(np.isnan(x))] for 2D: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna:\n',x[np.logical_not(np.isnan(x))],sep='')

Resultado:

==================== 1D Case: ====================
Input:
[1400. 1500. 1600.   nan   nan   nan 1700.]

dropna:
[1400. 1500. 1600. 1700.]


==================== 2D Case: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna (rows):
[[1400. 1500. 1600.]]

dropna (columns):
[[1500.]
 [   0.]
 [1800.]]


==================== x[np.logical_not(np.isnan(x))] for 2D: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna:
[1400. 1500. 1600. 1700.]
Markus Dutschke
fuente
3

Si estas usando numpy

# first get the indices where the values are finite
ii = np.isfinite(x)

# second get the values
x = x[ii]
aloha
fuente
0

Este es mi enfoque para filtrar ndarray "X" para NaNs e infs,

Creo un mapa de filas sin ninguno NaNy ninguno de la infsiguiente manera:

idx = np.where((np.isnan(X)==False) & (np.isinf(X)==False))

idx es una tupla. Su segunda columna ( idx[1]) contiene los índices de la matriz, donde no se encuentra NaN ni inf en la fila.

Luego:

filtered_X = X[idx[1]]

filtered_Xcontiene X sin NaN ni inf.

aerijman
fuente
0

La respuesta de @ jmetz es probablemente la que más necesita la gente; sin embargo, produce una matriz unidimensional, por ejemplo, hace que sea inutilizable eliminar filas o columnas enteras en matrices.

Para hacerlo, uno debe reducir la matriz lógica a una dimensión, luego indexar la matriz de destino. Por ejemplo, lo siguiente eliminará las filas que tengan al menos un valor NaN:

x = x[~numpy.isnan(x).any(axis=1)]

Ver más detalles aquí .

M4urice
fuente