Análisis de los programas de candidatos en Argentina

Antes de comenzar a realizar las visualizaciones, se realiza la tokenización y limpieza del data set, para poder trabajar a nivel palabra.
#### Codigo para levantar los data sets y limpiarlos ####

#### Levanto los data sets

fernandez <- readr::read_csv("https://raw.githubusercontent.com/cienciadedatos/datos-de-miercoles/master/datos/2019/2019-09-04/argentina_frente-de-todos_fernandez_2019.txt")


macri <- readr::read_csv("https://raw.githubusercontent.com/cienciadedatos/datos-de-miercoles/master/datos/2019/2019-09-04/argentina_juntos-por-el-cambio_macri_2019.txt")


#### Abro las librerias necesarias

library(dplyr)
library(tidytext)
library(ggplot2)
library(purrr)
library(stringr)
library(tidyr)
library(forcats)
library(plotly)
library(collapsibleTree)

#### Convierto el set de datos en tipo "tibble"

fernandez <- tibble(line = 1:nrow(fernandez), text = fernandez$INTRODUCCIÓN)
macri <- tibble(line = 1:nrow(macri), text = macri$CAMBIEMOS)

#### Uno los dos data sets en uno solo

propuestas <- rbind(fernandez,macri)

#### Armo una columna para diferenciar el candidato

propuestas$Candidato <- c(rep("Fernandez",nrow(fernandez)),
                          rep("Macri",nrow(macri)))


#### Defino una funcion para limpiar y tokenizar los datos

limpiar_df <- function(texto){
  # El orden de la limpieza no es arbitrario
  # Se convierte todo el texto a minúsculas
  nuevo_texto <- tolower(texto)
  # Eliminación de páginas web (palabras que empiezan por "http." seguidas 
  # de cualquier cosa que no sea un espacio)
  nuevo_texto <- str_replace_all(nuevo_texto,"http\\S*", "")
  # Eliminación de signos de puntuación
  nuevo_texto <- str_replace_all(nuevo_texto,"[[:punct:]]", " ")
  #Elimino tildes en las letras
  nuevo_texto<-stringi::stri_trans_general(nuevo_texto,"Latin-ASCII")
  # Eliminación de números
  nuevo_texto <- str_replace_all(nuevo_texto,"[[:digit:]]", " ")
  # Eliminación de espacios en blanco múltiples
  nuevo_texto <- str_replace_all(nuevo_texto,"[\\s]+", " ")
  # Tokenización por palabras individuales
  nuevo_texto <- str_split(nuevo_texto, " ")[[1]]
  # Eliminación de tokens con una longitud < 2
  nuevo_texto <- keep(.x = nuevo_texto, .p = function(x){str_length(x) > 1})
  return(nuevo_texto)
}


#### Limpio y tokenizo los datos 

propuestas <- propuestas %>% mutate(texto_tokenizado = map(.x = text,
                                                           .f = limpiar_df))


#### Creo un nuevo data set ordenado, donde tengo una fila por palabra:

data_tidy <- propuestas %>% select(-text) %>% unnest()
data_tidy <- data_tidy %>% rename(token = texto_tokenizado)

Comienza el análisis!

¿Cuánto se habla en cada programa de los temas claves?

Para realizar este análisis, se definió un conjunto de palabras consideradas como “temas claves”, a los efectos de detectar la porción del programa destinada a ese tema. Los temas elegidos son los siguientes:
#### Sobre "data_tidy", reemplazo algunas palabras, para poder englobar al analisis por temas:

data_tidy$token[data_tidy$token=="derecho"]<-"derechos"
data_tidy$token[data_tidy$token=="juventudes"]<-"juventud"
data_tidy$token[data_tidy$token=="economicas"]<-"economia"
data_tidy$token[data_tidy$token=="economica"]<-"economia"
data_tidy$token[data_tidy$token=="educativas"]<-"educativa"
data_tidy$token[data_tidy$token=="casa"]<-"vivienda"
data_tidy$token[data_tidy$token=="trabajadores"]<-"trabajo"
data_tidy$token[data_tidy$token=="trabajadores"]<-"trabajo"
data_tidy$token[data_tidy$token=="exterior"]<-"internacional"

