Predicción de Enfermedad Cardíaca con Inteligencia Artificial
Inteligencia Artificial Publicado el 20 de julio de 2025 Tiempo de lectura: 9 min.Introducción
Las enfermedades cardiovasculares (ECV) son la principal causa de muerte en el mundo, con 17,9 millones de fallecimientos en 2019, equivalentes al 32% de todas las muertes globales. El 85% de estos casos se debieron a infartos de miocardio y accidentes cerebrovasculares, afectando especialmente a países de ingresos bajos y medianos. Además, el 38% de las muertes prematuras por enfermedades no transmisibles se atribuyen a las ECV. Fuente: Organización Mundial de la Salud.
La insuficiencia cardíaca emerge como una consecuencia común de las enfermedades cardiovasculares, y las personas con ECV o con alto riesgo cardiovascular requieren detección y manejo temprano. En este contexto, los modelos de Machine Learning pueden proporcionar una ayuda invaluable para la identificación temprana de estos riesgos.
Dataset Utilizado
Para este estudio se utilizó un conjunto de datos que combina cinco conjuntos independientes de datos de cardiología, lo cual constituye el mayor dataset sobre enfermedades cardíacas disponible para investigación. El dataset contiene 918 observaciones con 11 características predictoras y una variable objetivo binaria (0 = Normal, 1 = Enfermedad cardíaca). Fuente: Kaggle.
Características del Dataset
- Age: Edad del paciente [años]
- Sex: Sexo del paciente [M: Masculino, F: Femenino]
- ChestPainType: Tipo de dolor torácico [TA: angina típica, ATA: angina atípica, NAP: dolor no anginoso, ASY: asintomático]
- RestingBP: Presión arterial en reposo [mm Hg]
- Cholesterol: Colesterol sérico [mm/dl]
- FastingBS: Azúcar en sangre en ayunas [1: si Azúcar en sangre en ayunas > 120 mg/dl, 0: en caso contrario]
- RestingECG: Resultados del electrocardiograma en reposo [Normal: Normal, ST: con anomalía de la onda ST-T (inversiones de la onda T y/o elevación o depresión del ST de > 0,05 mV), LVH: que muestra hipertrofia ventricular izquierda probable o definitiva según los criterios de Estes]
- MaxHR: Frecuencia cardíaca máxima alcanzada [Valor numérico entre 60 y 202]
- ExerciseAngina: Angina inducida por el ejercicio [Y: Sí, N: No]
- Oldpeak: Depresión del ST [Valor numérico medido en depresión]
- ST_Slope: Pendiente del segmento ST del ejercicio máximo [Arriba: pendiente ascendente, Plano: plano, Abajo: pendiente descendente]
- HeartDisease: Clase de salida [1: enfermedad cardíaca, 0: normal]
Nota: El segmento ST es una parte específica de la onda del electrocardiograma que se encuentra entre el complejo QRS (despolarización ventricular) y la onda T (repolarización ventricular).
Metodología: Enfoque de 7 Fases
El estudio se estructura en siete fases sistemáticas que abarcan desde la carga inicial de datos hasta la evaluación final de modelos optimizados. Se evaluaron 9 algoritmos diferentes de Machine Learning, comparando su rendimiento tanto con hiperparámetros por defecto (línea base) como con hiperparámetros ajustados (optimización).
La primera fase consiste en la importación y carga inicial del dataset utilizando la librería pandas de Python.
# FASE 1: Carga del conjunto de datos
import warnings
warnings.filterwarnings("ignore")
import pandas as pd
df = pd.read_csv('heart.csv')
pd.set_option('display.max_columns', None)
df.head(3)
Resultados de la Carga del Conjunto de Datos

En esta fase se determina la información fundamental del dataset: dimensiones, tipos de datos, clasificación de variables y detección de valores nulos.
# FASE 2: Exploración básica del conjunto de datos
# Número de registros y columnas
print("DIMENSIONES DEL DATASET:")
print(f"Registros (filas): {df.shape[0]}")
print(f"Columnas (variables): {df.shape[1]}\n")
# Tipos de datos por columna
print("TIPOS DE DATOS DE CADA COLUMNA:")
print(df.dtypes)
print()
# Clasificación de variables: numéricas vs categóricas
print("CLASIFICACIÓN DE VARIABLES (Numéricas vs Categóricas):")
numericas = df.select_dtypes(include=['number']).columns.tolist()
categoricas = df.select_dtypes(exclude=['number']).columns.tolist()
print(f"Variables numéricas ({len(numericas)}): {numericas}")
print(f"Variables categóricas ({len(categoricas)}): {categoricas}\n")
# Valores nulos por columna
print("VALORES NULOS POR COLUMNA:")
nulos = df.isnull().sum()
print(nulos.to_string())
Resultados de la Exploración Básica
El dataset contiene 918 registros y 12 columnas (11 características + 1 variable objetivo). Se identificaron 8 variables numéricas y 3 categóricas, sin presencia de valores nulos, lo que indica un dataset limpio y completo.
Esta fase incluye análisis estadísticos descriptivos, visualizaciones de la distribución de clases, matrices de correlación y detección de outliers mediante boxplots.
# FASE 3: Exploración más a fondo del conjunto de datos
import seaborn as sns
import matplotlib.pyplot as plt
# 1. Estadísticas descriptivas de variables numéricas
print("ESTADÍSTICAS DESCRIPTIVAS (Variables Numéricas):")
print(df.describe())
# 2. Distribución de la variable objetivo 'HeartDisease'
print("\nDISTRIBUCIÓN DE LA VARIABLE OBJETIVO (HeartDisease):")
print(df['HeartDisease'].value_counts())
print("\nDISTRIBUCIÓN PORCENTUAL:")
print(df['HeartDisease'].value_counts(normalize=True).map("{:.2%}".format))
# 3. Gráfico de barras: distribución de clases
plt.figure(figsize=(6,4))
sns.countplot(x='HeartDisease', data=df, palette='Set2')
plt.title('Distribución de Clases (HeartDisease)')
plt.xlabel('Clase (0 = No Enfermo, 1 = Enfermo)')
plt.ylabel('Frecuencia')
plt.show()
Análisis Exploratorio Profundo



En esta etapa se realiza el escalado de variables numéricas, codificación de variables categóricas, y la división estratégica de los datos en conjuntos de entrenamiento, prueba y predicción.
# FASE 4: Preprocesamiento y división del conjunto de datos
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.compose import ColumnTransformer
# 1. Separar 5 registros aleatorios para pronóstico futuro
df_sample = df.sample(n=5, random_state=42)
df_rest = df.drop(df_sample.index).reset_index(drop=True)
# 2. Identificar columnas numéricas y categóricas
X = df_rest.drop(columns=['HeartDisease']) # características
y = df_rest['HeartDisease'] # variable objetivo
numeric_features = X.select_dtypes(include=['number']).columns.tolist()
categorical_features = X.select_dtypes(exclude=['number']).columns.tolist()
# 3. Definir transformaciones para preprocesamiento
preprocessor = ColumnTransformer(
transformers=[
('num', StandardScaler(), numeric_features),
('cat', OneHotEncoder(handle_unknown='ignore', drop='first'), categorical_features)
])
# 4. Aplicar transformaciones y dividir datasets
X_processed = preprocessor.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(
X_processed, y, test_size=0.2, random_state=42, stratify=y
)
Resultados Preprocesamiento

Se entrenan y evalúan 9 modelos diferentes utilizando sus configuraciones por defecto para establecer una línea base de rendimiento.
# FASE 5: Entrenamiento y evaluación de modelos con hiperparámetros por defecto
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
# Definición de modelos
modelos = [
("Decision Tree", DecisionTreeClassifier(random_state=42)),
("AdaBoost", AdaBoostClassifier(random_state=42)),
("Gradient Boosting", GradientBoostingClassifier(random_state=42)),
("Random Forest", RandomForestClassifier(random_state=42)),
("SVM", SVC(random_state=42, probability=True)),
("Gaussian Naive Bayes", GaussianNB()),
("Logistic Regression", LogisticRegression(max_iter=1000, random_state=42)),
("K Neighbors", KNeighborsClassifier()),
("XGBoost", XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42))
]
# Entrenar y evaluar modelos
resultados = []
for nombre, modelo in modelos:
modelo.fit(X_train, y_train)
y_pred = modelo.predict(X_test)
# Calcular métricas
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
resultados.append({
"Modelo": nombre,
"Accuracy": accuracy,
"Precision": precision,
"Recall": recall,
"F1-Score": f1
})
Modelos con Hiperparámetros por Defecto

Exactitud Inicial de Referencia
Basado en los resultados de validación cruzada (CV Accuracy) podemos alcanzar exactitud en los resultados del orden del 86.16%. Esta métrica podría ser engañosa si las clases están desbalanceadas, sin embargo, no es el caso de este estudio porque las clases de la variable objetivo están bien balancedas. Sin ajuste de parámetros, las mejores líneas bases fueron alcanzados por:
- Random Forest
- SVM
- Logistic Regression
Nota: Puede ampliar la información sobre métricas de evalación de modelos en el artículo Métricas de Evaluación de Modelos de Clasificación Binaria .
Se implementa GridSearchCV para encontrar la configuración óptima de hiperparámetros para cada modelo, maximizando el F1-Score.
# FASE 6: Entrenamiento y evaluación con ajuste de hiperparámetros
from sklearn.model_selection import GridSearchCV
# Definición de modelos con espacios de búsqueda
modelos_con_grid = [
("Random Forest", RandomForestClassifier(random_state=42), {
'n_estimators': [50, 100, 150],
'max_depth': [None, 5, 10],
'min_samples_split': [2, 4],
'min_samples_leaf': [1, 2],
'bootstrap': [True, False]
}),
("SVM", SVC(random_state=42, probability=True), {
'C': [0.1, 1, 10],
'kernel': ['linear', 'rbf'],
'gamma': ['scale', 'auto']
}),
("XGBoost", XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42), {
'n_estimators': [50, 100, 150],
'learning_rate': [0.01, 0.1, 0.2],
'max_depth': [3, 5],
'min_child_weight': [1, 3, 5]
})
]
# Optimizar hiperparámetros
for nombre, modelo, param_grid in modelos_con_grid:
grid_search = GridSearchCV(
estimator=modelo,
param_grid=param_grid,
cv=5,
scoring='f1',
n_jobs=-1
)
grid_search.fit(X_train, y_train)
print(f"Mejores parámetros para {nombre}: {grid_search.best_params_}")
Modelos con Hiperparámetros Ajustados

