quel est le moyen le plus rapide/le plus simple de supprimer les valeurs nan et inf/-inf d'un pandas DataFrame 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 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?
Le moyen le plus simple serait de commencer par replace
infs to NaN:
df.replace([np.inf, -np.inf], np.nan)
puis utilisez le 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.
Avec l'option context, cela est possible sans régler en permanence use_inf_as_na
. Par exemple:
with pd.option_context('mode.use_inf_as_na', True):
df = df.dropna(subset=['col1', 'col2'], how='all')
Bien sûr, il peut être configuré pour traiter inf
comme NaN
de manière permanente avec
pd.set_option('use_inf_as_na', True)
Pour les versions plus anciennes, remplacez use_inf_as_na
par use_inf_as_null
.
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
La solution ci-dessus modifiera les inf
s qui ne figurent pas dans les colonnes cibles. Pour y remédier,
lst = [np.inf, -np.inf]
to_replace = {v: lst for v in ['col1', 'col2']}
df.replace(to_replace, np.nan)
Une autre solution consisterait à 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]
Utilisez (rapide et simple):
df = df[np.isfinite(df).all(1)]
Cette réponse est basée sur réponse de DougR dans une autre question. Voici un exemple de code:
import pandas as pd
import numpy as np
df=pd.DataFrame([1,2,3,np.nan,4,np.inf,5,-np.inf,6])
print('Input:\n',df,sep='')
df = df[np.isfinite(df).all(1)]
print('\nDropped:\n',df,sep='')
Résultat:
Input:
0
0 1.0000
1 2.0000
2 3.0000
3 NaN
4 4.0000
5 inf
6 5.0000
7 -inf
8 6.0000
Dropped:
0
0 1.0
1 2.0
2 3.0
4 4.0
6 5.0
8 6.0
Vous pouvez utiliser pd.DataFrame.mask
avec np.isinf
. Vous devez d'abord vous assurer que vos séries de données sont de type float
. Puis utilisez dropna
avec votre logique existante.
_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
_