Skip to content

Exploração de Dados

Descrição da base de dados e código de exploração

O câncer de mama é o tipo de câncer mais comum entre mulheres em todo o mundo, responsável por aproximadamente 25% de todos os casos e afetando milhões de pessoas todos os anos. Ele se desenvolve quando células da mama começam a crescer de forma descontrolada, formando tumores que podem ser identificados por exames de imagem (raios-X) ou detectados como nódulos.

O principal desafio no diagnóstico é diferenciar corretamente os tumores malignos (cancerosos) dos benignos (não cancerosos). O objetivo deste projeto é desenvolver um modelo de classificação supervisionada capaz de prever, com base em atributos numéricos das células, se um tumor é maligno ou benigno, e estabelecer um diagnóstico confiável.

Sobre o Dataset

Total de registros: 569 amostras

Variável alvo: diagnosis (M = maligno, B = benigno)

Número de variáveis preditoras: 30 atributos numéricos relacionados ao tamanho, textura, formato e concavidade das células.

id diagnosis radius_mean texture_mean perimeter_mean area_mean smoothness_mean compactness_mean concavity_mean concave points_mean symmetry_mean fractal_dimension_mean radius_se texture_se perimeter_se area_se smoothness_se compactness_se concavity_se concave points_se symmetry_se fractal_dimension_se radius_worst texture_worst perimeter_worst area_worst smoothness_worst compactness_worst concavity_worst concave points_worst symmetry_worst fractal_dimension_worst
87930 B 12.47 18.6 81.09 481.9 0.09965 0.1058 0.08005 0.03821 0.1925 0.06373 0.3961 1.044 2.497 30.29 0.006953 0.01911 0.02701 0.01037 0.01782 0.003586 14.97 24.64 96.05 677.9 0.1426 0.2378 0.2671 0.1015 0.3014 0.0875
859575 M 18.94 21.31 123.6 1130 0.09009 0.1029 0.108 0.07951 0.1582 0.05461 0.7888 0.7975 5.486 96.05 0.004444 0.01652 0.02269 0.0137 0.01386 0.001698 24.86 26.58 165.9 1866 0.1193 0.2336 0.2687 0.1789 0.2551 0.06589
8670 M 15.46 19.48 101.7 748.9 0.1092 0.1223 0.1466 0.08087 0.1931 0.05796 0.4743 0.7859 3.094 48.31 0.00624 0.01484 0.02813 0.01093 0.01397 0.002461 19.26 26 124.9 1156 0.1546 0.2394 0.3791 0.1514 0.2837 0.08019
907915 B 12.4 17.68 81.47 467.8 0.1054 0.1316 0.07741 0.02799 0.1811 0.07102 0.1767 1.46 2.204 15.43 0.01 0.03295 0.04861 0.01167 0.02187 0.006005 12.88 22.91 89.61 515.8 0.145 0.2629 0.2403 0.0737 0.2556 0.09359
921385 B 11.54 14.44 74.65 402.9 0.09984 0.112 0.06737 0.02594 0.1818 0.06782 0.2784 1.768 1.628 20.86 0.01215 0.04112 0.05553 0.01494 0.0184 0.005512 12.26 19.68 78.78 457.8 0.1345 0.2118 0.1797 0.06918 0.2329 0.08134
927241 M 20.6 29.33 140.1 1265 0.1178 0.277 0.3514 0.152 0.2397 0.07016 0.726 1.595 5.772 86.22 0.006522 0.06158 0.07117 0.01664 0.02324 0.006185 25.74 39.42 184.6 1821 0.165 0.8681 0.9387 0.265 0.4087 0.124
9012000 M 22.01 21.9 147.2 1482 0.1063 0.1954 0.2448 0.1501 0.1824 0.0614 1.008 0.6999 7.561 130.2 0.003978 0.02821 0.03576 0.01471 0.01518 0.003796 27.66 25.8 195 2227 0.1294 0.3885 0.4756 0.2432 0.2741 0.08574
853201 M 17.57 15.05 115 955.1 0.09847 0.1157 0.09875 0.07953 0.1739 0.06149 0.6003 0.8225 4.655 61.1 0.005627 0.03033 0.03407 0.01354 0.01925 0.003742 20.01 19.52 134.9 1227 0.1255 0.2812 0.2489 0.1456 0.2756 0.07919
8611161 B 13.34 15.86 86.49 520 0.1078 0.1535 0.1169 0.06987 0.1942 0.06902 0.286 1.016 1.535 12.96 0.006794 0.03575 0.0398 0.01383 0.02134 0.004603 15.53 23.19 96.66 614.9 0.1536 0.4791 0.4858 0.1708 0.3527 0.1016
911673 B 13.9 16.62 88.97 599.4 0.06828 0.05319 0.02224 0.01339 0.1813 0.05536 0.1555 0.5762 1.392 14.03 0.003308 0.01315 0.009904 0.004832 0.01316 0.002095 15.14 21.8 101.2 718.9 0.09384 0.2006 0.1384 0.06222 0.2679 0.07698
  1. Preparação dos Dados

