使用 sklearn OneHotEncoder 时如何忽略数字列?
How to leave numerical columns out when using sklearn OneHotEncoder?
环境:
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.ensemble import RandomForestClassifier
示例数据:
X_train = pd.DataFrame({'A': ['a1', 'a3', 'a2'],
'B': ['b2', 'b1', 'b3'],
'C': [1, 2, 3]})
y_train = pd.DataFrame({'Y': [1,0,1]})
期望的结果:
我想以这种格式在我的管道中包含 sklearn OneHotEncoder:
encoder = ### SOME CODE ###
scaler = StandardScaler()
model = RandomForestClassifier(random_state=0)
# This is my ideal pipeline
pipe = Pipeline([('OneHotEncoder', encoder),
('Scaler', scaler),
('Classifier', model)])
pipe.fit(X_train, y_train)
挑战:
OneHotEncoder 正在对包括数字列在内的所有内容进行编码。我想保持数字列不变,并以与 Pipeline() 兼容的有效方式仅对分类特征进行编码。
encoder = OneHotEncoder(drop='first', sparse=False)
encoder.fit(X_train)
encoder.transform(X_train) # Columns C is encoded - this is what I want to avoid
解决方法(不理想):我可以使用 pd.get_dummies()
解决这个问题。但是,这意味着我不能将它包含在我的管道中。或者有什么办法吗?
X_train = pd.get_dummies(X_train, drop_first=True)
我会做的是创建我自己的自定义转换器并将其放入管道中。通过这种方式,您将对手中的数据拥有很大的权力。所以,步骤如下:
1) 创建自定义转换器 class 继承 BaseEstimator and TransformerMixin。在其 transform()
函数中,尝试检测该列的值是数字值还是分类值。如果您现在不想处理逻辑,您总是可以随时将分类列的列名称提供给 transform()
函数,然后即时提供给 select。
2)(可选)创建自定义转换器来处理仅包含分类值的列。
3)(可选)创建自定义转换器来处理仅包含数值的列。
4) 使用您创建的转换器构建两个管道(一个用于分类,另一个用于数值),您也可以使用 sklearn 中的现有转换器。
5) 用 FeatureUnion 合并两个管道。
6) 将您的大型管道与您的 ML 模型合并。
7) 调用 fit_transform()
示例代码(未实现可选):GitHub Jupyter Noteboook
我的首选解决方案是使用 sklearn 的 ColumnTransformer
(参见 here)。
它使您能够根据需要将数据分成多个组(在您的情况下,分类数据与数值数据)并对这些组应用不同的预处理操作。这个转换器可以像任何其他 sklearn 预处理工具一样在管道中使用。这是一个简短的例子:
import pandas as pd
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
X = pd.DataFrame({"a":[1,2,3],"b":["A","A","B"]})
y = np.array([0,1,1])
OHE = OneHotEncoder()
scaler = StandardScaler()
RFC = RandomForestClassifier()
cat_cols = ["b"]
num_cols = ["a"]
transformer = ColumnTransformer([('cat_cols', OHE, cat_cols),
('num_cols', scaler, num_cols)])
pipe = Pipeline([("preprocessing", transformer),
("classifier", RFC)])
pipe.fit(X,y)
注意:我已经对你的请求取得了一些许可,因为这只将缩放器应用于数字数据,我认为这更有意义?如果确实要将缩放器应用于所有列,也可以通过修改此示例来实现。
环境:
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.ensemble import RandomForestClassifier
示例数据:
X_train = pd.DataFrame({'A': ['a1', 'a3', 'a2'],
'B': ['b2', 'b1', 'b3'],
'C': [1, 2, 3]})
y_train = pd.DataFrame({'Y': [1,0,1]})
期望的结果: 我想以这种格式在我的管道中包含 sklearn OneHotEncoder:
encoder = ### SOME CODE ###
scaler = StandardScaler()
model = RandomForestClassifier(random_state=0)
# This is my ideal pipeline
pipe = Pipeline([('OneHotEncoder', encoder),
('Scaler', scaler),
('Classifier', model)])
pipe.fit(X_train, y_train)
挑战: OneHotEncoder 正在对包括数字列在内的所有内容进行编码。我想保持数字列不变,并以与 Pipeline() 兼容的有效方式仅对分类特征进行编码。
encoder = OneHotEncoder(drop='first', sparse=False)
encoder.fit(X_train)
encoder.transform(X_train) # Columns C is encoded - this is what I want to avoid
解决方法(不理想):我可以使用 pd.get_dummies()
解决这个问题。但是,这意味着我不能将它包含在我的管道中。或者有什么办法吗?
X_train = pd.get_dummies(X_train, drop_first=True)
我会做的是创建我自己的自定义转换器并将其放入管道中。通过这种方式,您将对手中的数据拥有很大的权力。所以,步骤如下:
1) 创建自定义转换器 class 继承 BaseEstimator and TransformerMixin。在其 transform()
函数中,尝试检测该列的值是数字值还是分类值。如果您现在不想处理逻辑,您总是可以随时将分类列的列名称提供给 transform()
函数,然后即时提供给 select。
2)(可选)创建自定义转换器来处理仅包含分类值的列。
3)(可选)创建自定义转换器来处理仅包含数值的列。
4) 使用您创建的转换器构建两个管道(一个用于分类,另一个用于数值),您也可以使用 sklearn 中的现有转换器。
5) 用 FeatureUnion 合并两个管道。
6) 将您的大型管道与您的 ML 模型合并。
7) 调用 fit_transform()
示例代码(未实现可选):GitHub Jupyter Noteboook
我的首选解决方案是使用 sklearn 的 ColumnTransformer
(参见 here)。
它使您能够根据需要将数据分成多个组(在您的情况下,分类数据与数值数据)并对这些组应用不同的预处理操作。这个转换器可以像任何其他 sklearn 预处理工具一样在管道中使用。这是一个简短的例子:
import pandas as pd
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
X = pd.DataFrame({"a":[1,2,3],"b":["A","A","B"]})
y = np.array([0,1,1])
OHE = OneHotEncoder()
scaler = StandardScaler()
RFC = RandomForestClassifier()
cat_cols = ["b"]
num_cols = ["a"]
transformer = ColumnTransformer([('cat_cols', OHE, cat_cols),
('num_cols', scaler, num_cols)])
pipe = Pipeline([("preprocessing", transformer),
("classifier", RFC)])
pipe.fit(X,y)
注意:我已经对你的请求取得了一些许可,因为这只将缩放器应用于数字数据,我认为这更有意义?如果确实要将缩放器应用于所有列,也可以通过修改此示例来实现。