PRESENTACIÓN

¿Qué es R y RStudio?

RStudio es una interfaz libre y gratuita que nos permite explotar todo el potencial que tiene el lenguaje de programación R.

R es un lenguaje que ofrece una gran variedad de funciones para realizar cálculos estadísticos y generar diversos gráficos a partir de los datos. Sin embargo, el gran potencial está en que, al ser libre y colaborativo, constantemente los usuarios están actualizando y ampliando la cantidad de funciones que presenta. Hoy en día podemos realizar desde operaciones básicas sobre los datos hasta aplicar algoritmos de inteligencia artificial.

A su vez, dentro de RStudio, hay diferentes formatos de archivos (RMarkdown, RScript, RNotebook, etc) y su elección depende del objetivo que tengamos. En nuestro caso, a lo largo del manual trabajaremos con el formato RMarkdown, un tipo de documento de RStudio que integra texto con código de R y nos permite generar informes a partir de los datos.

Lo primero que tenemos que hacer es crear un nuevo proyecto y un nuevo RMarkdown. Los pasos a seguir pueden encontrarlos en el siguiente tutorial: https://rpubs.com/angiescetta/conociendo-R

Carguemos y revisemos nuestro dataset

A continuación vamos a trabajar con los datos del Censo 2010 en el Área Metropolitana de Buenos Aires (AMBA) agregados a nivel de partido. Estos datos son públicos y pueden encontrarlos en el portal de datos del INDEC.

En este caso, para facilitar la manipulación de la información, usaremos un set de datos (en formato csv) previamente procesado que pueden descargarlo de este link

Recomendación: Al descargarlo, moverlo de la carpeta “Descargas” a una nueva carpeta llamada “data” dentro de la carpeta del Proyecto donde estén trabajando.

Ahora si, para cargar el dataset pueden copiar la siguiente línea de código y pegarla dentro de un chunk:

partidos_censo2010 <- read.csv("partidos_censo2010.csv", stringsAsFactors = TRUE)

Para entender la lógica detrás del chunk anterior pueden revisar el ejemplo de este link

Ahora conozcamos nuestro dataset: Veamos como se estructura (cuantas filas y columnas tiene) y que información trae…

Para esto empezaremos utilizando dim():

dim(partidos_censo2010)
## [1] 48  6

Podemos ver que tenemos 48 registros/filas y 6 columnas.

Pero ¿Qué información contienen esas 6 columnas?

head(partidos_censo2010)
##   codigo          nombre provincia pob_2010 viv_2010 hog_2010
## 1   6028 Almirante Brown       GBA   552902   156204   156918
## 2   6035      Avellaneda       GBA   342677   121292   113142
## 3   6091     Berazategui       GBA   324244    96025    93164
## 4   6098         Berisso       GBA    88470    29507    27449
## 5   2001        Comuna 1      CABA   205886   130771    84468
## 6   2010       Comuna 10      CABA   166022   107967    61453

Parece que las columnas que tenemos son: código, nombre del partido, provincia, población 2010, viviendas 2010 y hogares 2010.

Por último veamos un resumen estadístico de los datos:

summary(partidos_censo2010)
##      codigo                 nombre   provincia    pob_2010      
##  Min.   :2001   Almirante Brown: 1   CABA:15   Min.   :  56729  
##  1st Qu.:2013   Avellaneda     : 1   GBA :33   1st Qu.: 174013  
##  Median :6319   Berazategui    : 1             Median : 223281  
##  Mean   :5075   Berisso        : 1             Mean   : 301108  
##  3rd Qu.:6544   Comuna 1       : 1             3rd Qu.: 340723  
##  Max.   :6861   Comuna 10      : 1             Max.   :1775816  
##                 (Other)        :42                              
##     viv_2010         hog_2010     
##  Min.   : 19287   Min.   : 17116  
##  1st Qu.: 64864   1st Qu.: 59537  
##  Median : 93389   Median : 81055  
##  Mean   :104104   Mean   : 95612  
##  3rd Qu.:123359   3rd Qu.:109566  
##  Max.   :447306   Max.   :484909  
## 

Podemos analizar un poco los valores y ver por ejemplo que, en promedio los partidos de AMBA tienen 301.108 habitantes, y que el más poblado tiene 177.5816 y el menos poblado 56.729.

MANIPULACIÓN DE DATOS

Ahora que ya sabemos abrir un dataset y conocer que información tiene, vamos a aprender a manipular, limpiar, normalizar y transformar los datos, o lo que se conoce como data wrangling. Para esto vamos a trabajar con uno de los paquetes más usados y más útiles de R que se llama tidyverse.

Pero, ¿Qué es un paquete?

Cuando instalamos R ya viene con múltiples funciones básicas para manipular datos, sin embargo el potencial de la herramienta surge con la posibilidad de incorporar constantemente nuevas funciones que nos permitan realizar nuevas tareas o mejorar el resultado de las ya existentes.

Estos grupos de funciones son a los que llamamos paquetes o packages y para poder utilizarlos es necesario instalarlos por única vez en la computadora, y luego activarlos cada vez que vayamos a usarlos.

Comencemos instalándolo. Esto podemos hacerlo manualmente en Tools/Install packages o con el siguiente chunk:

#install.packages("tidyverse")

Una vez que instalamos el paquete, no vamos a tener que volver a hacerlo. Solamente vamos a tener que “activarlo” cada vez que queramos usarlo. Esta activación se hace con library() así:

library(tidyverse)

A continuación veremos algunos ejemplos de como el paquete tidyverse nos va a permitir manipular nuestros datos a partir de funciones como filtrar, modificar, seleccionar, ordenar, renombrar, resumir y agrupar.

Aprender a utilizar todas estas funciones es muy importante ya que la comprensión, transformación y limpieza de los datos es la etapa que más tiempo nos llevará a la hora de encarar cualquier proyecto de Ciencia de Datos.

Quien quiera profundizar con más ejemplos se recomienda revisar este link

Filtrar datos

Como su nombre lo indica, esta función hace referencia a realizar un filtro determinado sobre los registros/filas de toda la base de datos, es decir, quedarnos solo con las filas que cumplan cierta condición establecida.

Esto nos será muy útil si por algún motivo queremos dejar de lado registros y utilizar solo una parte de la base. Por ejemplo, en el caso de nuestro dataset, podríamos filtrar la data y quedarnos solo con los partidos que tienen más de 100.000 habitantes:

partidos_2 <- filter(partidos_censo2010, pob_2010>=100000)

Seleccionar datos

La función select() nos permite elegir u ordenar columnas de nuestro dataset. Esto se puede hacer indicando los nombres completos de las columnas, palabras que contienen, o la letra con la que empiezan o terminan.

Por ejemplo, de la siguiente forma podríamos quedarnos solo con 5 de las 6 columnas (partidos_2, nombre, provincia, pob_2010, viv_2010, hog_2010):

partidos_2 <- select(partidos_2, nombre, provincia, pob_2010, viv_2010, hog_2010)
head(partidos_2)
##            nombre provincia pob_2010 viv_2010 hog_2010
## 1 Almirante Brown       GBA   552902   156204   156918
## 2      Avellaneda       GBA   342677   121292   113142
## 3     Berazategui       GBA   324244    96025    93164
## 4        Comuna 1      CABA   205886   130771    84468
## 5       Comuna 10      CABA   166022   107967    61453
## 6       Comuna 11      CABA   189832   101161    71460

Modificar o agregar datos

Ahora veamos como mutar nuestro dataset agregando nuevas columnas o cambiando el contenido de las existentes.

Aprovechando que tenemos los datos de población (pob_2010) y de cantidad de viviendas (viv_2010) de cada partido, agreguemos una nueva columna a nuestro dataset que incluya la relación entre ambas variables:

partidos_2 <- mutate(partidos_2, pob_viv=pob_2010/viv_2010)
head(partidos_2)
##            nombre provincia pob_2010 viv_2010 hog_2010  pob_viv
## 1 Almirante Brown       GBA   552902   156204   156918 3.539615
## 2      Avellaneda       GBA   342677   121292   113142 2.825223
## 3     Berazategui       GBA   324244    96025    93164 3.376662
## 4        Comuna 1      CABA   205886   130771    84468 1.574401
## 5       Comuna 10      CABA   166022   107967    61453 1.537711
## 6       Comuna 11      CABA   189832   101161    71460 1.876533

Ordenar datos

