1 Declaración

Yo, PATRICIO ANDRES LLANOS BAHAMONDES, declaro que realicé los pasos de la presente actividad.

2 Instrucciones

Los objetivos de este tutorial son:

  1. Familiarizarse con el uso de RStudio, e
  2. Interiorizarse con R para la manipulación de datos, leyendo y ejecutando este tutorial.

3 Introducción

3.1 Instalando los requisitos

Primero debe instalar R y RStudio:

3.2 Instalar librerías

Copie y pegue el siguiente código en la consola de R para instalar las librerías necesarias para este tutorial y el siguiente laboratorio:

install.packages("reshape")
install.packages("tidyverse")
install.packages("ggplot2")
install.packages("tm")

3.3 RStudio

La interfaz de RStudio es sencilla. En el panel superior izquierdo se encuentra el editor de código fuente, en el panel inferior izquierdo está el intérprete, en el panel superior derecho se encuentra el ambiente o listado de variables cargadas, y en el panel inferior derecho está el explorador de archivos. Todo esto se puede apreciar en la figura de abajo.

3.4 RMarkdown

Una metodología que se ha hecho muy popular en el análisis de datos es el uso de notebooks que mezclan contenido multimedia (texto, imágenes) con código fuente ejecutable, como este mismo documento. Esto también se conoce como literate programming.

Para R existe el formato RMarkdown, que es Markdown aumentado con sintaxis de R, que se puede ejecutar dentro de RStudio.

Por ejemplo, abra este documento en RStudio, posicione el cursor dentro del siguiente bloque de código, y presione Ctrl+Shift+Enter.

x <- c(1, 2, 3)
x^2
## [1] 1 4 9

Puede presionar Ctrl+Enter para ejecutar una línea individual, o hacer click Run en la barra de herramientas que está sobre el editor.

Note que las tildes inversas y {r} no son parte del código fuente, sino que son una expresión de RMarkdown para denotar un bloque de código.

3.5 Exportar este documento

Para exportar este documento a otros formatos, haga click en Knit en la barra de herramientas, en File -> Knit Document, o presionando Ctrl+Shift+K. Probablemente RStudio pedirá descargar algunas librerías. El archivo será generado en el mismo directorio donde se encuentra el .Rmd. Ábralo para confirmar que fue generado correctamente.

Se puede generar la versión HTML de este documento, lo que dará evidencia de que instaló las librerías necesarias para los siguientes laboratorios.

3.6 Problemas con la codificación

Si en este tutorial tiene problemas respecto a las tildes, realice lo siguiente. En Tools -> Global Options. Luego, busque en el menú Code -> Saving -> Default Text Encoding. Presione Change y escoja UTF-8. Guarde sus cambios para finalmente re-abrir el archivo en la codificación correcta. Para ello, presione File -> Reopen with Encoding y seleccione la misma codificación anterior.

4 Comandos básicos de R

Para ejecutar cada bloque, en el editor, posiciona el cursor en el código fuente correspondiente y presiona Ctrl+Shift+Enter para ejecutar el bloque completo, o Ctrl+Enter para ejecutar sólo la línea correspondiente.

x <- c(1, 2, 3)
x^2
## [1] 1 4 9

Nota que cuando un bloque posee más de una instrucción, el output del bloque será la última instrucción escrita, por lo que si quieres ver el output individual de cada instrucción, deberás posicionarte sobre ésta y presionar Ctrl+Enter o hacer click en Run en la barra de herramientas.

4.1 Vectores

# un vector cuyos valores son los enteros 1 2 3 
c(1, 2, 3) 
## [1] 1 2 3
# un vector cuyos valores son caracteres a,b,c
c("a", "b", "c") 
## [1] "a" "b" "c"
# un vector cuyos valores tienen nombre
c(a = 1, b = 2, c = 3) 
## a b c 
## 1 2 3

4.2 Asignación

# se asigna el valor 5 a la variable a
a <- 5  
# la asignacion no imprime el resultado, para ello hay que llamar directamente a la variable
a
## [1] 5
# una forma de asignar y evaluar a la vez es usar paréntesis
(a <- 5)
## [1] 5
# se asigna un arreglo a a2
a2 <- c(1, a + 1, a - 1)   
a2
## [1] 1 6 4
# se asigna un arreglo a a3 con encabezados incluidos 
a3 <- c(a = 1, b = 2, c = a + 2) 

names(a3) # muestro los encabezados de a3
## [1] "a" "b" "c"
# c() también sirve para "combinar" valores
# de esta forma se puede adjuntar valores a un vector
# nota que los números y caracteres son vectores de largo 1
a <- c(1, 2, 3)
b <- c(a, 4, 5, 6)
b
## [1] 1 2 3 4 5 6

4.3 Operaciones sobre vectores

# vector que va de 1 a 10
seq(1, 10)
##  [1]  1  2  3  4  5  6  7  8  9 10
# azúcar sintáctico para lo anterior
1:10
##  [1]  1  2  3  4  5  6  7  8  9 10
# vector que va de 1 a 9, cada 2
seq(1, 10, 2)
## [1] 1 3 5 7 9
# repetir un valor N veces
rep(5, 3)
## [1] 5 5 5
# repetir un vector N veces
rep(c(1, 2), 3)
## [1] 1 2 1 2 1 2
# suma los valores de un vector
sum(seq(1, 10, 2))
## [1] 25
# largo del vector
length(c(1, 2, 3))
## [1] 3
# Operaciones típicas
# Nota que las funciones están vectorizadas, es decir, funcionan sobre escalares y vectores (recuerda que un escalar es un vector de largo 1)
a <- c(1, 3, 5, 7)

# Exponencial
exp(a)
## [1]    2.718282   20.085537  148.413159 1096.633158
# Suma
sum(a)  
## [1] 16
# Logaritmo natural
log(a) 
## [1] 0.000000 1.098612 1.609438 1.945910
# Log base 10
log10(a)
## [1] 0.0000000 0.4771213 0.6989700 0.8450980
# Promedio
mean(a) 
## [1] 4
# Desv estandar
sd(a) 
## [1] 2.581989
# Mediana
median(a)
## [1] 4

4.4 Data frames

Un data frame es una tabla, con filas y columnas. Cada columna debe tener nombre mientras que las filas pueden tener nombre, pero no es recomendable.

