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 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)
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