Existe-t-il une méthode pour remplacer les valeurs par None
dans Pandas en Python?
Vous pouvez utiliser df.replace('pre', 'post')
et remplacer une valeur par une autre, mais cela ne peut pas être fait si vous souhaitez remplacer par la valeur None
. Si vous essayez, vous obtenez un résultat étrange.
Alors, voici un exemple:
df = DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df.replace('-', 0)
ce qui retourne un résultat réussi.
Mais,
df.replace('-', None)
qui retourne un résultat suivant:
0
0 - // this isn't replaced
1 3
2 2
3 5
4 1
5 -5
6 -1
7 -1 // this is changed to `-1`...
8 9
Pourquoi un résultat aussi étrange est-il renvoyé?
Puisque je veux verser ce cadre de données dans la base de données MySQL, je ne peux pas mettre de valeurs NaN
dans aucun élément de mon cadre de données, mais plutôt mettre None
. Vous pouvez sûrement d'abord changer '-'
to NaN
puis convertissez NaN
en None
, mais je veux savoir pourquoi le cadre de données agit de manière si terrible.
Testé sur pandas 0.12.0 dev Python 2.7 et OS X 10.8. Python est une version préinstallée sur OS X et moi avons installé pandas en utilisant le script SciPy Superpack, pour votre information.
En fait, dans les versions ultérieures de pandas, cela donnera une erreur TypeError:
df.replace('-', None)
TypeError: If "to_replace" and "value" are both None then regex must be a mapping
Vous pouvez le faire en passant soit une liste, soit un dictionnaire:
In [11]: df.replace('-', df.replace(['-'], [None]) # or .replace('-', {0: None})
Out[11]:
0
0 None
1 3
2 2
3 5
4 1
5 -5
6 -1
7 None
8 9
Mais je recommande d'utiliser NaNs plutôt que None:
In [12]: df.replace('-', np.nan)
Out[12]:
0
0 NaN
1 3
2 2
3 5
4 1
5 -5
6 -1
7 NaN
8 9
where
est probablement ce que vous recherchez. Alors
data=data.where(data=='-', None)
De la panda docs :
where
[renvoie] un objet de même forme que self et dont les entrées correspondantes proviennent de self où cond est True et sinon, elles proviennent d'autres.
Je préfère la solution utilisant replace
avec un dict
en raison de sa simplicité et de son élégance:
df.replace({'-': None})
Vous pouvez également avoir plus de remplaçants:
df.replace({'-': None, 'None': None})
Et même pour les gros remplaçants, ce qui est remplacé par ce qui est bien plus difficile pour de longues listes, à mon avis, est toujours évident et clair.
Avant de continuer avec ce post, il est important de comprendre la différence entre NaN et None . L'un est un type float, l'autre est un type d'objet. Pandas est plus approprié pour travailler avec des types scalaires car de nombreuses méthodes sur ces types peuvent être vectorisées. Pandas essaie de gérer None et NaN de manière cohérente, mais NumPy ne le peut pas. .
Ma suggestion ( et Andy ) est de rester avec NaN.
na_values=['-']
Si vous avez chargé ces données à partir de CSV/Excel, j'ai de bonnes nouvelles pour vous. Vous pouvez annuler cela à la racine lors du chargement des données au lieu de devoir écrire un correctif avec du code à l'étape suivante.
La plupart pd.read_*
_ fonctions (telles que read_csv
et read_Excel
) accepte un na_values
attribut.
file.csv
A,B
-,1
3,-
2,-
5,3
1,-2
-5,4
-1,-1
-,0
9,0
Maintenant, pour convertir le -
caractères dans NaNs,
import pandas as pd
df = pd.read_csv('file.csv', na_values=['-'])
df
A B
0 NaN 1.0
1 3.0 NaN
2 2.0 NaN
3 5.0 3.0
4 1.0 -2.0
5 -5.0 4.0
6 -1.0 -1.0
7 NaN 0.0
8 9.0 0.0
Et similaire pour d'autres fonctions/formats de fichiers.
P.S .: Sur la version 0.24 +, vous pouvez conserver le type d’entier même si votre colonne contient des NaN (oui, parlez d’avoir le gâteau et de le manger aussi). Vous pouvez spécifier dtype='Int32'
df = pd.read_csv('file.csv', na_values=['-'], dtype='Int32')
df
A B
0 NaN 1
1 3 NaN
2 2 NaN
3 5 3
4 1 -2
5 -5 4
6 -1 -1
7 NaN 0
8 9 0
df.dtypes
A Int32
B Int32
dtype: object
Le type n'est pas un type int conventionnel ... mais plutôt un Type entier Nullable. Il existe d'autres options.
pd.to_numeric
avec errors='coerce
Si vous utilisez des données numériques, une solution plus rapide consiste à utiliser pd.to_numeric
avec le errors='coerce'
argument qui convertit les valeurs non valides (valeurs impossibles à convertir en numérique) en NaN.
pd.to_numeric(df['A'], errors='coerce')
0 NaN
1 3.0
2 2.0
3 5.0
4 1.0
5 -5.0
6 -1.0
7 NaN
8 9.0
Name: A, dtype: float64
Pour conserver un type entier (nullable), utilisez
pd.to_numeric(df['A'], errors='coerce').astype('Int32')
0 NaN
1 3
2 2
3 5
4 1
5 -5
6 -1
7 NaN
8 9
Name: A, dtype: Int32
Pour contraindre plusieurs colonnes, utilisez apply
:
df[['A', 'B']].apply(pd.to_numeric, errors='coerce').astype('Int32')
A B
0 NaN 1
1 3 NaN
2 2 NaN
3 5 3
4 1 -2
5 -5 4
6 -1 -1
7 NaN 0
8 9 0
... et assigne le résultat après.
Plus d'informations peuvent être trouvées dans cette réponse .
df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df = df.where(df!='-', None)
La définition de valeurs nulles peut être faite avec np.nan
:
import numpy as np
df.replace('-', np.nan)
L'avantage est que df.last_valid_index()
les reconnaît comme non valides.