# load packages ----------------------------------------------------------------
library(introexercises)
library(learnr)
library(gradethis)
library(dplyr)
library(flair)
library(ggplot2)
library(lubridate)
library(fontawesome)
library(tidyr)
library(forcats)
library(janitor)
library(kableExtra)
# library(RMariaDB)        # connect to sql database 

## set options for exercises and checking ---------------------------------------

## Define how exercises are evaluated 
gradethis::gradethis_setup(
  ## note: the below arguments are passed to learnr::tutorial_options
  ## set the maximum execution time limit in seconds
  exercise.timelimit = 60, 
  ## set how exercises should be checked (defaults to NULL - individually defined)
  # exercise.checker = gradethis::grade_learnr
  ## set whether to pre-evaluate exercises (so users see answers)
  exercise.eval = FALSE 
)

# ## event recorder ---------------------------------------------------------------
# ## see for details: 
# ## https://pkgs.rstudio.com/learnr/articles/publishing.html#events
# ## https://github.com/dtkaplan/submitr/blob/master/R/make_a_recorder.R
# 
# ## connect to your sql database
# sqldtbase <- dbConnect(RMariaDB::MariaDB(),
#                        user     = Sys.getenv("userid"),
#                        password = Sys.getenv("pwd"),
#                        dbname   = 'excersize_log',
#                        host     = "144.126.246.140")
# 
# 
# ## define a function to collect data 
# ## note that tutorial_id is defined in YAML
#     ## you could set the tutorial_version too (by specifying version:) but use package version instead 
# recorder_function <- function(tutorial_id, tutorial_version, user_id, event, data) {
#     
#   ## define a sql query 
#   ## first bracket defines variable names
#   ## values bracket defines what goes in each variable
#   event_log <- paste("INSERT INTO responses (
#                        tutorial_id, 
#                        tutorial_version, 
#                        date_time, 
#                        user_id, 
#                        event, 
#                        section,
#                        label, 
#                        question, 
#                        answer, 
#                        code, 
#                        correct)
#                        VALUES('", tutorial_id,  "', 
#                        '", tutorial_version, "', 
#                        '", format(Sys.time(), "%Y-%M%-%D %H:%M:%S %Z"), "',
#                        '", Sys.getenv("SHINYPROXY_PROXY_ID"), "',
#                        '", event, "',
#                        '", data$section, "',
#                        '", data$label,  "',
#                        '", paste0('"', data$question, '"'),  "',
#                        '", paste0('"', data$answer,   '"'),  "',
#                        '", paste0('"', data$code,     '"'),  "',
#                        '", data$correct, "')",
#                        sep = '')
# 
#     # Execute the query on the sqldtbase that we connected to above
#     rsInsert <- dbSendQuery(sqldtbase, event_log)
#   
# }
# 
# options(tutorial.event_recorder = recorder_function)
# hide non-exercise code chunks ------------------------------------------------
knitr::opts_chunk$set(echo = FALSE)


# Data prep --------------------------------------------------------------------
# Import
combined <- rio::import(system.file("dat/linelist_combined_20141201.rds", package = "introexercises"))
# hide non-exercise code chunks ------------------------------------------------
knitr::opts_chunk$set(echo = FALSE)

Introducción a R para Epidemiología Aplicada y Salud Pública

Bienvenido

Bienvenido al curso "Introducción a R para epidemiología aplicada", ofrecido por Epidemiología - una organización sin ánimo de lucro y el principal proveedor de formación, apoyo y herramientas de R para profesionales de primera línea de la salud pública.

knitr::include_graphics("images/logo.png", error = F)

Datos pivotantes

Este ejercicio se centra en pivotar columnas dentro de marcos de datos de ancho a largo, e introduce la clase de columna "factor".

Formato

Este ejercicio te guía a través de las tareas que debes realizar en RStudio en tu ordenador lo.

Obtener ayuda

Hay varias formas de obtener ayuda:

