想要在分类特征上运行编码器,在数字特征上运行Imputter(见下文),并将它们统一在一起
例如,具有分类特征的Numerical:
df_with_cat = pd.DataFrame({
'A' : ['ios', 'android', 'web', 'NaN'],
'B' : [4, 4, 'NaN', 2],
'target' : [1, 1, 0, 0]
})
df_with_cat.head()
A B target
----------------------
0 ios 4 1
1 android 4 1
2 web NaN 0
3 NaN 2 0
我们希望对数值特征运行Imputer,即用"most_frequency"/"median"/"mean"===>管道1替换缺失值/NaN。但我们希望将分类特征转换为数字/OneHotEncoding etc=>Pipeline 2
统一它们的最佳做法是什么
p.s:将以上2个与分类器统一。。。(随机森林/决策树/GBM)
正如@Sergey Bushmanov所提到的,ColumnTransformer可以用来实现同样的功能。
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
df = pd.DataFrame({
'A' : ['ios', 'android', 'web', 'NaN'],
'B' : [4, 4, 'NaN', 2],
'target' : [1, 1, 0, 0]
})
categorical_features = ['A']
numeric_features = ['B']
TARGET = ['target']
df[numeric_features]=df[numeric_features].replace('NaN', np.NaN)
columnTransformer = ColumnTransformer(
transformers=[
('cat', OneHotEncoder(), categorical_features),
('num', SimpleImputer( strategy='most_frequent'), numeric_features)])
columnTransformer.fit_transform(df)
#
array([[0., 0., 1., 0., 4.],
[0., 1., 0., 0., 4.],
[0., 0., 0., 1., 4.],
[1., 0., 0., 0., 2.]])
显然有一种很酷的方法!,对于这个df:
df_with_cat = pd.DataFrame({
'A' : ['ios', 'android', 'web', 'NaN'],
'B' : [4, 4, 'NaN', 2],
'target' : [1, 1, 0, 0]
})
如果您不介意将sklearn升级到0.20.2
,请运行:
pip3 install scikit-learn==0.20.2
并使用此解决方案(如@AI_learning所建议的):
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
columnTransformer = ColumnTransformer(
transformers=[
('cat', OneHotEncoder(), CATEGORICAL_FEATURES),
('num', Imputer( strategy='most_frequent'), NUMERICAL_FEATURES)
])
然后:
columnTransformer.fit(df_with_cat)
但如果你使用的是早期的sklearn版本,请使用以下版本:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import Imputer
from sklearn.preprocessing import LabelBinarizer, LabelEncoder
CATEGORICAL_FEATURES = ['A']
NUMERICAL_FEATURES = ['B']
TARGET = ['target']
numerical_pipline = Pipeline([
('selector', DataFrameSelector(NUMERICAL_FEATURES)),
('imputer', Imputer(strategy='most_frequent'))
])
categorical_pipeline = Pipeline([
('selector', DataFrameSelector(CATEGORICAL_FEATURES)),
('cat_encoder', LabelBinarizerPipelineFriendly())
])
如果你注意到我们错过了DataFrameSelector
,它不是sklearn
的一部分,所以让我们把它写在这里:
from sklearn.base import BaseEstimator, TransformerMixin
class DataFrameSelector(BaseEstimator, TransformerMixin):
def __init__(self, attribute_names):
self.attribute_names = attribute_names
def fit(self, X, y=None):
return self
def transform(self, X):
return X[self.attribute_names].values
让我们统一他们:
from sklearn.pipeline import FeatureUnion, make_pipeline
preprocessing_pipeline = FeatureUnion(transformer_list=[
('numerical_pipline', numerical_pipline),
('categorical_pipeline', categorical_pipeline)
])
就是这样,现在让我们运行:
preprocessing_pipeline.fit_transform(df_with_cat[CATEGORICAL_FEATURES+NUMERICAL_FEATURES])
现在让我们更疯狂!将它们与分类器管道统一起来:
from sklearn import tree
clf = tree.DecisionTreeClassifier()
full_pipeline = make_pipeline(preprocessing_pipeline, clf)
一起训练他们:
full_pipeline.fit(df_with_cat[CATEGORICAL_FEATURES+NUMERICAL_FEATURES], df_with_cat[TARGET])
只需打开一个Jupyter笔记本,取出代码片段,自己尝试一下!
以下是LabelBinarizerPipelineFriendly()的定义:
class LabelBinarizerPipelineFriendly(LabelBinarizer):
'''
Wrapper to LabelBinarizer to allow usage in sklearn.pipeline
'''
def fit(self, X, y=None):
"""this would allow us to fit the model based on the X input."""
super(LabelBinarizerPipelineFriendly, self).fit(X)
def transform(self, X, y=None):
return super(LabelBinarizerPipelineFriendly, self).transform(X)
def fit_transform(self, X, y=None):
return super(LabelBinarizerPipelineFriendly, self).fit(X).transform(X)
这种方法的主要优点是,您可以将经过训练的模型和所有管道转储到pkl文件中,然后您可以实时使用相同的(生产中的预测)