Métricas - Doenças Cardiovasculares
O KNN e K-Means já foram treinados e avaliados. Aqui apresentamos os resultados detalhados.
Aviso
Não consegui exibir os códigos diretamente aqui porque meu Markdown não printou. Vou colocar o código completo no final da página, e os resultados aparecerão em imagens (prints) ao longo do documento.
Observação: se você executar o código localmente, verá que os resultados estão corretos!
Modelo Supervisionado: KNN (k=3)
O KNN é um modelo de aprendizado supervisionado, que prevê a classe de um paciente com base na proximidade de características em relação aos vizinhos mais próximos.
| Curva ROC | Resultados KNN |
|---|---|
![]() | ![]() |
- Acurácia: 0.89 - Indica que 89% das previsões do modelo estão corretas.
- Balanced Accuracy: 0.88 - Ajusta a acurácia para desequilíbrios entre classes (importante em doenças raras).
- AUC-ROC: 0.91 - Mede a capacidade do modelo de distinguir pacientes com e sem doença. Quanto mais próximo de 1, melhor.
Detalhamento por Classe
-
Classe 0 (Sem doença)
- Precision: 0.91 - Das vezes que o modelo previu "sem doença", 91% estavam corretas.
- Recall: 0.83 - Identificou corretamente 83% dos pacientes realmente saudáveis.
- F1: 0.87 - Média harmônica entre Precision e Recall, bom equilíbrio.
-
Classe 1 (Com doença)
- Precision: 0.87 - Das vezes que o modelo previu "com doença", 87% estavam corretas.
- Recall: 0.93 - Identificou corretamente 93% dos pacientes com doença (muito importante clinicamente).
- F1: 0.90 - Excelente equilíbrio para casos positivos.
Matriz de Confusão
| Matriz de Confusão |
|---|
![]() |
Interpretação:
-
O modelo acerta principalmente os pacientes com doença (Recall=0.93), reduzindo o risco de falsos negativos, que é crítico na prática clínica.
-
Pacientes saudáveis também são corretamente identificados na maioria das vezes (Precision 0.91).
Modelo Não Supervisionado: K-Means (k=3)
O K-Means é um modelo não supervisionado, que agrupa pacientes em clusters com base em semelhanças de atributos, sem usar rótulos.
| Resultado K-Means | Clusters |
|---|---|
![]() | ![]() |
-
Inércia (WSS): 704.09 - Quanto menor, melhor a compactação dos clusters.
-
Silhouette Score: 0.28 - Mede a separação entre clusters (0.28 indica separação moderada).
Interpretação:
O K-Means conseguiu separar razoavelmente bem os grupos, formando:
- Um cluster quase exclusivo de pacientes saudáveis (Cluster 1).
- Dois clusters majoritariamente de pacientes com doença (Cluster 0 e 2).
Isso sugere que os atributos do dataset têm boa separabilidade natural entre doentes e não-doentes, mesmo sem supervisão.
Conclusão
O KNN se destaca pela alta acurácia e recall para casos positivos, sendo ideal para aplicações médicas.
O K-Means confirma que os dados apresentam estrutura separável, mas com sobreposição entre grupos.
- O melhor modelo para predição clínica é o KNN (supervisionado).
- O K-Means pode ser útil para análises exploratórias e segmentação inicial.
Código
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import (
accuracy_score, balanced_accuracy_score, confusion_matrix, classification_report,
roc_auc_score, roc_curve
)
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
# preprocessamento
def preprocess(df):
df = df.copy()
if df["HeartDisease"].dtype != int:
df["HeartDisease"] = df["HeartDisease"].astype(int)
df["Sex"] = df["Sex"].map({"M": 1, "F": 0})
df["ChestPainType"] = df["ChestPainType"].map({"TA": 0, "ATA": 1, "NAP": 2, "ASY": 3})
df["RestingECG"] = df["RestingECG"].map({"Normal": 0, "ST": 1, "LVH": 2})
df["ExerciseAngina"] = df["ExerciseAngina"].map({"Y": 1, "N": 0})
df["ST_Slope"] = df["ST_Slope"].map({"Up": 0, "Flat": 1, "Down": 2})
return df
# knn
def run_knn(df):
df = preprocess(df)
numeric_cols = df.select_dtypes(include=[np.number]).columns
df[numeric_cols] = (df[numeric_cols] - df[numeric_cols].min()) / (df[numeric_cols].max() - df[numeric_cols].min())
X = df.drop("HeartDisease", axis=1)
y = df["HeartDisease"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
predictions = knn.predict(X_test)
y_prob = knn.predict_proba(X_test)[:, 1]
acc = accuracy_score(y_test, predictions)
balanced_acc = balanced_accuracy_score(y_test, predictions)
cm = confusion_matrix(y_test, predictions)
report = classification_report(y_test, predictions, digits=2)
auc = roc_auc_score(y_test, y_prob)
# Curva ROC
fpr, tpr, _ = roc_curve(y_test, y_prob)
plt.figure(figsize=(6,4))
plt.plot(fpr, tpr, label=f"KNN (AUC={auc:.2f})")
plt.plot([0,1], [0,1], 'k--')
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("Curva ROC - KNN")
plt.legend()
plt.show()
# Matriz de confusão
plt.figure(figsize=(5,4))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", cbar=False)
plt.xlabel("Predito")
plt.ylabel("Real")
plt.title("Matriz de Confusão - KNN")
plt.show()
print("\n🔹 Resultados KNN")
print(f"Accuracy: {acc:.2f}")
print(f"Balanced Accuracy: {balanced_acc:.2f}")
print(f"AUC-ROC: {auc:.2f}")
print("\nClassification Report:")
print(report)
# kmeans
def run_kmeans(df, n_clusters=3):
df = preprocess(df)
numeric_cols = df.select_dtypes(include=[np.number]).columns
df[numeric_cols] = (df[numeric_cols] - df[numeric_cols].min()) / (df[numeric_cols].max() - df[numeric_cols].min())
X = df[numeric_cols].values
kmeans = KMeans(n_clusters=n_clusters, init="k-means++", max_iter=300, random_state=42)
labels = kmeans.fit_predict(X)
inertia = kmeans.inertia_
sil_score = silhouette_score(X, labels)
df_clusters = df.copy()
df_clusters["Cluster"] = labels
cluster_vs_target = pd.crosstab(df_clusters["Cluster"], df_clusters["HeartDisease"], normalize="index") * 100
# Plot distribuição clusters
cluster_vs_target.plot(kind="bar", stacked=True, figsize=(6,4), colormap="coolwarm")
plt.ylabel("% Pacientes")
plt.title("Distribuição de HeartDisease por Cluster (K-Means)")
plt.legend(title="HeartDisease", loc="upper right")
plt.show()
print("\n🔹 Resultados K-Means")
print(f"Inércia (WSS): {inertia:.2f}")
print(f"Silhouette Score: {sil_score:.2f}")
print("\nDistribuição (%) de HeartDisease por cluster:")
print(cluster_vs_target)
if __name__ == "__main__":
df = pd.read_csv("https://raw.githubusercontent.com/bligui/Machine-Learning-Ana/refs/heads/main/dados/heart.csv")
# Rodar KNN
run_knn(df)
# Rodar K-Means
run_kmeans(df, n_clusters=3)