1) Busca a los "ayudantes" (ver más abajo) 2) Pide ayuda al instructor/facilitador de tu curso en directo 3) Programa una llamada 1 a 1 con un instructor para "Tutoría del curso". 4) Publica una pregunta en Comunidad Epi Aplicada

Este es el aspecto que tendrán esos "ayudantes":

r fontawesome::fa("lightbulb", fill = "gold") Haz clic para leer una sugerencia

¡Aquí verás una pista útil!


r fontawesome::fa("check", fill = "red")Haz clic para ver la solución (¡pruébalo tú primero!)

linelist %>% 
  filter(
    age > 25,
    district == "Bolo"
  )

Aquí tienes más explicaciones sobre por qué funciona la solución.


Preguntas del concurso

Responder a las preguntas del cuestionario te ayudará a comprender el material. Las respuestas no se registran.

Para practicar, responde a las siguientes preguntas:

quiz(
  question_radio("When should I view the red 'helper' code?",
    answer("After trying to write the code myself", correct = TRUE),
    answer("Before I try coding", correct = FALSE),
    correct = "Reviewing best-practice code after trying to write yourself can help you improve",
    incorrect = "Please attempt the exercise yourself, or use the hint, before viewing the answer."
  )
)
question_numeric(
 "How anxious are you about beginning this tutorial - on a scale from 1 (least anxious) to 10 (most anxious)?",
 answer(10, message = "Try not to worry, we will help you succeed!", correct = T),
 answer(9, message = "Try not to worry, we will help you succeed!", correct = T),
 answer(8, message = "Try not to worry, we will help you succeed!", correct = T),
 answer(7, message = "Try not to worry, we will help you succeed!", correct = T),
 answer(6, message = "Ok, we will get there together", correct = T),
 answer(5, message = "Ok, we will get there together", correct = T),
 answer(4, message = "I like your confidence!", correct = T),
 answer(3, message = "I like your confidence!", correct = T),
 answer(2, message = "I like your confidence!", correct = T),
 answer(1, message = "I like your confidence!", correct = T),
 allow_retry = TRUE,
 correct = "Thanks for sharing. ",
 min = 1,
 max = 10,
 step = 1
)

Licencia

Por favor, envía un correo electrónico a contact@appliedepi.org si tienes preguntas sobre el uso de estos materiales.

Objetivos de aprendizaje

En este ejercicio

El código de este ejercicio no es vital para futuros ejercicios. Si estás cansado, puedes simplemente leer el ejercicio, copiar/pegar el código y asimilar el material.

Preparación

Este ejercicio utiliza el combined marco de datos que se creó en el ejercicio anterior sobre "Unir datos".

Si no has completado ese ejercicio, o ves errores al intentar utilizar combined puedes importar y utilizar una "copia de seguridad". combined de la carpeta "data/clean/backup/" añadiendo este comando a tu fragmento de código de importación:

combined <- import(here("data", "clean", "backup", "linelist_combined_20141201.rds"))

Nuevo trozo para Pivotar

Añade un nuevo fragmento de código para "Líneas de tiempo del paciente", cerca de la parte inferior, después de la sección "Análisis puntual" de tu script R Markdown.

Puedes añadir un encabezado de sección en el fragmento de código para mayor claridad:

# Patient timelines - pivoting exercise

Pivotar para trazar líneas temporales de pacientes

Ahora que tenemos la combined marco de datos, podemos elaborar una imagen más completa del recorrido de cada paciente por el sistema sanitario. Tenemos información sobre date_infection, date_onset, date_report, date_hospitalization y date_outcome.

Vamos a crear un pequeño marco de datos y un gráfico para examinar las líneas temporales de 5 pacientes. Crearemos la siguiente figura. Cada caso tiene su propia fila, y las fechas de los hitos se visualizan mediante puntos de color y forma variables.

# Pivoting - patient timelines ----------------------------------------

