Pipeline

 

目录

1 使用sklearn进行数据挖掘

1.1 数据挖掘的步骤

1.2 数据初貌

1.3 关键技术

2 Pipeline的作用

3 Pipeline的参数与使用

3.1 function

3.2 用法(例子)

3.3 示例

3.3.1 Pipeline的调用

3.3.2 Pipeline参数改变

3.3.3 Pipeline与GridSearch

4 FeatureUnion的作用

4.1 整体并行处理

4.2 部分并行处理

4.3 示例

4.3.1 FeatureUnion的调用

4.3.2 FeatureUnion的参数变更

5 FeatureUnion与pipeline的结合使用


1 使用sklearn进行数据挖掘

1.1 数据挖掘的步骤

        数据挖掘通常包括数据采集数据分析特征工程训练模型模型评估等步骤。使用sklearn工具可以方便地进行特征工程和模型训练工作,在《使用sklearn做单机特征工程》中,最后留下了一些疑问:特征处理类都有三个方法fittransformfit_transformfit方法居然和模型训练方法fit同名(不光同名,参数列表都一样),这难道都是巧合?

        显然,这不是巧合,这正是sklearn的设计风格。我们能够更加优雅地使用sklearn进行特征工程和模型训练工作。此时,不妨从一个基本的数据挖掘场景入手:

        Pipeline_第1张图片

       我们使用sklearn进行虚线框内的工作(sklearn也可以进行文本特征提取)。通过分析sklearn源码,我们可以看到除训练,预测和评估以外,处理其他工作的类都实现了3个方法:fit、transform和fit_transform。从命名中可以看到,fit_transform方法是先调用fit然后调用transform,我们只需要关注fit方法和transform方法即可。

        transform方法主要用来对特征进行转换。从可利用信息的角度来说,转换分为无信息转换有信息转换。无信息转换是指不利用任何其他信息进行转换,比如指数、对数函数转换等。有信息转换从是否利用目标值向量又可分为无监督转换和有监督转换。无监督转换指只利用特征的统计信息的转换,统计信息包括均值、标准差、边界等等,比如标准化、PCA法降维等。有监督转换指既利用了特征信息又利用了目标值信息的转换,比如通过模型选择特征、LDA法降维等。

Pipeline_第2张图片

        通过总结常用的转换类,我们得到下表:

参数列表 类别 fit方法有用 说明
sklearn.preprocessing StandardScaler 特征 无监督 Y 标准化
sklearn.preprocessing MinMaxScaler 特征 无监督 Y 区间缩放
sklearn.preprocessing Normalizer 特征 无信息 N 归一化
sklearn.preprocessing Binarizer 特征 无信息 N 定量特征二值化
sklearn.preprocessing OneHotEncoder 特征 无监督 Y 定性特征编码
sklearn.preprocessing Imputer 特征 无监督 Y 缺失值计算
sklearn.preprocessing PolynomialFeatures 特征 无信息 N 多项式变换(fit方法仅仅生成了多项式的表达式)
sklearn.preprocessing FunctionTransformer 特征 无信息 N 自定义函数变换(自定义函数在transform方法中调用)
sklearn.feature_selection VarianceThreshold 特征 无监督 Y 方差选择法
sklearn.feature_selection SelectKBest 特征/特征+目标值 无监督/有监督 Y 自定义特征评分选择法
sklearn.feature_selection SelectKBest+chi2 特征+目标值 有监督 Y 卡方检验选择法
sklearn.feature_selection RFE 特征+目标值 有监督 Y 递归特征消除法
sklearn.feature_selection SelectFromModel 特征+目标值 有监督 Y 自定义模型训练选择法
sklearn.decomposition PCA 特征 无监督 Y PCA降维
sklearn.lda LDA 特征+目标值 有监督 Y LDA降维

        不难看到,只有有信息的转换类的fit方法才实际有用,显然fit方法的主要工作是获取特征信息和目标值信息,在这点上,fit方法和模型训练时的fit方法就能够联系在一起了:都是通过分析特征和目标值,提取有价值的信息,对于转换类来说是某些统计量,对于模型来说可能是特征的权值系数等。另外,只有有监督的转换类的fit和transform方法才需要特征和目标值两个参数。fit方法无用不代表其没实现,而是除合法性校验以外,其并没有对特征和目标值进行任何处理,Normalizer的fit方法实现如下:

def fit(self, X, y=None):
    """Do nothing and return the estimator unchanged
        This method is just there to implement the usual API and hence
        work in pipelines.
    """
    X = check_array(X, accept_sparse='csr')
    return self

        基于这些特征处理工作都有共同的方法,那么试想可不可以将他们组合在一起?在本文假设的场景中,我们可以看到这些工作的组合形式有两种:流水线式和并行式。基于流水线组合的工作需要依次进行,前一个工作的输出是后一个工作的输入;基于并行式的工作可以同时进行,其使用同样的输入,所有工作完成后将各自的输出合并之后输出。sklearn提供了包pipeline来完成流水线式和并行式的工作

1.2 数据初貌

        在此,我们仍然使用IRIS数据集来进行说明。为了适应提出的场景,对原数据集需要稍微加工:

from numpy import hstack, vstack, array, median, nan
from numpy.random import choice
from sklearn.datasets import load_iris

#特征矩阵加工
#使用vstack增加一行含缺失值的样本(nan, nan, nan, nan)
#使用hstack增加一列表示花的颜色(0-白、1-黄、2-红),花的颜色是随机的,意味着颜色并不影响花的分类
iris.data = hstack((choice([0, 1, 2], size=iris.data.shape[0]+1).reshape(-1,1), vstack((iris.data, array([nan, nan, nan, nan]).reshape(1,-1)))))
#目标值向量加工
#增加一个目标值,对应含缺失值的样本,值为众数
iris.target = hstack((iris.target, array([median(iris.target)])))

1.3 关键技术

  并行处理流水线处理自动化调参持久化是使用sklearn优雅地进行数据挖掘的核心。并行处理流水线处理将多个特征处理工作,甚至包括模型训练工作组合成一个工作(从代码的角度来说,即将多个对象组合成了一个对象)。在组合的前提下,自动化调参技术帮我们省去了人工调参的反锁。训练好的模型是贮存在内存中的数据,持久化能够将这些数据保存在文件系统中,之后使用时无需再进行训练,直接从文件系统中加载即可。

2 Pipeline的作用

        Pipeline可以将许多算法模型串联起来,可以用于把多个estamitors级联成一个estamitor,比如将特征提取、归一化、分类组织在一起形成一个典型的机器学习问题工作流。Pipleline中最后一个之外的所有estimators都必须是变换器(transformers),最后一个estimator可以是任意类型(transformer,classifier,regresser),若最后一个estimator是个分类器,则整个pipeline就可以作为分类器使用,如果最后一个estimator是个聚类器,则整个pipeline就可以作为聚类器使用。
  实际上,调用pipeline的fit方法,是用前n-1个变换器处理特征,之后传递给最后的estimator训练。pipeline继承最后一个estimator的所有方法。

        由此带来两点直接好处:

  • 1.直接调用fitpredict方法来对pipeline中的所有算法模型进行训练和预测。
  • 2.可以结合grid search对参数进行选择。

3 Pipeline的参数与使用

3.1 function

        Pipeline的方法都是执行各个学习器中对应的方法,如果该学习器没有该方法,会报错,假设该Pipeline共有n个学习器。

  • transform,依次执行各个学习器的transform方法
  • inverse_transform,依次执行各个学习器的inverse_transform方法
  • fit,依次对前n-1个学习器执行fittransform方法,第n个学习器(最后一个学习器)执行fit方法
  • predict,执行前n-1个学习器的transform方法和执行第n个学习器的predict方法
  • score,执行前n-1个学习器的transform方法和第n个学习器的score方法
  • set_params,设置第n个学习器的参数
  • get_param,获取第n个学习器的参数

3.2 用法(例子)

步骤:1.首先对数据进行预处理,比如缺失值的处理
       2.数据的标准化
       3.降维
       4.特征选择算法
       5.分类或者预测或者聚类算法(估计器,estimator)

