# import numpy package
import numpy as np
theta_list = [-1.0, 1.0, 4.0]
# Create a 1-D array (a vector) by passing in a Python list
theta_array = np.array(theta_list)
# To examine the dimensions of an array, use .shape
print('Shape of theta_array:', theta_array.shape)
Shape of theta_array: (3,)
# Indexing is the same for Python lists and numpy arrays
print('Second element of theta_list = ', theta_list[1])
print('Second element of theta_array = ', theta_array[1])
Second element of theta_list = 1.0 Second element of theta_array = 1.0
# Another 1-D array
x_array = np.array([1, 1, 1])
# Can also create 2-D arrays (and higher dimensions)
x2D_array = np.array([[1,2,3],
[4, 5, 6]])
print('Shape of x2D_array =', x2D_array.shape)
print('\t num. rows =', x2D_array.shape[0])
print('\t num. columns =', x2D_array.shape[1])
Shape of x2D_array = (2, 3) num. rows = 2 num. columns = 3
# Dot product between two arrays
dot_product = np.dot(x_array, theta_array)
print('Dot product (np.dot) =', dot_product)
Dot product (np.dot) = 4.0
# np.dot much more efficient than for-loops by hand
dot_product = 0
for i in range(x_array.shape[0]):
dot_product += theta_array[i]*x_array[i]
print('Dot product (by hand) =', dot_product)
Dot product (by hand) = 4.0
# Note: by definition, dot products must have the same shape
# If not, numpy gives an error
x2_array = np.array([1, 2, 3, 4])
np.dot(theta_array, x2_array)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[11], line 4 1 # Note: by definition, dot products must have the same shape 2 # If not, numpy gives an error 3 x2_array = np.array([1, 2, 3, 4]) ----> 4 np.dot(theta_array, x2_array) File <__array_function__ internals>:180, in dot(*args, **kwargs) ValueError: shapes (3,) and (4,) not aligned: 3 (dim 0) != 4 (dim 0)
# Array broadcasting is one of the most powerful and efficient aspects
# of numpy because it allows you to write intuitive code with arrays
x_array
array([1, 1, 1])
# Array broadcasting applies the float(scalar) element-wise
3*x_array
array([3, 3, 3])
4+x_array
array([5, 5, 5])
# Matrices
X = np.array([[1, 1, 1],
[2, 0, 1],
[1, 2, 3]])
X.shape
(3, 3)
X.dot(theta_array)
array([ 4., 2., 13.])
#it's applying via each row of X
X[0]
array([1, 1, 1])
X[0].dot(theta_array)
4.0
X[1].dot(theta_array)
2.0
X[2].dot(theta_array)
13.0
# Careful! Matrix multiplication is not transitive
theta_array.dot(X)
array([ 5., 7., 12.])