Capítulo 3
Support Vector Machines
3.1 Hiperplanos de Separación
Un SVM busca el hiperplano óptimo que separa dos clases con el máximo margen:
Clasificamos como si , si no. El margen es la distancia mínima del hiperplano a cualquier punto de entrenamiento.
3.2 Formulación Primal
Queremos maximizar el margen , equivalente a minimizar:
Para datos no separables, introducimos variables de holgura :
controla el trade-off entre margen y error de clasificación.
3.3 Formulación Dual y Kernels
El problema dual introduce multiplicadores de Lagrange :
Con el kernel trick, reemplazamos el producto punto por una función kernel:
Polinomial
RBF (Gaussiano)
3.4 Visualización Interactiva
El SVM encuentra el hiperplano con margen máximo. Ajusta C para ver el efecto en los vectores de soporte.
3.5 Implementación
Sklearn implementa SMO (optimización de secuencia mínima) para resolver el dual eficientemente:
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
X, y = make_classification(n_samples=500, n_features=10,
n_informative=5, random_state=42)
for kernel in ['linear', 'rbf', 'poly']:
model = SVC(kernel=kernel, C=1.0, gamma='scale')
scores = cross_val_score(model, X, y, cv=5)
print(f"{kernel}: {scores.mean():.3f} (±{scores.std():.3f})")3.6 Una SVM desde Cero (Dual)
import numpy as np
from scipy.optimize import minimize
class SimpleSVM:
def fit(self, X, y, C=1.0):
n = X.shape[0]
K = X @ X.T # kernel lineal
y2 = np.outer(y, y)
def loss(alpha):
return 0.5 * (alpha * y2 * K).sum() - alpha.sum()
bounds = [(0, C) for _ in range(n)]
constraints = {'type': 'eq', 'fun': lambda a: a @ y}
alpha0 = np.zeros(n)
res = minimize(loss, alpha0, bounds=bounds,
constraints=constraints)
self.alpha = res.x
sv = self.alpha > 1e-6
self.w = (self.alpha[sv, None] * y[sv, None] * X[sv]).sum(0)
self.b = np.mean(y[sv] - X[sv] @ self.w)
return self
def predict(self, X): return np.sign(X @ self.w + self.b)3.7 Support Vectors
Los puntos con son los vectores de soporte — los únicos que determinan el hiperplano. Puntos fuera del margen tienen . Esto hace que SVM sea esparso: eficiente en inferencia.
# Cuántos vectores de soporte?
model = SVC(kernel='rbf', C=1.0)
model.fit(X, y)
print(f"Support vectors: {len(model.support_vectors_)} / {len(X)}")
# Los pesos duales (alpha) para kernel RBF
print(f"Alpha no-cero: {(model.dual_coef_ != 0).sum()}")