如果我在 python 管道中有自定义的集成模型,如何进行交叉验证和网格搜索

Posted

技术标签:

【中文标题】如果我在 python 管道中有自定义的集成模型,如何进行交叉验证和网格搜索【英文标题】:How to do cross validation and grid search if I have a customized ensemble model in python pipeline 【发布时间】:2019-12-28 23:49:19 【问题描述】:

我正在构建一个定制的集成模型,并希望使用管道在 python 中进行交叉验证和网格搜索。我该怎么做?

我有一个包含网页内容的数据集。我想做的是

    将内容从一个网页分成两部分。拆分的原因是因为文本来自页面的不同位置,我想分别处理它们。

    我只使用第 1 部分的特征训练模型 1,只使用第 2 部分的特征训练模型 2。

    假设我从 model1 获得的分数为 S1,而从 model2 获得的分数为 S2。我训练了另一个模型,即逻辑回归模型,将这两个分数集成为最终分数 S。

在整个过程中,有没有办法可以在 sklearn 中使用 ML 管道进行交叉验证和网格搜索?


感谢 Dev 在下面的回复,但是当我尝试做同样的事情时,我遇到了新问题。 我的代码如下:

data = pd.DataFrame(columns = ['landingVector', 'contentVector', 'label'])

def extractLandingData(X):
        return X['landingVector']

def extractContentData(X):
        return X['contentVector']



svm_landing = Pipeline([
    ("extractLanding", FunctionTransformer(extractLandingData)),
    ("svmLanding", SVC(random_state=0, class_weight='balanced', kernel='linear', probability=True)),
])
svm_content = Pipeline([
    ("extractContent", FunctionTransformer(extractContentData)),
    ("svmContent", SVC(random_state=0, class_weight='balanced', kernel='linear', probability=True)),
])

stage_pipeline = FeatureUnion([
    ("svmForLanding", svm_landing),
    ("svmForContent", svm_content),
])

full_pipeline = Pipeline([
    ("stagePipeline", stage_pipeline),
    ("lr", LogisticRegression())
])

params = [
    
        "stagePipeline__svmForLanding__svmLanding__C": [3,5,10],
        "full_pipeline__lr__C": [1, 5, 10],
        "full_pipeline__lr__penalty": ['l1', 'l2']
    
]

grid_search = GridSearchCV(full_pipeline, params, cv=3, verbose=3, return_train_score=True, n_jobs=-1)
X_train = df[['landingVector', 'contentVector']]
y_train = df['label']
grid_search.fit(X_train, y_train)

然后我收到一条错误消息

----------------------------------- ---------------------------- TypeError Traceback(最近一次调用 最后)在 23 stage_pipeline = FeatureUnion([ 24(“svmForLanding”,svm_landing), ---> 25 ("svmForContent", svm_content), 26]) 27

~/anaconda3/lib/python3.7/site-packages/sklearn/pipeline.py 在 init(自我、transformer_list、n_jobs、transformer_weights) 第672章 第673章 --> 674 self._validate_transformers() 675 676 def get_params(自我,深=真):

~/anaconda3/lib/python3.7/site-packages/sklearn/pipeline.py 在 _validate_transformers(自我) 716 raise TypeError("所有估计器都应该实现 fit 和 " 第717章 --> 718 (t, type(t))) 719 720 定义_iter(自我):

TypeError:所有估计器都应该实现拟合和变换。 '管道(内存=无, steps=[('extractLanding', FunctionTransformer(accept_sparse=False, check_inverse=True, 函数=, inv_kw_args=无,inverse_func=无,kw_args=无, pass_y='deprecated', validate=None)), ('svmLanding', SVC(C=1.0, cache_size=200...inear', max_iter=-1, probability=True, random_state=0,shrinking=True,tol=0.001,verbose=False))])'(类型 ) 没有

【问题讨论】:

看看vecstack 【参考方案1】:

假设您将合奏分为 2 个阶段。 1. 阶段 1 模型,即模型 1 和模型 2。 2. 基于第一阶段模型输出的逻辑回归模型。

因此,您可以在第一阶段使用 GridSearchCV。这将帮助您找到最佳参数。因为,GridSearchCV 在内部使用交叉验证,并有一个参数 'cv' 表示折叠的数量。在不同折叠的数据上选择最佳参数。

