如果我在 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 管道中有自定义的集成模型,如何进行交叉验证和网格搜索的主要内容,如果未能解决你的问题,请参考以下文章