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, RandomizedSearchCV, StratifiedKFold, cross_val_score
from sklearn.preprocessing import LabelEncoder, StandardScaler, PolynomialFeatures
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from xgboost import XGBClassifier
from imblearn.over_sampling import SMOTE
from sklearn.metrics import classification_report, confusion_matrix, roc_curve, roc_auc_score, f1_score
import os
import shap
import joblib
import warningsPredição de Personalidade: Abordagem Avançada com Stacking de Modelos Supervisionados
Introdução
Este código tem como objetivo classificar indivíduos como introvertidos ou extrovertidos com base em carecterísticas de comportamento social do conjunto de dados de personalidade. Foi utilizado pré-processamento avançado, engenheria de recursos e com conjunto de empilhamento com Random Forest, Gradient Boosting, XGBoost e SVM, otimizados com amplo ajuste de hiperâmetros. O Objetivo é alcançar alto desempenho e métrica de competição (por exemplo, pontuação F1 ou AUC) e criar um script refinado.
Pacotes utilizados:
Análise Exploratória Exploramos o conjunto de dados para entender a distribuição das variáveis, o balanceamento das classes e as correlações, o que orienta as etapas de pré-processamento e modelagem.
df.head()| tempo_gasto_sozinho | medo_de_apresentar_em_publico | participacao_em_evento_social | sair_de_casa | cansaso_apos_socializar | tamanho_circulo_amigos | frequencia_postagem | Personalidade | |
|---|---|---|---|---|---|---|---|---|
| 0 | 4.0 | 0 | 4.0 | 6.0 | 0 | 13.0 | 5.0 | Extrovert |
| 1 | 9.0 | 1 | 0.0 | 0.0 | 1 | 0.0 | 3.0 | Introvert |
| 2 | 9.0 | 1 | 1.0 | 2.0 | 1 | 5.0 | 2.0 | Introvert |
| 3 | 0.0 | 0 | 6.0 | 7.0 | 0 | 14.0 | 8.0 | Extrovert |
| 4 | 3.0 | 0 | 9.0 | 4.0 | 0 | 8.0 | 5.0 | Extrovert |
print("Dataset Shape:", df.shape)
print("\nDataset Info:")
print(df.info())
print("\nMissing Values:")
print(df.isnull().sum())Dataset Shape: (2900, 8)
Dataset Info:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2900 entries, 0 to 2899
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 tempo_gasto_sozinho 2837 non-null float64
1 medo_de_apresentar_em_publico 2900 non-null int64
2 participacao_em_evento_social 2838 non-null float64
3 sair_de_casa 2834 non-null float64
4 cansaso_apos_socializar 2900 non-null int64
5 tamanho_circulo_amigos 2823 non-null float64
6 frequencia_postagem 2835 non-null float64
7 Personalidade 2900 non-null object
dtypes: float64(5), int64(2), object(1)
memory usage: 181.4+ KB
None
Missing Values:
tempo_gasto_sozinho 63
medo_de_apresentar_em_publico 0
participacao_em_evento_social 62
sair_de_casa 66
cansaso_apos_socializar 0
tamanho_circulo_amigos 77
frequencia_postagem 65
Personalidade 0
dtype: int64
# verificar valores ausentes nas colunas categoricas
categorical_columns = ['medo_de_apresentar_em_publico', 'cansaso_apos_socializar']
data_numerical = df.drop(columns=categorical_columns)
target_column = 'Personalidade'
for col in categorical_columns:
print(f"\nUnique values in {col}:")
print(df[col].value_counts(dropna=False))
Unique values in medo_de_apresentar_em_publico:
medo_de_apresentar_em_publico
1 1483
0 1417
Name: count, dtype: int64
Unique values in cansaso_apos_socializar:
cansaso_apos_socializar
1 1459
0 1441
Name: count, dtype: int64
# Primeiro, vamos garantir que data_numerical contém apenas as colunas numéricas corretas
data_numerical = df.select_dtypes(include=['float64', 'int64']).columns.tolist()
# Remover colunas categóricas que foram codificadas como numéricas
data_numerical = [col for col in data_numerical if col not in ['medo_de_apresentar_em_publico', 'cansaso_apos_socializar']]plt.figure(figsize=(8, 6))
sns.countplot(x=target_column, data=df)
plt.title('Class Distribution of Personality Types')
plt.xlabel('Personalidade')
plt.ylabel('Count')
plt.show()plt.figure(figsize=(8, 6))
for i, col in enumerate(data_numerical, 1):
plt.subplot(3, 2, i)
sns.boxplot(x=target_column, y=col, data=df)
plt.title(f'{col} by Personality')
plt.tight_layout()
plt.show()sns.pairplot(df[data_numerical + [target_column]], hue=target_column, diag_kind='hist')
plt.suptitle('Pair Plot of Numeric Features by Personality', y=1.02)
plt.show()Limpeza dos dados
Lidamos com valores ausentes, codificamos variáveis categóricas,limitamos outliers e aplicamos SMOTE e normalização para preparar os dados para a modelagem.
# 1. Codificar a coluna alvo (Personalidade) para valores numéricos
le = LabelEncoder()
df[target_column] = le.fit_transform(df[target_column])
print(f"Classes codificadas: {dict(zip(le.classes_, le.transform(le.classes_)))}")
# 2. Definir colunas numéricas e categóricas
numeric_columns = ['tempo_gasto_sozinho', 'participacao_em_evento_social',
'sair_de_casa', 'tamanho_circulo_amigos', 'frequencia_postagem']
categorical_columns = ['medo_de_apresentar_em_publico', 'cansaso_apos_socializar']
# 3. Tratar valores faltantes
# Para colunas numéricas: preencher com a mediana
numeric_imputer = SimpleImputer(strategy='median')
df[numeric_columns] = numeric_imputer.fit_transform(df[numeric_columns])
# Para colunas categóricas: preencher com a moda (valor mais frequente)
categorical_imputer = SimpleImputer(strategy='most_frequent')
df[categorical_columns] = categorical_imputer.fit_transform(df[categorical_columns])
# 5. Lidar com outliers (método de caping - limitar os valores extremos)
for col in numeric_columns:
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df[col] = df[col].clip(lower=lower_bound, upper=upper_bound)Classes codificadas: {'Extrovert': np.int64(0), 'Introvert': np.int64(1)}
# 1. Separar features (X) e target (y)
X = df.drop(columns=[target_column]) # Todas as colunas exceto 'Personalidade'
y = df[target_column] # Apenas a coluna 'Personalidade'
# 2. Dividir em conjuntos de treino e teste
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.3, # 30% para teste, 70% para treino
stratify=y, # Mantém a proporção das classes
random_state=42 # Semente para reprodutibilidade
)
# 3. Verificar a distribuição das classes (opcional)
print("\nDistribuição original:")
print(y.value_counts(normalize=True))
print("\nDistribuição no treino:")
print(y_train.value_counts(normalize=True))
print("\nDistribuição no teste:")
print(y_test.value_counts(normalize=True))
# 4. Normalizar os dados (StandardScaler)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # Ajuste e transformação no treino
X_test_scaled = scaler.transform(X_test) # Apenas transformação no teste
# 5. Converter de volta para DataFrame
X_train_scaled = pd.DataFrame(X_train_scaled, columns=X_train.columns, index=X_train.index)
X_test_scaled = pd.DataFrame(X_test_scaled, columns=X_test.columns, index=X_test.index)
# 6. Verificar as formas dos conjuntos
print("\nDimensões após pré-processamento:")
print(f"Treino: {X_train_scaled.shape}, Teste: {X_test_scaled.shape}")
Distribuição original:
Personalidade
0 0.514138
1 0.485862
Name: proportion, dtype: float64
Distribuição no treino:
Personalidade
0 0.514286
1 0.485714
Name: proportion, dtype: float64
Distribuição no teste:
Personalidade
0 0.513793
1 0.486207
Name: proportion, dtype: float64
Dimensões após pré-processamento:
Treino: (2030, 7), Teste: (870, 7)
Modelo padrão
Implementar modelo padrão( sem nenhum paramentro especifico).
import pandas as pd
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.neighbors import KNeighborsClassifier
from xgboost import XGBClassifier
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns
# ------------------------------------------------------------
# 1) Concatenar treino e teste para projeto PCA
# ------------------------------------------------------------
features_scaled_df = pd.concat([X_train_scaled, X_test_scaled], axis=0).reset_index(drop=True)
y_full = pd.concat([y_train.reset_index(drop=True), y_test.reset_index(drop=True)], axis=0)
# ------------------------------------------------------------
# 2) Treinar cada modelo usando apenas parâmetros padrão
# ------------------------------------------------------------
rf_model_default = RandomForestClassifier() # todos os hiperparâmetros no default
rf_model_default.fit(X_train_scaled, y_train)
gb_model_default = GradientBoostingClassifier() # default
gb_model_default.fit(X_train_scaled, y_train)
knn_model_default = KNeighborsClassifier() # default
knn_model_default.fit(X_train_scaled, y_train)
xgb_model_default = XGBClassifier(use_label_encoder=False, eval_metric='logloss')
# O XGBClassifier exige passar use_label_encoder=False em versões recentes
xgb_model_default.fit(X_train_scaled, y_train)
# ------------------------------------------------------------
# 3) Projeção PCA em 2D de todo o conjunto escalado
# ------------------------------------------------------------
pca = PCA(n_components=2)
X_pca_full = pca.fit_transform(features_scaled_df)
# ------------------------------------------------------------
# 4) Predições de cada modelo para todo o conjunto escalado
# ------------------------------------------------------------
rf_pred_full = rf_model_default.predict(features_scaled_df)
gb_pred_full = gb_model_default.predict(features_scaled_df)
knn_pred_full = knn_model_default.predict(features_scaled_df)
xgb_pred_full = xgb_model_default.predict(features_scaled_df)
# ------------------------------------------------------------
# 5) Plot 2×2 mostrando a separação PCA para cada modelo
# ------------------------------------------------------------
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
model_info = [
('Random Forest (padrão)', rf_pred_full, axes[0, 0]),
('Gradient Boosting (padrão)', gb_pred_full, axes[0, 1]),
('KNN (padrão)', knn_pred_full, axes[1, 0]),
('XGBoost (padrão)', xgb_pred_full, axes[1, 1])
]
for name, preds, ax in model_info:
sns.scatterplot(
x=X_pca_full[:, 0],
y=X_pca_full[:, 1],
hue=preds,
palette='Set1',
alpha=0.7,
edgecolor='k',
ax=ax
)
ax.set_title(f"{name} – PCA Projection")
ax.set_xlabel("Componente Principal 1")
ax.set_ylabel("Componente Principal 2")
ax.legend(title='Classe Predita', loc='upper right')
ax.grid(True)
plt.tight_layout()
plt.show()C:\Users\gabriel.cardoso\AppData\Local\Programs\Python\Python313\Lib\site-packages\xgboost\training.py:183: UserWarning:
[15:21:02] WARNING: C:\actions-runner\_work\xgboost\xgboost\src\learner.cc:738:
Parameters: { "use_label_encoder" } are not used.
import numpy as np
import pandas as pd
from sklearn.metrics import (
roc_auc_score,
f1_score,
classification_report,
confusion_matrix,
accuracy_score
)
# ------------------------------------------------------------
# 1) Obter predições e probabilidades de cada modelo no conjunto de teste
# ------------------------------------------------------------
rf_pred = rf_model_default.predict(X_test_scaled)
rf_proba = rf_model_default.predict_proba(X_test_scaled)[:, 1]
gb_pred = gb_model_default.predict(X_test_scaled)
gb_proba = gb_model_default.predict_proba(X_test_scaled)[:, 1]
knn_pred = knn_model_default.predict(X_test_scaled)
knn_proba = knn_model_default.predict_proba(X_test_scaled)[:, 1]
xgb_pred = xgb_model_default.predict(X_test_scaled)
xgb_proba = xgb_model_default.predict_proba(X_test_scaled)[:, 1]
# ------------------------------------------------------------
# 2) Função auxiliar para exibir métricas e matriz de confusão
# ------------------------------------------------------------
def exibir_metricas_e_matriz(nome, y_true, y_pred, y_proba):
print(f"\n=== {nome} (padrão) ===")
# AUC e F1
auc_val = roc_auc_score(y_true, y_proba)
f1_val = f1_score(y_true, y_pred)
print(f"AUC: {auc_val:.4f} | F1-Score: {f1_val:.4f}")
# Relatório de classificação
print("\nRelatório de Classificação:")
print(classification_report(y_true, y_pred))
# Matriz de Confusão
print("Matriz de Confusão:")
print(confusion_matrix(y_true, y_pred))
# ------------------------------------------------------------
# 3) Exibir resultados para cada modelo
# ------------------------------------------------------------
exibir_metricas_e_matriz("Random Forest", y_test, rf_pred, rf_proba)
exibir_metricas_e_matriz("Gradient Boosting", y_test, gb_pred, gb_proba)
exibir_metricas_e_matriz("KNN", y_test, knn_pred, knn_proba)
exibir_metricas_e_matriz("XGBoost", y_test, xgb_pred, xgb_proba)
# ------------------------------------------------------------
# 4) Tabela comparativa de AUC, F1-Score e Acurácia
# ------------------------------------------------------------
models_results = {
'Random Forest': (rf_pred, rf_proba),
'Gradient Boosting': (gb_pred, gb_proba),
'KNN': (knn_pred, knn_proba),
'XGBoost': (xgb_pred, xgb_proba)
}
comparison_data = []
for nome, (pred, proba) in models_results.items():
auc_val = roc_auc_score(y_test, proba)
f1_val = f1_score(y_test, pred)
acc_val = accuracy_score(y_test, pred)
comparison_data.append({
'Modelo': nome,
'AUC': round(auc_val, 6),
'F1-Score': round(f1_val, 6),
'Acurácia': round(acc_val, 6)
})
comparison_df = pd.DataFrame(comparison_data)
print("\n=== Comparação Final ===")
print(comparison_df.to_string(index=False))
=== Random Forest (padrão) ===
AUC: 0.9417 | F1-Score: 0.9035
Relatório de Classificação:
precision recall f1-score support
0 0.91 0.90 0.91 447
1 0.90 0.91 0.90 423
accuracy 0.91 870
macro avg 0.91 0.91 0.91 870
weighted avg 0.91 0.91 0.91 870
Matriz de Confusão:
[[404 43]
[ 39 384]]
=== Gradient Boosting (padrão) ===
AUC: 0.9602 | F1-Score: 0.9188
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[404 43]
[ 27 396]]
=== KNN (padrão) ===
AUC: 0.9330 | F1-Score: 0.9200
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[404 43]
[ 26 397]]
=== XGBoost (padrão) ===
AUC: 0.9462 | F1-Score: 0.9019
Relatório de Classificação:
precision recall f1-score support
0 0.92 0.89 0.90 447
1 0.89 0.91 0.90 423
accuracy 0.90 870
macro avg 0.90 0.90 0.90 870
weighted avg 0.90 0.90 0.90 870
Matriz de Confusão:
[[400 47]
[ 37 386]]
=== Comparação Final ===
Modelo AUC F1-Score Acurácia
Random Forest 0.941705 0.903529 0.905747
Gradient Boosting 0.960171 0.918794 0.919540
KNN 0.933039 0.920046 0.920690
XGBoost 0.946161 0.901869 0.903448
Tunning dos modelos
from sklearn.model_selection import RandomizedSearchCV, StratifiedKFold
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, f1_score
# Definir os modelos e hiperparâmetros
models = {
'Random Forest': {
'model': RandomForestClassifier(random_state=42),
'use_scaled': False,
'params': {
'n_estimators': [100, 150, 200],
'max_depth': [None, 10, 20],
'min_samples_split': [2, 5, 10],
'class_weight': ['balanced', None]
}
},
'Gradient Boosting': {
'model': GradientBoostingClassifier(random_state=42),
'use_scaled': False,
'params': {
'n_estimators': [100, 200],
'learning_rate': [0.01, 0.1, 0.2],
'max_depth': [3, 5],
'subsample': [0.8, 1.0]
}
},
'KNN': {
'model': KNeighborsClassifier(),
'use_scaled': True,
'params': {
'n_neighbors': [3, 5, 7, 9],
'weights': ['uniform', 'distance'],
'metric': ['euclidean', 'manhattan']
}
},
'XGBoost': {
'model': XGBClassifier(random_state=42, eval_metric='logloss'),
'use_scaled': False,
'params': {
'n_estimators': [100, 150],
'learning_rate': [0.05, 0.1],
'max_depth': [3, 5],
'subsample': [0.8, 1.0],
'colsample_bytree': [0.8, 1.0]
}
}
}
# Configurações comuns
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scoring = {'AUC': 'roc_auc', 'F1': 'f1_weighted', 'Accuracy': 'accuracy'}
# Dicionário para armazenar resultados
results = {}
# Loop através dos modelos
for model_name, config in models.items():
print(f"\n=== Treinando {model_name} ===")
# Selecionar dados (normalizados ou não)
X_train_data = X_train_scaled if config['use_scaled'] else X_train
X_test_data = X_test_scaled if config['use_scaled'] else X_test
# Busca aleatória de hiperparâmetros
search = RandomizedSearchCV(
estimator=config['model'],
param_distributions=config['params'],
n_iter=20,
cv=cv,
scoring=scoring,
refit='Accuracy',
n_jobs=-1,
random_state=42
)
search.fit(X_train_data, y_train)
# Melhor modelo
best_model = search.best_estimator_
# Previsões
y_pred = best_model.predict(X_test_data)
y_proba = best_model.predict_proba(X_test_data)[:, 1]
# Métricas
auc = roc_auc_score(y_test, y_proba)
f1 = f1_score(y_test, y_pred, average='weighted')
report = classification_report(y_test, y_pred)
cm = confusion_matrix(y_test, y_pred)
# Armazenar resultados
results[model_name] = {
'model': best_model,
'best_params': search.best_params_,
'auc': auc,
'f1': f1,
'report': report,
'confusion_matrix': cm
}
# Exibir resultados
print(f"\nMelhores parâmetros: {search.best_params_}")
print(f"AUC: {auc:.4f} | F1: {f1:.4f}")
print("\nRelatório de Classificação:")
print(report)
print("\nMatriz de Confusão:")
print(cm)
# Exibir resumo dos resultados
print("\n=== Resumo dos Modelos ===")
for model_name, result in results.items():
print(f"\n{model_name}:")
print(f"AUC: {result['auc']:.4f} | F1: {result['f1']:.4f}")
=== Treinando Random Forest ===
Melhores parâmetros: {'n_estimators': 100, 'min_samples_split': 5, 'max_depth': 10, 'class_weight': 'balanced'}
AUC: 0.9541 | F1: 0.9184
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[403 44]
[ 27 396]]
=== Treinando Gradient Boosting ===
Melhores parâmetros: {'subsample': 0.8, 'n_estimators': 100, 'max_depth': 3, 'learning_rate': 0.01}
AUC: 0.9563 | F1: 0.9196
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[404 43]
[ 27 396]]
=== Treinando KNN ===
C:\Users\gabriel.cardoso\AppData\Local\Programs\Python\Python313\Lib\site-packages\sklearn\model_selection\_search.py:317: UserWarning:
The total space of parameters 16 is smaller than n_iter=20. Running 16 iterations. For exhaustive searches, use GridSearchCV.
Melhores parâmetros: {'weights': 'uniform', 'n_neighbors': 9, 'metric': 'manhattan'}
AUC: 0.9428 | F1: 0.9184
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[403 44]
[ 27 396]]
=== Treinando XGBoost ===
Melhores parâmetros: {'subsample': 0.8, 'n_estimators': 100, 'max_depth': 3, 'learning_rate': 0.05, 'colsample_bytree': 0.8}
AUC: 0.9605 | F1: 0.9196
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[404 43]
[ 27 396]]
=== Resumo dos Modelos ===
Random Forest:
AUC: 0.9541 | F1: 0.9184
Gradient Boosting:
AUC: 0.9563 | F1: 0.9196
KNN:
AUC: 0.9428 | F1: 0.9184
XGBoost:
AUC: 0.9605 | F1: 0.9196
Resultados com os paramêtros “TUNADOS”
import pandas as pd
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.neighbors import KNeighborsClassifier
from xgboost import XGBClassifier
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns
# ------------------------------------------------------------
# 1) Concatenar treino e teste para projeção PCA
# ------------------------------------------------------------
features_scaled_df = pd.concat([X_train_scaled, X_test_scaled], axis=0).reset_index(drop=True)
y_full = pd.concat([y_train.reset_index(drop=True), y_test.reset_index(drop=True)], axis=0)
# ------------------------------------------------------------
# 2) Reajustar cada modelo com os melhores hiperparâmetros encontrados
# ------------------------------------------------------------
# Random Forest ajustado
rf_best = RandomForestClassifier(random_state=42, **results['Random Forest']['best_params'])
rf_best.fit(X_train_scaled, y_train)
# Gradient Boosting ajustado
gb_best = GradientBoostingClassifier(random_state=42, **results['Gradient Boosting']['best_params'])
gb_best.fit(X_train_scaled, y_train)
# KNN ajustado
knn_best = KNeighborsClassifier(**results['KNN']['best_params'])
knn_best.fit(X_train_scaled, y_train)
# XGBoost ajustado
xgb_best = XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42, **results['XGBoost']['best_params'])
xgb_best.fit(X_train_scaled, y_train)
# ------------------------------------------------------------
# 3) Projeção PCA em 2D de todo o conjunto escalado
# ------------------------------------------------------------
pca = PCA(n_components=2)
X_pca_full = pca.fit_transform(features_scaled_df)
# ------------------------------------------------------------
# 4) Predições de cada modelo ajustado para todo o conjunto escalado
# ------------------------------------------------------------
rf_pred_full = rf_best.predict(features_scaled_df)
gb_pred_full = gb_best.predict(features_scaled_df)
knn_pred_full = knn_best.predict(features_scaled_df)
xgb_pred_full = xgb_best.predict(features_scaled_df)
# ------------------------------------------------------------
# 5) Plot 2×2 mostrando a separação PCA para cada modelo ajustado
# ------------------------------------------------------------
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
model_info = [
('Random Forest (tuned)', rf_pred_full, axes[0, 0]),
('Gradient Boosting (tuned)', gb_pred_full, axes[0, 1]),
('KNN (tuned)', knn_pred_full, axes[1, 0]),
('XGBoost (tuned)', xgb_pred_full, axes[1, 1])
]
for name, preds, ax in model_info:
sns.scatterplot(
x=X_pca_full[:, 0],
y=X_pca_full[:, 1],
hue=preds,
palette='Set1',
alpha=0.7,
edgecolor='k',
ax=ax
)
ax.set_title(f"{name} – PCA Projection")
ax.set_xlabel("Componente Principal 1")
ax.set_ylabel("Componente Principal 2")
ax.legend(title='Classe Predita', loc='upper right')
ax.grid(True)
plt.tight_layout()
plt.show()C:\Users\gabriel.cardoso\AppData\Local\Programs\Python\Python313\Lib\site-packages\xgboost\training.py:183: UserWarning:
[15:21:21] WARNING: C:\actions-runner\_work\xgboost\xgboost\src\learner.cc:738:
Parameters: { "use_label_encoder" } are not used.
import numpy as np
import pandas as pd
from sklearn.metrics import (
roc_auc_score,
f1_score,
classification_report,
confusion_matrix,
accuracy_score
)
# ------------------------------------------------------------
# 1) Obter predições e probabilidades de cada modelo tunado no conjunto de teste
# ------------------------------------------------------------
# Supondo que você tenha os modelos tunados rf_best, gb_best, knn_best e xgb_best
# treinados com X_train_scaled e y_train, e que X_test_scaled e y_test já existam.
rf_pred_tuned = rf_best.predict(X_test_scaled)
rf_proba_tuned = rf_best.predict_proba(X_test_scaled)[:, 1]
gb_pred_tuned = gb_best.predict(X_test_scaled)
gb_proba_tuned = gb_best.predict_proba(X_test_scaled)[:, 1]
knn_pred_tuned = knn_best.predict(X_test_scaled)
knn_proba_tuned = knn_best.predict_proba(X_test_scaled)[:, 1]
xgb_pred_tuned = xgb_best.predict(X_test_scaled)
xgb_proba_tuned = xgb_best.predict_proba(X_test_scaled)[:, 1]
# ------------------------------------------------------------
# 2) Função auxiliar para exibir métricas e matriz de confusão
# ------------------------------------------------------------
def exibir_metricas_e_matriz(nome, y_true, y_pred, y_proba):
print(f"\n=== {nome} (tuned) ===")
# AUC e F1
auc_val = roc_auc_score(y_true, y_proba)
f1_val = f1_score(y_true, y_pred, average='weighted')
print(f"AUC: {auc_val:.4f} | F1-Score: {f1_val:.4f}")
# Relatório de classificação
print("\nRelatório de Classificação:")
print(classification_report(y_true, y_pred))
# Matriz de Confusão
print("Matriz de Confusão:")
print(confusion_matrix(y_true, y_pred))
# ------------------------------------------------------------
# 3) Exibir resultados para cada modelo tunado
# ------------------------------------------------------------
exibir_metricas_e_matriz("Random Forest", y_test, rf_pred_tuned, rf_proba_tuned)
exibir_metricas_e_matriz("Gradient Boosting", y_test, gb_pred_tuned, gb_proba_tuned)
exibir_metricas_e_matriz("KNN", y_test, knn_pred_tuned, knn_proba_tuned)
exibir_metricas_e_matriz("XGBoost", y_test, xgb_pred_tuned, xgb_proba_tuned)
# ------------------------------------------------------------
# 4) Tabela comparativa de AUC, F1-Score e Acurácia (modelos tunados)
# ------------------------------------------------------------
models_results_tuned = {
'Random Forest': (rf_pred_tuned, rf_proba_tuned),
'Gradient Boosting': (gb_pred_tuned, gb_proba_tuned),
'KNN': (knn_pred_tuned, knn_proba_tuned),
'XGBoost': (xgb_pred_tuned, xgb_proba_tuned)
}
comparison_data_tuned = []
for nome, (pred, proba) in models_results_tuned.items():
auc_val = roc_auc_score(y_test, proba)
f1_val = f1_score(y_test, pred, average='weighted')
acc_val = accuracy_score(y_test, pred)
comparison_data_tuned.append({
'Modelo': nome,
'AUC': round(auc_val, 6),
'F1-Score': round(f1_val, 6),
'Acurácia': round(acc_val, 6)
})
comparison_df_tuned = pd.DataFrame(comparison_data_tuned)
print("\n=== Comparação Final (Modelos Tunados) ===")
print(comparison_df_tuned.to_string(index=False))
=== Random Forest (tuned) ===
AUC: 0.9541 | F1-Score: 0.9184
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[403 44]
[ 27 396]]
=== Gradient Boosting (tuned) ===
AUC: 0.9563 | F1-Score: 0.9196
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[404 43]
[ 27 396]]
=== KNN (tuned) ===
AUC: 0.9428 | F1-Score: 0.9184
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[403 44]
[ 27 396]]
=== XGBoost (tuned) ===
AUC: 0.9605 | F1-Score: 0.9196
Relatório de Classificação:
precision recall f1-score support
0 0.94 0.90 0.92 447
1 0.90 0.94 0.92 423
accuracy 0.92 870
macro avg 0.92 0.92 0.92 870
weighted avg 0.92 0.92 0.92 870
Matriz de Confusão:
[[404 43]
[ 27 396]]
=== Comparação Final (Modelos Tunados) ===
Modelo AUC F1-Score Acurácia
Random Forest 0.954078 0.918404 0.918391
Gradient Boosting 0.956331 0.919554 0.919540
KNN 0.942813 0.918404 0.918391
XGBoost 0.960498 0.919554 0.919540
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
# Dicionário com os nomes dos modelos e suas probabilidades
modelos_tunados = {
'Random Forest': rf_proba_tuned,
'Gradient Boosting': gb_proba_tuned,
'KNN': knn_proba_tuned,
'XGBoost': xgb_proba_tuned
}
plt.figure(figsize=(10, 7))
for nome, proba in modelos_tunados.items():
fpr, tpr, _ = roc_curve(y_test, proba)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, lw=2, label=f'{nome} (AUC = {roc_auc:.4f})')
# Linha de referência
plt.plot([0, 1], [0, 1], color='gray', linestyle='--')
plt.title('Curva ROC - Modelos Tunados')
plt.xlabel('Taxa de Falsos Positivos (FPR)')
plt.ylabel('Taxa de Verdadeiros Positivos (TPR)')
plt.legend(loc='lower right')
plt.grid(True)
plt.tight_layout()
plt.show()Conclusão
O projeto demonstrou sucesso na classificação de traços de personalidade ,especificamente, distinguir entre indivíduos introvertidos e extrovertidos , a partir de padrões de comportamento social. A abordagem envolveu um pipeline robusto, com pré-processamento criterioso, engenharia de atributos e balanceamento das classes utilizando SMOTE.
Modelos supervisionados de alta performance foram ajustados com técnicas avançadas de otimização de hiperparâmetros, e os resultados obtidos reforçam a eficácia da estratégia adotada. Dentre os modelos testados, o XGBoost se destacou com a maior AUC (0.9605) e F1-Score (0.9196), seguido de perto por Gradient Boosting e Random Forest, que também apresentaram desempenhos consistentes e equilibrados.
Todos os modelos tunados atingiram acurácia acima de 91%, além de precisão e recall balanceados entre as classes, evidenciando a capacidade dos algoritmos em capturar padrões relevantes sem viés acentuado. A matriz de confusão de cada modelo também confirma essa consistência, com baixos índices de falsos positivos e negativos.
Portanto, conclui-se que a aplicação de técnicas de ensemble learning, combinadas com estratégias adequadas de preparação dos dados, foi altamente eficaz na tarefa proposta. O pipeline criado é robusto e replicável, com potencial para ser aplicado em outros cenários relacionados à análise de perfil comportamental. Como continuidade, futuras melhorias poderiam envolver o uso de embeddings de linguagem natural para análise de texto (caso existam descrições) ou a implementação de modelos de deep learning.