# definimos una tabla con dos columnas, `x` e `y`, cuyos valores son como sigue
d <- data.frame(x = c(10, 20, 30), y = c("a", "b", "c"), voltaje= rep(1,3))
# Muestra todo el data frame, note como se crean los encabezados.
d
##    x y voltaje
## 1 10 a       1
## 2 20 b       1
## 3 30 c       1
# Para mostrar sólo la columna x.
d$x 
## [1] 10 20 30
# Para mostrar sólo la columna y.
d$y 
## [1] "a" "b" "c"
# Para indicar el número de filas de d.
nrow(d)  
## [1] 3
# Para indicar el número de columnas de d.
ncol(d)  
## [1] 3
# Para indicar el número de filas y columnas de d
dim(d)
## [1] 3 3

Para ver ayuda se emplea ? o help()

?sum   
help(sum)

5 Ejemplo: Datos de Accidentes de Tránsito en Chile

Usaremos los datos de accidentes de tránsito en Chile en los años 2010 y 2011.

Puedes descargar los datos al computador de las siguientes direcciones:

https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/accidentes_2010_2011.txt https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/afectados_2010_2011.txt

Si lo descargas a un directorio (por ejemplo ~/RDATA/), debes indicarle a R cuál será el directorio de trabajo:

# Asignamos nuestro "working directory" (set w. d.) como el directorio ~/RDATA
setwd("~/RDATA/")

Luego asignarle una variable a cada dataset mediante read.table():

# Se asume que los archivos se encuentran en el w.d., si no los tienes descargados, lo siguiente fallará:
tipos <- read.table("accidentes_2010_2011.txt")
afectados <- read.table("afectados_2010_2011.txt")

Para cargar los datos remotamente:

tipos <- read.table("https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/accidentes_2010_2011.txt")
afectados <- read.table("https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/afectados_2010_2011.txt")

Esta última opción es conveniente porque son archivos pequeños.

Siempre que llegue a sus manos un dataset, lo primero es hacer una revisión inicial para entender cómo están estructurados los datos. Esto significa, entender cuántos datos son, cuántas columnas, qué describe cada columna, el tipo de datos de las columnas, normalización de datos, entre otras cosas.

En nuestro caso, el dataset tipos contiene la frecuencia de los distintos tipos de accidentes ocurridos en el 2010 y 2011, en Chile. Por otro lado, el dataset afectados contiene el estado de gravedad en que terminaron los accidente en Chile. Desde luego que ambos datasets se complementan.

En el caso de tener problemas con las tildes a pesar de seguir los pasos de la sección Problemas con la codificación, se recomienda usar el parámetro encoding. Por otro lado, al usar read.table los campos de caracteres (chr) son convertidos en tipo Factor por defecto. Para esto último, se recomienda usar el parámetro as.is:

tipos <- read.table("https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/accidentes_2010_2011.txt", encoding = "UTF-8", as.is = F)
afectados <- read.table("https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/afectados_2010_2011.txt", encoding = "UTF-8", as.is = F)

5.1 Atributos de un dataset

str(tipos)
## 'data.frame':    4296 obs. of  5 variables:
##  $ Muestra      : Factor w/ 3 levels "Comunal","Nacional",..: 2 2 3 3 1 1 1 1 1 1 ...
##  $ Descripcion  : Factor w/ 359 levels "AISEN","ALGARROBO",..: 182 182 355 355 13 13 25 25 248 248 ...
##  $ Anio         : int  2010 2011 2010 2011 2010 2011 2010 2011 2010 2011 ...
##  $ TipoAccidente: Factor w/ 6 levels "Atropello","Caida",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ Cantidad     : int  8247 8339 115 159 115 158 0 0 0 1 ...

Acá se muestra el nombre de los campos, el tipo de datos y una pequeña muestra de los datos. Cuando es Factor significa que el valor de ese campo toma un valor diferente un número limitado de veces. Por ejemplo, el campo Muestra tiene 3 tipos de valores “Comunal”, “Nacional” y el otro no se alcanza a visualizar. Lo mismo con Descripción, es una “Factor” con 359 valores diferentes. En contraste, Cantidad es una valor continuo por lo tanto indica que es entero y se da una muestra de estos valores ” 8247 8339…. etc”.

Ahora, lo mismo para afectados:

str(afectados)
## 'data.frame':    2864 obs. of  5 variables:
##  $ Muestra    : Factor w/ 3 levels "Comunal","Nacional",..: 2 2 3 3 1 1 1 1 1 1 ...
##  $ Descripcion: Factor w/ 358 levels "AISEN","ALGARROBO",..: 182 182 354 354 13 13 25 25 248 248 ...
##  $ Anio       : int  2010 2011 2010 2011 2010 2011 2010 2011 2010 2011 ...
##  $ Estado     : Factor w/ 4 levels "Graves","Leves",..: 4 4 4 4 4 4 4 4 4 4 ...
##  $ Cantidad   : int  1595 1573 28 33 24 29 2 2 2 2 ...

5.2 Funciones head y view

Con la función head podemos hacernos una idea de cómo son los datos, nos muestra los primeros 6 datos del dataset con los encabezados de cada atributo. Esto es útil para ver si los datos quedaron bien cargados o no (mejor mostrar unos pocos a mostrar todo el dataset completo). Mientras que la función view muestra el dataset completo.

head(tipos)
##    Muestra                  Descripcion Anio TipoAccidente Cantidad
## 1 Nacional                     Nacional 2010     Atropello     8247
## 2 Nacional                     Nacional 2011     Atropello     8339
## 3 Regional XV Región Arica y Parinacota 2010     Atropello      115
## 4 Regional XV Región Arica y Parinacota 2011     Atropello      159
## 5  Comunal                        ARICA 2010     Atropello      115
## 6  Comunal                        ARICA 2011     Atropello      158
nrow(tipos)
## [1] 4296

Ahora lo mismo para afectados:

head(afectados)
##    Muestra                  Descripcion Anio  Estado Cantidad
## 1 Nacional                     Nacional 2010 Muertos     1595
## 2 Nacional                     Nacional 2011 Muertos     1573
## 3 Regional XV Región Arica y Parinacota 2010 Muertos       28
## 4 Regional XV Región Arica y Parinacota 2011 Muertos       33
## 5  Comunal                        ARICA 2010 Muertos       24
## 6  Comunal                        ARICA 2011 Muertos       29
nrow(afectados)
## [1] 2864

5.3 Función summary

La función summary aplica estadísticas a cada columna. En particular, indica el promedio, mediana, quantiles, valor máximo, mínimo, entre otros.

summary(tipos)
##      Muestra              Descripcion        Anio        TipoAccidente
##  Comunal :4104   AISEN          :  12   Min.   :2010   Atropello:716  
##  Nacional:  12   ALGARROBO      :  12   1st Qu.:2010   Caida    :716  
##  Regional: 180   ALHUE          :  12   Median :2010   Choque   :716  
##                  ALTO BIO BIO   :  12   Mean   :2010   Colision :716  
##                  ALTO DEL CARMEN:  12   3rd Qu.:2011   Otros    :716  
##                  ALTO HOSPICIO  :  12   Max.   :2011   Volcadura:716  
##                  (Other)        :4224                                 
##     Cantidad      
##  Min.   :    0.0  
##  1st Qu.:    1.0  
##  Median :    5.0  
##  Mean   :   84.2  
##  3rd Qu.:   20.0  
##  Max.   :31487.0  
## 
summary(afectados)
##      Muestra              Descripcion        Anio              Estado   
##  Comunal :2736   AISEN          :   8   Min.   :2010   Graves     :716  
##  Nacional:   8   ALGARROBO      :   8   1st Qu.:2010   Leves      :716  
##  Regional: 120   ALHUE          :   8   Median :2010   MenosGraves:716  
##                  ALTO BIO BIO   :   8   Mean   :2010   Muertos    :716  
##                  ALTO DEL CARMEN:   8   3rd Qu.:2011                    
##                  ALTO HOSPICIO  :   8   Max.   :2011                    
##                  (Other)        :2816                                   
##     Cantidad      
##  Min.   :    0.0  
##  1st Qu.:    3.0  
##  Median :    9.0  
##  Mean   :  115.6  
##  3rd Qu.:   32.0  
##  Max.   :43034.0  
## 

Aunque también podemos hacer el muestreo por separado empleando las siguientes funciones:

# promedio columna Cantidad
mean(tipos$Cantidad)
## [1] 84.20391
# desviacion estandar
sd(afectados$Cantidad) 
## [1] 1220.347
# minimo (maximo)
min(tipos$Cantidad)
## [1] 0
# mediana
median(tipos$Cantidad) 
## [1] 5
# cuantiles, los valores que son mayores que una fracción $q$ de los datos
quantile(tipos$Cantidad)
##    0%   25%   50%   75%  100% 
##     0     1     5    20 31487
quantile(tipos$Cantidad, probs = c(0, .5, .8, .9)) 
##  0% 50% 80% 90% 
##   0   5  29  92
# diferencia entre cuartil 3 y cuartil 1  (Q3 - Q1), o cuantil 0.75 y cuantil 0.25
IQR(tipos$Cantidad)
## [1] 19

6 Consultas sobre data frames (proyección y filtro)

Para proyectar o seleccionar columnas de una tabla, usamos el operador $. (Siempre emplearemos head para no alargar este manual).

# muestra sólo la columna Cantidad
# note que el resultado de esta operación es un Vector
head(tipos$Cantidad)   
## [1] 8247 8339  115  159  115  158

También podemos seleccionar columnas usando su índice en la tabla.

# en R los índices parten desde 1
# note que el output en este caso es un data frame
head(tipos[5])
##   Cantidad
## 1     8247
## 2     8339
## 3      115
## 4      159
## 5      115
## 6      158
head(tipos["Cantidad"])
##   Cantidad
## 1     8247
## 2     8339
## 3      115
## 4      159
## 5      115
## 6      158
# se puede seleccionar más de una columna
head(tipos[c(4, 5)])
##   TipoAccidente Cantidad
## 1     Atropello     8247
## 2     Atropello     8339
## 3     Atropello      115
## 4     Atropello      159
## 5     Atropello      115
## 6     Atropello      158
head(tipos[c("TipoAccidente", "Cantidad")])
##   TipoAccidente Cantidad
## 1     Atropello     8247
## 2     Atropello     8339
## 3     Atropello      115
## 4     Atropello      159
## 5     Atropello      115
## 6     Atropello      158

Ahora, para filtrar filas, usamos la notación [filas, columnas].

# fila 3, columna 5
# el resultado es un vector
tipos[3, 5]
## [1] 115
# De la fila 3, muestra todas las columnas
# el resultado es un data frame
tipos[3, ] 
##    Muestra                  Descripcion Anio TipoAccidente Cantidad
## 3 Regional XV Región Arica y Parinacota 2010     Atropello      115

¡OJO con la coma dentro de los paréntesis! Si no la usas, estarás proyectando la columna 3 en vez de elegir la fila 3 y todas las columnas.

head(tipos[3])
##   Anio
## 1 2010
## 2 2011
## 3 2010
## 4 2011
## 5 2010
## 6 2011

También podemos hacer referencia al nombre de la columna:

# Muestra la columna Cantidad
# en este caso, el output es un vector
head(tipos[, c("Cantidad")]) 
## [1] 8247 8339  115  159  115  158

También podemos ser más específicos.

# Muestra los primeros 6 datos y las columnas seleccionadas
tipos[0:6, c("Anio","TipoAccidente")]
##   Anio TipoAccidente
## 1 2010     Atropello
## 2 2011     Atropello
## 3 2010     Atropello
## 4 2011     Atropello
## 5 2010     Atropello
## 6 2011     Atropello

Desde luego que podemos crear condiciones o filtros.

# Para cada valor de la columna Anio, indica si es 2010 o no (mediante True y False)
head(afectados$Anio == 2010) 
## [1]  TRUE FALSE  TRUE FALSE  TRUE FALSE
# Suma cuántos datos hay en la columna Anio con valor 2010
sum(afectados$Anio == 2010) 
## [1] 1432

Una función util para contar cuantos valores son NA en una columna, es la siguiente:

sum(is.na(afectados$Anio))
## [1] 0

Para todas las columnas:

sapply(afectados, function(x) sum(is.na(x)))
##     Muestra Descripcion        Anio      Estado    Cantidad 
##           0           0           0           0           0

Por ejemplo que muestre sólo los datos del 2011:

