Como detetar features irrelevantes com SHAP em Machine Learning
Este tutorial mostra como detetar features irrelevantes em Machine Learning usando o SHAP, uma técnica que explica a contribuição de cada feature para as previsões. Saber quais features são pouco relevantes ajuda a simplificar modelos, reduzir overfitting e acelerar a colocação em produção.
Pré-requisitos
- Python 3.8+ e pip
- Bibliotecas: scikit-learn, xgboost, shap, pandas, numpy, matplotlib
- Conhecimentos básicos de modelação: treino/teste, fitting de um modelo
Passo 1: Porquê usar o SHAP para detetar features irrelevantes
O SHAP (SHapley Additive exPlanations) atribui a cada feature uma contribuição consistente para a previsão. Ao agregar as importâncias SHAP por feature, obtemos uma medida robusta de relevância que considera interações e não apenas correlações simples. Isto evita erros comuns como confiar somente em coeficientes de modelos lineares ou nas importâncias intrínsecas do algoritmo.
Passo 2: Instalar dependências
Instala as bibliotecas necessárias. Este passo é simples e evita problemas de compatibilidade.
pip install scikit-learn xgboost shap pandas numpy matplotlib
Passo 3: Preparar dados de exemplo
Criamos um conjunto sintético com features relevantes e irrelevantes para demonstrar a deteção. Mantém sempre um split treino/teste para avaliar o impacto.
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=1000, n_features=10, n_informative=3,
n_redundant=1, n_repeated=0, random_state=42)
# adiciona features irrelevantes ruidosas
rng = np.random.RandomState(0)
noise = rng.normal(size=(X.shape[0], 3))
X = np.hstack([X, noise])
feature_names = [f'f{i}' for i in range(X.shape[1])]
df = pd.DataFrame(X, columns=feature_names)
X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2, random_state=42)
Passo 4: Treinar um modelo (exemplo com XGBoost)
Usa um modelo potente como o XGBoost; o SHAP funciona bem com modelos de árvore e generaliza para outros modelos.
import xgboost as xgb
from sklearn.metrics import accuracy_score
model = xgb.XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42)
model.fit(X_train, y_train)
preds = model.predict(X_test)
print('Accuracy:', accuracy_score(y_test, preds))
Passo 5: Calcular valores SHAP e agregar importâncias
Usa o TreeExplainer para modelos de árvore. Calcula o valor médio absoluto do SHAP por feature para obter a importância global.
import shap
import numpy as np
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_train)
# para classificação binária em XGBoost, shap_values é uma lista; usa o índice 1
sv = shap_values if isinstance(shap_values, np.ndarray) else shap_values[1]
mean_abs_shap = np.mean(np.abs(sv), axis=0)
shap_importance = pd.Series(mean_abs_shap, index=X_train.columns).sort_values(ascending=False)
print(shap_importance)
Passo 6: Identificar e remover features irrelevantes
Define um limiar simples, por exemplo as features com importância abaixo de uma fracção do valor máximo. Remove-as e re-treina para verificar o impacto.
threshold = shap_importance.max() * 0.05 # 5% do máximo
irrelevant = shap_importance[shap_importance < threshold].index.tolist()
print('Features irrelevantes detectadas:', irrelevant)
X_train_reduced = X_train.drop(columns=irrelevant)
X_test_reduced = X_test.drop(columns=irrelevant)
model_reduced = xgb.XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42)
model_reduced.fit(X_train_reduced, y_train)
print('Accuracy original:', accuracy_score(y_test, preds))
print('Accuracy reduzido:', accuracy_score(y_test, model_reduced.predict(X_test_reduced)))
Passo 7: Evitar erros comuns
Erros frequentes: (1) confiar apenas na importância do modelo sem validar a performance; (2) remover features correlacionadas sem verificar a multicolinearidade; (3) usar o SHAP com amostras muito pequenas. Valida sempre o impacto no conjunto de teste e considera cross-validation.
Verificar o resultado
Confirmas que ficou bem se: (a) as features listadas como irrelevantes têm valores SHAP muito baixos; (b) a performance no teste se mantém ou melhora; (c) o modelo reduzido é mais simples (menos colunas) e mais rápido a inferir. Além disso, visualiza as importâncias com um gráfico:
import matplotlib.pyplot as plt
shap_importance.sort_values(ascending=True).plot(kind='barh', figsize=(6,6))
plt.title('SHAP mean abs importance')
plt.show()
Conclusão
Detetar features irrelevantes com o SHAP é uma abordagem prática para simplificar modelos e prevenir overfitting, porque considera interações e não apenas correlações simples. Próximos passos: experimenta com cross-validation, testa limiares diferentes e aplica a regressão ou outros modelos. Dica: e se removeres apenas um subconjunto e comparares a performance em cada passo — que features são realmente essenciais?