scikit网格搜索多个分类器

时间:2014-04-13 16:36:17

标签: python scikit-learn

我想知道是否有更好的内置方式来进行网格搜索并在单个管道中测试多个模型。当然,模型的参数会有所不同,这对我来说很复杂。这是我做的:

from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import MultinomialNB
from sklearn.grid_search import GridSearchCV


def grid_search():
    pipeline1 = Pipeline((
    ('clf', RandomForestClassifier()),
    ('vec2', TfidfTransformer())
    ))

    pipeline2 = Pipeline((
    ('clf', KNeighborsClassifier()),
    ))

    pipeline3 = Pipeline((
    ('clf', SVC()),
    ))

    pipeline4 = Pipeline((
    ('clf', MultinomialNB()),
    ))

    parameters1 = {
    'clf__n_estimators': [10, 20, 30],
    'clf__criterion': ['gini', 'entropy'],
    'clf__max_features': [5, 10, 15],
    'clf__max_depth': ['auto', 'log2', 'sqrt', None]
    }

    parameters2 = {
    'clf__n_neighbors': [3, 7, 10],
    'clf__weights': ['uniform', 'distance']
    }

    parameters3 = {
    'clf__C': [0.01, 0.1, 1.0],
    'clf__kernel': ['rbf', 'poly'],
    'clf__gamma': [0.01, 0.1, 1.0],

    }
    parameters4 = {
    'clf__alpha': [0.01, 0.1, 1.0]
    }

    pars = [parameters1, parameters2, parameters3, parameters4]
    pips = [pipeline1, pipeline2, pipeline3, pipeline4]

    print "starting Gridsearch"
    for i in range(len(pars)):
        gs = GridSearchCV(pips[i], pars[i], verbose=2, refit=False, n_jobs=-1)
        gs = gs.fit(X_train, y_train)
        print "finished Gridsearch"
        print gs.best_score_

然而,这种方法仍然在每个分类器中提供最佳模型,而不是在分类器之间进行比较。

6 个答案:

答案 0 :(得分:16)

帖子Hyperparameter Grid Search across multiple models in scikit-learn(由David S. Batista提供)提供了EstimatorSelectionHelper估算器的更新实现,该估算器可以运行不同的估算器,每个估算器都有自己的参数网格。

答案 1 :(得分:7)

尽管来自dubek的解决方案更直接,但它对于在类别之前出现的管道元素的参数之间的交互没有帮助。因此,我编写了helper class来处理它,并且可以包含在scikit的默认管道设置中。一个最小的例子:

from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler, MaxAbsScaler
from sklearn.svm import LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn import datasets
from pipelinehelper import PipelineHelper

iris = datasets.load_iris()
X_iris = iris.data
y_iris = iris.target
pipe = Pipeline([
    ('scaler', PipelineHelper([
        ('std', StandardScaler()),
        ('max', MaxAbsScaler()),
    ])),
    ('classifier', PipelineHelper([
        ('svm', LinearSVC()),
        ('rf', RandomForestClassifier()),
    ])),
])

params = {
    'scaler__selected_model': pipe.named_steps['scaler'].generate({
        'std__with_mean': [True, False],
        'std__with_std': [True, False],
        'max__copy': [True],  # just for displaying
    }),
    'classifier__selected_model': pipe.named_steps['classifier'].generate({
        'svm__C': [0.1, 1.0],
        'rf__n_estimators': [100, 20],
    })
}
grid = GridSearchCV(pipe, params, scoring='accuracy', verbose=1)
grid.fit(X_iris, y_iris)
print(grid.best_params_)
print(grid.best_score_)

它也可以用于管道的其他元素,而不仅仅是分类器。 如果有人想查看代码,则代码在github

答案 2 :(得分:5)

虽然这个话题有点陈旧,但我发布了答案,以防将来有人帮助。

您可以使用'hyperopt' library

,而不是使用网格搜索进行超参数选择

请查看this page的第2.2节。在上述情况下,您可以使用' hp.choice'表达式在各种管道中进行选择,然后分别为每个管道定义参数表达式。

在目标函数中,您需要根据所选管道进行检查,并返回所选管道和参数的CV分数(可能通过cross_cal_score)。

执行结束时的试验对象将指示最佳的管道和参数。

答案 3 :(得分:3)

另一个简单的解决方案。

首先加载所有估计量。在这里,我将主要使用分类器。

logi=LogisticRegression(penalty="elasticnet",l1_ratio=0.5,solver="saga", random_state=4, n_jobs=-1)
rf=RandomForestClassifier(random_state=4, n_jobs=-1, max_features="auto", warm_start=True)
gb=GradientBoostingClassifier(random_state=4, subsample=0.8, max_features="auto", warm_start=True)
svc=SVC(random_state=4, kernel='rbf')
ex=ExtraTreesClassifier(random_state=4, n_jobs=-1, max_features="auto", warm_start=True)

