Visualização de Modelos de Machine Learning com SHAP

Introdução aos Gráficos SHAP

Hoje, o trabalho foca em reflexões conceituais com um nível de dificuldade moderado.

  1. Com base na documentação fornecida, complete os tipos restantes de visualizações
  2. Tente determinar os requisitos de dimensão para cada parâmetro nas funções de plotagem SHAP, como as necessidades de formato para o gráfico de força (shap.force_plot)
  3. Identifique como os dados para problemas de classificação e regressão devem ser formatados, utilizadno o dataset de crédito para classificação e o dataset de bicicletas para regressão.
# Execute o código de pré-processamento anterior
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

# Configuração de fonte para caracteres chineses
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# Carregamento dos dados
dataset = pd.read_csv('dados.csv')

# Seleção de variáveis categóricas
recursos_discretos = dataset.select_dtypes(include=['object']).columns.tolist()

# Codificação de rótulo para 'Propriedade da Casa'
propriedade_mapping = {
    'Própria': 1,
    'Alugada': 2,
    'Financiamento': 3,
    'Hipoteca': 4
}
dataset['Propriedade da Casa'] = dataset['Propriedade da Casa'].map(propriedade_mapping)

# Codificação de rótulo para 'Anos no Emprego Atual'
anos_emprego_mapping = {
    '< 1 ano': 1,
    '1 ano': 2,
    '2 anos': 3,
    '3 anos': 4,
    '4 anos': 5,
    '5 anos': 6,
    '6 anos': 7,
    '7 anos': 8,
    '8 anos': 9,
    '9 anos': 10,
    '10+ anos': 11
}
dataset['Anos no Emprego Atual'] = dataset['Anos no Emprego Atual'].map(anos_emprego_mapping)

# Codificação one-hot para 'Propósito'
dataset_codificado = pd.get_dummies(dataset, columns=['Propósito'])
dataset_original = pd.read_csv("dados.csv")
novos_recursos = []
for coluna in dataset_codificado.columns:
    if coluna not in dataset_original.columns:
       novos_recursos.append(coluna)
       
for recurso in novos_recursos:
    dataset_codificado[recurso] = dataset_codificado[recurso].astype(int)

# Mapeamento de 'Prazo' para 0-1
prazo_mapping = {
    'Curto Prazo': 0,
    'Longo Prazo': 1
}
dataset_codificado['Prazo'] = dataset_codificado['Prazo'].map(prazo_mapping)
dataset_codificado.rename(columns={'Prazo': 'Longo Prazo'}, inplace=True)

recursos_continuos = dataset_codificado.select_dtypes(include=['int64', 'float64']).columns.tolist()

# Preenchimento de valores ausentes em recursos contínuos com a moda
for recurso in recursos_continuos:     
    moda = dataset_codificado[recurso].mode()[0]
    dataset_codificado[recurso].fillna(moda, inplace=True)

# Divisão do conjunto de dados
from sklearn.model_selection import train_test_split
X = dataset_codificado.drop(['Inadimplência de Crédito'], axis=1)
y = dataset_codificado['Inadimplência de Crédito']
X_treino, X_teste, y_treino, y_teste = train_test_split(X, y, test_size=0.2, random_state=42)

# Modelo de Floresta Aleatória
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.metrics import classification_report, confusion_matrix
import warnings
warnings.filterwarnings('ignore')

print("--- 1. Floresta Aleatória com parâmetros padrão ---")
import time
inicio = time.time()
modelo_rf = RandomForestClassifier(random_state=42)
modelo_rf.fit(X_treino, y_treino)
predicoes = modelo_rf.predict(X_teste)
fim = time.time()

print(f"Tempo de treino e previsão: {fim - inicio:.4f} segundos")
print("\nRelatório de classificação da Floresta Aleatória no conjunto de teste:")
print(classification_report(y_teste, predicoes))
print("Matriz de confusão da Floresta Aleatória no conjunto de teste:")
print(confusion_matrix(y_teste, predicoes))

Princípios Básicos do SHAP

Objetivo: Compreender por que modelos complexos de machine learning (especialmente modelos "caixa preta", como florestas aleatórias, árvores de boosting gradiente e redes neurais) fazem previsões específicas para entradas específicas. O SHAP fornece um método unificado para explicar as saídos dos modelos.

Conceito Central: Valores de Shapley da Teoria dos Jogos Cooperativos

O SHAP (SHapley Additive exPlanations) tem como base o conceito de Valores de Shapley da teoria dos jogos cooperativos. Imagine um jogo cooperativo:

  1. Jogadores: Os recursos (features) do modelo são os jogadores.
  2. Jogo: O objetivo é prever o valor de saída para uma amostra específica.
  3. Cooperação: Diferentes subconjuntos de recursos podem "cooperar" para fazer previsões.
  4. Recompensa/Valor: O valor obtido pela previsão de um subconjunto específico de recursos.
  5. Objetivo: Como justamente distribuir o resultado da previsão final (o "ganho" em relação à previsão média) para cada recurso participante (jogador)?

Abordagem do Cálculo dos Valores de Shapley (conceitualmente):

