```{=html}
```r # load packages ---------------------------------------------------------------- library(introexercises) # get datos for exercises library(learnr) # create lessons from rmd library(gradethis) # evaluate exercises library(dplyr) # wrangle datos library(tidyr) # pivot library(forcats) # factors library(stringr) # strings library(flair) # highlight code library(ggplot2) # visualise datos library(lubridate) # work with dates library(epikit) # for emojis library(skimr) # browse datos library(fontawesome) # for emojis library(janitor) # limpios datos # 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 datos # ## 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, datos) { # # ## 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, "', # '", datos$section, "', # '", datos$label, "', # '", paste0('"', datos$question, '"'), "', # '", paste0('"', datos$answer, '"'), "', # '", paste0('"', datos$code, '"'), "', # '", datos$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)
# datos prep -------------------------------------------------------------------- vig_bruta <- rio::import(system.file("dat/listado_vigilancia_20141201.csv", package = "introexercises")) # for quizes vig <- rio::import(system.file("dat/listado_vigilancia_limpio_20141201.rds", package = "introexercises")) malaria_recuento <- rio::import(system.file("dat/malaria_facility_count_data.rds", package = "introexercises")) datadict <- rio::import(system.file("dat/diccionario_listado_es.csv", package = "introexercises")) cobertura_lugares_ord <- rio::import(system.file("dat/ejemplos_datos_desordenados.xlsx", package = "introexercises"), sheet = "tidy_site_coverage")
Bienvenido al curso "Introducción a R para epidemiología aplicada", ofrecido por Epidemiología - una organización sin fines 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)
Este ejercicio se centra en la recodificación lógica de valores, el filtrado de filas, la creación de categorías de edad y otras tareas más complejas.
Este ejercicio te guía a través de las tareas que debes realizar en RStudio en tu ordenador o computadora.
Hay varias formas de obtener ayuda:
1) Busca la sección de ayuda (ver más abajo) 2) Pide ayuda al instructor/a o facilitador/a de tu curso en directo 3) Programa una llamada 1 a 1 con un/a instructor/a para "Tutoría del curso". 4) Publica una pregunta en Comunidad Epi Aplicada
Este es el aspecto que tendrá esa sección de ayuda:
r fontawesome::fa("lightbulb", fill = "gold")
Haz clic para leer una
pista
¡Aquí verás una pista útil!
r fontawesome::fa("check", fill = "red")
Haz clic para ver una solución
(¡pruébalo tú primero!)
vig %>% filter( edad > 25, distrito == "Bolo" )
Aquí tienes más explicaciones sobre por qué funciona la solución.
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("¿Cuándo debería mirar las secciones de ayuda en rojo?", answer("Tras intentar escribir el código yo mismo", correct = TRUE), answer("Antes de intentar escribir el código", correct = FALSE), correct = "Revisar el código de ejemplo después de intentar escribirlo usted mismo puede ayudarle a mejorar", incorrect = "Por favor, intente completar el ejercicio usted mismo, o use las pistas disponibles, antes de mirar la respuesta." ) )
question_numeric( "¿Qué tan preocupado/a estás ante la idea de empezar este tutorial - en una escala de 1 (nada nervioso) a 10 (extremadamente preocupado/a)?", answer(10, message = "Intenta no preocuparte, ¡te ayudaremos a conseguirlo!", correct = T), answer(9, message = "Intenta no preocuparte, ¡te ayudaremos a conseguirlo!", correct = T), answer(8, message = "Intenta no preocuparte, ¡te ayudaremos a conseguirlo!", correct = T), answer(7, message = "Intenta no preocuparte, ¡te ayudaremos a conseguirlo!", correct = T), answer(6, message = "De acuerdo, lo conseguiremos juntos", correct = T), answer(5, message = "De acuerdo, lo conseguiremos juntos", correct = T), answer(4, message = "¡Me gusta tu confianza!", correct = T), answer(3, message = "¡Me gusta tu confianza!", correct = T), answer(2, message = "¡Me gusta tu confianza!", correct = T), answer(1, message = "¡Me gusta tu confianza!", correct = T), allow_retry = TRUE, correct = "Gracias por responder", min = 1, max = 10, step = 1 )
Por favor, envía un correo electrónico a contact@appliedepi.org si tienes preguntas sobre el uso de estos materiales.
Abre el proyecto "ebola" de RStudio haciendo doble clic en el archivo "ebola.Rproj" de la carpeta "ebola".
Abre el archivo "analisis_ebola.R" con el que habías trabajado anteriormente. Seguirás completando el comando de limpieza.
Ejecuta todos los comandos desde la parte superior de este script hasta la parte inferior y lo más importante:
pacman::p_load()
para cargar paquetesimport()
y here()
para importar la base de datos
"sucia" vig_bruta
vig
(datos
depurados) en tu Entorno u área de trabajoTómate un momento para organizar y simplificar las secciones "Análisis exploratorio", "Lista de vigilancia limpia" y "Área de pruebas" de tu script para que no provoquen errores. Lo ideal sería que pudieras ejecutar todo tu script sin errores.
Ahora, compara tu comando de limpieza con el siguiente y asegúrate de que a tu comando de limpieza no le falta ningún paso.
vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer"))
Recuerda sólo debes tener un comando de limpieza en tu script.
Cualquier otro comando como class()
y tabyl()
deben estar en la sección de "Área
de Pruebas".
A veces, la recodificación de valores no es tan sencilla como sustituir un valor por otro. En su lugar, puedes utilizar sentencias y operadores lógicos para realizar acciones de recodificación más complejas.
En la columna de peso en kilogramos peso_kg
hay que corregir algunos
valores negativos, lo cual no tiene sentido.\
En el panel de Entorno, haz clic en el objeto dataframe vig
. A
continuación, busca la columna peso_kg
y en el botón a la derecha de la columna, haz
clic izquierdo para ordenar de menor a mayor. Observa los valores
negativos.
Alternativamente, en tu sección "Área de pruebas", ejecuta el comando
summary()
del paquete {base} con la columna vig$peso_kg
para retornar en la consola
estadísticas resumidas de esta columna numérica:
summary(vig$peso_kg)
¡Los valores negativos deben ser un error de introducción de datos!
Debemos eliminarlos de nuestros datos limpios convirtiéndolos en NA
(desaparecidos).
Recuerda que es mejor realizar estas modificaciones en tu script de R que en Excel u otro programa. De este modo, los cambios quedan registrados, se pueden repetir en cualquier versión actualizada de la base de datos y se pueden revertir fácilmente.
La lógica que queremos aplicar es sencilla: "Si el valor de nuestro
peso_kg
es negativo, conviértelo en NA
de lo contrario, mantén el
mismo valor". Como la lógica es sencilla, podemos utilizar la función
ifelse()
dentro de la función mutate()
para corregir la columna
peso_kg
.
La sintaxis de la función ifelse()
es la siguiente:
ifelse(Condición aplicada en la fila, resultado si la condición es VERDADERA, resultado si la condición es FALSA)
En este ejemplo
ifelse(valor en la fila de la columna peso_kg es < 0, reemplaza el valor negativo con NA, de lo contrario, mantén su valor original)
Este es el ejemplo, escrito dentro de un mutate()
que podría añadirse
al comando de limpieza:
# actualiza peso_kg para reemplazar valores negativos con NA, de lo contrario manten el valor original mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg))
Añade esto a tu comando de limpieza y comprueba que funciona correctamente.
r fontawesome::fa("check", fill = "red")
Haz clic para ver la solución (¡pruébalo tú primero!)
vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg))
Ahora que has vuelto a ejecutar tu comando de limpieza y has actualizado
tu objeto dataframe vig
, volvamos a ejecutar el comando summary()
en el "Área de pruebas" para comprobar el nuevo intervalo de valores:
summary(vig$peso_kg)
A continuación, ofrecemos un resumen de los operadores lógicos útiles en R. No es necesario memorizarlos (consulta la sección capítulo de conceptos básicos del Manual de Epi), pero están aquí para que los revises.
Los operadores relacionales comparan valores y suelen utilizarse al definir nuevas variables y subconjuntos de conjuntos de datos.
| Significado | Operador | Ejemplo | Resultado |
|:---------------:|:---------------:|:---------------:|:-------------------:|
| Igual a | ==
| "A" == "a"
| FALSE
(because R is case sensitive) |
| No igual a | !=
| 2 != 0
| TRUE
|
| Mayor que | >
| 4 > 2
| TRUE
|
| Menor que | <
| 4 < 2
| FALSE
|
| Mayor o igual a | >=
| 6 >= 4
| TRUE
|
| Menor o igual a | <=
| 6 <= 4
| FALSE
|
| Valores vacios | is.na()
| is.na(7)
| FALSE
|
| Valores no vacios | !is.na()
| !is.na(7)
| TRUE
|
Ten en cuenta que ==
(doble igual) hace la pregunta a R: "¿El
valor de la derecha es igual al valor de la izquierda? El resultado es
TRUE
o FALSE
(Verdadero o falso).
edad == 12
pregunta es el valor de la columna edad
de una fila
determinada es igual a 12?En cambio, la =
(igual simple) se utiliza para asignar valores, como
por ejemplo para un argumento dentro de una función:
max(edad, na.rm = TRUE)
Esto establece na.rm=
argumento a TRUE
.paste(jurisdictions, collapse = ",")
Esto establece el argumento
de colapso en una coma.Los operadores lógicos, como Y y O, suelen utilizarse para conectar operadores relacionales y crear criterios más complicados. Las sentencias complejas pueden requerir paréntesis ( ) para la agrupación y el orden de aplicación.
| Significado | Operator |
|:------------------:|:--------------------------------------------------:|
| Y (AND) | &
|
| O (OR) | |
(barra vertical) |
| Parentesis | ( )
Para agrupar criterios y especificar el orden de ejecución de operaciones |
Ahora que has aprendido la recodificación lógica simple, puedes utilizar
ifelse()
para muchas situaciones. Aquí tienes otras dos funciones
sencillas de recodificación lógica que deberías marcar para leer más
adelant:
if_else()
es
especialmente útil para recodificar fechas. NOTA esta función es ligeramente diferente de la funciónifelse()
.replace()
puede ser una función alternativa a ifelse()
para recodificacióncase_when()
para la recodificación complejaPara una recodificación más compleja o avanzada, debes utilizar
case_when()
del paquete {dplyr} (parte del tidyverse). Esta función te permite ejecutar el equivalente de múltiples sentencias ifelse()
- es el equivalente de R al SQL CASE WHEN
de R -.
¡Es sólo una coincidencia que la función case_when()
tenga un nombre que parece hecho para construir definiciones de casos epidemiológicos!
Es una función general, no específica de la salud pública. La función
genérica case_when()
es la siguiente:
mutate(NUEVA_columna = case_when( RECODIFICACIÓN LÓGICA 1 ~ VALOR NUEVA_columna SI DECLARACIÓN 1 ES VERDADERA, RECODIFICACIÓN LÓGICA 2 ~ VALOR NUEVA_columna SI DECLARACIÓN 2 ES VERDADERA, RECODIFICACIÓN LÓGICA 3 ~ VALOR NUEVA_columna SI DECLARACIÓN 3 ES VERDADERA) )
Nota: los dos lados de las líneas de la declaración lógica están
separados por un ~
(tilde o virgulilla). Este símbolo puede ser difícil de encontrar en el teclado. Para algunos, se encuentra cerca de la tecla Intro. Para otros, se encuentra en la parte inferior izquierda del teclado (a la izquierda del "1" en la fila de números). Tómate un momento para identificar dónde está la ~
en tu teclado, y avisa a un instructor si no lo encuentras. (la distribución del teclado influye)
Recuerda: siempre puedes utilizar ?case_when()
para buscar la
documentación de la función.
Aquí tienes un ejemplo de case_when()
utilizado en mutate()
para
crear una columna de definición de caso:
mutate(def_caso = case_when( # crea una nueva columna def_caso lab_conferma == TRUE ~ "Confirmado", # Caso confirmado si laboratorio confirmado epilink == "si" & fiebre == "si" ~ "Sospechoso", # de lo contrario, caso sospechoso si vinculo epidemiologico y fiebre TRUE~ "A investigar")) # de lo contrario, si ninguno de las declaraciones anteriores son verdadera, asigna como "A investigar"
Examinemos lo que ocurre en el comando anterior:
Preparación
La función mutate()
debe estar conectada por un operador pipe a los comandos de limpieza anteriores
A la izquierda del símbolo igual debe de estar el nombre de la columna que queremos crear o ajustar: def_caso
A la derecha del símbilo igual debe de estar la función case_when()
que se utiliza para asignar los valores de esta nueva columna
Dentro de la estructura case_when()
case_when()
consiste en fórmulas en líneas separadas. Cada una
tiene un lado derecho (LDER) y un lado izquierdo (LIZQ), separados por
una "tilde" o "Virgulilla" \~
A la izquierda tenemos una declaración lógica que puede evaluarse
como TRUE
o FALSE
para una fila determinada de los datos
La declaración derecha es el valor que se asigna si la declaración izquierda es TRUE
para una fila dada
ATENCIÓN: Todos los valores de resultado del lado DERECHO deben ser de la misma clase: numéricos, enteros, caracteres, fechas, lógicos, etc.
Si se confirma el laboratorio de un paciente, se clasifica inmediatamente como caso "Confirmado" en nuestro nuevo def_caso
columna. Si la confirmación de laboratorio es FALSE
o falta, se
comprueba la segunda fórmula: si el caso tiene un vínculo epidemiológico Y fiebre, se clasifica como caso "Sospechoso". Por último, a cualquier paciente / fila en el que no se cumplan las condiciones primera y segunda, se le asigna el valor "A investigar".
Cómo se evalúan las declaraciones
Las declaraciones se evalúan de arriba-abajo (no todas a la vez), por lo que el orden es importante. En este ejemplo, cada fila del la base de datos se evalúa primero para la declaración lógica superior (lab_conferma == TRUE
). Si esta afirmación es verdadera (TRUE
) para esa fila, su valor en la columna def_caso
se establece como "Confirmado". Sin embargo, si lab_conferma
no es Verdadera (TRUE
) para esa fila de los datos, sólo entonces se comprueba la segunda afirmación lógica. Así, para cada fila de la base de datos, la primera sentencia lógica que se evalúa como TRUE
es utilizada.
Escribe las fórmulas en un orden intencionado: de muy específica (arriba) a muy amplia (abajo)..
Si ninguna de las afirmaciones lógicas se aplica a una fila de los
datos, se asigna el valor de esa fila NA
por defecto. Puedes ajustar
este valor "por defecto" haciendo una de las siguientes cosas:
Haz una declaración lógica final escrita simplemente como TRUE
. En nuestro escenario de definición de casos, a las filas en las que no
se cumplían los criterios lógicos 1 ó 2, se les asigna el valor "A
investigar".
Alternativamente, establece el argumento
.default = "A investigar"
. Sin embargo, esto puede resultar
confuso para los principiantes, porque utiliza la función =
en
lugar de ~
.
Ejecuta ?case_when
en la Consola para saber más sobre el argumento .default =
, si te interesa.
Ahora que hemos revisado el uso de la función case_when()
añade una nueva línea con la funciónmutate()
y dentro de este, la función case_when()
al final de tu comando de limpieza y vuelve a ejecutarlo.
Por favor, escribe el comando y no te limites a copiar/pegar.
r fontawesome::fa("check", fill = "red")
Haz clic para ver la solución
(¡pruébalo tú primero!)
vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numerica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg)) %>% # Crea la definición de caso mutate(def_caso = case_when( lab_conferma == TRUE ~ "Confirmado", epilink == "si" & fiebre == "si" ~ "Sospechoso", TRUE ~ "A investigar"))
<!--
NOTA: Fin de la solución -->
Ahora podemos hacer una tabla con la nueva columna def_caso
y ver los resultados
(escribe en la sección de "Area de Pruebas"):
tabyl(vig, def_caso)
¡También es conveniente ir a ver la base de datos o vig
para confirmar que la lógica se ha aplicado de la forma como lo has especificado!
edad_anios
Ahora aplica tus conocimientos sobre el uso de case_when()
en el siguiente escenario.
Recuerda que según la unidad_edad
, algunos valores de la columna edad
se
registran en "años", otros en "meses", y a algunos les falta este valor.
Tenemos que crear una regla para que edad_anios
contenga una edad numérica
en años.
Añade otro paso a tu comando de limpieza para crear una nueva columna
edad_anios
. Utiliza las funciones mutate()
y case_when()
para evaluar la
edad
y unidad_edad
y realizar los cálculos correspondientes.
A continuación te damos el esquema: es tu objetivo es rellenar las afirmaciones lógicas de la izquierda y los cálculos de la derecha.
# crea la variable o columna nueva edad_anios (edad en años) mutate(edad_anios = case_when( # criterio de edad en años # ajustes hacer para edad en años [if meses] ~ [calculo], # retorna: edad / 12 [if años] ~ [calculo], # retorna: edad [if si valor] ~ [calculo])) # si unidad es vacia, asume años
r fontawesome::fa("lightbulb", fill = "gold")
Haz clic para leer una
sugerencia
Dentro del paréntesis de la función case_when()
, en los lados IZQUIERDOS debes
escribir los criterios lógicos que se evaluarán para cada fila del
base de datos, y en los lados derechos debes escribir el valor
resultante que se devolverá.
El primer criterio lógico debe ser "es unidad_edad
igual a"meses"? En
código, esto se escribe unidad_edad == "meses"
(fíjate en el doble
igual, que plantea la cuestión de la equivalencia). A la derecha del simbolo \~ (virgulilla),
escribirías una ecuación que produjera el resultado correcto en la nueva
columna edad_anios
. En este caso, sería el valor en edad
dividido por
12. En código se escribiría como unidad_edad == "meses" ~ edad / 12
. No
olvides poner una coma al final, y continuar siempre en la línea
siguiente con el siguiente criterio lógico.
Si te encuentras con este error
'names' attribute [1] must be the same length as the vector [0]
,
confirma que has convertido el edad
columna a Clase numérica
anteriormente en el comando de limpieza. Este error se debe a que, al
dividir por 12, estamos introduciendo decimales, lo que no es aceptable
si la columna sigue siendo de clase "entero" (integer).
r fontawesome::fa("check", fill = "red")
Haz clic para ver una solución
(¡pruébalo tú primero!)
vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg)) %>% # Crea la definición de caso mutate(def_caso = case_when( lab_conferma == TRUE ~ "Confirmado", epilink == "si" & fiebre == "si" ~ "Sospechoso", TRUE ~ "A investigar")) %>% # crea edad-en-años mutate(edad_anios = case_when( unidad_edad == "meses" ~ edad/12, # si la edad es dada en meses unidad_edad == "anios" ~ edad, # si la edad es dada en años is.na(unidad_edad) ~ edad)) # si unidad_edad está en blanco,asume edad en años, de lo contrario,será NA
¡Qué difícil! Si el ejercicio anterior con case_when()
te ha resultado
muy difícil, ¡no te desesperes! Lo conseguirás con la práctica. Habla con
un instructor sobre los errores que pudiste haber encontrado.
Ahora que tenemos una edad_anios
en la que todas las edades se
registran en años, vamos a crear una columna nominal o categórica de grupos
de edades.
Hay varias formas de hacerlo (ver este capítulo del Manual de Epi R para más detalles), pero aquí te mostramos el método más sencillo.
La función age_categories()
de {epikit} puede utilizarse dentro de
mutate()
para definir una nueva columna edad_cat
con categorías de
edad de 10 años.
Los argumentos para age_categories
son:
1) La columna numérica con los valores de edad que hay que dividir en
categorías (edad_anios
)
2) lower =
Un número que es el límite numérico inferior (a menudo
utilizamos 0
)
3) upper =
Un número que es el límite numérico superior para las
categorías (por ejemplo, ponlo a 70, para que todas las edades por
encima de 70 se incluyan en la categoría "70+")
4) by =
Un número para los intervalos de las categorías (a menudo
utilizamos 10, de modo que, por ejemplo, la categoría más joven
sería "0-9")
Añade esta línea al final de tu comando de limpieza.
```{=html}
<details> <summary style="text-decoration: underline; color: red;"> `r fontawesome::fa("check", fill = "red")`Haz clic para ver la solución (¡pruébalo tú primero!) </summary> </br> ```r vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg)) %>% # Crea la definición de caso mutate(def_caso = case_when( lab_conferma == TRUE ~ "Confirmado", epilink == "si" & fiebre == "si" ~ "Sospechoso", TRUE ~ "A investigar")) %>% # crea edad-en-años mutate(edad_anios = case_when( unidad_edad == "meses" ~ edad/12, # si la edad es dada en meses unidad_edad == "anios" ~ edad, # si la edad es dada en años is.na(unidad_edad) ~ edad)) %>% # si unidad_edad está en blanco,asume edad en años, de lo contrario,será NA # crea la columna de categoría de edades mutate(edad_cat = age_categories( # crea una nueva columna edad_anios, # columna numérica para hacer grupos lower = 0, upper = 70, by = 10))
También puedes definir las categorías de edad de otras formas. Por
ejemplo, puedes proporcionar una vector con valores de los intervalos de edad como
c(0, 5, 10, 15, 20, 30, 40, 50)
a el argumento breaks =
. Pregunta a
un instructor si quieres saber cómo hacerlo, o lee la documentación de
la función introduciendo ?age_categories
en la consola de R.
Otras funciones que realizan tareas similares, pero con menos facilidad,
son cut()
de {base} R. Consulta el capítulo sobre limpieza de datos
del Manual Epi R.
¿Has guardado tu
guión últimamente?r fontawesome::fa("exclamation", fill = "red")
Ahora que las dos columnas de fecha están correctamente clasificadas como clase "Fecha" (date), podemos hacer operaciones matemáticas sobre ellas con operadores de suma (+) y de resta (-).
Añade otro paso a tu comando de limpieza utilizando mutate()
para
crear una nueva columna llamada difer
. Define esta nueva columna para
que sea igual al número de días transcurridos entre fecha_sintomas
y
fecha_notifica
para cada caso.
r fontawesome::fa("lightbulb", fill = "gold")
Haz clic para leer una
sugerencia
Dentro de la función mutate
, pon el nombre de la nueva columna difer
y luego un
signo igual, después utiliza la resta ( - ) para hallar la diferencia
entre las dos fechas, en días.
r fontawesome::fa("check", fill = "red")
Haz clic para ver una solución
(¡pruébalo tú primero!)
vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg)) %>% # Crea la definición de caso mutate(def_caso = case_when( lab_conferma == TRUE ~ "Confirmado", epilink == "si" & fiebre == "si" ~ "Sospechoso", TRUE ~ "A investigar")) %>% # crea edad-en-años mutate(edad_anios = case_when( unidad_edad == "meses" ~ edad/12, # si la edad es dada en meses unidad_edad == "anios" ~ edad, # si la edad es dada en años is.na(unidad_edad) ~ edad)) %>% # si unidad_edad está en blanco,asume edad en años, de lo contrario,será NA # crea la columna de categoría de edades mutate(edad_cat = age_categories( # crea una nueva columna edad_anios, # columna numérica para hacer grupos lower = 0, upper = 70, by = 10)) %>% # crea una columna para calcular la diferencia en días entre fecha de reporte y fecha de inicio de sintomas mutate(difer = fecha_notifica - fecha_sintomas)
Abre el objeto dataframe vig
y revisa algunas filas
manualmente. Observa la diferencia entre fecha_notifica
y fecha_sintomas
en comparación con el valor de la nueva difer
columna. ¿Es como
esperabas?
En la columnadifer
los valores aparecen como "4 days" (días) - se trata de una clase
especial llamada "difftime" - . Si quieres que el resultado sea puramente
numérico, puedes envolver el resultado del cálculo con función as.numeric()
de {base}.
.
NO LO HAGAS AHORA pero sólo como referencia, añadiendo
as.numeric()
al comando anterior quedaría así
mutate(difer = as.numeric(fecha_notifica - fecha_sintomas))
Actualmente, un caso con fecha_sintomas
y fecha_notifica
del 9 de noviembre
de 2014 está registrado con difer
de 0 días. No cambies esto, pero ten
en cuenta que en tu contexto de trabajo, puedes optar por añadir un
+ 1
para que el ingreso en el mismo día se registre con un valor de
1
.
Tenemos dos columnas que expresan el distrito / ubicación de los casos -
distrito_res
es el distrito de residencia, y distrito_not
es el
lugar donde se detectaron-.
¿En qué se parecen estas dos columnas?
Una forma de evaluar la similitud de las columnas es crear una nueva columna que indique si los valores de las dos columnas de una fila determinada son diferentes. Luego, puedes resumir en una tabla esta nueva columna.
En realidad, la sintaxis es bastante sencilla utilizando mutate()
y el operador !=
(que significa NO ES IGUAL A).
Añade un nuevo paso al comando de limpieza que compare las dos columnas de distrito, y vuelve a ejecutar tu comando de limpieza.
# Nueva columna para evaluar si hay diferencias entre dos columnas (si son diferentes, será TRUE o verdadera) mutate(translado = distrito_res != distrito_not)
Ahora evalúa el cambio - abre el vig
-. Haz clic
en el botón de filtro de la parte superior izquierda para limitar la
vista a las filas en las que está la nueva columna translado
sea
VERDADERA. ¿Se ha aplicado correctamente la lógica de la nueva columna?
¿Aparecen VERDADERO y FALSO donde deberían?
quiz(caption = "Cuestionario - Casos que emigran", question_numeric( "¿Cuantos casos viven en un distrito y son diagnosticado en otro distrito?", answer(vig_bruta %>% distinct() %>% mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% mutate(translado = adm3_nombre_res != adm3_nombre_not) %>% filter(translado) %>% nrow(), correct = T), allow_retry = TRUE, correct = "Correcto, buen trabajo.", min = 1, max = 700, step = 1 ) )
También puedes utilizar código R para encontrar la respuesta, utilizando
la función tabyl()
en la nueva columna. Pruébalo en la sección "Área
de pruebas" de tu script.
tabyl(vig, translado)
coalesce()
Ahora que sabes que existen discrepancias, ¿cuál de estos valores debe priorizarse? ¿Distrito de residencia o distrito de detección?
Ésta es una pregunta que el equipo de epidemiología del brote debe responder dado su conocimiento del proceso de recogida de datos, y del propio brote. Para este ejercicio, daremos prioridad al lugar de detección porque puede reflejar mejor las poblaciones cercanas con mayor riesgo de infección (lo que puede interpretarse mejor mediante una buena investigación de los casos).
Crea una nueva columna en los datos llamada simplemente distrito
.
En mutate()
utiliza la función coalesce()
que tomará el primer valor
si está disponible; en caso contrario, tomará el segundo valor. Esta
función nos permite "rellenar" los valores que faltan utilizando el
primer valor disponible (dado un orden de preferencia), o dar prioridad
En mutate()
utiliza el botón coalesce()
que tomará el primer valor
si está disponible; en caso contrario, tomará el segundo valor. Esta
función nos permite "rellenar" los valores que faltan utilizando el
primer valor no faltante (dado un orden de preferencia), o dar prioridad
a un valor sobre otro si difieren.
Añade el siguiente paso a tu comando de limpieza y vuelve a
ejecutarlo. Asegúrate de volver a ejecutar tu comando de limpieza para
que tu vig
se actualice con un distrito
columna adicional.
# Añade el siguiente comando a tu cadena de limpieza mutate(distrito = coalesce(distrito_not, distrito_res))
```{=html}
<details> <summary style="text-decoration: underline; color: red;"> `r fontawesome::fa("check", fill = "red")`Haz clic para ver la solución (¡pruébalo tú primero!) </summary> </br> ```r vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg)) %>% # Crea la definición de caso mutate(def_caso = case_when( lab_conferma == TRUE ~ "Confirmado", epilink == "si" & fiebre == "si" ~ "Sospechoso", TRUE ~ "A investigar")) %>% # crea edad-en-años mutate(edad_anios = case_when( unidad_edad == "meses" ~ edad/12, # si la edad es dada en meses unidad_edad == "anios" ~ edad, # si la edad es dada en años is.na(unidad_edad) ~ edad)) %>% # si unidad_edad está en blanco,asume edad en años, de lo contrario,será NA # crea la columna de categoría de edades mutate(edad_cat = age_categories( # crea una nueva columna edad_anios, # columna numérica para hacer grupos lower = 0, upper = 70, by = 10)) %>% # crea una columna para calcular la diferencia en días entre fecha de reporte y fecha de inicio de síntomas mutate(difer = fecha_notifica - fecha_sintomas) %>% # nueva columna para evaluar si hay diferencias entre dos columnas (si son diferentes, será TRUE o verdadera) mutate(translado = distrito_res != distrito_not) %>% # nueva columna que prioriza distrito de detección de caso mutate(distrito = coalesce(distrito_not, distrito_res))
Visualiza de nuevo la base de datos y comprueba con la vista que este código ha funcionado como se esperaba
Añade el siguiente comando a tu "Sección del área de pruebas" y responde a la pregunta del cuestionario que aparece a continuación.
# tabla cruzada entre la columna "translado" con la columna "distrito_res" (emigró vs distrito de residencia) tabyl(vig, translado, distrito_res)
quiz(caption = "Cuestionario - Origen de los casos que emigran", question_numeric( "De los casos donde el distrito de residencia es diferente al distrito de detección ¿Cúantos residian en el distrito 'Mountain Rural'?", answer(vig_bruta %>% distinct() %>% mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% mutate(translado = adm3_nombre_res != adm3_nombre_not) %>% filter(translado & adm3_nombre_res == "Mountain Rural") %>% nrow(), correct = T), allow_retry = TRUE, correct = "Correcto, buen trabajo.", min = 1, max = 700, step = 1 ) )
¿Has guardado tu
script últimamente? r fontawesome::fa("exclamation", fill = "red")
El subconjunto de filas se realiza con la función filter()
. ¡Esta
función es muy útil! Dentro del paréntesis de la función filter()
escribes criterios lógicos que se aplican a cada fila. Las filas que
cumplan los criterios se conservan.
Vuelve a repasar brevemente los operadores relacionales y lógicos de R. Puedes encontrarlos siempre en el Manual de Epi R Página de conceptos básicos.
+--------------------------+------------+--------------+------------------------------------------+
| Significado | Operador | Ejemplo | Resulado |
+==========================+============+==============+==========================================+
| igual a | ==
| "A" == "a"
| FALSE
R distingue el tipo de letra |
+--------------------------+------------+--------------+------------------------------------------+
| No igual a | !=
| 2 != 0
| TRUE
|
+--------------------------+------------+--------------+------------------------------------------+
| Mayor que | >
| 4 > 2
| TRUE
|
+--------------------------+------------+--------------+------------------------------------------+
| Menor que | <
| 4 < 2
| FALSE
|
+--------------------------+------------+--------------+------------------------------------------+
| Mayor o igual que | >=
| 6 >= 4
| TRUE
|
+--------------------------+------------+--------------+------------------------------------------+
| Menor o igual que | <=
| 6 <= 4
| FALSE
|
+--------------------------+------------+--------------+------------------------------------------+
| El valor es "vacio" | is.na()
| is.na(7)
| FALSE
|
+--------------------------+------------+--------------+------------------------------------------+
| El valos no es vacio | !is.na()
| !is.na(7)
| TRUE
|
+--------------------------+------------+--------------+------------------------------------------+
Los operadores lógicos, como Y y O, suelen utilizarse para conectar operadores relacionales y crear criterios más complicados. Las sentencias complejas pueden requerir paréntesis ( ) para la agrupación y el orden de aplicación.
+---------------------+-----------------------------------------------------------------------------+
| Significado | Operator |
+=====================+=============================================================================+
| Y (AND) | &
|
+---------------------+-----------------------------------------------------------------------------+
| O (OR) | |
(barra vertical) |
+---------------------+-----------------------------------------------------------------------------+
| Parentesis | ( )
Usado para agrupar criterios y clarificar el orden de las operaciones |
+---------------------+-----------------------------------------------------------------------------+
Ten en cuenta que ==
(doble igual) hace la pregunta a R: "¿El
valor de la derecha es igual al valor de la izquierda? El resultado es
TRUE
o FALSE
.
edad == 12
"pregunta" el valor de la columna edad
de una fila dada es
igual a 12?Por el contrario, el símbolo =
(igual simple) se utiliza para asignar valores,
edad == 12
pregunta es el valor de la columna edad
de una fila dada es
igual a 12?Por el contrario, la =
(igual simple) se utiliza para asignar valores,
como por ejemplo para un argumento dentro de una función:
max(edad, na.rm = TRUE)
Esto establece na.rm=
argumento a TRUE
paste(jurisdictions, collapse = ",")
Esto establece el argumento
de colapso en una coma%in%
El operador %in%
es un operador muy útil para emparejar valores y
para evaluar rápidamente si un valor está dentro de un vector o una base de datos.
Por ejemplo, en un vector simple, podemos evaluar
utilizando %in%
si un valor (a la izquierda) está en el vector (a la
derecha). Mira el ejemplo siguiente:
#Creamos un vector nuevo mis_paises <- c("Estados Unidos", "Vietnam", "Mongolia", "Peru")
"Peru" %in% mis_paises "Tanzania" %in% mis_paises
Para preguntar si un valor está no es %in%
un vector, pon un signo
de exclamación (!) delante de la declaración lógica:
# para negar, pon un símbolo de exclamación al principio del comando !"Peru" %in% mis_paises !"Tanzania" %in% mis_paises
Esto también funciona con columnas, porque las columnas son "vectores".
A efectos de este ejercicio, sólo mantendremos en los datos los casos "Confirmados" y "Sospechosos", y excluiremos las filas "A investigar".
La forma más sencilla de utilizar filter()
es aplicar una condición
lógica (por ejemplo ==
, !=
, >
, <
) de modo que sólo las filas en
las que la afirmación lógica sea TRUE
se conservan.
Por ejemplo, sólo (NO añadas esto a tu código), esto es un
filter()
que mantiene sólo las filas en las que el sexo es igual a
"mujer":
filter(sexo == "mujer")
En %in%
puede utilizarse para comprobar si una fila contiene uno de
los valores incluidos en un vector de valores.
NO LO AÑADAS A TU COMANDO
filter(sexo %in% c("hombre", "mujer"))
Ahora, añade otro paso a tu comando de limpieza utilizando filter()
,
%in%
y c()
para conservar sólo las filas en las que def_caso
sea
"Confirmado" o "Sospechoso".
A continuación, vuelve a ejecutar tucomando de limpieza para ver los cambios.
```{=html}
<details> <summary style="text-decoration: underline; color: red;"> `r fontawesome::fa("check", fill = "red")`Haz clic para ver una solución (¡pruébalo tú primero!) </summary> </br> ```r vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg)) %>% # Crea la definición de caso mutate(def_caso = case_when( lab_conferma == TRUE ~ "Confirmado", epilink == "si" & fiebre == "si" ~ "Sospechoso", TRUE ~ "A investigar")) %>% # crea edad-en-años mutate(edad_anios = case_when( unidad_edad == "meses" ~ edad/12, # si la edad es dada en meses unidad_edad == "anios" ~ edad, # si la edad es dada en años is.na(unidad_edad) ~ edad)) %>% # si unidad_edad está en blanco,asume edad en años, de lo contrario,será NA # crea la columna de categoría de edades mutate(edad_cat = age_categories( # crea una nueva columna edad_anios, # columna numérica para hacer grupos lower = 0, upper = 70, by = 10)) %>% # crea una columna para calcular la diferencia en días entre fecha de reporte y fecha de inicio de síntomas mutate(difer = fecha_notifica - fecha_sintomas) %>% # nueva columna para evaluar si hay diferencias entre dos columnas (si son diferentes, será TRUE o verdadera) mutate(translado = distrito_res != distrito_not) %>% # nueva columna que prioriza distrito de detección de caso mutate(distrito = coalesce(distrito_not, distrito_res)) %>% # Remueve casos "a investigar" filter(def_caso %in% c("Confirmado", "Sospechoso"))
r fontawesome::fa("exclamation", fill = "red")
Es importante tener en cuenta que filter(def_caso %in% c("Confirmado", "Sospechoso"))
¡Eliminará las filas en las que def_caso
sean vacios (NA
)!.
Del mismo modo, el filtrado basado en un criterio numérico o de fecha también puede eliminar las filas a las que les falten esos valores. Por ejemplo:
filter(edad > 12)
mantendrá sólo las filas en las que edad
sea
mayor que 12. Se eliminarán las filas en las que falte la edad.filter(fecha_sintomas > ymd("2014-11-25")
conservará sólo las filas en
las que fecha_sintomas
sea posterior al 25 de noviembre de 2014. Se
eliminarán las filas en las que falte la fecha de inicio.Para conservar las filas con valores omitidos, añade una barra vertical (operador O u "OR") y
luego la función is.na()
al filtro:
filter(edad > 12 | is.na(edad))
filter(fecha_sintomas > ymd("2014-11-25") | is.na(fecha_sintomas))
Los comandos anteriores permiten mantener las filas que cumplen el primer criterio, O que tienen valores que faltan.
Ahora, revisa tu comando de limpieza y el script de solución anterior. Asegúrate de que todos los pasos de limpieza de la solución también están presentes en tu script R "ebola_analysis.R".
Haz clic en tu base de datos vig
en el panel Entorno para revisar el
orden de las columnas.
quiz(caption = "Cuestionario - Re-organiza las columnas", question("Las nuevas columnas que has creado ¿Dónde se encuentran en el dataframe?", allow_retry = TRUE, answer("En el lado más a la izquierda de la base de datos"), answer("En el lado más a la derecha de la base de datos", correct = TRUE), answer("En el medio de la base de datos") ) )
Puede que prefiramos guardar o exportar la base de datos con algunas
columnas colocadas unas junto a otras, por ejemplo edad
y edad_anios
.
Si recuerdas la demostración de limpieza de datos de select()
puedes
utilizar la función select()
para reorganizar columnas, así como
para seleccionar determinadas columnas.
Por ejemplo, puedes listar algunas columnas para re-posicionarlas al principio,
y terminar el select()
utilizando la función de ayuda tidyselect
everything()
que incluye todas las demás columnas. Tienes a tu
disposición otros ayudantes "tidyselect" como contains()
y
starts_with()
con los que puedes escribir dentro de la página
select()
comando. Lee más sobre estos ayudantes en [capítulo del
Epi](https://epirhandbook.com/en/cleaning-datos-and-core-functions.html#clean_tidyselect).
He aquí un ejemplo (haz NO añadas este ejemplo a tu comando de limpieza):
select(id_caso, contains("fecha"), everything())
Añade un select()
al final de tu comando de limpieza que reorganice
las columnas en el siguiente orden:
id_caso
primero, seguida de cualquier columna que empiece por
"fecha", seguida de difer
, sexo
, edad
, unidad_edad
, edad_anios
,
edad_cat
, hospital
, distrito
, distrito_res
, distrito_not
,
translado
, todas las demás columnasr fontawesome::fa("check", fill = "red")
Haz clic para ver la solución
(¡pruébalo tú primero!)
vig <- vig_bruta %>% # automaticamente limpia los nombres de las columnas clean_names() %>% # limpia los nombres de las columnas de forma manual rename( fecha_sintomas = fecha_inicio_sintomas, fecha_notifica = fecha_de_notifica, distrito_res = adm3_nombre_res, distrito_not = adm3_nombre_not) %>% # remueve las columnas innecesarias select(-num_fila) %>% # de-duplica las filas distinct() %>% # convierte columna fecha_sintomas a tipo fecha ("Date") mutate(fecha_sintomas = mdy(fecha_sintomas)) %>% mutate(fecha_notifica = mdy(fecha_notifica)) %>% # convierte la columna aga a clase numérica mutate(edad = as.numeric(edad)) %>% # convierte "Desconocido" (Desconocido) de la columna sexo a NA mutate(sexo = na_if(sexo, "Desconocido")) %>% # de forma apropiada corrige en las columnas de tipo caracter el valor "" o en blanco a NA mutate(across(.cols = where(is.character), .fns = ~na_if(.x, ""))) %>% # re-codifica la columna hospital mutate(hospital = recode(hospital, # para referencia: Valor VIEJO = valor NUEVO "Other" = "Military Hospital", "Port" = "Port Hospital", "Port Hopital" = "Port Hospital", "St. Mark's Maternity Hospital (SMMH)" = "SMMH")) %>% # re-codifica la columna sexo mutate(sexo = recode(sexo, "m" = "hombre", "f" = "mujer")) %>% # convierte valores de peso negativos a NA mutate(peso_kg = ifelse(peso_kg < 0, NA, peso_kg)) %>% # Crea la definición de caso mutate(def_caso = case_when( lab_conferma == TRUE ~ "Confirmado", epilink == "si" & fiebre == "si" ~ "Sospechoso", TRUE ~ "A investigar")) %>% # crea edad-en-años mutate(edad_anios = case_when( unidad_edad == "meses" ~ edad/12, # si la edad es dada en meses unidad_edad == "anios" ~ edad, # si la edad es dada en años is.na(unidad_edad) ~ edad)) %>% # si unidad_edad está en blanco,asume edad en años, de lo contrario,será NA # crea la columna de categoría de edades mutate(edad_cat = age_categories( # crea una nueva columna edad_anios, # columna numérica para hacer grupos lower = 0, upper = 70, by = 10)) %>% # crea una columna para calcular la diferencia en días entre fecha de reporte y fecha de inicio de síntomas mutate(difer = fecha_notifica - fecha_sintomas) %>% # nueva columna para evaluar si hay diferencias entre dos columnas (si son diferentes, será TRUE o verdadera) mutate(translado = distrito_res != distrito_not) %>% # nueva columna que prioriza distrito de detección de caso mutate(distrito = coalesce(distrito_not, distrito_res)) %>% # Remueve casos "a investigar" filter(def_caso %in% c("Confirmado", "Sospechoso")) %>% # re-organiza el orden de las columnas select(id_caso, starts_with("fecha"), difer, sexo, edad, unidad_edad, edad_anios, edad_cat, hospital, distrito, distrito_res, distrito_not, translado, everything())
Recuerda volver a ejecutar tu comando de para que tu objeto dataframe vig
se actualice con este último paso.
Ahora que hemos limpiado esta base de datos, debemos guardarlo en el proyecto RStudio para utilizarlo más adelante, y quizás para compartirlo con otras personas.
Podemos utilizar la función export()
de la función {rio} que es el
mismo que utilizamos para import()
los datos brutos.
La exportación es un comando autónomo - no forma parte de tu comando de limpieza. Los argumentos que espera son
1) El objeto R (dataframe o base de datos) que debe exportarse
2) El nombre deseado para el archivo, entre comillas, con extensión (por ejemplo, "lista_de_vigilancia_limpia_20141201.csv")
El comando siguiente es independiente (no forma parte de tu comando de
limpieza). Esto significa que no hay ninguna base de datos conectado
a él, por lo que tienes que escribir vig
como primer argumento.
Como se escribe a continuación, vig
se guardará como un archivo CSV
en la carpeta raíz de tu proyecto RStudio.
Ejecuta el comando y comprueba que se ha guardado en la ubicación prevista.
# Exporta la base de datos limpia en un archivo en la carpeta principal del proyecto de R export(vig, "listado_vigilancia_limpio_20141201.csv")
Si guardas el archivo como .xlsx o .csv, cualquier persona que utilice R para seguir analizando los datos tendrá que volver a limpiarlo convirtiendo de nuevo las columnas a sus clases correctas.
Para evitarlo, guarda la base de datos limpio como archivo ".rds". RDS es un formato de archivo específico de R, y resulta muy útil si vas a volver a trabajar en R con los datos exportados.
Por ejemplo, si trabajas en un equipo de epidemiología y necesitas enviar archivos de datos a un equipo de SIG para la elaboración de mapas, y ellos también utilizan R, ¡sólo tienes que enviarles el archivo .rds! Así se conservan todas las clases de columnas y tienen menos trabajo de limpieza que hacer.
En el ejemplo siguiente, vig
se guarda como un archivo .rds. También especificamos que queremos que se guarde en una sub-carpeta ("datos/limpios") escribiendo la ruta del archivo mediante here()
del mismo modo que hacemos para importar los datos.
¡Prueba éste también!
# Exporta el archivo limpio export(vig, here("datos", "limpios", "listado_vigilancia_limpio_20141201.rds"))
Si quieres exportar los datos como CSV o Excel, simplemente cambia la extensión del archivo en el comando a .csv o .xlsx.
¡Felicidades! ¡Has completado el ejercicio de limpieza! Este es un gran paso en tu introducción a R. Ahora ya conoces la mayoría de las funciones importantes de gestión de datos en R.
Asegúrate de guardar tu script de R, y compruébalo con tu facilitador.
En caso de que no hayas terminado, no te preocupes. Busca en la carpeta "ebola/scripts/copia_seguridad". Encontrarás scripts de R para el análisis del ébola en cada etapa de este curso. Así que siempre puedes utilizarlos como "copia de seguridad" para módulos posteriores.*
Haz clic para ver material extra interesante...
En estas secciones, repasaremos los conceptos de "datos ordenados" y algunos escollos habituales que impiden analizar fácilmente en R los datos de las hojas de cálculo de Excel.
knitr::include_graphics("images/tidy_shelves.png")
La forma en que estructures tu base de datos influirá en gran medida en lo complicado que deba ser tu código R. Una atención anticipada durante la fase de introducción de datos te ahorrará mucho tiempo durante la limpieza y el análisis de los datos.
Reflexiona: ¿Cuáles son algunas características de tus datos que dificultan especialmente su limpieza para el análisis?
Los datos ordenados tienen un significado específico en el análisis de datos: se refieren a cómo se ha almacenado la información dentro de la estructura de la base de datos. Así que empecemos con algo de terminología.
Estructuralmente, los conjuntos de datos o base de datos (llamados "dataframe" en R) constan de celdas, columnas, filas.
Sin embargo, "valores", "variables" y "observaciones son conceptos más abstractos.
Pongamos a prueba tu comprensión de estos términos.
quiz( question("50 kg, 75 kg, 67 kg, 90 kg son...", answer("Diferentes observaciones de la variable `temperatura`", message = "¡Piensa otra vez! ¡No tiene mucho sentido que la 'temperatura' se mida en kilogramos! También es poco probable que estos valores se denominen observaciones..."), answer("Diferentes variables de la observación `peso`", message = "¡Piensa otra vez! Todos estos valores tienen la misma unidad, por lo que probablemente serían una variable en lugar de diferentes. El 'peso' como observación también podría no ser la forma más lógica de registrar estos datos..."), answer("Diferentes valores de la variable `peso`", correct = TRUE, message = "De hecho, estos son valores correctos (en este caso estamos tratando con números, es decir, datos cuantitativos). Como los diferentes valores tienen la misma unidad, se pueden agrupar bajo una misma variable (en este caso, el peso tendría sentido)."), answer("Ninguna de estas answers son correctas", message = "¿Está seguro? ¡Intenta pensar a qué se refieren estos diferentes términos!"), answer("Todas estas answers son correctas", message = "¿Está seguro? ¡Intenta pensar a qué se refieren estos diferentes términos!"), allow_retry = TRUE ), question("Lo más probable es que 'Nombre' sea...", answer("Un Valor", message = "Si esto fuera un valor, ¿Cuál sería la variable y la observación bajo las cuales se podría agrupar?"), answer("Una variable", correct = TRUE, message = "De hecho, diferentes valores podrían incluir 'Josefina', 'Alejandro' o 'Guillermo'."), answer("Una observación", message = "Si esto fuera una observación, ¿cuál es la unidad de medida? ¿Cómo obtendrías otras observaciones?"), allow_retry = TRUE ), question("Pensando en la estructura de datos, ¿Cómo se representaría mejor una observación?", answer("Como una fila", correct = TRUE, message = "¡Así es! Más sobre esto a continuación..."), answer("Como una columna", message = "¡Piensa otra vez! ¿Es esta la forma más eficiente de representar sus datos?"), answer("Como una celda", message = "¡Piensa otra vez! ¿Es esta la forma más eficiente de representar sus datos?"), allow_retry = TRUE ) )
Tus datos pueden almacenarse de muchas formas: ¿Por qué es importante que estén "ordenados"?
ggplot()
para trazar) -
los paquetes de la {tidyverse} están diseñados para trabajar con
datos ordenadosHay tres principios que hacen que una base de datos esté "ordenado":
Fuente: R para la Ciencia de Datos
Idealmente, se alinean: columnas = variables y filas = observacion
knitr::include_graphics("images/tidy_image.png")
Pero no siempre es así... sobre todo en los datos de salud pública. Seguro que has visto datos introducidos en este formato "amplio":
ejemplo_largo <- tribble( ~pais, ~Enero, ~Febrero, ~Marzo, "Mozambique", 3200, 3300, 4100, "Lesotho", 500, 750, 900, "Sudafrica", 5100, 6200, 8100,) ejemplo_largo
quiz( question("'Enero' es una columna, pero ¿es una variable?", answer("Si", message = "No, recuerda que una variable es el atributo subyacente más abstracto que se mide."), answer("No", correct = TRUE, message = "Enero es un valor de la variable 'mes'"), allow_retry = TRUE ), question("¿Dónde está la variable 'mes'?", answer("En la tercera columna", message = "No, no está en una columna."), answer("En una hoja de cálculo diferente", message = "Estas siendo tont@"), answer("Está distribuido en muchas columnas.", correct = TRUE, message = "Correcto, no tiene columna propia."), allow_retry = TRUE ), question("¿Cada observación tiene su propia fila?", answer("Si", message = "No, cada valor es una observación y hay tres en cada fila."), answer("No", correct = TRUE, message = "Correcto, hay tres observaciones en cada fila."), allow_retry = TRUE ) )
Aquí tienes los mismos datos, pero en un formato "ordenado":
ejemplo_largo_pivoted <- ejemplo_largo %>% pivot_longer(cols=2:4, names_to="mes", values_to = "casos") ejemplo_largo_pivoted
Reflexionando sobre las prácticas de los datos ordenados, ¿Qué proporción de las bases de datos que utilizas están ordenadas?
Cuando empieces a recopilar datos, debes plantearte la pregunta: ¿es el público principal de este conjunto de humanos o máquinas?
Registrar la información de forma que esté optimizada para la "legibilidad humana" puede ser muy diferente de la optimización para la "legibilidad mecánica" y el análisis. Ten claro desde el principio cuál es tu prioridad. Aquí que te demos un consejo general: ¡Es más fácil pasar de la lectura de máquina a la lectura humana que al revés!
En Applied Epi, promovemos el uso de R para muchas razones pero sabemos que para la mayoría de los epidemiólogos de campo, Excel es una herramienta fundamental para el trabajo diario. No hay nada malo en utilizar Excel. Los flujos de trabajo que implican R casi siempre también incluyen usar Excel u otro software de hojas de cálculo. Pero es importante que utilices Excel de forma que también puedas aprovechar al máximo las ventajas de R.
knitr::include_graphics("images/interoperability.png")
Excel es un programa potente y fácil de usar para principiantes. Aunque también es posible realizar algunos análisis en Excel, es probable que descubras que los análisis más sofisticados y las operaciones de gestión de datos pueden ser muy complicados o imposibles de llevar a cabo en este software. En estas situaciones es cuando programas versátiles como R resultan muy útiles.
knitr::include_graphics("images/difficulty_plot-1.png")
En este curso, te familiarizarás con la sintaxis del código R. En esta sección, nos centraremos en los pasos que puedes dar para asegurarte de que una base de datos de Excel pueda ser interpretado fácilmente por R para su análisis.
La principal razón por la que uno se encuentra con problemas al analizar datos de hojas de cálculo de Excel es cuando la hoja de cálculo se diseñó para dar prioridad a la lectura fácil por parte de humanos, no a la lectura fácil por parte de máquinas/software.
Para ayudarte a ver la diferencia, a continuación hay algunos ejemplos ficticios de hojas de cálculo que priorizan la lehumana-a la legibilidad máquina-legibilidad.
Escribe un comando para importar la hoja de cálculo
"datos_desordenados_ejemplos.xlsx" y almacenarla como objeto
partner_tracking
. La hoja de cálculo se guarda en la carpeta
"ebola/datos/brutos".
r fontawesome::fa("check", fill = "red")
Haz clic para ver una solución
(¡pruébalo tú primero!)
partner_tracking <- import(here("datos", "brutos", "ejemplos_datos_desordenados.xlsx"))
Ahora, abre la hoja de cálculo con Microsoft Excel. Si puedes
hacerlo, observa cómo en realidad hay 4 hojas en este libro de
Excel. Utilizando la función import()
¡sólo ha importado la primera
hoja!
Revisa tu comando de importación para utilizar la función sheet =
para
especificar el nombre de la hoja a importar. Escribe y ejecuta un
comando para cada una de las hojas, como se muestra a continuación:
# importa la hojas para hacer seguimiento de los contactos con código de colores contactos_tracking <- import(here("datos", "brutos", "ejemplos_datos_desordenados.xlsx"), sheet = "messy_colors") # importa la hoja sobre cobertura de los sitios con los datos desordenados sitio_cobertura <- import(here("datos", "brutos", "ejemplos_datos_desordenados.xlsx"), sheet = "messy_site_coverage") # importa la hoja con los datos en formato "tidy" sobre la cobertura de los sitios cobertura_lugares_ord <- import(here("datos", "brutos", "ejemplos_datos_desordenados.xlsx"), sheet = "tidy_site_coverage") # importa la hoja con los datos de SIG desorganizados messy_gis <- import(here("datos", "brutos", "ejemplos_datos_desordenados.xlsx"), sheet = "messy_gis")
Ahora que has importado estas cuatro hojas, vamos a revisarlas.
La hoja importada y nombrada parter_tracking
registra el estado de una
intervención de salud pública de varios socios de answer en varias
provincias, distritos y subdistritos. En la parte derecha, el estado
para fechas concretas se indica mediante el color de la celda, y hay un
pequeño diccionario por colores en la parte superior derecha de la hoja.
knitr::include_graphics("images/messydata2.PNG")
Debemos preguntarnos: ¿esta hoja está escrita para maximizar la legibilidad humana, o la legibilidad de la máquina? Un ejemplo excelente de priorizar la legibilidad humana sobre la legibilidad mecánica es el uso de la codificación por colores de las celdas de una hoja de cálculo.
En R es bastante difícil interpretar el color de cada celda de una hoja de cálculo de Excel. Si utilizas el color, no debes sólo utilizar el color, sino también hacer que los valores reflejen las diferencias entre las celdas.
Almacenar información como en esta hoja no es lee o interpreta fácilmente por R - ¡Ni por humanos con daltonismo! -
Además, se combinan distintos datos en una misma celda (varias organizaciones asociadas que trabajan en un área, o el estado "TBC" en la misma celda que "Socio D").
question("En este caso, ¿Cuál crees que sería la mejor modificación antes de cargar la base de datos en R?", answer("Mantener como está, R reconocerá los colores.", message = "Es muy difícil para R interpretar los colores."), answer("Mantener como está, pero agregar texto a los colores.", message = "Esto ayudaría ya que R no puede leer colores. Sin embargo, este formato de datos aún no se leería bien en R y el diccionario de colores a la derecha causaría problemas. "), answer("Mantener como está, pero mover el diccionario de colores a otra hoja.", message = "Mover el diccionario de colores a otra hoja sería útil y podría cargarse por separado como una búsqueda; sin embargo, R no puede leer los colores, por lo que aún tendría problemas al cargar la tabla principal."), answer("Cambiar la base de datos para que cada columna sea una variable y cada celda contenga un valor único, integrando los colores como una nueva variable.", correct = TRUE, message = "De hecho, transformar estos datos a un formato ordenado es absolutamente necesario si se va a realizar algún análisis sobre estos datos. Eliminar la necesidad de colores agregando una variable para especificar lo que representan sería el camino a seguir."), answer("Cambie la base de datos agregando una columna para especificar lo que significa el color.", message = "Si bien este es generalmente el camino a seguir para transformar una base de datos usando un diccionario de colores antes de cargarlo en R, esta base de datos contiene otros problemas que lo hacen desordenado y difícil de analizar en el formato actual."), allow_retry = TRUE )
Aunque los diccionarios basados en colores pueden ser útiles para la legibilidad humana de una base de datos, los colores nunca deben utilizarse como única forma de registrar los datos. Las máquinas no podrán interpretarlos para el análisis.
De nuevo, es importante pensar cuál es la mejor forma de representar esa variable que actualmente se representa por colores: lo más probable es que debas reestructurar tus datos y representarla en su propia columna.
Y como regla general, los diccionarios (ya sean diccionarios de colores como los que se muestran aquí o diccionarios de datos) deben mantenerse separados de la tabla principal. En Excel, la mejor práctica sería tener este diccionario en otra hoja. Al importarlo a R, puedes importarlo como una base de datos independiente.
Pero nos estamos adelantando... ¡Más adelante hablaremos de los diccionaros de variables!
La hoja que ahora se importa como site_coverage
contiene información
sobre la "cobertura" en una serie de centros en mayo y junio de 2022:
knitr::include_graphics("images/site_coverage_untidy.jpg")
Observa las celdas fusionadas. Las celdas combinadas suelen ser útiles para hacer que los datos legibles para el ser pero pueden causar problemas en el análisis mecánico.
question("¿Qué problemas crees que encontrará R al cargar esta base de datos?", answer("R no reconocerá las celdas fusionadas y eliminará el valor.", message = "De hecho, R no puede reconocer las celdas fusionadas. Sin embargo, no eliminará todos esos valores."), answer("R reconocerá la celda fusionada y también creará una celda fusionada.", message = "Los objetos dataframe en R no pueden contener celdas fusionadas."), answer("R no reconocerá la celda fusionada, por lo que solo mantendrá el valor en la primera fila y columna del área fusionada.", correct = TRUE), answer("R reconocerá las celdas fusionadas y duplicará estos valores en el área fusionada.", message = "Desafortunadamente, la mayoría de las funciones de importación en R no harán esto de forma predeterminada."), allow_retry = TRUE )
¿Cómo se importan a R las celdas fusionadas utilizando el programa
import()
función de {rio}? Haz clic en la base de datos para abrirlo
en el panel Visor. Mira la fila 8 como ejemplo.
knitr::include_graphics("images/site_coverage_imported.jpg")
Como ves, importar este base de datos a R en el formato Excel dado conlleva la pérdida de datos de múltiples formas:
Utilizando la import()
R no reconocerá el formato de las celdas
combinadas y todas las celdas, excepto la primera, se leerán como
vacías. Esto provocará la pérdida de datos y dificultará el análisis.
Una solución es utilizar un paquete diferente para importar los datos.
La página {openxlsx} R maneja los libros de Excel con más precisión que
{rio}. Su función read.xlsx()
ofrece un argumento fillMergedCells =
que puede ajustarse a TRUE
. Para esta función, el argumento para el
nombre de la hoja también es sheet =
.
sites <- openxlsx::read.xlsx(here("datos", "brutos", "ejemplos_datos_desordenados.xlsx"), sheet = "messy_site_coverage", fillMergedCells = TRUE)
El argumento fillMergedCells =
puede hacer que el valor fusionado
aparezca en todas sus celdas, pero la hoja de cálculo sigue siendo muy
difícil de analizar:
knitr::include_graphics("images/site_coverage_filled.jpg")
Aún no está claro qué columnas utilizar: harían falta muchos comandos de R para limpiar los datos y producir incluso una simple tabulación de los valores "Sí" por centro.
¿Cómo introducirías estos datos en una hoja de cálculo de forma "ordenada" y legible por máquina?
question("Si estos datos se ingresaran en un formato ordenado, ¿Cuáles serían los encabezados de las columnas?", answer("Día, Celular, Provincia, X", message = ""), answer("Fecha, Provincia, Sitio, Estado", correct=T, message= "Correcto, estas son las variables importantes, siendo el Estado Sí o No."), answer("mayo, junio"), answer("A, B, Sitio, Fecha"), allow_retry = TRUE )
Mira la hoja que has importado como objeto cobertura_lugares_ord
.
Contiene los mismos datos que site_coverage
pero en un formato
ordenado (también llamado formato "largo"). Mira cómo:
knitr::include_graphics("images/site_coverage_long.jpg")
El formato anterior no es muy fácil de leer para los humanos, pero R lo importa y lo maneja con facilidad.
Una vez en R, es relativamente fácil trabajar con la base de datos. No esperamos que entiendas el código que aparece a continuación, pero debes saber que limpia y amplía estos datos ordenados para que todas las fechas y lugares posibles estén presentes en los datos.
# importa la datos en formato "largo"(vertical) cobertura_lugares_limpio <- cobertura_lugares_ord %>% # crea una base de datos completa mutate(Date = ymd(Date)) %>% # convierte fechas a su clase apropiada en R complete( # completa todos los sitios y fechas Date = seq.Date( from = min(Date), to = max(Date), by = "day"), Site = seq(1:14), fill = list(Status = "No")) %>% # Si no esta listado en los datos, el estatus es "No" mutate(Province = as_factor(ifelse(Site %in% 1:7, "A", "B")), # Añade provincias Site = as_factor(Site))
Ahora la base de datos se ha ampliado de
r nrow(cobertura_lugares_ord)
filas a r nrow(cobertura_lugares_limpio)
filas - todas las fechas y lugares posibles - ¡Una base de datos
completa! (¡una fila por cada celda de la desordenada hoja de cálculo
Excel original!)
cobertura_lugares_limpio
Con los datos en formato "ordenado", ¡las posibilidades de transformación y análisis de los datos se abren de par en par!
Por ejemplo, podemos utilizar la función {ggplot2} paquete R de visualización de datos para crear un "gráfico de calor" que se parezca a la hoja de cálculo original de Excel.
No esperamos que entiendas o escribas este código ahora mismo. Aprenderás más sobre {ggplot2} en sesiones posteriores
# crea un gráfico de mosaico de calor ggplot(data = cobertura_lugares_limpio, mapping = aes(x = Date, y = fct_rev(Site), fill = Status, label = Status))+ geom_tile(color = "white")+ geom_text()+ scale_x_date( date_breaks = "day", labels = scales::label_date_short(), expand = c(0,0))+ scale_fill_manual( values = c( "Si" = "darkgreen", "No" = "orange"))+ theme_minimal(base_size = 16)+ labs(title = "Site coverage", y = "Site")+ facet_wrap(~Province, ncol = 1, scales = "free_y")
Si no entiendes el código anterior, no pasa nada; sólo queremos mostrarte que con unas pocas líneas de código R puedes crear una salida "similar a Excel", "legible por humanos", que es mucho más más fácil de analizar que la hoja de cálculo original.
En muchos sentidos, esta configuración es más útil que la hoja de cálculo Excel original:
A diferencia del Excel, ¡Esta base de datos R se puede analizar!
Sólo se necesitan unas pocas líneas de código para tabular Status
en
Province
:
cobertura_lugares_limpio %>% tabyl(Province, Status)
O por Date
:
cobertura_lugares_limpio %>% tabyl(Date, Status) %>% arrange(desc(No))
O los datos pueden agregarse en semanas y tabular el número de plazas sin cubrir:
cobertura_lugares_limpio %>% group_by(week_of = floor_date(Date, "week")) %>% summarise(days_coverage_needed = sum(Status == "No"))
O se pueden utilizar los datos para hacer rápidamente otros gráficos informativos:
cobertura_lugares_limpio %>% filter(Status == "Si") %>% ggplot(mapping = aes(x = fct_infreq(Site)))+ geom_bar(fill = "dodgerblue")+ coord_flip()+ theme_minimal(base_size = 16)+ labs(title = "Numero de dias 'cubiertos', por sitio", x = "Sitio", y = "Numero de dias con cobertura of days with coverage")
Examina la hoja de Excel "messy_gis", que registra información sobre dispensarios concretos, incluidas las coordenadas GPS, la organización asociada operativa y la capacidad de camas.
knitr::include_graphics("images/messydata.PNG")
quiz( question("¿Cuáles cree que pueden ser los problemas al importar esto a R? Marque todos los que sean más probables de aplicar.", answer("No creo que haya ningún problema cuando carguemos esto en R.", message = "El formato no será el mismo en R."), answer("R no podrá leer esta base de datos.", message = "R podrá leer esta base de datos, ¡sin embargo, requerirá mucha limpieza!"), answer("Los colores no aparecerán.", correct=TRUE, message = "Los colores no aparecerán, lo cual puede ser un problema si los colores representan otra variable!"), answer("Los colores aparecerán pero no está claro qué representan.", message = "Los colores no aparecerán en R."), answer("Algunas filas están vacías.", correct=TRUE, message = "Las filas adicionales vacías requerirán un paso de limpieza adicional."), answer ("Algunos valores de fila están vacíos.", correct=TRUE, message = "R puede manejar valores faltantes en diferentes celdas. El problema con esta base de datos es que algunas celdas vacías implican otro valor (el de la fila anterior).") , answer("Algunas columnas están vacías.", correct=TRUE, message = "Las columnas vacías requerirán un paso de limpieza adicional."), answer("Algunos valores de columna están vacíos.", message = "R puede manejar valores faltantes en las columnas."), answer("Espacios en los nombres de las columnas.", correct=TRUE, message = "Los nombres de las columnas se cambiarán de lo que vemos en Excel si tienen espacios y, como resultado, pueden requerir un paso de limpieza adicional!"), answer("Espacios en los valores de celda.", message = "R puede manejar espacios cuando se trata de valores de celda. Tenga en cuenta que estos valores se registrarán como una variable de caracteres (es decir, una cadena)."), answer ("Diferentes formatos de grabación en la misma columna.", message = "Si la misma columna tiene diferentes formatos de grabación, R aún podrá leerla. Sin embargo, es posible que la guarde en el formato incorrecto, lo que requerirá un paso de limpieza adicional . La grabación en diferentes formatos en la misma columna tampoco sigue los principios de datos ordenados."), allow_retry = TRUE ) )
Las filas y columnas vacías adicionales dla base de datos causarán dolores de cabeza de limpieza en R.
question("¿Cuál de las celdas vacías crees que será más problemática?", answer ("La primera fila vacía ya que R no reconocerá los nombres de las columnas", message = "R realmente reconocerá la segunda fila como la fila de encabezado en este caso. Entonces, aunque esto no es ideal, esta fila vacía no es demasiado problemática."), answer("La tercera fila vacía.", message = "La tercera fila vacía se cargará como una fila de valores `NA`. Aunque no es ideal, esto se puede eliminar con bastante facilidad."), answer("Las columnas vacías.", correct=TRUE, message = "Estos serán los más problemáticos ya que probablemente tendrás que eliminarlos manualmente en R, porque una columna 'real' (`Pacientes`) tampoco contiene valores. Esto significa que necesitarás tomar nota de cada columna. número que desea eliminar y hacerlo manualmente!"), answer("Todas las celdas vacías.", message = "Todas las celdas vacías no son necesariamente problemas, ya que a veces no hay datos disponibles para una variable en particular (que pueden ser datos en sí mismos o motivos para la exclusión del análisis)."), allow_retry=TRUE )
Los vacíos vacías de esta base de datos serán probablemente las más problemáticas de las opciones anteriores, ya que tendrás que eliminarlas manualmente en R.
Las filas vacías a partir de la fila número 4 también son un problema,
ya que en realidad implican el valor que se da en la celda anterior,
pero se registrarán como NA
valores. Esto requerirá una limpieza
adicional importante.
Por otra parte, los valores de la columna Patients
en realidad faltan.
En este caso, sería más prudente escribir "falta" o algún otro indicador
de ello en cada una de esas celdas, para indicar explícitamente que esos
datos faltan para esa variable concreta.
Echa un vistazo a cómo se importaron los datos a R como el objeto
messy_gis
.
Aquí tienes algunos enlaces a tutoriales que te ayudarán en la transición a R desde Excel:
R dispone de sólidas formas de importar libros de Excel, trabajar con los datos, exportar/guardar archivos de Excel y trabajar con los matices de las hojas de Excel. Es cierto que algunos de los formatos más estéticos de Excel pueden perderse en la traducción (por ejemplo, cursiva, texto de lado, etc.). Si tu flujo de trabajo requiere pasar documentos de un lado a otro entre R y Excel conservando el formato original de Excel, prueba paquetes como {openxlsx}.
En estas secciones hay algunos ejercicios de limpieza de datos para practicar.
¿Puedes crear una base de datos? partiendo del objeto dataframe o conjunto de datos vig
?
Crea una base de datos separado para los niños y guárdalo en la carpeta "salidas" como "niños_foco.csv"
vig
y asigna a esta nueva
base de datos el nombre ninos
infant
que diga "Infantil" si el caso tiene
menos de 1 año, y diga "No infantil" en caso contrarioid_caso
,
edad_anios
, infant
, sexo
, distrito
, hospital
y fecha_notifica
ninos
Crea una base de datos separado para los niños y guárdalo en la carpeta "salidas" como "niños_foco.csv"
vig
y asigna a este nuevo
conjunto de datos el nombre children
infant
que diga "Infantil" si el caso tiene
menos de 1 año, y diga "No infantil" en caso contrarioid_caso
,
edad_anios
, infant
, sexo
, distrito
, hospital
y fecha_notifica
children
conjunto de datos en el
carpeta raíz de tu proyecto RStudio como "children_spotlight.csv".r fontawesome::fa("check", fill = "red")
Haz clic para ver una solución
(¡pruébalo tú primero!)
# crea un objeto dataframe con los casos menores de edad children <- vig %>% filter(edad_anios < 18) %>% mutate(infant = ifelse(edad_anios < 1, "Infant", "Non-infant")) %>% select(id_caso, edad_anios, infant, sexo, distrito, hospital, fecha_notifica) # exporta export(children, "children_spotlight.csv")
¿Puedes crear estos conjuntos de datos? partiendo de los datos limpios
dla base de datos vig
?
Tu equipo de SIG necesita una base de datos para poder incluir mapas en su informe rutinario de este brote. Utilizan R, por lo que esperan un archivo .rds
¿Puedes crear estos marcos de datos? partiendo de los datos limpios
vig
marco de d?
Tu equipo de SIG necesita una base de datos para incluirlo en sus mapas rutinarios de este brote. Utilizan R, por lo que esperan un archivo .rds
bc13e7dcb5241508dfb9551dd18ea2226da9213c que contenga la
id_caso
, cualquier columna que contenga información sobre la ubicación o si el paciente se movió significativamente de su residencia antes de ser detectado.
Tienen acceso a tu proyecto RStudio y esperan que el archivo se guarde en la subcarpeta "salidas con la fecha actual de los datos al final del nombre del arch.
¿Puedes hacerles este archivo?
r fontawesome::fa("check", fill = "red")
Haz clic para ver una solución
(¡pruébalo tú primero!)
# crea una base de datos solo con la información SIG gis <- vig %>% select(id_caso, distrito, distrito_res, distrito_not, translado, lat, lon) # exporta export(gis, here("resultados", "gis_ebola_cases_20141201.rds"))
El paquete R {stringr} forma parte del paquete {tidyverse} y contiene muchas funciones diferentes para manejar palabras y "cadenas" de caracteres. Si alguna vez quieres dividir, unir o buscar dentro de un valor de caracteres, debes buscar en el paquete Capítulo Caracteres y cadenas del Manual de Epi R.
Por ejemplo, la función str_detect()
devuelve TRUE
o FALSE
dependiendo de si se encuentran determinados caracteres dentro de un
valor especificado. Los argumentos verdaderos son:
1) string =
es la columna o el texto en el que buscar
2) pattern =
este es el patrón de caracteres a buscar
Por ejemplo
str_detect(string = name, pattern = "Isha")
devolverá TRUE
si se
encuentran los caracteres "Isha" en una fila concreta de la colunm
name
str_detect(string = occupation, pattern = "nurse")
devolverá
TRUE
si se encuentran los caracteres "enfermera" en una fila
concreta de la colunm occupation
Ten en cuenta que esta función es distingue entre mayúsculas y minúsculas por defecto. Puedes ajustarlo utilizando el consejo que se encuentra en aquí en el Manual de Epi R.
Ahora, partiendo dla base de datos limpio vig
crea uno nuevo que contenga sólo los casos notificados desde el distrito cuyo nombre contenga "West". Luego expórtalo como
Ahora, partiendo dla base de datos limpio vig
crea un nuevo marco
de datos que contenga sólo los casos notificados desde el distrito cuyo
nombre contenga "Oeste". Luego expórtalo como "western_district_cases.csv" a la carpeta "resultados".
quiz(caption = "Cuestionario - Distritos del Oeste", question("Cuantos casos ocurrieron en los distritos del Oeste?", allow_retry = TRUE, answer("170"), answer(vig %>% filter(str_detect(string = distrito, pattern = "West")) %>% nrow(), correct = TRUE), answer("418") ) )
r fontawesome::fa("check", fill = "red")
Haz clic para ver una solución
(¡pruébalo tú primero!)
# Crea un dataframe solo con los casos de los distritos "West" western_district_cases <- vig %>% filter(str_detect(string = distrito, pattern = "West")) # exporta export(western_district_cases, here("resultados", "western_district_cases.csv"))
Puedes buscar varios patrones a la vez, por ejemplo "Doctor" O "Médico" O "Cirujano" utilizando la "barra OR" en tu cadena de patrones. Por ejemplo
str_detect(string = distrito, pattern = "West|North|west|north")
Más información sobre esta función y cómo hacer que no distinga entre mayúsculas y minúsculas en esta sección del Manual de Epi R.
Un diccionario de datos, también denominado a veces "claves", es una tabla independiente de tu hoja de registro principal. Este diccionario permite especificar qué significan determinadas variables, ya sean nombres de columnas, colores u otros.
Un diccionario de datos describe el significado, las unidades y el rango de valores que tiene cada columna.
Aunque estés familiarizado con una base de datos, ¡el significado de los nombres de las columnas puede no ser obvio! Es entonces cuando los diccionarios de datos resultan útiles, ya que te proporcionarán información sobre el significado del nombre de las columnas.
quiz( question("Por ejemplo, ¿qué crees que representa una columna llamada `age_cat5`?", answer("La quinta categoría de edad"), answer("La edad de los cinco gatos"), answer("La categoría de edad, categorizada por rangos de edad de 5 años", correct = T), answer("La categoría de edad, categorizada en 5 grupos"), allow_retry = TRUE ) )
Los diccionarios de datos también pueden utilizarse para especificar los valores aceptables de una variable.
Por ejemplo, podrías especificar la unidad para una variable numérica (kilogramos, libras, años, meses, etc.), o los incrementos de los grupos de edad. Esto es similar a lo que proporcionaría una celda con una lista desplegable de valores en Excel.
quiz( question("¿Cuál de estos sería útil agregar en un diccionario de datos para especificar los niveles de valor o el formato?", answer ("Fecha: AAAA-MM-DD", correct=TRUE, message = "Agregar el formato de fecha es útil ya que una fecha se puede escribir de muchas maneras diferentes (por ejemplo, años en 2 o 4 dígitos, poniendo el día/mes primero , etc.) y especificar qué formato de entrada debe tener la fecha ayudará a ahorrar tiempo a la hora de limpiar su conjunto de datos"), answer ("sexo: 'M' o 'F' u 'otro' o 'desconocido'", correct=TRUE, message = "Especificar el formato de entrada es útil ya que puede ingresar el sexo como palabras o iniciales, que pueden diferir según el idioma o los datos de entrada. Esto también puede ser útil para decidir dónde solo está registrando 'hombres' y 'hembras' o si también está registrando otros sexos."), answer("Edad: en años", correct = TRUE, message = "Especificar la unidad de un valor es importante especialmente si esa unidad no es evidente. En este caso, la edad podría registrarse en días, meses o años, por ejemplo." ), answer("Categoría de edad, '0-4' o '5-14' o '15-44', '45+' o 'desconocido'", correct=TRUE, message="Al solicitar que se categoricen los datos, es muy importante especificar las categorías que espera, ya que pueden no ser obvias y pueden diferir según la pregunta de investigación y el tipo de datos."), answer("Presencia de fiebre al ingreso: 'sí', 'no' o 'desconocido'", correct=TRUE, message = "Si espera una entrada de datos binarios, es importante especificar que así como el formato que espera. En este ejemplo, en lugar de 'sí' y 'no', el recopilador de datos podría haber pedido `1` y `0`, donde 1 = `sí` y 0 = `no`. para entradas numéricas a datos binarios, es importante especificar qué representan estos números."), allow_retry = TRUE ) )
Aquí tienes las 5 primeras filas de la base vig_bruta
que has
importado:
head(vig_bruta, 5)
Y a continuación un diccionario de datos para estos datos:
knitr::kable(datadict)
Este diccionario de datos permite comprender qué significa cada valor de columna, así como en qué unidades se registraron los valores. Esto ayuda a mantener ordenados los marcos de datos, de modo que la base de datos importado pueda ser entendido por los ordenadores, pero el epidemiólogo siga teniendo una comprensión clara de lo que representa cada columna.
Es una buena práctica crear diccionarios de datos cuando recopiles datos y crees nuevas plantillas. También te permitirán tener nombres de columnas más fáciles de utilizar para el análisis. Cuando crees tu plantilla en Excel, intenta recordar estos consejos para que tu análisis en R sea lo más sencillo posible:
_
) en los nombres de las
columnas-
), comas
(,
), signos de porcentaje (%
), o signos de moneda (por
ejemplo$
o £
). R no los leerá, o bien habrá que llamar a los
nombres de las columnas mediante signos de interrogación.Pensando en las buenas prácticas que acabas de aprender, intenta responder a las siguientes preguntas.
quiz( question("¿Cuál sería la mejor descripción para una columna llamada `Fecha`?", answer ("Fecha, AA-MM-JJ", message = "Esta descripción puede no ser explícita (¿qué ocurrencia registra esta fecha?) y el formato es inconsistente: AA se refiere a 'años' (es decir, en inglés), mientras que JJ se refiere a 'jour' (es decir, en francés)."), answer("Fecha, AA-MM-DD", message = "Esta descripción puede no ser explícita (¿qué ocurrencia registra esta fecha?)."), answer("Fecha de recolección de muestras, AAAA-MM-DD", correct = TRUE, message = "Esta descripción especifica explícitamente qué evento está registrando la fecha y el formato es claro y consistente."), answer("Fecha, AAAA.MM.DD", message = "Esta descripción puede no ser explícita (¿qué ocurrencia registra esta fecha?)."), allow_retry = TRUE ) )
Los diccionarios de datos son extremadamente útiles e importantes si los datos son registrados por varias personas o analizados por personas que no fueron las que los recopilaron. Ser lo más explícito posible en el diccionario minimiza el riesgo de malentendidos y registros inexactos. Los diccionarios de datos deben guardarse en documentos u hojas separados de tu documento Excel.
El paquete R {epikit} desarrollado conjuntamente por Applied Epi y otras organizaciones, tiene funciones específicas para importar Kobo en R.
Al registrar datos, el aspecto más importante es permanecer coherente. Esto ayudará a minimizar el tiempo que se tarda en limpiar los datos, así como a reutilizar el mismo código en nuevos datos.
Las fechas pueden registrarse en numerosos formatos. Por ejemplo:
question("¿Cuál es la forma óptima de registrar una cita?", answer("AAAA-MM-DD", message="Así es, ¡esta es una forma correcta de registrar una fecha! ¿Estás seguro de que esta es la única forma correcta?"), answer("DD/MM/AA", message="Así es, ¡esta es una forma correcta de registrar una fecha! ¿Estás seguro de que esta es la única forma correcta?"), answer("MM/DD/AAAA", message="Así es, ¡esta es una forma correcta de registrar una fecha! ¿Estás seguro de que esta es la única forma correcta?"), answer("MM.DD.YY", message="Así es, ¡esta es una forma correcta de registrar una fecha! ¿Estás seguro de que esta es la única forma correcta?"), answer("Todos ellos pueden ser correctos", correct = TRUE, message="De hecho, ¡todas las opciones anteriores pueden ser formas correctas de registrar fechas!"), answer("Ninguna de las dos es correcta", message="¿Estás seguro de esto?"), allow_retry = TRUE )
Las fechas pueden registrarse de múltiples formas, ninguna de las cuales es particularmente superior a otra. Lo más importante es recordar coherente en la forma de registrar la fecha, ya sea numéricamente o en cadenas, el tipo de separador utilizado, el orden o la cantidad de números previstos para días, meses, años u horas y minutos.
question("De las siguientes opciones, ¿Cuáles crees que son buenas formas de grabar sexo?", answer("`f`,`h`", correct = TRUE), answer("`Mujer`, `Niño`, `Hombre`, `Bebé`", message = "'Niño' y 'Bebé' no se incluirían en una variable de 'sexo'. Si se usa 'hombre', la coherencia requeriría la contraparte 'mujer' en lugar de 'mujer', pero al registrar el sexo, 'mujer' y 'hombre' ' son la forma más correcta."), answer("`mujer`, `hombre`", message = "¡Es necesaria la coherencia en el uso de mayúsculas!"), answer("`F`,`M`", correct = TRUE), answer("`0`,`1`", correct = TRUE), answer("`f`,`hombre`", message = "¡Es necesaria la coherencia en el formato de grabación! También sería mejor utilizar el término 'hombre' en lugar de 'hombre' al grabar sexo."), allow_retry = TRUE )
Al registrar los sexos, tener coherencia es clave, sea cual sea el formato utilizado.
Las letras "F" y "M" suelen entenderse bien. Ten en cuenta que esto debe ir acompañado de un diccionario de datos para que, si se utilizan otras iniciales (por ejemplo, H y F para "homme" y "femme", en francés), la persona que analice los datos sepa lo que representan.
Si se utiliza un formato numérico binario para representar el sexo, un diccionario de datos es crucial para especificar qué número se refiere a qué sexo.
Aunque no es incorrecto, en general es mejor evitar deletrear el sexo, ya que esto deja más espacio para errores tipográficos o para utilizar diferentes estilos de mayúsculas y minúsculas (que se leerán como valores diferentes en R).
Mira la columna GPS
dla base de datos siguiente:
knitr::include_graphics("images/messydata.PNG")
question("¿Cuál es el problema con esto?", answer("No creo que haya ningún problema con esto."), answer("Los datos están registrados en el formato incorrecto."), answer("Los datos se registran en múltiples formatos."), answer("Los datos se registran en el formato correcto pero en varias filas."), answer("Los datos están registrados en el formato incorrecto y en varias filas."), answer("Los datos se registran en múltiples formatos y en múltiples filas", correct = TRUE), allow_retry = TRUE )
Hay dos problemas con la forma en que se registran estos datos:
question("¿Cuál crees que es la mejor manera de remediar esto?", answer("Armonizas los formatos (elige uno) y duplicas los datos de la primera fila a la siguiente.", message = "¿Está seguro de que duplicar los datos de una fila a la siguiente es la forma más eficaz de presentar sus datos?"), answer("Armonizas los formatos (elige uno) y separas las coordenadas en dos columnas (celda fusionada).", message = "¡Recuerde que R no puede leer celdas fusionadas!"), answer("Armonizas los formatos (elige uno) y separas las coordenadas en dos columnas (`latitud` y `longitud`).",correct = TRUE), answer("El formato en las filas 16 y 17 es la forma correcta de registrar datos GPS. Convierte los otros valores a este formato y combina los valores de las dos filas en una celda.", message = "Si bien combinar los dos valores de coordenadas en una celda es correcto, no existe un formato que sea mejor que otro al registrar coordenadas GPS. Puede elegir el que crea adecuado, pero el aspecto más importante es mantener la coherencia. "), answer("El formato en las filas 16 y 17 es la forma correcta de registrar datos GPS. Elimina los valores que no se ajustan a este formato y combina los valores de las dos filas en una celda.", message = "Si bien combinar los dos valores de coordenadas en una celda es correcto, no existe un formato que sea mejor que otro al registrar coordenadas GPS. Puede elegir el que crea adecuado, pero el aspecto más importante es mantener la coherencia. No debe eliminar los valores ya que entonces estaría eliminando datos válidos."), answer("Las coordenadas están bien registradas excepto la fila 14. Elimina las filas 14 y 15 y convierte las coordenadas en dos columnas.", message = "Eliminar las filas 14 y 15 significaría deshacerse de los datos de otras variables también, por lo que no deberías hacerlo. Podrías reemplazar el valor 'pendiente' por `NA`."), allow_retry = TRUE )
Las coordenadas GPS se pueden dar en diferentes formatos:
Puedes grabar en cualquiera de estas unidades, pero la regla más importante que debes recordar al grabar la ubicación es ser coherente con el formato que utilizas.
En este tutorial, has aprendido qué son los datos ordenados y su importancia para el análisis de datos. Repasemos algunos de estos conceptos, que será importante que tengas en cuenta la próxima vez que diseñes una base de datos.
Antes de recoger tus datos, piensa en:
Una base de datos ideal será lo suficientemente exhaustivo como para permitir tu análisis sin que sea demasiado complicado rellenarlo al recoger los datos.
En este tutorial te hemos mostrado ejemplos de conjuntos de datos almacenados en Excel y analizados en R. Tanto si utilizas este formato como si no, ten en cuenta que:
Cuando crees tu plantilla de recogida de datos y cuando recojas los datos, recuerda:
Si recoges datos en varias hojas de cálculo, piensa en:
1) Si tiene sentido recogerlos en varias hojas. Por ejemplo, si cada hoja representa el registro de un lugar o mes diferente, ¿no podrías añadir en su lugar una columna para especificar a qué lugar/mes pertenece la observación?
2) Si tiene sentido tener los datos en varias hojas, pero registras variables comunes en ambas hojas, ¡mantén la coherencia en la forma de registrar los datos y en las unidades que utilizas! También debes ser coherente en las celdas en las que registras los datos, de modo que puedas automatizar la extracción de datos de las hojas de Excel en R (en lugar de seleccionar manualmente las celdas de las que extraerás los datos en cada hoja).
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.