numpy
array normalization
unit vector
data processing
linear algebra

How to normalize a numpy array to a unit vector

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Normalizing a NumPy array to a unit vector means scaling it so its length becomes 1 while keeping the same direction. This is a standard operation in linear algebra, machine learning, signal processing, and graphics.

The most common normalization is L2 normalization, where you divide the vector by its Euclidean norm. In NumPy, that is usually a one-line operation, but there are a few important edge cases to handle correctly.

Normalizing a Single Vector

For a one-dimensional array, compute the norm with np.linalg.norm and divide the vector by that value.

python
1import numpy as np
2
3
4def normalize(vector: np.ndarray) -> np.ndarray:
5    vector = np.asarray(vector, dtype=float)
6    norm = np.linalg.norm(vector)
7
8    if norm == 0.0:
9        raise ValueError("Cannot normalize the zero vector")
10
11    return vector / norm
12
13
14v = np.array([3.0, 4.0])
15u = normalize(v)
16
17print(u)                       # [0.6 0.8]
18print(np.linalg.norm(u))       # 1.0

The array is converted to float first so division behaves predictably and the result is suitable for downstream numeric work.

Why np.linalg.norm Is Preferred

You could compute the norm manually with a square-root expression, but np.linalg.norm is clearer and generalizes well across shapes and axes.

python
1manual = np.sqrt((v ** 2).sum())
2library = np.linalg.norm(v)
3
4print(manual == library)

For most code, the library version is easier to read and less error-prone.

Normalizing Multiple Vectors by Row

If you have a matrix where each row is a vector, normalize along axis=1 and keep dimensions so broadcasting works correctly.

python
1import numpy as np
2
3vectors = np.array(
4    [
5        [3.0, 4.0],
6        [1.0, 2.0],
7        [0.0, 0.0],
8    ]
9)
10
11norms = np.linalg.norm(vectors, axis=1, keepdims=True)
12
13unit_vectors = np.divide(
14    vectors,
15    norms,
16    out=np.zeros_like(vectors, dtype=float),
17    where=norms != 0,
18)
19
20print(unit_vectors)
21print(np.linalg.norm(unit_vectors[0]))
22print(np.linalg.norm(unit_vectors[1]))

Using keepdims=True preserves the column dimension, which makes the division broadcast row by row. The where argument prevents division by zero for zero rows.

Choosing the Right Axis

Axis choice determines what gets normalized:

  • 'axis=0 normalizes each column'
  • 'axis=1 normalizes each row'
  • no axis normalizes the entire flattened array as one vector

That means the correct answer depends on how your data is organized. In machine learning, rows often represent samples, so axis=1 is a common choice for per-sample normalization. In other domains, columns may represent features or basis vectors, so axis=0 may be the intended operation.

Handling Zero Vectors

The zero vector cannot be normalized in the usual sense because its norm is zero, which makes division undefined. You need an explicit policy for this case:

  • Raise an exception
  • Leave the zero vector unchanged
  • Replace it with zeros in the output

The right choice depends on the application. If a zero vector indicates corrupt input, raising an error is appropriate. If zero rows are expected, using np.divide with where=norms != 0 is often the cleanest batch-processing approach.

Verifying the Result

After normalization, the norm should be very close to 1, though floating-point arithmetic means you should usually check with tolerance rather than exact equality.

python
u = normalize([10, -2, 7])
print(np.allclose(np.linalg.norm(u), 1.0))

np.allclose is preferable to a strict equality check for floating-point results.

Common Pitfalls

The most common pitfall is ignoring zero vectors. A silent division by zero can produce nan or inf values that spread through later computations.

Another issue is normalizing along the wrong axis. If the output shape looks correct but the numbers seem wrong, axis selection is often the cause.

It is also easy to forget dtype=float when using out=np.zeros_like(...). If the output array inherits an integer dtype, the normalized values may be truncated or the operation may fail depending on the exact code path.

Finally, do not confuse L2 normalization with other scaling methods such as min-max scaling or standardization. Those serve different goals and produce different outputs.

Summary

  • A unit vector is obtained by dividing a vector by its L2 norm.
  • 'np.linalg.norm is the standard and readable way to compute that norm in NumPy.'
  • For row-wise normalization, use axis=1 with keepdims=True for clean broadcasting.
  • Zero vectors need explicit handling because they cannot be normalized by ordinary division.
  • Use np.allclose to verify that the resulting norm is approximately 1.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.