Compreendendo o SVC para Problemas de Classificação
O SVC (Support Vector Classification) é a implementação principal para problemas de classificação nos Support Vector Machines do Scikit-Learn. Esta classe implementa o algoritmo clássico de SVM para classificação binária e multiclasse usando a abordagem one-vs-one.
Funcionamento Básico do SVC
Primeiramente, o SVC busca encontrar o hiperplano ótimo que separa as classes maximizando a margem entre os pontos mais próximos de cada classe. A formulação matemática resolve o problema de otimização:
\(\min_{w, b} \frac{1}{2} \|w\|^2 + C \sum_{i=1}^n \xi_i\)
sujeito a:
\(y_i (w \cdot \phi(x_i) + b) \geq 1 – \xi_i \quad \text{e} \quad \xi_i \geq 0\)
onde φ(x_i) é a transformação para o espaço de características através do kernel trick.
Parâmetros Principais do SVC
Certamente, entender os parâmetros é crucial para usar efetivamente o SVC. Os mais importantes incluem:
|
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 |
from sklearn.svm import SVC from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # Criando dados de exemplo X, y = make_classification(n_samples=1000, n_features=4, n_classes=2, n_redundant=0, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # Inicializando SVC com parâmetros principais svc_model = SVC( C=1.0, # Parâmetro de regularização kernel='rbf', # Tipo de kernel gamma='scale', # Parâmetro do kernel RBF degree=3, # Grau para kernel polinomial coef0=0.0, # Termo independente para poly/sigmoid shrinking=True, # Usar heurística shrinking probability=False, # Habilitar estimativas de probabilidade tol=1e-3, # Tolerância para critério de parada cache_size=200, # Tamanho do cache (MB) class_weight=None, # Peso das classes verbose=False, max_iter=-1, # Número máximo de iterações decision_function_shape='ovr' # Estratégia multiclasse ) # Treinando o modelo svc_model.fit(X_train, y_train) # Fazendo predições y_pred = svc_model.predict(X_test) print(classification_report(y_test, y_pred)) |
Kernels e Suas Aplicações
Conquanto o kernel linear seja o mais simples, a verdadeira potência do SVC surge com kernels não lineares. Cada kernel tem características específicas:
- linear: \(K(x_i, x_j) = x_i \cdot x_j\) – Para problemas linearmente separáveis
- poly: \(K(x_i, x_j) = (\gamma x_i \cdot x_j + r)^d\) – Para relações polinomiais
- rbf: \(K(x_i, x_j) = \exp(-\gamma \|x_i – x_j\|^2)\) – Kernel mais popular e flexível
- sigmoid: \(K(x_i, x_j) = \tanh(\gamma x_i \cdot x_j + r)\) – Similar a redes neurais
Comparação Prática de Kernels
Embora a teoria seja importante, decerto a aplicação prática revela diferenças cruciais. Portanto, vejamos uma comparação sistemática:
|
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 |
import numpy as np import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.datasets import make_circles, make_moons, make_classification from sklearn.model_selection import cross_val_score from sklearn.preprocessing import StandardScaler # Criando diferentes tipos de dados datasets = { 'Linear': make_classification(n_features=2, n_redundant=0, n_informative=2, random_state=1), 'Moons': make_moons(noise=0.3, random_state=0), 'Circles': make_circles(noise=0.2, factor=0.5, random_state=1) } kernels = ['linear', 'rbf', 'poly', 'sigmoid'] results = {} for data_name, (X, y) in datasets.items(): # Normalizando os dados X_scaled = StandardScaler().fit_transform(X) data_results = {} for kernel in kernels: if kernel == 'poly': svc = SVC(kernel=kernel, degree=3, gamma='scale') else: svc = SVC(kernel=kernel, gamma='scale') scores = cross_val_score(svc, X_scaled, y, cv=5, scoring='accuracy') data_results[kernel] = scores.mean() results[data_name] = data_results print(f"\n{data_name}:") for kernel, score in data_results.items(): print(f" {kernel}: {score:.4f}") |
O Parâmetro C e Controle de Overfitting
Atualmente, o parâmetro C é um dos mais mal compreendidos no SVC. Aliás, ele controla o trade-off entre maximizar a margem e minimizar o erro de classificação:
- C baixo: Margem larga, pode underfit, mas generaliza melhor
- C alto: Margem estreita, ajusta-se mais aos dados, risco de overfitting
Visualizando o Efeito do Parâmetro C
Enquanto a descrição teórica ajuda, igualmente importante é ver o efeito visual:
|
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 |
from sklearn.inspection import DecisionBoundaryDisplay # Demonstrando o efeito de C X, y = make_classification(n_samples=200, n_features=2, n_redundant=0, n_informative=2, random_state=1, n_clusters_per_class=1) C_values = [0.01, 0.1, 1, 10, 100] fig, axes = plt.subplots(2, 3, figsize=(15, 10)) axes = axes.ravel() for i, C in enumerate(C_values): svc = SVC(C=C, kernel='linear', random_state=42) svc.fit(X, y) DecisionBoundaryDisplay.from_estimator( svc, X, response_method="predict", alpha=0.5, ax=axes[i] ) # Plotando pontos e vetores suporte axes[i].scatter(X[:, 0], X[:, 1], c=y, edgecolors='k') axes[i].scatter(svc.support_vectors_[:, 0], svc.support_vectors_[:, 1], s=100, facecolors='none', edgecolors='red', linewidths=1.5) axes[i].set_title(f'C = {C}\nVetores Suporte: {len(svc.support_vectors_)}') plt.tight_layout() plt.show() |
Problemas Multiclasse
Surpreendentemente, o SVC nativamente implementa apenas classificação binária. Para problemas multiclasse, duas estratégias são empregadas:
- one-vs-one: Constrói \(\frac{n(n-1)}{2}\) classificadores
- one-vs-rest: Constrói n classificadores (um por classe)
Implementação Multiclasse
|
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 |
from sklearn.svm import SVC from sklearn.datasets import make_classification from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt # Criando problema multiclasse X_multi, y_multi = make_classification(n_samples=1000, n_features=4, n_classes=3, n_informative=3, n_redundant=0, random_state=42) # Comparando estratégias multiclasse strategies = ['ovr', 'ovo'] # one-vs-rest e one-vs-one for strategy in strategies: svc_multi = SVC(kernel='rbf', decision_function_shape=strategy, random_state=42) # Validação cruzada scores = cross_val_score(svc_multi, X_multi, y_multi, cv=5) print(f"Estratégia {strategy}: Acurácia média = {scores.mean():.4f}") # Treinando modelo final e matriz de confusão svc_final = SVC(kernel='rbf', decision_function_shape='ovr', random_state=42) svc_final.fit(X_train, y_train) # Matriz de confusão y_pred_multi = svc_final.predict(X_test) cm = confusion_matrix(y_test, y_pred_multi) disp = ConfusionMatrixDisplay(confusion_matrix=cm) disp.plot() plt.title('Matriz de Confusão - SVC Multiclasse') plt.show() |
Otimização de Hiperparâmetros
Contudo, escolher os parâmetros corretos manualmente pode ser desafiador. Assim, técnicas sistemáticas de otimização são essenciais:
|
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 |
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV from sklearn.svm import SVC from sklearn.datasets import make_classification import numpy as np # Criando dataset para tuning X_tune, y_tune = make_classification(n_samples=1000, n_features=10, random_state=42) # Busca em Grade para SVC param_grid = { 'C': [0.1, 1, 10, 100], 'kernel': ['linear', 'rbf', 'poly'], 'gamma': ['scale', 'auto', 0.1, 1, 10], 'degree': [2, 3, 4] # Apenas para kernel poly } svc = SVC(random_state=42) grid_search = GridSearchCV(svc, param_grid, cv=5, scoring='accuracy', n_jobs=-1) grid_search.fit(X_tune, y_tune) print("Melhores parâmetros:", grid_search.best_params_) print("Melhor score:", grid_search.best_score_) # Busca aleatória para espaços de parâmetros maiores param_dist = { 'C': np.logspace(-3, 3, 10), 'gamma': np.logspace(-3, 3, 10), 'kernel': ['rbf', 'linear', 'poly'] } random_search = RandomizedSearchCV(svc, param_dist, n_iter=50, cv=5, scoring='accuracy', random_state=42, n_jobs=-1) random_search.fit(X_tune, y_tune) print("\nMelhores parâmetros (Randomized):", random_search.best_params_) |
Considerações de Performance
Inegavelmente, o SVC pode ser computacionalmente intensivo para grandes conjuntos de dados. Então, considere estas estratégias:
- Use LinearSVC para problemas lineares em grande escala
- Reduza cache_size se memory for limitada
- Ajuste tol para trade-off entre precisão e tempo
- Considere amostragem para datasets muito grandes
Comparação com LinearSVC
|
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 |
from sklearn.svm import LinearSVC import time # Dataset maior para comparação X_large, y_large = make_classification(n_samples=10000, n_features=20, random_state=42) # SVC com kernel linear start_time = time.time() svc_linear = SVC(kernel='linear', random_state=42) svc_linear.fit(X_large, y_large) svc_time = time.time() - start_time # LinearSVC start_time = time.time() linear_svc = LinearSVC(random_state=42) linear_svc.fit(X_large, y_large) linear_svc_time = time.time() - start_time print(f"SVC (linear kernel): {svc_time:.2f} segundos") print(f"LinearSVC: {linear_svc_time:.2f} segundos") print(f"LinearSVC é {svc_time/linear_svc_time:.1f}x mais rápido") # Comparando acurácia svc_score = svc_linear.score(X_large, y_large) linear_svc_score = linear_svc.score(X_large, y_large) print(f"\nSVC Acurácia: {svc_score:.4f}") print(f"LinearSVC Acurácia: {linear_svc_score:.4f}") |
Conclusão e Melhores Práticas
Enfim, o SVC é uma ferramenta poderosa mas que requer entendimento adequado para uso efetivo. Inegavelmente, seu desempenho depende criticamente da escolha correta de kernel e parâmetros.
Afinal, dominar o SVC significa compreender não apenas como usá-lo, mas quando usá-lo. Eventualmente, você desenvolverá intuição para selecionar a configuração ideal para cada problema.
Portanto, pratique com diversos datasets e experimente diferentes configurações. Inclusive para problemas onde outros algoritmos podem falhar, o SVC frequentemente surpreende com sua eficácia.