Skip to content

K-Means

Acurácia do K-Means para prever 'Survived': 0.67 Matriz de confusão: [[450 99] [191 151]] 2025-11-30T20:15:42.690009 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler, LabelEncoder
import kagglehub
import os
from io import StringIO
import numpy as np
from sklearn.metrics import accuracy_score, confusion_matrix



path = kagglehub.dataset_download("yasserh/titanic-dataset")
file_path = os.path.join(path, "Titanic-Dataset.csv")
df = pd.read_csv(file_path)



features = df[['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare']].copy()
labels_true = df['Survived'].copy()

# Preprocessamento
features['Sex'] = LabelEncoder().fit_transform(features['Sex'])
features['Age'].fillna(features['Age'].median(), inplace=True)

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

kmeans = KMeans(n_clusters=2, init='k-means++', max_iter=100, random_state=42, n_init=10)
labels = kmeans.fit_predict(X_scaled)
buffer = StringIO()
plt.savefig(buffer, format="svg", transparent=True)



# K-Means
kmeans = KMeans(n_clusters=2, init='k-means++', max_iter=100, random_state=42, n_init=10)
labels_pred = kmeans.fit_predict(X_scaled)

# Ajuste de rótulo (clusters podem estar invertidos)
if accuracy_score(labels_true, labels_pred) < accuracy_score(labels_true, 1-labels_pred):
    labels_pred = 1-labels_pred

# Avaliação
acc = accuracy_score(labels_true, labels_pred)
cm = confusion_matrix(labels_true, labels_pred)
print(f"Acurácia do K-Means para prever 'Survived': {acc:.2f}")
print("Matriz de confusão:")
print(cm)

# Visualização dos clusters
x_var = 'Age'
y_var = 'Fare'
x_idx = features.columns.get_loc(x_var)
y_idx = features.columns.get_loc(y_var)

plt.figure(figsize=(10, 8))
plt.scatter(X_scaled[:, x_idx], X_scaled[:, y_idx], c=labels_pred, cmap='viridis', s=50)
plt.scatter(kmeans.cluster_centers_[:, x_idx], kmeans.cluster_centers_[:, y_idx],
            c='red', marker='*', s=200, label='Centroids')
plt.title("K-Means Clustering - Titanic Dataset")
plt.xlabel(f"{x_var} (scaled)")
plt.ylabel(f"{y_var} (scaled)")
plt.legend()

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

KNN

Accuracy (KNN com k=5): 0.66 Classification Report: precision recall f1-score support Não Sobreviveu 0.68 0.77 0.72 126 Sobreviveu 0.60 0.49 0.54 89 accuracy 0.66 215 macro avg 0.64 0.63 0.63 215 weighted avg 0.65 0.66 0.65 215 Confusion Matrix: [[97 29] [45 44]] 2025-11-30T20:15:43.110466 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

import numpy as np
import matplotlib.pyplot as plt
from io import StringIO
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
from sklearn.preprocessing import StandardScaler
import seaborn as sns
import pandas as pd
import kagglehub
import os

# 1. CARREGAMENTO E PRÉ-PROCESSAMENTO DE DADOS

# Baixar o dataset Titanic via kagglehub
path = kagglehub.dataset_download("yasserh/titanic-dataset")
file_path = os.path.join(path, "Titanic-Dataset.csv")
df = pd.read_csv(file_path)

# Selecionar features numéricas: Age, Fare, Pclass
# Variável alvo binária: Survived (0 = não sobreviveu, 1 = sobreviveu)
X = df[['Pclass', 'Age', 'Fare']].copy()

# Variável alvo binária
y = df['Survived'].copy()

# Limpeza dos dados (remover linhas com valores faltantes)
data = X.copy()
data['Survived'] = y
data = data.dropna()

X_clean = data[['Pclass', 'Age', 'Fare']]
y_clean = data['Survived']

# 2. ESCALONAMENTO DOS DADOS (CRÍTICO PARA KNN)
scaler = StandardScaler()
# Ajustar e transformar as features
X_scaled = scaler.fit_transform(X_clean)
X_scaled_df = pd.DataFrame(X_scaled, columns=X_clean.columns, index=X_clean.index)


# 3. DIVISÃO TREINO/TESTE
# Usamos os dados escalonados (X_scaled_df) para o treino
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled_df, y_clean,
    test_size=0.3,
    random_state=42
)

# 4. TREINAMENTO E AVALIAÇÃO DO MODELO KNN
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
predictions = knn.predict(X_test)

# Métricas de desempenho
accuracy = accuracy_score(y_test, predictions)
print(f"Accuracy (KNN com k=5): {accuracy:.2f}")
print("\nClassification Report:")
print(classification_report(y_test, predictions, target_names=['Não Sobreviveu', 'Sobreviveu']))

# Matriz de confusão
cm = confusion_matrix(y_test, predictions)
print("\nConfusion Matrix:")
print(cm)


# 5. VISUALIZAÇÃO DA FRONTEIRA DE DECISÃO