# Filtra los datos cuyo año es 2011 y muestra todas las columnas (notar que ahora no muestra TRUE/FALSE)
head(afectados[afectados$Anio == 2011, ]) 
##     Muestra                  Descripcion Anio  Estado Cantidad
## 2  Nacional                     Nacional 2011 Muertos     1573
## 4  Regional XV Región Arica y Parinacota 2011 Muertos       33
## 6   Comunal                        ARICA 2011 Muertos       29
## 8   Comunal                    CAMARONES 2011 Muertos        2
## 10  Comunal                        PUTRE 2011 Muertos        2
## 12  Comunal                GENERAL LAGOS 2011 Muertos        0
# Filtramos que la columna Anio sea 2011 y además que la columna Muestra sea Regional. Se muestran todas las columnas. 
head(afectados[afectados$Anio == 2011 & afectados$Muestra == "Regional", ]) 
##      Muestra                  Descripcion Anio  Estado Cantidad
## 4   Regional XV Región Arica y Parinacota 2011 Muertos       33
## 14  Regional         I Región de Tarapacá 2011 Muertos       56
## 30  Regional     II Región de Antofagasta 2011 Muertos       87
## 50  Regional        III Región de Atacama 2011 Muertos       53
## 70  Regional        IV Región de Coquimbo 2011 Muertos       73
## 102 Regional       V Región de Valparaíso 2011 Muertos      151
# Filtramos que la columna Anio sea 2011 y además que la columna Muestra sea Regional. Seleccionamos la Descripcion y la Cantidad
head(afectados[afectados$Anio == 2011 & afectados$Muestra == "Regional", c("Descripcion", "Cantidad")])
##                      Descripcion Cantidad
## 4   XV Región Arica y Parinacota       33
## 14          I Región de Tarapacá       56
## 30      II Región de Antofagasta       87
## 50         III Región de Atacama       53
## 70         IV Región de Coquimbo       73
## 102       V Región de Valparaíso      151

Con with hacemos la misma clase de filtro, pero sin tener que usar la notación $:

with(afectados, afectados[Anio == 2011 & Descripcion == "TEMUCO", ])
##      Muestra Descripcion Anio      Estado Cantidad
## 420  Comunal      TEMUCO 2011     Muertos       18
## 1136 Comunal      TEMUCO 2011      Graves      151
## 1852 Comunal      TEMUCO 2011 MenosGraves       70
## 2568 Comunal      TEMUCO 2011       Leves     1080

Más adelante veremos una forma más sencilla de realizar todas estas operaciones.

7 Operaciones sobre data frames

7.1 Aggregate

Para saber cuántos muertos por accidentes hubo en todo Chile podemos emplear aggregate. Esto es similar a GROUP BY en SQL.

# Aplica la función suma (sum) a la columna Cantidad en base a los datos de Estado
aggregate(Cantidad ~ Estado, afectados, FUN=sum) 
##        Estado Cantidad
## 1      Graves    40869
## 2       Leves   254334
## 3 MenosGraves    26325
## 4     Muertos     9504

Esta función hará grupos dentro de afectados, donde cada grupo estará asociado al mismo valor de Estado, y estará compuesto de todos los valores dados por Cantidad. A cada uno de estos grupos aplicará la función FUN, que en este caso es sum. Es decir, entregará la suma de las cantidades agrupadas por cada estado.

La notación X ~ Y se llama formula en R.

También podríamos ser más especificos y sumar la columna cantidad agrupando por Estado y Anio.

aggregate(Cantidad ~ Estado + Anio, afectados, FUN=sum)
##        Estado Anio Cantidad
## 1      Graves 2010    20697
## 2       Leves 2010   125232
## 3 MenosGraves 2010    12963
## 4     Muertos 2010     4785
## 5      Graves 2011    20172
## 6       Leves 2011   129102
## 7 MenosGraves 2011    13362
## 8     Muertos 2011     4719

7.2 Unique

Con unique podemos obtener el conjunto de datos (sin repetir) de una columna.

# muestra los valores diferentes que tiene la columna TipoAccidente.
unique(tipos$TipoAccidente)
## [1] Atropello Caida     Colision  Choque    Volcadura Otros    
## Levels: Atropello Caida Choque Colision Otros Volcadura

7.3 Order y sort

En algún momento vamos a requerir ordenar las columnas en base a uno o más atributos. Por ejemplo:

# Para hacer el ejemplo pequeño, vamos a tomar los 10 primeros datos de afectados
afectados_reducido <- afectados[1:10,]

# Ordenar ascendentemente la columna Cantidad
afectados_reducido[order(afectados_reducido$Cantidad), ] 
##     Muestra                  Descripcion Anio  Estado Cantidad
## 7   Comunal                    CAMARONES 2010 Muertos        2
## 8   Comunal                    CAMARONES 2011 Muertos        2
## 9   Comunal                        PUTRE 2010 Muertos        2
## 10  Comunal                        PUTRE 2011 Muertos        2
## 5   Comunal                        ARICA 2010 Muertos       24
## 3  Regional XV Región Arica y Parinacota 2010 Muertos       28
## 6   Comunal                        ARICA 2011 Muertos       29
## 4  Regional XV Región Arica y Parinacota 2011 Muertos       33
## 2  Nacional                     Nacional 2011 Muertos     1573
## 1  Nacional                     Nacional 2010 Muertos     1595
# Ordenar descendente la columna Cantidad
afectados_reducido[order(afectados_reducido$Cantidad, decreasing = TRUE), ]
##     Muestra                  Descripcion Anio  Estado Cantidad
## 1  Nacional                     Nacional 2010 Muertos     1595
## 2  Nacional                     Nacional 2011 Muertos     1573
## 4  Regional XV Región Arica y Parinacota 2011 Muertos       33
## 6   Comunal                        ARICA 2011 Muertos       29
## 3  Regional XV Región Arica y Parinacota 2010 Muertos       28
## 5   Comunal                        ARICA 2010 Muertos       24
## 7   Comunal                    CAMARONES 2010 Muertos        2
## 8   Comunal                    CAMARONES 2011 Muertos        2
## 9   Comunal                        PUTRE 2010 Muertos        2
## 10  Comunal                        PUTRE 2011 Muertos        2
# Otra forma de ordenar descendente
afectados_reducido[order(-afectados_reducido$Cantidad), ]
##     Muestra                  Descripcion Anio  Estado Cantidad
## 1  Nacional                     Nacional 2010 Muertos     1595
## 2  Nacional                     Nacional 2011 Muertos     1573
## 4  Regional XV Región Arica y Parinacota 2011 Muertos       33
## 6   Comunal                        ARICA 2011 Muertos       29
## 3  Regional XV Región Arica y Parinacota 2010 Muertos       28
## 5   Comunal                        ARICA 2010 Muertos       24
## 7   Comunal                    CAMARONES 2010 Muertos        2
## 8   Comunal                    CAMARONES 2011 Muertos        2
## 9   Comunal                        PUTRE 2010 Muertos        2
## 10  Comunal                        PUTRE 2011 Muertos        2

