get_dummies(パンダ)とOneHotEncoder(Scikit-learn)の長所と短所は何ですか?


83

機械学習分類器のカテゴリ変数を数値に変換するさまざまな方法を学習しています。私はその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.dummies超える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 2016

1
それ以外に、1つは他よりも効率的ですか?
Ankit Seth 2017

6
更新、OneHotEncoder0.20.0バージョンでは文字列にも適用できません。
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
1

125

機械学習の場合、ほぼ間違いなく使用したい 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

変数の1つとX_testは異なるレベルが含まれている場合にどうなるかを検討してくださいX_train。たとえば、とX_train["color"]だけが含まれている"red"としましょう"green"。ただし、これらに加えて、X_test["color"]が含まれることもあります"blue"

を使用するとpd.get_dummiesX_testがない追加の"color_blue"列がX_train作成され、特にフィードしている場合は、不整合により後でコードが破損する可能性があります。X_testsklearnトレーニングしたモデルにしX_trainます。

そして、このようなデータを本番環境で処理したい場合、一度に1つの例を受け取ります。 pd.get_dummies環境で役に立ちません。

sklearn.OneHotEncoder私たちはエンコーダを作成したら、他の一方で、我々は唯一の列で、同じ出力を毎回生成するために、それを再利用することができます"red"し、"green"。そして、新しいレベルに遭遇したときに何が起こるかを明示的に制御"blue"できます。それが不可能だと思う場合は、handle_unknown="error";でエラーをスローするように指示できます。それ以外の場合は、続行するように指示し、赤と緑の列を0に設定しhandle_unknown="ignore"ます。


22
この答えは、受け入れられているよりもはるかに大きな影響があると思います。本当の魔法は、本番環境でポップアップするはずの未知のカテゴリ機能を処理することです。
バーカー

2
これは、受け入れられた答えよりも優れた、より完全な答えだと思います。
ChirazBenAbdelkader19年

1
はい。私見、これは受け入れられた答えよりも良い答えです。
dami.max

1
うん 。この回答は、one_hot_encoderが優れている理由と明確な例を明確に説明しています
Binod Mathews

1
それは美しい説明でした。あなたへの
称賛

4

結果のget_dummiesから列を変数col_listとしてキャッシュまたは保存してから、pd.reindexを使用してトレインデータセットとテストデータセットを整列させないのはなぜですか。例:

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

SklearnOHEはhandle_unknownのために優れているという以前のコメントに反論するためにもっと。パンダのインデックスの再作成を使用して同じことができます。
カール

1回限りの実行を除いて、get_dummiesの使用には卑劣な問題が発生する可能性があります。drop_first = Trueがあり、次のサンプルにドロップされた値が含まれていない場合はどうなりますか?
ミント

2

私はカールの答えが本当に好きで、それを支持しました。カールの例を少し拡張して、pd.get_dummiesが不明を処理できることをより多くの人が理解できるようにします。以下の2つの例は、pd.get_dummiesが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の例を含めてから、ドロップされた値を含まない新しいデータも表示してください。
ミント
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.