---
title: "AjusteHiperSVM"
author: "Ricardo Aler"
date: "1/8/2019"
output:
  pdf_document: default
  html_notebook: default
---

## Ajuste hiper-par�metros SVMs

```{r}
library(mlr)
library(mlbench)
library(mlrHyperopt) # Esta librer�a ayuda en la obtenci�n de hiper-par�metros 
library(ggplot2)     # Librer�a para hacer plots

# Esto es para que no haya demasiados mensajes de informaci�n en el documento
configureMlr(show.info = FALSE)

data(BostonHousing)
# Primero, definimos una tarea de regresi�n, cuyos datos est�n contenidos en el data.frame BostonHousing y cuyo target es "mdev"
task_bh <- makeRegrTask(data= BostonHousing, target="medv")

# Segundo, definimos el nombre delgoritmo de aprendizaje ("learner").
learner_name <- "regr.svm"

# Tercero, vemos que hiper-par�metros ajustables tiene
filterParams(getParamSet(learner_name), tunable = TRUE)

# Nuestro learner inicial va a ser una SVM con kernel gausiano (radial). Lo definimos as�:

learner_svm <- makeLearner(learner_name, kernel="radial")



```

Vemos que tiene muchos hiper-par�metros, pero sabemos que los m�s importantes son el **kernel** (linear o radial), el **cost** y **gamma** (que representa la desviaci�n de la gausiana). Vamos a probar con una radial (gausiana), con lo que ajustaremos s�lo **cost** y **gamma**

Es interesante saber que podemos conseguir ayuda sobre el m�todo y de sus par�metros as�:

```{r}
helpLearner(learner_name)
helpLearnerParam(learner_name, "gamma")
```


```{r}

# Ahora habr�a que definir un espacio de b�squeda para los hiper-par�metros
# Una opci�n es ir a la p�gina web # http://mlrhyperopt.jakob-r.de/parconfigs

# Una segunda opci�n es descargar directamente el espacio de b�squeda desde la web as�:

pc = downloadParConfigs(learner.name="regr.svm") # http://mlrhyperopt.jakob-r.de/parconfigs
print(pc)
if(length(pc)>0) {
 ps = getParConfigParSet(pc[[1]], task=task_bh)
 print(ps)
}
# Desgraciadamente, en este caso no hay ninguno exactamente para ese learner
# Tendr�amos que ir a la p�gina web http://mlrhyperopt.jakob-r.de/parconfigs
# y buscarlo a mano, para svm.

```

En este caso, usaremos una tercera opci�n, m�s sencilla: la funci�n **generateParConfig** nos da un espacio de b�squeda b�sico para un learner concreto.

```{r}
pc_svm <- generateParConfig(learner=learner_name, task=task_bh)
ps_svm <- getParConfigParSet(pc_svm, task=task_bh)
print(ps_svm)
```
Puede ser interesante ver que funci�n se usa para el **trafo** (transformaci�n), que en ambos casos es $2^x$

```{r}
print(ps_svm$pars$cost$trafo)
print(ps_svm$pars$cost$trafo)
```

Tambi�n puede ser interesante saber c�mo tendr�amos que definir este espacio de b�squeda si hubiera que hacerlo a mano, o quisieramos cambiarlo. Ser�a as�:

```{r}
ps_amano <- makeParamSet(
  makeNumericParam("cost", lower=-15, upper=+15, trafo = function(x) 2^x),
  makeNumericParam("gamma", lower=-15, upper=+15, trafo = function(x) 2^x)
)

print(ps_amano)

```

Ahora definimos c�mo se b�sca en el espacio de hiper-par�metros (con **randomsearch** en este caso y un **budget** de 100 evaluaciones), y c�mo se eval�an los distintos hiper-par�metros (validaci�n cruzada de tres folds).

```{r}
# Ojo, he puesto 1000 evaluaciones para hacer una buena visualizaci�n despu�s, pero puede tardar mucho. 
# Posiblemente con budget = 50 sea suficiente

control_grid <- makeTuneControlRandom(budget=1000)
inner_desc <- makeResampleDesc("CV", iter=3)

# Aqu� construimos una secuencia de ajuste seguida de construcci�n de modelo
learner_tune_svm <- makeTuneWrapper(learner_svm, resampling = inner_desc, par.set = ps_svm, control = control_grid, measures = list(rmse))

# Tambi�n tenemos que definir c�mo se va a evaluar el modelo final. En este caso con train/test (holdout)
outer_desc <-  makeResampleDesc("Holdout")
set.seed(0)
outer_inst <- makeResampleInstance(outer_desc, task_bh)

# Por �ltimo, usamos resample para entrenar y evaluar learner_tune_svm
set.seed(0)
error_tune_svm <- resample(learner_tune_svm, task_bh, outer_inst, measures = list(rmse), extract = getTuneResult )
```

