Imagine que você está aprendendo uma nova língua. Primeiro, você domina as letras básicas (kernels básicos), depois aprende a combiná-las em palavras (operações com kernels), e finalmente descobre que algumas letras como o ‘R’ são tão fundamentais que aparecem em quase todas as palavras (kernel RBF). No mundo dos Processos Gaussianos, os kernels básicos são seu alfabeto, os operadores são sua gramática, e o kernel RBF é como a vogal ‘A’ – tão ubíquo que se tornou o padrão para a maioria das aplicações.
Como isso funciona na prática?
Kernels básicos são as funções de covariância fundamentais que definem tipos específicos de similaridade entre pontos de dados. O kernel RBF assume que pontos próximos são similares, o kernel linear captura relações lineares, e o kernel periódico identifica padrões que se repetem. Os operadores de kernel (+, ×, **) permitem combinar esses kernels básicos como peças de Lego, criando kernels complexos que podem capturar múltiplos padrões simultaneamente. Diferentemente de escolher um único kernel, esta abordagem composicional permite construir modelos customizados que refletem a complexidade real dos seus dados.
Mãos na massa: explorando kernels básicos e suas combinações
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
""" Explorando kernels básicos, operadores e o ubíquo kernel RBF Demonstra como construir kernels complexos a partir de componentes simples """ import numpy as np import matplotlib.pyplot as plt from sklearn.gaussian_process.kernels import (RBF, ConstantKernel, ExpSineSquared, DotProduct, WhiteKernel, RationalQuadratic) from sklearn.gaussian_process import GaussianProcessRegressor # Criando dados de demonstração def criar_dados_demonstracao(): """Cria dados com múltiplos padrões para testar diferentes kernels""" np.random.seed(42) x = np.linspace(0, 10, 100).reshape(-1, 1) # Dados com padrão suave (ideal para RBF) y_smooth = np.sin(x.ravel()) + 0.1 * np.random.normal(size=100) # Dados com tendência linear + ruído y_linear = 0.5 * x.ravel() + 0.2 * np.random.normal(size=100) # Dados periódicos y_periodic = np.sin(2 * np.pi * x.ravel()) + 0.1 * np.random.normal(size=100) # Dados com múltiplos padrões y_complex = (np.sin(x.ravel()) + # Componente suave 0.3 * x.ravel() + # Tendência linear 0.5 * np.sin(3 * x.ravel()) + # Componente periódico 0.1 * np.random.normal(size=100)) # Ruído return x, y_smooth, y_linear, y_periodic, y_complex x, y_smooth, y_linear, y_periodic, y_complex = criar_dados_demonstracao() print("=== KERNELS BÁSICOS DO SCIKIT-LEARN ===\n") # Demonstração dos kernels básicos kernels_basicos = { 'RBF (Gaussiano)': RBF(length_scale=1.0), 'Linear': DotProduct(sigma_0=1.0), 'Periódico': ExpSineSquared(length_scale=1.0, periodicity=1.0), 'RationalQuadratic': RationalQuadratic(length_scale=1.0, alpha=1.0), 'Constante': ConstantKernel(constant_value=1.0), 'Ruído': WhiteKernel(noise_level=0.1) } # Testando cada kernel básico nos dados suaves fig, axes = plt.subplots(2, 3, figsize=(15, 10)) axes = axes.ravel() for idx, (nome, kernel) in enumerate(kernels_basicos.items()): try: gpr = GaussianProcessRegressor(kernel=kernel, alpha=0.0, random_state=42) gpr.fit(x, y_smooth) # Previsões x_pred = np.linspace(0, 10, 200).reshape(-1, 1) y_pred, sigma = gpr.predict(x_pred, return_std=True) # Plot axes[idx].plot(x, y_smooth, 'ro', alpha=0.6, markersize=3, label='Dados') axes[idx].plot(x_pred, y_pred, 'b-', linewidth=2, label='Previsão') axes[idx].fill_between(x_pred.ravel(), y_pred - 1.96*sigma, y_pred + 1.96*sigma, alpha=0.2, label='Incerteza') axes[idx].set_title(f'{nome}\n{kernel}', fontsize=10) axes[idx].grid(True, alpha=0.3) axes[idx].legend(fontsize=8) except Exception as e: axes[idx].text(0.5, 0.5, f'Erro\n{str(e)}', ha='center', va='center', transform=axes[idx].transAxes, fontsize=8) axes[idx].set_title(nome, fontsize=10) plt.tight_layout() plt.show() print("\n=== OPERADORES DE KERNEL: COMBINANDO KERNELS BÁSICOS ===\n") # Demonstração dos operadores de kernel k_rbf = RBF(length_scale=1.0) k_linear = DotProduct(sigma_0=1.0) k_periodic = ExpSineSquared(length_scale=1.0, periodicity=1.0) k_const = ConstantKernel(constant_value=1.0) # Operações com kernels operacoes_kernels = { 'Soma\n(RBF + Linear)': k_rbf + k_linear, 'Multiplicação\n(RBF × Periódico)': k_rbf * k_periodic, 'Exponenciação\n(RBF²)': k_rbf**2, 'Escala\n(Const × RBF)': k_const * k_rbf, 'Combinação Complexa\n(Const×RBF + Linear)': k_const * k_rbf + k_linear, 'Múltiplos Padrões\n(Const×RBF + Const×Periódico + Linear)': k_const * k_rbf + k_const * k_periodic + k_linear } # Testando operações nos dados complexos fig, axes = plt.subplots(2, 3, figsize=(15, 10)) axes = axes.ravel() for idx, (nome, kernel) in enumerate(operacoes_kernels.items()): try: gpr = GaussianProcessRegressor(kernel=kernel, alpha=0.0, random_state=42) gpr.fit(x, y_complex) # Previsões x_pred = np.linspace(0, 10, 200).reshape(-1, 1) y_pred, sigma = gpr.predict(x_pred, return_std=True) # Plot axes[idx].plot(x, y_complex, 'ro', alpha=0.6, markersize=3, label='Dados') axes[idx].plot(x_pred, y_pred, 'b-', linewidth=2, label='Previsão') axes[idx].fill_between(x_pred.ravel(), y_pred - 1.96*sigma, y_pred + 1.96*sigma, alpha=0.2, label='Incerteza') axes[idx].set_title(f'{nome}', fontsize=10) axes[idx].grid(True, alpha=0.3) axes[idx].legend(fontsize=8) print(f"{nome}: Log-likelihood = {gpr.log_marginal_likelihood():.2f}") except Exception as e: axes[idx].text(0.5, 0.5, f'Erro\n{str(e)}', ha='center', va='center', transform=axes[idx].transAxes, fontsize=8) axes[idx].set_title(nome, fontsize=10) plt.tight_layout() plt.show() print("\n=== KERNEL RBF: O PADRÃO OURO ===\n") # Demonstração detalhada do kernel RBF print("O kernel RBF (Radial Basis Function) é definido por:") print("[latex]k(x_i, x_j) = \\exp\\left(-\\frac{\\|x_i - x_j\\|^2}{2l^2}\\right)[/latex]") print("Onde l é o parâmetro length_scale que controla a suavidade da função\n") # Explorando diferentes length_scales no RBF length_scales = [0.1, 0.5, 1.0, 2.0, 5.0] fig, axes = plt.subplots(2, 3, figsize=(15, 10)) axes = axes.ravel() for idx, length_scale in enumerate(length_scales): kernel_rbf = RBF(length_scale=length_scale) gpr = GaussianProcessRegressor(kernel=kernel_rbf, alpha=0.0, random_state=42) gpr.fit(x, y_smooth) # Previsões x_pred = np.linspace(0, 10, 200).reshape(-1, 1) y_pred, sigma = gpr.predict(x_pred, return_std=True) # Plot axes[idx].plot(x, y_smooth, 'ro', alpha=0.6, markersize=3, label='Dados') axes[idx].plot(x_pred, y_pred, 'b-', linewidth=2, label='Previsão') axes[idx].fill_between(x_pred.ravel(), y_pred - 1.96*sigma, y_pred + 1.96*sigma, alpha=0.2, label='Incerteza') axes[idx].set_title(f'RBF length_scale = {length_scale}', fontsize=10) axes[idx].grid(True, alpha=0.3) axes[idx].legend(fontsize=8) print(f"length_scale {length_scale}: Log-likelihood = {gpr.log_marginal_likelihood():.2f}") # Plot da função RBF para diferentes length_scales axes[5].set_title('Função RBF para Diferentes length_scales', fontsize=10) x_rbf = np.linspace(0, 3, 100) for length_scale in length_scales: y_rbf = np.exp(-x_rbf**2 / (2 * length_scale**2)) axes[5].plot(x_rbf, y_rbf, label=f'l={length_scale}', linewidth=2) axes[5].set_xlabel('Distância') axes[5].set_ylabel('Similaridade') axes[5].grid(True, alpha=0.3) axes[5].legend() plt.tight_layout() plt.show() # Comparação RBF vs outros kernels nos dados suaves print("\n=== COMPARAÇÃO: RBF VS OUTROS KERNELS ===\n") kernels_comparacao = { 'RBF': RBF(), 'Matern (ν=1.5)': Matern(nu=1.5), 'RationalQuadratic': RationalQuadratic(), 'Linear': DotProduct() } resultados = [] for nome, kernel in kernels_comparacao.items(): gpr = GaussianProcessRegressor(kernel=kernel, random_state=42) gpr.fit(x, y_smooth) log_likelihood = gpr.log_marginal_likelihood() resultados.append((nome, log_likelihood, gpr.kernel_)) # Ordenando por log-likelihood resultados.sort(key=lambda x: x[1], reverse=True) print("Ranking de kernels por log-likelihood marginal:") for nome, ll, kernel in resultados: print(f"{nome:20} → Log-likelihood: {ll:8.2f} | Kernel otimizado: {kernel}") # Caso de uso prático: escolhendo o kernel certo print("\n=== CASO PRÁTICO: ESCOLHENDO O KERNEL CERTO ===\n") def diagnosticar_kernel_ideal(y_data, x_data): """Ferramenta simples para diagnosticar qual kernel pode ser apropriado""" from scipy import stats # Análise de linearidade slope, intercept, r_value, p_value, std_err = stats.linregress(x_data.ravel(), y_data) # Análise de periodicidade (usando FFT) fft = np.fft.fft(y_data - np.mean(y_data)) freqs = np.fft.fftfreq(len(y_data)) dominant_freq = np.abs(freqs[np.argmax(np.abs(fft[1:])) + 1]) print("Diagnóstico dos dados:") print(f" Correlação linear (R²): {r_value**2:.3f}") print(f" Frequência dominante: {dominant_freq:.3f}") recomendacoes = [] if r_value**2 > 0.7: recomendacoes.append("Alta correlação linear → Considere kernel Linear") if dominant_freq > 0.1: recomendacoes.append("Padrão periódico detectado → Considere kernel Periódico") if len(recomendacoes) == 0: recomendacoes.append("Padrão complexo → Use RBF ou Matern como ponto de partida") return recomendacoes recomendacoes = diagnosticar_kernel_ideal(y_complex, x) print("Recomendações:") for rec in recomendacoes: print(f" • {rec}") |
Os detalhes que fazem diferença
O kernel RBF se tornou o padrão da indústria por uma boa razão: sua suavidade infinita e propriedades matemáticas elegantes o tornam apropriado para a maioria dos problemas do mundo real. Contudo, entender quando não usá-lo é igualmente importante – dados com descontinuidades podem precisar do kernel Matern, padrões sazonais exigem ExpSineSquared, e tendências lineares fortes se beneficiam do DotProduct. Os operadores de kernel permitem construir soluções híbridas: adição combina padrões independentes, multiplicação modela interações, e exponenciação controla a escala de variação. A escolha do length_scale no RBF é particularmente crucial – valores muito pequenos levam a overfitting, valores muito grandes a underfitting.
- RBF: Padrão ouro para funções suaves, use quando não souber por onde começar
- Operador +: Combina padrões independentes (ex: tendência + sazonalidade)
- Operador ×: Modela interações entre padrões (ex: sazonalidade que varia suavemente)
- Length_scale: Controla o “raio de influência” de cada ponto nos dados
- Kernel constante: Escala a variância geral do processo
Perguntas que os iniciantes fazem
Você deve estar se perguntando: “Por que o RBF é tão popular se existem tantos outros kernels?” Excelente questão! O RBF é um excelente ponto de partida porque assume apenas que pontos próximos têm valores similares – uma suposição razoável para a maioria dos fenômenos naturais. Uma confusão comum é sobre quando usar soma versus multiplicação de kernels: use soma para padrões aditivos independentes, multiplicação para padrões que interagem. Outra dúvida frequente: “Como escolher o length_scale inicial?” Comece com a distância média entre pontos nos seus dados e deixe a otimização ajustar a partir daí.
Para onde ir agora?
Pratique construindo kernels customizados para problemas específicos do seu domínio. Comece sempre com RBF puro e depois adicione componentes baseando-se nos padrões que observar nos resíduos. Use a log-verossimilhança marginal para comparar objetivamente diferentes arquiteturas de kernel. O momento “aha!” acontece quando você percebe que kernels bem construídos não são apenas ferramentas matemáticas, mas expressões da sua compreensão sobre como os dados se relacionam.
Assuntos relacionados
Para se tornar um expert em kernels, estude:
- Funções de base radial: fundamentos matemáticos do RBF
- Teoria de aproximação: como kernels criam espaços de funções
- Processos estacionários: propriedades de invariância por translação
- Análise espectral: decomposição de kernels em componentes de frequência
- Mercer’s Theorem: fundamento teórico dos métodos de kernel