Otra forma de ordenar es usando sort.

7.4 Merge

Tal como lo vimos al principio de este documento, para crear un nuevo data frame se usa data.frame(). Por ejemplo:

a <- data.frame(x1 = 0:8, y1 = c(10,20,40,60,80,100,120,140,160))
b <- data.frame(x1 = c(1,2,4,6,8,10), y2 = c(0,3,5,7,9,11))
a
##   x1  y1
## 1  0  10
## 2  1  20
## 3  2  40
## 4  3  60
## 5  4  80
## 6  5 100
## 7  6 120
## 8  7 140
## 9  8 160
b
##   x1 y2
## 1  1  0
## 2  2  3
## 3  4  5
## 4  6  7
## 5  8  9
## 6 10 11

También podemos hacer cruce entre ambos dataframes usando merge. Para hacerlo en base a la columna x1, sería:

# Inner join 
merge(a, b, by = "x1")
##   x1  y1 y2
## 1  1  20  0
## 2  2  40  3
## 3  4  80  5
## 4  6 120  7
## 5  8 160  9
# Full outer join
merge(a, b, by = "x1", all = T)
##    x1  y1 y2
## 1   0  10 NA
## 2   1  20  0
## 3   2  40  3
## 4   3  60 NA
## 5   4  80  5
## 6   5 100 NA
## 7   6 120  7
## 8   7 140 NA
## 9   8 160  9
## 10 10  NA 11
# Left outer join
merge(a, b, by = "x1", all.x = T)
##   x1  y1 y2
## 1  0  10 NA
## 2  1  20  0
## 3  2  40  3
## 4  3  60 NA
## 5  4  80  5
## 6  5 100 NA
## 7  6 120  7
## 8  7 140 NA
## 9  8 160  9
# Right outer join
merge(a, b, by = "x1", all.y = T)
##   x1  y1 y2
## 1  1  20  0
## 2  2  40  3
## 3  4  80  5
## 4  6 120  7
## 5  8 160  9
## 6 10  NA 11

7.5 rowSums y colSums

Para sumar toda las filas de un data frame:

df <- data.frame(x1=1:10, y1=1:10)
df
##    x1 y1
## 1   1  1
## 2   2  2
## 3   3  3
## 4   4  4
## 5   5  5
## 6   6  6
## 7   7  7
## 8   8  8
## 9   9  9
## 10 10 10
rowSums(df)  # suma cada fila de df
##  [1]  2  4  6  8 10 12 14 16 18 20
rowSums(df[df$x1 > 5,])  # suma las filas cuyo x1 es mayor a 5
##  6  7  8  9 10 
## 12 14 16 18 20

Para sumar las columnas de un data frame:

colSums(df)
## x1 y1 
## 55 55

7.6 Melt

La librería reshape permite reformatear o manipular una matriz de datos. Primero, cargamos el paquete:

library("reshape")

Consideremos el siguiente dataframe que contiene el registro de goles que convirtió Colo-Colo (CC) y la Universidad de Chile (U) en la primera y segunda jornada de la liga chilena:

d <- data.frame(jornada = c(1,2,1,2),
                equipo = c("CC", "CC", "U", "U"), 
                favor = c(3, 2, 1, 5),
                contra = c(0, 1, 2, 1))
d
##   jornada equipo favor contra
## 1       1     CC     3      0
## 2       2     CC     2      1
## 3       1      U     1      2
## 4       2      U     5      1

Por ejemplo, en la jornada 1, Colo-Colo hizo 3 goles (a favor) y no recibió goles en contra. En la misma jornada, la Universidad de Chile hizo 1 gol (a favor) y recibió 2 en contra.

Si quiero saber el total de goles de la primera jornada es mediante la suma de las columnas favor y contra:

f1 <- d[d$jornada == 1,]   
sum(f1[, c(3,4)])  # c(3,4) indica que tomará la columna 3 y la 4. 
## [1] 6
sum(f1[, c("favor", "contra")])  # lo mismo 
## [1] 6
sum(d[d$jornada == 1, 3:4])        # lo mismo 
## [1] 6

Ahora, algo más sofisticado es emplear melt() Esta función nos permitirá reformatear la tabla y dejar todos los goles en una sola columna.

d2 <- melt(d, id=c("jornada", "equipo"))  # jornada y equipo queda fijo, se crea un registro para cada instancia
d2   # observe qué es lo que hace
##   jornada equipo variable value
## 1       1     CC    favor     3
## 2       2     CC    favor     2
## 3       1      U    favor     1
## 4       2      U    favor     5
## 5       1     CC   contra     0
## 6       2     CC   contra     1
## 7       1      U   contra     2
## 8       2      U   contra     1

Con esto formateamos los datos de otra manera. En la función se le indica que deje fijas las columnas jornada y equipo, y cree un registro para cada instancia de favor y otro en contra. Además, observe el nombre de las nuevas columnas.

Con esto podríamos sumar más fácilmente todos los goles de la primera fecha:

f2 <- d2[d2$jornada == 1,]
sum(f2$value)
## [1] 6

8 tidyverse

