scikit网格搜索多个分类器

Anu*_*nuj 26 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_
Run Code Online (Sandbox Code Playgroud)

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

dub*_*bek 18

在scikit-learn中跨多个模型的后超参数网格搜索提供了EstimatorSelectionHelper估计器的实现,该估计器可以运行不同的估计器,每个估计器具有其自己的参数网格.

  • 这个解决方案最适合我,我只需要做一些小改动就可以在Python3上运行,并且最新版本的scikit-learn 0.19,代码可以在这里找到:http://davidsbatista.net/blog/2018/02/23/model_optimization / (5认同)
  • 谢谢@DavidBatista,特别是因为答案中的链接被破坏了. (2认同)

bmu*_*uer 8

虽然来自dubek的解决方案更直接,但它对于在类别之前出现的管道元素的参数之间的交互没有帮助.因此,我编写了一个帮助类来处理它,并且可以包含在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_)
Run Code Online (Sandbox Code Playgroud)

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


Tar*_*hak 8

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

得分最高的将使用 pickle 保存到磁盘

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
import operator
Run Code Online (Sandbox Code Playgroud)
#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=operator.itemgetter('best score'),reverse=True)

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

Run Code Online (Sandbox Code Playgroud)


Ste*_*ios 7

尽管主题有点老,但我发布了答案,以防将来对任何人有帮助。

可以使用'hyperopt'库,而不是使用Grid Search进行超参数选择。

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

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

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


Rup*_*yak 5

该问题的另一个简单解决方案。

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

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

之后创建一个分类器列表:

ensemble_clf=[rf, ex, gb, svc] 
Run Code Online (Sandbox Code Playgroud)

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

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

现在创建一个列表:

parameters_list=[params1, params2, params3, params4]
Run Code Online (Sandbox Code Playgroud)

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

model_log=["_rf", "_ex", "_gb", "_svc"]
Run Code Online (Sandbox Code Playgroud)

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

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

所述“全局()[‘网格%s’的%model_log [I] = pd.DataFrame(Grid.cv_results_)”将分别创建dataframes为每个所使用的估计量,并且可被用来比较排序和拾起最佳每个估计器的参数。

希望这可以帮助。

  • 喜欢这种方法——非常简洁。但是,我会使用模型字典来使其更具可读性,而不是为每个模型网格搜索创建数据框,**在 for 循环内,我会执行“Grid.best_estimator_”来获取找到的最佳估计器一个特定的模型:)** https://scikit-learn.org/stable/modules/ generated/sklearn.model_selection.GridSearchCV.html#best_estimator_ (2认同)