了解sklearn中的pipeline及FeatureUnions

来源:互联网 发布:淘宝5金冠店铺有哪些 编辑:程序博客网 时间:2024/06/05 02:43
        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会推出更强大的功能。



   

原创粉丝点击