Estudios epidemiológicos: Estudios transversales

Author

Dr. Juan Fidel Osuna Ramos

Published

December 18, 2024

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:

Dataframes

Cómo usar Google Colab

  1. Abrir el entorno:

    • Ve a Dataframes

    • Puedes cargar un archivo .ipynb o trabajar desde un cuaderno nuevo.

  2. 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.
  3. 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)

# install.packages("readxl")
# install.packages("tidyverse")
# install.packages("janitor")

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() de dplyr se 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"

  1. 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"

  1. 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"

  1. 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"

  1. 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 datos ya 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

      1. Preparación de datos: Es un paso esencial en el preprocesamiento para evitar errores durante el análisis.

      2. Uniformidad: Asegura que los valores sean consistentes, lo que facilita el análisis y evita confusiones.

      3. 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

  1. mutate: Modifica las columnas del DataFrame.

  2. 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.

  3. TRUE ~ NA_character_: Marca como NA cualquier valor que no coincida con los esperados.

  4. 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:

  1. Tablas listas para publicación: Formato limpio y profesional.

  2. Flexibilidad: Fácil personalización del contenido y apariencia de las tablas.

  3. Integración: Compatible con otros paquetes como tidyverse, dplyr y broom.

  4. 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.

  1. concatenamos con el data frame y con la función select hacemos selección de las variables que queremos analizar y crear en tabla
  2. Conectamos con pipe a la función tbl_summaryque es del paquete gtsummary
  3. Si queremos que nos divida en columnas, usamos by= y agregamos la variable, asegurate que la hayas seleccionado previamente
  4. 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

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

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:

  1. by = sexo: Divide las estadísticas por el grupo “sexo”.

  2. statistic = all_continuous() ~ "{mean} ({sd})": Calcula la media y desviación estándar para variables cuantitativas.

  3. 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 0 y 1.

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 diabetes para identificar inconsistencias.

  • Probablemente devolverá valores como "Sí" y "No", que deben transformarse.

Transformaremos la variable diabetes para que sea binaria, convirtiendo:

  • "Sí" a 1 (indica presencia de diabetes).

  • "No" a 0 (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í" a 1 y "No" a 0, asegurando que la variable sea numérica y binaria.

  • TRUE ~ NA_real_: Si un valor no coincide con "Sí" o "No", se asigna NA para 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:

  1. 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.

  2. Fórmula diabetes ~ hipertension + edad:

    • Especifica la relación entre la variable dependiente (diabetes) y las independientes (hipertension y edad).

    • diabetes: Variable dependiente categórica (Sí/No), codificada como binaria (0 = No, 1 = Sí).

    • hipertension y edad: Variables independientes explicativas.

  3. data = datos:

    • Indica que las variables están en el DataFrame datos.
  4. family = binomial:

    • Especifica que el modelo es una regresión logística (distribución binomial).
  5. 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:

  1. tbl_regression():

    • Función del paquete gtsummary que genera una tabla profesional con los resultados del modelo ajustado.
  2. Argumento modelo:

    • El modelo ajustado (usando glm) se pasa como entrada para generar la tabla.
  3. 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:

  1. ¿Cuál es la asociación entre hipertensión y diabetes?

    • Hipótesis: Las personas con hipertensión tienen mayor probabilidad de desarrollar diabetes.
  2. ¿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.
  3. ¿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.
  4. ¿Influye la edad en la probabilidad de ser fumador?

    • Hipótesis: La prevalencia de fumar disminuye en grupos de mayor edad.
  5. ¿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:

  1. 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.

  2. 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.

  3. 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.