Supposons que j'ai un DataFrame avec quelques NaN
s:
>>> 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?
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)
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
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.
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
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
Version à une seule colonne
df[column_name].fillna(method='ffill', inplace=True)
df[column_name].fillna(method='backfill', inplace=True)
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
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