Làm cách nào để thay thế NaN bằng các giá trị trước trong DataFrame của gấu trúc?


140

Giả sử tôi có DataFrame với một số 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

Những gì tôi cần làm là thay thế mọi thứ NaNbằng NaNgiá trị không đầu tiên trong cùng một cột phía trên nó. Giả định rằng hàng đầu tiên sẽ không bao giờ chứa a NaN. Vì vậy, với ví dụ trước, kết quả sẽ là

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

Tôi chỉ có thể lặp qua toàn bộ từng cột DataFrame, từng yếu tố và đặt các giá trị trực tiếp, nhưng liệu có cách nào dễ dàng (tối ưu hóa một vòng lặp) để đạt được điều này không?

Câu trả lời:


213

Bạn có thể sử dụng fillnaphương thức trên DataFrame và chỉ định phương thức là ffill(điền vào phía trước):

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

Phương pháp này...

tuyên truyền [s] quan sát hợp lệ cuối cùng chuyển tiếp đến hợp lệ tiếp theo

Để đi ngược lại, cũng có một bfillphương pháp.

Phương pháp này không sửa đổi DataFrame tại chỗ - bạn sẽ cần buộc lại DataFrame được trả về thành một biến hoặc nếu không chỉ định inplace=True:

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

31

Câu trả lời được chấp nhận là hoàn hảo. Tôi đã có một tình huống liên quan nhưng hơi khác nhau khi tôi phải điền vào phía trước nhưng chỉ trong các nhóm. Trong trường hợp ai đó có cùng nhu cầu, hãy biết rằng fillna hoạt động trên một đối tượng 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

chính xác những gì tôi đang tìm kiếm, ty
Tony

18

Bạn có thể sử dụng pandas.DataFrame.fillnavới method='ffill'tùy chọn. 'ffill'là viết tắt của 'fill fill' và sẽ tuyên truyền quan sát hợp lệ cuối cùng về phía trước. Thay thế là 'bfill'hoạt động theo cùng một cách, nhưng ngược lại.

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

Ngoài ra còn có một chức năng đồng nghĩa trực tiếp cho việc này pandas.DataFrame.ffill, để làm cho mọi thứ đơn giản hơn.


13

Một điều mà tôi nhận thấy khi thử giải pháp này là nếu bạn có N / A ở đầu hoặc cuối mảng, thì ffill và bfill không hoạt động tốt. Bạn cần cả hai.

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

Xuất sắc. Tôi cần chính xác điều này cho vấn đề của tôi. Làm đầy cả trước và sau. Cảm ơn rất nhiều.
Prometheus

Tuyệt quá. Tôi cần giải pháp này. Cảm ơn
Junkrat


5

Chỉ có một phiên bản cột

  • Điền NAN với giá trị hợp lệ cuối cùng
df[column_name].fillna(method='ffill', inplace=True)
  • Điền NAN với giá trị hợp lệ tiếp theo
df[column_name].fillna(method='backfill', inplace=True)

5

Chỉ cần đồng ý với ffillphương thức, nhưng một thông tin bổ sung là bạn có thể giới hạn điền vào phía trước với đối số từ khóa 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

Bây giờ với limitđối số từ khóa

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

Trong trường hợp của tôi, chúng tôi có chuỗi thời gian từ các thiết bị khác nhau nhưng một số thiết bị không thể gửi bất kỳ giá trị nào trong một khoảng thời gian. Vì vậy, chúng ta nên tạo các giá trị NA cho mọi thiết bị và khoảng thời gian và sau đó làm 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')

Kết quả:

        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

Bạn có thể sử dụng fillnađể loại bỏ hoặc thay thế các giá trị NaN.

Xóa NaN

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

Thay thế 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

Gấu trúc tham khảo.DataFrame.fillna

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.