#### Hago el conteo de palabras, excluyendo las stop words: 

data_tidy %>%
  group_by(Candidato,token) %>%
  count(token, sort = TRUE) -> conteo

#### Me quedo con las palabas me interesan analizar en este caso:

palabras_interesantes <- c("trabajo","derechos","vivienda","salud","educacion","seguridad","ciencia","igualdad","economia","crisis","cambiemos","social","juventud","internacional")

palabras_interesantes
##  [1] "trabajo"       "derechos"      "vivienda"      "salud"        
##  [5] "educacion"     "seguridad"     "ciencia"       "igualdad"     
##  [9] "economia"      "crisis"        "cambiemos"     "social"       
## [13] "juventud"      "internacional"
#### Este set de palabras las elegi por lo que a mi parecer son los temas mas importantes, pero todo se puede cambiar
El siguiente gráfico muestra la cantidad de veces que se menciona cada palabra relacionada a cada tema seleccionado como importante. El tamaño de la burbuja denota la cantidad de veces que aparece dicha palabra (o alguna palabra que quiera decir lo mismo) en el programa de cada candidato.
#### Por ultimo, me quedo con el conteo unicamente de las palabras mas interesantes: 

conteo <- conteo %>%
            filter(token %in% palabras_interesantes)

#### Convierto en factor las variables a graficar: 

conteo$Candidato <- as.factor(conteo$Candidato)
conteo$token <- as.factor(conteo$token)

#### Armo el gafico: 

ggplot(conteo,
       aes(x=Candidato, y=token, size=n, fill=Candidato)) +
  geom_point(alpha=0.5, shape=21, color="black") +
  scale_size(range = c(2, 20), name="Frecuencia") +
  ylab("Palabras de interes") +
  xlab("Candidato") +
  theme(legend.position = "none") +
  theme_bw() -> p

ggplotly(p)

¿Cómo es la estructura de cada programa?

El siguiente TreeMap intenta mostrar cómo es la estructura del programa de cada candidato. El tamaño de cada porción se encuentra dado por la cantidad de lineas dedicadas a ese tema. A simple vista puede observarse que el programa de Fernandez es más extenso (tiene mayor cantidad de líneas) y abarca más cantidad de temas principales que el de Macri.
#### Vuelvo a crear el data_tidy (para que las palabras reemplazadas vuelvan a ser las originales)

data_tidy <- propuestas %>% select(-text) %>% unnest()
data_tidy <- data_tidy %>% rename(token = texto_tokenizado)

#### Defino la estructura del documento (esto es completamente manual)

