Suppression de valeurs nan d'un tableau

223

Je veux savoir comment supprimer les valeurs nan de mon tableau. Mon tableau ressemble à ceci:

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

Comment puis-je supprimer les nanvaleurs de x?

Dax Feliz
la source
Pour être clair, par «supprimer les NaN», vous entendez filtrer uniquement le sous-ensemble de valeurs non nulles . Pas "remplir les NaN avec une certaine valeur (zéro, constant, moyenne, médiane, etc.)"
smci

Réponses:

362

Si vous utilisez numpy pour vos tableaux, vous pouvez également utiliser

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

De manière équivalente

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

[Merci à chbrown pour le raccourci ajouté]

Explication

La fonction interne, numpy.isnanrenvoie un tableau booléen / logique qui a Truepartout la valeur qui xn'est pas un nombre. Comme nous voulons le contraire, nous utilisons l'opérateur non logique ~pour obtenir un tableau avec Trues partout qui x est un nombre valide.

Enfin, nous utilisons ce tableau logique pour indexer dans le tableau d'origine x, pour récupérer uniquement les valeurs non NaN.

jmetz
la source
31
Oux = x[numpy.isfinite(x)]
lazy1
14
Ou x = x[~numpy.isnan(x)], ce qui équivaut à la réponse originale de mutzmatron, mais plus court. Dans le cas où vous souhaitez garder vos infinis, sachez que numpy.isfinite(numpy.inf) == False, bien sûr, mais ~numpy.isnan(numpy.inf) == True.
chbrown
8
Pour les personnes qui cherchent à résoudre ce problème avec un ndarray et à maintenir les dimensions, utilisez numpy où :np.where(np.isfinite(x), x, 0)
BoltzmannBrain
1
TypeError: seuls les tableaux scalaires entiers peuvent être convertis en un index scalaire
jusqu'au
1
@towry: cela se produit parce que votre entrée xn'est pas un tableau numpy. Si vous souhaitez utiliser l'indexation logique, ce doit être un tableau - par exemplex = np.array(x)
jmetz
50
filter(lambda v: v==v, x)

fonctionne à la fois pour les listes et le tableau numpy puisque v! = v uniquement pour NaN

udibr
la source
5
Un hack mais particulièrement utile dans le cas où vous filtrez des nans à partir d'un tableau d'objets de types mixtes, tels que des chaînes et des nans.
Austin Richardson
Solution très propre.
Moondra
2
Cela peut sembler intelligent, mais s'il obscurcit la logique et théoriquement d'autres objets (tels que des classes personnalisées) peuvent également avoir cette propriété
Chris_Rands
Également utile car il ne doit xêtre spécifié qu'une seule fois, contrairement aux solutions du type x[~numpy.isnan(x)]. C'est pratique quand xest défini par une expression longue et que vous ne voulez pas encombrer le code en créant une variable temporaire pour stocker le résultat de cette expression longue.
Christian O'Reilly
34

Essaye ça:

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

Pour en savoir plus, lisez la liste des compréhensions .

liori
la source
5
Si vous utilisez numpy, ma réponse et celle de @ lazy1 sont presque un ordre de grandeur plus rapides que la compréhension de la liste - la solution de lazy1 est légèrement plus rapide (bien que techniquement, elle ne renverra pas non plus de valeurs à l'infini).
jmetz
N'oubliez pas les parenthèses :)print ([value for value in x if not math.isnan(value)])
hypers
Si vous utilisez numpy comme la réponse du haut, vous pouvez utiliser cette réponse de compréhension de liste avec le nppackage: renvoie donc votre liste sans les nans:[value for value in x if not np.isnan(value)]
yeliabsalohcin
23

Pour moi, la réponse de @jmetz n'a pas fonctionné, mais l'utilisation de pandas isnull () l'a fait.

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

Faire ce qui précède:

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

ou

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

J'ai trouvé que la réinitialisation à la même variable (x) ne supprimait pas les valeurs nanos réelles et devait utiliser une variable différente. Le définir sur une variable différente a supprimé les nans. par exemple

y = x[~numpy.isnan(x)]
melissaOu
la source
Cela est étrange; selon la documentation , l'indexation de tableaux booléens (ce qui est le cas) est sous indexation avancée qui apparemment "renvoie toujours une copie des données", vous devriez donc xécraser avec la nouvelle valeur (c'est-à-dire sans les NaN ...) . Pouvez-vous fournir plus d'informations sur la raison pour laquelle cela pourrait se produire?
jmetz
5

Comme le montrent d'autres

x[~numpy.isnan(x)]

travaux. Mais cela générera une erreur si le type numpy n'est pas un type de données natif, par exemple s'il s'agit d'un objet. Dans ce cas, vous pouvez utiliser des pandas.

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

La réponse acceptée change de forme pour les tableaux 2D. Je présente ici une solution, en utilisant la fonctionnalité Pandas dropna () . Il fonctionne pour les tableaux 1D et 2D. Dans le cas 2D, vous pouvez choisir la météo pour supprimer la ligne ou la colonne contenant 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='')

Résultat:

==================== 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
la source
3

Si vous utilisez numpy

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

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

Ceci est mon approche pour filtrer ndarray "X" pour NaNs et infs,

Je crée une carte de lignes sans aucun NaNet infcomme suit:

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

idx est un tuple. C'est la deuxième colonne ( idx[1]) contient les indices du tableau, où aucun NaN ni inf ne se trouvent à travers la ligne.

Ensuite:

filtered_X = X[idx[1]]

filtered_Xcontient X sans NaN ni inf.

aerijman
la source
0

La réponse de @ jmetz est probablement celle dont la plupart des gens ont besoin; cependant, il donne un tableau unidimensionnel, ce qui rend par exemple inutilisable la suppression de lignes ou de colonnes entières dans les matrices.

Pour ce faire, il faut réduire le tableau logique à une dimension, puis indexer le tableau cible. Par exemple, ce qui suit supprimera les lignes qui ont au moins une valeur NaN:

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

Voir plus de détails ici .

M4urice
la source