Support Vector Machines: the maximum margin
What it is
Among all the hyperplanes that separate two classes, an SVM picks the one whose distance to the nearest point of either class is largest. That distance is the margin; the points sitting exactly on the margin's edges are the support vectors, and they alone determine the boundary.
Why it matters
Maximising the margin is a principled answer to 'which of the infinitely many separating lines should I use', and it generalises well: a wide margin means the boundary can move a long way before any training point changes side. It is also why the model is so compact — everything but the support vectors can be discarded.
In the real world: Drawing the widest possible gap between genuine and fake product reviews, which holds up well on new reviews.
Visual example
SVC(kernel='linear')Two classes, the maximum-margin boundary, and the shaded margin. Only the three circled support vectors touch it.
The margin, numerically
boundary at x1 = 0.05; nearest class-0 point at x1 = -0.6, nearest class-1 at x1 = 0.7
margin half-width = 0.65, so the full margin is 1.30 wide
any other separating line would have one class closer than 0.65
3 support vectors out of 16 points: the other 13 could be deleted
Why this matters
Almost every training point is irrelevant to the fitted boundary. That is what 'support vector' means, and it is why an SVM is robust to points far from the boundary and extremely sensitive to points on it.
Common misconception
Wrong idea: the SVM boundary is the line that best separates the bulk of the two clouds.
Correct idea: it is determined entirely by the few closest points. Add a thousand class-0 rows far to the left and the boundary does not move a millimetre.
- 1Find candidatesEvery hyperplane that separates the classes (with slack, if none does).
- 2Maximise the gapPick the one whose nearest point on either side is farthest away.
- 3Keep the supportOnly the points on the margin edges enter the final model.
from sklearn.svm import SVC
svc = make_pipeline(StandardScaler(), SVC(kernel="linear", C=1.0)).fit(X_train, y_train)
model = svc[-1]
model.support_vectors_.shape # (34, 30) — only 34 of 455 rows matter
model.n_support_ # per class
model.decision_function(svc[0].transform(X_test[:5])).round(3)
# signed distance to the hyperplane; the sign is the predictionCalling SVC(probability=True) and treating the output as a real probability. It fits a separate Platt-scaling logistic model by internal 5-fold CV, which is slow, can disagree with predict on borderline points, and is only as good as that calibration. If you need ranking, use decision_function; if you need calibrated probabilities, use CalibratedClassifierCV deliberately.