Al momento de escribir este artículo, no encontramos en medio de una pandemia global por una nueva cepa del Coronavirus (COVID-19), para la cual no cuenta con una vacuna, que ha contagiado a decenas de miles de personas en más de ciento cincuenta países, causando una enorme pérdida de vidas humana en algunos de ellos.
Esta es un problema de salud pública sumamente delicado, que ha generado una gran demanda en información sobre sus diferentes facetas por diferentes actores de la sociedad, para entender esta situación y tomar decisiones adecuadas y oportunas.
Una de estas facetas es la tendencia en contagio y muertes atribuidas al Coronavirus COVID-19, en especial, su comparación entre diferentes países.
Saber que de un día a otro han aparecido veinte casos de contagio nuevos es un dato difícil de interpretar si no tenemos puntos de comparación. Por ejemplo, ¿Qué tan grande es este número de contagios comparado con la tendencia mundial? ¿Son muchos, son pocos? ¿Qué tantos casos son con respecto a la población de un país? ¿Representa un número gran de o pequeño de la población?
En este artículo revisaremos una manera de visualizar los datos disponibles de contagio y fallecimientos por Coronavirus que pueden ayudar a responder estas preguntas, usando R. Al concluir este artículo, podrás generar un gráfico como el siguiente, que compara las tendencias de cuatro países diferentes.
Este artículo asume que tienes conocimiento básico de R y del paquete ggplot2, que será nuestra herramienta para generar gráficos.
Todo el código usado en este artículo lo podrás encontrar en GitHub:
Comenzamos instalando los paquetes necesarios para este análisis.
Para este análisis necesitamos los siguientes paquetes:
tidyverse: Un metapaquete que contine múltiples paquetes los cuales extienden las características de R. Usaremos los siguientes:
dplyr: Manipulación de datos. En particular, usaremos mucho el operador %>%, que significa “toma el resultado del lado izquierdo como argumento para el lado derecho”. Esto facilita realizar operaciones en secuencia, presentándolas de una manera clara, que es sencilla de modificar.readr: Lectura y escritura de archivos.tidyr: Funciones para limpiar y uniformar datos.stringr: Procesamiento de cadenas de texto.purr: Programación funcional en R, en particlar, herramentas para trabajar con listas.ggplot2: Creación de gráficos y visualizaciones de información.readxl: Lectura de documentos de Microsoft Excel (xls y xlsx).lubridate: Herramientas para trabajar con fechas.janitor: Limpieza de nombres de variables.scales: Herramientas para dar formato a datos.RColorBrewer: Creación de paletas de colores.Si no tienes instalados estos paquetes, puedes instalarlos con la función install.packages().
Una vez que hemos instalado estos paquetes, los cargamos a nuestro espacio de trabajo con library()
library(tidyverse)
library(readxl)
library(lubridate)
library(janitor)
library(scales)
library(RColorBrewer)Nuestro siguiente paso es crear algunas variables auxiliares que nos serán de utilidad más adelante.
Como nuestro objetivo es visualizar tendencias, creamos un par de variables con fechas de referencia.
La primera será la fecha actual, que al momento de realizar el análisis es 2020-03-22, que asignamos en la variable hoy.
Nuestro resultado.
## [1] "2020-03-22"
También creamos una variable con un data frame de todas las fechas del 2020, desde el primero de enero hasta el día de hoy. Esta nos ayudará a asegurar que tenemos secuencias de días completos en nuestros datos.
Usamos la función seq.Date() en conjunto con la función ymd() de lubridate para generar una secuencia de fechas desde el primero de enero de 2020 hasta el día de hoy.
Guardamos el resultado en el objeto llamado fechas_2020, creado con la función tibble() de dplyr()
El siguiente paso es descargar los datos que de contagio y de población.
Necesitamos datos del número de personas contagiadas de Coronavirus y que han fallecido a causa de este.
Existen diferentes fuentes de información para obtener estos datos, distribuidas por organizaciones públicas y privadas, con distintas características y distribuidos en diferentes formatos.
Usaremos los datos del Centro Europeo para la Prevención y Control de Enfermedades (ECDPC, European Centre for Disease Prevention and Control).
Este conjunto de datos se actualiza diariamente y lleva un registro de contagios y muertes de todo el mundo, identificados por fecha y región.
Los datos se encuentran en la siguiente página.
Los descargaremos usando la función download.file(), pero antes debemos crear el enlace para los datos del día de hoy, pues cambia diariamente. Usando como referencia la información de la página, generamos un enlace de la siguiente manera, con la función paste0().
url_covid <-
paste0(
"https://www.ecdc.europa.eu/sites/default/files/documents/COVID-19-geographic-disbtribution-worldwide-",
hoy, ".xlsx"
)También creamos una ruta para el archivo local en el que guardaremos los datos.
Ya definidas estas variables, descargamos los datos usando download.file() con el argumento mode = "wb" para evitar problemas al leer el documento ontenido. El archivo es un documento de Microsoft Excel, que será guardado en nuestra carpeta de trabajo.
El siguiente paso es obtener los datos de población de los diferentes países del mundo.
Los datos de población nos permitirán obtener un valor relativo de los contagios y muertes, es decir, qué proporción de los habitantes de un país representan.
Usaremos los datos del Population Reference Bureau, que corresponden a la población de mediados del 2019, que para nuestros fines es una dato aceptable. Esta información se encuentra en la siguiente página.
Descargamos los datos al archivo poblacion.csv en nuestra carpeta de trabajo.
download.file(
url = "https://datacenter.prb.org/download/international/indicator/population/2019/csv",
destfile = "poblacion.csv",
mode = "wb"
)Ya tenemos los datos, ahora necesitamos leerlo y procesarlos a un formato apropiado para nuestros fines.
Leemos los primeros diez renglones de nuestros datos de población del archivo poblacion.csv. Vamos a usar read_lines() de readr para ilustrar un aspecto importante del procesamiento de datos.
## [1] "Population mid-2019"
## [2] "Population Reference Bureau prb.org"
## [3] "Sources: 2019 World Population Data Sheet"
## [4] ""
## [5] "FIPS,Name,Type,TimeFrame,Data"
## [6] "WORLD,WORLD,World,2019,7691.463"
## [7] "AFRICA,AFRICA,Sub-Region,2019,1305.215"
## [8] "NORTHERN AFRICA,NORTHERN AFRICA,Sub-Region,2019,239.895"
## [9] "DZ,Algeria,Country,2019,43.406"
## [10] "EG,Egypt,Country,2019,99.064"
Al leer de esta manera el archivo, nos damos cuenta que tenemos renglones de encabezado que necesitamos omitir. Después de ese encabezado se encuentran los datos que necesitamos con un formato bastante limpio que no requiere mayor procesamiento.
Sin embargo, si intentas leer directamente con read_csv() de readr, el resultado es el siguiente.
## Parsed with column specification:
## cols(
## `Population mid-2019` = col_character()
## )
## Warning: 9 parsing failures.
## row col expected actual file
## 3 -- 1 columns 5 columns 'poblacion.csv'
## 4 -- 1 columns 5 columns 'poblacion.csv'
## 5 -- 1 columns 5 columns 'poblacion.csv'
## 6 -- 1 columns 5 columns 'poblacion.csv'
## 7 -- 1 columns 5 columns 'poblacion.csv'
## ... ... ......... ......... ...............
## See problems(...) for more details.
## # A tibble: 10 x 1
## `Population mid-2019`
## <chr>
## 1 Population Reference Bureau prb.org
## 2 Sources: 2019 World Population Data Sheet
## 3 FIPS
## 4 WORLD
## 5 AFRICA
## 6 NORTHERN AFRICA
## 7 DZ
## 8 EG
## 9 LY
## 10 MA
Si no te tomas el tiempo de explorar directamente tus datos, encontrar la razón por la que estás obteniendo esta salida puede ser sumamente difícil. Por esto es importante inspeccionar tus archivos, aunque tengan una extensión que, tradicionalmente, es fácil procesar y que en teoría no debería generar problemas.
Dicho esto, todo lo que tenemos que hacer es agregar el argumento skip = 3 a read_csv() para omitir el encabezado.
Después de eso, realizaremos el siguiente procesamiento.
select() para cambiar los nombres de las columnas. La columna Data contiene la información de población, expresada en millones de personas, por eso la renombramos como pob_mill. La columna FIPS es renombrada a geo_id para poder unir estos datos con los que tenemos de Coronavirus.filter() elegimos los renglones que coincidan con tipo igual a “Country”, es decir, países y no continentes u otras regiones geográficas.mutate() para crear la columna pob_raw, que la población expresada en miles de personas. Esto nos servirá más adelante, al visualizar los datos.Todo lo anterior lo realizamos con el siguiente bloque de código y lo asignamos a la variable data_poblacion.
data_poblacion <-
read_csv("poblacion.csv", skip = 3) %>%
select(
"geo_id" = FIPS,
"nombre" = Name,
"tipo" = Type,
"periodo" = TimeFrame,
"pob_mill" = Data
) %>%
filter(tipo == "Country") %>%
select(geo_id, pob_mill) %>%
mutate(pob_raw = pob_mill * 10 ^ 3) ## Parsed with column specification:
## cols(
## FIPS = col_character(),
## Name = col_character(),
## Type = col_character(),
## TimeFrame = col_double(),
## Data = col_double()
## )
Es momento de unir los datos de Coronavirus con los de población.
Dado que tenemos una columna geo_id en nuestros dos conjuntos de datos, la unión es muy sencilla usando la función inner_join() de dplyr. Guardamos el resultado en la variable datos_combinados.
Nuestro resultado es el siguiente.
## # A tibble: 3,440 x 10
## fecha casos_nuevos muertes_nuevas region geo_id casos_acumulados
## <date> <dbl> <dbl> <chr> <chr> <dbl>
## 1 2020-03-03 1 0 Andor~ AD 1
## 2 2020-03-04 0 0 Andor~ AD 1
## 3 2020-03-05 0 0 Andor~ AD 1
## 4 2020-03-06 0 0 Andor~ AD 1
## 5 2020-03-07 0 0 Andor~ AD 1
## 6 2020-03-08 0 0 Andor~ AD 1
## 7 2020-03-09 0 0 Andor~ AD 1
## 8 2020-03-10 0 0 Andor~ AD 1
## 9 2020-03-11 0 0 Andor~ AD 1
## 10 2020-03-12 0 0 Andor~ AD 1
## # ... with 3,430 more rows, and 4 more variables: muertes_acumuladas <dbl>,
## # dia <int>, pob_mill <dbl>, pob_raw <dbl>
Hasta aquí todo va bien, pero necesitamos transformar nuestros datos para poder visualizarlos más fácilmente con ggplot2.
Haremos lo siguiente.
mutate() creamos la proporción de contagios y muertes por mil habitantes, dividiendo entre la variable pob_raw. Obtenemos las columnas casos_por_mil_habitantes y muertes_por_mil_habitantes.pivot_longer() de tidyr. Con esta función transformamos múltiples columnas en dos, una con una etiqueta, el nombre de la columna original, y otra con un dato, lo que contenía la columna. Crearemos las columnas tipo y valor.mutate_at() de dplyr cambiamos el contenido de las columnas tipo y region. La función toTitleCase de tools (incluida con la instalación estándar de R) cambia la primera letra de cada palabra a mayúscula y la función str_replace_all() de stringr para cambiar los guiones bajos (_) a espacios.Realizamos lo anterior con el siguiente bloque de código y lo asignamos al objeto data_combinados.
data_combinados <-
data_combinados %>%
mutate(
casos_por_mil_habitantes = casos_acumulados / pob_raw,
muertes_por_mil_habitantes = muertes_acumuladas / pob_raw
) %>%
pivot_longer(
cols = c("casos_nuevos", "muertes_nuevas",
"casos_acumulados", "muertes_acumuladas",
"casos_por_mil_habitantes", "muertes_por_mil_habitantes"),
names_to = "tipo", values_to = "valor"
) %>%
mutate_at(c("tipo", "region"),
~tools::toTitleCase(.) %>%
str_replace_all("_", " "))Ya casi estamos listos para visualizar nuestros datos, pero antes necesitamos otra variable.
Para visualizar nuestros datos, necesitamos definir cuál el núero de días que han ocurrido desde el primero contagio hasta hoy, un dato que cambiará dependiendo del país que elijamos para nuestro análisis.
Algunos países han tenido casos desde el inicio desde 2019 e inicio de 2020, mientras que otros tienen apenas días desde el primer caso. En mi caso, me interesan los datos de México, que es donde vivo, así que extraere el dato para ese país.
Usamos filter() para obtener el renglón con los datos de México (MX) para hoy, nos quedamos con el primer renglón de estos datos con head() y usamos pull() de dplyr() para obtener el valor de dia como un vector numérico.
Nuestro resultado.
## [1] 23
Nuestro siguiente paso es la visualización
Como mencionamos en la introducción de este artículo, asumimos que tienes un dominio básico de ggplot2, es decir, que por lo menos puedes crear un gráfico usando la función ggplot(), agregar dimensiones con aes() y agregar elementos gráficos con geom().
Dicho esto, empezamos creando un tema de ggplot2 para darle una mejor presentación a nuestros gráficos.
Nuestro tema toma como base el tema minimal incluido en ggplot2, quita las líneas de referencia menores en los páneles de ambos ejes y las líneas de referencia mayores para el eje x. Además, agrega un color de fondo para los títulos de facets.
Guardamos este tema en la variable tema_plot y lo agregaremos con + una vez que hemos definido los elementos de nuestros gráficos.
tema_plot <-
theme_minimal() +
theme(
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank(),
strip.background = element_rect(fill = "#eeeeee", color = NA)
) Ahora sí, a crear gráficos.
En este artículo revisamos una manera de visualizar información que puede resultar relevante para comprender un problema complejo, como lo es la pandemia actual de Coronavirus COVID-19.
Vimos la manera de descargar, leer, procesar y combinar datos, así como la generación de gráficos más o menos complejos.
No nos detuvimos mucho en el análisis de los resultados obtenidos del análisis, pues esto requiere de un conocimiento disciplinar específico, por ejemplo en epidemiología o salud pública, que no poseo. Sin embargo, creo que es posible contextualizar mejor la situación actual al tener más puntos de referencia.
Los datos que hemos usado y los gráficos que hemos generado pueden usarse para realizar análisis diferentes, lo cual podría resultar en insights interesantes.
Y, desde luego, ante una situación como esta pandemia, lo mejor que podemos hacer es cuidarnos y cuidar de los demás.
El código de este artículo se encuentra disponible en GitHub:
Consultas, dudas, comentarios y correcciones son bienvenidas:
El código y los datos usados en este documento se encuentran en Github: