Ejercicio Práctico - Estudio de Caso

Evaluación de Introducción a R y estadística

Author
Affiliation

Mtro. Santiago Ríos

Introducción

Para concluir la sección de introducción, integremos todo lo aprendido para abordar un problema práctico. Usaremos el conjunto de datos oms del paquete datos que hemos utilizado en los módulos anteriores. Este dataset incluye información sobre la tuberculosis (TB), desglosada por año, país, edad, género y método de diagnóstico. Estos datos provienen del Informe de Tuberculosis de la Organización Mundial de la Salud 2014, que se puede encontrar en http://www.who.int/tb/country/data/download/en/.

Este dataset contiene mucha información epidemiológica, solo que tiene un detalle muy importante: los datos están muy sucios. Para limpiarlos y explorarlos, necesitamos aplicar todo lo que hemos aprendido en los módulos anteriores.

El objetivo es que puedas limpiar, explorar, visualizar y describir el dataset oms para obtener información relevante sobre la tuberculosis en el mundo. En la vida real, los datos que obtenemos rara vez están limpios y listos para ser analizados. Por lo tanto, es fundamental que sepas cómo limpiarlos y explorarlos para obtener información valiosa.

Preparación

Primero, vamos a cargar el dataset y a explorar su estructura. Desplazate con la barra de desplazamiento para ver todas las variables del dataset.

¿Qué problemas observas con este dataset? Observa que tiene: - Columnas redundantes. - Variables con nombres poco descriptivos. - Valores faltantes.

Si no sabemos qué significan las variables, es imposible analizar los datos. Sin embargo, recuerda que los datasets de R contienen información sobre las variables si llamamos al juego de datos con un argumento:

Solución

Recuerda los argumentos ?dataset y help(dataset).

Limpiar datos

  • A partir de la descripción del dataset que obtuviste en el ejercicio anterior, podemos ver distintos problemas. Vamos a limpiar los datos por partes antes de analizarlos

  • Existen 3 variables que se refieren a país. vamos a quitar 2 de estas 3 variables. Idealmente, deberías quedarte con la variable que tiene el nombre del país ya en limpio.

Solución

Recuerda la clase de manipulación de datos (link) y el resumen de las funciones de dplyr (link).

  • Después, tenemos una variable que indica año. Explora qué tipo de variable es y conviértela a una variable de tipo factor (si es que aplica). Esto solo lo haremos para simplificar el análisis, pero recuerda que también podríamos analizarla como una variable numérica.
Solución

Recuerda la función mutate() y cómo usarla para cambiar el tipo de dato en este (link).

  • Ahora, tenemos que solucionar el mayor problema de estos datos.
  • Las 56 columnas restantes son redundantes. Todas representan la cuenta de casos de TB, sin embargo, están desglosadas por edad, género y método de diagnóstico.
  • Podemos unir estas columnas en una sola variable que contenga la cuenta de casos de TB y así obtener un dataset con formato largo (una observación por fila).
  • Si no recuerdas esto, puedes revisar la sección de Forma de Datos en este (link).

  • Para juntar y agrupar en una sola variable, usaremos la función pivot_longer() del paquete tidyr.
  • Aquí el reto es juntar las 56 variables. La forma más fácil, pero menos práctica, sería específicar cada columna que queremos juntar. Sin embargo, podemos hacerlo de forma más eficiente.
  • Hay muchas formas para hacer esto. Mi recomndación es esta: observa que todas las columnas que queremos agrupar tienen un patrón común en su nombre. En la lección de manipulación de datos (link), revisa las funciones de ayuda de dplyr. Analiza cuál de ellas te puede ayudar a resolver este problema:
  • Al correr el siguiente código, deberías tener un dataframe con 4 columnas: pais, anio, clave y casos en un total de 76046 filas.
  • No te olvides cargar la librería necesaria para cargar la función pivot_longer().
  • Ojo: en este paso, también vamos a eliminar las filas con valores faltantes con el argumento values_drop_na = TRUE.
Pista 1

Cuál de las siguientes funciones de ayuda te podría ayudar: starts_with(), ends_with(), contains(), matches(), num_range(), one_of(), everything().

  • Ahora, pon atención en los nombres de la columna clave. Estos nombres son poco descriptivos y no nos dicen mucho. Vamos a limpiarlos para que sean más descriptivos.
  • Si revisas la estructura de los datos, verás que los nombres de las columnas clave siguen ciertos patrones.
  • Cuando tienen las siguientes letras, significan lo siguiente:
    • recaida se refiere a casos reincidentes
    • ep se refiere a tuberculosis extra pulmonar
    • fpn se refiere a casos de tuberculosis pulmonar que no se pueden detectar mediante examen de frotis pulmonar (frotis pulmonar negativo)
    • fpp se refiere a casos de tuberculosis pulmonar que se pueden detectar mediante examen de frotis pulmonar (frotis pulmonar positivo)
    • La letra que aparece después del último _ se refiere al sexo de los pacientes. El conjunto de datos agrupa en hombres (h) y mujeres (m).
    • Los números finales se refieren al grupo de edad que se ha organizado en siete categorías:
      • 014 = 0 – 14 años de edad
      • 1524 = 15 – 24 años de edad
      • 2534 = 25 – 34 años de edad
      • 3544 = 35 – 44 años de edad
      • 4554 = 45 – 54 años de edad
      • 5564 = 55 – 64 años de edad
      • 65 = 65 o más años de edad
  • Idealmente, lo que queremos es que estos patrones se conviertan en variables separadas. Por ejemplo, si tenemos una columna clave con el nombre recaida_ep_h_014, queremos que se convierta en 4 columnas: incidencia, ep, h, 014.
  • Esto nos permitirá analizar los datos de forma más sencilla, por ejemplo, agrupando los casos por sexo o por edad.

Verás que el problema anterior puede resolverse con solo dos funciones. - Para empezar, observa que los patrones que queremos extraer están separados por _; por ejemplo, recaida_ep_h_014, nuevos_ep_h1524, etc. - Por lo tanto, podemos usar una función que haga lo siguiente: tome cada dato de la columna clave y lo separe en distintas columnas cada vez que encuentre un _. - Antes de enseñarte a hacer esto, tenemos que resolver un problema antes te aplicar esta función. - Si observas la estructura de los datos, verás que hay casos en los que no se cumple el patrón que mencionamos. En específico, hay unos casos donde tenemos el patrón nuevosrecaida en lugar de nuevos_recaida. - Por lo tanto, tenemos que ver una forma de separar estos casos. - Para esto, hay un paquete del tidyverse que nos puede ayudar. Este paquete se llama stringr y tiene una función que nos permite hacer esto. - stringr es una referencia a los tipos de datos que se conocen como strings, que si recuerdas, son las cadenas de texto: “hola”, “mundo”, “recaida_ep_h_014”, etc.

Figuras de Allison Horst
  • La función que nos va a ayudar a separar estos casos es str_replace(). Esta función nos permite reemplazar un patrón en una cadena de texto por otro patrón.
  • Por lo tanto, para tener nombres consistentes, basta con reemplazar nuevosrecaida por nuevos_recaida.
  • Esta función toma los siguientes argumentos: str_replace(string, pattern, replacement).
    • string es la cadena de texto en la que queremos hacer el reemplazo.
    • pattern es el patrón que queremos reemplazar.
    • replacement es el patrón por el que queremos reemplazar.
Respuesta
library(stringr) # Carga la librería necesaria

# Reemplaza los casos donde no se cumple el patrón
oms_5 <- oms_4 %>%
  mutate(clave = str_replace(clave, "nuevosrecaida", "nuevos_recaida"))

