【问题标题】:Try multiple estimator in one grid-search在一次网格搜索中尝试多个估计器
【发布时间】:2016-11-28 01:57:03
【问题描述】:

有没有一种方法可以在 Sklearn 或任何其他库中一次grid-search 多个估算器。例如,我们可以在一次网格搜索中通过 SVM 和随机森林吗?

【问题讨论】:

  • 你想达到什么目的?
  • 我试图同时为多个算法创建网格搜索

标签: scikit-learn grid-search


【解决方案1】:

是的。示例:

pipeline = Pipeline([
    ('vect', CountVectorizer()),
    ('clf', SGDClassifier()),
])
parameters = [
    {
        'vect__max_df': (0.5, 0.75, 1.0),
        'clf': (SGDClassifier(),),
        'clf__alpha': (0.00001, 0.000001),
        'clf__penalty': ('l2', 'elasticnet'),
        'clf__n_iter': (10, 50, 80),
    }, {
        'vect__max_df': (0.5, 0.75, 1.0),
        'clf': (LinearSVC(),),
        'clf__C': (0.01, 0.5, 1.0)
    }
]
grid_search = GridSearchCV(pipeline, parameters)

【讨论】:

  • 您好,谢谢您的回答。我一直在寻找的是如何创建一个管道,我们可以在其中并行使用 SGDClassifier 和 SVM 等两种模型。在这种情况下,来自 CountVectorizer 的结果将传递给 SGDClassifier。无论如何,我改变了我的方法来解决这个问题。
  • @tj89 它将并行运行,但我想您的意思是 CountVectorizer 应该运行一次,然后为每个分类器重用其结果?您是如何改变方法的?
  • 我发现 (sklearn==0.23.2) 您可以将 None 用于管道中的“clf”。不需要虚拟 SGDClassifier。
【解决方案2】:

我想你要找的是这个:

from sklearn.svm import LinearSVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

names = [
         "Naive Bayes",
         "Linear SVM",
         "Logistic Regression",
         "Random Forest",
         "Multilayer Perceptron"
        ]

classifiers = [
    MultinomialNB(),
    LinearSVC(),
    LogisticRegression(),
    RandomForestClassifier(),
    MLPClassifier()
]

parameters = [
              {'vect__ngram_range': [(1, 1), (1, 2)],
              'clf__alpha': (1e-2, 1e-3)},
              {'vect__ngram_range': [(1, 1), (1, 2)],
              'clf__C': (np.logspace(-5, 1, 5))},
              {'vect__ngram_range': [(1, 1), (1, 2)],
              'clf__C': (np.logspace(-5, 1, 5))},
              {'vect__ngram_range': [(1, 1), (1, 2)],
              'clf__max_depth': (1, 2)},
              {'vect__ngram_range': [(1, 1), (1, 2)],
              'clf__alpha': (1e-2, 1e-3)}
             ]

for name, classifier, params in zip(names, classifiers, parameters):
    clf_pipe = Pipeline([
        ('vect', TfidfVectorizer(stop_words='english')),
        ('clf', classifier),
    ])
    gs_clf = GridSearchCV(clf_pipe, param_grid=params, n_jobs=-1)
    clf = gs_clf.fit(X_train, y_train)
    score = clf.score(X_test, y_test)
    print("{} score: {}".format(name, score))

【讨论】:

  • 你为什么用 clf 预先修复它?你可以随便叫它吗
  • 您真的可以随意称呼它,@Maths12,但通过选择一致的前缀,您可以使用GridSearchCV 对每个估计器进行参数调整。不过,您可以通过使用上面示例中的 name 来获得相同的效果。
  • 这会创建多个网格搜索,但问题要求进行 1 个网格搜索。
【解决方案3】:
    from sklearn.base import BaseEstimator
    from sklearn.model_selection import GridSearchCV
    
    class DummyEstimator(BaseEstimator):
        def fit(self): pass
        def score(self): pass
        
    # Create a pipeline
    pipe = Pipeline([('clf', DummyEstimator())]) # Placeholder Estimator
    
    # Candidate learning algorithms and their hyperparameters
    search_space = [{'clf': [LogisticRegression()], # Actual Estimator
                     'clf__penalty': ['l1', 'l2'],
                     'clf__C': np.logspace(0, 4, 10)},
                    
                    {'clf': [DecisionTreeClassifier()],  # Actual Estimator
                     'clf__criterion': ['gini', 'entropy']}]
    
    
    # Create grid search 
    gs = GridSearchCV(pipe, search_space)