Tidyverse (https://www.tidyverse.org/) es una “meta-librería”, que apunta a tener mejores librerías para la manipulación de datos en R. Una de las librerías incluidas en tidyverse es ggplot. Otra de las quizás más importantes es dplyr, que nos permite manipular datos fácilmente, como veremos a continuación.

library(tidyverse)
# Informacion del dataframe
glimpse(afectados)
## Rows: 2,864
## Columns: 5
## $ Muestra     <fct> Nacional, Nacional, Regional, Regional, Comunal, Comunal, …
## $ Descripcion <fct> Nacional, Nacional, XV Región Arica y Parinacota, XV Regió…
## $ Anio        <int> 2010, 2011, 2010, 2011, 2010, 2011, 2010, 2011, 2010, 2011…
## $ Estado      <fct> Muertos, Muertos, Muertos, Muertos, Muertos, Muertos, Muer…
## $ Cantidad    <int> 1595, 1573, 28, 33, 24, 29, 2, 2, 2, 2, 0, 0, 32, 56, 7, 1…
# Seleccionar una columna del dataframe
afectados %>%
  select(Cantidad) %>%
  head()
##   Cantidad
## 1     1595
## 2     1573
## 3       28
## 4       33
## 5       24
## 6       29

El operador %>% nos permite “encadenar” instrucciones, muy similar a ggplot. dplyr nos provee funciones para proyectar (select), filtrar (filter), modificar o crear nuevas columnas (mutate), agrupar (group_by y summarize), ordenar (arrange) etc.

afectados %>%
  filter(Anio == 2010 & Muestra == "Comunal") %>%   # Año 2010 y solo comunas
  group_by(Estado) %>%                       # Agrupamos por "muerto", "leve", etc
  summarise(total = sum(Cantidad)) %>%              # Creamos una nueva columna a partir de cada grupo, llamada "total"
  arrange(-total)           # Ordenamos descendentemente por "total"
## # A tibble: 4 × 2
##   Estado      total
##   <fct>       <int>
## 1 Leves       41744
## 2 Graves       6899
## 3 MenosGraves  4321
## 4 Muertos      1595

Con spread y gather podemos modificar la forma de un data frame (como con melt). Piense en spread como su traducción literal: “esparcir” un data frame, de uno con pocas columnas a uno de varias columnas; y en gather como “recolectar” varias columnas en pocas columnas.

Por ejemplo, queremos esparcir el Estado de los afectados por accidentes en varias columnas, y bajo cada columna poner la cantidad correspondiente:

sp <- afectados %>%
  spread(key = Estado, value = Cantidad)
head(sp)
##   Muestra Descripcion Anio Graves Leves MenosGraves Muertos
## 1 Comunal       AISEN 2010     11    57          11       1
## 2 Comunal       AISEN 2011      7    55           9       2
## 3 Comunal   ALGARROBO 2010      1    42           2       2
## 4 Comunal   ALGARROBO 2011      4    58           3       1
## 5 Comunal       ALHUE 2010      0     0           0       3
## 6 Comunal       ALHUE 2011      1     6           0       1

Luego, si queremos restaurar este data frame a su estado original, “recolectamos” las columnas:

# en dplyr podemos generar un vector de nombres usando la notacion:
# en este caso, `Graves:Muertos` creará un vector que considerará el orden del data frame original:
# -> c(Graves, Leves, MenosGraves, Muertos)
sp %>%
  gather(Graves:Muertos, key = "Estado", value = "Cantidad") %>%
  head()
##   Muestra Descripcion Anio Estado Cantidad
## 1 Comunal       AISEN 2010 Graves       11
## 2 Comunal       AISEN 2011 Graves        7
## 3 Comunal   ALGARROBO 2010 Graves        1
## 4 Comunal   ALGARROBO 2011 Graves        4
## 5 Comunal       ALHUE 2010 Graves        0
## 6 Comunal       ALHUE 2011 Graves        1

9 Gráficos

Los gráficos son clave para mostrar tendencias o la distribución de los datos. En R existen varios tipos de gráficos. Veremos ejemplos de cada uno de ellos.

9.1 Plot

Un gráfico básico que se emplea usando plot(). En el ejemplo se usa la exponencial e.

plot(exp(1:10))

Con líneas:

plot(exp(1:10), type = "l")

Si queremos agregarle decoración, como el título del gráfico y etiquetas a ambos ejes:

plot(exp(1:10), main="Mi primer gráfico", xlab="eje x", ylab="eje y", type = "l")

9.2 Boxplot

Los Boxplotsirven para ver la distribución de los datos. Por ejemplo, para ver la distribución de los datos basado en muestra Regional y del año 2011:

tipos2011 <- with(tipos,tipos[Muestra == "Regional" & Anio == 2011, ])
plot(tipos2011$TipoAccidente, tipos2011$Cantidad)

Si se dan cuenta, hay dos outlier que no nos permiten ver bien los gráficos. Por ello, podemos ajustar el límite del eje y usando ylim y además agregar texto (con esto sacamos al outlier del gráfico):

plot(tipos2011$TipoAccidente, tipos2011$Cantidad, ylim=c(0,4000), main="TITULO", 
     xlab="eje x", ylab="eje y")

Para jugar con el eje \(x\), usamos xlim de la misma forma.

9.3 Barplot

Otra opción es un gráfico de barras mostrando la cantidad de afectados. Primero hacemos el filtro, por ejemplo: muestra regional de muertos del 2011. Luego hacemos un gráfico de barras mostrando la cantidad por región (en este caso por la columna Descripción).

head(afectados)
##    Muestra                  Descripcion Anio  Estado Cantidad
## 1 Nacional                     Nacional 2010 Muertos     1595
## 2 Nacional                     Nacional 2011 Muertos     1573
## 3 Regional XV Región Arica y Parinacota 2010 Muertos       28
## 4 Regional XV Región Arica y Parinacota 2011 Muertos       33
## 5  Comunal                        ARICA 2010 Muertos       24
## 6  Comunal                        ARICA 2011 Muertos       29
afect2011 <- with(afectados,
                  afectados[ Muestra == "Regional" &
                                Anio == 2011 &
                              Estado == "Muertos", ])
barplot(afect2011$Cantidad, names.arg = afect2011$Descripcion)

9.4 Histograma

Los histogramas sirven para agrupar los datos en clases. Luego se cuenta la cantidad de observaciones (o frecuencia) que hay en cada una de ellas. Por ejemplo:

hist(afect2011$Cantidad)

9.5 Densidad

Una forma alternativa a los histogramas es hacer un gráfico de densidad de los datos. A veces la visualización de una gráfico de densidad es mejor que un histograma.

plot(density(afect2011$Cantidad))

9.6 ggplot2

La librería ggplot2 (https://ggplot2.tidyverse.org) permite hacer gráficos más elaborados. La idea principal detrás de ggplot es el uso de la “Gramática de Gráficos”, que nos ayuda a generar gráficos con una sintaxis más cómoda, que separa los componentes de un gráfico en distintas “capas”.

library(ggplot2)  # cargamos la librería

ggplot(afect2011) +   # asociamos un data frame a ggplot
  geom_bar(aes(x = Descripcion, y = Cantidad), stat="identity") +   # creamos un gráfico de barras como una capa
  coord_flip() +  # transformamos el gráfico invirtiendo los ejes de coordenadas (sólo visualmente)
  ggtitle("Muertos por accidentes durante el 2011") + # título
  xlab("Región (descripción)") + ylab("Frecuencia (cantidad)")  # etiquetas

La función aes nos permite hacer un mapeo desde columnas a variables visuales. En el ejemplo anterior, sólo usamos los ejes de coordenadas (x e y), pero podemos usar otras variables (color, shape, fill, size, type (tipo de línea), etc.). Podemos incluir aes dentro de cada capa por separado, o bien al comienzo, en la función ggplot, cuando queremos que todas las capas tengan el mismo mapeo.

ggplot(tipos2011, aes(x = TipoAccidente, y = Cantidad)) + 
  geom_boxplot()

ggplot(afect2011, aes(x=Cantidad)) + geom_histogram(binwidth = 50)

ggplot(tipos[tipos$Muestra == "Nacional", ], 
       aes(x=TipoAccidente, y=Cantidad)) +
  facet_grid(Anio ~ Descripcion) +
  coord_flip() +
  geom_bar(stat="identity")

Lo anterior se lee como: de la muestra Nacional, grafique TipoAccidente vs Cantidad, separados por Anioy Descripcion.

10 Manipulación de texto

Si bien, para los humanos es fácil entender y representar el lenguaje (palabras, oraciones, etc), para un computador no es trivial. Para ello, debemos realizar ciertas operaciones para que estas sean comprendidas para el análisis. Para ello, usaremos una colección de mensajes de redes sociales.

msj <- read.csv("https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/messages.csv",sep = ";", quote = "\"'")

Este dataset, posee 2 columnas que corresponden al identificador y el cuerpo del mensaje.

head(msj)
##     tweet_id
## 1 9725643670
## 2 9725759250
## 3 9725877906
## 4 9726077826
## 5 9721475512
## 6 9721677425
##                                                                                                                                     tweet_text
## 1                                                                                     fuentes sobre el terremoto en chile http://bit.ly/auedsj
## 2          sube el parte de víctimas: las autoridades chilenas informan de que al menos 64 personas fallecieron en las... http://bit.ly/awx73m
## 3                                                                         despierta desde el terremoto y no puedo pegar un ojo #terremotochile
## 4                                                                                 en magallanes estamos muy preocupados por parral y concepció
## 5 #internetnecesario rt @ac_scl se recogió el mar en algarrobo informa radio bio bio!! // precaucion ante tsunami @drpisanty sismologicos wrld
## 6                                                           vamos todavía hermanos chilenos...! un abrazo solidario para lo que queda de noche

Crearemos una tercera columna en nuestro dataset el cual tendrá el texto (mensaje) sin tildes. Para ello usaremos una lista que contiene una especie de diccionario que convertirá un patrón en otro.

replacement.list <- list('á' = 'a', 'é' = 'e', 'í' = 'i', 'ó' = 'o', 'ú' = 'u' ,'Á' = 'A', 'É' = 'E', 'Í' = 'I', 'Ó' = 'O', 'Ú' = 'U')

msj <- msj %>% 
      mutate(tweet_text_nacc = chartr(old = names(replacement.list) %>% str_c(collapse = ''), 
                           new = replacement.list %>% str_c(collapse = ''),
                           x = tweet_text))

10.1 Bag-of-words

La forma más tradicional de representar texto, es considerar cada elemento (token) de una cierta oración (párrafo, etc) y agregarlo como una columna en nuestro dataset. La idea principal es considerar, por ejemplo, si aparece o no una palabra en cierto documento o cuántas veces aparece en él. Por lo tanto, podríamos tener tantas columnas como elementos tengamos en la colección completa. Adicionalmente, consideraremos cada fila (cada mensaje) como un documento.

Para lograr esto, utilizaremos la librería tm la cual permite realizar text mining en R.

library(tm)

Convertiremos nuestro vector de mensajes de texto a uno que pueda ser leído por tm, donde habrán tantos documentos como mensajes de texto. Luego, crearemos un Corpus o colección de documentos.

docs <- VectorSource(msj[, 3])
docs <- VCorpus(docs)

Al ejecutar la siguiente instrucción, veremos resumidamente cómo está compuesto el Corpus o colección de documentos

inspect(docs)

10.2 Pre-procesamiento de texto

En un comienzo, el contenido de cada documento en nuestra colección contendrá mucha información que podría no ser relevante para nosotros. Por ejemplo, puntuaciones, números, palabras no relevantes, etc. Por ello, es necesario efectuar el pre-procesamiento y limpieza de los datos.

10.2.1 Remover puntuación

docs <- tm_map(docs, removePunctuation)

10.2.2 Remover números

docs <- tm_map(docs, removeNumbers)

10.2.3 Convertir a minúscula

Esto es importante, ya que normalmente el procesamiento de texto es sensible a mayúscula o minúscula.

docs <- tm_map(docs, content_transformer(tolower))

Notar que la función tolower se aplica sobre un vector de texto. Sin embargo, lo que poseemos es una colección de documentos representados como listas, los cuales a su vez poseen vectores de texto. Por esta razón, utilizamos la función content_transformer para aplicar tolower sobre todos los contenidos de los documentos.

10.2.4 Eliminar espacios en blanco innecesarios

Por ejemplo, 2 o más espacios en blanco continuos, se transforman en uno solo.

docs <- tm_map(docs, stripWhitespace)

10.2.5 Reemplazar caracteres específicos

La función gsub permite reemplazar ciertos caracteres o patrones dentro de un texto. En nuestro caso, aplicaremos la función sobre el contenido de cada documento. Por esta razón, utilizaremos content_transformer sobre tm_map y los otros parámetros son los que utilizará gsub.

docs <- tm_map(docs, content_transformer(gsub), pattern = "/", replacement = "")
docs <- tm_map(docs, content_transformer(gsub), pattern = '[[:digit:]]+', replacement = "")  #elimina cualquier digito

10.2.6 Remover caracteres especiales no considerados por removePunctuation

removeSpecialChars <- function(x) gsub("[^ñÑa-zA-Z0-9 ]","",x) #ojo que incluimos las letras ñ de forma literal
docs <- tm_map(docs, content_transformer(removeSpecialChars))

10.3 Matriz Documento-término

Dado que necesitamos representar los datos de alguna manera, una forma tradicional de hacerlo es mediante una matriz. La idea principal es considerar cada documento como una fila, la cual a su vez tiene tantas columnas como términos existan en el corpus completo de documento (no por documento). De esta forma, podríamos conocer cuáles términos se repiten entre documentos (por ejemplo).

Para esto, usaremos la función DocumentTermMatrix, que utilizará nuestra colección completa de documentos.

dtm <- DocumentTermMatrix(docs)
inspect(dtm)
## <<DocumentTermMatrix (documents: 400, terms: 1879)>>
## Non-/sparse entries: 3682/747918
## Sparsity           : 100%
## Maximal term length: 73
## Weighting          : term frequency (tf)
## Sample             :
##      Terms
## Docs  chile con del las los mas por que terremoto terremotochile
##   11      0   1   0   1   1   0   1   0         0              0
##   146     1   0   0   0   0   0   2   2         0              0
##   156     0   0   1   0   1   0   1   1         0              0
##   177     0   0   0   0   1   0   0   2         0              0
##   183     0   0   0   0   0   2   0   1         0              0
##   185     1   0   0   0   0   0   1   3         0              0
##   29      0   0   0   0   1   2   0   2         0              0
##   303     0   1   0   0   0   0   2   1         0              0
##   330     1   1   0   0   2   0   0   1         0              0
##   60      0   0   0   0   1   1   1   1         0              0

Esta matriz, tendrá en cada celda (i,j) la frecuencia de un término j dentro del documento i.

Además, algo interesante a ver acá, es el valor de Sparsity. Se tienen 400 documentos y 1906 términos, esto genera 400 * 1906 = 762400 celdas. El valor de Non~/sparse entries indica que 758745 celdas tienen como valor 0. Mientras que 3655 celdas tienen un valor diferente a 0. Por lo que el valor de Sparsity nos indica que de todas nuestras celdas en la matriz, un 99.5% (redondeando 100%) están con valores 0. Por lo tanto, esto nos puede señalar que hay términos que solo están presentes en ciertos documentos y no en la mayoría de ellos.

Para ver el tamaño de la matriz, utilizaremos el siguiente comando:

dim(dtm)
## [1]  400 1879

O para inspeccionar una parte de la matriz:

inspect(dtm[1:3, 1:10])
## <<DocumentTermMatrix (documents: 3, terms: 10)>>
## Non-/sparse entries: 0/30
## Sparsity           : 100%
## Maximal term length: 7
## Weighting          : term frequency (tf)
## Sample             :
##     Terms
## Docs aabuelo aayala abierto abrazo absurdo abuelos aburria aca acabo accion
##    1       0      0       0      0       0       0       0   0     0      0
##    2       0      0       0      0       0       0       0   0     0      0
##    3       0      0       0      0       0       0       0   0     0      0

10.3.1 Transformar la DocumentTermMatrix en una matriz “visualizable”

Dado que la función DocumentTermMatrix agrega más información aparte de solo la matriz (metadata), muchas veces nos gustaría visualizar la matriz de forma más sencilla. Para ello, transformaremos el contenido a una matriz.

dtm.matrix <- as.matrix(dtm) 

10.3.2 Términos más frecuentes

Creamos un dataframe donde tendremos 2 columnas: una para el término y otra para la cantidad de veces que aparece en la colección completa.

freq <- colSums(dtm.matrix)
word_freq <- data.frame(word = names(freq), freq = freq, row.names = NULL)
word_freq <- word_freq[order(-word_freq$freq),]

10.3.3 Graficar términos más frecuentes

library(ggplot2)
ggplot(word_freq[1:20,], aes(x = reorder(word, freq), y = freq)) +
          geom_bar(stat = "identity") + 
          coord_flip()+
          ggtitle(label = "Top-20 palabras de la colección")

Como es posible apreciar, la mayor de estas palabras son aquellas que no entregan mayor significado a los documentos. Por ejemplo, artículos o preposiciones en su mayoría. Para solucionar este problema, podemos considerar una bolsa de palabras comunes llamada stopwords. Por lo tanto, eliminaremos palabras comunes para luego calcular la matriz nuevamente.

Primero, podemos ver cuáles son las stopwords que considera la librería para el español:

head(stopwords("spanish"),20)
##  [1] "de"   "la"   "que"  "el"   "en"   "y"    "a"    "los"  "del"  "se"  
## [11] "las"  "por"  "un"   "para" "con"  "no"   "una"  "su"   "al"   "lo"

Usando esta colección estándar, removeremos los stopwords:

docs <- tm_map(docs, removeWords, stopwords("spanish"))

Si tuviéramos una colección de palabras como vector, también podríamos removerlas. Para ello, cargaremos un archivo externo con stopwords:

stopwords_es <- read.table("https://gitlab.com/pablo.valenzuela1/datasets/-/raw/main/stopwords_es.txt" , stringsAsFactors = F)
head(stopwords_es)
##            V1
## 1           a
## 2 actualmente
## 3     acuerdo
## 4    adelante
## 5      ademas
## 6   adem\xe1s

Quitaremos las tildes de este vector utilizando algo similar a lo efectuado sobre la colección. En este caso, la codificación latin1 pareciera transformar mejor los caracteres.

stopwords_es$V1 <- iconv(stopwords_es$V1, from="latin1",to="ASCII//TRANSLIT")

Y eliminamos los stopwords en base a nuestra colección:

docs <- tm_map(docs, removeWords, stopwords_es$V1)
dtm.sw <- DocumentTermMatrix(docs)
dtm.sw.matrix <- as.matrix(dtm.sw)
freq.sw <- colSums(dtm.sw.matrix)
word_freq.sw <- data.frame(word = names(freq.sw), freq = freq.sw, row.names = NULL)
word_freq.sw <- word_freq.sw[order(-word_freq.sw$freq),]
ggplot(word_freq.sw[1:20,], aes(x = reorder(word, freq), y = freq)) +
          geom_bar(stat = "identity") + 
          coord_flip()+
          ggtitle(label = "Top-20 palabras de la colección sin stopwords")

11 Información extra para ejecutar código R en la nube.

Como mencionamos al inicio, una metodología que se ha hecho muy popular en el análisis de datos es el uso de notebooks. Para Python existe Jupyter Notebooks. En este sentido, Colaboratory es un servicio gratuito en la nube proporcionado por Google basado en Jupyter Notebooks. Donde se puede ejecutar código Python y R por hasta 12 horas. Si se reinician los recursos asignados, se perderán todos los datos que no hayan sido guardados. No solo es una gran herramienta para mejorar sus habilidades de codificación, sino que también provee un conjunto de bibliotecas preinstaladas para el análisis de datos.

Uno de los aspectos más importantes de la popularidad de Colaboratory es que da acceso gratis a GPUs (Gracias Google). Los GPUs son parte esencial en la construcción de modelos de machine learning, como redes neuronales, para los que se animen a utilizarlas en sus proyectos.

En este link https://colab.research.google.com/github/IRkernel/IRkernel/blob/master/example-notebooks/Demo.ipynb pueden encontrar un ejemplo de cómo comenzar a usar Google Colaboratory para ejecutar código R. Pueden salvar una copia a su Google Drive en la pestaña File o Archivo y tendrán su propio Notebook para ejecutar código R en la nube.

12 Referencias, lectura adicional