Pipeline 深入解读及实验

2024-01-01  本文已影响0人  马尔代夫Maldives

一、Pipeline基本知识

Pipeline 对象将不同计算步骤串联起来执行,方便、快速、统一、保险!

构造一个Pipeline对象时,需要输入一个由多个二元tuple构成的list,每个tuple的第一个元素可以是任意自定义字符串,第二元素表示一个已经存在的计算步骤,例:
my_steps = [(name1, algo1), (name2, algo2), (name3, algo3)...] # 定义计算步骤list
pipe = Pipline(step=my_steps) # 生成Pipline对象

这些计算步骤(algo)通常有3种类型:变换器(transformer)估计器(estimator)'passthrough'

Pipeline的使用方法:

二、Pipeline内部计算过程窥探(包括一些结论)

下面我们自定义两个变换器(实际上也是估计器,因为我们都定义了predict()函数),并组成Pipeline,来窥探其内部执行过程!

import numpy as np
from sklearn.base import TransformerMixin, BaseEstimator
from sklearn.pipeline import Pipeline

定义变换器:

说明:我们用 self.flag 变量来代表‘计算参数S’,即fit(X)根据输入X计算得到的。

# 自定义变换器1
class T1(BaseEstimator, TransformerMixin):
    def __init__(self):
        self.flag = 'T1原始参数S1_old!'

    def fit(self, X, y=None):
        self.flag = 'T1 fit() 计算的新参数S1_new!'
        print(f'Run T1 fit(), 输入X={X},计算并保存新参数S1_new!')
        return self

    def transform(self, X, y=None):
        print(f'Run T1 transform(), 输入X={X}, 用 {self.flag}')
        return X*2
    
    def predict(self, X):
         print(f'Run T1 predict(), 输入X={X}, 用 {self.flag}')

# 自定义变换器2
class T2(BaseEstimator, TransformerMixin):
    
    def __init__(self):
        self.flag = '原始参数S2_old!'

    def fit(self, X, y=None):
        self.flag = 'T2 fit() 计算的新参数S2_new!'
        print(f'Run T2 fit(), 输入X={X},计算并保存新参数S2_new!')
        return self

    def transform(self, X, y=None):
        print(f'Run T2 transform(), 输入X={X}, 用 {self.flag}')
        return X*4
    
    def predict(self, X):
         print(f'Run T2 predict(), 输入X={X}, 用 {self.flag}')

例1:pipe.fit()→pipe.transform()→pipe.predict()

X = np.array([1,2,3,4,5])  # 数据准备

pipe = Pipeline([('name1', T1()), ('name2', T2())]) # 生成Pipline对象

pipe.fit(X)
print('#######################################分割线1################################################')
result = pipe.transform(X)
print(result)
print('#######################################分割线2################################################')
pipe.predict(X)

输出:
Run T1 fit(), 输入X=[1 2 3 4 5],计算并保存新参数S1_new!
Run T1 transform(), 输入X=[1 2 3 4 5], 用 T1 fit() 计算的新参数S1_new!
Run T2 fit(), 输入X=[ 2  4  6  8 10],计算并保存新参数S2_new!
#######################################分割线1################################################
Run T1 transform(), 输入X=[1 2 3 4 5], 用 T1 fit() 计算的新参数S1_new!
Run T2 transform(), 输入X=[ 2  4  6  8 10], 用 T2 fit() 计算的新参数S2_new!
[ 8 16 24 32 40]
#######################################分割线2################################################
Run T1 transform(), 输入X=[1 2 3 4 5], 用 T1 fit() 计算的新参数S1_new!
Run T2 predict(), 输入X=[ 2  4  6  8 10], 用 T2 fit() 计算的新参数S2_new!

例2:pipe.fit_transform()→pipe.predict()

X = np.array([1,2,3,4,5])  # 数据准备

pipe = Pipeline([('name1', T1()), ('name2', T2())]) # 生成Pipline对象

result = pipe.fit_transform(X)
print(result)
print('#######################################分割线1################################################')
pipe.predict(X)

输出:
Run T1 fit(), 输入X=[1 2 3 4 5],计算并保存新参数S1_new!
Run T1 transform(), 输入X=[1 2 3 4 5], 用 T1 fit() 计算的新参数S1_new!
Run T2 fit(), 输入X=[ 2  4  6  8 10],计算并保存新参数S2_new!
Run T2 transform(), 输入X=[ 2  4  6  8 10], 用 T2 fit() 计算的新参数S2_new!
[ 8 16 24 32 40]
#######################################分割线1################################################
Run T1 transform(), 输入X=[1 2 3 4 5], 用 T1 fit() 计算的新参数S1_new!
Run T2 predict(), 输入X=[ 2  4  6  8 10], 用 T2 fit() 计算的新参数S2_new!

三、一个比较完整的Pipeline例子

对鸢尾花数据集进行分类:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression

from sklearn.datasets import load_iris  # 自带的样本数据集
from sklearn.model_selection import train_test_split
iris = load_iris()  # 导入数据

X = iris.data  # 150个样本,4个属性
y = iris.target # 150个类标号

# 将数据集划分为训练集和验证集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 生成pipeline对象
pipe = Pipeline([('preprocessing','passthrough'),
                 ('sc', StandardScaler()),
                 ('pca', PCA(n_components=2)),
                 ('clf', LogisticRegression(random_state=1))])
# 利用pipeline对象训练模型
pipe.fit(X_train, y_train)
# 利用测试数据对模型进行评价
pipe.score(X_test,y_test)
输出:
0.9
# 利用训练好的模型对新数据进行预测(这里用测试数据代替)
pipe.predict(X_test)
输出:
array([1, 0, 2, 1, 2, 0, 1, 2, 2, 1, 2, 0, 0, 0, 0, 1, 2, 1, 1, 2, 0, 1, 0, 2, 2, 2, 2, 2, 0, 0])

上述例子中,在定义pipe对象时,用了四个计算步骤:其中第1个是'passthrough',啥也不做;第2、3个分别是标准化处理和PCA分解,都属于变换器(transformer);第4个是逻辑回归,属于估计器(estimator)。

我们继续做实验,在pipe步骤中做两种修改:1)估计器不放在最后位置;2)有两个估计器,如下所示:

# 修改1:把估计器(逻辑回归)放在非最后位置
pipe = Pipeline([('preprocessing','passthrough'),
                 ('sc', StandardScaler()),
                 ('clf', LogisticRegression(random_state=1)),
                 ('pca', PCA(n_components=2))])

# 修改2:把增加一个估计器(逻辑回归clf和clf2)
pipe = Pipeline([('preprocessing','passthrough'),
                 ('sc', StandardScaler()),
                 ('pca', PCA(n_components=2)),
                 ('clf', LogisticRegression(random_state=1)),
                 ('clf2', LogisticRegression(random_state=1))])

上述两种改变,在定义时都不会报错,但在执行pipe.fit(X_train, y_train)时都会报错:

pipe.fit(X_train, y_train)
输出:
 TypeError: All intermediate steps should be transformers and implement fit and transform or be the string 'passthrough' 'LogisticRegression(random_state=1)' (type <class 'sklearn.linear_model._logistic.LogisticRegression'>) doesn't

由此可见:

参考:
https://blog.csdn.net/nkufang/article/details/129973061

上一篇下一篇

猜你喜欢

热点阅读