Index Ai Academy
Phase 3 · Machine learning · Models

Support vector machines

The widest margin, support vectors, the hinge loss and C, kernels for curved boundaries, and when an SVM fits.

About 30 minutes · A free account opens the whole lesson

Create a free account Try part of it here

Already have an account? Sign in to open this lesson

Why it matters

Many lines can separate two classes perfectly on the training data, and they don't all predict equally well on new data. Support vector machines answer "which line?" with a principle: the one that leaves the widest gap to the nearest examples of each class. That idea gives a model that depends on only a handful of training points, works well with many features and little data, and, with kernels, draws curved boundaries. SVMs are still a strong choice for text classification and small tabular problems, and the hinge loss behind them shows up again in ranking and embedding training.

What you'll be able to do

  • Explain the maximum-margin idea and which training points the boundary depends on
  • Compute the hinge loss and the margin width from a weight vector
  • Tune C to trade a wide margin against training mistakes
  • Use a kernel for curved boundaries, and know when an SVM is the right tool

What it covers

  1. The widest street
  2. Support vectors
  3. Soft margins and C
  4. The hinge loss
  5. Seeing C at work
  6. Kernels: curved boundaries without new features
  7. When to reach for an SVM
Quick check
A guess first. Two lines both separate the training points perfectly. One passes right next to some points; the other keeps as far from both classes as it can. Which is likely better on new data?
  1. The one with the widest gap to both classes
  2. They're equally good: both make no mistakes
  3. The one that passes closest to the points
  4. Whichever was found first
Show the answer

The one with the widest gap to both classes

New points vary a little from the training points. A boundary with room to spare on both sides tolerates that variation; one that skims the training points misclassifies the first new point that lands slightly differently.

The widest street

Picture the boundary as the middle of a street, with the two classes on either side. A linear classifier scores a point as w⋅x+bw \cdot x + b: positive on one side, negative on the other. An SVM requires every training point to score at least +1 (one class) or at most -1 (the other), so the street's edges are where the score is ±1, and asks for the widest such street. The width works out to:

margin width=2∥w∥\text{margin width} = \frac{2}{\lVert w \rVert}

In plain words: smaller weights mean a gentler slope, so the score takes longer to climb from -1 to +1, and the street is wider. Maximizing the margin means making ww as small as the constraints allow.

Quick check
A trained SVM has weights w = (3, 4). How wide is its margin?
import math
w = (3, 4)
print(2 / math.hypot(*w))
  1. 0.2
  2. 0.4
  3. 5.0
  4. 2.5
Show the answer

0.4

The length of w is 5, so the width is 2/5 = 0.4. Halving the weights would double the width.

Support vectors

The points that sit exactly on the edges of the street are the support vectors. Move any other point, as long as it stays off the street, and the boundary doesn't change at all. A model that depends on a few points near the border, not on the bulk far away, is the defining trait of an SVM.

Compare logistic regression, which every point pulls on a little, even ones far from the boundary. Neither is better everywhere; they're different bets about which examples carry the information.

Quick check
You move a training point that sits far from the street, deep in its own class's side. What happens to the SVM's boundary?
  1. It rotates by a small amount
  2. It has to be retrained from scratch
  3. It shifts toward the moved point
  4. Nothing, as long as it stays off the street
Show the answer

Nothing, as long as it stays off the street

Only support vectors, on or inside the street, shape the boundary. Points far from it contribute nothing, so moving them changes nothing.

In your own words
What does an SVM look for, and which points shape it?

Write a sentence or two, then compare it with a good answer in the lesson.

Soft margins and C

Real data overlaps, so a street with no points on it usually doesn't exist. The soft-margin SVM allows points inside the street or on the wrong side, and charges for each with the hinge loss:

hinge(x,y)=max⁡(0,  1−y (w⋅x+b))\text{hinge}(x, y) = \max\big(0,\; 1 - y\,(w \cdot x + b)\big)

with labels y=±1y = \pm 1. A point comfortably on its side, scoring beyond ±1, costs nothing. A point inside the street costs a little, and one on the wrong side costs more, growing with how far it is. Training minimizes the size of ww plus CC times the total hinge loss.

C sets the trade. A large C punishes every mistake, so the street narrows to fit the training data closely, which risks overfitting. A small C tolerates mistakes for a wider street and a smoother, more general boundary. As with any setting that controls fit, choose C by cross-validation.

When one class is much rarer than the other, such as fraud among payments, the hinge losses of the common class outnumber the rare one's and push the boundary toward it. Setting class_weight="balanced" makes each mistake on the rare class cost more, in proportion to how rare it is, so the margin stops ignoring it.

Drill

The hinge loss

Write hinge(score, y) for one point: max(0, 1 - y * score), where score is the model's w · x + b and y is +1 or -1.

def hinge(score, y):
    return 0.0


print(hinge(2.5, 1), hinge(0.4, 1), hinge(0.4, -1))
In the lesson, your code is checked as you write it.

Seeing C at work

scikit-learn's SVC trains an SVM and reports its support vectors. Here two overlapping clouds are fitted with a small and a large C:

import numpy as np
from sklearn.svm import SVC

rng = np.random.default_rng(0)
X = np.vstack([rng.normal([2, 2], 1.0, (40, 2)), rng.normal([4, 4], 1.0, (40, 2))])
y = np.array([0] * 40 + [1] * 40)
for C in (0.01, 100):
    model = SVC(kernel="linear", C=C).fit(X, y)
    width = 2 / np.linalg.norm(model.coef_[0])
    print(f"C={C}: {len(model.support_)} support vectors, margin width {width:.2f}, training accuracy {model.score(X, y):.2f}")

With a small C, the street is wide and many points lie on or inside it, so many points are support vectors. With a large C, the street shrinks to the few points that are hardest to separate. Neither is right in general: C is chosen on held-out data.

Quick check
You raise C from 0.01 to 100 on overlapping data. What happens to the margin?
  1. It widens, to make fewer mistakes
  2. It narrows, to make fewer training mistakes
  3. Nothing: C only affects the speed
  4. It disappears entirely
Show the answer

It narrows, to make fewer training mistakes

A large C makes each training mistake expensive, so the SVM accepts a narrower street to fit the training points more closely.

In your own words
What does raising C do?

Write a sentence or two, then compare it with a good answer in the lesson.

Kernels: curved boundaries without new features

A straight line can't separate a ring of one class around a blob of the other. One fix is to add features, such as x12+x22x_1^2 + x_2^2, the squared distance from the center, after which a straight boundary in the bigger feature space is a circle in the original. The kernel trick gets the same effect without building those features: the SVM's math only ever needs similarities between pairs of points, so you can swap in a similarity that behaves like a richer space.

The common choice is the RBF (radial basis function) kernel, exp⁡(−γ∥x−x′∥2)\exp(-\gamma \lVert x - x' \rVert^2): points close together are similar, far apart are not. Its γ\gamma sets how far each training point's influence reaches. A small γ\gamma gives smooth boundaries; a large one wraps tightly around individual points and overfits.

from sklearn.datasets import make_moons
from sklearn.model_selection import cross_val_score
from sklearn.svm import SVC

X, y = make_moons(n_samples=300, noise=0.2, random_state=0)
for name, model in [("linear", SVC(kernel="linear")), ("RBF", SVC(kernel="rbf", gamma=1.0))]:
    print(name, round(cross_val_score(model, X, y, cv=5).mean(), 2))

The curved RBF boundary separates the crescents far better than any straight line can.

Quick check
The RBF kernel scores two points' similarity as exp(-γ · squared distance). With γ = 1, two points a squared distance of 2 apart score what?
import math
gamma, squared_distance = 1.0, 2.0
print(round(math.exp(-gamma * squared_distance), 3))
  1. 7.389
  2. 0.135
  3. 2.0
  4. 0.5
Show the answer

0.135

exp(-2) ≈ 0.135: fairly dissimilar. Identical points score 1, and the score falls toward 0 with distance; a larger γ makes it fall faster.

Try it now

The order of a real scikit-learn pipeline: data, a scaler and the model joined, then fit and score.

Quick check
A reminder from the regularization lesson. Making C smaller in an SVM plays the same role as what in ridge regression?
  1. A smaller penalty on the weights
  2. A higher learning rate
  3. A larger penalty on the weights
  4. More training data
Show the answer

A larger penalty on the weights

Both trade fitting the training data against keeping the weights small. Small C, like a strong ridge penalty, favors small weights and a simpler model.

When to reach for an SVM

SVMs do well with many features and modest data: text classification on TF-IDF features is a classic strength, as are small scientific and tabular problems. A linear SVM on text trains in seconds and is hard to beat as a baseline. SVMs separate two classes at a time; with more, scikit-learn trains one per pair or one per class behind the scenes, and LinearSVC handles hundreds of thousands of rows when the boundary can be straight.

Three practical notes. Scale your features: the margin is a distance, so a feature measured in thousands swamps one measured in fractions; put a StandardScaler in front. Kernel SVMs grow slowly with data: training compares pairs of points, so beyond some tens of thousands of rows, a linear SVM, logistic regression or a tree ensemble is the practical choice. SVMs don't give probabilities natively: their scores are distances from the boundary. When you need calibrated probabilities, logistic regression gives them directly, or calibrate the SVM's scores on held-out data.

Quick check
Which problem suits an SVM best?
  1. Ranking search results by probability of a click, with calibrated probabilities
  2. Classifying 5,000 support tickets from TF-IDF features
  3. Predicting a price from 10 million rows of tabular data
  4. Generating text from a prompt
Show the answer

Classifying 5,000 support tickets from TF-IDF features

Many sparse features and modest data is where SVMs shine. Ten million rows is too many for a kernel SVM, generation isn't classification, and calibrated probabilities come more naturally from logistic regression.

In your own words
What does a kernel give you, and when is an SVM the right tool?

Write a sentence or two, then compare it with a good answer in the lesson.

Practice what you just read

  • 2 code examples you can edit and run
  • a practice exercise that checks your code
  • a 5-question quiz
  • 6 review cards for spaced repetition

Create a free account

Try a quiz question

Which training points determine an SVM's boundary?

  1. The support vectors, on or inside the margin
  2. Every training point equally
  3. The points farthest from the boundary
  4. The class averages

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson