web-dev-qa-db-fra.com

Comment remplacer les NaN par les valeurs précédentes dans les pandas DataFrame?

Supposons que j'ai un DataFrame avec quelques NaNs:

>>> import pandas as pd
>>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
>>> df
    0   1   2
0   1   2   3
1   4 NaN NaN
2 NaN NaN   9

Ce que je dois faire est de remplacer chaque NaN par la première valeur non -NaN dans la même colonne au-dessus de celle-ci. On suppose que la première ligne ne contiendra jamais une NaN. Donc, pour l'exemple précédent, le résultat serait

   0  1  2
0  1  2  3
1  4  2  3
2  4  2  9

Je peux simplement parcourir l'intégralité de DataFrame colonne par colonne, élément par élément et définir directement les valeurs, mais existe-t-il un moyen simple (idéalement sans boucle) d'y parvenir?

64
zegkljan

Vous pouvez utiliser la méthode fillna sur le DataFrame et spécifier la méthode comme suit: ffill (remplissage en aval):

>>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
>>> df.fillna(method='ffill')
   0  1  2
0  1  2  3
1  4  2  3
2  4  2  9

Cette méthode...

propager la dernière observation valide [s] en avant à la prochaine valide

Pour aller dans le sens opposé, il existe également une méthode bfill.

Cette méthode ne modifie pas le DataFrame inplace - vous devrez rediriger le DataFrame renvoyé vers une variable ou indiquez inplace=True:

df.fillna(method='ffill', inplace=True)
106
Alex Riley

La réponse acceptée est parfaite. J'avais une situation connexe mais légèrement différente où je devais remplir, mais uniquement au sein de groupes. Si quelqu'un a le même besoin, sachez que fillna fonctionne sur un objet DataFrameGroupBy.

>>> example = pd.DataFrame({'number':[0,1,2,nan,4,nan,6,7,8,9],'name':list('aaabbbcccc')})
>>> example
  name  number
0    a     0.0
1    a     1.0
2    a     2.0
3    b     NaN
4    b     4.0
5    b     NaN
6    c     6.0
7    c     7.0
8    c     8.0
9    c     9.0
>>> example.groupby('name')['number'].fillna(method='ffill') # fill in row 5 but not row 3
0    0.0
1    1.0
2    2.0
3    NaN
4    4.0
5    4.0
6    6.0
7    7.0
8    8.0
9    9.0
Name: number, dtype: float64
12
ErnestScribbler

Vous pouvez utiliser pandas.DataFrame.fillna avec l'option method='ffill'. 'ffill' signifie 'forward fill' et propage la dernière observation valide en avant. L'alternative est 'bfill' qui fonctionne de la même manière, mais en arrière.

import pandas as pd

df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
df = df.fillna(method='ffill')

print(df)
#   0  1  2
#0  1  2  3
#1  4  2  3
#2  4  2  9

Il existe également une fonction synonyme directe pour cela, pandas.DataFrame.ffill , afin de simplifier les choses.

11
Ffisegydd

Une chose que j'ai remarquée en essayant cette solution est que, si vous avez N/A au début ou à la fin du tableau, ffill et bfill ne fonctionnent pas tout à fait. Vous avez besoin des deux.

In [224]: df = pd.DataFrame([None, 1, 2, 3, None, 4, 5, 6, None])

In [225]: df.ffill()
Out[225]:
     0
0  NaN
1  1.0
...
7  6.0
8  6.0

In [226]: df.bfill()
Out[226]:
     0
0  1.0
1  1.0
...
7  6.0
8  NaN

In [227]: df.bfill().ffill()
Out[227]:
     0
0  1.0
1  1.0
...
7  6.0
8  6.0
5
jjs

ffill a maintenant sa propre méthode pd.DataFrame.ffill

df.ffill()

     0    1    2
0  1.0  2.0  3.0
1  4.0  2.0  3.0
2  4.0  2.0  9.0
1
piRSquared

Version à une seule colonne

  • Remplir NAN avec dernière valeur valide
df[column_name].fillna(method='ffill', inplace=True)
  • Remplir NAN avec prochaine valeur valide
df[column_name].fillna(method='backfill', inplace=True)
1
DeveScie

En acceptant simplement la méthode ffill, mais une information supplémentaire est que vous pouvez limiter le remplissage en avant avec le mot clé argument limit.

>>> import pandas as pd    
>>> df = pd.DataFrame([[1, 2, 3], [None, None, 6], [None, None, 9]])

>>> df
     0    1    2
0  1.0  2.0  3.0
1  NaN  NaN  6.0
2  NaN  NaN  9.0

>>> df[1].fillna(method='ffill', inplace=True)
>>> df
     0    1    2
0  1.0  2.0  3.0
1  NaN  2.0  NaN
2  NaN  2.0  9.0

Maintenant, avec l'argument de mot clé limit

>>> df[0].fillna(method='ffill', limit=1, inplace=True)

>>> df
     0    1  2
0  1.0  2.0  3
1  1.0  2.0  6
2  NaN  2.0  9
1
user3724647

Dans mon cas, nous avons des séries chronologiques de différents appareils, mais certains appareils ne pouvaient envoyer aucune valeur pendant une période donnée. Nous devrions donc créer des valeurs NA pour chaque appareil et chaque période, puis effectuer le remplissage.

df = pd.DataFrame([["device1", 1, 'first val of device1'], ["device2", 2, 'first val of device2'], ["device3", 3, 'first val of device3']])
df.pivot(index=1, columns=0, values=2).fillna(method='ffill').unstack().reset_index(name='value')

Résultat:

        0   1   value
0   device1     1   first val of device1
1   device1     2   first val of device1
2   device1     3   first val of device1
3   device2     1   None
4   device2     2   first val of device2
5   device2     3   first val of device2
6   device3     1   None
7   device3     2   None
8   device3     3   first val of device3
0
Anton Shelin