get_dummies (Pandas) 和 OneHotEncoder (Scikit-learn) 之间的优缺点是什么?
What are the pros and cons between get_dummies (Pandas) and OneHotEncoder (Scikit-learn)?
我正在学习将机器学习分类器的分类变量转换为数值的不同方法。我遇到了 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
OneHotEncoder
不能直接处理字符串值。如果你的标称特征是字符串,那么你需要先将它们映射成整数。
pandas.get_dummies
正好相反。默认情况下,它只将字符串列转换为单热表示,除非指定列。
对于机器学习,您几乎肯定想使用 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_test
喂给我们在 X_train
.
上训练的 sklearn
模型
如果我们想在生产中像这样处理数据,我们一次只接收一个示例,pd.get_dummies
将没有用。
另一方面,对于 sklearn.OneHotEncoder
,一旦我们创建了编码器,我们就可以重复使用它来每次生成相同的输出,只有 "red"
和 [=21= 的列].我们可以明确地控制它遇到新级别 "blue"
时会发生什么:如果我们认为这是不可能的,那么我们可以告诉它用 handle_unknown="error"
抛出错误;否则我们可以告诉它继续并简单地将红色和绿色列设置为 0,handle_unknown="ignore"
.
为什么不直接将结果 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)
我非常喜欢 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.]])
我正在学习将机器学习分类器的分类变量转换为数值的不同方法。我遇到了 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
OneHotEncoder
不能直接处理字符串值。如果你的标称特征是字符串,那么你需要先将它们映射成整数。
pandas.get_dummies
正好相反。默认情况下,它只将字符串列转换为单热表示,除非指定列。
对于机器学习,您几乎肯定想使用 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_test
喂给我们在 X_train
.
sklearn
模型
如果我们想在生产中像这样处理数据,我们一次只接收一个示例,pd.get_dummies
将没有用。
另一方面,对于 sklearn.OneHotEncoder
,一旦我们创建了编码器,我们就可以重复使用它来每次生成相同的输出,只有 "red"
和 [=21= 的列].我们可以明确地控制它遇到新级别 "blue"
时会发生什么:如果我们认为这是不可能的,那么我们可以告诉它用 handle_unknown="error"
抛出错误;否则我们可以告诉它继续并简单地将红色和绿色列设置为 0,handle_unknown="ignore"
.
为什么不直接将结果 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)
我非常喜欢 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.]])