scikit-learn 管道中的锁定步骤(防止改装)
Posted
技术标签:
【中文标题】scikit-learn 管道中的锁定步骤(防止改装)【英文标题】:Lock steps (prevent refit) in scikit-learn pipeline 【发布时间】:2017-06-27 14:48:55 【问题描述】:是否有一种方便的机制来锁定 scikit-learn 管道中的步骤以防止它们重新安装在 pipeline.fit() 上?例如:
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
from sklearn.datasets import fetch_20newsgroups
data = fetch_20newsgroups(subset='train')
firsttwoclasses = data.target<=1
y = data.target[firsttwoclasses]
X = np.array(data.data)[firsttwoclasses]
pipeline = Pipeline([
("vectorizer", CountVectorizer()),
("estimator", LinearSVC())
])
# fit intial step on subset of data, perhaps an entirely different subset
# this particular example would not be very useful in practice
pipeline.named_steps["vectorizer"].fit(X[:400])
X2 = pipeline.named_steps["vectorizer"].transform(X)
# fit estimator on all data without refitting vectorizer
pipeline.named_steps["estimator"].fit(X2, y)
print(len(pipeline.named_steps["vectorizer"].vocabulary_))
# fitting entire pipeline refits vectorizer
# is there a convenient way to lock the vectorizer without doing the above?
pipeline.fit(X, y)
print(len(pipeline.named_steps["vectorizer"].vocabulary_))
我能想到在没有中间转换的情况下这样做的唯一方法是定义一个自定义估计器类(如 here 所示),它的 fit 方法什么都不做,它的 transform 方法是 pre-fit 转换器的转换。这是唯一的方法吗?
【问题讨论】:
【参考方案1】:查看代码,Pipeline 对象中似乎没有任何具有以下功能的内容:在管道上调用 .fit() 会在每个阶段产生 .fit()。
我能想到的最好的快速而肮脏的解决方案是猴子修补舞台的拟合功能:
pipeline.named_steps["vectorizer"].fit(X[:400])
# disable .fit() on the vectorizer step
pipeline.named_steps["vectorizer"].fit = lambda self, X, y=None: self
pipeline.named_steps["vectorizer"].fit_transform = model.named_steps["vectorizer"].transform
pipeline.fit(X, y)
【讨论】:
很不幸,但是当您将这样的 lambda 函数附加到实例时,它不会像本地方法那样传递“self”。所以,这部分不会像你期望的那样工作。 在这种情况下模型对象是什么? 这个解决方案非常接近有效的解决方案!您只需将pipeline.named_steps["vectorizer"].fit = lambda self, X, y=None: self
更改为pipeline.named_steps["vectorizer"].__class__.fit = lambda s, X, y=None: s
【参考方案2】:
您可以采用管道的一个子集,例如
preprocess_pipeline = Pipeline(pipeline.best_estimator_.steps[:-1]) # 排除最后一步
然后
tmp = preprocess_pipeline.fit(x_train) normalized_x = tmp.fit_transform(x_train)
【讨论】:
以上是关于scikit-learn 管道中的锁定步骤(防止改装)的主要内容,如果未能解决你的问题,请参考以下文章
如何从 scikit-learn 中的 TransformedTargetRegressor 管道中的经过训练的估计器访问属性?
如何在 scikit-learn 管道中的 CountVectorizer 之前包含 SimpleImputer?