get_dummies(Pandas)和OneHotEncoder(Scikit-learn)之间的优缺点是什么?

2admgd59  于 2023-03-16  发布在  其他
关注(0)|答案(5)|浏览(165)

我正在学习机器学习分类器将分类变量转换为数值的不同方法,我遇到了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.dummiessklearn.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
1tu0hz3e

1tu0hz3e1#

**对于机器学习,您几乎肯定要使用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将以X_train没有的额外"color_blue"列结束,并且这种不一致性可能会在稍后破坏我们的代码,特别是如果我们将X_test提供给我们在X_train上训练的sklearn模型。
如果我们想在生产环境中处理这样的数据,一次只接收一个示例,pd.get_dummies就没有用处了。
另一方面,对于sklearn.OneHotEncoder,一旦我们创建了编码器,我们就可以重用它,每次都产生相同的输出,列只用于"red""green",并且我们可以显式地控制当它遇到新级别"blue"时会发生什么:如果我们认为这是不可能,那么我们可以告诉它抛出一个错误:handle_unknown="error";否则,我们可以告诉它继续,并简单地将红色和绿色列设置为0,handle_unknown="ignore"

2hh7jdfx

2hh7jdfx2#

OneHotEncoder不能直接处理字符串值。如果你的名义特征是字符串,那么你需要先将它们Map成整数。
pandas.get_dummies正好相反,默认情况下,它只将字符串列转换为一个热码表示,除非指定了列。

zmeyuzjn

zmeyuzjn3#

我真的很喜欢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.]])
zqry0prt

zqry0prt4#

您为什么不将生成的get_dummies中的列缓存或保存为变量col_list,然后使用pd.reindex对齐train与test数据集....示例:

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)
wa7juj8i

wa7juj8i5#

这个问题很早以前就被问到了,但在2023年依然相关。
一句话:两者都可以用于任务,选择哪一个取决于个人喜好和其他情况。
更详细地说:

  • 对于OneHotEncoder和get_dummies,显式指定类别是可能的,也是最可靠的方法。对于OneHotEncoder,可以使用“categories”参数来实现,该参数是列表的列表。对于get_dummies,您需要将相关列转换为具有适当类别的分类。
  • OneHotEncoder假设您要对数据中的所有列进行编码,因此如果不是这种情况,您必须手动选择/transform/join-with-original-columns或将OneHotEncoder Package 在列转换器中。
  • 如果您喜欢在数据处理管道期间停留在DataFrame空间中,那么pandas.get_dummies是最直接的方法,但如果您依赖于scikit Pipeline-s,那么 Package 在列转换器中的OneHotEncoder更直接。

有关示例的完整说明,请阅读my article on towards data science.

相关问题