data_tidy %>%
  mutate(Estructura =case_when(line %in% 1:6 & Candidato == "Macri" ~ "INTRO",
                               line %in% 7:18 & Candidato == "Macri" ~ "PRINCIPIOS",
                               line %in% 19:20 & Candidato == "Macri" ~ "PLATAF. ELECTORAL",
                               line %in% 21:46 & Candidato == "Macri" ~ "INCLUSION SOCIAL",
                               line %in% 47:66 & Candidato == "Macri" ~ "DESARROLLO ECONOMICO",
                               line %in% 67:92 & Candidato == "Macri" ~ "FORTALECIMIENTO INSTITUCIONAL",
                               line %in% 1:7 & Candidato == "Fernandez" ~ "INTRO",
                               line %in% 8:21 & Candidato == "Fernandez" ~ "ESTADO",
                               line %in% 22:32 & Candidato == "Fernandez" ~ "DESARROLLO ECONOMICO",
                               line %in% 33:62 & Candidato == "Fernandez" ~ "DESARROLLO SOCIAL",
                               line %in% 63:72 & Candidato == "Fernandez" ~ "TRABAJO",
                               line %in% 73:82 & Candidato == "Fernandez" ~ "PERSONAS MAYORES",
                               line %in% 83:92 & Candidato == "Fernandez" ~ "EDUCACION",
                               line %in% 93:99 & Candidato == "Fernandez" ~ "SALUD",
                               line %in% 100:106 & Candidato == "Fernandez" ~ "CIENCIA",
                               line %in% 107:113 & Candidato == "Fernandez" ~ "AMBIENTE",
                               line %in% 114:120 & Candidato == "Fernandez" ~ "JUSTICIA",
                               line %in% 121:127 & Candidato == "Fernandez" ~ "SEGURIDAD",
                               line %in% 128:132 & Candidato == "Fernandez" ~ "DDHH",
                               line %in% 133:140 & Candidato == "Fernandez" ~ "EQUIDAD GENERO",
                               line %in% 141:152 & Candidato == "Fernandez" ~ "TRANSPARENCIA",
                               line %in% 153:158 & Candidato == "Fernandez" ~ "CULTURA",
                               line %in% 159:169 & Candidato == "Fernandez" ~ "EXTERIOR",
                               line %in% 170:176 & Candidato == "Fernandez" ~ "DEFENSA"
                               )) -> data_tidy
  
#### Armo la agrupacion para el treemap 

data_tidy_ag <- data_tidy %>%
  group_by(Candidato,Estructura) %>%
  summarise(Cant_Lines = length(unique(line)))

library(treemap)
treemap(data_tidy_ag, 
        index=c("Candidato","Estructura"), 
        vSize = "Cant_Lines",  
        type="index", 
        title="Estructura del programa de cada candidato", 
        fontsize.title = 14,
        fontsize.labels=c(25,6),
        fontcolor.labels=c("white","black"),
        align.labels=list(
        c("center", "bottom"), 
        c("center", "center")
        ),
        inflate.labels=F,
        bg.labels=c("transparent"),
        border.col = c("black","gray"),
        border.lwds = c(5,1)
)

Análisis Relacional: árbol representando la estructura de cada programa

El siguiente árbol intenta mostrar cómo es la estructura de cada programa, y qué palabras son las más frecuentes dentro de cada tema tratado por cada candidato. Los nodos finales del árbol muestran el TOP 15 de palabras más frecuentes en cada tema tratado, siempre y cuando aparezcan al menos dos veces mencionadas en cada tema.

Por supuesto que previamente se han eliminado las “stop words”, para no ensuciar el análisis.

El tamaño de los nodos intermedios es el promedio de cantidad de veces que se repite cada palabra por nivel, mientras que el tamaño del nodo final representa la cantidad de veces que se repite cada palabra.

#### Defino las STOP WORDS: 

stop_words_general <- c("de","la","el","en","las","que","los",
                        "un","del","para","una","se","con",
                        "es","por","al","su","como","ello","esta",
                        "mas","sus","debe","este","no","sobre","desde",
                        "as","tiene","tambien","entre","ha","esto","nos",
                        "puede","cada","lo","otra","otro","sin","ante",
                        "estar","gran","lo","mayor","tal","tanto","si",
                        "sera","todo","ademas","dan","cuando","alla",
                        "la", "las", "el", "los", "a", "ante", "bajo", "cabe", "con", "contra", "de",
                        "desde", "durante", "en", "entre", "hacia", "hasta", "mediante", "para", "por",
                        "segun", "sin", "so", "sobre", "tras", "versus","via",
                        "me", "se", "una", "te", "esta", "tu", "pero", "yo", "como", "ya", "mi",
                        "aqui","le", "no", "si", "ha", "mas", "su", "nos", "hay", "he","no","si","ha",
                        "eso","mas","todo","su","nos","hay","he","va","voy","porque","eh","nada",
                        "muy","ahi","asi","todos","estas","favor", "hacer", "pues", "esto","cuando",
                        "este", "soy", "ni", "tengo", "donde" ,"dos","has","ese", "estan",
                        "uno","dos","tres","cuatro","cinco","seis","siete","ocho","nueve","diez",
                        "casi","cabo","ir","hora")


#### Armo el conteo

data_tidy_conteo <- data_tidy %>%
  filter(!token %in% stop_words_general) %>%
  group_by(Candidato,Estructura,token) %>%
  count(token, sort = TRUE)

#### Armo la logica para tomar el top de cada categoria 

# Primero defino mi clave unica, que en este caso es la combinacion de candidato y estructura:

CLAVE <- unique(paste(data_tidy_conteo$Candidato,data_tidy_conteo$Estructura))

CLAVE <- data.frame(CLAVE,
                    ORDEN=1:length(CLAVE))

# Armo el vector con cantidad de filas como el data set de conteo de palabras, matcheando el numero de codigo que le asigne a cada combinacion de candidato y estructura

CLAVE_data_tidy <- paste(data_tidy_conteo$Candidato,data_tidy_conteo$Estructura)

data_tidy_conteo$CLAVE_ORDEN <- CLAVE$ORDEN[match(CLAVE_data_tidy,CLAVE$CLAVE)]

# Ordeno el data set segun la clave asignada

data_tidy_conteo %>% 
  arrange(CLAVE_ORDEN,-n) -> data_tidy_conteo

# Agrego una columna que simplemente cuenta del 1 hasta la cantidad de filas del data set

data_tidy_conteo$ORDEN <- 1:nrow(data_tidy_conteo)

# Me armo una referencia de en que valor del orden empieza una nueva clave

MINIMOS <- data_tidy_conteo %>% 
  group_by(CLAVE_ORDEN) %>%
  summarise(MIN=min(ORDEN))

# Matcheo este minimo 

data_tidy_conteo$MIN <- MINIMOS$MIN[match(data_tidy_conteo$CLAVE_ORDEN,MINIMOS$CLAVE_ORDEN)]

# Hago el conteo por categoria 

data_tidy_conteo %>% 
  mutate(CONTEO_PORCLAVE= ORDEN - MIN +1 ) -> data_tidy_conteo

# Filtro para quedarme con el top 15 de las palabras mas frecuentes en cada tematica, siempre y cuando haya aparecido al menos 2 veces en dicha seccion- 

data_tidy_conteo %>% 
  filter(CONTEO_PORCLAVE<=15 & n>=2) -> data_tidy_conteo

# Armo la columna que se va a mostrar al final del grafico (cantidad de veces que aparece cada palabre)

data_tidy_conteo$Palabra <- paste0(data_tidy_conteo$token," (",data_tidy_conteo$n," veces)")

# Para definir los colores, calculo la cantidad de veces que aparece cada combinacion posible

nivel_1 <- length(unique(data_tidy_conteo$Candidato))

# A partir de aca voy concatenando el nivel 1 y el 2, luego agrego el 3, ay asi con todos los niveles que tenga

nivel_2 <- length(unique(paste(data_tidy_conteo$Candidato,data_tidy_conteo$Estructura)))

nivel_3 <- length(unique(paste(data_tidy_conteo$Candidato,data_tidy_conteo$Estructura,data_tidy_conteo$Palabra)))

p <- collapsibleTree(data_tidy_conteo, 
                     root="Candidatos Argentinos",
                     hierarchy = c("Candidato", "Estructura","Palabra"),
                     fontSize = 12,
                     nodeSize = "n",
                     fill = c("darkmagenta",
                              rep("plum", nivel_1),
                              rep("lightskyblue",nivel_2),
                              rep("mediumseagreen",nivel_3)),
                     collapsed = TRUE,
                     attribute = "n",
                     aggFun=mean,
                     tooltip=TRUE,
                     zoomable = TRUE,
                     fillByLevel=TRUE)
p