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?
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.
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
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.
La solution ci-dessus modifiera les inf
qui 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)
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]
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