对于第 2 阶段模型,即逻辑回归,您实际上不需要执行 GridSearchCV。但是,仍然可以使用 'cross_val_score' 来计算不同数据子集的分数

【讨论】:

【参考方案2】:

是的,您可以使用 GridSearchCv 或 RandomizedSearchCv 为您的管道模型找到最佳超参数。

您可以将模型定义为顺序或并行的管道组合 然后就可以使用GridSearchCV中的最终管道了 在 grid_params 中,您可以通过用“__”双下划线连接管道名称来引用每个内部管道的超参数

请看以下与您类似的案例。查看管道如何链接以及在 grid_params 中如何引用管道项的超参数

email_body_to_wordcount = Pipeline([
    ("convert_to_text", MapTransformer(email_to_text)),
    ("strip_html", MapTransformer(strip_html)),
    ("replace_urls", MapTransformer(replace_urls)),
    ("replace_numbers", MapTransformer(replace_numbers)),
    ("replace_non_word_characters", MapTransformer(replace_non_word_characters)),
    ("count_word_stem", CountStemmedWord()),   
], memory="cache")

subject_to_wordcount =  Pipeline([

    ("process_text", Pipeline([
        ("get_subject", MapTransformer(get_email_subject)),
        ("replace_numbers", MapTransformer(replace_numbers)),
        ("replace_non_word_characters", MapTransformer(replace_non_word_characters)),
    ], memory="cache")),
    ("count_word_stem", CountStemmedWord(importance=5)),
])

email_to_word_count = FeatureUnion([
    ("email_to_wordcount", email_body_to_wordcount),
    ("subject_to_wordcount", subject_to_wordcount)
])

content_type_pipeline = Pipeline([
   ("get_content_type", MapTransformer(email.message.EmailMessage.get_content_type)),
    ("binarize", LblBinarizer())
])

email_len_transform = Pipeline([
    ("convert_to_text", MapTransformer(email_to_text)),
    ("get_email_len", MapTransformer(len)),

])

email_to_word_vector = Pipeline([
    ("email_to_word_count", email_to_word_count),
    ("word_count_to_vector", WordCountsToVector())
])

full_pipeline = FeatureUnion([
    ("email_to_word_vector", email_to_word_vector),
    ("content_type_pipeline", content_type_pipeline),
    ("email_len_transform", email_len_transform)
])

predict_pipeline = Pipeline([
    ("full_pipeline", full_pipeline),
    ("predict", RandomForestClassifier(n_estimators = 5))
])

params = [
    
        "full_pipeline__email_to_word_vector__email_to_word_count__email_to_wordcount" +
        "__count_word_stem__importance": [3,5],
        "full_pipeline__email_to_word_vector" +
        "__word_count_to_vector__vocabulary_len": [500,1000,1500]
    
]

grid_search = GridSearchCV(predict_pipeline, params, cv=3, verbose=3, return_train_score=True)
grid_search.fit(X_train, y_train)

已编辑 管道将对变压器使用fit and transform 方法,因此您的变压器应该实现这些方法。您可以像下面那样实现自定义转换器并使用它来代替 SVC 分类器

from sklearn.base import BaseEstimator, TransformerMixin

class CustomTransformer(BaseEstimator, TransformerMixin):
    def fit(self,X,y):
        self.svc = SVC() #initialize your svc here
        return self

    def transform(self,X,y=None):
        return self.svc.predict(X)

【讨论】:

非常感谢!是的,这看起来像我正在寻找的东西。我将尝试在此处发布结果。 我尝试过同样的方法,但遇到了新问题。我已将我的代码附加到原始问题。请帮忙。谢谢 @pipal 我认为SVC没有转换方法,你能验证一下吗?如果没有,那么您需要使用 SVC 制作自定义转换器并在管道中使用它。请参阅上面的编辑答案

以上是关于如果我在 python 管道中有自定义的集成模型,如何进行交叉验证和网格搜索的主要内容,如果未能解决你的问题,请参考以下文章

ListView 模型函数

如果依赖属性为真,则 ICommand 属性应执行

如何在 UICollectionView 中有自定义单元格

如何在媒体基础中有自定义视频媒体/流接收器请求 RGB32 帧?

无法找到自定义管道

如何将 Python Lambda 函数集成到 AWS Amplify 的管道中