Ưu và nhược điểm giữa get_dummies (Pandas) và OneHotEncoder (Scikit-learning) là gì?


83

Tôi đang tìm hiểu các phương pháp khác nhau để chuyển đổi các biến phân loại thành số cho bộ phân loại học máy. Tôi đã xem qua pd.get_dummiesphương pháp và sklearn.preprocessing.OneHotEncoder()tôi muốn xem chúng khác nhau như thế nào về hiệu suất và cách sử dụng.

Tôi đã tìm thấy một hướng dẫn về cách sử dụng OneHotEncoder()trên https://xgdgsc.wordpress.com/2015/03/20/note-on-using-onehotencoder-in-scikit-learn-to-work-on-categorical-features/ kể từ đó các sklearntài liệu không phải là quá hữu ích về tính năng này. Tôi có cảm giác mình làm không đúng ... nhưng

Một số có thể giải thích những ưu và nhược điểm của việc sử dụng pd.dummiesover sklearn.preprocessing.OneHotEncoder()và ngược lại? Tôi biết điều đó OneHotEncoder()cung cấp cho bạn một ma trận thưa thớt nhưng ngoài điều đó tôi không chắc nó được sử dụng như thế nào và lợi ích của pandasphương pháp này là gì. Tôi đang sử dụng nó không hiệu quả?

import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
sns.set()

%matplotlib inline

#Iris Plot
iris = load_iris()
n_samples, m_features = iris.data.shape

#Load Data
X, y = iris.data, iris.target
D_target_dummy = dict(zip(np.arange(iris.target_names.shape[0]), iris.target_names))

DF_data = pd.DataFrame(X,columns=iris.feature_names)
DF_data["target"] = pd.Series(y).map(D_target_dummy)
#sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
#0                  5.1               3.5                1.4               0.2   
#1                  4.9               3.0                1.4               0.2   
#2                  4.7               3.2                1.3               0.2   
#3                  4.6               3.1                1.5               0.2   
#4                  5.0               3.6                1.4               0.2   
#5                  5.4               3.9                1.7               0.4   

DF_dummies = pd.get_dummies(DF_data["target"])
#setosa  versicolor  virginica
#0         1           0          0
#1         1           0          0
#2         1           0          0
#3         1           0          0
#4         1           0          0
#5         1           0          0

from sklearn.preprocessing import OneHotEncoder, LabelEncoder
def f1(DF_data):
    Enc_ohe, Enc_label = OneHotEncoder(), LabelEncoder()
    DF_data["Dummies"] = Enc_label.fit_transform(DF_data["target"])
    DF_dummies2 = pd.DataFrame(Enc_ohe.fit_transform(DF_data[["Dummies"]]).todense(), columns = Enc_label.classes_)
    return(DF_dummies2)

%timeit pd.get_dummies(DF_data["target"])
#1000 loops, best of 3: 777 µs per loop

%timeit f1(DF_data)
#100 loops, best of 3: 2.91 ms per loop

Câu trả lời:


55

OneHotEncoderkhông thể xử lý các giá trị chuỗi trực tiếp. Nếu các đối tượng địa lý của bạn là chuỗi, thì trước tiên bạn cần ánh xạ chúng thành số nguyên.

pandas.get_dummieslà loại ngược lại. Theo mặc định, nó chỉ chuyển đổi các cột chuỗi thành biểu diễn một nóng, trừ khi các cột được chỉ định.


Hey @nos, xin lỗi vì sự chậm trễ trong việc trở lại với bạn về câu trả lời này
O.rka

1
Khác hơn thế, là một trong những hiệu quả hơn khác?
Ankit Seth

6
cập nhật, OneHotEncoderkhông thể được áp dụng trên chuỗi cũng như trong phiên bản 0.20.0.
Bs He

15
@BsHe Không còn đúng trong sklearn 0.20.3: OneHotEncoder(sparse=False).fit_transform(pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad'])))hoạt động, có nghĩa là OneHotEncodercó thể áp dụng trên stiren.
dzieciou

1
Bạn không thể mã hóa dữ liệu mới chưa thấy với pd.get_dummies.
gent

125

Đối với học máy, bạn gần như chắc chắn muốn sử dụng sklearn.OneHotEncoder. Đối với các tác vụ khác như phân tích đơn giản, bạn có thể sử dụng pd.get_dummies, điều này thuận tiện hơn một chút.

Lưu ý rằng sklearn.OneHotEncoderđã được cập nhật trong phiên bản mới nhất để nó chấp nhận các chuỗi cho các biến phân loại, cũng như các số nguyên.

Điểm mấu chốt của nó là sklearnbộ mã hóa tạo ra một hàm tồn tạisau đó có thể được áp dụng cho các tập dữ liệu mới sử dụng cùng các biến phân loại, với kết quả nhất quán .

from sklearn.preprocessing import OneHotEncoder

# Create the encoder.
encoder = OneHotEncoder(handle_unknown="ignore")
encoder.fit(X_train)    # Assume for simplicity all features are categorical.

# Apply the encoder.
X_train = encoder.transform(X_train)
X_test = encoder.transform(X_test)

Lưu ý cách chúng tôi áp dụng cùng một bộ mã hóa mà chúng tôi đã tạo X_traincho tập dữ liệu mới X_test.

Hãy xem xét điều gì sẽ xảy ra nếu X_testchứa các mức khác với X_trainmột trong các biến của nó. Ví dụ, giả sử X_train["color"]chỉ chứa "red""green", nhưng ngoài những thứ đó, X_test["color"]đôi khi chứa "blue".

Nếu chúng tôi sử dụng pd.get_dummies, X_testsẽ kết thúc với một "color_blue"cột bổ sung X_trainkhông có và sự không nhất quán có thể sẽ phá vỡ mã của chúng tôi sau này, đặc biệt nếu chúng tôi đang cung cấp X_testcho một sklearnmô hình mà chúng tôi đã đào tạo X_train.

Và nếu chúng tôi muốn xử lý dữ liệu như thế này trong sản xuất, nơi chúng tôi nhận được một ví dụ duy nhất tại một thời điểm, pd.get_dummiessẽ không được sử dụng.

Với sklearn.OneHotEncoderMặt khác, khi chúng tôi đã tạo ra một bộ mã hóa, chúng ta có thể tái sử dụng nó để tạo ra cùng một sản lượng mỗi lần, với các cột chỉ cho "red""green". Và chúng tôi có thể kiểm soát rõ ràng những gì sẽ xảy ra khi nó gặp phải cấp độ mới "blue": nếu chúng tôi nghĩ rằng điều đó là không thể, thì chúng tôi có thể yêu cầu nó ném một lỗi với handle_unknown="error"; nếu không, chúng ta có thể yêu cầu nó tiếp tục và chỉ cần đặt cột màu đỏ và xanh lá cây thành 0, với handle_unknown="ignore".


22
Tôi tin rằng câu trả lời này có tác động lớn hơn nhiều so với câu được chấp nhận. Điều kỳ diệu thực sự là xử lý các tính năng phân loại không xác định có thể xuất hiện trong quá trình sản xuất.
sủa

2
Tôi nghĩ đây là một câu trả lời hay hơn, đầy đủ hơn câu trả lời được chấp nhận.
Chiraz BenAbdelkader

1
Đúng. IMHO, đây là một câu trả lời tốt hơn câu trả lời được chấp nhận.
dami.max

1
Đúng vậy. Câu trả lời này chắc chắn giải thích tốt hơn tại sao one_hot_encoder có thể tốt hơn cùng với một ví dụ rõ ràng
Binod Mathews

1
Đó là một lời giải thích tuyệt vời
Kudos

4

tại sao bạn không chỉ lưu vào bộ nhớ cache hoặc lưu các cột dưới dạng biến col_list từ get_dummies kết quả sau đó sử dụng pd.reindex để căn chỉnh tập dữ liệu huấn luyện và kiểm tra .... ví dụ:

df = pd.get_dummies(data)
col_list = df.columns.tolist()

new_df = pd.get_dummies(new_data)
new_df = new_df.reindex(columns=col_list).fillna(0.00) 

Làm thế nào để trả lời câu hỏi này?
jorijnsmit

thêm để bác bỏ nhận xét trước đó rằng Sklearn OHE kém hơn vì handle_unknown. Điều tương tự cũng có thể được thực hiện bằng cách sử dụng pandas reindex.
Carl

Có thể có một vấn đề lén lút khi sử dụng get_dummies ngoại trừ một lần chạy thử. Điều gì xảy ra nếu bạn có drop_first = True và mẫu tiếp theo không bao gồm giá trị bị giảm?
Mint

2

Tôi thực sự thích câu trả lời của Carl và đã ủng hộ nó. Tôi sẽ chỉ mở rộng ví dụ của Carl một chút để nhiều người hy vọng sẽ đánh giá cao rằng pd.get_dummies có thể xử lý ẩn số. Hai ví dụ dưới đây cho thấy rằng pd.get_dummies có thể thực hiện điều tương tự trong việc xử lý OHE chưa biết.

# data is from @dzieciou's comment above
>>> data =pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad']))
# new_data has two values that data does not have. 
>>> new_data= pd.DataFrame(
pd.Series(['good','bad','worst','good', 'good', 'bad','excellent', 'perfect']))

Sử dụng pd.get_dummies

>>> df = pd.get_dummies(data)
>>> col_list = df.columns.tolist()
>>> print(df)
   0_bad  0_good  0_worst
0      0       1        0
1      1       0        0
2      0       0        1
3      0       1        0
4      0       1        0
5      1       0        0
6      0       0        0
7      0       0        0

>>> new_df = pd.get_dummies(new_data)
# handle unknow by using .reindex and .fillna()
>>> new_df = new_df.reindex(columns=col_list).fillna(0.00)
>>> print(new_df)
#    0_bad  0_good  0_worst
# 0      0       1        0
# 1      1       0        0
# 2      0       0        1
# 3      0       1        0
# 4      0       1        0
# 5      1       0        0
# 6      0       0        0
# 7      0       0        0

Sử dụng OneHotEncoder

>>> encoder = OneHotEncoder(handle_unknown="ignore", sparse=False)
>>> encoder.fit(data)
>>> encoder.transform(new_data)
# array([[0., 1., 0.],
#        [1., 0., 0.],
#        [0., 0., 1.],
#        [0., 1., 0.],
#        [0., 1., 0.],
#        [1., 0., 0.],
#        [0., 0., 0.],
#        [0., 0., 0.]])

Bạn có thể vui lòng mở rộng câu trả lời của mình để bao gồm một ví dụ với drop_first = True, và sau đó cũng hiển thị dữ liệu mới không bao gồm giá trị đã giảm.
Mint
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.