get_dummies (Pandas)와 OneHotEncoder (Scikit-learn)의 장단점은 무엇입니까?


84

기계 학습 분류기를 위해 범주 형 변수를 숫자로 변환하는 다양한 방법을 배우고 있습니다. 나는 pd.get_dummies방법을 발견했고 sklearn.preprocessing.OneHotEncoder()성능과 사용 측면에서 어떻게 다른지보고 싶었습니다.

내가 사용하는 방법에 대한 자습서 발견 OneHotEncoder()https://xgdgsc.wordpress.com/2015/03/20/note-on-using-onehotencoder-in-scikit-learn-to-work-on-categorical-features/ 이후를 sklearn문서는이 기능에 너무 도움이되지 않았습니다. 제대로하고 있지 않다는 느낌이 있지만 ...

일부는 pd.dummiesover 사용의 장단점을 설명 할 수 있습니까 sklearn.preprocessing.OneHotEncoder()? 나는 그것이 OneHotEncoder()당신에게 희소 행렬 을 제공 한다는 것을 알고 있지만 그것이 사용되는 pandas방법 과 방법에 대한 이점이 무엇인지 확실하지 않습니다 . 비효율적으로 사용하고 있습니까?

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

답변:


55

OneHotEncoder문자열 값을 직접 처리 할 수 ​​없습니다. 명목 특징이 문자열 인 경우 먼저 정수로 매핑해야합니다.

pandas.get_dummies그 반대입니다. 기본적으로 열을 지정하지 않는 한 문자열 열만 원-핫 표현으로 변환합니다.


안녕하세요 @nos,이 답변에 대한 답변이 지연되어 죄송합니다
O.rka

1
그 외에 하나가 다른 것보다 효율적입니까?
Ankit Seth

6
업데이트, OneHotEncoder0.20.0 버전에서는 문자열에도 적용 할 수 없습니다.
Bs He

15
@BsHe 더 이상 sklearn 0.20.3에서 사실이 아닙니다 : OneHotEncoder(sparse=False).fit_transform(pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad'])))작동합니다. 이는 OneHotEncoder교반에 적용될 수 있음 을 의미 합니다.
dzieciou

1
보이지 않는 새 데이터를 pd.get_dummies.
16:54에 gented

127

기계 학습의 경우 거의 확실히 sklearn.OneHotEncoder. 간단한 분석과 같은 다른 작업의 경우을 사용할 수 있습니다 pd.get_dummies. 이는 좀 더 편리합니다.

참고 sklearn.OneHotEncoder가되도록 최신 버전으로 업데이트되었습니다 문자열 동의 않는 범주 변수뿐만 아니라 정수를.

핵심은 sklearn인코더가 지속 되는 함수를 생성 한 다음 동일한 범주 형 변수를 사용하는 새로운 데이터 세트에 적용 할 수 있으며 일관된 결과를 제공한다는 것 입니다.

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)

우리가 만든 동일한 인코더를 X_train새 데이터 세트에 적용하는 방법에 유의하십시오 X_test.

변수 중 하나와 X_test다른 수준이 포함 된 경우 어떻게되는지 고려하십시오 X_train. 예를 들어,하자의 말은 X_train["color"]단지 포함 "red"하고 "green"있지만, 그뿐만 아니라, X_test["color"]때때로 포함 "blue".

우리가 사용하는 경우 pd.get_dummies, X_test추가로 끝날 것이다 "color_blue"X_train이없는, 그리고 불일치는 아마 우리가 먹이 특히, 나중에 우리의 암호를 해독합니다 X_testsklearn우리가 훈련 모델 X_train.

그리고 한 번에 하나의 예제를받는 프로덕션에서 이와 같은 데이터를 처리하려면 pd.get_dummies사용할 수 없습니다.

함께 sklearn.OneHotEncoder우리는 인코더를 만든 후 다른 한편으로, 우리는 단지에 대한 열이있는, 동일한 출력마다 생산을 다시 사용할 수 있습니다 "red""green". 그리고 우리는 그것이 새로운 레벨을 만날 때 일어나는 일을 명시 적으로 제어 할 수 있습니다 "blue". 만약 그것이 불가능하다고 생각한다면, 우리는 그것에 오류를 던지도록 말할 수 있습니다 handle_unknown="error"; 그렇지 않으면 계속하도록 지시하고 단순히 빨간색과 녹색 열을 0으로 설정할 수 있습니다 handle_unknown="ignore".


22
나는이 대답이 받아 들여진 것보다 훨씬 더 큰 영향을 미친다고 생각합니다. 진짜 마법은 프로덕션에서 팝업 될 수있는 알려지지 않은 범주 적 기능을 처리하는 것입니다.
barker 19

2
나는 이것이 받아 들여지는 대답보다 더 좋고 완전한 대답이라고 생각합니다.
Chiraz BenAbdelkader

1
예. IMHO, 이것은 허용 된 답변보다 더 나은 답변입니다.
dami.max

1
네. 이 답변은 명확한 예와 함께 one_hot_encoder가 더 나은 이유를 더 잘 설명합니다
Binod Mathews

1
그것은 아름다운 설명이었습니다.
Kudos

4

결과 get_dummies에서 col_list 변수로 열을 캐시하거나 저장 한 다음 pd.reindex를 사용하여 train 대 테스트 데이터 세트를 정렬하는 이유는 무엇입니까? ... 예 :

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) 

이것은 질문에 어떻게 대답합니까?
jorijnsmit

Sklearn OHE가 handle_unknown 때문에 더 우월하다는 이전 의견을 반박합니다. pandas reindex를 사용하여 동일한 작업을 수행 할 수 있습니다.
Carl

일회성 실행을 제외하고 get_dummies를 사용하는 데 교활한 문제가있을 수 있습니다. drop_first = True이고 다음 샘플에 삭제 된 값이 포함되지 않으면 어떻게됩니까?
Mint

2

나는 Carl의 대답을 정말 좋아하고 찬성했습니다. 더 많은 사람들이 pd.get_dummies가 unknown을 처리 할 수 ​​있다는 사실에 감사 할 수 있도록 Carl의 예제를 조금 확장하겠습니다. 아래의 두 예는 pd.get_dummies가 unknown을 OHE로 처리 할 때 동일한 작업을 수행 할 수 있음을 보여줍니다.

# 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']))

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

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.]])

drop_first = True가 포함 된 예제를 포함하도록 답변을 확장 한 다음 삭제 된 값을 포함하지 않는 새 데이터도 표시 할 수 있습니까?
Mint
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.