Mejora con Hiperparámetros Optimizados
En este caso, en la validación cruzada, podemos alcanzar exactitud en los resultados del orden del 87.53%. Tras la optimización, los tres mejores modelos corresponden a:
- K Neighbors (n_neighbors=10, p=1, weights='distance')
- XGBoost (learning_rate=0.1, max_depth=3, n_estimators=50)
- Random Forest (max_depth=5, n_estimators=50, bootstrap=True)
Para la selección de los mejores modelos se consideró: F1-Score (Equilibrio entre precisión y recall), ROC AUC (Capacidad de discriminación entre clases), Log Loss (Calibración de probabilidades...menos es mejor) y CV Accuracy (Estabilidad de la exactitud del modelo...promedio en validación cruzada).
Finalmente, se entrenan los tres mejores modelos identificados y se realizan predicciones sobre los 5 registros reservados para validar la efectividad del sistema.
# FASE 7: Predicciones con los tres mejores modelos identificados
from sklearn.neighbors import KNeighborsClassifier
from xgboost import XGBClassifier
from sklearn.ensemble import RandomForestClassifier
# Entrenar modelos optimizados
knn = KNeighborsClassifier(n_neighbors=10, p=1, weights='distance')
xgb = XGBClassifier(learning_rate=0.1, max_depth=3, min_child_weight=3,
n_estimators=50, subsample=1.0, use_label_encoder=False,
eval_metric='logloss')
rf = RandomForestClassifier(bootstrap=True, max_depth=5, min_samples_leaf=1,
min_samples_split=2, n_estimators=50, random_state=42)
# Entrenar con todo el conjunto de entrenamiento
knn.fit(X_train, y_train)
xgb.fit(X_train, y_train)
rf.fit(X_train, y_train)
# Realizar predicciones en datos reservados
predicciones = []
for modelo, nombre in zip([knn, xgb, rf], ['KNN', 'XGBoost', 'Random Forest']):
y_pred = modelo.predict(X_sample_processed)
y_proba = modelo.predict_proba(X_sample_processed)[:, 1]
for i, (pred, proba) in enumerate(zip(y_pred, y_proba)):
predicciones.append({
"Modelo": nombre,
"Registro": i + 1,
"Predicción": "Enfermo (1)" if pred == 1 else "No enfermo (0)",
"Probabilidad": f"{proba:.2%}"
})
# Mostrar resultados
df_predicciones = pd.DataFrame(predicciones)
print("PREDICCIONES EN LOS 5 REGISTROS RESERVADOS:")
print(df_predicciones)
Resultados Predicciones

Registros Reservados para Predicción

Validación de Resultados
Las predicciones de los tres mejores modelos fueron completamente correctas, coincidiendo perfectamente con los resultados reales de los datos reservados. Este resultado es altamente satisfactorio, especialmente considerando que estos datos corresponden a información completamente nueva, no utilizada durante el entrenamiento ni las pruebas.
Conclusiones
Este estudio demuestra la efectividad de los modelos de Machine Learning para la predicción temprana de enfermedades cardíacas. Los modelos finales seleccionados (K Neighbors, XGBoost y Random Forest) muestran alta confiabilidad y robustez, validados mediante:
- Validación cruzada (5 fold)
- Optimización rigurosa de hiperparámetros
- Evaluación en datos completamente nuevos
- Múltiples métricas de rendimiento
Estos resultados sugieren que la implementación de sistemas de IA para la detección temprana de insuficiencia cardíaca puede contribuir significativamente a la reducción de la mortalidad por enfermedades cardiovasculares.
Impacto y Aplicaciones Futuras
La implementación de estos modelos en entornos clínicos podría revolucionar la detección temprana de enfermedades cardiovasculares, permitiendo intervenciones oportunas que podrían salvar millones de vidas anualmente. Los sistemas de apoyo a la decisión clínica basados en estos algoritmos representan un paso crucial hacia una medicina preventiva más efectiva y personalizada.
El enfoque metodológico presentado en este estudio puede ser replicado y adaptado para otros conjuntos de datos médicos, contribuyendo al desarrollo de herramientas de diagnóstico asistido por IA más precisas y confiables. ¡No esperes a que el futuro llegue… Sé parte de él!. Agenda una consulta gratuita con nuestro equipo y descubre cómo podemos personalizar esta tecnología para tu institución..