timelines <- combined %>% 
  arrange(date_onset) %>%                 # sort dataset so that earliest are at the top
  head(5) %>%                             # keep only the top 5 rows
  select(case_id, starts_with("date"))    # keep only certain columns 

timelines_long <- timelines %>% 
  pivot_longer(
    cols = starts_with("date"),
    names_to = "date_type",
    values_to = "date"
  ) %>% 
  mutate(date_type = fct_relevel(date_type, "date_infection", "date_onset", "date_report", "date_hospitalisation", "date_outcome"))

timelines_long %>% 
  ggplot(mapping = aes(x = date, y = case_id, color = date_type, shape = date_type, group = case_id))+
  geom_point(size = 4)+
  geom_line()+
  theme_minimal()

Vamos a construir juntos este gráfico, y de paso aprenderemos sobre pivotar más tiempo y sobre factores.

Seleccionar casos

En primer lugar, reducimos el conjunto de datos de las siguientes maneras:

Añade este código a tu fragmento de código "Pivotar - Líneas de tiempo del paciente", resalta y ejecuta el código.

timelines <- combined %>% 
  arrange(date_onset) %>%                 # sort dataset so that earliest are at the top
  head(5) %>%                             # keep only the top 5 rows
  select(case_id, starts_with("date"))    # keep only certain columns 

Observa que podemos utilizar la función de ayuda "tidyselect starts_with() para consultar todas las columnas de fecha a la vez.

Veamos este nuevo conjunto de datos. Ejecuta un comando timelines en tu Área de Pruebas, o directamente en la Consola, para ver los registros.

timelines

Anticipa el trazado de estos datos con ggplot(). Como ya sabes, ggplot() con geom_point() te pedirá los nombres de las columnas que utilizarás para asignarlas a los ejes (x = y y =).

quiz(
  question("In it's current form, which column would be assigned to the X-axis to create the plot??",
    answer("date_onset", message = "This will not work because in the plot, the date axis reflects all the different date types"),
    answer("date_outcome", message = "This will not work because in the plot, the date axis reflects all the different date types"),
    answer("date_infection", message = "This will not work because in the plot, the date axis reflects all the different date types"),
    answer("date", message = "This is not a column in the current dataset."),
    answer("Not possible in current format", correct=TRUE, message = "Yes, the dataset must be transformed."),
    allow_retry = TRUE
  )
)

Pivotar más tiempo

Para utilizar este conjunto de datos en ggplot() tenemos que transformar o "pivotar" las columnas en formato "largo". Esto dará lugar a un nuevo marco de datos llamado timelines_long con sólo 3 columnas:

Para ello, utilizaremos pivot_longer() para recoger todas las columnas de fecha y pivotar sus valores en sólo esas dos nuevas columnas (date_type y date).

En su mínima expresión, la función sólo necesita el argumento cols = que debe proporcionarse con un vector de las columnas a pivotar (en este caso, las columnas de fecha).

Afortunadamente, podemos hacer referencia a todas las columnas "fecha" con el ayudante starts_with("date"). En otras circunstancias podrías enumerar los nombres de las columnas dentro de un vector c().

Añade el siguiente código a tu trozo de código "pivotante".

# Pivot dates longer
timelines_long <- timelines %>% 
  pivot_longer(cols = starts_with("date"))

Mira qué aspecto tiene ahora este conjunto de datos:

timelines_long


Fíjate en lo siguiente:

quiz(
  question("How did the dimensions of the data frame change?",
    answer("The pivoted data frame is the same as the old."),
    answer("The pivoted data frame has more columns"),
    answer("The pivoted data frame has more columns, but fewer rows"),
    answer("The pivoted data frame has fewer columns, but more rows", correct=TRUE, message = "Yes, since there were 5 date columns pivoted, there is now 5x as many rows as before. All the 5 date columns have been collapsed into 2 columns."),
    allow_retry = TRUE
  )
)

