📊 Análise de Churn em Finanças - Notebook Completo

Notebook de Demonstração: Este notebook demonstra uma análise completa de churn no setor financeiro, incluindo análise exploratória de dados, feature engineering, modelagem de machine learning e interpretabilidade.

1. Importação de Bibliotecas

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
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score
import xgboost as xgb
import shap

# Configurações
plt.style.use('seaborn-v0_8-darkgrid')
sns.set_palette("husl")
%matplotlib inline

2. Carregamento e Exploração Inicial dos Dados

# Carregar dados
df = pd.read_csv('dados_clientes.csv')

# Visualizar primeiras linhas
print(df.head())
print(f"\nDimensões: {df.shape}")
print(f"\nColunas: {df.columns.tolist()}")
print(f"\nTipos de dados:\n{df.dtypes}")
print(f"\nValores ausentes:\n{df.isnull().sum()}")
   cliente_id  idade  genero  tempo_cliente  saldo_medio  num_produtos  churn
0           1     45       M             24      5000.50             3      0
1           2     32       F             12      2500.00             2      0
...
Dimensões: (10000, 7)

Colunas: ['cliente_id', 'idade', 'genero', 'tempo_cliente', 'saldo_medio', 'num_produtos', 'churn']

3. Análise Exploratória de Dados (EDA)

3.1. Distribuição da Variável Target

# Distribuição de churn
churn_counts = df['churn'].value_counts()
print(f"Churn: {churn_counts[1]}")
print(f"Não Churn: {churn_counts[0]}")
print(f"Taxa de Churn: {churn_counts[1] / len(df) * 100:.2f}%")

# Visualização
plt.figure(figsize=(8, 5))
churn_counts.plot(kind='bar', color=['#2ecc71', '#e74c3c'])
plt.title('Distribuição de Churn')
plt.xlabel('Churn')
plt.ylabel('Quantidade')
plt.xticks([0, 1], ['Não Churn', 'Churn'], rotation=0)
plt.show()

3.2. Análise de Features Numéricas

# Estatísticas descritivas
print(df[['idade', 'tempo_cliente', 'saldo_medio', 'num_produtos']].describe())

# Correlação com churn
correlacoes = df[['idade', 'tempo_cliente', 'saldo_medio', 'num_produtos', 'churn']].corr()
print(f"\nCorrelação com Churn:\n{correlacoes['churn'].sort_values(ascending=False)}")

4. Feature Engineering

# Criar features derivadas
df['idade_categoria'] = pd.cut(df['idade'], bins=[0, 30, 45, 60, 100], labels=['Jovem', 'Adulto', 'Meia-Idade', 'Idoso'])
df['tempo_cliente_categoria'] = pd.cut(df['tempo_cliente'], bins=[0, 12, 24, 60], labels=['Novo', 'Intermediário', 'Antigo'])
df['saldo_medio_log'] = np.log1p(df['saldo_medio'])

# Encoding de variáveis categóricas
df = pd.get_dummies(df, columns=['genero', 'idade_categoria', 'tempo_cliente_categoria'], drop_first=True)

# Features selecionadas
features = ['idade', 'tempo_cliente', 'saldo_medio', 'num_produtos', 'saldo_medio_log']
features.extend([col for col in df.columns if col.startswith('genero_') or col.startswith('idade_') or col.startswith('tempo_')])

print(f"Features selecionadas: {len(features)}")
print(features)

5. Preparação dos Dados

# Separar features e target
X = df[features]
y = df['churn']

# Dividir em treino e teste (80/20)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

print(f"Treino: {X_train.shape[0]} amostras")
print(f"Teste: {X_test.shape[0]} amostras")
print(f"\nTaxa de churn - Treino: {y_train.mean():.3f}")
print(f"Taxa de churn - Teste: {y_test.mean():.3f}")

6. Modelagem

6.1. Modelo 1: Logistic Regression

# Treinar modelo
lr = LogisticRegression(max_iter=1000, random_state=42)
lr.fit(X_train, y_train)

# Predições
y_pred_lr = lr.predict(X_test)
y_pred_proba_lr = lr.predict_proba(X_test)[:, 1]

# Métricas
print("=== Logistic Regression ===")
print(f"AUC-ROC: {roc_auc_score(y_test, y_pred_proba_lr):.4f}")
print(f"\n{classification_report(y_test, y_pred_lr)}")
=== Logistic Regression ===
AUC-ROC: 0.8234

              precision    recall  f1-score   support

           0       0.87      0.93      0.90      1593
           1       0.72      0.57      0.64       407

    accuracy                           0.85      2000
   macro avg       0.80      0.75      0.77      2000
weighted avg       0.84      0.85      0.84      2000

6.2. Modelo 2: Random Forest

# Treinar modelo
rf = RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42)
rf.fit(X_train, y_train)

# Predições
y_pred_rf = rf.predict(X_test)
y_pred_proba_rf = rf.predict_proba(X_test)[:, 1]

# Métricas
print("=== Random Forest ===")
print(f"AUC-ROC: {roc_auc_score(y_test, y_pred_proba_rf):.4f}")
print(f"\n{classification_report(y_test, y_pred_rf)}")
=== Random Forest ===
AUC-ROC: 0.8721

              precision    recall  f1-score   support

           0       0.90      0.94      0.92      1593
           1       0.76      0.65      0.70       407

    accuracy                           0.88      2000
   macro avg       0.83      0.80      0.81      2000
weighted avg       0.87      0.88      0.87      2000

6.3. Modelo 3: XGBoost

# Treinar modelo
xgb_model = xgb.XGBClassifier(n_estimators=100, max_depth=6, learning_rate=0.1, random_state=42)
xgb_model.fit(X_train, y_train)

# Predições
y_pred_xgb = xgb_model.predict(X_test)
y_pred_proba_xgb = xgb_model.predict_proba(X_test)[:, 1]

# Métricas
print("=== XGBoost ===")
print(f"AUC-ROC: {roc_auc_score(y_test, y_pred_proba_xgb):.4f}")
print(f"\n{classification_report(y_test, y_pred_xgb)}")
=== XGBoost ===
AUC-ROC: 0.8915

              precision    recall  f1-score   support

           0       0.91      0.95      0.93      1593
           1       0.79      0.68      0.73       407

    accuracy                           0.89      2000
   macro avg       0.85      0.82      0.83      2000
weighted avg       0.89      0.89      0.89      2000

7. Interpretabilidade com SHAP

# Criar explainer SHAP
explainer = shap.TreeExplainer(xgb_model)
shap_values = explainer.shap_values(X_test[:100])

# Visualizar importância de features
shap.summary_plot(shap_values, X_test[:100], plot_type="bar")
plt.title('Importância de Features (SHAP)')
plt.show()

# Waterfall plot para um exemplo específico
shap.waterfall_plot(explainer.expected_value, shap_values[0], X_test.iloc[0])
plt.show()
Interpretação: O SHAP mostra que as features mais importantes para prever churn são:
  • Tempo como cliente (negativamente correlacionado)
  • Saldo médio (negativamente correlacionado)
  • Número de produtos (negativamente correlacionado)
  • Idade (negativamente correlacionado)

8. Conclusões e Recomendações

Principais Insights:

  • Modelo Final: XGBoost com AUC-ROC de 0.8915
  • Fatores Críticos: Tempo como cliente, saldo médio e número de produtos são os principais fatores de churn
  • Ações Recomendadas:
    • Focar em clientes novos (menos de 12 meses)
    • Oferecer produtos adicionais para aumentar engajamento
    • Campanhas direcionadas para clientes com saldo médio baixo
    • Programas de fidelidade para aumentar tempo como cliente
Nota: Este é um notebook de demonstração. Em produção, seria necessário: