Skip to content

How to Compute the Angle Between Vectors in Python

Learn how to calculate the angle between two vectors in Python using the dot product formula, NumPy, or cross product methods for machine learning, physics, and data science applications.

Computing the angle between two vectors is a fundamental operation in linear algebra with applications across machine learning, computer graphics, physics simulations, and data science. Whether you're calculating similarity between feature vectors, determining the direction of movement, or analyzing forces, knowing how to find the angle between vectors is essential.

In this guide, you'll learn multiple methods to compute the angle between vectors in Python, using pure math, NumPy, and the cross product, with clear explanations of the underlying formulas and practical examples.

The Math Behind Vector Angles

The angle between two vectors u and v is derived from the dot product formula:

u · v = ‖u‖ ‖v‖ cos(θ)

Solving for θ:

θ = arccos( (u · v) / (‖u‖ ‖v‖) )

Where:

  • u · v is the dot product of the vectors
  • ‖u‖ and ‖v‖ are the magnitudes (lengths) of the vectors
  • θ is the angle between them

Using Pure Python (No Libraries)

You can compute the angle using only Python's built-in math module, no external libraries required:

import math

def angle_between_vectors(u, v):
    """
    Compute the angle between two vectors using the dot product.
    
    Args:
        u, v: Lists or tuples representing vectors.
    
    Returns:
        Tuple of (angle_radians, angle_degrees).
    """
    dot_product = sum(a * b for a, b in zip(u, v))

    magnitude_u = math.sqrt(sum(a ** 2 for a in u))
    magnitude_v = math.sqrt(sum(b ** 2 for b in v))

    cos_theta = dot_product / (magnitude_u * magnitude_v)

    cos_theta = max(-1.0, min(1.0, cos_theta))

    angle_rad = math.acos(cos_theta)
    angle_deg = math.degrees(angle_rad)

    return angle_rad, angle_deg


u = [3, 4]
v = [5, -2]

angle_rad, angle_deg = angle_between_vectors(u, v)
print(f"Angle in radians: {angle_rad:.4f}")
print(f"Angle in degrees: {angle_deg:.2f}°")

Output:

Angle in radians: 1.3078
Angle in degrees: 74.93°

NumPy provides optimized functions for vector operations, making the computation cleaner and significantly faster for large arrays:

import numpy as np

def angle_between_vectors(u, v):
    """Compute the angle between two vectors using NumPy."""
    u = np.array(u, dtype=float)
    v = np.array(v, dtype=float)

    cos_theta = np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v))
    angle_rad = np.arccos(np.clip(cos_theta, -1.0, 1.0))

    return angle_rad, np.degrees(angle_rad)


u = [3, 4]
v = [5, -2]

angle_rad, angle_deg = angle_between_vectors(u, v)
print(f"Angle in radians: {angle_rad:.4f}")
print(f"Angle in degrees: {angle_deg:.2f}°")

Output:

Angle in radians: 1.3078
Angle in degrees: 74.93°

Key NumPy functions used:

Function Purpose
np.dot(u, v) Computes the dot product
np.linalg.norm(u) Computes the vector magnitude
np.clip(val, -1, 1) Clamps value to valid arccos range
np.arccos(val) Computes the inverse cosine
np.degrees(rad) Converts radians to degrees

Using the Cross Product (3D Vectors)

For 3-dimensional vectors, the cross product provides an alternative method. The magnitude of the cross product relates to the sine of the angle:

‖u × v‖ = ‖u‖ ‖v‖ sin(θ)

However, the most robust approach combines both the dot product and cross product using atan2, which correctly handles all quadrants and avoids the precision issues of arccos and arcsin alone:

import numpy as np

def angle_between_3d_vectors(u, v):
    """
    Compute the angle between two 3D vectors using atan2
    with both cross product and dot product for maximum accuracy.
    """
    u = np.array(u, dtype=float)
    v = np.array(v, dtype=float)

    cross = np.cross(u, v)
    sin_theta = np.linalg.norm(cross)
    cos_theta = np.dot(u, v)

    angle_rad = np.arctan2(sin_theta, cos_theta)
    return angle_rad, np.degrees(angle_rad)


u = [3, 2, 1]
v = [1, 0, 2]

