Broadcasting lets NumPy perform arithmetic between arrays of different but compatible shapes without copying data. A smaller array is virtually stretched along dimensions of size 1 to match the larger array.
equal
or either is 1
.1
, broadcasting fails.# Example A: (3, 4) +/- (4,) -> OK
# Align from right: (3, 4)
# ( 4) <-- 1D treated as (1,4), row-wise
# Result: (3,4)
# Example B: (3, 1) + (1, 4) -> OK
# Align: (3, 1)
# (1, 4)
# Result: (3,4) (each 1 expands)
# Example C: (2, 3) + (2,) -> FAIL
# Align: (2, 3)
# ( 2)
# 3 != 2 and neither is 1 -> ValueError
import numpy as np
A = np.arange(12).reshape(3,4)
row = np.array([10, 20, 30, 40]) # shape (4,)
col = np.array([[100],[200],[300]]) # shape (3,1)
print(A + row) # adds to each row
print(A + col) # adds to each column group
NumPy 1D arrays have shape (N,)
(no row/col). Use np.newaxis
or reshape
to make explicit row/column vectors:
v = np.array([1, 2, 3, 4]) # shape (4,)
row_v = v[np.newaxis, :] # (1,4) row vector
col_v = v[:, np.newaxis] # (4,1) column vector
M = np.arange(8).reshape(2,4)
print(M + row_v) # OK: (2,4) + (1,4) -> (2,4)
print(M + col_v) # ValueError: (2,4) + (4,1) -- incompatible
# To add col-wise properly:
print(M + col_v[:2]) # (2,4) + (2,1) -> (2,4)
T = np.arange(2*3*4).reshape(2,3,4) # (depth=2, rows=3, cols=4)
bias_row = np.array([1,2,3,4]) # (4,)
bias_depth = np.array([100, 200]) # (2,)
print(T + bias_row) # (2,3,4) + (4,) -> (2,3,4)
print(T + bias_depth[:, None, None]) # (2,3,4) + (2,1,1) -> (2,3,4)
print(arr.shape)
, then align dimensions using np.newaxis
or reshape
.(1,N)
or (N,1)
depending on whether you want row-wise or column-wise broadcasting.# Standardize columns: (N, D) array -> subtract column means, divide by std
X = np.array([[1.0, 2.0, 3.0],
[2.0, 3.0, 4.0],
[3.0, 4.0, 5.0]])
mu = X.mean(axis=0) # (D,)
sigma = X.std(axis=0) # (D,)
Xz = (X - mu) / sigma # (N,D) - (D,) -> (N,D)
# Distance matrix between two sets: (N, d) and (M, d)
A = np.array([[0,0],[1,1],[2,2]]) # (3,2)
B = np.array([[0,1],[1,2]]) # (2,2)
diff = A[:, None, :] - B[None, :, :] # (3,1,2) - (1,2,2) -> (3,2,2)
D = np.sqrt((diff**2).sum(axis=-1)) # (3,2)
a = np.arange(6).reshape(2,3) # (2,3)
b = np.array([10,20]) # (2,)
# a + b -> ValueError (because 3 != 2, neither is 1)
# Fix 1: treat b as column vector (2,1)
b_col = b[:, None]
print(a + b_col) # (2,3) + (2,1) -> (2,3)
# Fix 2: repeat/expand if truly needed (use with care)
b_tiled = np.tile(b[:, None], (1, 3)) # explicit (2,3)
print(a + b_tiled)
tile
/repeat
: use broadcasting first; materialize only when required by APIs.%timeit
and observe peak memory when broadcasting to very large shapes.# 1) Add a column bias [100, 200, 300] to a (3,4) matrix using broadcasting
M = np.arange(12).reshape(3,4)
bias = np.array([100, 200, 300])[:, None]
print(M + bias)
# 2) Scale each column of (5,3) by [1.0, 0.5, 2.0] without loops
X = np.arange(15).reshape(5,3)
scale = np.array([1.0, 0.5, 2.0])
print(X * scale)
# 3) Given (2,3,4) tensor T, add depth-wise bias [10, 20] correctly
T = np.arange(24).reshape(2,3,4)
depth_bias = np.array([10, 20])[:, None, None]
print(T + depth_bias)
Author
🎥 Join me live on YouTubePassionate about coding and teaching, I publish practical tutorials on PHP, Python, JavaScript, SQL, and web development. My goal is to make learning simple, engaging, and project‑oriented with real examples and source code.