Predição de Churn com Redes Neurais (MLP)
Vamos construir do zero uma rede neural que aprende a identificar clientes com risco de cancelamento. Se você nunca viu Deep Learning, não se preocupe — vou explicar tudo com exemplos do dia a dia.
O que vamos fazer?
Uma empresa de telefonia quer saber quais clientes têm mais chance de cancelar o serviço antes que isso aconteça. Com esse aviso antecipado, o time comercial pode agir — ligar, oferecer um desconto — e salvar o contrato.
Imagina que você tem uma lista de 7.000 clientes. Cada um tem 20 informações: quanto tempo está na empresa, qual plano contratou, quanto paga por mês… A rede neural vai aprender com exemplos históricos para responder: esse cliente vai cancelar ou não?
Isso é um problema de classificação binária (sim ou não). Vamos resolvê-lo com uma rede MLP (Multilayer Perceptron) — a arquitetura mais clássica de Deep Learning.
O que você vai precisar
- Python 3.10+ — a linguagem que vamos usar.
- Pandas — para ler e organizar os dados em tabelas.
- Scikit-learn — tem o
MLPClassifierque vamos usar. - Matplotlib / Seaborn — para os gráficos.
- Jupyter Notebook — ambiente interativo onde rodamos o código.
Dataset: IBM Telco Customer Churn — arquivo Telco-Customer-Churn.csv com 7.043 registros de clientes.
Carregar e explorar os dados
Antes de construir qualquer modelo, precisamos entender o que temos. É como conhecer os ingredientes antes de cozinhar.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# pd.read_csv() lê o arquivo e transforma em uma tabela (DataFrame)
df = pd.read_csv('Telco-Customer-Churn.csv')
# .shape retorna (linhas, colunas)
print(f'Shape: {df.shape}') # Shape: (7043, 21)
pd.read_csv() é como "abrir uma planilha do Excel" dentro do Python. O resultado (df) é uma tabela com 7.043 linhas e 21 colunas.
# .info() mostra o tipo de cada coluna
# ATENÇÃO: TotalCharges aparece como "object" (texto) — isso é um erro que vamos corrigir!
df.info()
# Quantos clientes cancelaram?
churn_pct = df['Churn'].value_counts(normalize=True) * 100
print(churn_pct)
# No → 73.5%
# Yes → 26.5%
Só 26,5% dos clientes cancelaram. Isso significa que o dataset é desbalanceado — e precisamos cuidar disso na hora de dividir o treino e o teste.
O que descobrimos? 7.043 clientes, 26,5% com churn, e TotalCharges está como texto quando devia ser número.
Preparar os dados
A rede neural só entende números. Precisamos converter textos em números e colocar tudo na mesma escala — como se fossem notas de 0 a 10 em vez de valores brutos.
# Corrige TotalCharges: converte texto para número
# errors='coerce' → se encontrar espaço em branco, vira NaN (nulo)
df['TotalCharges'] = pd.to_numeric(df['TotalCharges'], errors='coerce')
# Separa o target (y) das features (X)
y = (df['Churn'] == 'Yes').astype(int).values
# True/False vira 1/0: cancelou=1, ficou=0
X = df.drop(columns=['Churn']).copy()
# Removemos a coluna Churn de X — ela é a resposta, não uma pista
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Divide: 80% treino, 20% teste
# stratify=y → mantém a proporção de 26,5% de churn nos dois grupos
X_train, X_test, y_train, y_test = train_test_split(
X.values, y, test_size=0.20, random_state=42, stratify=y
)
# Normalização: coloca tudo na mesma escala (média 0, desvio padrão 1)
# Sem isso, "tenure" (0-72) domina sobre "SeniorCitizen" (0 ou 1)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) # só aplica a escala do treino, não recalcula
O que descobrimos? Treino com 5.634 clientes, teste com 1.409. A normalização é essencial para a rede neural convergir rápido e de forma estável.
Treinar o modelo base (MLP)
Uma rede MLP é como uma série de filtros. Cada camada processa a informação e passa para a próxima — até chegar na resposta. Pensa num funil de decisão com várias etapas.
from sklearn.neural_network import MLPClassifier
mlp = MLPClassifier(
# ARQUITETURA: 2 camadas ocultas
# Primeira com 64 neurônios, segunda com 32
hidden_layer_sizes=(64, 32),
# FUNÇÃO DE ATIVAÇÃO: ReLU
# Se o valor for negativo → vira 0; se for positivo → fica igual
# Isso permite que a rede aprenda padrões não-lineares
activation='relu',
# OTIMIZADOR: adam → ajusta os pesos automaticamente
solver='adam',
max_iter=300,
# EARLY STOPPING: para o treino quando a validação não melhora mais
early_stopping=True,
validation_fraction=0.15,
random_state=42
)
# .fit() = momento em que a rede APRENDE com os 5.634 exemplos
mlp.fit(X_train, y_train)
print('Treinamento concluído!')
O que descobrimos? O Early Stopping interrompeu o treino automaticamente antes de memorizar demais. Isso é fundamental para um modelo que generaliza bem.
Analisar curvas e comparar com modelo regularizado
O gráfico de loss mostra se a rede aprendeu bem. Se a linha de treino cai mas a de validação sobe, a rede está "decorando" — isso é overfitting.
# .loss_curve_ → loss a cada época (queremos que caia)
train_loss = mlp.loss_curve_
val_scores = mlp.validation_scores_
epochs = range(1, len(train_loss) + 1)
fig, axes = plt.subplots(1, 2, figsize=(13, 4))
axes[0].plot(epochs, train_loss)
axes[0].set_title('Curva de Loss (Treino)')
axes[1].plot(epochs, val_scores, 'g')
axes[1].set_title('Acurácia de Validação')
plt.tight_layout()
plt.show()
# Modelo regularizado: adiciona penalização L2 nos pesos
# alpha=0.001 = freio leve — a rede aprende padrões mais gerais
mlp_reg = MLPClassifier(
hidden_layer_sizes=(64, 32),
activation='relu',
solver='adam',
max_iter=300,
alpha=0.001, # Regularização L2
early_stopping=True,
validation_fraction=0.15,
n_iter_no_change=15,
random_state=42
)
mlp_reg.fit(X_train, y_train)
from sklearn.metrics import classification_report, ConfusionMatrixDisplay
y_pred = mlp_reg.predict(X_test)
print(classification_report(y_test, y_pred, target_names=['Não Churn', 'Churn']))
O que descobrimos? O modelo regularizado com L2 + Early Stopping apresentou curvas mais estáveis e F1-score mais equilibrado — especialmente na classe Churn (a que mais importa para o negócio).
Código completo e referências
Notebook completo com todas as células, gráficos e outputs:
github.com/Jair-pc/puc-minas-arquiteturas_de_deep_learning
Dataset: IBM Telco Customer Churn — disponível publicamente no Kaggle e IBM Developer.