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?

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)

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

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.


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

Cemerlang. Saya membutuhkan ini untuk masalah saya. Mengisi sebelum dan sesudah. Terima kasih banyak.
Prometheus

Bagus. Saya butuh solusi ini. Terima kasih
Junkrat


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)

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

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

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.