Os dados foram pré-processados para garantir melhor qualidade nas previsões. As principais etapas incluíram:

Normalização das variáveis numéricas.

Aplicação do SMOTE (Synthetic Minority Oversampling Technique) para balanceamento das classes.

Utilização de PCA (Principal Component Analysis) para redução de dimensionalidade, garantindo menor complexidade e melhor desempenho computacional.

  1. Treinamento dos Modelos

KNN (K-Nearest Neighbors): Algoritmo supervisionado baseado na proximidade dos vizinhos mais próximos.

KMeans (K-Means Clustering): Algoritmo não supervisionado de agrupamento, adaptado para a tarefa de classificação.

Aplicação da Técnicas

Este projeto tem como objetivo avaliar e comparar o desempenho de dois algoritmos de Machine Learning – KNN (K-Nearest Neighbors) e KMeans (K-Means Clustering) – aplicados a um problema de classificação binária. A análise foi conduzida com foco em métricas de desempenho e matrizes de confusão, de forma a compreender vantagens e limitações de cada abordagem.

Implementação do KNN

Accuracy: 0.91 2026-01-20T18:12:08.118769 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/

import numpy as np
import matplotlib.pyplot as plt
from io import StringIO
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
import seaborn as sns
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from imblearn.over_sampling import SMOTE  


plt.figure(figsize=(12,10))

#carregamento da base
df = pd.read_csv('https://raw.githubusercontent.com/MariaLuizazz/MACHINE-LEARNING-PESSOAL/refs/heads/main/dados/breast-cancer.csv')

#Préprocess
#remoção da coluna id pois é irrelevante para o modelo
df = df.drop(columns=['id'])

#conversão de letra para número
label_encoder = LabelEncoder()  
df['diagnosis'] = label_encoder.fit_transform(df['diagnosis'])


#imputação com mediana de valores ausentes nas features concavity_worts e concavity points_worst
df['concavity_mean'].fillna(df['concavity_mean'].median(), inplace=True)
df['concave points_mean'].fillna(df['concave points_mean'].median(), inplace=True)

#escolha de features
# Em vez de usar apenas 2 features
X = df[['radius_mean', 'texture_mean']]
y = df['diagnosis']

#Separação de treino e teste
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)


smote = SMOTE(random_state=42)
X_train_balanced, y_train_balanced = smote.fit_resample(X_train, y_train)



#Treianamento do KNN
knn = KNeighborsClassifier(n_neighbors=11)
knn.fit(X_train_balanced, y_train_balanced) 


#Teste e validação
predictions = knn.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, predictions):.2f}")


# Mapeia os rótulos: 0 -> Benigno, 1 -> Maligno
labels_map = {0: "Benigno", 1: "Maligno"}
y_labels = y.map(labels_map)


#Preparação para o gráfico da fronteira de decisão(malha de visualização)
h = 0.02
x_min, x_max = X.iloc[:, 0].min() - 1, X.iloc[:, 0].max() + 1
y_min, y_max = X.iloc[:, 1].min() - 1, X.iloc[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),np.arange(y_min, y_max, h))

#Prevendo classe em cada ponto
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

#gráfico final
plt.contourf(xx, yy, Z, cmap=plt.cm.RdYlGn_r, alpha=0.3)
sns.scatterplot(x=X.iloc[:, 0], y=X.iloc[:, 1], hue=y_labels, style=y_labels, palette={'Benigno': 'green', 'Maligno': 'red'}, s=100) #motivooooooo do errroo
plt.xlabel("radius_mean")
plt.ylabel("texture_mean")
plt.title("KNN Decision Boundary (k=11) - Diagnóstico de Câncer (Com Balanceamento SMOTE)")
plt.legend(title="Diagnóstico")  



