Thay thế các giá trị không hợp lệ bằng Không có trong Pandas DataFrame


80

Có phương pháp nào để thay thế các giá trị bằng NonePandas trong Python không?

Bạn có thể sử dụng df.replace('pre', 'post')và có thể thay thế một giá trị bằng một giá trị khác, nhưng điều này không thể thực hiện được nếu bạn muốn thay thế bằng Nonegiá trị mà nếu bạn cố gắng, bạn sẽ nhận được một kết quả lạ.

Vì vậy, đây là một ví dụ:

df = DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df.replace('-', 0)

trả về kết quả thành công.

Nhưng,

df.replace('-', None)

trả về một kết quả sau:

0
0   - // this isn't replaced
1   3
2   2
3   5
4   1
5  -5
6  -1
7  -1 // this is changed to `-1`...
8   9

Tại sao lại trả về một kết quả kỳ lạ như vậy?

Vì tôi muốn đổ khung dữ liệu này vào cơ sở dữ liệu MySQL, tôi không thể đặt NaNcác giá trị vào bất kỳ phần tử nào trong khung dữ liệu của mình và thay vào đó tôi muốn đặt None. Chắc chắn, trước tiên bạn có thể thay đổi '-'thành NaNvà sau đó chuyển đổi NaNthành None, nhưng tôi muốn biết tại sao khung dữ liệu hoạt động theo cách khủng khiếp như vậy.

Đã thử nghiệm trên pandas 0.12.0 dev trên Python 2.7 và OS X 10.8. Python là phiên bản được cài đặt sẵn trên OS X và tôi đã cài đặt gấu trúc bằng cách sử dụng tập lệnh SciPy Superpack để biết thông tin của bạn.


Không write_framephân tích cú pháp NaNs thành nones?
Andy Hayden

Đúng vậy. Bạn gặp InternalError: (1054, u"Unknown column 'nan' in 'field list'")lỗi. Tôi không biết về bất kỳ giải pháp nào trên nó ngoài việc chuyển đổi NaNsang phương thức Nonetrước khi thực thi write_frame.
Blaszard

Bạn đang sử dụng phiên bản gấu trúc nào?
Andy Hayden

Scipy siêu gói cho ra nhà phát triển? Được rồi, tôi chắc chắn nghĩ rằng bạn nên nêu vấn đề này như một vấn đề trên github , không quá khó để khắc phục.
Andy Hayden

Nếu bạn đang đọc dữ liệu này từ CSV / Excel , bạn có thể đọc các giá trị này dưới dạng NaN bằng cách sử dụng na_valuesđối số. Thêm thông tin trong câu trả lời này.
cs95

Câu trả lời:


111

Trên thực tế, trong các phiên bản gấu trúc sau này, điều này sẽ đưa ra TypeError:

df.replace('-', None)
TypeError: If "to_replace" and "value" are both None then regex must be a mapping

Bạn có thể làm điều đó bằng cách chuyển danh sách hoặc từ điển:

In [11]: df.replace('-', df.replace(['-'], [None]) # or .replace('-', {0: None})
Out[11]:
      0
0  None
1     3
2     2
3     5
4     1
5    -5
6    -1
7  None
8     9

Nhưng tôi khuyên bạn nên sử dụng NaN thay vì Không có:

In [12]: df.replace('-', np.nan)
Out[12]:
     0
0  NaN
1    3
2    2
3    5
4    1
5   -5
6   -1
7  NaN
8    9

15
Hoặc đơn giản là một danh sách, ví dụ df.replace(['-'], [None]), hoặc df.replace({'-': None}), tôi nghĩ. Việc sử dụng Nonenhư một ngăn cản sentinel sử dụng nó như là một giá trị quá ..
DSM

@ user2360798 thay thế thực sự là một hàm rất giàu tính năng (đọc phức tạp), tuy nhiên, docstring (dev) thực sự tốt.
Andy Hayden

4
Tôi không biết nó có rõ ràng không, nhưng đã phải gán dflại cho chính nó như:df = df.replace({'?': np.nan})
luckyging3r

3
@AndyHayden df.replace('-', df.replace(['-'], [None])trông có vẻ sôi nổi, đó có phải là lỗi đánh máy không?
lin_bug

2
@lin_bug Mặc dù có vẻ như nó không còn hoạt động trong các phiên bản gấu trúc gần đây. df.where (df! = '-', None) hoạt động
Andy Hayden

17

Tôi thích giải pháp sử dụng replacevới một dictvì sự đơn giản và sang trọng của nó:

df.replace({'-': None})

Bạn cũng có thể có nhiều thay thế hơn:

df.replace({'-': None, 'None': None})

Và ngay cả đối với những thay thế lớn hơn, nó luôn rõ ràng và rõ ràng những gì được thay thế bởi những gì - theo tôi, điều này khó hơn đối với những danh sách dài.


1
Cần lưu ý rằng một phần lý do tại sao kỹ thuật này hoạt động là việc sử dụng dictkiểu trong to_replacelàm cho methodtham số không được đánh giá và do đó, method='pad'mặc định không có hiệu ứng xấu.
bsplosion

15

wherecó lẽ là những gì bạn đang tìm kiếm. Vì thế

data=data.where(data=='-', None) 

Từ tài liệu về gấu trúc :

where [trả về] một đối tượng có cùng hình dạng với self và có các mục nhập tương ứng là self trong đó cond là True và ngược lại là từ other).


5
Điều này thực sự không chính xác. data = data.where (data == '-', None) sẽ thay thế bất cứ thứ gì KHÔNG BẰNG NHAU thành '-' bằng Không. Phiên bản Pandas nơi giữ giá trị của đối số đầu tiên (trong trường hợp này là dữ liệu == '-') và thay thế bất kỳ thứ gì khác bằng đối số thứ hai (trong trường hợp này là Không có). Có một chút khó hiểu vì np.where rõ ràng hơn ở chỗ nó hỏi điều kiện trong đối số đầu tiên, sau đó nếu đúng trong đối số thứ hai, sau đó nếu sai trong đối số thứ ba.
clg

8

Trước khi tiếp tục bài đăng này, điều quan trọng là phải hiểu sự khác biệt giữa NaN và None . Một là kiểu float, còn lại là kiểu đối tượng. Gấu trúc phù hợp hơn khi làm việc với các loại vô hướng vì nhiều phương pháp trên các loại này có thể được vector hóa. Pandas cố gắng xử lý None và NaN một cách nhất quán, nhưng NumPy không thể.

Đề nghị của tôi ( và của Andy ) là gắn bó với NaN.

Nhưng để trả lời câu hỏi của bạn...

pandas> = 0.18: Sử dụng na_values=['-']đối số vớiread_csv

Nếu bạn đã tải dữ liệu này từ CSV / Excel, tôi có tin tốt cho bạn. Bạn có thể giải quyết vấn đề này tận gốc trong quá trình tải dữ liệu thay vì phải viết bản sửa lỗi bằng mã ở bước tiếp theo.

Hầu hết các pd.read_*hàm (chẳng hạn như read_csvread_excel) chấp nhận một na_valuesthuộc tính.

file.csv

A,B
-,1
3,-
2,-
5,3
1,-2
-5,4
-1,-1
-,0
9,0

Bây giờ, để chuyển đổi các -ký tự thành NaN, hãy làm,

import pandas as pd
df = pd.read_csv('file.csv', na_values=['-'])
df

     A    B
0  NaN  1.0
1  3.0  NaN
2  2.0  NaN
3  5.0  3.0
4  1.0 -2.0
5 -5.0  4.0
6 -1.0 -1.0
7  NaN  0.0
8  9.0  0.0

Và tương tự cho các chức năng / định dạng tệp khác.

Tái bút: Trên v0.24 +, bạn có thể giữ nguyên kiểu số nguyên ngay cả khi cột của bạn có NaN (vâng, hãy nói về việc ăn bánh và ăn nó). Bạn có thể chỉ địnhdtype='Int32'

df = pd.read_csv('file.csv', na_values=['-'], dtype='Int32')
df

     A    B
0  NaN    1
1    3  NaN
2    2  NaN
3    5    3
4    1   -2
5   -5    4
6   -1   -1
7  NaN    0
8    9    0

df.dtypes

A    Int32
B    Int32
dtype: object

Loại dtype không phải là một kiểu int thông thường ... mà là một Kiểu số nguyên Nullable. Có những lựa chọn khác.


Xử lý dữ liệu số: pd.to_numericvớierrors='coerce

Nếu bạn đang làm việc với dữ liệu số, một giải pháp nhanh hơn là sử dụng pd.to_numericvới errors='coerce'đối số, mà cưỡng ép các giá trị không hợp lệ (giá trị mà không thể được đúc để số) để NaN.

pd.to_numeric(df['A'], errors='coerce')

0    NaN
1    3.0
2    2.0
3    5.0
4    1.0
5   -5.0
6   -1.0
7    NaN
8    9.0
Name: A, dtype: float64

Để giữ lại loại số nguyên (nullable), hãy sử dụng

pd.to_numeric(df['A'], errors='coerce').astype('Int32')

0    NaN
1      3
2      2
3      5
4      1
5     -5
6     -1
7    NaN
8      9
Name: A, dtype: Int32 

Để ép buộc nhiều cột, hãy sử dụng apply:

df[['A', 'B']].apply(pd.to_numeric, errors='coerce').astype('Int32')

     A    B
0  NaN    1
1    3  NaN
2    2  NaN
3    5    3
4    1   -2
5   -5    4
6   -1   -1
7  NaN    0
8    9    0

... và gán lại kết quả sau.

Thông tin thêm có thể được tìm thấy trong câu trả lời này .


3
df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df = df.where(df!='-', None)

0

Đặt giá trị null có thể được thực hiện với np.nan:

import numpy as np
df.replace('-', np.nan)

Lợi thế là df.last_valid_index()công nhận những điều này là không hợp lệ.


0

Sử dụng thay thế và gán một df mới:

import pandas as pd
df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9])
dfnew = df.replace('-', 0)
print(dfnew)


(venv) D:\assets>py teste2.py
   0
0  0
1  3
2  2
3  5
4  1
5 -5

0
df.replace('-', np.nan).astype("object")

Điều này sẽ đảm bảo rằng bạn có thể sử dụng isnull()sau này trên khung dữ liệu của mình


0

Với phiên bản Pandas ≥1.0.0, tôi sẽ sử dụng DataFrame.replacehoặc Series.replace:

df.replace(old_val, pd.NA, inplace=True)

Điều này tốt hơn vì hai lý do:

  1. Nó sử dụng pd.NAthay vì Nonehoặc np.nan.
  2. Nó thay thế giá trị tại chỗ có thể tiết kiệm bộ nhớ hơn.
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.