了解sklearn中的pipeline及FeatureUnions

        pipeline模块是sklearn中一个可以让你链式操作系一列transformer和estimators的单元。当你需要做一系列数据提取、变换、规则化和训练的操作时往往是非常麻烦的。

       第一次参加一些数据竞赛,我会经常以以下的代码模式起手。 

_file('data/train.tsv')
train_y = extract_targets(train)
train_essays = extract_essays(train)
train_tokens = get_tokens(train_essays)
train_features = extract_feactures(train)
classifier = MultinomialNB()

scores = []
train_idx, cv_idx in KFold():
  classifier.fit(train_features[train_idx], train_y[train_idx])
  scores.append(model.score(train_features[cv_idx], train_y[cv_idx]))

print("Score: {}".format(np.mean(scores)))

       通常情况下,在第一次提交的时候会得到一个不错的分数,但是为了进一步提高分数,我通常会尝试提取更多的特征。

比如说文本n-gram计数,

       我想用tf-idf特征。另外,我想增加文章的长度特征,最好能把拼写错误的字数也做为一个特征。这样的话,我干脆把这些都打包成一个extract_features函数,可以提取一篇文章中的三个特征矩阵,然后将这三个矩阵在数轴1上进行合并。

    在提取完了特征以后,我发现我又做了很多normalize和scale的操作,我的代码会变的非常长,虽然我自己仍然能理解。


pipelines

  使用pipeline来简化上述流程。下面的例子提取了文档,进行了分词统计,tfidf计算,最后输入了一个分类器。

pipeline = Pipeline([
  ('extract_essays', EssayExractor()),
  ('counts', CountVectorizer()),
  ('tf_idf', TfidfTransformer()),
  ('classifier', MultinomialNB())
])

train = read_file('data/train.tsv')
train_y = extract_targets(train)
scores = []
train_idx, cv_idx in KFold():
  model.fit(train[train_idx], train_y[train_idx])
  scores.append(model.score(train[cv_idx], train_y[cv_idx]))

print("Score: {}".format(np.mean(scores)))

 pipeline就像一个线性的流水线,数据流入后经过每一步加工处理,最终达到我指定的分类器。


FeatureUnions

  正如我之前所说,我想提取更多的特征,那就意味着并行处理进来的数据,最后对结果进行合并。
  使用FeatureUnion可以对这些并行流程进行建模。
pipeline = Pipeline([
  ('extract_essays', EssayExractor()),
  ('features', FeatureUnion([
    ('ngram_tf_idf', Pipeline([
      ('counts', CountVectorizer()),
      ('tf_idf', TfidfTransformer())
    ])),
    ('essay_length', LengthTransformer()),
    ('misspellings', MispellingCountTransformer())
  ])),
  ('classifier', MultinomialNB())
])
在这个例子里,文章提取后进入了三个并行的处理流程:ngram_tf_idf、essay_length、misspellings,然后将三个合并起来输入到分类器。


通常情况下,我会用好几个pipeplines和featureunions来建立一个模型。例如下面就是一个很庞大的流水线
pipeline = Pipeline([
    ('features', FeatureUnion([
        ('continuous', Pipeline([
            ('extract', ColumnExtractor(CONTINUOUS_FIELDS)),
            ('scale', Normalizer())
        ])),
        ('factors', Pipeline([
            ('extract', ColumnExtractor(FACTOR_FIELDS)),
            ('one_hot', OneHotEncoder(n_values=5)),
            ('to_dense', DenseTransformer())
        ])),
        ('weekday', Pipeline([
            ('extract', DayOfWeekTransformer()),
            ('one_hot', OneHotEncoder()),
            ('to_dense', DenseTransformer())
        ])),
        ('hour_of_day', HourOfDayTransformer()),
        ('month', Pipeline([
            ('extract', ColumnExtractor(['datetime'])),
            ('to_month', DateTransformer()),
            ('one_hot', OneHotEncoder()),
            ('to_dense', DenseTransformer())
        ])),
        ('growth', Pipeline([
            ('datetime', ColumnExtractor(['datetime'])),
            ('to_numeric', MatrixConversion(int)),
            ('regression', ModelTransformer(LinearRegression()))
        ]))
    ])),
    ('estimators', FeatureUnion([
        ('knn', ModelTransformer(KNeighborsRegressor(n_neighbors=5))),
        ('gbr', ModelTransformer(GradientBoostingRegressor())),
        ('dtr', ModelTransformer(DecisionTreeRegressor())),
        ('etr', ModelTransformer(ExtraTreesRegressor())),
        ('rfr', ModelTransformer(RandomForestRegressor())),
        ('par', ModelTransformer(PassiveAggressiveRegressor())),
        ('en', ModelTransformer(ElasticNet())),
        ('cluster', ModelTransformer(KMeans(n_clusters=2)))
    ])),
    ('estimator', KNeighborsRegressor())
])

定制化的Transformers

       在前面的例子中包含了很多tansformer并不是来自sklearn。所有的ColumnExtractor、DenseTransformer和ModelTransformer都是我自己写的。
一个Transformer就是一个包含fit、transform和fit_transform的object,包括内建的transformer(如MinMaxScaler),Pipelines,FeatureUnions。
       当然,实现了上述方法的老python对象也是一种transformer。并不一定需要继承自TransformerMixin,但是那样比较方便。


      一个transformer可以想象成是一个数据进入、数据输出的黑盒子。他会接受一个矩阵作为输入,然后返回一个相同尺寸的矩阵作为输出。这样就可以方便的记录和二次处理。但是,我通常使用pandas的DataFrames,希望输入一个dataframe到tansformer里来。例如,ColumnExtractor是一个从dataframe提取column的transformer.


       有时tansformer可以非常简单,比如HourOfDay transformer,仅仅从datatime对象中提取出了小时的部分,这种事无状态的,他们不需要被fit,所以fit都是空操作。
class HourOfDayTransformer(TransformerMixin):

    def transform(self, X, **transform_params):
        hours = DataFrame(X['datetime'].apply(lambda x: x.hour))
        return hours

    def fit(self, X, y=None, **fit_params):
        return self


        但是,有时候tansformer也需要被fit。看一下ModelTransformer.我用它来包裹sklearn的模型,使他的行为像一个transformer。如果你想用kmeans聚类模型为其他模型产生特征,那么这将会非常有用。
class ModelTransformer(TransformerMixin):

    def __init__(self, model):
        self.model = model

    def fit(self, *args, **kwargs):
        self.model.fit(*args, **kwargs)
        return self

    def transform(self, X, **transform_params):
        return DataFrame(self.model.predict(X))
pipeline会像内建的transformer一样对待这些自己写的transformer。

   

        利用pipeline和featureunion,可以帮助对机器学习的建模流程进行统一化处理。当然目前的pipeline还有很多不足,比如没有办法对指定列进行处理,这在大型工程中是很伤的。期待pipeline会推出更强大的功能。



   

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值