Welcome back. You have already separated element-wise multiplication from matrix multiplication: * keeps one result per entry, while @ combines rows and columns. A vector dot product is the smallest useful case of that combination: it turns two equal-length vectors into one number.
In this lesson, you will compute dot products with NumPy and interpret them in two complementary ways:
- as a weighted sum, the calculation underlying linear-model scores; and
- as an indicator of directional alignment, which can support a similarity comparison when vector magnitudes are handled appropriately.
Plan for about 35–40 minutes, including a compact NumPy micro-challenge.
From paired products to one scalar
For two vectors of the same length,
their dot product is:
The process has two stages:
- Multiply corresponding entries.
- Sum the resulting products.
For example:
First compute the per-feature contributions:
Then add them:
This comparison should now feel familiar:
import numpy as np
x = np.array([2.0, -1.0, 0.5])
w = np.array([0.8, -0.4, 2.0])
contributions = x * w # one contribution per feature
score = x @ w # one scalar: sum of contributions
Here, contributions is [1.6, 0.4, 1.0], while score is 3.0.
For two one-dimensional NumPy arrays, these forms compute the same dot product:
np.dot(x, w)
x @ w
Both require the vectors to have equal length. The output is a scalar, not a vector:
print((x @ w).shape) # ()
The empty shape () is NumPy’s way of saying “zero-dimensional scalar result.”
To reinforce the computational mechanics, watch this short portion of The Dot Product — Topic 14 of Machine Learning Foundations by Jon Krohn.
The Dot Product — Topic 14 of Machine Learning Foundations
Watch this short explanation to see the dot product broken into corresponding multiplications followed by a reduction to one scalar, then reproduced with NumPy.
Watch the manual calculation and identify the two stages: pairwise multiplication and summation. Then watch the NumPy example, noting that np.dot() carries out the same calculation without a manual loop.
Interpretation 1: a weighted sum of features
The most immediately useful machine-learning interpretation is that a dot product is a weighted sum.
Suppose a record has three numeric features. A model assigns one coefficient, or weight, to each feature:
| Quantity | Meaning | Value |
|---|---|---|
| first feature value | ||
| second feature value | ||
| third feature value | ||
| weight for feature 1 | ||
| weight for feature 2 | ||
| weight for feature 3 |
The resulting score is:
Each product is that feature’s contribution to the total score:
- A feature with a positive value and positive weight raises the score.
- A feature with a positive value and negative weight lowers the score.
- A negative feature value reverses the contribution’s sign.
- A weight of zero means the feature contributes nothing to this linear score.
This is why inspecting only a model weight can be misleading. The impact for one observation depends on both the feature value and its weight.
Most tabular ML data consists of many observations, each with the same set of features. Put those observations into a feature matrix , where rows are records and columns are features:
Then:
In NumPy:
X = np.array([
[2.0, -1.0, 0.5],
[0.0, 3.0, 1.0]
])
w = np.array([0.8, -0.4, 2.0])
scores = X @ w
print(scores) # [3. 0.8]
This is matrix multiplication, but each output value is specifically a row-vector dot product:
So X @ w produces one weighted score per row. This operation will reappear when you implement linear regression and logistic regression from scratch.
A model often also includes an intercept, or bias:
The dot product aggregates feature contributions; the bias shifts every score by the same baseline amount. For now, keep those roles separate.
Interpretation 2: directional alignment and similarity
A dot product also has a geometric interpretation:
where is the angle between the vectors.

This formula gives a useful sign-based interpretation:
- If , the vectors point generally in similar directions.
- If , they are perpendicular, or orthogonal.
- If , they point generally in opposing directions.
For example:
Then:
because the vectors are perpendicular, while:
because they point in opposite directions.
a = np.array([1.0, 0.0])
b = np.array([0.0, 1.0])
c = np.array([-2.0, 0.0])
print(a @ b) # 0.0
print(a @ c) # -2.0
An important caveat about “similarity”
A raw dot product is affected by both direction and magnitude. A long vector can receive a large dot product even if its direction is not the closest match.
When “similarity” should mean directional similarity independent of scale, use cosine similarity:
For nonzero vectors, cosine similarity ranges from to :
- : exactly the same direction;
- : perpendicular directions;
- : exactly opposite directions.
In NumPy, the calculation is:
cosine_similarity = (x @ y) / (np.linalg.norm(x) * np.linalg.norm(y))
This formula is valid only when neither vector has norm zero. Later, when working with real data, you will need to guard against all-zero vectors before dividing.
The practical distinction is:
- Use a raw dot product when magnitude is meaningful, such as a weighted model score.
- Use cosine similarity when you want to compare directions or patterns while ignoring overall scale.
Concept-Level Micro-Challenge: inspect contributions and batch scores
Type and run this 15-line NumPy program. Before executing it, calculate the first score by hand and predict the shape of batch_scores.
import numpy as np
x = np.array([2.0, -1.0, 0.5])
w = np.array([0.8, -0.4, 2.0])
contributions = x * w
score = np.dot(x, w)
manual_score = contributions.sum()
X = np.array([[2.0, -1.0, 0.5], [0.0, 3.0, 1.0]])
batch_scores = X @ w
print("contributions:", contributions)
print("single score:", score)
print("batch scores:", batch_scores)
assert contributions.shape == (3,)
assert np.isclose(score, 3.0)
assert np.isclose(score, manual_score)
assert batch_scores.shape == (2,)
assert np.allclose(batch_scores, [3.0, 0.8])
Interpret your result rather than treating the assertions as the endpoint:
- The three values in
contributionsare individual feature contributions. scoreis their sum: one weighted score for one record.batch_scorescontains one dot product per row ofX.
If you change only the second weight from -0.4 to 0.4, identify which contributions change sign and explain why. This is a compact way to test whether you can reason from the formula rather than only call NumPy functions.
A debugging checklist for dot products
When a dot-product calculation fails or produces a surprising value, check these points in order:
-
Confirm the intended operation.
Usex * wto retain per-feature products; usex @ wornp.dot(x, w)to sum those products into a scalar. -
Inspect shapes.
print(x.shape, w.shape)For vector dot products, both should normally have shape
(n,). -
Check a contribution vector.
print(x * w)A negative contribution is not automatically an error. It may reflect a negative feature, a negative weight, or both.
-
Calculate one result manually.
For a short vector, manually add the products. For a matrix , manually verify one row score. -
Keep feature order fixed.
The first value inxmust correspond to the first weight inw, and so on. Equal lengths alone do not guarantee meaningful alignment.
That final point becomes critical once data is stored in DataFrames: a model weight vector is meaningful only when its feature ordering matches the preprocessing output.
Takeaways
A vector dot product multiplies corresponding entries and sums them into a single scalar:
In NumPy, use np.dot(x, w) or x @ w for equal-length one-dimensional arrays.
You can interpret the result in two ways:
- As a weighted sum, where each term is one feature’s contribution to a model score.
- As a measure of alignment, with positive, zero, and negative results indicating broadly aligned, perpendicular, and opposing directions. For scale-independent directional comparison, normalize to cosine similarity.
For a feature matrix, X @ w computes one weighted dot-product score per row. Next, you will move from these linear combinations to partial derivatives and gradients, which tell us how to change model parameters so that an error function decreases.
Can't find a good explanation? Sign up and we'll make it for you
Sign up