head(oms_5) # Verificamos que se haya hecho correctamente

  • Ahora, vamos a separar los patrones que mencionamos anteriormente.
  • Para esto, usaremos la función separate().
  • Esta función es parte del paquete tidyr y nos permite separar una columna en varias columnas a partir de un patrón.
  • Tomará los siguientes argumentos: separate(data, col, into, sep).
    • data es el dataframe que queremos modificar.
    • col es la columna que queremos separar.
    • into es un vector con los nombres de las columnas en las que queremos separar la columna original.
    • sep es el patrón que queremos usar para separar la columna original.
  • Los nombres de las columnas que vamos a separar son: nuevos, tipo, sexo_edad
Solución
# Separa los patrones de la columna clave
oms_6 <- oms_5 %>%
  separate(clave, into = c("nuevos", "tipo", "sexo_edad"), sep = "_")

head(oms_6) # Verificamos que se haya hecho correctamente
  • A continuación podemos eliminar la columna nuevos, ya que es constante en este dataset.
Solución

Recuerda la función select().

  • Para separar la columna sexo_edad en dos columnas, usaremos la función separate() de nuevo.
  • Observa los valores de esta columna; por ejemplo: h014, m1524, m2534, h65 etc.
  • ¿Qué patrón encuentras? ¿Cómo lo separarías en dos columnas?
  • Una opción es usar sep = x, donde x representa un número. Este número indica la posición en la que queremos separar la cadena de texto.
  • Intenta el siguiente código para separar la columna sexo_edad en dos columnas: sexo y edad.
Solución
separate(sexo_edad, c("sexo", "edad"), sep = 1)
Caso más complicado
  • Imagina que la columna sexo_edad tuviera un patrón más sucio, como h24, 027m, 6h.
  • En estos casos, se usa lo que se conoce como expresiones regulares.
  • Las expresiones regulares son patrones que se utilizan para encontrar secuencias de caracteres que conforma un patrón de búsqueda.
  • Son extremadamente poderosas y útiles, pero también muy complicadas.
  • Puedes leer más de ellas en el link de arriba. En este curso no las veremos, pero puedes conocerlas con este ejemplo.
  • Si pasamos una expresión regular a sep, podemos separar la cadena de texto en dos partes. Esta expresión regular es "(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)".
    • \\d significa cualquier dígito.
    • \\D significa cualquier carácter que no sea un dígito.
    • (?<=\\d)(?=\\D) significa que queremos separar la cadena de texto en dos partes: una que contenga letras y otra que contenga números.
    • | significa o.
    • Por lo tanto, "(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)" significa que queremos separar la cadena de texto en dos partes: una que contenga letras y otra que contenga números.
  • Por lo tanto, podrías usar sep = "(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)" para separar la columna sexo_edad en dos columnas: sexo y edad en patrones más complicados y menos consistentes.

Todo en un solo paso…

  • Cuando trabajas en datos, es normal que en un principio hagas las cosas paso a paso.
  • Esto es bueno para entender cómo funcionan las funciones y cómo se aplican a los datos.
  • Además, te permite verificar que cada paso se haya hecho correctamente.
  • Sin embargo, una vez que entiendes cómo funcionan las funciones, puedes hacer todo en un solo paso.
  • Esto es útil cuando tienes que hacer lo mismo con muchos datasets o cuando tienes que hacerlo de forma repetida.
  • Encadena todos los pasos anteriores en una sola línea de código utilizando la pipa %>%.
  • Una vez que ejecutas el código completo en una sola línea, ¿cuánto tiempo tardó en limpiar estos 70,000 datos?
  • ¿Cuánto tiempo te hubiera tomado hacerlo a mano o en Excel?
  • La eficiencia de R es una de las razones por las que es tan popular en la ciencia de datos.
  • Además, es menos propenso a errores, en especial si construyes tu código de forma ordenada y sistemática.
  • Aunque al principio puede ser complicado, con la práctica, te volverás más rápido y eficiente en el manejo de datos.
  • Imagina que tienes que hacer esto con 100 datasets. ¿Cuánto tiempo te ahorrarías?

Si todo va bien hasta ahora, deberías de tener un dataset similar a este. En el siguiente ejercicio exploraremos estos datos limpios.