En un estudio de casos y controles, identificamos un grupo de personas con el desenlace de interés (casos) y otro grupo sin el desenlace (controles). Luego, evaluamos y comparamos las exposiciones previas entre ambos grupos para explorar asociaciones.
Ejemplo de Planteamiento
Pregunta de Investigación: ¿La hipertensión está asociada con un mayor riesgo de desarrollar diabetes?
Casos: Personas con diagnóstico de diabetes.
Controles: Personas sin diagnóstico de diabetes.
Exposición de interés: Hipertensión.
Covariables: Edad, IMC, actividad física, nivel educativo, hábito de fumar.
Planteamiento del Estudio
Objetivo del Estudio:
Evaluar si la hipertensión aumenta el riesgo de diabetes.
Pregunta de Investigación:
¿Es más probable que las personas con hipertensión desarrollen diabetes que aquellas sin hipertensión?
Variables:
Dependiente: Diabetes (Casos: Sí; Controles: No).
Independiente: Hipertensión (Sí/No).
Covariables: Edad, IMC, actividad física, nivel educativo, hábito de fumar.
Próximos Pasos
Limpieza de la base de datos simulada.
Exploración descriptiva (EDA) de las características de casos y controles.
Análisis bivariado (Odds Ratio para hipertensión).
Ajustes multivariados usando regresión logística.
Este documento aborda el análisis de un estudio de casos y controles para explorar la asociación entre hipertensión y diabetes. Iniciaremos con:
1. Limpieza de una base de datos con errores intencionados. 2. Exploración descriptiva de las variables. 3. Análisis bivariado y multivariado mediante regresión logística.
# Instalar paquetes necesarios (si aún no están instalados)# install.packages("readxl")# install.packages("tidyverse")# install.packages("janitor")# install.packages("gtsummary")# Cargar libreríaslibrary(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
library(gtsummary)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
# Leer la base de datos desde Excel#archivo <- "estudio_casos_controles_errores.xlsx"library(readxl)library(readxl)estudio_casos_controles_errores <-read_excel("estudio_casos_controles_errores.xlsx")#datos <- read_excel(archivo)datos<-estudio_casos_controles_errores# Visualizar las primeras filas#head(datos)
Paso 2: Limpieza de la Base de Datos
En este paso, utilizaremos las funciones de janitor y dplyr para:
Limpiar nombres de columnas.
Corregir inconsistencias en valores categóricos.
# Limpiar nombres de columnasdatos <- datos %>%clean_names()names(datos)
# Corregir inconsistencias en valores categóricosdatos <- datos %>%mutate(sexo =str_to_title(trimws(sexo)), # Título (primera letra en mayúscula)fumador =str_to_lower(trimws(fumador)), # Minúsculahipertension =str_to_lower(trimws(hipertension)), # Minúsculanivel_educativo =str_to_title(trimws(nivel_educativo)) # Título )# Visualizar los datos limpioshead(datos)
# A tibble: 6 × 9
id diabetes edad sexo imc hipertension actividad_fisica_min…¹ fumador
<dbl> <chr> <dbl> <chr> <dbl> <chr> <dbl> <chr>
1 1 Sí 75 Mascul… 25.8 no 207 no
2 2 Sí 32 Femeni… 30.4 no 295 no
3 3 Sí 58 Femeni… 30.9 sí 126 sí
4 4 Sí 64 Mascul… 29.7 no 264 no
5 5 Sí 68 Mascul… 18.6 no 208 sí
6 6 Sí 47 Femeni… 39.7 sí 258 sí
# ℹ abbreviated name: ¹actividad_fisica_min_sem
# ℹ 1 more variable: nivel_educativo <chr>
id edad imc actividad_fisica_min_sem
Min. : 1.00 Min. :30.00 Min. :18.60 Min. : 0.0
1st Qu.: 25.75 1st Qu.:45.00 1st Qu.:24.38 1st Qu.: 71.0
Median : 50.50 Median :56.50 Median :30.30 Median :140.0
Mean : 50.50 Mean :55.81 Mean :29.53 Mean :145.5
3rd Qu.: 75.25 3rd Qu.:68.00 3rd Qu.:34.70 3rd Qu.:214.2
Max. :100.00 Max. :79.00 Max. :39.90 Max. :297.0
# Frecuencia de diabetesdatos %>%count(diabetes) %>%mutate(porcentaje = n /sum(n) *100)
# A tibble: 2 × 3
diabetes n porcentaje
<chr> <int> <dbl>
1 No 100 50
2 Sí 100 50
# Gráfico de barrasdatos %>%ggplot(aes(x = diabetes, fill = diabetes)) +geom_bar() +labs(title ="Distribución de Casos y Controles", x ="Diabetes", y ="Frecuencia") +theme_minimal()
Paso 4: Análisis Bivariado (Odds Ratios)
Usaremos tablas de contingencia para calcular las Odds Ratios de hipertensión.
# Tabla de contingenciadatos2 <- datos %>%mutate(diabetes =factor(diabetes, levels =c("Sí", "No")), # Diabetes: "si" primerohipertension =factor(hipertension, levels =c("Sí", "No")) # Hipertensión: "si" primero )tabla_contingencia <- datos2 %>%count(diabetes, hipertension) %>%pivot_wider(names_from = hipertension, values_from = n, values_fill =0)tabla_contingencia
# A tibble: 2 × 3
diabetes Sí No
<fct> <int> <int>
1 Sí 48 52
2 No 41 59
# Calcular Odds Ratio manualmenteodds_ratio <- (tabla_contingencia$Sí[1] * tabla_contingencia$No[2]) / (tabla_contingencia$Sí[2] * tabla_contingencia$No[1])# Extraer valores de la tablaa <- tabla_contingencia$Sí[1] # Diabetes "Sí" e Hipertensión "Sí"b <- tabla_contingencia$No[1] # Diabetes "Sí" e Hipertensión "No"c <- tabla_contingencia$Sí[2] # Diabetes "No" e Hipertensión "Sí"d <- tabla_contingencia$No[2] # Diabetes "No" e Hipertensión "No"# Calcular Odds Ratioodds_ratio <- (a * d) / (b * c)cat("Odds Ratio de hipertensión asociada a diabetes:", round(odds_ratio, 2))
Odds Ratio de hipertensión asociada a diabetes: 1.33
Determinar IC 95% a a los OR
# Logaritmo natural del ORln_or <-log(odds_ratio)# Varianza del log(OR)var_ln_or <- (1/ a) + (1/ b) + (1/ c) + (1/ d)# Intervalo de confianza del 95%z <-1.96# Valor crítico para 95%se_ln_or <-sqrt(var_ln_or) # Error estándar del log(OR)# Límites inferior y superior del ICic_lower <-exp(ln_or - z * se_ln_or)ic_upper <-exp(ln_or + z * se_ln_or)# Imprimir resultadoscat("OR =", round(odds_ratio, 2), "\n","IC95%:", round(ic_lower, 2), "-", round(ic_upper, 2), "\n")
OR = 1.33
IC95%: 0.76 - 2.32
Interpretación del Odds Ratio
OR>1: La hipertensión es más probable en personas con diabetes.
OR=1 : No hay asociación entre diabetes e hipertensión.
OR<1: La hipertensión es menos probable en personas con diabetes.
Frecuencias (a,b,c,d):
Se extraen directamente de la tabla de contingencia calculada con pivot_wider.
Odds Ratio (odds_ratio):
El cálculo del OR ya está realizado.
Logaritmo Natural del OR (ln_or):
Utilizamos log(odds_ratio) para calcular el logaritmo natural del OR.
Varianza del log(OR) (var_ln_or):
Fórmula:
Intervalo de Confianza:
Límite inferior:
Límite superior:
Interpretación del Resultado
El resultado de R=1.33 con un intervalo de confianza al 95% (C95%: 0.76 - 2.32) puede interpretarse de la siguiente manera:
1. Valor del Odds Ratio (OR)
OR=1.33 (OR=>1)
Indica que las personas con diabetes tienen 1.33 veces más probabilidades de tener hipertensión en comparación con las personas sin diabetes.
Sin embargo, este valor debe evaluarse junto con el intervalo de confianza para determinar si la asociación es estadísticamente significativa.
2. Intervalo de Confianza al 95% (IC95%)
IC95%=[0.76, 2.32]:
Este intervalo significa que, con un 95% de confianza, el verdadero Odds Ratio podría estar entre 0.76 y 2.32.
Incluye el valor 1, lo que implica que la asociación no es estadísticamente significativa (es posible que no haya diferencia real en las probabilidades de hipertensión entre personas con y sin diabetes).
Interpretación Práctica:
Existe una posible asociación positiva entre diabetes e hipertensión (OR=1.33), pero esta asociación no es estadísticamente significativa según el IC95%=[0.76, 2.32].
Más datos o estudios adicionales serían necesarios para confirmar esta relación.