Si quieres, puedes volver a ejecutar el comando pivotar y añadir estos argumentos, que te permiten cambiar estos nombres por defecto para las dos nuevas columnas:

Actualiza tu pivot_longer() en el fragmento de código "Pivotar":

# Pivot dates longer
timelines_long <- timelines %>% 
  pivot_longer(
    cols = starts_with("date"),
    names_to = "date_type",
    values_to = "date")

Observa a continuación cómo los nombres de las columnas del timelines_long marco de datos:

timelines_long

Trazando

¿Qué ocurre si hacemos el ggplot ahora mismo, utilizando el conjunto de datos timelines_long?

quiz(
  question("Which column in the pivoted data frame will be mapped to the X-axis?",
    answer("case_id", message = "No, this discrete column will be on the Y-axis."),
    answer("date", correct = TRUE, message = "Yes, this column is continuous date values."),
    answer("date_type", message = "No, this column contains discrete character values. It will be used as color for the points and lines."),
    allow_retry = TRUE
  ),
  question("Which column in the pivoted data frame will be mapped to the Y-axis?",
    answer("case_id",
           correct = TRUE,
           message = "Yes, these are discrete character values."),
    answer("date",
           correct = FALSE,
           message = "No, this column is mapped to the X-axis."),
    answer("date_type",
           message = "No, this column contains discrete character values. It will be used as color for the points and lines."),
    allow_retry = TRUE
  )
)

Añade este código a tu fragmento de código Pivoting.

# create plot of patient timelines
ggplot(data = timelines_long,      # use the long dataset
         mapping = aes(
           x = date,               # dates of all types displayed along the x-axis
           y = case_id,            # case_id are discrete, character values
           color = date_type,      # color of the points
           shape = date_type,      # shape of the points
           group = case_id))+      # this makes the lines appear by color
  geom_point(size = 4)+            # show points
  geom_line()+                     # show lines
  theme_minimal()

Los puntos y las líneas están ahí, pero ¿están en un orden razonable en la leyenda?

Factores

Si una variable tiene un orden inherente, podríamos llamarla variable "ordinal". Piensa si los valores de una columna fueran "primero", "segundo" o "tercero". Querríamos que aparecieran en un gráfico en un orden concreto.

En R, este tipo de variables deben convertirse a la clase "factor". Un factor tiene "niveles", de forma que los valores están ordenados (primero, segundo, tercero, cuarto, etc.).

En este caso, la ordenación esperada sería:

1) "fecha_infección" 2) "fecha_inicio" 3) "fecha_informe" 4) "fecha_hospitalización" 5) "fecha_resultado"

Por supuesto, para algunos pacientes puede haber hospitalizados antes de que sean declarados, pero en general digamos que éste es el orden que queremos incrustar en la variable.

¿Cuál es la clase actual de date_type?

class(timelines_long$date_type)

No es un factor. Los valores de los caracteres no tienen un orden inherente. Por defecto aparecerán alfabéticamente.

Podemos cambiarlo utilizando fct_relevel() de la función {forcats} paquete. {forcats} forma parte del tidyverse. Esta función convierte la columna en clase "factor" y te da la oportunidad de establecer el orden deseado.

A continuación, añadimos un mutate() paso a la cadena de tuberías que redefine esta nueva columna y, a continuación, enumera los valores en el orden que deseemos. Actualiza tu pivot_longer() en el fragmento de código "Pivotar" para incluir el comando mutate() paso siguiente:

# Pivot dates longer
timelines_long <- timelines %>% 

  # pivot the dataset longer
  pivot_longer(
    cols = starts_with("date"),
    names_to = "date_type",
    values_to = "date") %>% 

  # set the new column date_type as class factor, and define order for its values
  mutate(date_type = fct_relevel(
    date_type,
    "date_infection", "date_onset", "date_report", "date_hospitalisation", "date_outcome"))

La clase de la columna date_type es ahora "factor".

class(timelines_long$date_type)

La columna date_type tiene ahora "niveles".

