Bagaimana cara mengganti NaNs dengan mendahului nilai dalam panda DataFrame?

140

Misalkan saya memiliki DataFrame dengan beberapa 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

Apa yang perlu saya lakukan adalah mengganti setiap NaNdengan yang tidak NaNbernilai pertama di kolom yang sama di atasnya. Diasumsikan bahwa baris pertama tidak akan pernah mengandung a NaN. Jadi untuk contoh sebelumnya hasilnya akan

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

Saya hanya bisa mengulang seluruh kolom DataFrame, elemen demi elemen dan mengatur nilai-nilai secara langsung, tetapi apakah ada cara mudah (optimal tanpa loop) untuk mencapai ini?

zegkljan
sumber

Jawaban:

213

Anda bisa menggunakan fillnametode pada DataFrame dan menentukan metode sebagai ffill(meneruskan isi):

>>> 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

Metode ini...

menyebarkan [s] pengamatan valid terakhir ke depan untuk valid berikutnya

Untuk sebaliknya, ada juga bfillmetode.

Metode ini tidak mengubah DataFrame di tempat - Anda harus mengubah kembali DataFrame yang dikembalikan ke variabel atau menentukan inplace=True:

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

Jawaban yang diterima sempurna. Saya memiliki situasi terkait tetapi sedikit berbeda di mana saya harus mengisi ke depan tetapi hanya dalam kelompok. Jika seseorang memiliki kebutuhan yang sama, ketahuilah bahwa fillna bekerja pada objek 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
ErnestScribbler
sumber
persis apa yang saya cari, ty
Tony
18

Anda dapat menggunakan pandas.DataFrame.fillnadengan method='ffill'pilihan. 'ffill'singkatan 'forward fill' dan akan menyebarkan pengamatan valid terakhir ke depan. Alternatifnya adalah 'bfill'yang bekerja dengan cara yang sama, tetapi mundur.

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

Ada juga fungsi sinonim langsung untuk ini pandas.DataFrame.ffill,, untuk mempermudah.

Ffisegydd
sumber
14

Satu hal yang saya perhatikan ketika mencoba solusi ini adalah bahwa jika Anda memiliki N / A di awal atau di akhir array, ffill dan bfill tidak cukup berfungsi. Anda membutuhkan keduanya.

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
jjs
sumber
Cemerlang. Saya membutuhkan ini untuk masalah saya. Mengisi sebelum dan sesudah. Terima kasih banyak.
Prometheus
Bagus. Saya butuh solusi ini. Terima kasih
Junkrat
5

ffill sekarang memiliki metode sendiri 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
piRquared
sumber
5

Hanya satu versi kolom

  • Isi NAN dengan nilai terakhir yang valid
df[column_name].fillna(method='ffill', inplace=True)
  • Isi NAN dengan nilai valid berikutnya
df[column_name].fillna(method='backfill', inplace=True)
SpiralDev
sumber
5

Hanya setuju dengan ffillmetode, tetapi satu info tambahan adalah bahwa Anda dapat membatasi isi ke depan dengan argumen kata kunci 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
1  NaN  NaN   6
2  NaN  NaN   9

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

Sekarang dengan limitargumen kata kunci

>>> 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
Suvo
sumber
1

Dalam kasus saya, kami memiliki deret waktu dari perangkat yang berbeda tetapi beberapa perangkat tidak dapat mengirim nilai apa pun selama beberapa periode. Jadi kita harus membuat nilai NA untuk setiap perangkat dan periode waktu dan setelah itu lakukan 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')

Hasil:

        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
Hodza
sumber
0

Anda dapat menggunakan fillnauntuk menghapus atau mengganti nilai NaN.

NaN Hapus

import pandas as pd

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

df.fillna(method='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

Ganti NaN

df.fillna(0) # 0 means What Value you want to replace 
     0    1    2
0  1.0  2.0  3.0
1  4.0  0.0  0.0
2  0.0  0.0  9.0

Referensi pandas.DataFrame.fillna

Md Jewele Islam
sumber