#Exibição do gráfico
buffer = StringIO()
plt.savefig(buffer, format="svg", transparent=True)
print(buffer.getvalue())

Implementação do KMEANS

2026-01-20T18:12:08.379773 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
import numpy as np
import matplotlib.pyplot as plt
from io import StringIO
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import pandas as pd


df = pd.read_csv('https://raw.githubusercontent.com/MariaLuizazz/MACHINE-LEARNING-PESSOAL/refs/heads/main/dados/breast-cancer.csv')

# Features
X = df.drop(columns=['diagnosis', 'id'])



scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)


kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=100, random_state=42)
labels = kmeans.fit_predict(X_pca)

# Adicionar clusters ao dataframe
df['Cluster'] = labels

plt.figure(figsize=(10, 8))
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=labels, cmap='viridis', s=50)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
            c='red', marker='*', s=200, label='Centróides')
plt.title('Clusters após redução de dimensionalidade (PCA)')
plt.xlabel('Componente Principal 1')
plt.ylabel('Componente Principal 2')
plt.legend()
plt.show()




buffer = StringIO()
plt.savefig(buffer, format="svg", transparent=True)
print(buffer.getvalue())

Matrizes de Confusão

Matriz de Confusão - KNN

Previsto Benigno Previsto Maligno
Real Benigno 99 8
Real Maligno 7 57

Matriz de Confusão - KMeans

Previsto Benigno Previsto Maligno
Real Benigno 354 3
Real Maligno 53 159

Avaliação dos Modelos

Matriz de Confusão - KNN

Previsto Benigno Previsto Maligno
Real Benigno 99 8
Real Maligno 7 57
  • Acurácia: 0.912
  • Precisão: 0.877
  • Recall: 0.891
  • F1-score: 0.884

Matriz de Confusão - KMeans

Previsto Benigno Previsto Maligno
Real Benigno 354 3
Real Maligno 53 159
  • Acurácia: 0.902
  • Precisão: 0.981
  • Recall: 0.750
  • F1-score: 0.850

Comparação de Métricas

Modelo Acurácia Precisão Recall F1-score
KNN 0.912 0.877 0.891 0.884
KMeans 0.902 0.981 0.750 0.850

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.decomposition import PCA
from sklearn.metrics import confusion_matrix, classification_report, accuracy_score, precision_score, recall_score, f1_score
from imblearn.over_sampling import SMOTE
from sklearn.cluster import KMeans
from scipy.stats import mode

df = pd.read_csv('https://raw.githubusercontent.com/MariaLuizazz/MACHINE-LEARNING-PESSOAL/refs/heads/main/dados/breast-cancer.csv')

# Pré-processamento
df = df.drop(columns=['id'])
label_encoder = LabelEncoder()
df['diagnosis'] = label_encoder.fit_transform(df['diagnosis'])

# Corrigir valores ausentes
df['concavity_mean'].fillna(df['concavity_mean'].median(), inplace=True)
df['concave points_mean'].fillna(df['concave points_mean'].median(), inplace=True)

# Features selecionadas
X = df[['radius_mean', 'texture_mean', 'perimeter_mean', 'area_mean',
        'smoothness_mean', 'compactness_mean', 'concavity_mean']]
y = df['diagnosis']

#knn
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)


X_train, X_test, y_train, y_test = train_test_split(
    X_pca, y, test_size=0.3, random_state=42, stratify=y
)

# Balanceamento com SMOTE
smote = SMOTE(random_state=42)
X_train_bal, y_train_bal = smote.fit_resample(X_train, y_train)

# Treinamento do KNN
knn = KNeighborsClassifier(n_neighbors=11)
knn.fit(X_train_bal, y_train_bal)

# Predição
y_pred_knn = knn.predict(X_test)
cm_knn = confusion_matrix(y_test, y_pred_knn)

# Métricas KNN
acc_knn = accuracy_score(y_test, y_pred_knn)
prec_knn = precision_score(y_test, y_pred_knn)
rec_knn = recall_score(y_test, y_pred_knn)
f1_knn = f1_score(y_test, y_pred_knn)


# Modelo 2: KMeans
scaler_full = StandardScaler()
X_scaled_full = scaler_full.fit_transform(X)

pca_full = PCA(n_components=2)
X_pca_full = pca_full.fit_transform(X_scaled_full)

