Je souhaite rechercher dans un cadre de données Pandas toutes les valeurs contenant des espaces (tout montant arbitraire) et les remplacer par des valeurs NaN.
Des idées pour améliorer cela?
Fondamentalement, je veux transformer ceci:
A B C
2000-01-01 -0.532681 foo 0
2000-01-02 1.490752 bar 1
2000-01-03 -1.387326 foo 2
2000-01-04 0.814772 baz
2000-01-05 -0.222552 4
2000-01-06 -1.176781 qux
Dans ceci:
A B C
2000-01-01 -0.532681 foo 0
2000-01-02 1.490752 bar 1
2000-01-03 -1.387326 foo 2
2000-01-04 0.814772 baz NaN
2000-01-05 -0.222552 NaN 4
2000-01-06 -1.176781 qux NaN
J'ai réussi à le faire avec le code ci-dessous, mais l'homme est-il moche. Ce n'est pas Pythonic et je suis sûr que ce n'est pas l'utilisation la plus efficace des pandas non plus. Je parcourt chaque colonne et effectue un remplacement booléen par rapport à un masque de colonne généré en appliquant une fonction qui effectue une recherche regex de chaque valeur, en faisant correspondre les blancs.
for i in df.columns:
df[i][df[i].apply(lambda i: True if re.search('^\s*$', str(i)) else False)]=None
Il pourrait être optimisé un peu en ne parcourant que des champs pouvant contenir des chaînes vides:
if df[i].dtype == np.dtype('object')
Mais ce n'est pas vraiment une amélioration
Et finalement, ce code définit les chaînes cibles sur None, ce qui fonctionne avec les fonctions de Pandas telles que fillna()
, mais il serait intéressant de compléter si je pouvais insérer une NaN
directement au lieu de None
.
Je pense que df.replace()
fait le travail:
df = pd.DataFrame([
[-0.532681, 'foo', 0],
[1.490752, 'bar', 1],
[-1.387326, 'foo', 2],
[0.814772, 'baz', ' '],
[-0.222552, ' ', 4],
[-1.176781, 'qux', ' '],
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))
print df.replace(r'\s+', np.nan, regex=True)
Produit:
A B C
2000-01-01 -0.532681 foo 0
2000-01-02 1.490752 bar 1
2000-01-03 -1.387326 foo 2
2000-01-04 0.814772 baz NaN
2000-01-05 -0.222552 NaN 4
2000-01-06 -1.176781 qux NaN
Comme Temak le fait remarquer, utilisez df.replace(r'^\s+$', np.nan, regex=True)
si vos données valides contiennent des espaces.
Que diriez-vous:
d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)
La fonction applymap
applique une fonction à chaque cellule du cadre de données.
Si vous souhaitez remplacer une chaîne vide et que les enregistrements ne contiennent que des espaces, la réponse correcte est: !:
df = df.replace(r'^\s*$', np.nan, regex=True)
La réponse acceptée
df.replace(r'\s+', np.nan, regex=True)
Ne remplace pas une chaîne vide !, vous pouvez vous essayer avec l'exemple donné légèrement mis à jour:
df = pd.DataFrame([
[-0.532681, 'foo', 0],
[1.490752, 'bar', 1],
[-1.387326, 'fo o', 2],
[0.814772, 'baz', ' '],
[-0.222552, ' ', 4],
[-1.176781, 'qux', ''],
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))
Notez également que 'fo o' n'est pas remplacé par Nan, bien qu'il contienne un espace . Notez aussi qu'un simple:
df.replace(r'', np.NaN)
Ne fonctionne pas non plus - essayez-le.
Je vais faire ceci:
df = df.apply(lambda x: x.str.strip()).replace('', np.nan)
ou
df = df.apply(lambda x: x.str.strip() if isinstance(x, str) else x).replace('', np.nan)
Vous pouvez supprimer toutes les chaînes, puis remplacer les chaînes vides par np.nan
.
La solution la plus simple:
df = df.replace(r'^\s+$', np.nan, regex=True)
Si vous exportez les données du fichier CSV, cela peut être aussi simple que cela:
df = pd.read_csv(file_csv, na_values=' ')
Cela créera le bloc de données et remplacera les valeurs vides en tant que Na
Ce n'est pas une solution élégante, mais ce qui semble fonctionner, c’est enregistrer au format XLSX puis à le réimporter. Les autres solutions sur cette page ne fonctionnaient pas pour moi, sans savoir pourquoi.
data.to_Excel(filepath, index=False)
data = pd.read_Excel(filepath)
vous pouvez également utiliser un filtre pour le faire.
df = PD.DataFrame([
[-0.532681, 'foo', 0],
[1.490752, 'bar', 1],
[-1.387326, 'foo', 2],
[0.814772, 'baz', ' '],
[-0.222552, ' ', 4],
[-1.176781, 'qux', ' '])
df[df=='']='nan'
df=df.astype(float)
Pour une solution très simple et rapide où vous vérifiez l’égalité par rapport à une valeur unique, vous pouvez utiliser la méthode mask
.
df.mask(df == ' ')
Celles-ci sont toutes proches de la bonne réponse, mais je ne dirais pas que tout résoudrait le problème tout en restant plus lisible pour les autres lecteurs de votre code. Je dirais que cette réponse est une combinaison de Réponse de BrenBarn et du commentaire de tuomasttik ci-dessous/ réponse . La réponse de BrenBarn utilise la variable isspace
intégrée, mais ne prend pas en charge la suppression de chaînes vides, comme demandé par OP, et j'aurais tendance à l'attribuer comme cas d'utilisation standard du remplacement de chaînes par null.
Je l'ai réécrit avec .apply
pour que vous puissiez l'appeler sur un pd.Series
ou un pd.DataFrame
.
Python 3:
Pour remplacer des chaînes vides ou des chaînes d'espaces entièrement:
df = df.apply(lambda x: np.nan if isinstance(x, str) and (x.isspace() or not x) else x)
Pour remplacer des chaînes d'espaces entièrement:
df = df.apply(lambda x: np.nan if isinstance(x, str) and x.isspace() else x)
Pour utiliser cela dans Python 2, vous devrez remplacer str
par basestring
.
Python 2:
Pour remplacer des chaînes vides ou des chaînes d'espaces entièrement:
df = df.apply(lambda x: np.nan if isinstance(x, basestring) and (x.isspace() or not x) else x)
Pour remplacer des chaînes d'espaces entièrement:
df = df.apply(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)
print(df.isnull().sum()) # check numbers of null value in each column
modifiedDf=df.fillna("NaN") # Replace empty/null values with "NaN"
# modifiedDf = fd.dropna() # Remove rows with empty values
print(modifiedDf.isnull().sum()) # check numbers of null value in each column