Pipeline_第3张图片

3.3 示例

3.3.1 Pipeline的调用

        Pipeline是使用(key, value)对的列表构建的,其中key是包含要给予此步骤的名称的字符串,value是对应的不同学习器。

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
iris=load_iris()
pipe=Pipeline([('sc', StandardScaler()),('pca',PCA()),('svc',SVC())])
#例如‘sc’是StandardScaler()的简称,亦或者是代称
pipe.fit(iris.data,iris.target)

输出:

Pipeline(memory=None,
     steps=[('sc', StandardScaler(copy=True, with_mean=True, with_std=True)), ('pca', PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
  svd_solver='auto', tol=0.0, whiten=False)), ('svc', SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
  kernel='rbf', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False))])

        其次可以通过make_pipeline函数实现pipeline的调用:它是Pipeline类的简单实现,只需传入每个step的类实例即可,不需自己命名,自动将类的小写设为该step的名:

from sklearn.linear_model import ElasticNet, Lasso,  BayesianRidge, LassoLarsIC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import RobustScaler #用来解决离群点
new_pipeline=make_pipeline(RobustScaler(), Lasso(alpha =0.0005, random_state=1))

输出:

Pipeline(memory=None,
     steps=[('robustscaler', RobustScaler(copy=True, quantile_range=(25.0, 75.0), with_centering=True,
       with_scaling=True)), ('lasso', Lasso(alpha=0.0005, copy_X=True, fit_intercept=True, max_iter=1000,
   normalize=False, positive=False, precompute=False, random_state=1,
   selection='cyclic', tol=0.0001, warm_start=False))])

3.3.2 Pipeline参数改变

        可以通过set_params重新设置每个类里边需传入的参数,设置方法为step的name__parma=参数值:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
iris=load_iris()
pipe=Pipeline([('sc', StandardScaler()),('pca',PCA()),('svc',SVC())])
#例如‘sc’是StandardScaler()的简称,亦或者是代称
    
pipe.set_params(sc__copy=False)
#改变参数的格式为   学习器简称__该学习器对应参数名=参数值
pipe.fit(iris.data,iris.target)

3.3.3 Pipeline与GridSearch

        模型调参利器 gridSearchCV(网格搜索):https://blog.csdn.net/weixin_41988628/article/details/83098130

        GridSearchCV,它存在的意义就是自动调参,只要把参数输进去,就能给出最优化的结果和参数。但是这个方法适合于小数据集,一旦数据的量级上去了,很难得出结果。这个时候就是需要动脑筋了。数据量比较大的时候可以使用一个快速调优的方法——坐标下降。它其实是一种贪心算法:拿当前对模型影响最大的参数调优,直到最优化;再拿下一个影响最大的参数调优,如此下去,直到所有的参数调整完毕。这个方法的缺点就是可能会调到局部最优而不是全局最优,但是省时间省力,巨大的优势面前,还是试一试吧,后续可以再拿bagging再优化。

       通常算法不够好,需要调试参数时必不可少。比如SVM的惩罚因子C,核函数kernel,gamma参数等,对于不同的数据使用不同的参数,结果效果可能差1-5个点,sklearn为我们提供专门调试参数的函数grid_search。

        举例为pipeline与GridSearch在pca与svc中的使用:

from sklearn.model_selection import GridSearchCV
#以下格式为  学习器简写__该学习器对应的某个参数名=可选参数值范围
params = dict(pca__n_components=[2, 5, 10],
              svc__C=[0.1, 10, 100])
grid_search = GridSearchCV(pipe, param_grid=params)       

4 FeatureUnion的作用

        FeatureUnion把若干个transformer object组合成一个新的estimators。这个新的transformer组合了他们的输出,一个FeatureUnion对象接受一个transformer对象列表。

        在训练阶段,每一个transformer都在数据集上独立的训练。在数据变换阶段,多有的训练好的Trandformer可以并行的执行。他们输出的样本特征向量被以end-to-end的方式拼接成为一个更大的特征向量

  • 你只需要调用一次fit和transform就可以在数据集上训练一组estimators。
  • 可以把grid search用在FeatureUnion中所有的estimators的参数这上面。

        FeatureUnionPipeline可以组合使用来创建更加复杂的模型。

        注意:FeatureUnion无法检查两个transformers是否产生了相同的特征输出,它仅仅产生了一个原来互相分离的特征向量的集合。确保其产生不一样的特征输出是调用者的事情。

 

