Los modelos de aprendizaje de maquinas suelen requerir de varias iteraciones en busqueda de hiperparametros optimizados. Es por ello que existen paquetes como caret, el cual incluye una serie de funciones que facilitan el uso de decenas de metodos complejos de clasificacion y regresion. Utilizar este paquete en lugar de las fuciones originales de los metodos presenta dos ventajas:
Permite implementar un unico codigo donde se pueden aplicar reglas de clasificacion muy distintas las cuales se implementan normalemente en distintos paquetes.
Es mas sencillo poner en práctica algunos procedimientos usuales en problemas de clasificación. Por ejemplo, hay funciones especificas que permiten dividir las muestras en datos de entrenamiento y validacion a su vez que permite ajustar parametros mediante validacion cruzada.
En este documento nos centraremos en optimizar los hiperparametros de dos de los seis modelos utilizados en la actividad anterior (consultar enlace en la parte superior), utilizando caret.
Nota: El analisis descriptivo no se agrega al documento final debido a que ya fue realizado en la actividad anterior-
1.1 Maquinas de Soporte Vectorial (SVM)
Este modelo se fundamenta en encontrar los hiperplanos que mejor dividan el dataset, a los hiperplanos se les agrega unos vectores cercanos que en conjunto hacen las veces de margen sobre para los datos, permitiendo más flexibilidad y control sobre el modelo.
A continuacion se muestra el proceso de lectura y normalizacion de los datos.
# Se cargan los datos del archivo en formato csv
datos <- read.csv("real_estate_valuation_dataset.csv",
sep = ";", dec = ",")
# Se le asignan etiquetas a cada columna
names(datos)<-c('Numero', 'Fechatransaccion', 'Edadcasa', 'MRTDistance', 'NTiendas', 'Latitud', 'Longitud', 'Priceperarea')
# Se filtran algunas columnas
sub_datos_svm <- subset(datos, select = c('Edadcasa', 'MRTDistance', 'NTiendas', 'Priceperarea'))
#Hacemos el escalamiento de las variables
sub_datos_svm_scale <- scale(sub_datos_svm, center=TRUE, scale=TRUE)#Escala a media cero
medias <- attr(sub_datos_svm_scale, "scaled:center")
desv_est <- attr(sub_datos_svm_scale, "scaled:scale")
datos_subc_scale <- as.data.frame(sub_datos_svm_scale)
#Hacemos el escalamiento solo de Y (precio)
sub_datos_svm_scale_Y <- scale(sub_datos_svm$Priceperarea, center=TRUE, scale=TRUE)#Escala a media cero
media_Y <- attr(sub_datos_svm_scale_Y, "scaled:center")
desv_est_Y <- attr(sub_datos_svm_scale_Y, "scaled:scale")
Luego de procesamiento basico de los datos, se separaron los datos en dos conjuntos, uno de entrenamiento y otro de testeo.
# Dividimos el dataset para entrenamiento y testeo
set.seed(1)
sample = sample.split(sub_datos_svm_scale[,4], SplitRatio = 0.8)
train = subset(sub_datos_svm_scale, sample == TRUE)
test = subset(sub_datos_svm_scale, sample == FALSE)
Despues de tener los datos en dos conjuntos de muestras se prepara la malla de hiperparamentros para escoger la mejor combinacion.
| sigma | C |
|---|---|
| 0.1 | 15 |
| 0.2 | 15 |
| 0.3 | 15 |
| 0.4 | 15 |
| 0.5 | 15 |
| 0.1 | 20 |
Por último entrenamos el modelo con el metodo de evaluación SMV Radial, obteniendo los siguientes resultados:
| sigma | C | RMSE | Rsquared | MAE | RMSESD | RsquaredSD | MAESD |
|---|---|---|---|---|---|---|---|
| 0.1 | 15 | 0.6123855 | 0.6326600 | 0.4097195 | 0.2116766 | 0.1540402 | 0.0827384 |
| 0.1 | 20 | 0.6126392 | 0.6323379 | 0.4098520 | 0.2118023 | 0.1535270 | 0.0830983 |
| 0.1 | 25 | 0.6136951 | 0.6310872 | 0.4109268 | 0.2118670 | 0.1536063 | 0.0830668 |
| 0.1 | 30 | 0.6152875 | 0.6293490 | 0.4124050 | 0.2115207 | 0.1531959 | 0.0827384 |
| 0.1 | 35 | 0.6167077 | 0.6278649 | 0.4135758 | 0.2121166 | 0.1535994 | 0.0827974 |
| 0.1 | 45 | 0.6194071 | 0.6249977 | 0.4158290 | 0.2127048 | 0.1541239 | 0.0831025 |
## Support Vector Machine object of class "ksvm"
##
## SV type: eps-svr (regression)
## parameter : epsilon = 0.1 cost C = 30
##
## Gaussian Radial Basis kernel function.
## Hyperparameter : sigma = 0.3
##
## Number of Support Vectors : 271
##
## Objective Function Value : -2607.165
## Training error : 0.339684
Como indican los autores de “A Practical Guide to Support Vector Classification”, es recomendable probar el kernel radial. Este kernel tiene dos ventajas: que solo tiene dos hiperparámetros a optimizar (sigma y la penalización C común a todos los SVM) y que su flexibilidad puede ir desde un clasificador lineal a uno muy complejo. De acuerdo a esto, en primera instancia entrenamos con un modelo SVM Lineal obteniendo un error de entrenamiento del 49%, mientras que con SVM radial obtuvimos un error del 33,9%, reduciendo así el error drásticamente en 15 puntos porcentuales.
## sigma C
## 16 0.3 30
La malla para encontrar los hiperparámetros con mejor desempeño en el modelo los asignamos con un sigma entre ( 0.1, 0.2, 0.3, 0.4, 0.5) y una penalización C entre (15, 20, 25, 30, 35, 45), de los cuales los de mejor desempeño fueron 0.3 y 30 respectivamente.
| TrainRMSE | TrainRsquared | TrainMAE | method |
|---|---|---|---|
| 0.5963828 | 0.6488522 | 0.406499 | svmRadial |
En la gráfica observamos cómo a través de los diferentes valores de sigma establecidos en la malla se mueve el costo y el RMSE, siendo sigma de 0.3 y C de 30 efectivamente los de menor RMSE.
RMSE de los datos desnormalizados:
## [1] 7.35086
Luego de desnormalizar los datos, calculamos el RMSE del precio por área predicho por el modelo optimizado Vs el conjunto de testeo, obteniendo un RMSE de 7.35.
1.2 RandomForest
Para optimizar el modelo utilizaremos la funcion ranger como paquete adicional de caret el cual busca optimizar 3 parametros, mtry, min.node.size y splitrule.
(Caret incluye por defecto la funcion rf() de RandomForest, pero solo permite optimizar el mtry)
A continuacion se muestra el proceso de lectura de datos para este modelo.
# Se cargan los datos del archivo en formato csv
datos <- read.csv("real_estate_valuation_dataset.csv", sep = ";", dec = ",")
# Se le asignan etiquetas a cada columna
datos_subc <-subset(datos, select = c("X2","X3","X4","X5","X6","Y"))
# Se filtran algunas columnas
names(datos)<-c('Numero', 'Fechatransaccion', 'Edadcasa', 'MRTDistance', 'NTiendas', 'Latitud', 'Longitud', 'Priceperarea')
# Random Forest no necesita normalización porque es simplemente un proceso de spliteo sobre datos
sub_datos_rf <- subset(datos, select = c('Edadcasa', 'MRTDistance', 'NTiendas', 'Priceperarea'))
Como se observa y tambien se menciona en el codigo anterior, para el caso de RandomForest no se normalizan los datos ya que para este modelo es relevante este proceso, por lo que se procede directamente a separar los datos en los conjutos de entrenamiento y validacion como en el modelo anterior.
# Dividimos el dataset para entrenamiento y testeo
set.seed(99)
sample = sample.split(sub_datos_rf$Priceperarea, SplitRatio = 0.8)
train = subset(sub_datos_rf, sample == TRUE)
test = subset(sub_datos_rf, sample == FALSE)
Por consiguiente creamos la malla con los hiperparamentros para escoger la mejor combinacion.
| mtry | min.node.size | splitrule |
|---|---|---|
| 1 | 1 | variance |
| 2 | 1 | variance |
| 3 | 1 | variance |
| 1 | 2 | variance |
| 2 | 2 | variance |
| 3 | 2 | variance |
Entrenamos el modelo obteniendo los sigueintes resultados:
## mtry splitrule min.node.size
## 14 2 variance 4
A partir del paremetro Splitrule definido como varianza se obtuvieron los siguientes RMSE.
RMSE de entrenamiento:
## [1] 3.760505
RMSE de testeo:
## [1] 6.905069
Teniedo el parametro Splitrule como varianza y seleccionando el modelo optimo a partir del menor RMSE se obtuvieron los valores de mtry = 2 y el min.node.size = 5.
Se cambia el parametro de Splitrule por extratrees y se analiza la misma malla.
## mtry splitrule min.node.size
## 14 2 extratrees 4
A partir del paremetro Splitrule definido como extratrees se obtuvieron los siguientes RMSE.
RMSE de entrenamiento:
## [1] 4.649459
RMSE de testeo:
## [1] 7.002023
Teniedo el parametro Splitrule como extratrees y seleccionando el modelo optimo a partir del menor RMSE se obtuvieron los valores de mtry = 2 y el min.node.size = 4.
Se decidió optimizar estos modelos porque se encontró que eran en los que mayores oportunidades existían. En el caso de Random forest al realizar el entrenamiento con los valores por defecto se obtuvieron unos resultados muy por debajo de lo esperado, al analizar el RMSE de los distintos modelos sobre el conjunto de testeo RF y XGBoost fueron los que tuvieron un peor desempeño. Los métodos de ensamble de árboles son algunos de los modelos que mayores ventajas tienen, además de que no requieren de exhaustivo pre procesamiento (no necesitan normalización), evita el overfitting y otorga información sobre la importancia de cada variable predictora en el modelo, por tanto resultó de gran interés profundizar en los hiperparametros del modelo. Motivados por lo anterior y teniendo en cuenta que para el ejercicio previo se utilizó la librería ‘RandomForest’ y ésta solo permitía la optimización en Caret del parámetro mtry (número de variables consideradas por árbol), se utilizó el método Ranger, que permitía hacer la optimización de mtry, min.node.size y splitrule.
En lo que concierne a SVM, el desempeño observado llego a rivalizar con el de la red neuronal (hoy por hoy uno de los métodos más completos). Motivados en profundizar sobre la posibilidad de alcanzar o mejorar los resultados equiparables con un método a priori más costoso a nivel computacional como lo son las redes neuronales, los parámetros que se optimizaron fueron sigma y c. Sin embargo, mediante el desarrollo del trabajo observamos que el random forest tuvo un mejor comportamiento en error de entrenamiento y del RMSE que en SVM.