使用sklearn管线比较多种算法

viv*_*704 5 python algorithm machine-learning scikit-learn

我正在尝试建立scikit学习管道来简化我的工作。我面临的问题是我不知道哪种算法(随机森林,朴素贝叶斯,决策树等)最适合,因此我需要尝试每种算法并比较结果。但是,流水线一次只采用一种算法吗?例如,下面的管道仅采用SGDClassifier()作为算法。

pipeline = Pipeline([
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', SGDClassifier()),])
Run Code Online (Sandbox Code Playgroud)

如果我想比较不同的算法该怎么办?我可以做这样的事情吗?

pipeline = Pipeline([
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', SGDClassifier()),
('classifier', MultinomialNB()),])
Run Code Online (Sandbox Code Playgroud)

我不想将其分为两个管道,因为数据的预处理非常耗时。

提前致谢!

cgn*_*utt 9

改进布鲁诺的答案,大多数人真正想要做的是能够传入任何分类器(不必对每个分类器进行硬编码)以及每个分类器的任何参数。这是一个简单的方法来做到这一点:

创建适用于任何估算器的切换器类

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)
Run Code Online (Sandbox Code Playgroud)

现在您可以为 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)
Run Code Online (Sandbox Code Playgroud)

如何解读 clf__estimator__loss

clf__estimator__loss被解释loss为任何东西的参数estimatorestimator = SGDClassifier()在最上面的例子中,它本身就是一个参数,clf它是一个ClfSwitcher对象。

  • 巧妙的方法。基本上使分类器“只是另一个需要调整的超参数”。太棒了。 (3认同)

Bru*_*her 5

预处理

您说对数据进行预处理非常慢,因此我假设您将TF-IDF矢量化视为预处理的一部分。

您可以只预处理一次。

X = <your original data>

from sklearn.feature_extraction.text import TfidfVectorizer
X = TfidfVectorizer().fit_transform(X)
Run Code Online (Sandbox Code Playgroud)

获得新的转换数据后,您可以继续使用它并选择最佳分类器。

优化TF-IDF变压器

尽管您可以TfidfVectorizer一次转换数据,但我不建议您这样做,因为TfidfVectorizer本身具有超参数,也可以对其进行优化。最后,您希望一起优化整体Pipeline,因为a的参数可以与TfidfVectorizer ina 的参数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)
Run Code Online (Sandbox Code Playgroud)

然后,您可以在中使用此客户分类器Pipeline

pipeline = Pipeline([
    ('tfidf', TfidfVectorizer()),
    ('clf', MyClassifier())
])
Run Code Online (Sandbox Code Playgroud)

然后,您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_)
Run Code Online (Sandbox Code Playgroud)