levels(timelines_long$date_type)

Después de volver a ejecutar la cadena de tuberías anterior (con el mutate() añadida), probamos de nuevo el ggplot: observa cómo ha cambiado la ordenación (fíjate en la leyenda):

timelines_long %>% 
  ggplot(data = timelines_long,
         mapping = aes(
           x = date,
           y = case_id,
           color = date_type,
           shape = date_type,
           group = case_id))+
  geom_point(size = 4)+
  geom_line()+
  theme_minimal()
quiz(
  question("Which case seems to have an error in date_outcome?",
    answer("dce5cc"),
    answer("9d4019"),
    answer("974bc1"),
    answer("76b97a"),
    answer("2ae019", correct=TRUE, message = "Yes, The recorded date of outcome is prior to the recorded date of onset."),
    allow_retry = TRUE
  )
)

Hay muchos otros {forcats} funciones para manejar factores, consulta este capítulo del Manual de Epi.

fct_lump()

Un {forcats} función que merece la pena mostrarte es fct_lump(). Esta función agregará los valores de una columna en una categoría "Otros" basándose en la frecuencia.

Observa esta curva epidémica: como la columna district está asignada a la estética fill = muestra cada distrito en la leyenda. ¡Esto es bastante abrumador y difícil de interpretar! Añade esto en un trozo a tu área de trazado y ejecuta el comando:

ggplot(data = combined, 
       mapping = aes(
         x = date_onset,
         fill = district))+
  geom_histogram(binwidth = 7)

Podemos utilizar fct_lump() y sus variaciones como fct_lump_n() para reducir el número de distritos que se muestran en el gráfico:

A continuación, envolvemos district dentro de fct_lump_n() y especifica que sólo queremos conservar los 3 distritos más comunes. Actualiza tu código para utilizar fct_lump_n() para el fill = como se ve a continuación:

ggplot(data = combined, 
       mapping = aes(
         x = date_onset,
         fill = fct_lump_n(district, 3)))+
  geom_histogram(binwidth = 7)+
  labs(fill = "District")

Observa que al aplicar esta función dentro de la página ggplot() no cambia la district subyacentes. Los datos se agrupan sólo para este gráfico. Si quieres agrupar los datos subyacentes, puedes hacerlo con mutate() en un tubo de limpieza.

Pivotar más ampliamente

En este ejercicio no nos centraremos en el pivotaje más amplio, ya que es menos habitual. Sin embargo, debes saber que si necesitas pivotar datos de forma más amplia, puedes encontrar buenos ejemplos en estos dos capítulos del Manual de Epi R:

Fin

¡Enhorabuena! Has terminado este ejercicio. ¡Has hecho líneas de tiempo de casos, has practicado el pivotaje de datos más largo y has utilizado algunas funciones para manejar factores!

Si quieres aprender un poco más sobre el pivotaje, puedes pasar al siguiente tema extra.

Extras: Pivotaje avanzado

Pivotar con varias clases

Esta es una demostración de cómo arreglar el pivotaje más largo de columnas de múltiples clases. Cuando decimos multiclase, nos referimos a que queremos pivotar varias columnas (de formato ancho a largo) que incluyan diferentes clases en cada columna.

Es algo habitual en los conjuntos de datos que realizan un seguimiento de casos o personas a lo largo del tiempo. Nuestro ejemplo será el de los controles diarios de seguimiento de la salud de los contactos de los casos (personas expuestas a los casos).

Primero, abre un nuevo script R de formato clásico. Guárdalo en tu proyecto "ebola" en la subcarpeta "scripts" como "pivot_multiclass_example.R". Añade una descripción en la parte superior.

#############################################
# Pivoting multi-class example
# Bonus section
# Your NAME here
#############################################

A continuación, carga el archivo {tidyverse} paquetes en la sección "Cargar paquetes".

# Load packages ----------------------------------------------------------------
pacman::p_load(tidyverse)

