Pandas dataframe fillna () seulement quelques colonnes en place

145

J'essaie de ne remplir aucune valeur dans un dataframe Pandas avec des 0 pour seulement un sous-ensemble de colonnes.

Quand je fais:

import pandas as pd
df = pd.DataFrame(data={'a':[1,2,3,None],'b':[4,5,None,6],'c':[None,None,7,8]})
print df
df.fillna(value=0, inplace=True)
print df

Le résultat:

     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  NaN  7.0
3  NaN  6.0  8.0
     a    b    c
0  1.0  4.0  0.0
1  2.0  5.0  0.0
2  3.0  0.0  7.0
3  0.0  6.0  8.0

Il remplace chaque Nonepar 0. Ce que je veux faire, c'est ne remplacer que les Nones dans les colonnes aet b, mais pas c.

Quelle est la meilleure façon de procéder?

Sait
la source

Réponses:

219

Vous pouvez sélectionner les colonnes souhaitées et le faire par affectation:

df[['a', 'b']] = df[['a','b']].fillna(value=0)

Le résultat obtenu est comme prévu:

     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0
racine
la source
Oui, c'est exactement ce que je veux! Je vous remercie. Existe-t-il des moyens de le faire sur place? Ma base de données d'origine est assez grande.
Sait le
1
Je ne pense pas qu'il y ait de gain de performance en faisant cela en place car vous
écrasez de
4
Le loc est superflu ici, df[['a', 'b']] = df[['a','b']].fillna(value=0)fonctionnera toujours
EdChum
2
@EdChum Ne produit-il pas une trame de données temporaire et a donc besoin de plus de mémoire pour le faire? (Je suis plus préoccupé par la mémoire que par la complexité du temps.)
Sait
7
Pour de nombreuses opérations, fonctionnera inplacetoujours sur une copie. Je ne sais pas si c'est le cas fillnaou non. Voir cette réponse de l'un des principaux développeurs de pandas.
racine
86

Vous pouvez utiliser dict, fillnaavec une valeur différente pour une colonne différente

df.fillna({'a':0,'b':0})
Out[829]: 
     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0

Après l'avoir réattribué

df=df.fillna({'a':0,'b':0})
df
Out[831]: 
     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0
YOBEN_S
la source
1
vraiment cool, Btw pour le dict que vous pouvez utiliser fromkeyssi vous le souhaitez, +1
U10-Forward
1
La réponse / l'exemple serait plus clair si elle montrait effectivement des valeurs différentes pour les différentes colonnes.
RufusVS
@RufusVS c'est vrai, mais essayez toujours de correspondre à la sortie attendue de l'op
YOBEN_S
1
C'est la meilleure solution que la réponse acceptée, car elle évite les problèmes d'indexation chaînée, par exemple si elle est utilisée avecdf.fillna({'a':0,'b':0}, inplace=True)
Alex
19

Vous pouvez éviter de faire une copie de l'objet en utilisant la solution de Wen et inplace = True:

df.fillna({'a':0, 'b':0}, inplace=True)
print(df)

Ce qui donne:

     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0
Leesa H.
la source
1
Bien que ce soit correct, éviter une copie n'est pas nécessairement mieux .
jpp
7

Voici comment vous pouvez tout faire en une seule ligne:

df[['a', 'b']].fillna(value=0, inplace=True)

Ventilation: df[['a', 'b']]sélectionne les colonnes value=0pour lesquelles vous voulez remplir les valeurs NaN, lui dit de remplir NaNs avec zéro et inplace=Truerendra les modifications permanentes, sans avoir à faire une copie de l'objet.

Joséphine M. Ho
la source
7

l'utilisation de la réponse du haut produit un avertissement concernant la modification d'une copie d'une tranche df. En supposant que vous ayez d'autres colonnes, une meilleure façon de faire est de passer un dictionnaire:
df.fillna({'A': 'NA', 'B': 'NA'}, inplace=True)

Jonathan
la source
3

Ou quelque chose comme:

df.loc[df['a'].isnull(),'a']=0
df.loc[df['b'].isnull(),'b']=0

et s'il y en a plus:

for i in your_list:
    df.loc[df[i].isnull(),i]=0
U10-avant
la source
0

Parfois, cette syntaxe ne fonctionnera pas:

df[['col1','col2']] = df[['col1','col2']].fillna()

Utilisez plutôt ce qui suit:

df['col1','col2']
Bébé Sarath
la source