Skip to content

How to Perform Matrix Addition and Subtraction in Python

Learn efficient matrix addition and subtraction in Python using NumPy's optimized arrays or pure Python implementations for educational purposes.

Matrix operations form the foundation of scientific computing, machine learning, and data analysis. Python offers multiple approaches to matrix arithmetic, from optimized NumPy operations to pure Python implementations. This guide covers both methods and helps you choose the right tool for your situation.

Using NumPy for Matrix Operations

NumPy provides the most efficient and readable approach to matrix mathematics. Its arrays support element-wise operations with standard arithmetic operators.

Basic Addition and Subtraction

import numpy as np

A = np.array([[1, 2, 3],
              [4, 5, 6]])

B = np.array([[7, 8, 9],
              [10, 11, 12]])

sum_matrix = A + B
print("A + B:")
print(sum_matrix)

diff_matrix = A - B
print("\nA - B:")
print(diff_matrix)

Output:

A + B:
[[ 8 10 12]
 [14 16 18]]

A - B:
[[-6 -6 -6]
 [-6 -6 -6]]

Using NumPy Functions

NumPy also provides explicit functions that offer additional control:

import numpy as np

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

sum_result = np.add(A, B)
diff_result = np.subtract(A, B)

print(f"Sum:\n{sum_result}")
print(f"\nDifference:\n{diff_result}")

C = np.array([[1, 2], [3, 4]])
np.add(C, B, out=C)  # Result stored directly in C
print(f"\nIn-place addition:\n{C}")

Output:

Sum:
[[ 6  8]
 [10 12]]

Difference:
[[-4 -4]
 [-4 -4]]

In-place addition:
[[ 6  8]
 [10 12]]

Broadcasting with Scalars

NumPy automatically broadcasts scalar values across matrices:

import numpy as np

A = np.array([[1, 2, 3],
              [4, 5, 6]])

print("A + 10:")
print(A + 10)

print("\nA - 2:")
print(A - 2)

Output:

A + 10:
[[11 12 13]
 [14 15 16]]

A - 2:
[[-1  0  1]
 [ 2  3  4]]

Working with Different Shapes

Broadcasting also works with compatible array shapes:

import numpy as np

A = np.array([[1, 2, 3],
              [4, 5, 6]])

row = np.array([10, 20, 30])

col = np.array([[100],
                [200]])

print("Matrix + Row vector:")
print(A + row)

print("\nMatrix + Column vector:")
print(A + col)

Output:

Matrix + Row vector:
[[11 22 33]
 [14 25 36]]

Matrix + Column vector:
[[101 102 103]
 [204 205 206]]

Pure Python Implementation

When NumPy isn't available or you need to understand the underlying mechanics, implement matrix operations using nested lists.

Using List Comprehensions

def matrix_add(A, B):
    """Add two matrices represented as nested lists."""
    return [
        [a + b for a, b in zip(row_a, row_b)]
        for row_a, row_b in zip(A, B)
    ]

def matrix_subtract(A, B):
    """Subtract matrix B from matrix A."""
    return [
        [a - b for a, b in zip(row_a, row_b)]
        for row_a, row_b in zip(A, B)
    ]


A = [[1, 2, 3],
     [4, 5, 6]]

B = [[7, 8, 9],
     [10, 11, 12]]

print("A + B:")
for row in matrix_add(A, B):
    print(row)

print("\nA - B:")
for row in matrix_subtract(A, B):
    print(row)

Output:

A + B:
[8, 10, 12]
[14, 16, 18]

A - B:
[-6, -6, -6]
[-6, -6, -6]

Generalized Operation Function

Create a flexible function that handles any element-wise operation:

def matrix_operation(A, B, operation):
    """
    Apply an operation element-wise to two matrices.
    
    Args:
        A: First matrix (nested list)
        B: Second matrix (nested list)
        operation: Function taking two numbers, returning a number
    
    Returns:
        Result matrix as nested list
    """
    if len(A) != len(B) or len(A[0]) != len(B[0]):
        raise ValueError("Matrices must have the same dimensions")
    
    return [
        [operation(a, b) for a, b in zip(row_a, row_b)]
        for row_a, row_b in zip(A, B)
    ]


A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]

result_add = matrix_operation(A, B, lambda a, b: a + b)
print(f"Addition: {result_add}")

result_sub = matrix_operation(A, B, lambda a, b: a - b)
print(f"Subtraction: {result_sub}")

result_avg = matrix_operation(A, B, lambda a, b: (a + b) / 2)
print(f"Average: {result_avg}")

Output:

Addition: [[6, 8], [10, 12]]
Subtraction: [[-4, -4], [-4, -4]]
Average: [[3.0, 4.0], [5.0, 6.0]]

Traditional Loop Approach

For maximum clarity or debugging purposes:

def matrix_add_verbose(A, B):
    """Add matrices using explicit loops."""
    rows = len(A)
    cols = len(A[0])
    
    result = [[0 for _ in range(cols)] for _ in range(rows)]
    
    for i in range(rows):
        for j in range(cols):
            result[i][j] = A[i][j] + B[i][j]
    
    return result


A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]

result = matrix_add_verbose(A, B)
print(result)  # [[6, 8], [10, 12]]

Performance Comparison

NumPy significantly outperforms pure Python for matrix operations:

import numpy as np
import time

def benchmark(size=500, iterations=100):
    """Compare NumPy vs pure Python performance."""
    
    A_list = [[i + j for j in range(size)] for i in range(size)]
    B_list = [[i * j for j in range(size)] for i in range(size)]
    
    A_numpy = np.array(A_list)
    B_numpy = np.array(B_list)
    
    start = time.perf_counter()
    for _ in range(iterations):
        result = [
            [a + b for a, b in zip(row_a, row_b)]
            for row_a, row_b in zip(A_list, B_list)
        ]
    python_time = time.perf_counter() - start
    
    start = time.perf_counter()
    for _ in range(iterations):
        result = A_numpy + B_numpy
    numpy_time = time.perf_counter() - start
    
    print(f"Matrix size: {size}x{size}")
    print(f"Pure Python: {python_time:.4f}s")
    print(f"NumPy:       {numpy_time:.4f}s")
    print(f"Speedup:     {python_time / numpy_time:.1f}x")


benchmark()

Typical Output:

Matrix size: 500x500
Pure Python: 4.2341s
NumPy:       0.0089s
Speedup:     475.7x

Method Comparison

Aspect NumPy Pure Python
Syntax A + B Nested comprehensions
Performance Optimized C code Interpreted loops
Memory Efficient arrays List overhead
Dependencies Requires NumPy No dependencies
Best for Production code Learning, minimal environments

Practical Applications

import numpy as np

image = np.random.randint(0, 256, size=(100, 100))
brightened = np.clip(image + 50, 0, 255)

model1_predictions = np.array([[0.8, 0.2], [0.6, 0.4]])
model2_predictions = np.array([[0.7, 0.3], [0.5, 0.5]])
ensemble = (model1_predictions + model2_predictions) / 2

actual = np.array([[10], [20], [30]])
predicted = np.array([[12], [18], [33]])
residuals = actual - predicted

For any serious numerical work, NumPy is the standard choice. Reserve pure Python implementations for educational purposes, dependency-free environments, or very small matrices where the overhead of importing NumPy isn't justified.

Navigation