# install.packages("readxl")
# install.packages("tidyverse")
# install.packages("janitor")Estudios epidemiológicos: Estudios transversales
Tipos de Estudios en Epidemiología
La epidemiología se enfoca en estudiar la distribución y los determinantes de las enfermedades en poblaciones humanas. Los tipos de estudios epidemiológicos son herramientas fundamentales para investigar problemas de salud, establecer asociaciones y evaluar intervenciones. Se dividen en dos categorías principales:
1. Estudios Observacionales
Descriptivos: Buscan describir la ocurrencia de enfermedades o eventos de salud en términos de tiempo, lugar y persona. Ejemplos:
Estudios transversales.
Series de casos.
Analíticos: Estudian asociaciones entre factores de riesgo y desenlaces. Ejemplos:
Estudios de cohortes.
Estudios de casos y controles.
2. Estudios Experimentales
- Intervienen de forma controlada en la exposición para evaluar su impacto en un desenlace. Ejemplo clásico: Ensayos clínicos controlados.
Principales Características
Estudios Transversales
Observan a un grupo de personas en un momento específico.
Útiles para medir prevalencias.
Limitaciones: No pueden determinar causalidad.
Estudios de Cohorte
Identifican grupos basados en su exposición a un factor de riesgo y los siguen en el tiempo para observar desenlaces.
Prospectivos: Seguimiento desde el presente hacia el futuro.
Retrospectivos: Uso de datos históricos para reconstruir la cohorte.
Estudios de Casos y Controles
Comparan un grupo con el desenlace (casos) y otro sin él (controles).
Útiles para enfermedades raras.
Limitaciones: Mayor susceptibilidad al sesgo de selección.
Ensayos Clínicos
Participantes son asignados aleatoriamente a un grupo de intervención o control.
Considerados el estándar de oro para evaluar la eficacia de intervenciones.
Aplicación en R
Ahora procederemos a desarrollar un ejemplo práctico para analizar bases de datos epidemiológicas, incluyendo la limpieza de datos y el análisis exploratorio de datos (EDA). Se usará el archivo disponible en el enlace proporcionado y el entorno de R.
Práctica:
A continuación, presento el desarrollo de una práctica para trabajar con la base de datos, incluyendo bloques de código en R para limpieza y análisis:
Introducción
En esta práctica abordaremos los siguientes pasos: 1. Descarga y lectura de un archivo Excel. 2. Limpieza de datos con errores comunes. 3. Exploración y análisis de las variables. 4. Enfoque epidemiológico basado en los datos.
Paso 1: Descarga y Lectura del Archivo Excel
Para este ejercicio, descargaremos el archivo estudio_transversal_epidemiologia_errores.xlsx y lo leeremos en R utilizando el paquete readxl.
Para esto ingresaremos al siguiente Notebook de google Colab:
Cómo usar Google Colab
Abrir el entorno:
Ve a Dataframes
Puedes cargar un archivo
.ipynbo trabajar desde un cuaderno nuevo.
Ejecutar Bloques de Código:
- Cada bloque de código tiene un botón de “play” o “run” a la izquierda. Haz clic para ejecutar y comenzar a generar y descargar las bases de datos.
Descargar Archivos:
Cuando se genere un archivo (como un Excel o CSV), se mostrará un enlace o una ventana emergente para descargarlo.
¡Listo para analizar los datos en R! 😊
Paso 1: Descarga y Lectura del Archivo Excel
Para este ejercicio, descargaremos el archivo estudio_transversal_epidemiologia_errores.xlsx y lo leeremos en R utilizando el paquete readxl.
Instalar paquetes necesarios (si no los tienes instalados)
Cargar librerías necesarias
library(readxl)
library(tidyverse)── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.1 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(janitor)
Adjuntando el paquete: 'janitor'
The following objects are masked from 'package:stats':
chisq.test, fisher.test
Definir la ruta al archivo descargado para importarlo a R
Incluido en la carpeta de trabajo lo abres directamente o puedes abrirlo usando el paquete readxl, desde Import Dataset en la ventana Environment:
Localizada en el cuadrante superior derecho de RStudio:
Una vez que damos click allí, se despliega una ventana emergente en la cual podemos localizar el archivo que deseamos cargar, pero antes tienes que seleccionar el tipo de archivo:
En la ventana emergente, abres el buscador (Browser)
localizar el archivo y das importar. En este caso no hay que seleccionar que hoja, pues solo es una sola. Pero en caso, tienes abajo la opción de ser más especifico para la importación del archivo.
#archivo <- "estudio_transversal_epidemiologia_errores.xlsx"
#Incluido en la carpeta de trabajo lo abres directamente o puedes abrirlo usando el paquete readxl, desde import Dataset en Environment:
# Leer el archivo Excel
#datos <- read_excel(archivo)
library(readxl)
estudio_transversal_epidemiologia_errores <- read_excel("C:/Users/fidel/OneDrive - UNIVERSIDAD AUTONOMA DE SINALOA/MAESTRIA BIOMEDICINA MOLECULAR/EPIDEMIO 2025/ACTIVIDADES R/Dataframes/estudio_transversal_epidemiologia_errores.xlsx")
View(estudio_transversal_epidemiologia_errores)
#Creamos un objeto con nombre más simple:
datos <- estudio_transversal_epidemiologia_errores
# Visualizar los primeros datos
head(datos)# A tibble: 6 × 13
Id EDAD sexo `Peso (kg)` `Altura en cm` IMC fumador Hipertensión
<dbl> <dbl> <chr> <dbl> <dbl> <dbl> <chr> <chr>
1 1 56 FEMENINO 66.9 179. 37.1 no sí
2 2 69 femenino 75.5 166. 36.5 sí sí
3 3 46 MASCULINO 53.8 174. 27.7 No NO
4 4 32 FEMENINO 57.8 163. 23.3 No no
5 5 60 FEMENINO 71.5 152 27 No Si
6 6 25 FEMENINO 55 175. 37.7 No NO
# ℹ 5 more variables: diabetes <chr>, `nivel Colesterol` <dbl>,
# `nivel de glucosa` <dbl>, `actividad_Física_min/semana` <dbl>,
# `Nivel Educativo` <chr>
Podemos observar que tenemos una base de datos, con nombres de columnas que contienen espacios, minúsculas, mayúsculas. Esto lo tenemos que homogénizar para que al momento de que trabajemos con cada variable. No tengamos algún error.
Otro aspecto que se puede observar:
names(datos) #con la función `names`, podemos revisar el nombre de cada una de las columnas, que representa cada variable. [1] "Id" "EDAD"
[3] "sexo" "Peso (kg)"
[5] "Altura en cm" "IMC"
[7] "fumador" "Hipertensión"
[9] "diabetes" "nivel Colesterol"
[11] "nivel de glucosa" "actividad_Física_min/semana"
[13] "Nivel Educativo"
glimpse(datos) #glimpse es como str, pero nos da un poco más de detalle, sobre todo los elementos que tiene cada variable.Rows: 120
Columns: 13
$ Id <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1…
$ EDAD <dbl> 56, 69, 46, 32, 60, 25, 78, 38, 56, 75, …
$ sexo <chr> "FEMENINO", "femenino", "MASCULINO", "FE…
$ `Peso (kg)` <dbl> 66.9, 75.5, 53.8, 57.8, 71.5, 55.0, 93.3…
$ `Altura en cm` <dbl> 178.8, 165.5, 174.2, 162.7, 152.0, 174.7…
$ IMC <dbl> 37.1, 36.5, 27.7, 23.3, 27.0, 37.7, 21.7…
$ fumador <chr> "no", "sí", "No", "No", "No", "No", "No"…
$ Hipertensión <chr> "sí", "sí", "NO", "no", "Si", "NO", "Si"…
$ diabetes <chr> "Sí", "Sí", "No", "No", "Sí", "NO", "No"…
$ `nivel Colesterol` <dbl> 235.6, 179.9, 228.5, 189.2, 189.3, 207.7…
$ `nivel de glucosa` <dbl> 99.9, 98.0, 111.8, 93.2, 110.0, 124.2, 1…
$ `actividad_Física_min/semana` <dbl> 198, 180, 23, 45, 14, 152, 221, 205, 272…
$ `Nivel Educativo` <chr> "Secundaria", "UNIVERSITARIO", "Secundar…
Para inspeccionar los elementos en cada variable de manera específica y ver cómo están nombrados (especialmente en variables categóricas), puedes usar las siguientes funciones en R:
unique() para listar valores únicos
La función unique() devuelve una lista de valores únicos presentes en una columna o variable, mientras que lapply, lo hace para varias columnas del dataframe.
# Inspeccionar valores únicos en una variable específica
unique(datos$fumador)[1] "no" "sí" "No" "SÍ"
# Aplicar a varias columnas usando lapply
lapply(datos, unique)$Id
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
[37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
[73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
[91] 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
[109] 109 110 111 112 113 114 115 116 117 118 119 120
$EDAD
[1] 56 69 46 32 60 25 78 38 75 36 40 28 41 70 53 57 20 39 19 61 47 55 77 50 29
[26] 42 66 44 76 59 45 33 79 64 68 72 74 54 24 26 35 21 31 67 43 37 52 34 23 71
[51] 51 27 48 65 62
$sexo
[1] "FEMENINO" "femenino" "MASCULINO" "Masculino"
$`Peso (kg)`
[1] 66.9 75.5 53.8 57.8 71.5 55.0 93.3 68.2 59.1 60.2 64.2 63.2 44.9 85.2 69.8
[16] 69.7 79.8 57.3 60.9 69.2 74.1 69.0 67.1 87.2 82.8 40.0 87.8 95.9 84.8 67.4
[31] 61.7 78.7 62.6 74.3 84.6 65.3 64.7 74.5 93.2 71.0 65.0 80.3 78.6 58.6 63.6
[46] 83.2 75.1 40.4 75.8 81.1 59.9 78.1 92.5 74.8 62.5 63.7 70.2 70.8 76.0 72.2
[61] 81.6 57.2 71.3 81.0 67.3 77.8 47.8 84.0 58.2 56.9 35.4 60.4 69.9 65.4 64.4
[76] 56.7 80.4 81.5 75.0 47.4 97.3 71.8 76.5 52.0 68.3 80.5 85.6 53.9 80.2 74.7
[91] 51.2 48.6 73.9 76.1 68.5 95.4 88.6 62.8 68.7 49.0 50.5 56.2 86.7 59.7 57.7
$`Altura en cm`
[1] 178.8 165.5 174.2 162.7 152.0 174.7 154.5 164.9 172.0 164.4 168.7 154.4
[13] 190.0 158.0 182.0 171.5 171.4 173.5 151.2 179.7 182.1 168.5 166.3 157.1
[25] 162.3 156.9 150.1 161.4 178.4 187.8 163.2 166.6 171.8 175.8 191.3 172.3
[37] 186.6 165.4 170.9 164.1 167.4 167.2 164.0 164.5 181.0 191.1 165.0 166.8
[49] 175.2 201.9 170.8 185.4 173.4 179.3 176.1 180.3 159.7 174.8 181.4 174.5
[61] 158.6 175.9 161.2 163.0 165.8 168.9 154.6 181.2 158.4 185.7 158.8 182.8
[73] 169.7 152.8 159.6 183.3 169.2 147.8 183.9 188.7 186.9 163.8 173.8 174.9
[85] 154.7 180.7 177.6 158.9 177.9 176.3 147.5 145.4 167.0 165.9 179.8 171.0
[97] 172.7 156.6 136.4 191.4 172.5 173.2 186.8 178.9 175.0
$IMC
[1] 37.1 36.5 27.7 23.3 27.0 37.7 21.7 29.5 23.5 31.0 37.4 23.6 38.0 31.2 26.0
[16] 33.7 28.9 26.6 23.8 25.6 27.8 24.0 27.2 30.8 34.4 35.0 36.2 34.5 33.1 27.1
[31] 28.8 20.3 29.9 27.9 35.7 39.5 30.5 25.4 19.4 38.4 38.3 23.9 33.5 20.1 22.1
[46] 23.2 24.8 39.9 26.8 34.3 38.2 39.1 19.7 20.8 25.7 32.4 23.4 24.2 26.2 24.1
[61] 28.2 19.2 24.5 27.3 31.5 24.3 21.4 38.7 27.5 37.3 30.4 22.0 35.2 39.7 34.6
[76] 26.9 36.3 30.7 19.9 19.3 18.8 33.4 30.0 38.1 31.1 34.1 34.8 23.7 22.9 24.4
[91] 23.0 19.5 19.0 29.2 28.7 36.4 25.1 36.1
$fumador
[1] "no" "sí" "No" "SÍ"
$Hipertensión
[1] "sí" "NO" "no" "Si"
$diabetes
[1] "Sí" "No" "NO" "si"
$`nivel Colesterol`
[1] 235.6 179.9 228.5 189.2 189.3 207.7 208.5 201.2 160.0 196.4 268.4 116.5
[13] 226.1 231.7 159.2 185.9 170.0 255.6 233.1 234.5 203.6 239.4 199.8 240.8
[25] 195.5 179.6 254.3 199.4 173.0 172.7 172.8 225.3 197.0 268.9 242.1 185.1
[37] 144.4 170.3 204.4 193.3 224.7 196.3 222.4 245.0 196.2 216.7 147.4 163.0
[49] 207.1 207.0 185.6 269.0 162.0 160.1 249.6 178.9 171.7 269.1 229.6 182.2
[61] 206.5 258.4 220.7 238.6 224.1 227.9 200.3 208.0 222.0 191.5 203.7 190.7
[73] 203.5 162.5 278.2 178.0 175.4 218.5 194.1 171.1 219.7 223.7 198.0 180.1
[85] 265.7 210.2 161.8 242.4 174.3 282.3 202.4 230.4 137.6 161.5 240.0 209.5
[97] 261.3 214.6 251.4 230.3 167.2 128.9 186.9 164.4 277.9 180.5 179.7 154.4
[109] 192.0 252.1 205.1
$`nivel de glucosa`
[1] 99.9 98.0 111.8 93.2 110.0 124.2 106.9 96.3 85.7 95.9 108.4 77.0
[13] 112.5 103.1 97.8 90.1 92.9 109.0 98.1 92.5 107.0 107.6 81.3 108.6
[25] 137.5 74.5 102.7 72.5 147.5 133.5 90.0 66.3 86.8 97.3 73.6 99.0
[37] 97.2 101.9 103.4 85.5 87.2 100.7 90.5 113.6 100.5 128.0 112.3 116.6
[49] 102.0 102.4 126.0 94.3 108.2 96.0 82.5 88.9 86.1 108.9 115.6 98.6
[61] 97.7 87.8 112.9 109.8 71.6 95.8 94.1 89.9 99.3 95.1 94.7 89.4
[73] 91.7 107.4 90.9 96.5 127.7 91.2 128.7 125.9 90.6 97.5 93.3 116.9
[85] 91.5 111.0 110.2 119.5 101.6 92.6 89.1 106.5 103.6 94.8 123.2 83.3
[97] 82.4 114.1 105.3 95.7 107.5 125.8 137.7 75.2 93.7 92.8 124.4 62.8
$`actividad_Física_min/semana`
[1] 198 180 23 45 14 152 221 205 272 235 227 8 165 213 116 71 63 204
[19] 208 276 273 94 31 10 216 288 101 266 178 87 40 75 159 79 85 91
[37] 147 160 201 241 1 224 232 76 115 153 102 193 89 173 121 142 105 122
[55] 261 72 222 203 263 177 83 110 250 6 207 21 2 126 296 187 13 11
[73] 86 24 242 146 54 237 172 220 118 182 287 299 81 210 149 36 58 130
[91] 34 92 206 212 158 292 3 219 19 151 49 176 95 104 249
$`Nivel Educativo`
[1] "Secundaria" "UNIVERSITARIO" "primaria"
table() para contar frecuencias
La función table() genera una tabla de frecuencias para cada valor en una columna.
# Tabla de frecuencias para una variable
table(datos$sexo)
femenino FEMENINO Masculino MASCULINO
20 31 37 32
# Aplicar a varias columnas
sapply(datos, function(col) if(is.character(col)) table(col) else NA)$Id
[1] NA
$EDAD
[1] NA
$sexo
col
femenino FEMENINO Masculino MASCULINO
20 31 37 32
$`Peso (kg)`
[1] NA
$`Altura en cm`
[1] NA
$IMC
[1] NA
$fumador
col
no No sí SÍ
8 71 28 13
$Hipertensión
col
no NO Si sí
6 65 24 25
$diabetes
col
No NO si Sí
60 11 16 33
$`nivel Colesterol`
[1] NA
$`nivel de glucosa`
[1] NA
$`actividad_Física_min/semana`
[1] NA
$`Nivel Educativo`
col
primaria Secundaria UNIVERSITARIO
23 54 43
Ya que nos hemos percatado de que la base de datos no esta limpia, vamos a proceder a limpiar los datos.
Paso 2: Limpieza de Datos
Los datos contienen errores intencionados, como espacios en los nombres de las columnas, mayúsculas y valores inconsistentes en las variables categóricas. Los limpiaremos usando janitor y funciones de dplyr.
# Limpiar nombres de columnas
datos <- datos %>% clean_names()
names(datos) [1] "id" "edad"
[3] "sexo" "peso_kg"
[5] "altura_en_cm" "imc"
[7] "fumador" "hipertension"
[9] "diabetes" "nivel_colesterol"
[11] "nivel_de_glucosa" "actividad_fisica_min_semana"
[13] "nivel_educativo"
clean_names es una función de janitor, que automaticamente nos limpia los nombres de cada columna si agregamos () y dejamos espacio vacío, pero si agregamos dentro del parentesis la variable especifica. Solamente nos hace el cambio para la variable que se ha especificado.
Estas herramientas permiten identificar:
Errores comunes: Valores con mayúsculas/minúsculas inconsistentes, espacios adicionales o mal escritos.
Inconsistencias: Duplicados conceptuales (por ejemplo,
"Sí"vs."sí").Distribuciones: Frecuencia de cada categoría.
Como pudimos ver al momento de hacer la exploración hay inconsistencias sobre todo en las variables que contienen elementos categoricos. Por ejemplo tenemos duplicados conceptuales. Identificamos esto y homogenizamos los elementos.
# Identificaremos con la siguiente función sapply y Aplicar a varias columnas
sapply(datos, function(col) if(is.character(col)) table(col) else NA)$id
[1] NA
$edad
[1] NA
$sexo
col
femenino FEMENINO Masculino MASCULINO
20 31 37 32
$peso_kg
[1] NA
$altura_en_cm
[1] NA
$imc
[1] NA
$fumador
col
no No sí SÍ
8 71 28 13
$hipertension
col
no NO Si sí
6 65 24 25
$diabetes
col
No NO si Sí
60 11 16 33
$nivel_colesterol
[1] NA
$nivel_de_glucosa
[1] NA
$actividad_fisica_min_semana
[1] NA
$nivel_educativo
col
primaria Secundaria UNIVERSITARIO
23 54 43
Y las trasnformaremos usando la función mutate:
# Transformar variables categóricas para uniformar valores
datos <- datos %>%
mutate(
sexo = str_to_title(trimws(sexo)), # Convertir a mayúscula inicial
fumador = str_to_lower(trimws(fumador)), # Convertir a minúsculas
hipertension = str_to_lower(trimws(hipertension)),
diabetes = str_to_lower(trimws(diabetes)),
nivel_educativo = str_to_title(trimws(nivel_educativo))
)
# Visualizar los datos limpios
head(datos)# A tibble: 6 × 13
id edad sexo peso_kg altura_en_cm imc fumador hipertension diabetes
<dbl> <dbl> <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr>
1 1 56 Femenino 66.9 179. 37.1 no sí sí
2 2 69 Femenino 75.5 166. 36.5 sí sí sí
3 3 46 Masculino 53.8 174. 27.7 no no no
4 4 32 Femenino 57.8 163. 23.3 no no no
5 5 60 Femenino 71.5 152 27 no si sí
6 6 25 Femenino 55 175. 37.7 no no no
# ℹ 4 more variables: nivel_colesterol <dbl>, nivel_de_glucosa <dbl>,
# actividad_fisica_min_semana <dbl>, nivel_educativo <chr>
lapply(datos, unique)$id
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
[37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
[73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
[91] 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
[109] 109 110 111 112 113 114 115 116 117 118 119 120
$edad
[1] 56 69 46 32 60 25 78 38 75 36 40 28 41 70 53 57 20 39 19 61 47 55 77 50 29
[26] 42 66 44 76 59 45 33 79 64 68 72 74 54 24 26 35 21 31 67 43 37 52 34 23 71
[51] 51 27 48 65 62
$sexo
[1] "Femenino" "Masculino"
$peso_kg
[1] 66.9 75.5 53.8 57.8 71.5 55.0 93.3 68.2 59.1 60.2 64.2 63.2 44.9 85.2 69.8
[16] 69.7 79.8 57.3 60.9 69.2 74.1 69.0 67.1 87.2 82.8 40.0 87.8 95.9 84.8 67.4
[31] 61.7 78.7 62.6 74.3 84.6 65.3 64.7 74.5 93.2 71.0 65.0 80.3 78.6 58.6 63.6
[46] 83.2 75.1 40.4 75.8 81.1 59.9 78.1 92.5 74.8 62.5 63.7 70.2 70.8 76.0 72.2
[61] 81.6 57.2 71.3 81.0 67.3 77.8 47.8 84.0 58.2 56.9 35.4 60.4 69.9 65.4 64.4
[76] 56.7 80.4 81.5 75.0 47.4 97.3 71.8 76.5 52.0 68.3 80.5 85.6 53.9 80.2 74.7
[91] 51.2 48.6 73.9 76.1 68.5 95.4 88.6 62.8 68.7 49.0 50.5 56.2 86.7 59.7 57.7
$altura_en_cm
[1] 178.8 165.5 174.2 162.7 152.0 174.7 154.5 164.9 172.0 164.4 168.7 154.4
[13] 190.0 158.0 182.0 171.5 171.4 173.5 151.2 179.7 182.1 168.5 166.3 157.1
[25] 162.3 156.9 150.1 161.4 178.4 187.8 163.2 166.6 171.8 175.8 191.3 172.3
[37] 186.6 165.4 170.9 164.1 167.4 167.2 164.0 164.5 181.0 191.1 165.0 166.8
[49] 175.2 201.9 170.8 185.4 173.4 179.3 176.1 180.3 159.7 174.8 181.4 174.5
[61] 158.6 175.9 161.2 163.0 165.8 168.9 154.6 181.2 158.4 185.7 158.8 182.8
[73] 169.7 152.8 159.6 183.3 169.2 147.8 183.9 188.7 186.9 163.8 173.8 174.9
[85] 154.7 180.7 177.6 158.9 177.9 176.3 147.5 145.4 167.0 165.9 179.8 171.0
[97] 172.7 156.6 136.4 191.4 172.5 173.2 186.8 178.9 175.0
$imc
[1] 37.1 36.5 27.7 23.3 27.0 37.7 21.7 29.5 23.5 31.0 37.4 23.6 38.0 31.2 26.0
[16] 33.7 28.9 26.6 23.8 25.6 27.8 24.0 27.2 30.8 34.4 35.0 36.2 34.5 33.1 27.1
[31] 28.8 20.3 29.9 27.9 35.7 39.5 30.5 25.4 19.4 38.4 38.3 23.9 33.5 20.1 22.1
[46] 23.2 24.8 39.9 26.8 34.3 38.2 39.1 19.7 20.8 25.7 32.4 23.4 24.2 26.2 24.1
[61] 28.2 19.2 24.5 27.3 31.5 24.3 21.4 38.7 27.5 37.3 30.4 22.0 35.2 39.7 34.6
[76] 26.9 36.3 30.7 19.9 19.3 18.8 33.4 30.0 38.1 31.1 34.1 34.8 23.7 22.9 24.4
[91] 23.0 19.5 19.0 29.2 28.7 36.4 25.1 36.1
$fumador
[1] "no" "sí"
$hipertension
[1] "sí" "no" "si"
$diabetes
[1] "sí" "no" "si"
$nivel_colesterol
[1] 235.6 179.9 228.5 189.2 189.3 207.7 208.5 201.2 160.0 196.4 268.4 116.5
[13] 226.1 231.7 159.2 185.9 170.0 255.6 233.1 234.5 203.6 239.4 199.8 240.8
[25] 195.5 179.6 254.3 199.4 173.0 172.7 172.8 225.3 197.0 268.9 242.1 185.1
[37] 144.4 170.3 204.4 193.3 224.7 196.3 222.4 245.0 196.2 216.7 147.4 163.0
[49] 207.1 207.0 185.6 269.0 162.0 160.1 249.6 178.9 171.7 269.1 229.6 182.2
[61] 206.5 258.4 220.7 238.6 224.1 227.9 200.3 208.0 222.0 191.5 203.7 190.7
[73] 203.5 162.5 278.2 178.0 175.4 218.5 194.1 171.1 219.7 223.7 198.0 180.1
[85] 265.7 210.2 161.8 242.4 174.3 282.3 202.4 230.4 137.6 161.5 240.0 209.5
[97] 261.3 214.6 251.4 230.3 167.2 128.9 186.9 164.4 277.9 180.5 179.7 154.4
[109] 192.0 252.1 205.1
$nivel_de_glucosa
[1] 99.9 98.0 111.8 93.2 110.0 124.2 106.9 96.3 85.7 95.9 108.4 77.0
[13] 112.5 103.1 97.8 90.1 92.9 109.0 98.1 92.5 107.0 107.6 81.3 108.6
[25] 137.5 74.5 102.7 72.5 147.5 133.5 90.0 66.3 86.8 97.3 73.6 99.0
[37] 97.2 101.9 103.4 85.5 87.2 100.7 90.5 113.6 100.5 128.0 112.3 116.6
[49] 102.0 102.4 126.0 94.3 108.2 96.0 82.5 88.9 86.1 108.9 115.6 98.6
[61] 97.7 87.8 112.9 109.8 71.6 95.8 94.1 89.9 99.3 95.1 94.7 89.4
[73] 91.7 107.4 90.9 96.5 127.7 91.2 128.7 125.9 90.6 97.5 93.3 116.9
[85] 91.5 111.0 110.2 119.5 101.6 92.6 89.1 106.5 103.6 94.8 123.2 83.3
[97] 82.4 114.1 105.3 95.7 107.5 125.8 137.7 75.2 93.7 92.8 124.4 62.8
$actividad_fisica_min_semana
[1] 198 180 23 45 14 152 221 205 272 235 227 8 165 213 116 71 63 204
[19] 208 276 273 94 31 10 216 288 101 266 178 87 40 75 159 79 85 91
[37] 147 160 201 241 1 224 232 76 115 153 102 193 89 173 121 142 105 122
[55] 261 72 222 203 263 177 83 110 250 6 207 21 2 126 296 187 13 11
[73] 86 24 242 146 54 237 172 220 118 182 287 299 81 210 149 36 58 130
[91] 34 92 206 212 158 292 3 219 19 151 49 176 95 104 249
$nivel_educativo
[1] "Secundaria" "Universitario" "Primaria"
mutate()
La función
mutate()dedplyrse usa para crear nuevas variables o transformar las existentes.Dentro de
mutate(), se aplican las transformaciones a las columnas especificadas.trimws(sexo)Elimina espacios en blanco al principio y al final de cada valor en la columna
sexo.Ejemplo:
Antes:
" Masculino ","FEMENINO "Después:
"Masculino","FEMENINO"
str_to_title()Convierte el texto a mayúscula inicial (título).
Ejemplo:
Antes:
"masculino","FEMENINO"Después:
"Masculino","Femenino"
fumador = str_to_lower(trimws(fumador))trimws(fumador)Elimina espacios adicionales en los valores de la columna
fumador.Ejemplo:
Antes:
" sí ","NO "Después:
"sí","NO"
str_to_lower()Convierte todos los valores a minúsculas.
Ejemplo:
Antes:
"Sí","NO"Después:
"sí","no"
hipertension = str_to_lower(trimws(hipertension))Igual que en la columna
fumador, limpia espacios y transforma todo a minúsculas.Antes:
"Si"," NO "Después:
"si","no"
diabetes = str_to_lower(trimws(diabetes))Elimina espacios y transforma a minúsculas en la columna
diabetes.Ejemplo:
Antes:
"Sí","NO","si "Después:
"sí","no"
nivel_educativo = str_to_title(trimws(nivel_educativo))trimws(nivel_educativo)Limpia espacios adicionales en la columna
nivel_educativo.Ejemplo:
Antes:
" primaria "," UNIVERSITARIO "Después:
"primaria","UNIVERSITARIO"
str_to_title()Convierte a mayúscula inicial (título).
Ejemplo:
Antes:
"primaria","UNIVERSITARIO"Después:
"Primaria","Universitario"head(datos)Muestra las primeras 6 filas del conjunto de datos
datosya limpio.Es una forma rápida de verificar las transformaciones aplicadas.
Resultado
Todas las columnas especificadas tendrán valores uniformes en cuanto a:
Espacios adicionales: Eliminados.
Uso de mayúsculas/minúsculas: Homogeneizado según el contexto.
Ejemplo Antes y Después:
Importancia del Código
Preparación de datos: Es un paso esencial en el preprocesamiento para evitar errores durante el análisis.
Uniformidad: Asegura que los valores sean consistentes, lo que facilita el análisis y evita confusiones.
Evita duplicados conceptuales: Sin limpieza,
"Sí","sí", y"si "serían interpretados como valores distintos.
# Identificaremos con la siguiente función sapply y Aplicar a varias columnas
sapply(datos, function(col) if(is.character(col)) table(col) else NA)$id
[1] NA
$edad
[1] NA
$sexo
col
Femenino Masculino
51 69
$peso_kg
[1] NA
$altura_en_cm
[1] NA
$imc
[1] NA
$fumador
col
no sí
79 41
$hipertension
col
no si sí
71 24 25
$diabetes
col
no si sí
71 16 33
$nivel_colesterol
[1] NA
$nivel_de_glucosa
[1] NA
$actividad_fisica_min_semana
[1] NA
$nivel_educativo
col
Primaria Secundaria Universitario
23 54 43
Al parecer continúan las inconsistencias, vamos a limpiarlas:
Para homogenizar los elementos en las variables categóricas que tienen diferencias (por ejemplo, mayúsculas/minúsculas o múltiples formas de escribir un valor), aplicaremos funciones de limpieza. Aquí te proporciono un código que hace esto paso a paso utilizando el paquete dplyr.
# Cargar librerías necesarias
library(dplyr)
library(stringr)
# Limpieza y homogenización de datos categóricos
datos <- datos %>%
mutate(
# Homogeneizar valores en `sexo`
sexo = case_when(
sexo %in% c("Femenino", "femenino", "FEMENINO") ~ "Femenino",
sexo %in% c("Masculino", "masculino", "MASCULINO") ~ "Masculino",
TRUE ~ NA_character_ # Marcar como NA si no coincide con los valores esperados
),
# Homogeneizar valores en `fumador`
fumador = case_when(
fumador %in% c("sí", "Sí", "SÍ", "si") ~ "Sí",
fumador %in% c("no", "No", "NO") ~ "No",
TRUE ~ NA_character_
),
# Homogeneizar valores en `hipertension`
hipertension = case_when(
hipertension %in% c("sí", "Sí", "SÍ", "si") ~ "Sí",
hipertension %in% c("no", "No", "NO") ~ "No",
TRUE ~ NA_character_
),
# Homogeneizar valores en `diabetes`
diabetes = case_when(
diabetes %in% c("sí", "Sí", "SÍ", "si") ~ "Sí",
diabetes %in% c("no", "No", "NO") ~ "No",
TRUE ~ NA_character_
),
# Homogeneizar valores en `nivel_educativo`
nivel_educativo = case_when(
nivel_educativo %in% c("Primaria", " primaria ", "PRIMARIA") ~ "Primaria",
nivel_educativo %in% c("Secundaria", " secundaria ", "SECUNDARIA") ~ "Secundaria",
nivel_educativo %in% c("Universitario", " universitario ", "UNIVERSITARIO") ~ "Universitario",
TRUE ~ NA_character_
)
)
# Factorizar la variable `nivel_educativo`
datos <- datos %>%
mutate(
nivel_educativo = factor(
nivel_educativo,
levels = c("Primaria", "Secundaria", "Universitario"), # Especificar niveles en orden lógico
labels = c("Primaria", "Secundaria", "Universitario") # Etiquetas estandarizadas
)
)
# Verificar la estructura de la variable después de la factoración
str(datos$nivel_educativo) Factor w/ 3 levels "Primaria","Secundaria",..: 2 3 2 3 3 3 2 2 2 2 ...
Explicación del Código
mutate: Modifica las columnas del DataFrame.case_when: Evalúa múltiples condiciones y asigna valores uniformes:Por ejemplo, en la columna
sexo:Si el valor está en
c("Femenino", "femenino", "FEMENINO"), se convierte a"Femenino".Si no coincide con los valores esperados, se asigna
NA.
TRUE ~ NA_character_: Marca comoNAcualquier valor que no coincida con los esperados.Variables procesadas:
sexo,fumador,hipertension,diabetes,nivel_educativo.
Validación de Resultados
Puedes verificar que los valores están homogenizados utilizando funciones como unique() o table():
# Verificar valores únicos de cada variable
unique(datos$sexo)[1] "Femenino" "Masculino"
unique(datos$fumador)[1] "No" "Sí"
unique(datos$hipertension)[1] "Sí" "No"
unique(datos$diabetes)[1] "Sí" "No"
unique(datos$nivel_educativo)[1] Secundaria Universitario Primaria
Levels: Primaria Secundaria Universitario
# Tablas de frecuencia
table(datos$sexo)
Femenino Masculino
51 69
table(datos$fumador)
No Sí
79 41
table(datos$hipertension)
No Sí
71 49
table(datos$diabetes)
No Sí
71 49
table(datos$nivel_educativo)
Primaria Secundaria Universitario
23 54 43
lapply(datos, unique)$id
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
[37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
[73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
[91] 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
[109] 109 110 111 112 113 114 115 116 117 118 119 120
$edad
[1] 56 69 46 32 60 25 78 38 75 36 40 28 41 70 53 57 20 39 19 61 47 55 77 50 29
[26] 42 66 44 76 59 45 33 79 64 68 72 74 54 24 26 35 21 31 67 43 37 52 34 23 71
[51] 51 27 48 65 62
$sexo
[1] "Femenino" "Masculino"
$peso_kg
[1] 66.9 75.5 53.8 57.8 71.5 55.0 93.3 68.2 59.1 60.2 64.2 63.2 44.9 85.2 69.8
[16] 69.7 79.8 57.3 60.9 69.2 74.1 69.0 67.1 87.2 82.8 40.0 87.8 95.9 84.8 67.4
[31] 61.7 78.7 62.6 74.3 84.6 65.3 64.7 74.5 93.2 71.0 65.0 80.3 78.6 58.6 63.6
[46] 83.2 75.1 40.4 75.8 81.1 59.9 78.1 92.5 74.8 62.5 63.7 70.2 70.8 76.0 72.2
[61] 81.6 57.2 71.3 81.0 67.3 77.8 47.8 84.0 58.2 56.9 35.4 60.4 69.9 65.4 64.4
[76] 56.7 80.4 81.5 75.0 47.4 97.3 71.8 76.5 52.0 68.3 80.5 85.6 53.9 80.2 74.7
[91] 51.2 48.6 73.9 76.1 68.5 95.4 88.6 62.8 68.7 49.0 50.5 56.2 86.7 59.7 57.7
$altura_en_cm
[1] 178.8 165.5 174.2 162.7 152.0 174.7 154.5 164.9 172.0 164.4 168.7 154.4
[13] 190.0 158.0 182.0 171.5 171.4 173.5 151.2 179.7 182.1 168.5 166.3 157.1
[25] 162.3 156.9 150.1 161.4 178.4 187.8 163.2 166.6 171.8 175.8 191.3 172.3
[37] 186.6 165.4 170.9 164.1 167.4 167.2 164.0 164.5 181.0 191.1 165.0 166.8
[49] 175.2 201.9 170.8 185.4 173.4 179.3 176.1 180.3 159.7 174.8 181.4 174.5
[61] 158.6 175.9 161.2 163.0 165.8 168.9 154.6 181.2 158.4 185.7 158.8 182.8
[73] 169.7 152.8 159.6 183.3 169.2 147.8 183.9 188.7 186.9 163.8 173.8 174.9
[85] 154.7 180.7 177.6 158.9 177.9 176.3 147.5 145.4 167.0 165.9 179.8 171.0
[97] 172.7 156.6 136.4 191.4 172.5 173.2 186.8 178.9 175.0
$imc
[1] 37.1 36.5 27.7 23.3 27.0 37.7 21.7 29.5 23.5 31.0 37.4 23.6 38.0 31.2 26.0
[16] 33.7 28.9 26.6 23.8 25.6 27.8 24.0 27.2 30.8 34.4 35.0 36.2 34.5 33.1 27.1
[31] 28.8 20.3 29.9 27.9 35.7 39.5 30.5 25.4 19.4 38.4 38.3 23.9 33.5 20.1 22.1
[46] 23.2 24.8 39.9 26.8 34.3 38.2 39.1 19.7 20.8 25.7 32.4 23.4 24.2 26.2 24.1
[61] 28.2 19.2 24.5 27.3 31.5 24.3 21.4 38.7 27.5 37.3 30.4 22.0 35.2 39.7 34.6
[76] 26.9 36.3 30.7 19.9 19.3 18.8 33.4 30.0 38.1 31.1 34.1 34.8 23.7 22.9 24.4
[91] 23.0 19.5 19.0 29.2 28.7 36.4 25.1 36.1
$fumador
[1] "No" "Sí"
$hipertension
[1] "Sí" "No"
$diabetes
[1] "Sí" "No"
$nivel_colesterol
[1] 235.6 179.9 228.5 189.2 189.3 207.7 208.5 201.2 160.0 196.4 268.4 116.5
[13] 226.1 231.7 159.2 185.9 170.0 255.6 233.1 234.5 203.6 239.4 199.8 240.8
[25] 195.5 179.6 254.3 199.4 173.0 172.7 172.8 225.3 197.0 268.9 242.1 185.1
[37] 144.4 170.3 204.4 193.3 224.7 196.3 222.4 245.0 196.2 216.7 147.4 163.0
[49] 207.1 207.0 185.6 269.0 162.0 160.1 249.6 178.9 171.7 269.1 229.6 182.2
[61] 206.5 258.4 220.7 238.6 224.1 227.9 200.3 208.0 222.0 191.5 203.7 190.7
[73] 203.5 162.5 278.2 178.0 175.4 218.5 194.1 171.1 219.7 223.7 198.0 180.1
[85] 265.7 210.2 161.8 242.4 174.3 282.3 202.4 230.4 137.6 161.5 240.0 209.5
[97] 261.3 214.6 251.4 230.3 167.2 128.9 186.9 164.4 277.9 180.5 179.7 154.4
[109] 192.0 252.1 205.1
$nivel_de_glucosa
[1] 99.9 98.0 111.8 93.2 110.0 124.2 106.9 96.3 85.7 95.9 108.4 77.0
[13] 112.5 103.1 97.8 90.1 92.9 109.0 98.1 92.5 107.0 107.6 81.3 108.6
[25] 137.5 74.5 102.7 72.5 147.5 133.5 90.0 66.3 86.8 97.3 73.6 99.0
[37] 97.2 101.9 103.4 85.5 87.2 100.7 90.5 113.6 100.5 128.0 112.3 116.6
[49] 102.0 102.4 126.0 94.3 108.2 96.0 82.5 88.9 86.1 108.9 115.6 98.6
[61] 97.7 87.8 112.9 109.8 71.6 95.8 94.1 89.9 99.3 95.1 94.7 89.4
[73] 91.7 107.4 90.9 96.5 127.7 91.2 128.7 125.9 90.6 97.5 93.3 116.9
[85] 91.5 111.0 110.2 119.5 101.6 92.6 89.1 106.5 103.6 94.8 123.2 83.3
[97] 82.4 114.1 105.3 95.7 107.5 125.8 137.7 75.2 93.7 92.8 124.4 62.8
$actividad_fisica_min_semana
[1] 198 180 23 45 14 152 221 205 272 235 227 8 165 213 116 71 63 204
[19] 208 276 273 94 31 10 216 288 101 266 178 87 40 75 159 79 85 91
[37] 147 160 201 241 1 224 232 76 115 153 102 193 89 173 121 142 105 122
[55] 261 72 222 203 263 177 83 110 250 6 207 21 2 126 296 187 13 11
[73] 86 24 242 146 54 237 172 220 118 182 287 299 81 210 149 36 58 130
[91] 34 92 206 212 158 292 3 219 19 151 49 176 95 104 249
$nivel_educativo
[1] Secundaria Universitario Primaria
Levels: Primaria Secundaria Universitario
También lo podemos hacer usando la función sapply:
# Identificaremos con la siguiente función sapply y Aplicar a varias columnas
sapply(datos, function(col) if(is.character(col)) table(col) else NA)$id
[1] NA
$edad
[1] NA
$sexo
col
Femenino Masculino
51 69
$peso_kg
[1] NA
$altura_en_cm
[1] NA
$imc
[1] NA
$fumador
col
No Sí
79 41
$hipertension
col
No Sí
71 49
$diabetes
col
No Sí
71 49
$nivel_colesterol
[1] NA
$nivel_de_glucosa
[1] NA
$actividad_fisica_min_semana
[1] NA
$nivel_educativo
[1] NA
Resultado Esperado
Después de ejecutar este código, las variables categóricas tendrán valores uniformes, sin duplicados conceptuales. Por ejemplo:
sexo:"Femenino","Masculino"fumador:"Sí","No"hipertension:"Sí","No"diabetes:"Sí","No"nivel_educativo:"Primaria","Secundaria","Universitario"
Paso 3: Exploración de Datos (EDA)
Resumen Estadístico de las Variables Cuantitativas
# Resumen estadístico de variables cuantitativas
datos %>%
select_if(is.numeric) %>%
summary() id edad peso_kg altura_en_cm
Min. : 1.00 Min. :19.00 Min. :35.40 Min. :136.4
1st Qu.: 30.75 1st Qu.:33.75 1st Qu.:60.77 1st Qu.:163.2
Median : 60.50 Median :51.50 Median :69.90 Median :170.9
Mean : 60.50 Mean :50.39 Mean :69.68 Mean :170.1
3rd Qu.: 90.25 3rd Qu.:68.00 3rd Qu.:78.22 3rd Qu.:178.0
Max. :120.00 Max. :79.00 Max. :97.30 Max. :201.9
imc nivel_colesterol nivel_de_glucosa actividad_fisica_min_semana
Min. :18.80 Min. :116.5 Min. : 62.80 Min. : 1.00
1st Qu.:23.88 1st Qu.:180.1 1st Qu.: 91.65 1st Qu.: 74.25
Median :27.75 Median :202.9 Median : 99.30 Median :146.50
Mean :28.82 Mean :205.0 Mean :101.29 Mean :140.48
3rd Qu.:34.42 3rd Qu.:228.8 3rd Qu.:110.05 3rd Qu.:210.50
Max. :39.90 Max. :282.3 Max. :147.50 Max. :299.00
Con paqute dlookr y la función describe()
#install.packages("dlookr")
library(dlookr)Registered S3 methods overwritten by 'dlookr':
method from
plot.transform scales
print.transform scales
Adjuntando el paquete: 'dlookr'
The following object is masked from 'package:tidyr':
extract
The following object is masked from 'package:base':
transform
datos %>% select() %>% describe()# A tibble: 0 × 9
# ℹ 9 variables: described_variables <chr>, n <int>, na <int>, mean <dbl>,
# sd <dbl>, se_mean <dbl>, IQR <dbl>, skewness <dbl>, kurtosis <dbl>
datos %>% normality()# A tibble: 8 × 4
vars statistic p_value sample
<chr> <dbl> <dbl> <dbl>
1 id 0.955 0.000482 120
2 edad 0.936 0.0000234 120
3 peso_kg 0.993 0.849 120
4 altura_en_cm 0.997 0.994 120
5 imc 0.949 0.000196 120
6 nivel_colesterol 0.989 0.453 120
7 nivel_de_glucosa 0.987 0.336 120
8 actividad_fisica_min_semana 0.958 0.000818 120
datos %>% select(nivel_colesterol ) %>% plot_normality()Histograma: Distribución de la Edad
# Histograma de edad
datos %>%
ggplot(aes(x = nivel_colesterol)) +
geom_histogram(binwidth = 5, fill = "blue", color = "black") +
labs(title = "Distribución de la Edad", x = "Edad (años)", y = "Frecuencia") +
theme_minimal()Variables Categóricas: Distribución de Frecuencias
# Frecuencias de Sexo
datos %>%
count(sexo) %>%
mutate(porcentaje = n / sum(n) * 100)# A tibble: 2 × 3
sexo n porcentaje
<chr> <int> <dbl>
1 Femenino 51 42.5
2 Masculino 69 57.5
# Gráfico de barras: Sexo
datos %>%
ggplot(aes(x = sexo, fill = sexo)) +
geom_bar() +
labs(title = "Distribución por Sexo", x = "Sexo", y = "Frecuencia") +
theme_minimal()Paso 4: Enfoque Epidemiológico
Estimar la Prevalencia de Hipertensión y Diabetes
# Prevalencia de hipertensión
datos %>%
count(hipertension) %>%
mutate(prevalencia = n / sum(n) * 100)# A tibble: 2 × 3
hipertension n prevalencia
<chr> <int> <dbl>
1 No 71 59.2
2 Sí 49 40.8
# Prevalencia de diabetes
datos %>%
count(diabetes) %>%
mutate(prevalencia = n / sum(n) * 100)# A tibble: 2 × 3
diabetes n prevalencia
<chr> <int> <dbl>
1 No 71 59.2
2 Sí 49 40.8
Comparar Características Demográficas entre Fumadores y No Fumadores
# Comparación de Edad entre Fumadores y No Fumadores
datos %>%
filter(fumador %in% c("Sí", "No")) %>%
ggplot(aes(x = fumador, y = edad, fill = fumador)) +
geom_boxplot() +
labs(
title = "Comparación de Edad entre Fumadores y No Fumadores",
x = "Hábito de Fumar",
y = "Edad (años)"
) +
theme_minimal()Implementación de gtsummary en el análisis de datos epidemiológicos
El paquete gtsummary es una herramienta poderosa para crear tablas descriptivas y analíticas listas para publicación en R. Este paquete simplifica la generación de tablas bien formateadas para resúmenes estadísticos, análisis univariados, bivariados y multivariados, lo que es ideal para investigaciones en epidemiología.
Ventajas de gtsummary:
Tablas listas para publicación: Formato limpio y profesional.
Flexibilidad: Fácil personalización del contenido y apariencia de las tablas.
Integración: Compatible con otros paquetes como
tidyverse,dplyrybroom.Exportación sencilla: Tablas pueden ser exportadas a Word, PDF, o HTML.
Instalación y Carga de Paquetes
Primero, asegurémonos de instalar y cargar el paquete gtsummary junto con otros necesarios.
# Instalar paquetes necesarios (si aún no están instalados)
# install.packages("gtsummary")
library(gtsummary)Crear una Tabla Descriptiva Básica
La función tbl_summary() genera una tabla con estadísticas descriptivas para todas las variables de interés.
Los pasos son los siguientes:
1. Primero creamos un objeto en donde vamos a guardar nuesta tabla.
- concatenamos con el data frame y con la función
selecthacemos selección de las variables que queremos analizar y crear en tabla - Conectamos con pipe a la función
tbl_summaryque es del paquetegtsummary - Si queremos que nos divida en columnas, usamos
by=y agregamos la variable, asegurate que la hayas seleccionado previamente - Una vez creada, la imprimimos y visualizamos. Reconoce autmaticamente variables que son cualitativas y cuantitativas.
# Tabla descriptiva básica
tabla_descriptiva <- datos %>% select(fumador, sexo, edad, altura_en_cm, nivel_educativo) %>%
tbl_summary(by= fumador)
# Visualizar la tabla
tabla_descriptiva| Characteristic | No N = 791 |
Sí N = 411 |
|---|---|---|
| sexo | ||
| Femenino | 35 (44%) | 16 (39%) |
| Masculino | 44 (56%) | 25 (61%) |
| edad | 46 (35, 66) | 59 (31, 70) |
| altura_en_cm | 169 (162, 176) | 173 (164, 181) |
| nivel_educativo | ||
| Primaria | 11 (14%) | 12 (29%) |
| Secundaria | 37 (47%) | 17 (41%) |
| Universitario | 31 (39%) | 12 (29%) |
| 1 n (%); Median (Q1, Q3) | ||
Si queremos agregar más información a la tabla por ejemplo los valores de significancia estadística valor p y una columna de total, usamos las funciones add_overall y add_p:
str(datos$edad) num [1:120] 56 69 46 32 60 25 78 38 56 75 ...
datos <- datos %>%
mutate(
fumador = as.factor(fumador),
sexo = as.factor(sexo),
nivel_educativo = as.factor(nivel_educativo)
)
str(datos$edad) num [1:120] 56 69 46 32 60 25 78 38 56 75 ...
# Tabla descriptiva básica
tabla_descriptiva <- datos %>%
select(fumador, sexo, edad, altura_en_cm, nivel_educativo, nivel_de_glucosa, nivel_colesterol) %>%
tbl_summary(
by = fumador,
statistic = list(
all_continuous() ~ "{median} ({IQR})", # Para variables continuas
all_categorical() ~ "{n} ({p}%)" # Para variables categóricas
)
) %>%
add_overall() %>%
add_p()
# Visualizar la tabla
tabla_descriptiva| Characteristic | Overall N = 1201 |
No N = 791 |
Sí N = 411 |
p-value2 |
|---|---|---|---|---|
| sexo | 0.6 | |||
| Femenino | 51 (43%) | 35 (44%) | 16 (39%) | |
| Masculino | 69 (58%) | 44 (56%) | 25 (61%) | |
| edad | 52 (34) | 46 (30) | 59 (39) | 0.7 |
| altura_en_cm | 171 (15) | 169 (13) | 173 (17) | 0.076 |
| nivel_educativo | 0.12 | |||
| Primaria | 23 (19%) | 11 (14%) | 12 (29%) | |
| Secundaria | 54 (45%) | 37 (47%) | 17 (41%) | |
| Universitario | 43 (36%) | 31 (39%) | 12 (29%) | |
| nivel_de_glucosa | 99 (18) | 100 (18) | 98 (17) | 0.4 |
| nivel_colesterol | 203 (49) | 204 (49) | 199 (45) | 0.6 |
| 1 n (%); Median (IQR) | ||||
| 2 Pearson’s Chi-squared test; Wilcoxon rank sum test | ||||
tbl_summary:
by = sexo: Divide las estadísticas por el grupo “sexo”.statistic = all_continuous() ~ "{mean} ({sd})": Calcula la media y desviación estándar para variables cuantitativas.missing = "no": Excluye valores faltantes de la tabla.
Comparación Bivariada entre Grupos
La función add_p() agrega valores p para comparar variables entre grupos.
Explicación de add_p:
- Esta función calcula automáticamente el valor p para comparar variables cuantitativas y categóricas entre grupos.
Tablas Multivariadas (Regresión)
Podemos usar gtsummary para mostrar resultados de un modelo de regresión logística.
Pero antes debemos de preparar nuevamente los datos:
la variable dependiente diabetes no está codificada correctamente. En una regresión logística (family = binomial), la variable dependiente (y) debe ser:
- Binaria: Solo puede tener dos valores, generalmente
0y1.
En este caso, los valores en diabetes probablemente son "Sí" y "No", que no son numéricos.
# Revisar los valores únicos de la variable dependiente
unique(datos$diabetes)[1] "Sí" "No"
unique(datos$diabetes):
Verifica los valores únicos en la variable
diabetespara identificar inconsistencias.Probablemente devolverá valores como
"Sí"y"No", que deben transformarse.
Transformaremos la variable diabetes para que sea binaria, convirtiendo:
"Sí"a1(indica presencia de diabetes)."No"a0(indica ausencia de diabetes)
# Convertir la variable dependiente en binaria
datos <- datos %>%
mutate(
diabetes = case_when(
diabetes == "Sí" ~ 1,
diabetes == "No" ~ 0,
TRUE ~ NA_real_ # Marcar como NA si no coincide
)
)
# Verificar los cambios
unique(datos$diabetes)[1] 1 0
mutate() y case_when():
Convierte
"Sí"a1y"No"a0, asegurando que la variable sea numérica y binaria.TRUE ~ NA_real_: Si un valor no coincide con"Sí"o"No", se asignaNApara evitar errores.
Ahora vamos con el modelo:
# Modelo de regresión logística: Diabetes en función de hipertensión y edad
modelo <- glm(diabetes ~ hipertension + edad, data = datos, family = binomial)
modelo
Call: glm(formula = diabetes ~ hipertension + edad, family = binomial,
data = datos)
Coefficients:
(Intercept) hipertensionSí edad
-0.396451 0.576248 -0.004305
Degrees of Freedom: 119 Total (i.e. Null); 117 Residual
Null Deviance: 162.3
Residual Deviance: 159.8 AIC: 165.8
Funciones y Parámetros:
glm():Esta función ajusta un modelo lineal generalizado.
En este caso, se usa para regresión logística, que modela probabilidades de un desenlace binario.
Fórmula
diabetes ~ hipertension + edad:Especifica la relación entre la variable dependiente (
diabetes) y las independientes (hipertensionyedad).diabetes: Variable dependiente categórica (Sí/No), codificada como binaria (0 = No, 1 = Sí).hipertensionyedad: Variables independientes explicativas.
data = datos:- Indica que las variables están en el DataFrame
datos.
- Indica que las variables están en el DataFrame
family = binomial:- Especifica que el modelo es una regresión logística (distribución binomial).
AIC
Comparación de Modelos:
El AIC no tiene un significado absoluto. Se utiliza para comparar varios modelos ajustados a los mismos datos.
Un modelo con menor AIC es preferible.
La diferencia ΔAIC=AIC1−AIC2 se usa para determinar la magnitud de la mejora entre dos modelos.
Regla General:
Si ΔAIC>10AIC > 10ΔAIC>10, el modelo con el AIC más bajo tiene evidencia mucho más fuerte de ser el mejor.
Si ΔAIC está entre 4 y 7, hay evidencia moderada.
Si ΔAIC < 2, ambos modelos son comparables.
Generar una Tabla Resumida con tbl_regression
tabla_regresion <- tbl_regression(modelo, exponentiate = TRUE)
tabla_regresion| Characteristic | OR1 | 95% CI1 | p-value |
|---|---|---|---|
| hipertension | |||
| No | — | — | |
| Sí | 1.78 | 0.85, 3.77 | 0.13 |
| edad | 1.00 | 0.98, 1.02 | 0.7 |
| 1 OR = Odds Ratio, CI = Confidence Interval | |||
Explicación de tbl_regression:
Este código realiza un análisis de regresión logística para evaluar la asociación entre diabetes (variable dependiente) y factores como hipertensión y edad (variables independientes). Luego, genera una tabla de resumen profesional utilizando el paquete gtsummary.
Salida del Modelo:
El modelo estima:
Coeficientes: Muestran el efecto de cada variable independiente sobre la probabilidad de tener diabetes.
Odds Ratios (OR): Los coeficientes exponentiados indican cómo cambian las probabilidades con cada variable.
Funciones y Parámetros:
tbl_regression():- Función del paquete
gtsummaryque genera una tabla profesional con los resultados del modelo ajustado.
- Función del paquete
Argumento
modelo:- El modelo ajustado (usando
glm) se pasa como entrada para generar la tabla.
- El modelo ajustado (usando
exponentiate = TRUE:Convierte los coeficientes del modelo a Odds Ratios (OR), que son más intuitivos para interpretar en regresión logística.
Ejemplo:
OR > 1: Aumento en la probabilidad de tener diabetes con un incremento en la variable.
OR < 1: Disminución en la probabilidad.
Salida de tbl_regression:
La tabla incluye:
Variable: Nombre de cada variable independiente.
OR: Odds Ratio para cada variable.
IC (Intervalo de Confianza): Margen de error para el OR.
Valor p: Indica si la asociación es estadísticamente significativa.
Uso de Regresión Logística en el Contexto del Estudio
La regresión logística es una técnica estadística utilizada para modelar relaciones entre una variable dependiente categórica (como tener o no diabetes) y una o más variables independientes. En este caso, sí podemos aplicar un modelo de regresión logística, ya que tenemos un conjunto de datos donde variables categóricas como diabetes (Sí/No) pueden ser modeladas como dependientes y explicadas por variables independientes (como edad, hipertensión, IMC, etc.).
Preguntas de Investigación
A partir de los datos del estudio transversal que estamos analizando, podemos formular preguntas clave como:
¿Cuál es la asociación entre hipertensión y diabetes?
- Hipótesis: Las personas con hipertensión tienen mayor probabilidad de desarrollar diabetes.
¿Cómo afecta el IMC (índice de masa corporal) al riesgo de diabetes?
- Hipótesis: Un IMC elevado está asociado con un mayor riesgo de diabetes.
¿Existen diferencias en el nivel de actividad física entre fumadores y no fumadores?
- Hipótesis: Los fumadores realizan menos actividad física que los no fumadores.
¿Influye la edad en la probabilidad de ser fumador?
- Hipótesis: La prevalencia de fumar disminuye en grupos de mayor edad.
¿Qué factores demográficos (edad, sexo, nivel educativo) están asociados con tener hipertensión?
- Hipótesis: Los hombres tienen mayor probabilidad de tener hipertensión que las mujeres.
Estas preguntas pueden ser exploradas con modelos de regresión logística y técnicas descriptivas.
Diseño del Estudio
Este es un estudio transversal, lo que significa que las observaciones y mediciones se realizaron en un momento específico. En este tipo de estudios:
Fortalezas:
Es útil para medir la prevalencia de enfermedades o factores de riesgo.
Relativamente económico y rápido.
Limitaciones:
No establece causalidad (asociaciones pueden ser coincidencias).
Sensible a sesgos de selección y medición.
Hipótesis Estadísticas
Con base en las preguntas planteadas, podemos definir hipótesis específicas:
Hipótesis 1: Asociación entre hipertensión y diabetes.
Hipótesis Nula (H0): No hay asociación entre hipertensión y diabetes.
Hipótesis Alternativa (Ha): La hipertensión está asociada con un mayor riesgo de diabetes.
Hipótesis 2: Relación entre IMC y diabetes.
H0 El IMC no afecta el riesgo de diabetes.
Ha: Un mayor IMC aumenta el riesgo de diabetes.
Hipótesis 3: Diferencias en actividad física según hábito de fumar.
H0: No hay diferencia en actividad física entre fumadores y no fumadores.
Ha: Los fumadores realizan menos actividad física que los no fumadores.
Conclusión
El uso de regresión logística en este tipo de datos es completamente válido y adecuado para explorar asociaciones. Sin embargo, debido al diseño transversal, no podemos establecer causalidad directa. Las hipótesis planteadas pueden servir como base para futuros estudios más robustos, como estudios de cohorte o ensayos clínicos.