Aula 6 — Classificação Paramétrica, Entropia Cruzada e a Família Exponencial
2026-09-21
Pausa Ativa 1 — Limites do Modelo Linear em Classificação
Pense sobre o comportamento do resíduo e da variância ao forçar uma reta contínua sobre alvos binários.
Pausa Ativa 1 — Resolução
Pausa Ativa 2 — Entropia Cruzada e Propriedades
Analise o comportamento probabilístico da perda de entropia cruzada.
Pausa Ativa 2 — Resolução
O Problema: Não há solução fechada (como no OLS) pois \(\mathbf{w}\) está dentro da sigmoide. Precisamos de métodos iterativos.
Método de Newton (IRLS): \[\mathbf{w}^{(\text{novo})} = \mathbf{w}^{(\text{antigo})} - H^{-1} \nabla E(\mathbf{w})\]
# Matriz de projeto: intercepto, idade, horas trabalhadas semanais
X_mat = np.column_stack([np.ones(len(df_adult)), df_adult["age"].values, df_adult["hours.per.week"].values])
y_vec = df_adult["y"].values
# Inicializacao em zeros
w_irls = np.zeros(3)
tabela_convergencia = []
for it in range(8):
a = X_mat @ w_irls
mu = 1.0 / (1.0 + np.exp(-a))
# Negative Log-Likelihood (NLL)
eps = 1e-15
mu_clipped = np.clip(mu, eps, 1.0 - eps)
nll = -np.sum(y_vec * np.log(mu_clipped) + (1.0 - y_vec) * np.log(1.0 - mu_clipped))
# Gradiente e Hessiana
grad = X_mat.T @ (mu - y_vec)
R_diag = mu * (1.0 - mu)
Hess = (X_mat.T * R_diag) @ X_mat
norma_grad = np.linalg.norm(grad)
tabela_convergencia.append((it, w_irls.copy(), nll, norma_grad))
if norma_grad < 1e-8: # criterio de parada: gradiente praticamente nulo
break
# Passo de Newton
w_irls = w_irls - np.linalg.solve(Hess, grad)
# Tabela dos passos
df_conv = pd.DataFrame([
{
"Iteração": it,
"Intercepto": f"{w[0]:.4f}",
"w_idade": f"{w[1]:.4f}",
"w_horas": f"{w[2]:.4f}",
"NLL (Perda)": f"{nll:.2f}",
"Norma Gradiente": f"{gnorm:.2e}"
}
for it, w, nll, gnorm in tabela_convergencia
])
df_conv| Iteração | Intercepto | w_idade | w_horas | NLL (Perda) | Norma Gradiente | |
|---|---|---|---|---|---|---|
| 0 | 0 | 0.0000 | 0.0000 | 0.0000 | 554.52 | 7.05e+03 |
| 1 | 1 | -5.3742 | 0.0887 | 0.0568 | 129.14 | 1.80e+03 |
| 2 | 2 | -8.8511 | 0.1460 | 0.0935 | 51.08 | 6.62e+02 |
| 3 | 3 | -12.3585 | 0.2049 | 0.1296 | 21.74 | 2.52e+02 |
| 4 | 4 | -16.0922 | 0.2694 | 0.1664 | 9.73 | 9.60e+01 |
| 5 | 5 | -20.1702 | 0.3427 | 0.2039 | 4.60 | 3.53e+01 |
| 6 | 6 | -24.7248 | 0.4285 | 0.2415 | 2.34 | 1.13e+01 |
| 7 | 7 | -29.9710 | 0.5337 | 0.2774 | 1.29 | 2.49e+00 |
Fronteira \(p=0{,}5\): Definida por \(-4{,}9134 + 0{,}0431 \cdot \text{idade} + 0{,}0478 \cdot \text{horas} = 0\).
def sigmoide(a):
return 0.5 * (1.0 + np.tanh(a / 2.0)) # sigmoide estavel numericamente
def descida_gradiente(X, y, n_iter):
L = np.linalg.eigvalsh(X.T @ X)[-1] / 4.0 # constante de Lipschitz do gradiente
w = np.zeros(X.shape[1])
normas = []
for _ in range(n_iter):
grad = X.T @ (sigmoide(X @ w) - y)
normas.append(np.linalg.norm(grad))
w = w - grad / L # passo fixo eta = 1/L
return np.array(normas)
# Atributos padronizados (o intercepto permanece como coluna de uns)
X_pad = X_mat.copy()
X_pad[:, 1:] = (X_mat[:, 1:] - X_mat[:, 1:].mean(axis=0)) / X_mat[:, 1:].std(axis=0)
n_iter_gd = 200
normas_gd_bruto = descida_gradiente(X_mat, y_vec, n_iter_gd)
normas_gd_pad = descida_gradiente(X_pad, y_vec, n_iter_gd)
normas_newton = [gnorm for _, _, _, gnorm in tabela_convergencia]
def iteracoes_ate(normas, tol):
idx = np.flatnonzero(np.asarray(normas) < tol)
return int(idx[0]) if idx.size else f"> {len(normas) - 1}"
comparacao = pd.DataFrame({
"Método": ["Newton (IRLS)", "GD, atributos padronizados", "GD, atributos brutos"],
"Iterações até ‖∇‖ < 1e-4": [iteracoes_ate(n, 1e-4) for n in (normas_newton, normas_gd_pad, normas_gd_bruto)],
"Iterações até ‖∇‖ < 1e-8": [iteracoes_ate(n, 1e-8) for n in (normas_newton, normas_gd_pad, normas_gd_bruto)],
f"‖∇‖ após {n_iter_gd} iterações": [
f"{normas_newton[-1]:.1e} (parou em {len(normas_newton) - 1})",
f"{normas_gd_pad[-1]:.1e}",
f"{normas_gd_bruto[-1]:.1e}",
],
})
display(comparacao.set_index("Método"))
fig, ax = plt.subplots(figsize=(8, 4.5))
ax.semilogy(range(len(normas_newton)), normas_newton, "o-", color=COR_AZUL, lw=2.2, label="Newton (IRLS)")
ax.semilogy(range(n_iter_gd), normas_gd_pad, "-", color=COR_LARANJA, lw=2.2, label="GD, atributos padronizados")
ax.semilogy(range(n_iter_gd), normas_gd_bruto, "-", color=COR_VERM, lw=2.2, label="GD, atributos brutos")
ax.set_xlabel("Iteração")
ax.set_ylabel(r"Norma do gradiente $\|\nabla E(\mathbf{w})\|$")
ax.set_title("Convergência: Newton vs. Descida de Gradiente (Adult Census)")
ax.set_xlim(-1, 100)
ax.legend()
plt.tight_layout()
plt.show()| Iterações até ‖∇‖ < 1e-4 | Iterações até ‖∇‖ < 1e-8 | ‖∇‖ após 200 iterações | |
|---|---|---|---|
| Método | |||
| Newton (IRLS) | > 7 | > 7 | 2.5e+00 (parou em 7) |
| GD, atributos padronizados | > 199 | > 199 | 2.2e+00 |
| GD, atributos brutos | > 199 | > 199 | 3.3e+02 |
Pausa Ativa 3 — Dinâmica de Otimização e Hessiana
Reflita sobre as propriedades numéricas da matriz \(H = X^T R X\) e da atualização de Newton.
Pausa Ativa 3 — Resolução
| Distribuição | Alvo \(y\) | Ligação Canônica \(g(\mu)\) | Ativação \(\mu = f(a)\) | Modelo Resultante |
|---|---|---|---|---|
| Gaussiana | \(\mathbb{R}\) contínuo | Identidade: \(\mu\) | Identidade: \(a\) | Regressão Linear (OLS) |
| Bernoulli | \(\{0, 1\}\) binário | Logit: \(\ln\frac{\mu}{1-\mu}\) | Sigmoide: \(\frac{1}{1+e^{-a}}\) | Regressão Logística |
| Poisson | \(\{0, 1, 2, \dots\}\) contagem | Logaritmo: \(\ln \mu\) | Exponencial: \(e^a\) | Regressão de Poisson |
| Categórica | \(\{1, \dots, K\}\) multiclasse | Log-odds relativo | Softmax: \(\frac{e^{a_k}}{\sum e^{a_j}}\) | Regressão Softmax |
Pausa Ativa 4 — GLMs e Ligações Canônicas
Considere o impacto da escolha da função de ligação nas propriedades analíticas do modelo.
Pausa Ativa 4 — Resolução
Pausa Ativa 5 — Separação Perfeita e Regularização
Considere o impacto de dados linearmente separáveis na norma dos parâmetros \(\|\mathbf{w}\|\).
Pausa Ativa 5 — Resolução
UNICAMP — Instituto de Computação