Crea un conjunto de datos de demostración

No utilizaremos nuestro surv datos para este ejemplo, sino un conjunto de datos sencillo que crearemos nosotros mismos utilizando código R.

Añade una sección "Crear datos" a tu script y ejecuta en ella el código siguiente. Este código crea un mini marco de datos en el objeto followup. Debería tener 5 columnas y 3 filas.

En tribble() te permite crear un marco de datos proporcionando valores de filas y columnas en una disposición de tabla estándar. La fila superior de valores (con tildes delante) son los nombres de las columnas.

# Create demo data ----------------------------------------------------------------
followup <- tribble(
  ~id, ~day1_date, ~day1_status, ~day2_date,   ~day2_status, ~day3_date,   ~day3_status,
  "A", "2022-04-01", "Healthy",  "2022-04-02", "Healthy",    "2022-04-03", "Sick",
  "B", "2022-04-01", "Healthy",  "2022-04-02", "Sick",       "2022-04-03", "Sick",
  "C", "2022-04-01", "Healthy",  "2022-04-02", "Healthy",    "2022-04-03", "Sick",
)


# review the dataset
followup

Observa cómo las columnas alternan entre valores de caracteres como "Sano" y valores de fecha.

Nos gustaría hacer pivotar el marco de datos más tiempo, para que haya 4 columnas:

Intento inicial

Primero, intenta pivotar el marco de datos simplemente utilizando pivot_longer(). Pivota todas las columnas excepto id. Utiliza names_to = y values_to = para ajustar los nuevos nombres de columna.

r fontawesome::fa("check", fill = "red")Haz clic para ver la solución (¡pruébalo tú primero!)

# Pivoting the data ----------------------------------------------------------------

# initial pivot (note dates and status values are combined into one column)
pivot_longer(
  followup,
  cols = -id,
  names_to = "Day",
  values_to = "Status")


Como verás, esto crea sólo 3 columnas, ¡no 4!

¿Qué notas en el Status columna? Tiene valores de Día y Fecha en su interior, y es de clase carácter. Esto no es útil para el análisis.

Debemos pivotar el marco de datos de forma diferente, para que estos valores estén en columnas separadas con la clase correcta, respectivamente.

Basa el pivote en la estructura del nombre de la columna

Para evitar esta situación de clases mezcladas, aprovecha la estructura sintáctica de los nombres de columna originales.

Existe una estructura de nombres común, con el número de observación, un guión bajo y, a continuación, "estado" o "fecha". Podemos aprovechar esta sintaxis para mantener estos dos tipos de datos en columnas separadas después del pivote.

Para ello

Así, la denominación y división de las nuevas columnas se basa en el guión bajo de los nombres de las variables existentes.

Actualiza tu comando como se indica a continuación y revisa el resultado.

# correct pivot
# .value is a special term. Pivoted columns are split based on a character in their name. 
pivot_longer(followup,
             cols = -id,
             names_to = c("Day", ".value"), 
             names_sep = "_")

Ahora tenemos las 4 columnas deseadas.

Este marco de datos es "largo" y "ordenado". Podemos introducirlo en un ggplot() para visualizar cómo ha cambiado la salud de los contactos a lo largo del tiempo. Observa el paso intermedio que garantiza que date tenga la clase Fecha correcta.

# Pivot data
pivot_longer(followup,
             cols = -id,
             names_to = c("Day", ".value"), 
             names_sep = "_") %>% 

mutate(date = ymd(date)) %>%   # ensure date class

ggplot(mapping = aes(x = date, y = id, color = status, shape = status, group = id))+
  geom_line()+
  geom_point()+
  scale_color_manual(
    values = c("Healthy" = "darkgreen",
               "Sick" = "red"))+
  labs(
    title = "Follow-up of patients over time",
    y = "Patient ID",
    x = "Date",
    color = "Status",
    shape = "Status")


appliedepi/introexercises documentation built on April 22, 2024, 1:01 a.m.