【问题标题】:How to use unified pipelines on numerical and categorical features in machine learning?如何在机器学习中对数值和分类特征使用统一管道?
【发布时间】:2019-07-05 21:43:31
【问题描述】:

想在分类特征上运行编码器,在数值特征上运行 Imputer(见下文)并将它们统一在一起。
例如,具有分类特征的数值:

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,即将缺失值 / NaN 替换为 "most_frequent" / "median" / "mean" ==> Pipeline 1 。但我们想将分类特征转换为数字 / OneHotEncoding 等 ==> Pipeline 2

统一它们的最佳做法是什么?
p.s:把上面2个用分类器统一起来……(随机森林/决策树/GBM)

【问题讨论】:

    标签: python machine-learning scikit-learn


    【解决方案1】:

    显然有一个很酷的方法来做到这一点!,对于这个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 文件中,然后您可以实时使用相同的模型(生产中的预测)

    【讨论】:

    • ColumnTransformer 有一种更简单的方法
    • LabelBinarizerPipelineFriendly() 需要定义!
    【解决方案2】:

    正如@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.]])
    

    【讨论】:

      猜你喜欢
      • 2020-07-23
      • 1970-01-01
      • 2015-12-11
      • 1970-01-01
      • 1970-01-01
      • 2013-03-25
      • 2021-06-19
      • 2016-03-09
      • 2021-02-06
      相关资源
      最近更新 更多