En la actividad anterior de análisis exploratorio con el dataset Heart Disease UCI, se identificaron patrones diferenciados en la capacidad cardiovascular según el estado de salud de los pacientes. Específicamente, se observó que los pacientes diagnosticados con enfermedad cardíaca tendían a alcanzar frecuencias cardíacas máximas más bajas durante las pruebas de esfuerzo, en comparación con aquellos sin diagnóstico de enfermedad.
Desde una perspectiva de salud pública y epidemiología social, comprender estas diferencias es relevante porque la capacidad funcional cardiovascular no solo es un indicador biomédico, sino también un factor que incide en la calidad de vida, las posibilidades de inserción laboral y las dinámicas de vulnerabilidad social de las personas con enfermedades crónicas.
Este análisis inferencial busca determinar si la diferencia observada visualmente en el análisis exploratorio es estadísticamente significativa o si podría explicarse por variación aleatoria en la muestra. En otras palabras, ¿podemos generalizar este hallazgo a la población más amplia de personas con características similares?
library(readxl)
library(dplyr)
library(ggplot2)
library(knitr)
# Cargar datos limpios
datos <- read_excel("/Users/lorenaumana/Desktop/Curso R/datos/a2_umana_lorena.xlsx")
# Filtrar datos sin valores faltantes en target
datos_completos <- datos %>%
filter(!is.na(target))
# Ver estructura
glimpse(datos_completos)
## Rows: 676
## Columns: 7
## $ age <dbl> 63, 67, 37, 41, 56, 57, 53, 57, 56, 44, 52, 57, 48, 54, 48, 4…
## $ sex <chr> "Male", "Male", "Male", "Female", "Male", "Female", "Male", "…
## $ trestbps <dbl> 145, 120, 130, 130, 120, 120, 140, 140, 140, 120, 172, 150, 1…
## $ chol <dbl> 233, 229, 250, 204, 236, 354, 203, 192, 294, 263, 199, 168, 2…
## $ thalch <dbl> 150, 129, 187, 172, 178, 163, 155, 148, 153, 173, 162, 174, 1…
## $ oldpeak <dbl> 2.3, 2.6, 3.5, 1.4, 0.8, 0.6, 3.1, 0.4, 1.3, 0.0, 0.5, 1.6, 1…
## $ target <chr> "Sano", "Enfermedad", "Sano", "Sano", "Sano", "Sano", "Enferm…
¿La frecuencia cardíaca máxima promedio de los pacientes con enfermedad cardíaca es significativamente menor que la de los pacientes sanos?
Esta pregunta surge directamente del análisis exploratorio de datos (EDA) realizado previamente, donde se identificó un patrón visual que sugiere diferencias sistemáticas en la capacidad cardiovascular entre ambos grupos.
La relevancia de esta pregunta trasciende lo puramente clínico: la capacidad funcional medida a través de la frecuencia cardíaca máxima alcanzada está asociada con:
Desde las ciencias sociales, es importante entender no solo la presencia de la enfermedad, sino también sus manifestaciones funcionales que pueden traducirse en desventajas sociales.
Primero, revisemos visualmente los datos para contextualizar nuestro análisis inferencial:
# Estadísticas descriptivas por grupo
estadisticas <- datos_completos %>%
group_by(target) %>%
summarise(
n = n(),
Media = mean(thalch, na.rm = TRUE),
DE = sd(thalch, na.rm = TRUE),
Mediana = median(thalch, na.rm = TRUE),
Min = min(thalch, na.rm = TRUE),
Max = max(thalch, na.rm = TRUE)
)
kable(estadisticas,
caption = "Estadísticas descriptivas de frecuencia cardíaca máxima por diagnóstico",
digits = 2)
| target | n | Media | DE | Mediana | Min | Max |
|---|---|---|---|---|---|---|
| Enfermedad | 265 | 131.48 | 22.9 | 130 | 72 | 195 |
| Sano | 411 | 148.37 | 23.1 | 150 | 69 | 202 |
# Boxplot comparativo
ggplot(datos_completos, aes(x = target, y = thalch, fill = target)) +
geom_boxplot(alpha = 0.7, show.legend = FALSE) +
scale_fill_manual(values = c("Enfermedad" = "#E74C3C", "Sano" = "#3498DB")) +
labs(
title = "Frecuencia cardíaca máxima según diagnóstico",
subtitle = "Comparación entre pacientes sanos y con enfermedad cardíaca",
x = "Diagnóstico",
y = "Frecuencia cardíaca máxima (latidos por minuto)"
) +
theme_minimal(base_size = 13)
De la tabla y el gráfico se observa que:
Desde el análisis exploratorio, surge la pregunta: ¿Esta diferencia observada es una característica real de la población, o podría ser producto del azar en nuestra muestra particular?
Esta es la pregunta que la estadística inferencial nos permite responder con un nivel de certeza cuantificable.
Hipótesis nula (H₀): La frecuencia cardíaca máxima promedio de pacientes con enfermedad es igual o mayor que la de pacientes sanos.
Formalmente: H₀: μ_enfermedad ≥ μ_sano
Hipótesis alternativa (Hₐ): La frecuencia cardíaca máxima promedio de pacientes con enfermedad es menor que la de pacientes sanos.
Formalmente: Hₐ: μ_enfermedad < μ_sano
Se utiliza la prueba t de Student por las siguientes razones:
Tipo de pregunta: Queremos comparar si hay diferencias sistemáticas entre dos grupos independientes (con enfermedad vs sanos)
Naturaleza de los datos: Estamos comparando promedios de una variable continua (frecuencia cardíaca) entre dos categorías
Dirección de la hipótesis: Usamos una prueba unilateral (de una cola) porque nuestra hipótesis es específica sobre la dirección del efecto: esperamos que el grupo con enfermedad tenga valores menores, no solo diferentes
Esta elección metodológica nos permite hacer una inferencia precisa sobre la pregunta planteada, minimizando el riesgo de conclusiones erróneas.
# Separar datos por grupo
grupo_enfermedad <- datos_completos %>%
filter(target == "Enfermedad") %>%
pull(thalch)
grupo_sano <- datos_completos %>%
filter(target == "Sano") %>%
pull(thalch)
# Realizar prueba t de Student (unilateral)
resultado_t <- t.test(
grupo_enfermedad,
grupo_sano,
alternative = "less", # Hipótesis: enfermedad < sano
conf.level = 0.95
)
# Mostrar resultados
print(resultado_t)
##
## Welch Two Sample t-test
##
## data: grupo_enfermedad and grupo_sano
## t = -9.3334, df = 567.01, p-value < 2.2e-16
## alternative hypothesis: true difference in means is less than 0
## 95 percent confidence interval:
## -Inf -13.91416
## sample estimates:
## mean of x mean of y
## 131.4755 148.3723
cat("Estadístico t observado:", round(resultado_t$statistic, 4), "\n")
## Estadístico t observado: -9.3334
cat("Grados de libertad:", round(resultado_t$parameter, 2), "\n")
## Grados de libertad: 567.01
El estadístico t observado es -9.3334. Un valor negativo indica que la media del grupo con enfermedad es menor que la del grupo sano, lo cual es consistente con nuestra hipótesis alternativa.
¿Qué son los grados de libertad? Es un número técnico que R calcula automáticamente y que necesita para determinar el p-valor. En términos simples, mientras más grados de libertad tengamos, más confiables son nuestros resultados. En este caso tenemos suficientes datos para confiar en las conclusiones.
cat("p-valor:", format(resultado_t$p.value, scientific = FALSE, digits = 6), "\n")
## p-valor: 0.000000000000000000114841
El p-valor obtenido es 0.000000000000000000114841.
if(resultado_t$p.value < 0.05) {
cat("DECISIÓN: Rechazamos H₀ (p-valor < 0.05)\n\n")
cat("Existe evidencia estadística suficiente para concluir que la frecuencia cardíaca\n")
cat("máxima promedio de pacientes con enfermedad cardíaca es significativamente MENOR\n")
cat("que la de pacientes sanos.\n")
} else {
cat("DECISIÓN: No rechazamos H₀ (p-valor ≥ 0.05)\n\n")
cat("No existe evidencia estadística suficiente para concluir que la frecuencia cardíaca\n")
cat("máxima promedio de pacientes con enfermedad cardíaca es menor que la de pacientes sanos.\n")
}
## DECISIÓN: Rechazamos H₀ (p-valor < 0.05)
##
## Existe evidencia estadística suficiente para concluir que la frecuencia cardíaca
## máxima promedio de pacientes con enfermedad cardíaca es significativamente MENOR
## que la de pacientes sanos.
# Calcular medias de cada grupo
media_enfermedad <- mean(grupo_enfermedad)
media_sano <- mean(grupo_sano)
diferencia_medias <- media_enfermedad - media_sano
cat("Media del grupo con enfermedad:", round(media_enfermedad, 2), "latidos/min\n")
## Media del grupo con enfermedad: 131.48 latidos/min
cat("Media del grupo sano:", round(media_sano, 2), "latidos/min\n")
## Media del grupo sano: 148.37 latidos/min
cat("Diferencia de medias:", round(diferencia_medias, 2), "latidos/min\n\n")
## Diferencia de medias: -16.9 latidos/min
cat("Intervalo de confianza 95% para la diferencia de medias:\n")
## Intervalo de confianza 95% para la diferencia de medias:
cat("[", round(resultado_t$conf.int[1], 2), ", ", round(resultado_t$conf.int[2], 2), "]\n", sep="")
## [-Inf, -13.91]
Interpretación del intervalo: Con 95% de confianza, la diferencia real entre las medias poblacionales (enfermedad - sano) está dentro del intervalo reportado. Como es un intervalo unilateral, solo tiene límite superior.
La prueba t funciona mejor cuando los datos tienen una distribución aproximadamente normal (forma de campana). Aunque la prueba es robusta y funciona bien incluso con desviaciones moderadas, especialmente con muestras grandes como la nuestra, verificamos este supuesto visualmente:
par(mfrow = c(1, 2))
# Q-Q plots para evaluar normalidad
qqnorm(grupo_enfermedad, main = "Q-Q Plot: Grupo Enfermedad")
qqline(grupo_enfermedad, col = "red")
qqnorm(grupo_sano, main = "Q-Q Plot: Grupo Sano")
qqline(grupo_sano, col = "blue")
¿Cómo leer estos gráficos? Si los puntos siguen aproximadamente la línea roja o azul, significa que los datos tienen una distribución normal. En nuestro caso, los puntos siguen razonablemente bien la línea, con algunas desviaciones en los extremos. Esto es aceptable y la prueba t es apropiada para nuestros datos.
cat("Tamaño del grupo con enfermedad:", length(grupo_enfermedad), "\n")
## Tamaño del grupo con enfermedad: 265
cat("Tamaño del grupo sano:", length(grupo_sano), "\n")
## Tamaño del grupo sano: 411
Ambos grupos tienen tamaños de muestra adecuados para la aplicación de la prueba t.
El p-valor nos dice si existe una diferencia estadísticamente significativa, pero no nos dice qué tan grande es esa diferencia. Para eso calculamos la d de Cohen, que es una medida estandarizada del tamaño del efecto.
¿Por qué es importante? Podemos tener una diferencia estadísticamente significativa que sea muy pequeña y poco relevante en la práctica, o una diferencia grande que sí tenga importancia real.
# Calcular d de Cohen (tamaño del efecto estandarizado)
sd_pooled <- sqrt(((length(grupo_enfermedad)-1)*sd(grupo_enfermedad)^2 +
(length(grupo_sano)-1)*sd(grupo_sano)^2) /
(length(grupo_enfermedad) + length(grupo_sano) - 2))
cohens_d <- (media_enfermedad - media_sano) / sd_pooled
cat("d de Cohen:", round(cohens_d, 3), "\n\n")
## d de Cohen: -0.734
Interpretación de la d de Cohen:
## En este caso: d = -0.73 → Efecto MODERADO
## La diferencia es considerable y tiene clara relevancia práctica.
En resumen: No solo se encontro que la diferencia es estadísticamente significativa (p < 0.05), sino que además es una diferencia de magnitud considerable, lo que le da relevancia práctica y social al hallazgo.
El análisis exploratorio inicial reveló un patrón visual: los pacientes con enfermedad cardíaca mostraban frecuencias cardíacas máximas consistentemente más bajas. Sin embargo, la visualización por sí sola no nos permitía afirmar con certeza si este patrón era generalizable a la población o era específico de nuestra muestra.
El análisis inferencial confirma que este patrón observado es estadísticamente significativo y muy probablemente refleja una diferencia real en la población de pacientes con estas características.
Resultado estadístico: Existe evidencia estadística sólida (p < 0.05) de que la frecuencia cardíaca máxima promedio de pacientes con enfermedad cardíaca es significativamente menor que la de pacientes sanos.
Magnitud de la diferencia: La diferencia observada es de aproximadamente 16.9 latidos por minuto. El tamaño del efecto es moderado a grande (d de Cohen = -0.73), lo que indica que se trata de una diferencia sustantiva, no solo estadísticamente significativa.
Implicación práctica: Esta diferencia tiene relevancia tanto clínica como social. Una menor capacidad cardiovascular funcional limita las actividades que las personas pueden realizar, afectando su autonomía, participación social y oportunidades laborales.
Elaborado por: Lorena Umaña
Fecha: 2025-11-24
Dataset: Heart Disease UCI
Enfoque disciplinario: Sociología aplicada a salud
pública