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 xseja 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.
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
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 ifnot math.isnan(value)]
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.
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
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.
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:
====================1DCase:====================Input:[1400.1500.1600. nan nan nan 1700.]
dropna:[1400.1500.1600.1700.]====================2DCase:====================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))]for2D:====================Input:[[1400.1500.1600.][ nan 0. nan][1700.1800. nan]]
dropna:[1400.1500.1600.1700.]
Bem-vindo ao SO! A solução que você propõe não responde ao problema: sua solução substitui NaNs por um número grande, enquanto o OP solicitou a remoção completa dos elementos.
Pier Paolo
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:
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:
Respostas:
Se você estiver usando numpy para suas matrizes, também poderá usar
Equivalentemente
[Obrigado a chbrown pela abreviação adicionada]
Explicação
A função interna
numpy.isnan
retorna um array booleano / lógico que tem o valor emTrue
qualquer lugar quex
não seja um número. Como queremos o oposto, usamos o operador lógico-não,~
para obter uma matriz comTrue
s em todo lugar quex
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.fonte
x = x[numpy.isfinite(x)]
x = x[~numpy.isnan(x)]
, que é equivalente à resposta original de mutzmatron, mas mais curta. Caso você queira manter seus infinitos por perto, saiba dissonumpy.isfinite(numpy.inf) == False
, é claro, mas~numpy.isnan(numpy.inf) == True
.np.where(np.isfinite(x), x, 0)
x
não é uma matriz numpy. Se você quiser usar a indexação lógico, ele deve ser um array - por exemplox = np.array(x)
funciona tanto para listas quanto para array numpy, pois v! = v apenas para NaN
fonte
x
ser especificado apenas uma vez, em vez de soluções do tipox[~numpy.isnan(x)]
. Isso é conveniente quandox
é 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.Tente o seguinte:
Para mais informações, leia em Compreensões de lista .
fonte
print ([value for value in x if not math.isnan(value)])
np
pacote: Portanto, retorna sua lista sem os nans:[value for value in x if not np.isnan(value)]
Para mim, a resposta de @jmetz não funcionou, no entanto, usar pandas isnull () funcionou.
fonte
Fazendo o acima:
ou
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
fonte
x
sobrescrever o novo valor (ou seja, sem os NaNs ...) . Você pode fornecer mais informações sobre por que isso pode estar acontecendo?Como mostrado por outros
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.
fonte
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
.Resultado:
fonte
Se você estiver usando
numpy
fonte
Uma maneira mais simples é:
Documentação: https://docs.scipy.org/doc/numpy/reference/generated/numpy.nan_to_num.html
fonte
NaN
s por um número grande, enquanto o OP solicitou a remoção completa dos elementos.Esta é minha abordagem para filtrar o ndarray "X" para NaNs e infs,
Eu crio um mapa de linhas sem nenhuma
NaN
einf
como a seguir: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
contém X semNaN
neminf
.fonte
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:
Veja mais detalhes aqui .
fonte