# Para visualização em 2D, vamos usar apenas Age e Fare
X_2d = X_scaled_df[['Age', 'Fare']].copy()
X_train_2d, X_test_2d, y_train_2d, y_test_2d = train_test_split(
    X_2d, y_clean,
    test_size=0.3,
    random_state=42
)

# Treinar KNN com os dados 2D
knn_2d = KNeighborsClassifier(n_neighbors=5)
knn_2d.fit(X_train_2d, y_train_2d)

# Reduzir a amostra para visualização (para o scatter plot)
sample_size = min(1000, len(X_2d))
# Usamos o índice para garantir que X_vis e y_vis correspondam
X_vis = X_2d.sample(sample_size, random_state=42)
y_vis = y_clean.loc[X_vis.index]

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

# Definir os limites da grade a partir dos dados ESCALONADOS
h = 0.05 
x_min, x_max = X_2d['Age'].min() - 0.5, X_2d['Age'].max() + 0.5
y_min, y_max = X_2d['Fare'].min() - 0.5, X_2d['Fare'].max() + 0.5

xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))

# Criar a grade de pontos para predição
grid_points = np.c_[xx.ravel(), yy.ravel()]

# Previsão KNN para cada ponto da grade
Z = knn_2d.predict(grid_points)
Z = Z.reshape(xx.shape)

# Plot da fronteira e dos pontos
plt.contourf(xx, yy, Z, cmap=plt.cm.RdYlBu, alpha=0.3)
sns.scatterplot(x=X_vis['Age'], y=X_vis['Fare'], hue=y_vis, style=y_vis,
                palette="deep", s=100, legend='full')

# Configurar legenda e rótulos
handles, _ = plt.gca().get_legend_handles_labels()
plt.legend(handles=handles, labels=['Não Sobreviveu', 'Sobreviveu'], title="Titanic - Survivability")

plt.xlabel("Age (Scaled)")
plt.ylabel("Fare (Scaled)")
plt.title("KNN Decision Boundary (k=5) - Titanic Dataset")


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

Avaliação

Introdução

O objetivo desta atividade é utilizar dois algoritmos de Machine Learning --- KNN (K-Nearest Neighbors) e K-Means Clustering --- para prever uma variável categórica.\ O dataset escolhido foi o Titanic, cujo objetivo principal é prever a variável Survived, que indica se um passageiro sobreviveu (1) ou não (0).


1. Dataset Utilizado

O dataset do Titanic contém informações como idade, tarifa paga, classe, sexo, entre outros atributos.\ Para este projeto, utilizamos especialmente as variáveis Age e Fare, devidamente normalizadas, para visualizar o comportamento dos algoritmos.


2. Modelo K-Means

2.1 Objetivo

Embora o K-Means seja um algoritmo não supervisionado, ele pode ser usado para tentar identificar agrupamentos que se aproximem da variável categórica "Survived".

2.2 Resultados

  • Acurácia: 0.67\

  • Matriz de Confusão:

    [[450  99]
     [191 151]]
    

2.3 Interpretação

  • O K-Means conseguiu formar dois clusters que, parcialmente, se alinham às classes de sobrevivência.

  • O gráfico demonstra a distribuição dos passageiros por "Age" e "Fare", com os centróides marcados em vermelho.


3. Modelo KNN (k = 5)

3.1 Objetivo

O KNN é um algoritmo supervisionado que classifica um novo ponto com base na proximidade de seus vizinhos mais próximos.\ Neste caso, buscamos prever diretamente a variável Survived.

3.2 Resultados

  • Acurácia: 0.65\

  • Classification Report:

    Não Sobreviveu: precision=0.68, recall=0.75, f1=0.72
    Sobreviveu:    precision=0.59, recall=0.51, f1=0.55
    
  • Matriz de Confusão:

    [[95 31]
     [44 45]]
    

3.3 Interpretação

  • O modelo tem desempenho moderado, com melhor recall para a classe "Não Sobreviveu".
  • O gráfico mostra a fronteira de decisão do KNN, onde áreas são classificadas como propensas à sobrevivência ou não.
  • A distribuição dos passageiros demonstra forte sobreposição entre classes, dificultando o trabalho do KNN.

4. Comparação Geral entre K-Means e KNN

Critério K-Means KNN


Tipo Não supervisionado Supervisionado Objetivo Criar clusters Classificar diretamente Acurácia obtida 0.67 0.65 Utilidade Explorar padrões Predição efetiva

Observações

  • Mesmo sendo não supervisionado, o K-Means obteve acurácia semelhante ao KNN, o que demonstra forte sobreposição de padrões no dataset.
  • O KNN sofre com limites pouco definidos entre as classes, como visto na fronteira de decisão.

5. Conclusão

Ambos os modelos apresentaram desempenho similar, mas o KNN é mais apropriado para a tarefa, pois é supervisionado.\ O K-Means, apesar de não ser ideal para classificação, oferece insights sobre agrupamentos naturais no dataset.

O experimento ilustra bem as diferenças entre algoritmos supervisionados e não supervisionados, bem como suas limitações ao lidar com dados reais e complexos como o Titanic.