【讨论】:

  • 如果使用 OneVsRestClassifier,您将如何进行,您正在测试的估算器在 OneVsRestClassifier 中被调用?您似乎能够将不同的估计器/参数网格传递给外部估计器,但是我只是找不到将参数传递给内部估计器的方法。只是徘徊,如果有什么魔法可以一起完成。即使我对每个内部估计器进行单独的网格搜索,我仍然面临我不知道如何将参数传递给内部估计器以进行网格搜索的问题。
  • 认为你可以用 None 代替 DummyEstimator。
【解决方案4】:

您可以做的是创建一个接收任何分类器的类,并为每个分类器设置任何参数。

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

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)

现在您可以随意预训练 tfidf。

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer()
tfidf.fit(data, labels)

现在使用这个预训练的 tfidf 创建一个管道

from sklearn.pipeline import Pipeline

pipeline = Pipeline([
    ('tfidf',tfidf), # Already pretrained/fit
    ('clf', ClfSwitcher()),
])

执行超参数优化

from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import GridSearchCV



parameters = [
    {
        'clf__estimator': [SGDClassifier()], # SVM if hinge loss / logreg if log loss
        '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()],
        'clf__estimator__alpha': (1e-2, 1e-3, 1e-1),
    },
]

gscv = GridSearchCV(pipeline, parameters, cv=5, n_jobs=12, verbose=3)
# param optimization
gscv.fit(train_data, train_labels)

如何解读clf__estimator__loss

clf__estimator__loss 被解释为loss 参数,无论estimator 是什么,其中estimator = SGDClassifier() 在最上面的示例中,它本身就是clf 的一个参数,它是一个ClfSwitcher 对象。

【讨论】:

    【解决方案5】:

    您可以使用TransformedTargetRegressor。 此类设计用于在拟合之前转换目标变量,以回归量和一组转换器作为参数。但是你可以不给变换器,然后应用恒等变换器(即不变换)。由于regressor是一个类参数,我们可以通过网格搜索对象来改变它。

    import numpy as np
    from sklearn.compose import TransformedTargetRegressor
    from sklearn.linear_model import LinearRegression
    from sklearn.neural_network import MLPRegressor
    from sklearn.model_selection import GridSearchCV
    
    Y = np.array([1,2,3,4,5,6,7,8,9,10])
    X = np.array([0,1,3,5,3,5,7,9,8,9]).reshape((-1, 1))
    

    为了进行网格搜索,我们应该将 param_grid 指定为 dict 列表,每个用于不同的估计器。这是因为不同的估计器使用不同的参数集(例如,将fit_intercept 设置为MLPRegressor 会导致错误)。 请注意,名称“regressor”会自动赋予回归器。

    model = TransformedTargetRegressor()
    params = [
        {
            "regressor": [LinearRegression()],
            "regressor__fit_intercept": [True, False]
        },
        {
            "regressor": [MLPRegressor()],
            "regressor__hidden_layer_sizes": [1, 5, 10]
        }
    ]
    

    我们可以像往常一样适应。

    g = GridSearchCV(model, params)
    g.fit(X, Y)
    
    g.best_estimator_, g.best_score_, g.best_params_
    
    # results in like
    (TransformedTargetRegressor(check_inverse=True, func=None, inverse_func=None,
                   regressor=LinearRegression(copy_X=True, fit_intercept=False, n_jobs=None,
              normalize=False),
                   transformer=None),
     -0.419213380219391,
     {'regressor': LinearRegression(copy_X=True, fit_intercept=False, n_jobs=None,
               normalize=False), 'regressor__fit_intercept': False})
    

    【讨论】:

      猜你喜欢
      • 2021-03-19
      • 2016-04-07
      • 2021-05-27
      • 2020-07-14
      • 2019-08-22
      • 2012-11-23
      • 2021-03-29
      • 2021-12-31
      • 2018-11-08
      相关资源
      最近更新 更多