An SVM is natively a binary, non-probabilistic classifier. Real problems have many classes and often need probabilities. This chapter covers the multiclass schemes, how to extract calibrated probabilities, and the end-to-end craft — scaling, tuning, handling imbalance, and building leak-free pipelines — that turns an SVM from a textbook idea into a dependable model.
From binary to multiclass
SVMs handle \(K>2\) classes by combining binary classifiers:
One-vs-Rest (OvR): train \(K\) classifiers, each “class \(k\) vs. all others”; predict the highest-scoring. Cheap (\(K\) models) but classes are imbalanced within each problem.
One-vs-One (OvO): train \(\binom{K}{2}\) classifiers, one per pair; predict by majority vote. More models but each is small and balanced — this is what LIBSVM/
SVCuses.
For large \(K\), OvO’s \(O(K^2)\) count grows, but each model trains on only the two relevant classes, so total cost is often manageable.
Getting probabilities
The raw score \(\vw^\top\vx+b\) is a signed distance, not a probability. To get \(P(y\mid\vx)\), SVMs use Platt scaling: fit a logistic function \(\sigma(a\,f(\vx)+b)\) to the SVM scores on held-out data. scikit-learn does this when you pass probability=True — but be aware it runs an internal cross-validation (slower) and the resulting probabilities can be inconsistent with the decision_function ranking. For ranking/thresholding you often don’t need probabilities at all; use decision_function directly.
The practitioner’s checklist
A reliable SVM workflow:
Standardize features (zero mean, unit variance) — mandatory, especially for RBF.
Choose a kernel: linear for high-dim/sparse (text); RBF as the nonlinear default.
Tune \(C\) (and \(\gamma\) for RBF) on a log grid by cross-validation; they interact, so search jointly.
Handle imbalance with
class_weight="balanced"and judge with the right metric (PR-AUC/F1, not accuracy).Wrap everything in a
Pipelineso scaling is fit inside each CV fold (no leakage).Mind scale: kernel
SVCfor up to \(\sim10^4\)–\(10^5\) rows;LinearSVC/SGD beyond.
One-class SVM for anomaly detection
A one-class SVM learns the support of “normal” data: it finds a boundary (in kernel feature space) enclosing most training points, flagging anything outside as an anomaly. With no labels needed, it is a classic tool for novelty and outlier detection (fraud, fault monitoring, intrusion). The parameter \(\nu\) sets the expected fraction of outliers. It reappears in Chapter [ch:svmmlai] as the surprising mathematical model for self-supervised contrastive learning.
Production gotchas. (1) Scaling leakage: fitting the scaler on all data before splitting leaks test statistics — always scale inside the pipeline/folds. (2) probability=True surprises: it retrains with CV and can disagree with decision_function; only enable it if you truly need probabilities. (3) Imbalance ignored: a 99/1 problem scores 99% by predicting the majority — set class_weight and use PR-AUC. (4) Default gamma left untuned. (5) Kernel SVM on too-large data, where training silently takes hours — subsample or go linear.
The practical scaffolding here — standardize, pipeline, grid/Bayesian search, calibrate, threshold, judge with the right metric — is identical to MLOps for any model, deep learning included, and uses the same tooling (scikit-learn pipelines, Optuna). Platt scaling, invented to calibrate SVMs, is now applied to neural networks too (alongside temperature scaling) to fix their overconfidence. And the one-class SVM is not just a legacy tool: it is the conceptual template for modern self-supervised representation learning (Chapter [ch:svmmlai]).
from sklearn.svm import SVC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_wine
X, y = load_wine(return_X_y=True) # 3 classes
pipe = make_pipeline(StandardScaler(),
SVC(kernel="rbf", class_weight="balanced",
decision_function_shape="ovo"))
grid = {"svc__C": [0.1, 1, 10], "svc__gamma": ["scale", 0.01, 0.1]}
gs = GridSearchCV(pipe, grid, cv=5).fit(X, y)
print("best:", gs.best_params_, " cv acc:", round(gs.best_score_, 3))Chapter summary
Multiclass via One-vs-Rest (\(K\) models) or One-vs-One (\(\binom{K}{2}\) models, used by
SVC).SVMs aren’t probabilistic; get \(P(y\mid\vx)\) via Platt scaling (
probability=True) — or usedecision_functionfor ranking.Always standardize, pipeline to avoid leakage, tune \(C,\gamma\) jointly, and handle imbalance with
class_weight.One-class SVM (\(\nu\)) detects anomalies without labels — and models contrastive learning later.
Use kernel
SVCup to \(\sim10^5\) rows; switch toLinearSVC/SGD beyond.