我正在尝试建立scikit学习管道以简化我的工作。我面临的问题是我不知道哪种算法(随机森林,朴素贝叶斯,决策树等)最适合,因此我需要尝试每种算法并比较结果。但是,流水线一次只采用一种算法吗?例如,下面的管道仅采用SGDClassifier()作为算法。
pipeline = Pipeline([
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', SGDClassifier()),])
如果我想比较不同的算法该怎么办?我可以做这样的事情吗?
pipeline = Pipeline([
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', SGDClassifier()),
('classifier', MultinomialNB()),])
我不想将其分解为两个管道,因为数据的预处理非常耗时。
谢谢!
答案 0 :(得分:4)
您说对数据进行预处理非常慢,所以我假设您考虑了TF-IDF矢量化是您进行预处理的一部分。
您只能预处理一次。
X = <your original data>
from sklearn.feature_extraction.text import TfidfVectorizer
X = TfidfVectorizer().fit_transform(X)
一旦有了新的转换数据,就可以继续使用它并选择最佳的分类器。
虽然您可以一次使用TfidfVectorizer
转换数据,但我不推荐这样做,因为TfidfVectorizer
本身具有超参数,也可以对其进行优化。最后,您希望一起优化整个Pipeline
,因为TfidfVectorizer in
a Pipeline [TfidfVectorizer, SGDClassifier]
的参数可能与Pipeline [TfidfVectorizer, MultinomialNB]
的参数不同。
要回答您的确切问题,您可以创建自己的估计器,并选择模型作为超参数。
from sklearn.base import BaseEstimator
class MyClassifier(BaseEstimator):
def __init__(self, classifier_type: str = 'SGDClassifier'):
"""
A Custome BaseEstimator that can switch between classifiers.
:param classifier_type: string - The switch for different classifiers
"""
self.classifier_type = classifier_type
def fit(self, X, y=None):
if self.classifier_type == 'SGDClassifier':
self.classifier_ = SGDClassifier()
elif self.classifier_type == 'MultinomialNB':
self.classifier_ = MultinomialNB()
else:
raise ValueError('Unkown classifier type.')
self.classifier_.fit(X, y)
return self
def predict(self, X, y=None):
return self.classifier_.predict(X)
然后您可以在Pipeline
中使用此客户分类器。
pipeline = Pipeline([
('tfidf', TfidfVectorizer()),
('clf', MyClassifier())
])
然后您可以GridSearchCV
选择最佳模型。创建参数空间时,可以使用双下划线在pipeline
中指定步骤的超参数。
parameter_space = {
'clf__classifier_type': ['SGDClassifier', 'MultinomialNB']
}
from sklearn.model_selection import GridSearchCV
search = GridSearchCV(pipeline , parameter_space, n_jobs=-1, cv=5)
search.fit(X, y)
print('Best model:\n', search.best_params_)
答案 1 :(得分:3)
根据Bruno的回答,大多数人真正想做的是能够传递ANY分类器(不必对每个分类器进行硬编码)以及每个分类器的任何参数。这是一种简单的方法:
from sklearn.base import BaseEstimator
class ClfSwitcher(BaseEstimator):
def __init__(
self,
estimator = SGDClassifier(),
):
"""
A Custom BaseEstimator that can switch between classifiers.
:param estimator: sklearn object - The classifier
"""
self.estimator = estimator
def fit(self, X, y=None, **kwargs):
self.estimator.fit(X, y)
return self
def predict(self, X, y=None):
return self.estimator.predict(X)
def predict_proba(self, X):
return self.estimator.predict_proba(X)
def score(self, X, y):
return self.estimator.score(X, y)
现在,您可以为estimator参数传递任何内容。您可以按以下步骤为传入的任何估算器优化任何参数:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import SGDClassifier
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
pipeline = Pipeline([
('tfidf', TfidfVectorizer()),
('clf', ClfSwitcher()),
])
parameters = [
{
'clf__estimator': [SGDClassifier()], # SVM if hinge loss / logreg if log loss
'tfidf__max_df': (0.25, 0.5, 0.75, 1.0),
'tfidf__stop_words': ['english', None],
'clf__estimator__penalty': ('l2', 'elasticnet', 'l1'),
'clf__estimator__max_iter': [50, 80],
'clf__estimator__tol': [1e-4],
'clf__estimator__loss': ['hinge', 'log', 'modified_huber'],
},
{
'clf__estimator': [MultinomialNB()],
'tfidf__max_df': (0.25, 0.5, 0.75, 1.0),
'tfidf__stop_words': [None],
'clf__estimator__alpha': (1e-2, 1e-3, 1e-1),
},
]
gscv = GridSearchCV(pipeline, parameters, cv=5, n_jobs=12, return_train_score=False, verbose=3)
gscv.fit(train_data, train_labels)
clf__estimator__loss
clf__estimator__loss
被解释为loss
的{{1}}参数,在最上面的示例中,estimator
本身就是estimator = SGDClassifier()
的参数,是clf
对象。