angle_rad, angle_deg = angle_between_3d_vectors(u, v)
print(f"Angle in radians: {angle_rad:.4f}")
print(f"Angle in degrees: {angle_deg:.2f}°")

Output:

Angle in radians: 0.9303
Angle in degrees: 53.30°

Special Cases to Handle

Zero Vectors

A zero vector has no direction, so the angle is undefined:

import numpy as np

def safe_angle(u, v):
    """Compute angle with zero-vector protection."""
    u = np.array(u, dtype=float)
    v = np.array(v, dtype=float)

    norm_u = np.linalg.norm(u)
    norm_v = np.linalg.norm(v)

    if norm_u == 0 or norm_v == 0:
        raise ValueError("Cannot compute angle with a zero vector.")

    cos_theta = np.dot(u, v) / (norm_u * norm_v)
    angle_rad = np.arccos(np.clip(cos_theta, -1.0, 1.0))
    return angle_rad, np.degrees(angle_rad)


try:
    safe_angle([0, 0], [1, 2])
except ValueError as e:
    print(f"Error: {e}")

Output:

Error: Cannot compute angle with a zero vector.

Common Angle Results

import numpy as np

def angle_deg(u, v):
    u, v = np.array(u, dtype=float), np.array(v, dtype=float)
    cos_t = np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v))
    return np.degrees(np.arccos(np.clip(cos_t, -1, 1)))

print(f"Parallel:      {angle_deg([1, 0], [3, 0]):.1f}°")

print(f"Opposite:      {angle_deg([1, 0], [-1, 0]):.1f}°")

print(f"Perpendicular: {angle_deg([1, 0], [0, 1]):.1f}°")

print(f"45 degrees:    {angle_deg([1, 0], [1, 1]):.1f}°")

Output:

Parallel:      0.0°
Opposite:      180.0°
Perpendicular: 90.0°
45 degrees:    45.0°

Computing Angles for Multiple Vector Pairs

When processing many vector pairs (common in machine learning), NumPy's vectorized operations are far more efficient than looping:

import numpy as np

def batch_angles(vectors_u, vectors_v):
    """Compute angles between corresponding pairs of vectors."""
    u = np.array(vectors_u, dtype=float)
    v = np.array(vectors_v, dtype=float)

    dots = np.sum(u * v, axis=1)

    norms_u = np.linalg.norm(u, axis=1)
    norms_v = np.linalg.norm(v, axis=1)

    cos_theta = dots / (norms_u * norms_v)
    angles_rad = np.arccos(np.clip(cos_theta, -1.0, 1.0))

    return np.degrees(angles_rad)


u_vectors = [[1, 0], [0, 1], [1, 1], [3, 4]]
v_vectors = [[0, 1], [0, 1], [-1, 1], [5, -2]]

angles = batch_angles(u_vectors, v_vectors)

for u, v, angle in zip(u_vectors, v_vectors, angles):
    print(f"{u} ↔ {v}: {angle:.2f}°")

Output:

[1, 0] ↔ [0, 1]: 90.00°
[0, 1] ↔ [0, 1]: 0.00°
[1, 1] ↔ [-1, 1]: 90.00°
[3, 4] ↔ [5, -2]: 74.93°

Quick Comparison of Methods

Method Dimensions Accuracy Dependencies Best For
Pure Python (dot product) Any Good (with clamping) None Simple scripts, no dependencies
NumPy (dot product) Any Good (with np.clip) numpy General-purpose, production code
Cross product + atan2 3D only ✅ Best numpy Maximum numerical stability
Batch NumPy Any Good numpy Processing many vector pairs

Conclusion

Computing the angle between vectors in Python is straightforward once you understand the underlying math:

  • Use the dot product formula with arccos for a clean, general-purpose solution. This works for vectors of any dimension.
  • Use NumPy for cleaner syntax and significantly better performance, especially with large or numerous vectors.
  • Use the cross product with atan2 for 3D vectors when you need maximum numerical stability.
  • Always clamp the cosine value to [-1, 1] before passing it to arccos to prevent floating-point domain errors.

For most applications, the NumPy dot product approach strikes the best balance of simplicity, performance, and reliability.

Navigation