En esta actividad voy a explorar visualmente el conjunto de datos Heart Disease UCI usando gráficos creados con ggplot2. El objetivo es practicar la creación de diferentes tipos de visualizaciones y aprender a interpretar lo que los gráficos nos muestran sobre los datos.
Primero cargo las librerías que voy a necesitar:
library(tidyverse)
library(readxl)
library(knitr)
library(scales)
Ahora importo mis datos limpios:
datos <- read_excel("/Users/lorenaumana/Desktop/Curso R/datos/a2_umana_lorena.xlsx")
Veamos cuántos datos tengo:
cat("Número de pacientes (observaciones):", nrow(datos), "\n")
## Número de pacientes (observaciones): 920
cat("Número de variables:", ncol(datos), "\n")
## Número de variables: 7
Aquí están las primeras filas de mis datos:
kable(head(datos, 8))
| age | sex | trestbps | chol | thalch | oldpeak | target |
|---|---|---|---|---|---|---|
| 63 | Male | 145 | 233 | 150 | 2.3 | Sano |
| 67 | Male | 160 | 286 | 108 | 1.5 | NA |
| 67 | Male | 120 | 229 | 129 | 2.6 | Enfermedad |
| 37 | Male | 130 | 250 | 187 | 3.5 | Sano |
| 41 | Female | 130 | 204 | 172 | 1.4 | Sano |
| 56 | Male | 120 | 236 | 178 | 0.8 | Sano |
| 62 | Female | 140 | 268 | 160 | 3.6 | NA |
| 57 | Female | 120 | 354 | 163 | 0.6 | Sano |
Resumen: Tengo datos de 920 pacientes con 7
variables que describen su salud cardiovascular. La variable más
importante es target, que indica el diagnóstico (Sano o
Enfermedad).
# Filtrar los datos que no son NA
datos_clean <- datos %>%
filter(!is.na(target))
ggplot(datos_clean, aes(x = target, fill = target)) +
geom_bar() +
geom_text(stat = 'count', aes(label = after_stat(count)), vjust = -0.5, size = 5) +
labs(title = "Distribución de pacientes según diagnóstico",
x = "Diagnóstico",
y = "Número de pacientes") +
scale_fill_manual(values = c("Enfermedad" = "#E74C3C",
"Sano" = "#3498DB")) +
theme_minimal(base_size = 13) +
theme(legend.position = "none")
Interpretación: En este conjunto de datos hay 265 pacientes diagnosticados con enfermedad cardíaca y 411 pacientes sanos. Los datos muestran la distribución de casos con y sin la enfermedad en la muestra estudiada.
ggplot(datos, aes(x = age)) +
geom_histogram(bins = 20, fill = "#9B59B6", color = "black", alpha = 0.7) +
labs(title = "Distribución de edad de los pacientes",
x = "Edad (años)",
y = "Frecuencia") +
theme_minimal(base_size = 13)
Interpretación: La mayoría de los pacientes tienen entre 50 y 60 años. La edad promedio es de 53.5 años. Hay muy pocos pacientes menores de 40 años o mayores de 70 años, lo que sugiere que la enfermedad cardíaca es más común en personas de edad media y adultos mayores.
datos_clean <- datos %>%
filter(!is.na(target))
ggplot(datos_clean, aes(x = target, y = age, fill = target)) +
geom_boxplot(alpha = 0.7) +
labs(title = "Edad según presencia de enfermedad cardíaca",
x = "Diagnóstico",
y = "Edad (años)") +
scale_fill_manual(values = c("Enfermedad" = "#E74C3C",
"Sano" = "#3498DB")) +
theme_minimal(base_size = 13) +
theme(legend.position = "none")
Interpretación: Los pacientes con enfermedad cardíaca tienden a ser un poco mayores que los pacientes sanos, pero la diferencia no es muy grande. La mediana de edad es similar en ambos grupos, lo que sugiere que la edad por sí sola no determina completamente quién desarrolla la enfermedad.
# Crear etiquetas para el sexo
datos <- datos %>%
mutate(sexo = ifelse(sex == "Male", "Hombre", "Mujer"))
ggplot(datos, aes(x = age, fill = sexo)) +
geom_histogram(bins = 20, position = "dodge", color = "black", alpha = 0.7) +
labs(title = "Distribución de edad según sexo",
x = "Edad (años)",
y = "Frecuencia",
fill = "Sexo") +
scale_fill_manual(values = c("Hombre" = "#2196F3", "Mujer" = "#E91E63")) +
theme_minimal(base_size = 13)
Interpretación: En este estudio hay más hombres que mujeres. Ambos sexos muestran distribuciones de edad similares, concentrándose principalmente entre los 50 y 60 años. La mayor presencia de hombres puede reflejar que históricamente se han estudiado más a hombres en investigaciones cardiovasculares.
datos_clean <- datos %>%
filter(!is.na(target))
ggplot(datos_clean, aes(x = age, y = thalch, color = target)) +
geom_point(alpha = 0.6, size = 2.5) +
geom_smooth(method = "lm", se = FALSE, linewidth = 1) +
labs(title = "Relación entre edad y frecuencia cardíaca máxima",
x = "Edad (años)",
y = "Frecuencia cardíaca máxima alcanzada (bpm)",
color = "Diagnóstico") +
scale_color_manual(values = c("Enfermedad" = "#E74C3C",
"Sano" = "#3498DB")) +
theme_minimal(base_size = 13)
Interpretación: Se observa una relación inversa clara: a mayor edad, los pacientes alcanzan frecuencias cardíacas máximas más bajas. Además, los pacientes sanos (puntos azules) tienden a alcanzar frecuencias más altas que aquellos con enfermedad (puntos rojos), lo que indica mejor capacidad cardiovascular en las personas sin la enfermedad.
datos_clean <- datos %>%
filter(!is.na(target))
ggplot(datos_clean, aes(x = chol, y = trestbps, color = target)) +
geom_point(alpha = 0.6, size = 2.5) +
labs(title = "Relación entre colesterol y presión arterial",
x = "Colesterol sérico (mg/dl)",
y = "Presión arterial en reposo (mm Hg)",
color = "Diagnóstico") +
scale_color_manual(values = c("Enfermedad" = "#E74C3C",
"Sano" = "#3498DB")) +
theme_minimal(base_size = 13)
Interpretación: No se observa una relación muy clara entre colesterol y presión arterial. Los puntos están bastante dispersos. Los pacientes con enfermedad (rojos) y los sanos (azules) están distribuidos en todos los niveles de ambas variables, sin un patrón muy definido. Esto sugiere que estos dos factores actúan de manera más independiente de lo que podríamos pensar.
datos_clean <- datos %>%
filter(!is.na(target))
ggplot(datos_clean, aes(x = target, y = oldpeak, fill = target)) +
geom_boxplot(alpha = 0.7) +
labs(title = "Depresión del segmento ST según diagnóstico",
subtitle = "Medida durante prueba de esfuerzo",
x = "Diagnóstico",
y = "Depresión del ST (oldpeak)") +
scale_fill_manual(values = c("Enfermedad" = "#E74C3C",
"Sano" = "#3498DB")) +
theme_minimal(base_size = 13) +
theme(legend.position = "none")
Interpretación: La depresión del segmento ST es una medida electrocardiográfica que se toma durante pruebas de esfuerzo. Los pacientes con enfermedad cardíaca muestran valores más altos, lo que indica mayor compromiso cardiovascular durante el ejercicio. Los pacientes sanos tienden a tener valores más bajos o cercanos a cero.
datos_clean <- datos %>%
filter(!is.na(target))
ggplot(datos_clean, aes(x = target, y = trestbps, fill = target)) +
geom_boxplot(alpha = 0.7) +
labs(title = "Presión arterial en reposo según diagnóstico",
x = "Diagnóstico",
y = "Presión arterial en reposo (mm Hg)") +
scale_fill_manual(values = c("Enfermedad" = "#E74C3C",
"Sano" = "#3498DB")) +
theme_minimal(base_size = 13) +
theme(legend.position = "none")
Interpretación: La presión arterial en reposo es bastante similar entre ambos grupos, con medianas alrededor de 130 mm Hg. Esto sugiere que la presión arterial por sí sola no es un factor muy distintivo para diferenciar entre tener o no la enfermedad en este conjunto de datos.
ggplot(datos, aes(x = chol)) +
geom_histogram(bins = 25, fill = "#16A085", color = "black", alpha = 0.7) +
geom_vline(xintercept = mean(datos$chol, na.rm = TRUE),
color = "red", linetype = "dashed", linewidth = 1) +
annotate("text", x = mean(datos$chol, na.rm = TRUE) + 20,
y = Inf, vjust = 2,
label = paste("Promedio:", round(mean(datos$chol, na.rm = TRUE), 0), "mg/dl"),
color = "red", fontface = "bold") +
labs(title = "Distribución del colesterol sérico",
x = "Colesterol (mg/dl)",
y = "Frecuencia") +
theme_minimal(base_size = 13)
Interpretación: El colesterol muestra una distribución aproximadamente normal centrada alrededor de 200 mg/dl. Hay algunos pacientes con valores muy altos (mayores a 400 mg/dl), que podrían considerarse valores extremos y representar casos de riesgo elevado.
datos_clean <- datos %>%
filter(!is.na(target))
ggplot(datos_clean, aes(x = sexo, fill = target)) +
geom_bar(position = "fill", alpha = 0.8) +
labs(title = "Proporción de diagnóstico según sexo",
x = "Sexo",
y = "Proporción",
fill = "Diagnóstico") +
scale_fill_manual(values = c("Enfermedad" = "#E74C3C",
"Sano" = "#3498DB")) +
scale_y_continuous(labels = percent_format()) +
theme_minimal(base_size = 13)
Interpretación: Se observan diferencias en la proporción de diagnósticos entre hombres y mujeres en este estudio. La distribución muestra cómo se reparten los casos de enfermedad y salud entre ambos sexos en la muestra analizada. Esto puede reflejar diferencias biológicas o en los patrones de presentación de la enfermedad.
A través de estas visualizaciones pude observar varios patrones importantes en los datos:
Distribución de casos: El dataset incluye tanto pacientes con enfermedad cardíaca como pacientes sanos, lo que permite hacer comparaciones entre grupos.
Edad: Aunque los pacientes con enfermedad tienden a ser ligeramente mayores, la edad no parece ser el único factor determinante. Hay personas mayores sanas y personas relativamente jóvenes con enfermedad.
Capacidad funcional: La frecuencia cardíaca máxima alcanzada durante el ejercicio muestra diferencias claras entre grupos, siendo un indicador importante de salud cardiovascular.
Factores de riesgo tradicionales: Variables como presión arterial y colesterol no muestran diferencias muy marcadas entre grupos cuando se observan individualmente. Esto sugiere que la enfermedad cardíaca es multifactorial.
Depresión del ST: Esta medida electrocardiográfica sí muestra diferencias entre grupos, siendo más elevada en pacientes con enfermedad.
Diferencias por sexo: Los patrones de distribución varían entre hombres y mujeres, lo que puede tener implicaciones para el diagnóstico y tratamiento.
Estos gráficos me ayudaron a entender mejor los datos antes de hacer análisis más complejos. La visualización hace más fácil identificar patrones que no son evidentes en tablas numéricas.
Elaborado por: Lorena Umaña
Fecha: 2025-11-09