之后,创建分类列表:

ensemble_clf=[rf, ex, gb, svc] 

现在,为每个分类器/估计器创建所有参数:-

params1={"max_depth": range(5,30,5), "min_samples_leaf": range(1,30,2),
         "n_estimators":range(100,2000,200)}
params2={"criterion":["gini", "entropy"],"max_depth": range(5,30,5), 
         "min_samples_leaf": range(1,30,2), "n_estimators":range(100,2000,200)}
params3={"learning_rate":[0.001,0.01,0.1], "n_estimators":range(1000,3000,200)}
params4={"kernel":["rbf", "poly"], "gamma": ["auto", "scale"], "degree":range(1,6,1)}

现在创建它们的列表:

parameters_list=[params1, params2, params3, params4]

现在,最重要的部分出现了: 为所有模型/分类器或估计器创建一个字符串名称: 这用于为比较

创建数据框
model_log=["_rf", "_ex", "_gb", "_svc"]

现在运行for循环并使用Grid搜索:

for i in range(len(ensemble_clf)):
    Grid=GridSearchCV(estimator=ensemble_clf[i], param_grid=parameters_list[i], 
                      n_jobs=-1, cv=3, verbose=3).fit(TrainX_Std, TrainY)
    globals()['Grid%s' % model_log[i]]=pd.DataFrame(Grid.cv_results_)  

“ globals()['Grid%s'%model_log [i]] = pd.DataFrame(Grid.cv_results_)” 将为每个使用的估计量分别创建数据框,并且可以通过排序进行比较,并选择每个估计量的最佳参数。

希望这会有所帮助。

答案 4 :(得分:3)

这是我没有包装函数的情况。 您可以评估任意数量的分类器。每个参数可以有多个参数用于超参数优化。

得分最高的一个将使用泡菜保存到磁盘

from sklearn.svm import SVC
from operator import itemgetter
from sklearn.utils import shuffle
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import MultinomialNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.feature_extraction.text import TfidfVectorizer
#pipeline parameters
    parameters = \
        [ \
            {
                'clf': [MultinomialNB()],
                'tf-idf__stop_words': ['english', None],
                'clf__alpha': [0.001, 0.1, 1, 10, 100]
            },

            {
                'clf': [SVC()],
                'tf-idf__stop_words': ['english', None],
                'clf__C': [0.001, 0.1, 1, 10, 100, 10e5],
                'clf__kernel': ['linear', 'rbf'],
                'clf__class_weight': ['balanced'],
                'clf__probability': [True]
            },

            {
                'clf': [DecisionTreeClassifier()],
                'tf-idf__stop_words': ['english', None],
                'clf__criterion': ['gini','entropy'],
                'clf__splitter': ['best','random'],
                'clf__class_weight':['balanced', None]
            }
        ]

    #evaluating multiple classifiers
    #based on pipeline parameters
    #-------------------------------
    result=[]

    for params in parameters:

        #classifier
        clf = params['clf'][0]

        #getting arguments by
        #popping out classifier
        params.pop('clf')

        #pipeline
        steps = [('tf-idf', TfidfVectorizer()), ('clf',clf)]

        #cross validation using
        #Grid Search
        grid = GridSearchCV(Pipeline(steps), param_grid=params, cv=3)
        grid.fit(features, labels)

        #storing result
        result.append\
        (
            {
                'grid': grid,
                'classifier': grid.best_estimator_,
                'best score': grid.best_score_,
                'best params': grid.best_params_,
                'cv': grid.cv
            }
        )

    #sorting result by best score
    result = sorted(result, key=itemgetter('best score'),reverse=True)

    #saving best classifier
    grid = result[0]['grid']
    joblib.dump(grid, 'classifier.pickle')

答案 5 :(得分:0)

另一种选择是使用HyperclassifierSearch (Github)软件包。它接近bmurauer above的解决方案。

但是,您可能会

  1. 找到DataFrame输出以获取最佳模型,这有助于跳过计时信息作为默认模型
  2. 找到三个usage examples helpful
  3. 就像较短的核心代码(大约100行)

我根据HyperclassifierSearch package的代码开发了David Batista(以pip install HyperclassifierSearch开头),我喜欢代码的简洁性。

1。的详细信息,使用超分类器validate_model函数:

search = HyperclassifierSearch(models, params)
best_model = search.train_model(X, y)
search.evaluate_model(sort_by='mean_test_score', show_timing_info=False) # default parameters explicitly given