Búsqueda en rejilla

En la estrategia denominada búsqueda en rejilla (o grid search) el proceso anterior se automatiza realizando una búsqueda, no aleatoria en todo el espacio formado por las posibles combinaciones de los parámetros, sino en puntos de dicho espacio repartidos de forma espaciada en una rejilla.

Scikit-learn ofrece esta funcionalidad en la clase sklearn.model_selection.GridSearchCV.

Repitamos la búsqueda de los mejores parámetros en el mismo escenario que el de la búsqueda aleatoria. Comenzamos importando la clase GridSearchCV y cargando el dataset:

from sklearn.model_selection import GridSearchCV

iris = sns.load_dataset("iris")

y = iris.pop("species")
X = iris
del(iris)

Al objeto de la clase GridSearchCV tenemos que pasarle un mínimo de dos argumentos: estimator -modelo a usar- y param_grid -diccionario conteniendo como "claves" los hiperparámetros del modelo, y como "valores" los valores de los hiperparámetros que queremos probar-. El parámetro opcional cv define la estrategia de validación cruzada a seguir: si pasamos un número entero n, se ejecutará una validación cruzada con n bloques.

Por lo tanto, instanciamos el algoritmo (vamos a seguir usando RandomForestClassifier):

model = RandomForestClassifier(n_estimators = 100, random_state = 0)

...y definimos el diccionario con los hiperparámetros y sus posibles valores:

parameters = {
    "max_depth": range(1, 11, 2),
    "min_samples_split": range(2, 21, 2)
}

Ahora ya podemos instanciar la clase GridSearchCV y entrenarla (obsérvese que, al ejecutarse la validación cruzada, podemos pasar a la clase las variables X e y sin necesidad de separaras en bloques de entrenamiento y validación):

clf = GridSearchCV(model, parameters, cv = 5)

clf.fit(X, y)

GridSearchCV(cv=5, error_score='raise-deprecating',
       estimator=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=None,
            oob_score=False, random_state=0, verbose=0, warm_start=False),
       fit_params=None, iid='warn', n_jobs=None,
       param_grid={'max_depth': range(1, 11, 2), 'min_samples_split': range(2, 21, 2)},
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=0)

Una vez entrenado, podemos acceder al mejor modelo, a la mejor puntuación y a los mejores parámetros encontrados a través de los atributos best_estimator_best_score_best_params_ respectivamente:

clf.best_estimator_ 

RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=5, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=4,
            min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=None,
            oob_score=False, random_state=0, verbose=0, warm_start=False)

clf.best_score_

0.9666666666666667

clf.best_params_

{'max_depth': 5, 'min_samples_split': 4}

El parámetro de la clase GridSearchCV scoring nos permite especificar un criterio de evaluación del algoritmo.

El parámetro param_grid comentado puede ser un diccionario o una lista de diccionarios. Si se trata de una lista, el objeto GridSearchCV probará de forma secuencial las combinaciones de hiperparámetros de cada uno de los diccionarios de la lista.

El mayor inconveniente que ofrece este método es que se prueban de forma exhaustiva todas las combinaciones indicadas, lo que puede exigir un tiempo más que notable y difícilmente estimable. Esto significa que si queremos aprovechar un equipo para que realice una búsqueda durante la noche, es muy fácil que el proceso termine a las 4 de la madrugada -y estemos desperdiciando varias horas de posible búsqueda adicional- o que no termine hasta las 11 de la mañana, retrasando otras tareas que estén pendientes.

Además, no es posible acceder a los mejores valores encontrados hasta que no termina el entrenamiento. Fijar el argumento "verbose" a 3 o más muestra en pantalla el detalle del proceso, pero la única forma de encontrar en la información mostrada los mejores valores es a través de una inspección visual, poco recomendable y muy pesada.