---
title: "Ucrania"
author: "Ricardo R. Palma"
date: '2022-05-12'
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
# Introducción a las Redes Neuronales Artificiales en R


En el siguiente documento se intentará realizar una predicción de la categoria de estado de salud de refugiados en función a una serie de características relevadas a su arribo .

## Introducción

En esta sesión práctica de programación en R, haremos una introducción básica a las Redes Neuronales Artificiales, e implementaremos con ellas un clasificador sobre el conjunto de datos Predicting a Pulsar Star, tal y como se utilizó anteriormente en la sesión práctica Introducción a los Modelos de Clasificación en R. Tanto éste como muchos otros conjuntos de datos reales y útiles se encuentran diponibles en el portal Kaggle.

## Redes Neuronales Artificiales

Las Redes Neuronales Artificiales son modelos computacionales inspirados en las neuronas biológicas, y que están conformadas por un conjunto de unidades de cómputo básico (neuronas) las cuales están conectadas entre ellas de múltiples maneras. Estas conexiones estarán definidas por unos pesos los cuales determinarán la fuerza o importancia de dichas conexiones, y durante el proceso de aprendizaje o entrenamiento de la red, serán estos pesos los que se ajustarán con el fin de producir la salida adecuada según la entrada que se aplique a la red. En términos generales, las redes neuronales artificiales están compuestas por una capa de entrada, una o más capas ocultas, y una capa de salida como se observa en la siguiente figura:

![Grafo de una Red Neuronal](rn1.png)

Por su parte, en cada neurona se realiza el cálculo matemático de la suma ponderada de las entradas con los pesos de la red, y luego se aplica sobre dicho resultado una función de activación, que producirá la salida final de cada neurona y que servirán como valores de entrada de la siguiente capa de la red neuronal.

El proceso de aprendizaje de la red se logra gracias al algoritmo de Propagación hacia atrás o Backpropagation, que consiste en aplicar las entradas a la red, obtener una salida final en la última capa, comparar este resultado con el resultado esperado (aprendizaje supervisado), y luego ir modificando hacia atrás los pesos de la capa de salida, oculta y de entrada a fin de minimizar (a partir del Descenso del Gradiente) el error entre la salida deseada y la salida generada por la red neuronal.

En este ejercicio práctico nos concentraremos en los detalles de la implementación de la red neuronal en R para un problema real, por lo que a efectos de una explicación más detallada del tema, recomiendo leer el artículo Introduction to Neural Networks de Ben Gorman.


 ## Carga de bibliotecas
```{r}
library(neuralnet)  # regression con redes neuronales
library(nnet) # classification con nn
library(NeuralNetTools)
library(plyr) # Herramientas para tratamiento de tablas
library(kableExtra) # H para impresión de tablas grandes
library(dplyr)
```



# Carga de dataset
```{r, error=TRUE}
library(readr)
ucrania <- read_delim("https://themys.sid.uncu.edu.ar/rpalma/R-cran/Ucrania.csv", 
    delim = ";", escape_double = FALSE, locale = locale(date_names = "es", 
        decimal_mark = ",", grouping_mark = "."), 
    trim_ws = TRUE)

# Eliminamos la primer columna que sólo tiene el índice
head(ucrania)
#wine <- select(wine, -X)
ucrania <- ucrania[ ,-1]
head(ucrania)
```

Revisión del nombre de las columnas

```{r}
str(ucrania)
```


# Tratamiento de variables categóricas
En este caso no se tienen variables categóricas, por lo que no es necesario este análisis.

# Correlación entre variables
Observamos si existe correlación entre alguna de las variables del conjunto.
```{r}
cor(ucrania)
correlacion <- cor(ucrania)
```

# Visualización de la matriz de correlación

```{r}
library(ggplot2)
library(ggcorrplot)
ggcorrplot(correlacion, method ="circle")
```


# Normalización de variables
```{r}
normalize<-function(x){
  return ( (x-min(x))/(max(x)-min(x)))
}

ucra_norm<-as.data.frame(lapply(ucrania,FUN=normalize))
```
# Muestreo para entrenamiento
Para generar un muestreo de una serie de datos podemos utilizar la función 'sample', que nos genera un arreglo de números aleatorios.
```{r}
indice <- sample(2, nrow(ucra_norm), replace = TRUE, prob = c(0.9,0.1))
ucra_train <- ucra_norm[indice==1,]
ucra_test  <- ucra_norm[indice==2,]
```
# Modelo de Neural Net
Una vez tengamos los datos de entrenamiento, podemos realizar el modelo.
En la función 'neuralnet' se deben pasar los parámetros en el siguiente formato:
variable_a_predecir~variables_fuente, y además los datos de entrenamiento.
```{r}
#algorithm = 'backprop', 'rprop+', 'rprop-', 'sag', or 'slr'
strAlgorithm <- 'rprop+'
ucra_model <- neuralnet(quality~. , data = ucra_train, rep = 1, algorithm = strAlgorithm)
str(ucra_model)
```
# Ploteo de la red Neuronal
Para visualizar el resultado de la red neuronal  
```{r}
plot(ucra_model, rep = "best")
```
  
# Evaluación de la performance del modelo  
Para la evaluación, utilizaremos los datos de prueba que habíamos generado y compararemos la predicción obtenida con los resultados reales
```{r}
model_results <- neuralnet::compute(ucra_model,ucra_test[1:11])
predicted_quality <- model_results$net.result
predicted_quality[1:10]
```

  Predicted quality Vs Actual quality of test data.
```{r}
cor(predicted_quality,ucra_test$quality)
```
# Desnormalización de los resultados
Dado que hicimos la predicciones con los datos normalizados, ahora deberemos des-normalizarlos. Para esto nuevamente creamos una función.
```{r}
str_max <- max(ucrania$quality)
str_min <- min(ucrania$quality)

unnormalize <- function(x, min, max) { 
  return( (max - min)*x + min )
}

ActualQuality_pred <- unnormalize(predicted_quality,str_min,str_max)
head(ActualQuality_pred)
```
# Mejoramiento de la performance del modelo
Es posible mejorar la performance con el agregado de más capas ocultas. Por defecto, 'neuralnet' utiliza sólo una capa.
```{r}
ucra_model2 <- neuralnet(quality~. , data = ucra_train, hidden=c(4,2),  rep = 1, algorithm = strAlgorithm)
plot(ucra_model2 ,rep = "best")
```
  Nueva evaluación de performance
```{r}
model_results2 <- neuralnet::compute(ucra_model2,ucra_test[1:11])
predicted_quality2 <- model_results2$net.result
cor(predicted_quality2,ucra_test$quality)
```



