get_dummies(Pandas)和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.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

Answers:


55

OneHotEncoder无法直接处理字符串值。如果名义特征是字符串,则需要首先将其映射为整数。

pandas.get_dummies相反。默认情况下,除非指定了列,否则它仅将字符串列转换为一键表示。


嗨,@ nos,很抱歉延迟回复您这个问题
O.rka '16

1
除此之外,还有效率吗?
Ankit Seth

6
更新,OneHotEncoder在0.20.0版本中也不能应用于字符串。
Bs他

15
@BsHe在sklearn 0.20.3中不再适用:OneHotEncoder(sparse=False).fit_transform(pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad'])))有效,这意味着OneHotEncoder可以在stngng上应用。
dzieciou

1
您无法使用编码新的看不见的数据pd.get_dummies
绅士

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

考虑如果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

如果我们想在生产环境中处理这样的数据,那么我们一次只收到一个示例, pd.get_dummies则将不再使用。

随着sklearn.OneHotEncoder在另一方面,一旦我们已经创建了编码器,我们可以重复使用它每次都产生相同的输出,仅列的"red""green"。并且我们可以显式地控制遇到新水平时发生的情况"blue":如果我们认为这是不可能的,则可以告诉它使用handle_unknown="error";引发错误。否则,我们可以告诉它继续,只需使用即可将红色和绿色列设置为0 handle_unknown="ignore"


22
我相信这个答案比公认的影响要大得多。真正的魔力在于处理未知的分类特征,这些特征肯定会在生产中弹出。
巴克

2
我认为这是比接受的答案更好,更完整的答案。
Chiraz BenAbdelkader

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

进一步驳斥先前的评论,即Sklearn OHE由于handle_unknown而处于优等地位。使用pandas reindex可以完成相同的操作。
卡尔,

使用get_dummies可能会有一个偷偷摸摸的问题,除非是一次性运行。如果您具有drop_first = True并且下一个样本不包含删除的值,会发生什么?
造币厂

2

我真的很喜欢卡尔的回答,并对此表示支持。我将稍微扩展一下Carl的示例,以便希望更多的人欣赏pd.get_dummies可以处理未知情况。下面的两个示例表明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的示例,然后还显示不包含下降值的新数据。
薄荷
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.