Web scraping + Visualización con R: ejemplo con datos de wikipedia

Web scraping + Visualización con R: ejemplo con datos de wikipedia

Web Scraping

En este post mostaré cómo hacer web scraping con R para obtener tablas de datos de la web. Para ello utilizaré la información sobre el Índice de Desarrollo Humano para Nicaragua (IDH) por departamento, estos datos están disponibles en Wikipedia.

¿Qué es Web Scraping? Para no complicarnos la vida, vamos a tomar la definición que proporciona Wikipedia: “es una técnica utilizada mediante programas de software para extraer información de sitios web.”

La siguiente pregunta importante es ¿por qué es importante esto? La respuesta es sencilla, fundamentalmente porque parte de la información que necesitamos para nuestros análisis está disponibe en formato HTML y no no está disponible en un excel o txt, así que hay herramientas apropidadas para hacer esas extraciones de datos de forma rápida y sencilla. Es lo que voy a mostrar en este post.

Para seguir este post y reproducir sus resultados, asegúrese de tener instalado tidyverse, zoo y ggrepel. Vamos utilizar los datos sobe los departamentos de Nicargua y el comportamiento del IDH por departamento que se presentan entos enlaces https://es.wikipedia.org/wiki/Anexo:Departamentos_de_Nicaragua y https://es.wikipedia.org/wiki/Anexo:Departamentos_de_Nicaragua_por_IDH, el objetivo es la extracción de las tablas de datos de ambas páginas. Para ello, primero cargamos los paquetes requeridos

library(rvest)
library(tidyverse)

Para importar las tablas de los departamentos sólo se hace los siguiente:

# departamentos de Nicaragua
url_wiki <- "https://es.wikipedia.org/wiki/Anexo:Departamentos_de_Nicaragua"

departamentos <- url_wiki %>% 
  read_html() %>% 
  html_nodes("table") %>% 
  html_table(fill = TRUE)

El código anterior hace lo siguiente:

  1. read_html() toma la url contenida en url_wiki y lee todo su contenido
  2. html_nodes extrae las piezas información especificadas, en este caso tablas (table) esta es la etiqueta que identifica a las tablas en las hmtl, se sugiere al lector familiarizarse con los selectores CSS.
  3. html_table convierte la tabla html a data.frame
  4. finalmente, este resultado se guarda con el nombre departamentos. Tenga en cuenta que en departamentos van a estar todos los objetos que tengan el identificador table, por tanto, ese resultado será una lista de data.frames, sin embargo, es este caso, por tratarse de una única tabla, departamentos es una lista de longitud 1 que contiene un data.frame.

Asi, los datos importados lucen de la siguiente manera:

departamentos[[1]] # por lista de longitud 1, debemos seleccionar con [[]] el objeto que deseamos mostrar
Departamentos
Departamento ISO 3166-2 Cabecera Población (2012) Áreakm² Densidad
Boaco NI-BO Boaco 174 682 4177 41,8
Carazo NI-CA Jinotepe 186 898 1081 172,8
Chinandega NI-CI Chinandega 432 062 4822 87,7
Chontales NI-CO Juigalpa 153 932 6481 24
Costa Caribe Norte NI-CN Puerto Cabezas 314 130 33106 10
Costa Caribe Sur NI-CS Bluefields 306 510 27260 11
Estelí NI-ES Estelí 201 548 2230 90
Granada NI-GR Granada 168 186 1040 162
Jinotega NI-JI Jinotega 331 335 9222 36
León NI-LE León 355 779 5138 69
Madriz NI-MD Somoto 132 459 1708 78
Managua NI-MN Managua 2 132 421 3465 365
Masaya NI-MS Masaya 289 988 611 475
Matagalpa NI-MT Matagalpa 469 172 6804 69
Nueva Segovia NI-NS Ocotal 208 523 3491 60
Río San Juan NI-SJ San Carlos 95 596 7541 13
Rivas NI-RI Rivas 156 283 2162 72

Para importar la tabla del IDH por departamentos, se repite el mismo procedimiento anteiror:

# clasificación de departamentos por Índice de Desarrollo Humano
url_wiki_idh <- "https://es.wikipedia.org/wiki/Anexo:Departamentos_de_Nicaragua_por_IDH"

departamentos_idh_1 <- url_wiki_idh %>% 
  read_html() %>% 
  html_nodes("table") %>%
  .[2] %>%  # en este caso la tabla es el elemento 2 de los nodos extraídos
  html_table(fill = TRUE)


# departamentos_idh_1[[1]] %>% 
#   head(5) # visualizando las primera 5 observaciones
IDH por departamentos
Puesto Departamento Capital IDH Población Simpatiza Para Capital NA
Desarrollo Humano Muy Alto Desarrollo Humano Muy Alto Desarrollo Humano Muy Alto Desarrollo Humano Muy Alto Desarrollo Humano Muy Alto Desarrollo Humano Muy Alto NA
Managua Managua 0,827 1.262.658 9.80% NA
Desarrollo Humano Alto Desarrollo Humano Alto Desarrollo Humano Alto Desarrollo Humano Alto Desarrollo Humano Alto Desarrollo Humano Alto Desarrollo Humano Alto
Masaya Masaya 0,796 289.467 7.01% NA
León León 0,781 373.662 8.60% NA

Como se observa, esta tabla que en la web es visualmente agradable, no lo es tanto para trabajar con ella por su diseño, por tanto, aquí hay que invertir un poco de tiempo para limpiar y convertir esta tabla en un objeto operable en término de análisis.

Así que manos la obra!

library(zoo)
library(forcats)
library(ggrepel)
# Esta requiere de limpieza
departamentos_idh_2 <- departamentos_idh_1[[1]] %>% 
  data.frame() %>% 
  select(-NA.) %>%  # elimino variable extra sin información
  mutate(IDH_categoria = ifelse(grepl("^Desarrollo", IDH), IDH, NA) %>%  na.locf()) %>% # creo categoría de IDH
  filter(!grepl("^Desarrollo", Puesto)) %>%  # eliminando filas en las que se repiten las categorías del IDH
  mutate(Puesto = 1:n(), # valores de Puesto a números enteros
         IDH = sub(",", "\\.", IDH) %>% as.numeric,  # cambio de "," a "." en IDH y convierto a número
         Población = gsub("\\.", "", Población)%>% as.numeric, # elimino "." en Población y convierto a número
         Simpatiza.Para.Capital = sub("%", "", Simpatiza.Para.Capital) %>% as.numeric, # elmino "%" 
         IDH_categoria = sub("Desarrollo Humano ", "", IDH_categoria)) %>% 
  mutate_if(is.character, as.factor) %>%   # cambiando atributos: los caracteres a factores
  mutate(IDH_categoria = fct_reorder(IDH_categoria, -IDH), # ordenando categoría según IDH
         Polacion.porcentaje = 100*Población/sum(Población)) %>%  # agregando nueva variable
  tibble() 

Todas las modificaciones anteriores nos permiten pasar el data.frame original y desordenado, a este:

departamentos_idh_2
IDH por departamentos
Puesto Departamento Capital IDH Población Simpatiza.Para.Capital IDH_categoria Polacion.porcentaje
1 Managua Managua 0.827 1262658 9.80 Muy Alto 24.896409
2 Masaya Masaya 0.796 289467 7.01 Alto 5.707554
3 León León 0.781 373662 8.60 Alto 7.367666
4 Granada Granada 0.760 179437 10.62 Alto 3.538042
5 Carazo Jinotepe 0.734 167810 5.11 Medio 3.308787
6 Estelí Estelí 0.712 197020 7.70 Medio 3.884734
7 Rivas Rivas 0.686 158142 6.08 Medio 3.118159
8 Chinandega Chinandega 0.679 405289 5.16 Medio 7.991270
9 Chontales Juigalpa 0.655 167895 4.18 Medio 3.310463
10 Madriz Somoto 0.640 124973 3.38 Medio 2.464150
11 Matagalpa Matagalpa 0.629 450143 10.90 Medio 8.875677
12 Nueva Segovia Ocotal 0.603 198521 3.68 Medio 3.914330
13 Boaco Boaco 0.599 157973 3.40 Medio 3.114826
14 Río San Juan San Carlos 0.558 87401 3.39 Medio 1.723326
15 Costa Caribe Sur Bluefields 0.536 340873 3.65 Medio 6.721150
16 Jinotega Jinotega 0.513 278504 3.87 Medio 5.491392
17 Costa Caribe Norte Puerto Cabezas 0.497 231879 3.47 Bajo 4.572065

Una vez descargados los datos y ordenados, podemos visualizar la información que contienen:

# visualizando
departamentos_idh_2 %>% 
  mutate_if(is.character, as.factor) %>% 
    ggplot(aes(y=Población, x = IDH))+
  geom_point(aes(color=IDH_categoria))+
  labs(title = "IDH de los departamentos de Nicaragua",
       caption = "Fuente: Elaboración propia con datos extraidos de Wikipedia")

Pese a que el gráfico, aparentemente, es informativo y está correcto, fíjese bien, falta un detalle fundamental: no contiene identificador para los departamentos, así que esto se puede corregir fácilmente, además se usará el porcentaje de población en lugar del valor absoluto.

plot2  <- departamentos_idh_2  %>% 
  ggplot(aes(x = IDH, y=Polacion.porcentaje, label=Departamento, color=IDH_categoria))+
  geom_point(aes(color=IDH_categoria))+
  geom_text_repel() +
  labs(title = "IDH de los departamentos de Nicaragua",
       caption = "Fuente: Elaboración propia con datos extraidos de Wikipedia",
       color = "Nivel de IDH",
       y="Porcentaje de población")+
  theme(legend.position = "bottom")

print(plot2)

Note que el gráfico es un objeto que puede ser guardado para, posteriormente, editarlo sin tener que reescribir todo el código.

Vamos a incorporar una mejora en este gráfico: vamos a incorporar una estratificación según la región a la que pertenece cada departamento, para ello usaremos la clasificación sugerida en https://www.comercioexterior.ub.edu/fpais/nicaragua/ciudadesmasimportantes.htm en donde se agrupan los departamentos en tres regiones según se indica:

  • Los de la Región del Pacífico son: Chinandega, León, Managua, Carazo, Masaya, Granada y Rivas.
  • Los de la Región Central son: Nueva Segovia, Madriz, Estelí, Jinotega, Matagalpa, Boaco, Chontales y Río San Juan.
  • Los de la Región del Caribe o Costa Atlántica son: Atlántico Norte y Atlántico Sur.

Antes de incorporar esa estratificación al gráfico, se debe crear la variable Región en la base de datos. Para crearla se hace lo siguiente

departamentos_idh_2 <- departamentos_idh_2 %>% 
  mutate(Region = fct_collapse(
    Departamento,
    Pacífico = c("Chinandega", "León", "Managua", "Carazo", "Masaya", "Granada", "Rivas"),
    Central = c("Nueva Segovia", "Madriz", "Estelí", "Jinotega", "Matagalpa", "Boaco", "Chontales", "Río San Juan"),
    Caribe = c("Costa Caribe Norte", "Costa Caribe Sur")))

Lo anterior luce así:

IDH por departamentos
Puesto Departamento Capital IDH Población Simpatiza.Para.Capital IDH_categoria Polacion.porcentaje Region
1 Managua Managua 0.83 1262658 9.80 Muy Alto 24.896409 Pacífico
2 Masaya Masaya 0.80 289467 7.01 Alto 5.707554 Pacífico
3 León León 0.78 373662 8.60 Alto 7.367666 Pacífico
4 Granada Granada 0.76 179437 10.62 Alto 3.538042 Pacífico
5 Carazo Jinotepe 0.73 167810 5.11 Medio 3.308787 Pacífico
6 Estelí Estelí 0.71 197020 7.70 Medio 3.884734 Central
7 Rivas Rivas 0.69 158142 6.08 Medio 3.118159 Pacífico
8 Chinandega Chinandega 0.68 405289 5.16 Medio 7.991270 Pacífico
9 Chontales Juigalpa 0.66 167895 4.18 Medio 3.310463 Central
10 Madriz Somoto 0.64 124973 3.38 Medio 2.464150 Central
11 Matagalpa Matagalpa 0.63 450143 10.90 Medio 8.875677 Central
12 Nueva Segovia Ocotal 0.60 198521 3.68 Medio 3.914330 Central
13 Boaco Boaco 0.60 157973 3.40 Medio 3.114826 Central
14 Río San Juan San Carlos 0.56 87401 3.39 Medio 1.723326 Central
15 Costa Caribe Sur Bluefields 0.54 340873 3.65 Medio 6.721150 Caribe
16 Jinotega Jinotega 0.51 278504 3.87 Medio 5.491392 Central
17 Costa Caribe Norte Puerto Cabezas 0.50 231879 3.47 Bajo 4.572065 Caribe

Una vez actualizado el data.frame, se puede agregar esta nueva información al gráfico

plot3 <- plot2 +
  facet_grid(~departamentos_idh_2$Region)+
  geom_text_repel() +
  labs(subtitle = "Estratificado por Región")

plot3

Ahora se puede decir que la zona central de Nicaragua se caracteriza por tener IDH medio, mientras que la zona del pacífico es la única con valor muy alto, sin embargo, esto sólo sucede en Managua, mientras que León, Masaya y Granada destacan por tener índices altos, mientras que Chinandega, Rivas y Carazo tienen IDH que las posicionan en la clasifiación de medio. La Costa Caribe es la de menor desempeño en cuanto al IDH.

¿Podemos agregar más información sin perjucio de la visualizacón en el gráfico en cuestión? ¿Qué tal si incluimos la densidad de población? Para ello, debemos retomar la primer tabla que habíamos importado al inicio

# retomemos la primer tabla que importamos y damos formato numérico a los números
departamentos_2 <- departamentos[[1]] %>% 
  select(Departamento, Densidad) %>% 
  mutate(Densidad = sub(",", "\\.", Densidad) %>% as.numeric)

# juntamos ambas tablas en una sola
departamentos_idh_3 <- departamentos_idh_2 %>% 
  right_join(departamentos_2, by="Departamento")

Ahora actualicemos el gráfico agregando la nueva variable. Esta variable la introduciremos para controlar el tamaño de los puntos, de manera que cuanto mayor sea la densidad de población de cada departamento, mayor será el tamaño del punto en el plano.

plot3 +
  geom_point(aes(color=IDH_categoria, size = departamentos_idh_3$Densidad, alpha = .5 ))+
  guides(size = FALSE, alpha = FALSE)

Como era de esperarse, Mayasa, Managua, Granada y Carazo son los mayormente poblados.

Para obtener el ultimo gráfico, habido construido previamente la base “departamentos_idh_3” procederíamos con la ejecución del siguiente código:

plot4 <- departamentos_idh_3  %>% 
  ggplot(aes(x = IDH, y=Polacion.porcentaje, label=Departamento, color=IDH_categoria))+
  geom_point(aes(color=IDH_categoria))+
  geom_text_repel() +
  labs(title = "IDH de los departamentos de Nicaragua",
       subtitle = "Estratificado por Región",
       caption = "Fuente: Elaboración propia con datos extraidos de Wikipedia",
       color = "Nivel de IDH",
       y="Porcentaje de población")+
  theme(legend.position = "bottom")+
  facet_grid(~Region)+
  geom_point(aes(color=IDH_categoria, size = Densidad, alpha = .5 ))+
  guides(size = FALSE, alpha = FALSE)

plot4

Finalmente, se presenta el mismo gráfico con algunos ajustes de personalización, sòlo para que combie con el tema de colores del blog.

plot4 +
  theme_light()+
  theme(legend.position = "bottom",
        strip.background =element_rect(fill="darkblue"),
        strip.text = element_text(colour = 'white', face="bold"))

No hay comentarios:

Publicar un comentario