FeatureUnionpipeline的区别

  • pipeline相当于feature串行处理,后一个transformer处理前一个transformer的feature结果;
  • featureunion相当于feature的并行处理,将所有transformer的处理结果拼接成大的feature vector。

 

        并行处理使得多个特征处理工作能够并行地进行。根据对特征矩阵的读取方式不同,可分为整体并行处理部分并行处理

  • 整体并行处理,即并行处理的每个工作的输入都是特征矩阵的整体;
  • 部分并行处理,即可定义每个工作需要输入的特征矩阵的列。

4.1 整体并行处理

  pipeline包提供了FeatureUnion类来进行整体并行处理:

from numpy import log1p
from sklearn.preprocessing import FunctionTransformer
from sklearn.preprocessing import Binarizer
from sklearn.pipeline import FeatureUnion

#新建将整体特征矩阵进行对数函数转换的对象
step2_1 = ('ToLog', FunctionTransformer(log1p))
#新建将整体特征矩阵进行二值化类的对象
step2_2 = ('ToBinary', Binarizer())
#新建整体并行处理对象
#该对象也有fit和transform方法,fit和transform方法均是并行地调用需要并行处理的对象的fit和transform方法
#参数transformer_list为需要并行处理的对象列表,该列表为二元组列表,第一元为对象的名称,第二元为对象
step2 = ('FeatureUnion', FeatureUnion(transformer_list=[step2_1, step2_2, step2_3]))

4.2 部分并行处理

        整体并行处理有其缺陷,在一些场景下,我们只需要对特征矩阵的某些列进行转换,而不是所有列。pipeline并没有提供相应的类(仅OneHotEncoder类实现了该功能),需要我们在FeatureUnion的基础上进行优化:

from sklearn.pipeline import FeatureUnion, _fit_one_transformer, _fit_transform_one, _transform_one
from sklearn.externals.joblib import Parallel, delayed
from scipy import sparse
import numpy as np

#部分并行处理,继承FeatureUnion
class FeatureUnionExt(FeatureUnion):
    #相比FeatureUnion,多了idx_list参数,其表示每个并行工作需要读取的特征矩阵的列
    def __init__(self, transformer_list, idx_list, n_jobs=1, transformer_weights=None):
        self.idx_list = idx_list
        FeatureUnion.__init__(self, transformer_list=map(lambda trans:(trans[0], trans[1]), transformer_list), n_jobs=n_jobs, transformer_weights=transformer_weights)

    #由于只部分读取特征矩阵,方法fit需要重构
    def fit(self, X, y=None):
        transformer_idx_list = map(lambda trans, idx:(trans[0], trans[1], idx), self.transformer_list, self.idx_list)
        transformers = Parallel(n_jobs=self.n_jobs)(
            #从特征矩阵中提取部分输入fit方法
            delayed(_fit_one_transformer)(trans, X[:,idx], y)
            for name, trans, idx in transformer_idx_list)
        self._update_transformer_list(transformers)
        return self

    #由于只部分读取特征矩阵,方法fit_transform需要重构
    def fit_transform(self, X, y=None, **fit_params):
        transformer_idx_list = map(lambda trans, idx:(trans[0], trans[1], idx), self.transformer_list, self.idx_list)
        result = Parallel(n_jobs=self.n_jobs)(
            #从特征矩阵中提取部分输入fit_transform方法
            delayed(_fit_transform_one)(trans, name, X[:,idx], y,
                                        self.transformer_weights, **fit_params)
            for name, trans, idx in transformer_idx_list)

        Xs, transformers = zip(*result)
        self._update_transformer_list(transformers)
        if any(sparse.issparse(f) for f in Xs):
            Xs = sparse.hstack(Xs).tocsr()
        else:
            Xs = np.hstack(Xs)
        return Xs

    #由于只部分读取特征矩阵,方法transform需要重构
    def transform(self, X):
        transformer_idx_list = map(lambda trans, idx:(trans[0], trans[1], idx), self.transformer_list, self.idx_list)
        Xs = Parallel(n_jobs=self.n_jobs)(
            #从特征矩阵中提取部分输入transform方法
            delayed(_transform_one)(trans, name, X[:,idx], self.transformer_weights)
            for name, trans, idx in transformer_idx_list)
        if any(sparse.issparse(f) for f in Xs):
            Xs = sparse.hstack(Xs).tocsr()
        else:
            Xs = np.hstack(Xs)
        return Xs

        在本文提出的场景中,我们对特征矩阵的第1列(花的颜色)进行定性特征编码,对第2、3、4列进行对数函数转换,对第5列进行定量特征二值化处理。使用FeatureUnionExt类进行部分并行处理的代码如下:

from numpy import log1p
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import FunctionTransformer
from sklearn.preprocessing import Binarizer

#新建将部分特征矩阵进行定性特征编码的对象
step2_1 = ('OneHotEncoder', OneHotEncoder(sparse=False))
#新建将部分特征矩阵进行对数函数转换的对象
step2_2 = ('ToLog', FunctionTransformer(log1p))
#新建将部分特征矩阵进行二值化类的对象
step2_3 = ('ToBinary', Binarizer())
#新建部分并行处理对象
#参数transformer_list为需要并行处理的对象列表,该列表为二元组列表,第一元为对象的名称,第二元为对象
#参数idx_list为相应的需要读取的特征矩阵的列
step2 = ('FeatureUnionExt', FeatureUnionExt(transformer_list=[step2_1, step2_2, step2_3], idx_list=[[0], [1, 2, 3], [4]]))

4.3 示例

4.3.1 FeatureUnion的调用

        FeatureUnion对象实例使用(key, value)构成的list来构造,key是你自己起的transformation的名称,value是一个estimator对象。

from sklearn.pipeline import FeatureUnion
from sklearn.decomposition import PCA
from sklearn.decomposition import KernelPCA
estimators = [('linear_pca', PCA()), ('kernel_pca', KernelPCA())]
combined = FeatureUnion(estimators)

4.3.2 FeatureUnion的参数变更

from sklearn.pipeline import FeatureUnion
from sklearn.decomposition import PCA
from sklearn.decomposition import KernelPCA
estimators = [('linear_pca', PCA()), ('kernel', KernelPCA())]
combined = FeatureUnion(estimators)
combined.set_params(kernel__alpha=0.6)##注意这里是两个下划线不然会报错
print(combined)

5 FeatureUnion与pipeline的结合使用

# Author: Andreas Mueller 
#
# License: BSD 3 clause

from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.grid_search import GridSearchCV
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.feature_selection import SelectKBest

iris = load_iris()

X, y = iris.data, iris.target

# This dataset is way to high-dimensional. Better do PCA:
pca = PCA(n_components=2)

# Maybe some original features where good, too?
selection = SelectKBest(k=1)

# Build estimator from PCA and Univariate selection:

combined_features = FeatureUnion([("pca", pca), ("univ_select", selection)])

# Use combined features to transform dataset:
X_features = combined_features.fit(X, y).transform(X)

svm = SVC(kernel="linear")

# Do grid search over k, n_components and C:

pipeline = Pipeline([("features", combined_features), ("svm", svm)])

param_grid = dict(features__pca__n_components=[1, 2, 3],
                  features__univ_select__k=[1, 2],
                  svm__C=[0.1, 1, 10])

grid_search = GridSearchCV(pipeline, param_grid=param_grid, verbose=10)
grid_search.fit(X, y)
print(grid_search.best_estimator_)

 

 

 

 

 

sklearn.pipeline.Pipeline:https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html

使用sklearn优雅地进行数据挖掘:https://www.cnblogs.com/jasonfreak/p/5448462.html

sklearn :Pipeline 与 FeatureUnion入门指南:https://blog.csdn.net/qq_35992440/article/details/89918305

你可能感兴趣的:(机器学习,机器学习)