Probemos ordenar las filas de nuestro data frame en función de los valores de población. Verán que por defecto se ordena en forma ascendente:

partidos_2 <- arrange(partidos_2, pob_2010)
head(partidos_2)
##         nombre provincia pob_2010 viv_2010 hog_2010  pob_viv
## 1        Luján       GBA   106273    37527    32524 2.831908
## 2     Comuna 2      CABA   157932    55377    73156 2.851942
## 3     Comuna 9      CABA   161797    86326    56495 1.874256
## 4 San Fernando       GBA   163240    51910    49384 3.144673
## 5       Ezeiza       GBA   163722    49204    44487 3.327412
## 6    Comuna 10      CABA   166022   107967    61453 1.537711

Renombrar datos

Ahora veamos como cambiar los nombres a una columna existente en nuestro dataset:

partidos_2 <- rename(partidos_2, partido=nombre)
head(partidos_2)
##        partido provincia pob_2010 viv_2010 hog_2010  pob_viv
## 1        Luján       GBA   106273    37527    32524 2.831908
## 2     Comuna 2      CABA   157932    55377    73156 2.851942
## 3     Comuna 9      CABA   161797    86326    56495 1.874256
## 4 San Fernando       GBA   163240    51910    49384 3.144673
## 5       Ezeiza       GBA   163722    49204    44487 3.327412
## 6    Comuna 10      CABA   166022   107967    61453 1.537711

Resumir y agrupar datos

Esta función es súper útil cuando manipulamos datos ya que nos permitirá realizar resumenes/sumarios de la data completa, obteniendo por ejemplo valores promedio, máximos o mínimos de una o más columnas.

Probemos calculando la mediana de todos los valores que aparecen en la columna pob_2010:

summarise(partidos_2, pob_mediana=median(pob_2010))
##   pob_mediana
## 1      265981

Como verán, esta función resulta útil para ver valores agregados de toda la base, sin embargo, también podemos agrupar los datos previo a calcular los resumenes, y así obtener resumenes por agrupaciones en vez de uno solo para toda la base. Para esto vamos a utilizar summarise() junto a group_by(). Veamos un ejemplo:

  • Primero agrupemos los datos por la variable “provincia”.

  • Luego calculemos el la mediana de población sobre la agrupación realizada previamente.

partidos_2 <- group_by(partidos_2, provincia)
partidos_2 <- summarise(partidos_2, pob_mediana=median(pob_2010))
head(partidos_2)
## # A tibble: 2 x 2
##   provincia pob_mediana
##   <fct>           <dbl>
## 1 CABA          187537 
## 2 GBA           323310.

Con la agrupación y el resumen podemos ver que la población promedio de las comunas de CABA es de 187.537 y la de los partidos de GBA es 323.309.

Concatenar todas las funciones!

Ya vimos varias funciones por separado, pero ¿Qué pasa si queremos aplicarlas todas a la vez? ¿Cómo podemos hacerlo?

En este caso debemos usar el operador pipe (%>%) Ctrl+Shift+M que sirve para encadenar funciones, y en vez de realizar una por una, poder realizar todas juntas.

Veamos como quedaría:

partidos_3 <- partidos_censo2010 %>%
  filter(pob_2010>=100000) %>%
  select(nombre, provincia, pob_2010, viv_2010, hog_2010) %>%
  mutate(pob_viv=pob_2010/viv_2010) %>%
  arrange(desc(pob_2010)) %>%
  rename(partido=nombre) %>%
  group_by(provincia) %>%
  summarise(pob_mediana=median(pob_2010))
head(partidos_3)
## # A tibble: 2 x 2
##   provincia pob_mediana
##   <fct>           <dbl>
## 1 CABA          187537 
## 2 GBA           323310.

Como podrán ver, el resultado es el mismo que en al hacer las funciones por separado pero nos ahorramos unos cuantos pasos!

ANÁLISIS Y VISUALIZACIÓN DE DATOS

El paquete tidyverse incluye diversos paquetes, entre los que se encuentra ggplot2, que nos permite realizar diferentes tipos de gráficos a partir de nuestros datos.

Hasta acá ya sabemos abrir, conocer, manipular y transformar un dataset, así que ahora nos enfocaremos en el desarrollo de visualizaciones que nos permitirán comunicar de forma gráfica lo que dicen nuestros datos.

A continuación seguiremos trabajando con los datos del Censo 2010 en AMBA y desarrollaremos diferentes visualizaciones que sinteticen y comuniquen la información que contiene.

Quien quiera profundizar con más ejemplos se recomienda revisar este link

En particular, hoy veremos como representar gráficamente lo siguiente:

  1. Distribución de una variable continua: Histograma

  2. Relación entre variables continuas: Gráfico de puntos

  3. Relación entre una variable continua y una categórica: Gráfico de barras

1.HISTOGRAMA

Los histogramas muestran gráficamente, a partir de barras, la distribución de una variable continua, es decir la frecuencia con la que aparece cada valor numérico en una determinada columna del dataset. En el eje X se representa la variable continua y en el eje Y la frecuencia de la misma.

Para generar este tipo de visualización utilizaremos ggplot() + geom_histogram(). Veamos por ejemplo como se distribuyen las poblaciones (pob_2010) de los partidos del AMBA:

ggplot(partidos_censo2010)+
  geom_histogram(aes(x=pob_2010))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

El eje X muestra la población que tienen los partidos y el eje Y la cantidad de veces que aparece cada volumen de población. Por lo tanto, podemos ver que hay varios partidos con “poca” población y un solo partido con “mucha” (La Matanza).

2.GRÁFICO DE PUNTOS

Ahora veamos el clásico gráfico de puntos o scatter plot que muestra la dispersión que existe entre 2 variables numéricas representadas en los 2 ejes X e Y, y que permite identificar si existe o no una relación entre ambas.

Veamos por ejemplo, si existe relación entre la población (pob_2010) y la cantidad de viviendas (viv_2010):

ggplot(partidos_censo2010)+
  geom_point(aes(x=pob_2010, y=viv_2010))

Tiene sentido, a mayor población, mayor cantidad de viviendas. Pero veamos esto diferenciando según provincia (CABA o PBA) y agreguemos etiquetas (título, subtítulo, etc):

options(scipen=20)
ggplot(partidos_censo2010)+
  geom_point(aes(x=pob_2010, y=viv_2010, color=provincia))+
  labs(title="Relación entre cantidad de población y de viviendas",
       subtitle="Censo 2010 - AMBA",
       x="Población",
       y="Viviendas",
       color="Zona")

3.GRÁFICO DE BARRAS

El gráfico de barras representa, a partir de la longitud de las barras, el valor numérico (eje Y) asociado a cada entidad de la variable categórica (eje X).

Al igual que en el resto de visualizaciones, es necesario elegir una variable para el eje X y otra para el eje Y (acá se llama weight). Sin embargo, si no asignamos ninguna variable numérica a weight, el gráfico automáticamente va a calcular cuantas veces aparece cada categoría en la base de datos.

Por ejemplo, veamos cuantas observaciones hay por provincia:

ggplot(partidos_censo2010)+
  geom_bar(aes(x=provincia))

En el gráfico anterior podemos ver que hay más de 30 partidos de GBA y 15 e CABA.

ggplot(partidos_censo2010)+
  geom_bar(aes(x=reorder(nombre, pob_2010), weight=pob_2010, fill=provincia))+
  coord_flip()+
  labs(title="Población por partido",
       subtitle="Censo 2010 - AMBA",
       x="Partido",
       y="Cantidad",
       fill="Zona")

INFORMACIÓN GEOGRÁFICA Y MAPAS

Llegó el momento de visualizar información en un mapa. Pero antes de empezar, ¿A que nos referimos cuando hablamos de Sistemas de Información Geográfica o SIG? Bueno, nos referimos a las herramientas informáticas que nos permiten ubicar y analizar un conjunto de datos en lugares específicos del territorio (georreferenciar).

Para poder hacer uso de los SIG necesitamos contar con información geográfica en nuestro dataset, es decir, que además de la información que ya vimos que puede haber en un dataset tradicional, se sume un componente espacial en cada registro (partido, barrio, manzana, calle o directamente las coordenadas X e Y).

Las herramientas que nos permitirán visualizar toda esta información serán los mapas, que son nada más y nada menos que representaciones planas, reducidas y simplificadas de la tierra que nos dan la posibilidad cruzar y relacionar datos en el espacio. Es decir que, mantienen una relación ordenada en el traspaso de puntos ubicados en la superficie curva de la tierra a puntos ubicados en la superficie plana de los mapas. Esto es posible a partir del uso de sistemas de coordenadas proyectadas.

En R hay varios paquetes de funciones que nos permiten manipular este tipo de información, entre los que se encuentra sf, que lo aprenderemos hoy. Para comenzar a utilizarlo vamos a tener que instalarlo y luego activarlo con library() al igual que lo veníamos haciendo con tidyverse:

#install.packages(sf)
library(sf)

Como verán, necesiamos que estén activos los 2 paquetes porque ambos presentan funciones que son necesarias a la hora de mapear información.

ANALIZAR DATOS ESPACIALES

Arranquemos cargando nuestro dataset espacial o shape con las geometrías correspondientes a todos los partidos de AMBA. Pueden descargarlo desde este link

Recomendación: Al descargar el shape deberán moverlo de la carpeta “Descargas” a la carpeta del Proyecto donde estan trabajando.

Para poder cargar nuestros datos espaciales en formato geoJSON utilizaremos la función st_read() de la siguiente forma:

partidos_amba <- st_read("partidos_amba.geojson", stringsAsFactors = TRUE)
## Reading layer `amba_partidos' from data source 
##   `C:\Users\27356214477\Desktop\DIPLO_CDDPC\partidos_amba.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 48 features and 2 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -59.3392 ymin: -35.23893 xmax: -57.70946 ymax: -34.23007
## Geodetic CRS:  WGS 84

Veamos que información contiene:

summary(partidos_amba)
##              nombre      area_km2               geometry 
##  Almirante Brown: 1   Min.   :  6.30   MULTIPOLYGON :48  
##  Avellaneda     : 1   1st Qu.: 17.72   epsg:4326    : 0  
##  Berazategui    : 1   Median : 55.91   +proj=long...: 0  
##  Berisso        : 1   Mean   :140.59                     
##  Comuna 1       : 1   3rd Qu.:177.07                     
##  Comuna 10      : 1   Max.   :889.49                     
##  (Other)        :42

Las primeras 2 columnas presentan el nombre del partido y el área en km2. Hasta acá son datos muy similares a las que ya veníamos encontrando en el dataset tradicional; sin embargo, aparece una 3era columna llamada “geometry” que hasta ahora no la habíamos visto y es donde se aloja la geometría de cada uno de los registros. La información de este campo es la que hace que el dataset sea espacial.

Si queda alguna duda, podemos utilizar la función class() para ver con que tipo de datos estamos trabajando:

class(partidos_amba)
## [1] "sf"         "data.frame"

Efectivamente partidos_amba, es un dataset espacial u objeto del tipo “sf”, que hace referencia a “simple features” por estar compuesto de geometrías bidimensionales (polígono, punto, línea, multipunto, multilínea, etc.).

Para poder visualizar toda esta información plasmada en un mapa vamos a utilizar nuevamente ggplot() pero como en esta oportunidad queremos sumar capas geográficas (sf) trabajaremos con geom_sf(). Veamos un ejemplo:

ggplot(partidos_amba)+
  geom_sf()

Como habrán notado, la lógica en la estructura del chunk que utilizamos para hacer este mapa es la misma del capítulo anterior, donde dentro del ggplot() asignamos el dataset y luego sumamos la capa a graficar/mapear (en este caso un objeto sf).

En el mapa podemos ver como las geometrías de cada registro del dataset espacial son polígonos que representan los partidos de AMBA. Probemos agregar algún atributo estético aes():

ggplot(partidos_amba)+
  geom_sf(aes(fill=area_km2))

Ya tenemos nuestro primer mapa coroplético. Probemos ajustando algunas cuestiones estéticas: cambiemos la paleta (y su escala) y el color del borde de los polígonos.

ggplot(partidos_amba)+
  geom_sf(aes(fill=area_km2), color="white")+
  scale_fill_viridis_c(breaks=c(0,250,500,750,1000))

Pero nuestro shape tiene poca información no? No podemos hacer muchos análisis si solo contamos con la variable de superficie, así que seamos proactivos y agreguemos más datos!

