607 votes

Comment remplacer les valeurs NaN par des zéros dans une colonne d'un cadre de données Pandas ?

J'ai un Dataframe Pandas comme ci-dessous :

      itm Date                  Amount 
67    420 2012-09-30 00:00:00   65211
68    421 2012-09-09 00:00:00   29424
69    421 2012-09-16 00:00:00   29877
70    421 2012-09-23 00:00:00   30990
71    421 2012-09-30 00:00:00   61303
72    485 2012-09-09 00:00:00   71781
73    485 2012-09-16 00:00:00     NaN
74    485 2012-09-23 00:00:00   11072
75    485 2012-09-30 00:00:00  113702
76    489 2012-09-09 00:00:00   64731
77    489 2012-09-16 00:00:00     NaN

Lorsque j'essaie d'appliquer une fonction à la colonne Montant, j'obtiens l'erreur suivante :

ValueError: cannot convert float NaN to integer

J'ai essayé d'appliquer une fonction en utilisant .isnan à partir du module mathématique. J'ai essayé l'attribut pandas .replace. J'ai essayé l'attribut .sparse data de pandas 0.9. J'ai également essayé l'instruction if NaN == NaN dans une fonction. J'ai également consulté cet article Comment remplacer les valeurs NA par des zéros dans un cadre de données R ? en regardant d'autres articles. Toutes les méthodes que j'ai essayées n'ont pas fonctionné ou ne reconnaissent pas NaN. Tout conseil ou solution serait apprécié.

2 votes

Le seul problème est que df.fill.na() ne fonctionne pas si le cadre de données sur lequel vous l'appliquez est rééchantillonné ou a été découpé par la fonction loc.

941voto

Aman Points 3440

Je crois DataFrame.fillna() le fera pour vous.

Lien vers les docs pour un cadre de données et pour une série .

Exemple :

In [7]: df
Out[7]: 
          0         1
0       NaN       NaN
1 -0.494375  0.570994
2       NaN       NaN
3  1.876360 -0.229738
4       NaN       NaN

In [8]: df.fillna(0)
Out[8]: 
          0         1
0  0.000000  0.000000
1 -0.494375  0.570994
2  0.000000  0.000000
3  1.876360 -0.229738
4  0.000000  0.000000

Pour remplir les NaNs dans une seule colonne, sélectionnez uniquement cette colonne. Dans ce cas, j'utilise inplace=True pour modifier réellement le contenu de df.

In [12]: df[1].fillna(0, inplace=True)
Out[12]: 
0    0.000000
1    0.570994
2    0.000000
3   -0.229738
4    0.000000
Name: 1

In [13]: df
Out[13]: 
          0         1
0       NaN  0.000000
1 -0.494375  0.570994
2       NaN  0.000000
3  1.876360 -0.229738
4       NaN  0.000000

EDIT :

Pour éviter un SettingWithCopyWarning pour utiliser la fonctionnalité intégrée propre à chaque colonne :

df.fillna({1:0}, inplace=True)

1 votes

Est-il garanti que df[1] est une vue plutôt qu'une copie de la DF originale ? Évidemment, s'il y a une situation rare où il s'agit d'une copie, cela causerait un bogue très gênant. Y a-t-il une déclaration claire à ce sujet dans la documentation de pandas ?

0 votes

@max Voir ceci, pourrait répondre à votre question : stackoverflow.com/questions/23296282/

0 votes

Merci. Si j'ai bien compris, dans cette réponse, un "indexeur qui fixe" est l'opération d'indexation la plus extérieure (exécutée juste avant l'affectation). Ainsi, toute affectation qui n'utilise qu'un seul indexeur est garantie sûre, ce qui rend votre code sûr ?

178voto

rakesh Points 1675

Il n'est pas garanti que le découpage en tranches renvoie une vue ou une copie. Vous pouvez faire

df['column'] = df['column'].fillna(value)

62voto

Anton Protopopov Points 7767

Vous pourriez utiliser replace pour changer NaN a 0 :

import pandas as pd
import numpy as np

# for column
df['column'] = df['column'].replace(np.nan, 0)

# for whole dataframe
df = df.replace(np.nan, 0)

# inplace
df.replace(np.nan, 0, inplace=True)

30voto

Cornel Ciobanu Points 389

Le code ci-dessous a fonctionné pour moi.

import pandas

df = pandas.read_csv('somefile.txt')

df = df.fillna(0)

27voto

Ezekiel Kruglick Points 398

Je voulais juste faire une petite mise à jour/un cas particulier puisqu'il semble que les gens viennent encore ici. Si vous utilisez un index multiple ou une tranche d'index, l'option inplace=True peut ne pas être suffisante pour mettre à jour la tranche que vous avez choisie. Par exemple, dans un index multiple à 2x2 niveaux, cela ne changera aucune valeur (à partir de pandas 0.15) :

idx = pd.IndexSlice
df.loc[idx[:,mask_1],idx[mask_2,:]].fillna(value=0,inplace=True)

Le "problème" est que le chaînage rompt la capacité de fillna à mettre à jour le cadre de données d'origine. Je mets "problème" entre guillemets parce qu'il y a de bonnes raisons pour les décisions de conception qui ont conduit à ne pas interpréter à travers ces chaînes dans certaines situations. En outre, il s'agit d'un exemple complexe (bien que je l'aie vraiment rencontré), mais la même chose peut s'appliquer à moins de niveaux d'index selon la façon dont vous tranchez.

La solution est DataFrame.update :

df.update(df.loc[idx[:,mask_1],idx[[mask_2],:]].fillna(value=0))

Il est en une ligne, se lit raisonnablement bien (en quelque sorte) et élimine toute manipulation inutile de variables intermédiaires ou de boucles tout en vous permettant d'appliquer fillna à n'importe quelle tranche multiniveau de votre choix !

Si quelqu'un trouve des endroits où cela ne fonctionne pas, merci de le signaler dans les commentaires, j'ai fait des essais et regardé les sources et cela semble résoudre au moins mes problèmes de tranches multi-index.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X