【问题标题】:What are the pros and cons between get_dummies (Pandas) and OneHotEncoder (Scikit-learn)?get_dummies (Pandas) 和 OneHotEncoder (Scikit-learn) 之间的优缺点是什么?
【发布时间】:2016-08-06 11:35:39
【问题描述】:

我正在学习将分类变量转换为机器学习分类器的数值的不同方法。我遇到了pd.get_dummies 方法和sklearn.preprocessing.OneHotEncoder(),我想看看它们在性能和使用方面有何不同。

我在https://xgdgsc.wordpress.com/2015/03/20/note-on-using-onehotencoder-in-scikit-learn-to-work-on-categorical-features/ 上找到了有关如何使用OneHotEncoder() 的教程,因为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

【问题讨论】:

    标签: python pandas machine-learning scikit-learn dummy-variable


    【解决方案1】:

    对于机器学习,你几乎肯定要使用sklearn.OneHotEncoder对于其他任务,比如简单的分析,你可能可以使用pd.get_dummies,这样会更方便一些。 p>

    请注意,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 没有,这种不一致可能会在以后破坏我们的代码,特别是如果我们提供@987654340 @ 到我们在X_train 上训练的sklearn 模型。

    如果我们想在生产环境中处理这样的数据,我们一次只接收一个示例,pd.get_dummies 将没有用处。

    另一方面,使用sklearn.OneHotEncoder,一旦我们创建了编码器,我们就可以重复使用它来每次产生相同的输出,只有"red""green" 的列。而且我们可以明确控制它遇到新关卡"blue"时会发生什么:如果我们认为这是不可能的,那么我们可以告诉它用handle_unknown="error"抛出一个错误;否则我们可以告诉它继续,只需将红色和绿色列设置为 0,handle_unknown="ignore"

    【讨论】:

    • 我相信这个答案比接受的影响要大得多。真正的魔力在于处理生产中必然会出现的未知分类特征。
    • 我认为这是一个比公认的答案更好、更完整的答案。
    • 是的。恕我直言,这是一个比接受的答案更好的答案。
    • 是的。这个答案肯定更好地解释了为什么 one_hot_encoder 和一个清晰的例子可能会更好
    • 补充说明; sklearn 中还有许多其他编码器。何时使用哪个,取决于数据。 stackoverflow.com/a/63822728/5114585 可能会帮助你了解一些常见的编码器的用途
    【解决方案2】:

    OneHotEncoder 不能直接处理字符串值。如果您的标称特征是字符串,那么您需要先将它们映射成整数。

    pandas.get_dummies 正好相反。默认情况下,它只将字符串列转换为 one-hot 表示,除非指定了列。

    【讨论】:

    • 除此之外,一个比另一个更有效吗?
    • 更新,OneHotEncoder 在 0.20.0 版本中也不能应用于字符串。
    • @BsHe 在 sklearn 0.20.3 中不再适用:OneHotEncoder(sparse=False).fit_transform(pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad']))) 有效,这意味着 OneHotEncoder 可以应用于搅拌。
    • @dzieciou 适合更新。
    • 你不能用pd.get_dummies编码新的看不见的数据。
    【解决方案3】:

    您为什么不将生成的 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) 
    

    【讨论】:

    • 这如何回答这个问题?
    • more 来驳斥之前的评论,即 Sklearn OHE 因为 handle_unknown 而优越。同样可以使用 pandas reindex 来完成。
    • 使用 get_dummies 可能会出现一个偷偷摸摸的问题,除非是一次性运行。如果您有 drop_first=True 并且下一个示例不包含丢弃的值,会发生什么情况?
    【解决方案4】:

    我真的很喜欢 Carl 的回答并点赞。我将稍微扩展 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 的示例,然后还显示不包含丢弃值的新数据。
    猜你喜欢
    • 2020-11-02
    • 2020-01-25
    • 2018-11-01
    • 2016-12-28
    • 2020-02-01
    • 2017-02-25
    • 2018-07-19
    • 2011-08-31
    相关资源
    最近更新 更多