BONUS TRACK: CRUZAR DATOS ESPACIALES Y TRADICIONALES

Es muy común que a la hora de trabajar con datos no encontremos toda la información que necesitamos en un solo dataset. Frente a esto, lo que se hace es unir/cruzar datos provenientes de diferentes fuentes de información. En este apartado veremos como realizar estos cruces entre datos tradicionales y espaciales.

Para poder unir 2 set de datos ambos tienen que tener algo en común (alguna columna como por ejemplo un ID), sino sería imposible que R entienda que tiene que unir con qué. Por lo tanto, antes de unirlos podríamos necesitar manipularlos y realizarles diferentes tipos de transformaciones que nos permitan llegar a generar esta variable en común.

Por ejemplo en nuestro caso, si queremos unir algún dato a nuestro dataset espacial de partidos, deberíamos tener un valor único por cada nombre de partido (que funciona como el ID de mi dataset espacial). Veamos de nuevo que columnas tenemos en el dataset del Censo 2010:

head(partidos_censo2010)
##   codigo          nombre provincia pob_2010 viv_2010 hog_2010
## 1   6028 Almirante Brown       GBA   552902   156204   156918
## 2   6035      Avellaneda       GBA   342677   121292   113142
## 3   6091     Berazategui       GBA   324244    96025    93164
## 4   6098         Berisso       GBA    88470    29507    27449
## 5   2001        Comuna 1      CABA   205886   130771    84468
## 6   2010       Comuna 10      CABA   166022   107967    61453

Hay una columna llamada “nombre” que tiene el nombre de nuestros partidos, y eso es una buena noticia ya que ella será quien nos permitirá unir ambos dataset (el espacial y el tradicional). Para esto utilizaremos la función llamada left_join():

partidos_amba <- left_join(partidos_amba, partidos_censo2010, by="nombre")

Revisemos el resultado!

summary(partidos_amba)
##              nombre      area_km2          codigo     provincia
##  Almirante Brown: 1   Min.   :  6.30   Min.   :2001   CABA:15  
##  Avellaneda     : 1   1st Qu.: 17.72   1st Qu.:2013   GBA :33  
##  Berazategui    : 1   Median : 55.91   Median :6319            
##  Berisso        : 1   Mean   :140.59   Mean   :5075            
##  Comuna 1       : 1   3rd Qu.:177.07   3rd Qu.:6544            
##  Comuna 10      : 1   Max.   :889.49   Max.   :6861            
##  (Other)        :42                                            
##     pob_2010          viv_2010         hog_2010               geometry 
##  Min.   :  56729   Min.   : 19287   Min.   : 17116   MULTIPOLYGON :48  
##  1st Qu.: 174013   1st Qu.: 64864   1st Qu.: 59537   epsg:4326    : 0  
##  Median : 223281   Median : 93389   Median : 81055   +proj=long...: 0  
##  Mean   : 301108   Mean   :104104   Mean   : 95612                     
##  3rd Qu.: 340723   3rd Qu.:123359   3rd Qu.:109566                     
##  Max.   :1775816   Max.   :447306   Max.   :484909                     
## 

Efectivamente, se sumaron 5 nuevas columnas a mi dataset espacial: codigo, provincia, pob_2010, viv_2010 y hog_2010. ¿Qué esperamos? ¡Veamos alguna de ellas en un mapa!

ggplot(partidos_amba)+
  geom_sf(aes(fill=pob_2010), color="white")+
  scale_fill_viridis_c()

Cómo veran, hay un partido que resalta ya que es el más poblado: La Matanza. Pero no nos quedemos con esa idea, y para que estos datos sean comparables entre todos los partidos, es necesario que calculemos una densidad relacionando la cantidad de habitantes y la superficie (km2) de cada uno. También aprovechemos y mejoremos la estética agregando etiquetas (título, subtítulo, etc) y cambiando el aspecto (theme):

ggplot(partidos_amba)+
  geom_sf(aes(fill=pob_2010/area_km2), color=NA)+
    labs(title = "Población por Partido",
         subtitle = "Censo 2010",
         fill = "Población/km2",
         caption= "Fuente: INDEC") +
  scale_fill_distiller(palette = "Spectral") +
  theme_light()

Y listo! Ahora les toca practicar a uds!