suppressMessages(library(rpart))
suppressMessages(library(caret))
suppressMessages(library(readr))
suppressMessages(library(dplyr))
Al usar la funcion read_csv del paquete readr tenemos la posibilidad de definir el tipo de dato que queremos para cada variable.
data_train <- readr::read_csv("./data/arbolado-mza-dataset.csv",
col_types = cols(
id = col_integer(),
especie = col_character(),
ultima_modificacion = col_character(),
altura = col_character(),
circ_tronco_cm = col_double(),
diametro_tronco = col_character(),
long = col_double(),
lat = col_double(),
seccion = col_integer(),
nombre_seccion = col_character(),
area_seccion = col_double(),
inclinacion_peligrosa = col_integer()
))
data_test <- readr::read_csv("./data/arbolado-mza-dataset-test.csv",col_types = cols(
id = col_integer(),
especie = col_character(),
ultima_modificacion = col_character(),
altura = col_character(),
circ_tronco_cm = col_double(),
diametro_tronco = col_character(),
long = col_double(),
lat = col_double(),
seccion = col_integer(),
nombre_seccion = col_character(),
area_seccion = col_double()
))
Algunos algoritmos no permiten nombres de factores como 1 y 0, se transforma la clase inclinacion_peligrosa a si y no
data_train<-data_train %>% mutate(inclinacion_peligrosa=ifelse(inclinacion_peligrosa=='1','si','no'))
data_train$inclinacion_peligrosa <-as.factor(data_train$inclinacion_peligrosa)
Seleccionamos algunos atributos que a priori creemos que pueden explicar la inclinacion del arbol
Luego se entrena un arbol de decision utilizando los parametros por omision.
train_formula<-formula(inclinacion_peligrosa~altura+circ_tronco_cm+lat+long+seccion+especie)
tree_model_3<-rpart(train_formula,data=data_train)
Para generar un archivo de envio, necesitamos aplicar la funcion predict() sobre el conjunto de evaluacion. La prediccion da como resultado la probabilidad asignada a cada clase.
preds_tree_probs=predict(tree_model_3,data_test,type='prob')
head(preds_tree_probs)
## no si
## [1,] 0.8878478 0.1121522
## [2,] 0.8878478 0.1121522
## [3,] 0.8878478 0.1121522
## [4,] 0.8878478 0.1121522
## [5,] 0.8878478 0.1121522
## [6,] 0.8878478 0.1121522
Sim embargo para poder hacer el envio a Kaggle, necesitamos un archivo que tenga los ID de cada registro y el valor 0 (no peligrosa) o 1 (peligrosa). Para esto hay que por un lado convertir las probabilidades de las classes si y no a sus correspondientes 0 y 1.
Para esto hay que establecer un umbral (threshold) a partir del cual se decide si un registro pertenece a la clase 0 o a la clase 1. Comunmente se toma un \(valor >=0.5\) para indicar la pertenencia a una clase. Por ejemplo el registro con el ID tiene una probabilidad 0.92798 la cual es >=0.5 por lo tanto \(\in\) a la clase 1. Esto se puede hacer facilmente en una linea usando la funcion ifelse()
preds_tree=ifelse(preds_tree_probs[,2] >=0.5,1,0)
head(preds_tree)
## [1] 0 0 0 0 0 0
Ahora tenemos para cada registro del conjunto de testeo la clase a la que pertenece segun las predicciones del arbol de decision. Lo que queda entonces es simplemente agregar los ID de cada registro y crear un archivo con el envio.
submission<-data.frame(id=data_test$id,inclinacion_peligrosa=preds_tree)
readr::write_csv(submission,"./arbolado-mza-dataset-envio-ejemplo-rpart.csv")
head(submission)
## id inclinacion_peligrosa
## 1 1 0
## 2 2 0
## 3 4 0
## 4 6 0
## 5 9 0
## 6 13 0
Antes de hacer un envio a Kaggle podemos darnos una idea de lo bien que funciona nuestro algoritmo, para esto basta con separar una porcion del conjunto de entrenamiento y usarla para validadcion
set.seed(100) # para que sea un ejemplo reproducible
data_validation_index<-sample(nrow(data_train),nrow(data_train)*0.1)
data_validation<-data_train[data_validation_index,]
data_train<-data_train[-data_validation_index,]
Una vez separado en 2 archivos, rentrenamos el modelo usando la funcion rpart() ## Entrenamiento
train_formula<-formula(inclinacion_peligrosa~altura+circ_tronco_cm+lat+long+seccion+especie)
tree_model_4<-rpart(train_formula,data=data_train)
y ahora calculamos las predicciones para el conjunto de validacion. Aca se repite el mismo proceso que en ejemplo anterior para convertir las probabilidades a las correspondientes classes 0 y 1. ## Generacion del dataframe con los resultados de la validacion
preds_tree_probs=predict(tree_model_4,data_validation,type='prob')
preds_tree=ifelse(preds_tree_probs[,2] >=0.5,'si','no')
resultados_validation<-data.frame(inclinacion_peligrosa=preds_tree)
Luego podemos calcular algunas metricas utilizando los resultados de nuestro prediccion y comparandolos con los valores correctos del archivo data_validation.
La funcion confusionMatrix() del paquete caret nos facilita calcular la matriz de confusion ademas de varias metricas
confusionMatrix(resultados_validation$inclinacion_peligrosa,data_validation$inclinacion_peligrosa)
## Confusion Matrix and Statistics
##
## Reference
## Prediction no si
## no 2805 386
## si 0 0
##
## Accuracy : 0.879
## 95% CI : (0.8672, 0.8902)
## No Information Rate : 0.879
## P-Value [Acc > NIR] : 0.5136
##
## Kappa : 0
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 1.000
## Specificity : 0.000
## Pos Pred Value : 0.879
## Neg Pred Value : NaN
## Prevalence : 0.879
## Detection Rate : 0.879
## Detection Prevalence : 1.000
## Balanced Accuracy : 0.500
##
## 'Positive' Class : no
##
Podemos ver que para este caso, el arbol a clasificado a todas los registros como NO peligrosos. Por que sera?