Para calcular a contribuição de um recurso específico (por exemplo, "Recurso A") para uma previsão, o SHAP considera:

  1. Todos os possíveis combinações de recursos (subconjuntos/coalizões): Do conjunto sem recursos ao conjunto com todos os recursos.
  2. Contribuição marginal do Recurso A: Para cada combinação de recursos, comparar a "previsão do conjunto que inclui o Recurso A" com a "previsão do conjunto que não inclui o Recurso A mas inclui os mesmos outros recursos". A diferença é a "contribuição marginal" do Recurso A para essa combinação específica.
  3. Média ponderada: O Valor de Shapley é a média ponderada das contribuições marginais do recurso em todos os possíveis subconjuntos de recursos. Os pesos garantem a justiça da distribuição.

Características Prnicipais do SHAP (Explicação Aditiva):

Uma característica importatne do SHAP é sua natureza aditiva. Isso significa:

  • Valor Base (Base Value / Expected Value): É a previsão média do modelo em todo o conjunto de dados de treinamento (ou de fundo). Pode ser entendido como a previsão "padrão" sem nenhuma informação de recurso.
  • Soma dos Valores SHAP: Para qualquer amostra, a soma de todos os valores SHAP mais o valor base é exatamente igual à previsão do modelo para essa amostra.

Valor da Previsão do Modelo (Amostra X) = Valor Base + SHAP(Recurso1) + SHAP(Recurso2) + ... + SHAP(RecursoN)

Por que é gerado um array valores\_shap?

Com base nos princípios acima, o SHAP precisa calcular um valor de contribuição (Valor SHAP) para cada recurso de cada amostra:

  1. Explicar previsões individuais: O cerne do SHAP é explicar previsões individuais.
  2. Contribuição dos recursos: Para essa previsão, precisamos saber se cada recurso está "empurrando" a previsão para "cima" ou para "baixo" (em relação ao valor base) e quão forte é esse empurrão.
  3. Numeração: O tamanho e direção desse "empurrão" é o Valor SHAP daquele recurso para aquela previsão da amostra.

Portanto:

  • Para problemas de regressão:
    • O modelo tem apenas uma saída.
    • Para cada uma das n\_amostras, calcula-se o Valor SHAP de n\_recursos recursos. < Isso naturalmente forma um array de formato (n\_amostras, n\_recursos). valores\_shap\[i, j\] representa a contribuição do recurso j da amostra i para o valor de previsão daquela amostra.
  1. Para problemas de classificação:
    • O modelo geralmente produz uma pontuação ou probabilidade para cada classe.
    • O SHAP precisa explicar como o modelo obteve a pontuação para cada classe.
    • Portanto, para cada uma das n\_amostras, calcula-se n\_recursos Valores SHAP para cada classe.
    • A organização mais comum é retornar uma lista cujo comprimento é igual ao número de classes. O elemento k da lista é um array (n\_amostras, n\_recursos) que representa a contribuição de todos os recursos de todas as amostras para a previsão da classe k.
    • valores\_shap\[k\]\[i, j\] representa a contribuição do recurso j da amostra i para a previsão da classe k para aquela amostra. Resumo:

O SHAP, calculando a contribuição marginal de cada recurso para uma previsão individual (em relação à previsão média), oferece um método para decompor a previsão do modelo em cada recurso. Essa decomposição é necessária para cada amostra e cada recurso (e para cada classe em problemas de classificação), resultando na estrutura do array valores\_shap que observamos.

import shap
import matplotlib.pyplot as plt

# Inicializador do explicador SHAP
explicador = shap.TreeExplainer(modelo_rf)

# Cálculo dos Valores SHAP (baseado no conjunto de teste)
# Este valores_shap é um array numpy que representa a contribuição de cada recurso para cada amostra
valores_shap = explicador.shap_values(X_teste)

# Os requisitos de dimensão dos dados serão uma das coisas mais importantes ao estudar redes neurais no futuro.

print("Formato de valores_shap:", valores_shap.shape)
print("Formato de valores_shap[0]:", valores_shap[0].shape)
print("Formato de valores_shap[:, :, 0]:", valores_shap[:, :, 0].shape)
print("Formato de X_teste:", X_teste.shape)

1. Gráfico de Importância de Recursos SHAP (Summary Plot - Bar)

# --- 1. Gráfico de Importância de Recursos SHAP (Summary Plot - Bar) ---
print("--- 1. Gráfico de Importância de Recursos SHAP (Bar) ---")
shap.summary_plot(valores_shap[:, :, 0], X_teste, plot_type="bar", show=False)
plt.title("Importância de Recursos SHAP (Gráfico de Barras)")
plt.show()

2. Gráfico de Violino de Importância de Recursos SHAP (Summary Plot - Violin)

# --- 2. Gráfico de Violino de Importância de Recursos SHAP (Summary Plot - Violin) ---
print("--- 2. Gráfico de Violino de Importância de Recursos SHAP ---")
shap.summary_plot(valores_shap[:, :, 0], X_teste, plot_type="violin", show=False, max_display=10)
plt.title("Importância de Recursos SHAP (Gráfico de Violino)")
plt.show()
# Note os parâmetros acima: plot_type pode ser "bar" ou "violin", max_display controla quantos recursos são exibidos (padrão é 20)

Tags: SHAP interpretabilidade machine-learning visualização random-forest

Publicado em 6-4 16:27 por Thomas