supprimer des valeurs infinies à partir de dataframes dans les pandas?

Quel est le moyen le plus rapide/le plus simple de supprimer les valeurs NaN et inf/-inf d'un DataFrame pandas sans réinitialiser mode.use_inf_as_null? J'aimerais pouvoir utiliser les arguments subset et how de dropna, sauf avec les valeurs inf considérées comme manquantes, comme:

df.dropna(subset=["col1", "col2"], how="all", with_inf=True)

Est-ce possible? Existe-t-il un moyen de dire à dropna d'inclure inf dans sa définition des valeurs manquantes?

110
demandé sur user248237dfsf 2013-07-05 00:55:20

6 réponses

Le moyen le plus simple serait de commencer replace infs à NaN:

df.replace([np.inf, -np.inf], np.nan)

, puis utiliser l'dropna:

df.replace([np.inf, -np.inf], np.nan).dropna(subset=["col1", "col2"], how="all")

Par exemple:

In [11]: df = pd.DataFrame([1, 2, np.inf, -np.inf])

In [12]: df.replace([np.inf, -np.inf], np.nan)
Out[12]:
    0
0   1
1   2
2 NaN
3 NaN

la même méthode fonctionnerait pour une série.

218
répondu Andy Hayden 2013-07-04 21:50:51

Voici une autre méthode utilisant .loc pour remplacer inf par nan sur une série:

s.loc[(~np.isfinite(s)) & s.notnull()] = np.nan

Donc, en réponse à la question initiale:

df = pd.DataFrame(np.ones((3, 3)), columns=list('ABC'))

for i in range(3): 
    df.iat[i, i] = np.inf

df
          A         B         C
0       inf  1.000000  1.000000
1  1.000000       inf  1.000000
2  1.000000  1.000000       inf

df.sum()
A    inf
B    inf
C    inf
dtype: float64

df.apply(lambda s: s[np.isfinite(s)].dropna()).sum()
A    2
B    2
C    2
dtype: float64
10
répondu Alexander 2016-03-04 00:20:30

Avec le contexte d'option, cela est possible sans définir définitivement use_inf_as_null. Par exemple:

with pd.option_context('mode.use_inf_as_null', True):
    df = df.dropna(subset=['col1', 'col2'], how='all')

Bien sûr, il peut être configuré pour traiter inf comme NaN permanence avec pd.set_option('use_inf_as_null', True) trop.

9
répondu ayhan 2017-08-17 23:10:32

La solution ci-dessus modifiera les infqui ne sont pas dans les colonnes cibles. Pour y remédier,

lst = [np.inf, -np.inf]
to_replace = dict((v, lst) for v in ['col1', 'col2'])
df.replace(to_replace, np.nan)
5
répondu has2k1 2014-08-10 02:27:01

Une autre solution serait d'utiliser la méthode isin. Utilisez-le pour déterminer si chaque valeur est infinie ou manquante, puis enchaînez la méthode all pour déterminer si toutes les valeurs des lignes sont infinies ou manquantes.

Enfin, utilisez la négation de ce résultat pour sélectionner les lignes qui n'ont pas toutes les valeurs infinies ou manquantes via l'indexation booléenne.

all_inf_or_nan = df.isin([np.inf, -np.inf, np.nan]).all(axis='columns')
df[~all_inf_or_nan]
3
répondu Ted Petrou 2017-11-03 18:34:37

Vous pouvez utiliser pd.DataFrame.mask avec np.isinf. Vous devez d'abord vous assurer que vos séries de dataframe sont toutes de type float. Ensuite, utilisez dropna, avec votre logique.

print(df)

       col1      col2
0 -0.441406       inf
1 -0.321105      -inf
2 -0.412857  2.223047
3 -0.356610  2.513048

df = df.mask(np.isinf(df))

print(df)

       col1      col2
0 -0.441406       NaN
1 -0.321105       NaN
2 -0.412857  2.223047
3 -0.356610  2.513048
0
répondu jpp 2018-06-28 15:42:01