Professional Documents
Culture Documents
1. ARRAY CREATION
A. Creating an array from a list or tuple
B. Creating arrays initialized with zeros or ones
C. Generating number sequences
D. Random number generator
E. Seeding the random generator
F. Exercise 1
2. SECTION 2: NUMERICAL OPERATIONS
A. Exercise 2
3. SECTION 3: INDEXING, SLICING AND ITERATING
A. Simple Indexing and Slicing
B. Indexing with Integer Arrays
C. Indexing with Boolean Arrays
D. Exercise 3
4. SECTION 4: MATRIX COMPUTATION
A. Exercise 4
5. SECTION 5: COPIES vs VIEWS
A. Reference copy
B. View copy
C. Copy
6. SECTION 6: MANIPULATING ARRAYS
A. Exercise 5
7. SECTION 7: ARRAY BROADCASTING
A. Exercise 6
Reference:
The numpy reference and user guide are available in this link
This tutorial is adapted from SciPy Quickstart Tutorial. If you need more exercises, you can work on
100 numpy exercises
INTRODUCTION
What is numpy?
NumPy is the fundamental package required for high performance scientific computing and data
analysis. It issued by practically all other scientific tools, such as Panda and Scikit. The following code
shows how to import the numpy library.
In [1]: import numpy as np # import numpy library
Why numpy?
Numpy is much faster for scientific computation compared to conventional Python methods.
Provides standard mathematical functions for fast operations on entire arrays of data without
having to write loops (easier to write)
Provides tools for reading / writing array data to disk
Linear algebra, random number generation capabilities
In [3]:
list1 = [2,4,6,8]
a = np.array(list1)
In [4]:
print('Shape of a =', a.shape) # number items in each dimension
Shape of a = (4,)
Number of dimensions of a = 1
In [5]:
print('Type of a =', type(a)) # a is a list
[ 6, 7, 8, 9, 10],
In [7]:
print('Shape of a =', a.shape) # number of items in each dimension
Shape of a = (3, 5)
Number of dimensions of a = 2
In [8]:
a = np.array([(1.5, 2, 3), (4, 5, 6)])
print(a)
print(a.dtype)
[[1.5 2. 3. ]
[4. 5. 6. ]]
float64
The type of the array can also be explicitly specified at creation time:
In [9]:
a = np.array( [ [1,1], [0,1] ], dtype=bool)
[False, True]])
In [10]:
all_zeros = np.zeros((3, 5))
all_zeros
In [11]:
all_ones = np.ones(3)
all_ones
np.arange returns evenly spaced values within a given interval. Values are generated within the
half-open interval [start, stop] . This means the interval includes start but excluding stop .
For integer arguments, the function is equivalent to the Python built-in range function, but returns
an ndarray (numpy array type)rather than a list .
In [12]:
a = np.arange( 10, 30, 5 ) # the parameters are start, end, step. Note
print(a)
[10 15 20 25]
In [13]:
b = np.arange( 0, 2, 0.3 ) # it accepts float arguments as well
print(b)
np.arange also accepts one parameter ( end ). By default, start = 0 and step = 1
In [14]:
c = np.arange(10) # starts = 0 and step = 1
Returns a particular number of numbers that are evenly spaced over a specified interval.
In [15]:
from numpy import pi
In [16]:
x = np.linspace( 0, 2*pi, 10) # useful to evaluate function at lots of points
print('x = ', x)
f = np.sin(x)
print('f = ', f)
-6.42787610e-01 -2.44929360e-16]
Creates an array of the given shape and populate it with random samples from a uniform
distribution over [0, 1] (i.e., inclusive of 0 but exclusive of 1)
In [17]:
np.random.rand() # generate a random scalar number uniform in [0,1)
Out[17]: 0.013906036200248773
In [18]:
np.random.rand(4) # generates an array of size 4
In [19]:
np.random.rand(3,2) # generates a matrix of size 3x2
[0.62905978, 0.48270902],
[0.80594488, 0.56769997]])
np.random.randint(low, high=None, size=None) :
Returns an array of size size . The array is populated with random integers from the discrete
uniform distribution in the interval [low, high] (excluding high ). If high is None (the
default), then results are from [0, low] .
In [20]:
np.random.randint(0, 20+1) # generate a random integer scalar between 0 and 20
Out[20]: 0
In [21]:
np.random.randint(0, 21, (3,2))# generates a matrix of size (3,2)
[11, 14],
[11, 11]])
np.random.randn :
In [22]:
np.random.randn() # univariate 'normal' (Gaussian distribution, with a mean = 0, vari
Out[22]: 1.4924468880710682
The following code show how to create a 2x2 matrix whose numbers are sampled from a normal
distribution
In [23]:
np.random.randn(2, 2)
By default, random number generators uses the system time for random seeding. This allows you to
generate different numbers each time you run your simultation.
But, sometimes you may want repeatable result. To produce repeatable results, seed your generator
using a constant number. Try running the following two cells. Notice that when we apply the same
seed, the random number generator will generate the same number sequences.
In [24]:
np.random.seed(4)
print(np.random.rand(4))
print(np.random.rand(4))
In [25]:
np.random.seed(4)
print(np.random.rand(4))
print(np.random.rand(4))
Exercise 1
Q1. Create a vector containing the first 10 odd integers using np.arange .
Answer:
In [26]:
np.arange(1, 20, 2)
Q2. Create a uniform subdivision of the interval -1.3 to 2.5 with 64 subdivisions using
np.linspace .
Answer:
In [27]:
np.linspace(-1.3, 2.5, 64)
array([[ 7, 9, 8, 4, 2],
[ 6, 10, 4, 3, 0],
[ 7, 5, 5, 9, 6],
[ 6, 8, 2, 5, 8]])
In [28]:
np.random.randint(0, 11,(4,5))
[ 6, 10, 4, 3, 0],
[ 7, 5, 5, 9, 6],
[ 6, 8, 2, 5, 8]])
Q4. Create a matrix of numbers randomly distributed between 0 and 1, having a size of (3,4). Use
np.random.rand .
In [29]:
np.random.rand(3,4)
array([[-0.08722439, 0.2021376 ],
[-0.68195243, 0.3402292 ],
[ 0.92526745, -1.51547866],
...,
[-0.81260973, 0.45430727],
[-0.11204656, 0.72001995],
[-0.88341863, -0.43912629]])
In [30]:
a = np.random.randn(1200, 2)
In [31]:
a = np.array ([ 2, 4, 6, 8])
b = np.array ([ 1, 2, 3, 1])
In [32]:
c = a - b # element-wise subtraction, a and b will remains unchanged
print(a)
print(b)
print(c)
[2 4 6 8]
[1 2 3 1]
[1 2 3 7]
In [33]:
a + b # element-wise addition
In [34]:
a + 2 # element-wise addition with constant
In [35]:
a / b # element-wise division
In [36]:
a / 2 # element-wise division with constant
In [37]:
a * b # element-wise multiplication
In [38]:
a ** b # Element-wise power
In [39]:
a += b # this will change the content of a
In [40]:
a *= b # this will change the content of a
Unlike in many matrix languages, the product operator * performs elementwise multiplication,
NOT matrix multiplication
In [41]:
A = np.array( [[1,1], [0,1]] )
A*B
[0, 4]])
b = np.array([2, 4, 7, 5])
In [43]:
a1 < 35 # element-wise comparison
In [44]:
a1 == 42
In [45]:
a1 == a2
Out[46]: True
In [47]:
np.array_equal(a1, b)
Out[47]: False
In [48]:
bool1 = np.array([True, True, False, False])
In [49]:
np.all(bool1) # Checks if every value is True
Out[49]: False
In [50]:
np.all(all_true)
Out[50]: True
In [51]:
np.any(bool1) # Checks if any value is True
Out[51]: True
In [52]:
np.any(all_false)
Out[52]: False
In [53]:
bool1 & bool2 # Element-wise AND operation
In [54]:
bool1 | bool2 # Element-wise OR operation
Comparing arrays
In [55]:
a = np.array([1, 2, 3, 4])
b = np.array([4, 2, 2, 4])
In [56]:
a == b
In [57]:
np.maximum (a, b) # Get the element-wise maximum of all corresponding items in a and
In [58]:
np.minimum (a, b) # Get the element-wise minimum of all corresponding items in a and
In [60]:
np.sin(a)
In [61]:
np.exp(a)
1.48413159e+02])
In [62]:
np.abs(a)
In [63]:
np.max(a) # get the item with the biggest value
Out[63]: 9
In [64]:
np.min(a) # get the item with the smallest value
Out[64]: -6
ndarray functions
All ndarrays come with a set of functions that can be invoked to operate on its data.
In [65]:
a = np.random.randint(0, 20, 10)
print('argmin: ', a.argmin()) # find the index of the item with the smalles
print('max: ', a.max()) # get the maximum value
print('argmax: ', a.argmax()) # find the index of the item with the biggest
sum: 70
mean: 7.0
std: 4.732863826479693
min: 1
argmin: 8
max: 17
argmax: 7
In [67]:
a = np.random.randint (0, 20, (3, 2))
[ 5, 7],
[19, 19]])
In [68]:
print('sum: ', a.sum()) # compute the sum
print('argmin: ', a.argmin()) # find the index of the item with the smalles
print('max: ', a.max()) # get the maximum value
print('argmax: ', a.argmax()) # find the index of the item with the biggest
sum: 58
mean: 9.666666666666666
std: 6.896053621859068
min: 1
argmin: 1
max: 19
argmax: 4
By default, these operations apply to the 2-D array as though it were a list of numbers, regardless of
its shape.
However, by specifying the axis parameter you can apply an operation along the specified axis of an
array:
In [69]:
a.sum(axis=0) # axis = 0 refers to the column dimension (sum all items in eac
In [70]:
a.sum(axis=1) # axis = 1 refers to the row dimension (sum all items in each row
Sample solution:
summation = 15.2933401657
mean = 0.509778005522
std = 0.273489774136
In [71]:
Z = np.random.rand(30)
print(Z)
summation = 15.293340165651928
mean = 0.5097780055217309
std = 0.2734897741357628
Q2. Create a 3x3 array with random integer values [0, 10) . Then, find the following:
Sample solution:
[[0 6 6]
[3 7 4]
[3 6 5]]
In [72]:
Z = np.random.randint(0, 10, (3,3))
print(Z, '\n')
[[0 6 6]
[3 7 4]
[3 6 5]]
Q3. Generate the array containing the value of f (x) = sin(x) for −2π ≤ x ≤ 2π . Compute
f (x)
for 100 evenly spaced points in x.
plt.plot(x, y)
plt.show()
In [73]:
angles = np.linspace(-2*np.pi, 2*np.pi, 100)
sinvalues = np.sin(angles)
plt.plot(angles, sinvalues)
plt.show()
2
x
Q4. Generate the array containing the value of f (x) for −5 . The array should
1 −
= e 2
≤ x ≤ 5
√2π
contain f (x) for 100 evenly spaced points in x. Then, plot out the computed values. Refer to Q3 on
how to plot the graph.
In [74]:
x = np.linspace(-5, 5, 100)
fx = np.exp(-x**2/2)/np.sqrt(2*np.pi)
plt.plot(x, fx)
plt.show()
Q5. Given the vector a = np.array([12, 14, 20, 26, 39, 49]) , find the closest value to
query = 27 . The algorithm to achieve this is as follows:
compute the absolute difference between all items with the query item (Useful command:
np.abs )
get the item with the smallest absolute distance (Useful command: np.argmin )
Ans:
In [75]:
a = np.array([12, 14, 20, 26, 39, 49])
query = 27
index = (np.abs(a-query)).argmin()
Q6. Randomly generate a vector a of size 10 with values betwen 100 and 200. Compute the L2
norm of a Then normalize the vector a to get an by dividing each item with the L2 norm.
In [76]:
import numpy as np
a = np.array([4, 3])
print('a: ', a)
L2ofA = np.sqrt(np.sum(a**2))
a: [4 3]
Norm 2 = 5.0
In [77]:
a = np.random.randint(100, 201, 10)
print('a: ', a)
L2ofA = np.sqrt(np.sum(a**2))
a: [178 181 132 136 166 180 136 128 197 186]
Norm 2 = 518.2721292911668
In [78]:
d1 = np.array([5, 0, 3, 0, 2, 0, 0, 2, 0, 0])
d2 = np.array([3, 0, 2, 0, 1, 1, 0, 1, 0, 1])
A = np.sum(d1*d2)
B = np.sqrt(np.sum(d1*d1))
C = np.sqrt(np.sum(d2*d2))
cos = A/(B*C)
print(cos)
0.9356014857063997
In [79]:
a = np.random.randint(0, 100, 10)
print(a)
[65 60 37 21 18 96 26 24 39 83]
In [80]:
a[2] # get item 2
Out[80]: 37
In [81]:
a[2:5] # start = 2, end = 5 (not inclusive). This gets item 2 up to item 4
In [82]:
a[:3] # equivalent to a[0:3]
In [83]:
a[7:] # gets item at position 7 to the last position
In [84]:
a[2] = -1 # overwritting the third item
Out[84]: array([65, 60, -1, 21, 18, 96, 26, 24, 39, 83])
In [85]:
a[::2] = -1000 # equivalent to a[0:10:2] = -1000
Out[85]: array([-1000, 60, -1000, 21, -1000, 96, -1000, 24, -1000,
83])
Negative indexing
Numpy array also supports negative indexing where we index from the end of the list.
In [86]:
a = np.random.randint(0, 100, 10)
print(a)
[24 19 66 85 65 23 56 14 10 5]
In [87]:
a[-1]
Out[87]: 5
In [88]:
a[-3:] # get the last three items
Multidimensional indexing
The following codes show how to index a 2-D array.
In [89]:
a = np.random.randint(0, 100, (3, 5))
In [90]:
a[2, 3] # item at row 2, column 3 (third row, fourth column)
Out[90]: 25
In [91]:
a[:, 1] # get the column 1 of a
In [92]:
a[:2, 1] # first two items in column 1 of a
In [93]:
a[:, 1:3] # get column 1 and 2 (not inclusive of 3)
[98, 27],
[87, 49]])
When fewer indices are provided than the number of axes, the missing indices are considered
complete slices:
In [94]:
a[2] # get row 2
In [95]:
a[1:] # get row 1 to the last row
In [96]:
a = np.array([10, 11, 13, 0, 10, 10, 16, 12, 18, 9])
selected = [2, 3, 5] #select third, fourth and sixth item from array
b = a[selected]
In [97]:
a = np.array([[2, 5, 1, 1, 2],
[5, 7, 2, 7, 35],
selected_row = (2, 1)
selected_col = (3, 4)
In [98]:
a = np.array([23, -56, 2, 3, -57])
a
In [99]:
selected = [True, False, True, False, False]
a[selected]
In [100…
all_pos = a > 0
In [101…
isEven = a % 2 == 0
In [102…
a = np.array([[2, 5, 1, 1, 2],
[5, 7, 2, 7, 35],
In [103…
sel_rows = [False, True, True]
[ 1, 9, 8, 49, 9]])
In [104… sel_cols = [True, True, False, False, False]
[5, 7],
[1, 9]])
Exercise 3
Q1. Create a vector of zeros (integers) of size 10. Use slicing to set the first two items with 2, the
next 3 items with 4 and the remaining items with 6.
In [105…
a = np.zeros(10, dtype = 'int')
a[:2] = 2
a[2:5] = 4
a[5:] = 6
Q2. Generate a random matrix of size 6x6. Then write the codes to extract the following items from
the matrix.
In [106…
a = np.random.randint(1,100, (6,6))
print(a, '\n')
print(a[2], '\n')
print(a[:,2], '\n')
print(a[0,3:5], '\n')
print(a[2:5], '\n')
print(a[4:,4:])
[[87 2 90 53 59 14]
[92 98 88 66 53 73]
[56 63 49 24 95 60]
[32 95 35 55 69 24]
[ 9 35 63 30 79 89]
[98 90 37 94 75 49]]
Matrix (a):
[56 63 49 24 95 60]
Matrix (b):
[90 88 49 35 63 37]
Matrix (c):
[53 59]
Matrix (d):
[[56 63 49 24 95 60]
[32 95 35 55 69 24]
[ 9 35 63 30 79 89]]
Matrix (e):
[[90 59]
[88 53]
[49 95]
[35 69]
[63 79]
[37 75]]
Matrix (f):
[[79 89]
[75 49]]
Q3. Randomly generate an array comprising all numbers of size 20 with numbers between 0 and
100. Then, extract the array of numbers that are both even and divisible by 3.
In [107…
a = np.random.randint(0,101,20)
print(a)
print(a[selected])
[89 45 55 72 31 49 60 98 91 28 97 68 72 88 95 62 41 38 1 95]
[72 60 72]
In [108…
A = np.array([[1, 0], [2, 5], [3, 1]], dtype = 'int')
print(A)
print(B)
[[1 0]
[2 5]
[3 1]]
[[4 0]
[2 5]
[0 1]]
In [109…
A + B # A plus B
[ 4, 10],
[ 3, 2]])
In [110…
A - B # A subtract B
[ 0, 0],
[ 3, 0]])
Matrix multiplication
np.dot :
In numpy, matrix multiplication is performed through np.dot . The operator * only performs
element-wise multiplication.
In [111…
m1 = np.array([[1, 2],[1, 4]])
print (m1)
print (m2)
v1 = np.array([2, 3])
print(v1)
v2 = np.array([1, 5])
print(v2)
[[1 2]
[1 4]]
[[0 1]
[1 2]]
[2 3]
[1 5]
In [112…
np.dot(m1, m2) # matrix matrix multiplication
[4, 9]])
In [113…
m1.dot(m2) # matrix matrix multiplication
[4, 9]])
In [114…
np.dot(m1, v1) # matrix vector multiplication
In [115…
np.dot(v1, v2) # vector-vector multiplication (or dot product)
Out[115… 17
Transpose a matrix
Transpose of a matrix is obtained by changing rows to columns and columns to rows. In other
words, transpose of A[][] is obtained by changing A[i][j] to A[j][i].
In [116…
A.T
[0, 5, 1]])
Invert a matrix
In [117…
b = np.random.randint(0, 10, (3, 3))
print(b)
[[8 0 4]
[5 9 8]
[5 6 2]]
In [118…
np.linalg.inv(b)
Exercise 4
Q1. First, set the seed for your random generator to 42. Then, randomly sample from the standard
normal distribution: (a) predicted output vector h and (b) actual output vector y , both having a
size of (m,) where m = 50 (Use np.random.randn ).
1 m
(i) (i) 2
RM SE = √ ∑ (h − y )
m i=1
1
T
= √ (h − y) (h − y)
m
m = 50
h = np.random.randn(m)
y = np.random.randn(m)
e = h - y
rmse
Out[119… 1.2192273122578396
Q2. Create the matrix X = np.array([[1, 1],[2, 1],[3, 1]]) and y = np.array([1, 3,
7]) . Then, compute the normal equation.
T −1 T
h = (X X) X y
In [120…
X = np.array([[1, 1],[2, 1],[3, 1]])
y = np.array([1, 3, 7])
This may be quite confusing for beginners. But, it is important to understand this concepts.
Reference copy
Returns the reference to the same data. This is done through the operator = .
In [121…
a = np.arange(12)
print("a = ", a)
a = [ 0 1 2 3 4 5 6 7 8 9 10 11]
In [122… b = a
print("b = ", b)
b is a # for simple assignment, a and b are two names for the same nd
b = [ 0 1 2 3 4 5 6 7 8 9 10 11]
Out[122… True
In [123…
a[0] = -99 # change the content of a affects b as well
print(a)
print(b)
[-99 1 2 3 4 5 6 7 8 9 10 11]
[-99 1 2 3 4 5 6 7 8 9 10 11]
In [124…
b.shape = 3,4 # change the shape of b
print("b = ")
print(b)
b =
[[-99 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
a =
[[-99 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
View copy
Different array objects can share the same data but present it differently as follows:
The following code creates three different view of the same data a .
First, we create our array a .
In [125…
a = np.array([[1, 2, 3],[4, 5, 6]])
[4, 5, 6]])
When we flatten an array using .ravel() , it returns a view of the original data.
In [126…
b = a.ravel()
When we reshape an array using .reshape() , it returns a view of the original data.
In [127…
c = a.reshape(3, 2)
[3, 4],
[5, 6]])
When we slice an array, we return a view of it:
In [128…
d = a[ : , 1:3] # spaces added for clarity; could also be written "s = a[:,1:3]"
[5, 6]])
Changing the content in b or c or d will change a as well. The changes will be reflected in all
views as well.
In [129… b[-1] = -9999
print('a:\n', a)
print('\nb:\n', b)
print('\nc:\n', c)
print('\nd:\n', d)
a:
[[ 1 2 3]
[ 4 5 -9999]]
b:
[ 1 2 3 4 5 -9999]
c:
[[ 1 2]
[ 3 4]
[ 5 -9999]]
d:
[[ 2 3]
[ 5 -9999]]
Copy
The copy method makes a complete copy of the array and its data.
In [130…
a = np.arange(15).reshape(3, 5)
In [131…
d is a # d is not the same as a
Out[131… False
In [132…
d[0,0] = 9999 # Changing the content of d does not affect a
print("a = ")
print(a)
print("d = ")
print(d)
a =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
d =
[[9999 1 2 3 4]
[ 5 6 7 8 9]
[ 10 11 12 13 14]]
In [133…
a = np.array([[1,2,3], [4,5,6]])
[4, 5, 6]])
In [134…
b = np.array([[23,23,34], [43,54,63]])
In [135…
c = np.hstack((a,b))
Stacks two arrays vertically. The two arrays must have the same number of columns.
In [136…
d = np.vstack((a,b))
[ 4, 5, 6],
newaxis
We can use newaxis to convert an array (vector) of size n into a 2-D array (matrix) of size nx1 .
In [137…
a = np.array([4, 2])
print(a)
print(a.shape)
[4 2]
(2,)
In [138…
b = a[:, np.newaxis]
print(b)
[[4]
[2]]
shape = (2, 1)
Exercise 5
Q1. Create the following matrix:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [139…
np.arange(9).reshape(3,3)
[3, 4, 5],
[6, 7, 8]])
Q2. Create the matrix a as follows: generate a 10x10 matrix of zeros. Then, frame it with a border
of ones.
In [140…
a = np.zeros((10,10))
a = np.hstack((a, np.ones((10,1))))
a = np.hstack((np.ones((10,1)), a))
a = np.vstack((a, np.ones((1,12))))
a = np.vstack((np.ones((1,12)), a))
print(a)
[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]
Q3. Create a 8x8 matrix and the fill it with a checkerboard pattern.
In [141…
A = np.zeros((8,8))
A[1::2,::2] = 1
A[::2,1::2] = 1
print(A)
[[0. 1. 0. 1. 0. 1. 0. 1.]
[1. 0. 1. 0. 1. 0. 1. 0.]
[0. 1. 0. 1. 0. 1. 0. 1.]
[1. 0. 1. 0. 1. 0. 1. 0.]
[0. 1. 0. 1. 0. 1. 0. 1.]
[1. 0. 1. 0. 1. 0. 1. 0.]
[0. 1. 0. 1. 0. 1. 0. 1.]
[1. 0. 1. 0. 1. 0. 1. 0.]]
When the input arrays have different shape, it may perform broadcasting before carrying out the
operation. Subject to certain constraints, the smaller array is "broadcast" across the larger array so
that they have compatible shapes.
In [142…
a = np.array([1, 2, 3])
b = 2
a * b
Note that numpy does not actually stretches b to create a new array but is smart enough to use
the original scalar value without actually making copies so that broadcasting operations are as
memory and computationally efficient as possible.
In [143…
a = np.array([[ 0, 0, 0],
b = np.array([0, 1, 2])
a + b
If you want to broadcast the column-wise addition of a matrix of shape (4,3) with a vector (4,),
ensure that you convert the vector into a 2-D array of shape (4, 1) to align the dimensions. Numpy
will then broadcast the operation across all columns.
In [144…
a = np.array([[ 0, 0, 0],
print(a)
print()
print(b)
a + b
[[ 0 0 0]
[10 10 10]
[20 20 20]
[30 30 30]]
[[ 0]
[10]
[20]
[30]]
Exercise 6
Q1. Randomly generate a matrix of size (5, 3). Normalize the columns such that the sum of each
column is equal to 1. Use broadcasting in your code to simplify your task.
In [145…
X = np.random.randn(5, 3)
print(Xn)
[1. 1. 1.]