Как заменить NaN на предыдущие значения в pandas DataFrame?
Предположим, что у меня есть DataFrame с некоторым 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
Что мне нужно сделать, это заменить каждый NaN
первым значением не NaN
в том же столбце над ним. Предполагается, что первая строка никогда не будет содержать NaN
. Таким образом, для предыдущего примера результатом будет
0 1 2
0 1 2 3
1 4 2 3
2 4 2 9
Я могу просто пропустить весь столбец DataFrame по каждому столбцу, поэтапно, и установить значения напрямую, но есть ли простой (оптимально свободный от цикла) способ достижения этого?
Ответы
Ответ 1
Вы можете использовать метод fillna
в DataFrame и указать метод как ffill
(forward fill):
>>> 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
Этот метод...
распространить [s] последнее действительное наблюдение вперед на следующий допустимый
Чтобы идти в обратном направлении, существует также метод bfill
.
Этот метод не изменяет DataFrame inplace - вам нужно будет перестроить возвращаемый DataFrame к переменной или указать inplace=True
:
df.fillna(method='ffill', inplace=True)
Ответ 2
Вы можете использовать pandas.DataFrame.fillna
с опцией method='ffill'
. 'ffill'
означает "прямое заполнение" и будет распространять последнее действительное наблюдение вперед. Альтернативой является 'bfill'
, который работает одинаково, но назад.
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
Для этого есть функция прямого синонима, pandas.DataFrame.ffill
, чтобы упростить задачу.
Ответ 3
Принятый ответ совершенен. У меня была связанная, но немного другая ситуация, когда мне приходилось заполнять форму, но только внутри групп. Если у кого-то есть такая же потребность, знайте, что fillna работает над объектом 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
Ответ 4
Одна вещь, которую я заметил при попытке этого решения, заключается в том, что если у вас есть N/A в начале или в конце массива, ffill и bfill не совсем работают. Вам нужны оба.
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
ffill
теперь имеет собственный метод 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
Ответ 6
В моем случае, у нас есть временные ряды от разных устройств, но некоторые устройства не могли отправить какое-либо значение в течение некоторого периода. Таким образом, мы должны создать значения NA для каждого устройства и периода времени, и после этого выполнить Fillna.
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')
Результат:
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
Ответ 7
Только одна версия столбца
- Заполните NAN последним действительным значением
df[column_name].fillna(method='ffill', inplace=True)
- Заполните NAN следующим действительным значением
df[column_name].fillna(method='backfill', inplace=True)