Альтернативные модели в Pipeline для GridSearchCV

Я хочу построить конвейер в sklearn и протестировать разные модели с помощью GridSearchCV.

Приведу пример (не обращайте внимания на то, какие именно модели выбраны):

reg = LogisticRegression()

proj1 = PCA(n_components=2)
proj2 = MDS()
proj3 = TSNE()

pipe = [('proj', proj1), ('reg' , reg)]

pipe = Pipeline(pipe)

param_grid = {
    'reg__c': [0.01, 0.1, 1],
}

clf = GridSearchCV(pipe, param_grid = param_grid)

Здесь, если я хочу попробовать разные модели для уменьшения размерности, мне нужно закодировать разные конвейеры и сравнить их вручную. Есть простой способ сделать это?

Одно из решений, которое я придумал, - определить мой собственный класс, производный от базового оценщика:

class Projection(BaseEstimator):
    def __init__(self, est_name):
        if est_name == "MDS":
            self.model = MDS()
        ...
    ...
    def fit_transform(self, X):
        return self.model.fit_transform(X)

Думаю, это сработает, я просто создаю объект Projection и передаю его Pipeline, используя имена оценщиков в качестве параметров для него.

Но для меня этот способ немного хаотичен и не масштабируется: он заставляет меня определять новый класс каждый раз, когда я хочу сравнить разные модели. Также, чтобы продолжить это решение, можно реализовать класс, который выполняет ту же работу, но с произвольным набором моделей. Мне это кажется слишком сложным.

Какой самый естественный и питонический способ сравнения разных моделей?


person sooobus    schedule 10.05.2018    source источник
comment
Вы можете напрямую использовать оценщики в качестве параметров.   -  person Vivek Kumar    schedule 10.05.2018


Ответы (2)


Предположим, вы хотите использовать PCA и TruncatedSVD в качестве шага уменьшения размерности.

pca = decomposition.PCA()
svd = decomposition.TruncatedSVD()
svm = SVC()
n_components = [20, 40, 64]

Ты можешь сделать это:

pipe = Pipeline(steps=[('reduction', pca), ('svm', svm)])

# Change params_grid -> Instead of dict, make it a list of dict
# In the first element, pass parameters related to pca, and in second related to svd

params_grid = [{
'svm__C': [1, 10, 100, 1000],
'svm__kernel': ['linear', 'rbf'],
'svm__gamma': [0.001, 0.0001],
'reduction':pca,
'reduction__n_components': n_components,
},
{
'svm__C': [1, 10, 100, 1000],
'svm__kernel': ['linear', 'rbf'],
'svm__gamma': [0.001, 0.0001],
'reduction':svd,
'reduction__n_components': n_components,
'reduction__algorithm':['randomized']
}]

а теперь просто передайте объект конвейера в gridsearchCV

grd = GridSearchCV(pipe, param_grid = params_grid)

Вызов grd.fit() будет искать параметры по обоим элементам списка params_grid, используя все значения из one за раз.

Пожалуйста, посмотрите мой другой ответ для получения более подробной информации: Параллельный конвейер чтобы получить лучшую модель с помощью gridsearch

person Vivek Kumar    schedule 10.05.2018
comment
Правильно ли я понял, что нужно также включить «сокращение»: algo_name в каждый из двух элементов param_grid? В противном случае svd не используется в обучающих классификаторах (если я правильно понял ваш другой ответ, который сработал для меня). - person sooobus; 10.05.2018
comment
@sooobus Ааа, это была моя ошибка. Исправлено сейчас. Спасибо. - person Vivek Kumar; 10.05.2018
comment
@VivekKumar Отличный ответ! К вашему сведению, в scikit-learn 0.23 (и, возможно, в более ранних версиях) отдельные значения в сетке параметров должны быть заключены в список с одним элементом, иначе произойдет ошибка. Таким образом, вы должны использовать «сокращение»: [pca] и «сокращение»: [svd], чтобы это работало. - person Kevin Markham; 29.07.2020

Альтернативное решение, которое не требует добавления префикса к именам оценщиков в сетке параметров, следующее:

from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression

# the models that you want to compare
models = {
    'RandomForestClassifier': RandomForestClassifier(),
    'KNeighboursClassifier': KNeighborsClassifier(),
    'LogisticRegression': LogisticRegression()
}

# the optimisation parameters for each of the above models
params = {
    'RandomForestClassifier':{ 
            "n_estimators"      : [100, 200, 500, 1000],
            "max_features"      : ["auto", "sqrt", "log2"],
            "bootstrap": [True],
            "criterion": ['gini', 'entropy'],
            "oob_score": [True, False]
            },
    'KNeighboursClassifier': {
        'n_neighbors': np.arange(3, 15),
        'weights': ['uniform', 'distance'],
        'algorithm': ['ball_tree', 'kd_tree', 'brute']
        },
    'LogisticRegression': {
        'solver': ['newton-cg', 'sag', 'lbfgs'],
        'multi_class': ['ovr', 'multinomial']
        }  
}

и вы можете определить:

from sklearn.model_selection import GridSearchCV

def fit(train_features, train_actuals):
        """
        fits the list of models to the training data, thereby obtaining in each 
        case an evaluation score after GridSearchCV cross-validation
        """
        for name in models.keys():
            est = models[name]
            est_params = params[name]
            gscv = GridSearchCV(estimator=est, param_grid=est_params, cv=5)
            gscv.fit(train_features, train_actuals)
            print("best parameters are: {}".format(gscv.best_estimator_))

в основном проходит через разные модели, каждая из которых ссылается на свой собственный набор параметров оптимизации через словарь. Конечно, не забудьте передать модели и словарь параметров в функцию fit, если у вас их нет в качестве глобальных переменных. Взгляните на этот проект GitHub, чтобы получить больше полный обзор.

person gented    schedule 03.01.2019
comment
gscv.fit (train_actuals, train_features) ‹- я думаю, все не так - person Maths12; 05.02.2020
comment
Как только я переберу все свои модели, чтобы найти лучшие гиперпараматоры с помощью gridsearch, я буду использовать модель, которая дала наивысшее значение оценки? например если после выполнения вышеизложенного я обнаружил, что лучший результат случайного леса = 0,8 и лучший результат логситикрегрессии = 0,9 потребует логистической регрессии? - person Maths12; 08.02.2020
comment
В принципе, да, вы бы взяли эту одну модель и обучили ее на всем наборе данных. Обратите внимание, однако, что баллы перекрестной проверки являются лишь показателем ошибки, с которой можно столкнуться при использовании неизвестных тестовых данных. - person gented; 10.02.2020