Vemos que los hiper-par�metros que se eligieron en la partici�n de entrenamiento son los siguientes (tambi�n se muestra el error que producen dichos hiper-par�metros en la validaci�n cruzada de 3 folds que se us� para seleccionarlos):

```{r}
error_tune_svm$extract
```

y el error del modelo final es:

```{r}
error_tune_svm$aggr
```

Por �ltimo, podemos ver un plot que nos muestra c�mo cambia el error con los distintos valores de los hiper-par�metros:

```{r}
data <- generateHyperParsEffectData(error_tune_svm, include.diagnostics = FALSE)

# Las siguientes dos l�neas son para solventar un bug de MLR
names(data$data)[names(data$data)=="rmse.test.rmse"] <- "rmse.test.mean"
data$measures[data$measures=="rmse.test.rmse"] <- "rmse.test.mean"


plt = plotHyperParsEffect(data, x = "cost", y = "gamma", z = "rmse.test.mean",
  plot.type = "contour", interpolate = "regr.earth", show.experiments = TRUE)

plot(plt + geom_point(x=log2(error_tune_svm$extract[[1]]$x$cost), y=log2(error_tune_svm$extract[[1]]$x$gamma), size=5))
```

A continuaci�n podemos ver como se ha ido reduciendo el error con las iteraciones y parece que con bastantes menos que con Random Search se alcanzan mejores m�nimos.

```{r}
plt = plotHyperParsEffect(data, x = "iteration", y = "rmse.test.mean",
  plot.type = "line")
plt
```

## Ajuste con model-based optimization

Ahora definimos c�mo se b�sca en el espacio de hiper-par�metros con MBO

```{r}
library(mlrMBO)
# Dedica 80 iteraciones al ajuste
control = makeMBOControl()
control = setMBOControlTermination(control, iters = 80)
control = setMBOControlInfill(control, crit = makeMBOInfillCritEI())

control_grid <-makeTuneControlMBO(mbo.control = control)

inner_desc <- makeResampleDesc("CV", iter=3)

# Aqu� construimos una secuencia de ajuste seguida de construcci�n de modelo
learner_tune_svm <- makeTuneWrapper(learner_svm, resampling = inner_desc, par.set = ps_svm, control = control_grid, measures = list(rmse))

# Tambi�n tenemos que definir c�mo se va a evaluar el modelo final. En este caso con train/test (holdout)
outer_desc <-  makeResampleDesc("Holdout")
set.seed(0)
outer_inst <- makeResampleInstance(outer_desc, task_bh)

# Por �ltimo, usamos resample para entrenar y evaluar learner_tune_svm
set.seed(0)
error_tune_svm <- resample(learner_tune_svm, task_bh, outer_inst, measures = list(rmse), extract = getTuneResult )
```

Vemos que los hiper-par�metros que se eligieron en la partici�n de entrenamiento son los siguientes (tambi�n se muestra el error que producen dichos hiper-par�metros en la validaci�n cruzada de 3 folds que se us� para seleccionarlos):

```{r}
error_tune_svm$extract
```

y el error del modelo final es:

```{r}
error_tune_svm$aggr
```

Por �ltimo, podemos ver un plot que nos muestra c�mo cambia el error con los distintos valores de los hiper-par�metros. Aqu� se ve como la b�squeda se concentra en una buena regi�n (a diferencia de Random Search, que explora todas las zonas por igual).

```{r}
data <- generateHyperParsEffectData(error_tune_svm, include.diagnostics = FALSE)

# Las siguientes dos l�neas son para solventar un bug de MLR
names(data$data)[names(data$data)=="rmse.test.rmse"] <- "rmse.test.mean"
data$measures[data$measures=="rmse.test.rmse"] <- "rmse.test.mean"


plt = plotHyperParsEffect(data, x = "cost", y = "gamma", z = "rmse.test.mean",
  plot.type = "contour", interpolate = "regr.earth", show.experiments = TRUE)

plot(plt + geom_point(x=log2(error_tune_svm$extract[[1]]$x$cost), y=log2(error_tune_svm$extract[[1]]$x$gamma), size=5))
```

A continuaci�n podemos ver como se ha ido reduciendo el error con las iteraciones y parece que con bastantes menos que con Random Search se alcanzan mejores m�nimos.

```{r}
plt = plotHyperParsEffect(data, x = "iteration", y = "rmse.test.mean",
  plot.type = "line")
plt
```
```{r}

```

