Removendo valores nan de uma matriz

223

Quero descobrir como remover os valores nan da minha matriz. Minha matriz se parece com isso:

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

Como posso remover os nanvalores x?

Dax Feliz
fonte
Para ser claro, por "remover NaNs", você quer dizer filtrar apenas o subconjunto de valores não nulos . Não "preenche os NaNs com algum valor (zero, constante, média, mediana etc.)"
smci

Respostas:

362

Se você estiver usando numpy para suas matrizes, também poderá usar

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

Equivalentemente

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

[Obrigado a chbrown pela abreviação adicionada]

Explicação

A função interna numpy.isnanretorna um array booleano / lógico que tem o valor em Truequalquer lugar que xnão seja um número. Como queremos o oposto, usamos o operador lógico-não, ~para obter uma matriz com Trues em todo lugar que x seja um número válido.

Por fim, usamos esse array lógico para indexar no array original x, para recuperar apenas os valores não-NaN.

jmetz
fonte
31
Oux = x[numpy.isfinite(x)]
lazy1
14
Ou x = x[~numpy.isnan(x)], que é equivalente à resposta original de mutzmatron, mas mais curta. Caso você queira manter seus infinitos por perto, saiba disso numpy.isfinite(numpy.inf) == False, é claro, mas ~numpy.isnan(numpy.inf) == True.
Chbrown #
8
Para as pessoas olhando para resolver isso com um ndarray e manter as dimensões, o uso numpy onde :np.where(np.isfinite(x), x, 0)
BoltzmannBrain
1
TypeError: única inteiro matrizes escalares pode ser convertido a um índice de escalar
towry
1
@Towry: isso está acontecendo porque sua entrada xnão é uma matriz numpy. Se você quiser usar a indexação lógico, ele deve ser um array - por exemplox = np.array(x)
jmetz
50
filter(lambda v: v==v, x)

funciona tanto para listas quanto para array numpy, pois v! = v apenas para NaN

udibr
fonte
5
Um hack, mas especialmente útil no caso em que você está filtrando nans de uma matriz de objetos com tipos mistos, como strings e nans.
Austin Richardson
Solução muito limpa.
Moondra 17/10
2
Isso pode parecer inteligente, mas se obscurece a lógica e, teoricamente, outros objetos (como classes personalizadas) também pode ter esta propriedade
Chris_Rands
Também é útil porque precisa xser especificado apenas uma vez, em vez de soluções do tipo x[~numpy.isnan(x)]. Isso é conveniente quando xé definido por uma expressão longa e você não deseja desorganizar o código criando uma variável temporária para armazenar o resultado dessa expressão longa.
Christian O'Reilly
34

Tente o seguinte:

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

Para mais informações, leia em Compreensões de lista .

liori
fonte
5
Se você estiver usando numpy, tanto a minha resposta como a do @ lazy1 são quase uma ordem de magnitude mais rápida que a compreensão da lista - a solução do lazy1 é um pouco mais rápida (embora tecnicamente também não retorne nenhum valor infinito).
jmetz
Não se esqueça dos suportes :)print ([value for value in x if not math.isnan(value)])
hipers
Se você estiver usando numpy como a resposta principal, poderá usar esta resposta de compreensão de lista com o nppacote: Portanto, retorna sua lista sem os nans:[value for value in x if not np.isnan(value)]
yeliabsalohcin
23

Para mim, a resposta de @jmetz não funcionou, no entanto, usar pandas isnull () funcionou.

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

Fazendo o acima:

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

ou

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

Eu descobri que a redefinição para a mesma variável (x) não removeu os valores reais de nan e precisava usar uma variável diferente. Configurá-lo para uma variável diferente removeu os nans. por exemplo

y = x[~numpy.isnan(x)]
melissaOu
fonte
Isto é estranho; de acordo com os documentos , a indexação de matriz booleana (que é essa) está sob indexação avançada que aparentemente "sempre retorna uma cópia dos dados", portanto, você deve xsobrescrever o novo valor (ou seja, sem os NaNs ...) . Você pode fornecer mais informações sobre por que isso pode estar acontecendo?
jmetz
5

Como mostrado por outros

x[~numpy.isnan(x)]

trabalho. Mas emitirá um erro se o numpy dtype não for um tipo de dados nativo, por exemplo, se for um objeto. Nesse caso, você pode usar pandas.

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

A resposta aceita muda de forma para matrizes 2D. Apresento uma solução aqui, usando a funcionalidade Pandas dropna () . Funciona para matrizes 1D e 2D. No caso 2D, você pode escolher o clima para descartar a linha ou coluna que contém 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
fonte
3

Se você estiver usando numpy

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

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

Esta é minha abordagem para filtrar o ndarray "X" para NaNs e infs,

Eu crio um mapa de linhas sem nenhuma NaNe infcomo a seguir:

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

idx é uma tupla. Sua segunda coluna ( idx[1]) contém os índices da matriz, onde nenhum NaN nem inf foram encontrados na linha.

Então:

filtered_X = X[idx[1]]

filtered_Xcontém X sem NaN nem inf.

aerijman
fonte
0

A resposta de @ jmetz é provavelmente a que a maioria das pessoas precisa; no entanto, gera uma matriz unidimensional, por exemplo, tornando inutilizável remover linhas ou colunas inteiras em matrizes.

Para fazer isso, é necessário reduzir a matriz lógica para uma dimensão e indexar a matriz de destino. Por exemplo, o seguinte removerá as linhas que possuem pelo menos um valor NaN:

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

Veja mais detalhes aqui .

M4urice
fonte