kmeans = KMeans(n_clusters=2, init='k-means++', max_iter=100, random_state=42, n_init=10)
clusters = kmeans.fit_predict(X_pca_full)

# Mapear clusters para classes reais
mapping = {}
for cluster in np.unique(clusters):
    mask = clusters == cluster
    mapping[cluster] = mode(y[mask], keepdims=True).mode[0]

y_pred_kmeans = [mapping[c] for c in clusters]
cm_kmeans = confusion_matrix(y, y_pred_kmeans)

# Métricas KMeans
acc_kmeans = accuracy_score(y, y_pred_kmeans)
prec_kmeans = precision_score(y, y_pred_kmeans)
rec_kmeans = recall_score(y, y_pred_kmeans)
f1_kmeans = f1_score(y, y_pred_kmeans)


# Impressão em Markdown
def matriz_markdown(cm, labels, titulo):
    md = f"### {titulo}\n\n"
    md += f"|                 | Previsto {labels[0]} | Previsto {labels[1]} |\n"
    md += f"|-----------------|------------------|------------------|\n"
    md += f"| **Real {labels[0]}** | {cm[0,0]}              | {cm[0,1]}               |\n"
    md += f"| **Real {labels[1]}** | {cm[1,0]}              | {cm[1,1]}               |\n"
    return md

print(matriz_markdown(cm_knn, ["Benigno", "Maligno"], "Matriz de Confusão - KNN"))
print(f"- Acurácia: {acc_knn:.3f}\n- Precisão: {prec_knn:.3f}\n- Recall: {rec_knn:.3f}\n- F1-score: {f1_knn:.3f}\n")

print(matriz_markdown(cm_kmeans, ["Benigno", "Maligno"], "Matriz de Confusão - KMeans"))
print(f"- Acurácia: {acc_kmeans:.3f}\n- Precisão: {prec_kmeans:.3f}\n- Recall: {rec_kmeans:.3f}\n- F1-score: {f1_kmeans:.3f}\n")


# Comparação lado a lado em Markdown
comparacao = f"""
### Comparação de Métricas

| Modelo   | Acurácia | Precisão | Recall | F1-score |
|----------|----------|----------|--------|----------|
| **KNN**  | {acc_knn:.3f} | {prec_knn:.3f} | {rec_knn:.3f} | {f1_knn:.3f} |
| **KMeans**| {acc_kmeans:.3f} | {prec_kmeans:.3f} | {rec_kmeans:.3f} | {f1_kmeans:.3f} |
"""
print(comparacao)

Comparação dos Resultados

A avaliação dos dois modelos (KNN e KMeans) permitiu observar diferenças importantes em termos de desempenho, destacando pontos fortes e limitações de cada abordagem.

O modelo KNN apresentou uma acurácia de 91,2%, com métricas balanceadas entre precisão (0,877), recall (0,891) e F1-score (0,884). Isso indica que o algoritmo teve um bom equilíbrio entre identificar corretamente os casos benignos e malignos, sendo mais consistente no tratamento das duas classes. No entanto, a precisão foi ligeiramente inferior, o que significa que, entre os casos previstos como malignos, houve uma proporção maior de falsos positivos em comparação ao KMeans.

Já o modelo KMeans, por se tratar de um algoritmo de aprendizado não supervisionado, surpreendeu ao alcançar uma acurácia de 90,2%, próxima à do KNN. Seu destaque foi a alta precisão (0,981), ou seja, quase todas as amostras classificadas como malignas realmente pertenciam a essa classe. Porém, essa alta precisão veio acompanhada de uma queda no recall (0,750), mostrando que o KMeans deixou de identificar corretamente uma parcela considerável dos casos malignos, classificando-os como benignos. Isso é crítico em contextos sensíveis, como o diagnóstico médico, em que falsos negativos podem trazer riscos significativos.

  • De forma geral, pode-se afirmar que:

O KNN é mais equilibrado e confiável para cenários em que tanto falsos positivos quanto falsos negativos precisam ser controlados.

O KMeans é vantajoso em termos de precisão, mas pode não ser o mais indicado em situações em que a detecção completa dos casos positivos (alto recall) é essencial.

Portanto, a escolha entre os dois modelos dependerá diretamente do contexto de aplicação: se o objetivo for minimizar falsos negativos, o KNN se mostra mais adequado; se o objetivo for garantir maior segurança nas classificações positivas, o KMeans pode ser preferido.