Búsqueda aleatoria en rejilla

El método anterior tenía un problema: si los hiperparámetros que estamos ajustando son muchos, las posibles combinaciones de sus valores pueden hacer el entrenamiento demasiado largo. La búsqueda aleatoria en rejilla intenta solucionar esto probando, no todas las combinaciones posibles de los valores, sino solo un cierto número de ellos. De esta forma, aun cuando el número total de posibles combinaciones sea elevado, podemos limitar el tiempo de entrenamiento. Scikit-Learn ofrece esta funcionalidad en la clase sklearn.model_selection.RandomizedSearchCV.

Siguiendo con el mismo ejemplo que en las páginas anteriores, importamos la clase RandomizedSearchCV y cargamos el dataset:

from sklearn.model_selection import RandomizedSearchCV

iris = sns.load_dataset("iris")

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

El funcionamiento de RandomizedSearchCV es semejante al de GridSearchCV: debemos pasar al objeto el modelo a usar (parámetro estimator), un diccionario (o lista de diccionarios) con los parámetros a probar (param_distributions), la estrategia de validación cruzada a seguir (cv) y, en este caso, el número de combinaciones a probar (parámetro n_iter). Añadamos a nuestro diccionario de hiperparámetros "min_samples_leaf":

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

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

clf = RandomizedSearchCV(model, parameters, cv = 5, n_iter = 100)

Ahora entrenamos el objeto y extraemos los mejores resultados obtenidos con los mismos atributos que hemos visto para GridSearchCV:

clf.fit(X, y)

RandomizedSearchCV(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_iter=100, n_jobs=None,
          param_distributions={'max_depth': range(1, 11), 'min_samples_split': range(2, 21), 'min_samples_leaf': range(1, 5)},
          pre_dispatch='2*n_jobs', random_state=None, refit=True,
          return_train_score='warn', scoring=None, verbose=0)

clf.best_estimator_ 

RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=10, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=5,
            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_

{'min_samples_split': 5, 'min_samples_leaf': 1, 'max_depth': 10}

Aunque con este método no estamos obligados a probar todas las combinaciones posibles, sigue teniendo problemas semejantes a los vistos en GridSearchCV, pues no es posible estimar el tiempo total que llevará el proceso, y no tendremos acceso a los mejores valores hasta el final del entrenamiento.