In [1]:
import numpy as np
In [2]:
a = np.array([0,1,2])
b = np.array([5,5,5])
a + b
Out[2]:
In [4]:
a, b
Out[4]:
In [5]:
a + 5
Out[5]:
In [6]:
M = np.ones((3,3)); M
Out[6]:
In [7]:
M + a
Out[7]:
In [8]:
a = np.arange(3)
b = np.arange(3)[:, np.newaxis]
print(a); print(b)
In [9]:
a + b
Out[9]:
Broadcasting in NumPy follows a strict set of rules to determine the interaction between the two arrays:
Rule 1: If the two arrays differ in their number of dimensions, the shape of the one with fewer dimensions is padded with ones on its leading (left) side.
Rule 2: If the shape of the two arrays doesn't match in any dimension, the array with shape equal to 1 in that dimension is stretched to match the other shape.
Rule 3: If in any dimension the sizes disagree and neither is equal to 1, an error is raised.
Example 1
In [10]:
M = np.ones((2,3))
a = np.arange(3)
M.shape = (2, 3)By Rule 1, a is padded on the left w/ ones:
M.shape → (2, 3)a.shape → (1, 3)By Rule 2, the first dimension now disagrees, so its stretched to match:
M.shape → (2, 3)a.shape → (2, 3)The shapes now match, and the final shape will be (2, 3).
In [12]:
M + a
Out[12]:
Example 2
In [13]:
a = np.arange(3).reshape((3, 1))
b = np.arange(3)
In [20]:
print('a.shape',a.shape); print('b.shape',b.shape)
Rule 1: pad b with ones:
a.shape -> (3,1)b.shape -> (1,3)Rule 2: upgrade each of these ones to match the corresp. size of the other array:
a.shape -> (3,3)b.shape -> (3,3)The result matches so the shapes are compatible.
In [21]:
a + b
Out[21]:
Example 3
In [22]:
M = np.ones((3,2))
a = np.arange(3)
Matrix M is transposed from above.
M.shape = (3,2)a.shape = (3,)Rule 1: pad the shape of a w/ ones:
M.shape = (3,2)a.shape = (1,3)Rule 2: first dim of a stretched to match that of M:
M.shape = (3,2)a.shape = (3,3)Rule 3 is triggered: the final shapes don't match so these arrays are incompatible:
In [23]:
M + a
You could manually 1-pad a from the right:
In [24]:
a[:, np.newaxis].shape
Out[24]:
In [25]:
M + a[:, np.newaxis]
Out[25]:
These rules apply to any binary ufunc (universal function):
In [26]:
np.logaddexp(M, a[:, np.newaxis])
Out[26]:
logaddexp(a,b) computes log(exp(a) + exp(b)) w/ more precision than the naïve approach.
Centering an array
In [32]:
# 10 observations, ea. w/ 3 vals
X = np.random.random((10, 3))
Calculate the mean of ea. feature using the mean aggregate across the first dimension:
In [33]:
Xmean = X.mean(0)
Xmean
Out[33]:
In [35]:
# center X by subtracting mean (broadcasting op)
X_centered = X - Xmean
In [36]:
# check centered array has ≈ 0 mean
X_centered.mean(0)
Out[36]:
Mean is now zero, to within machine precision.
Plotting a two-dimensional function
In [43]:
# x and y have 50 steps from 0 to 5
x = np.linspace(0, 5, 50)
y = np.linspace(0, 5, 50)[:, np.newaxis]
z = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
In [44]:
%matplotlib inline
import matplotlib.pyplot as plt
In [45]:
plt.imshow(z, origin='lower', extent=[0,5,0,5],cmap='viridis')
plt.colorbar();
A visualization of the two-dimensional function.
In [ ]: