import numpy as np
import time
For this exercise you will be provided with a problem and and asked to construct two solutions. The first solution should be without numpy and the second with numpy. The vectorized forms with numpy should perform magnitudes more quickly.
arg_length = 10000000
arg_vector = np.arange(arg_length) # An example vector argument.
print(f"Vector argument: {arg_vector}")
num_rows, num_cols = 200, 100
arg_matrix = np.array([[i + j for j in range(num_cols)] for i in range(num_rows)]) # An example matrix argument.
print(f"Matrix argument: {arg_matrix}")
Vector argument: [ 0 1 2 ... 9999997 9999998 9999999] Matrix argument: [[ 0 1 2 ... 97 98 99] [ 1 2 3 ... 98 99 100] [ 2 3 4 ... 99 100 101] ... [197 198 199 ... 294 295 296] [198 199 200 ... 295 296 297] [199 200 201 ... 296 297 298]]
Problem 1: Construct a function which takes a vector, and returns an vector with each element doubled.
def doubler(x):
"""Take an array and return an array with each element doubled. This version does not use numpy.
:param x: An array of numbers.
:return: An array of doubled numbers.
"""
new_x = [None] * len(x)
for i in range(len(x)):
new_x[i] = x[i] * 2
return new_x
start_time = time.time()
print(doubler(arg_vector)[:5])
print(f"Runtime: {time.time() - start_time}")
[0, 2, 4, 6, 8] Runtime: 2.5139989852905273
def doubler_numpy(x):
"""Take an array and return an array with each element doubled. This version uses numpy.
:param x: An array of numbers.
:return: An array of doubled numbers.
"""
return x * 2
start_time = time.time()
print(doubler_numpy(arg_vector)[:5])
print(f"Runtime: {time.time() - start_time}")
[0 2 4 6 8] Runtime: 0.02846217155456543
Problem 2: Construct a function which takes two vectors and returns the elementwise summation.
def adder(a, b):
"""Take two arrays and return an array with their elementwise addition. This version does not use numpy.
:param a: An array of numbers.
:param b: An array of numbers.
:return: An array of the elementwise addition of a and b.
"""
c = [None] * len(a)
for i in range(len(a)):
c[i] = a[i] + b[i]
return c
start_time = time.time()
print(adder(arg_vector, arg_vector)[:5])
print(f"Runtime: {time.time() - start_time}")
[0, 2, 4, 6, 8] Runtime: 2.389622926712036
def adder_numpy(a, b):
"""Take two arrays and return an array with their elementwise addition. This version uses numpy.
:param a: An array of numbers.
:param b: An array of numbers.
:return: An array of the elementwise addition of a and b.
"""
return np.add(a, b) #a + b
start_time = time.time()
print(adder_numpy(arg_vector, arg_vector)[:5])
print(f"Runtime: {time.time() - start_time}")
[0 2 4 6 8] Runtime: 0.03220081329345703
Problem 3: Construct a function which takes a matrix and returns the tranpose.
def transposer(A):
"""Take an mxn matrix (with m,n > 0) and return a nxm matrix with the transpose.
:param A: A mxn matrix.
:return: A nxm matrix.
"""
num_rows_input, num_cols_input = A.shape
# This is a list comprehension to construct the transpose
return [[A[i, j] for i in range(num_rows_input)]
for j in range(num_cols_input)]
start_time = time.time()
print(transposer(arg_matrix)[0][:5])
print(f"Runtime: {time.time() - start_time}")
[0, 1, 2, 3, 4] Runtime: 0.0033500194549560547
def transposer_numpy(A):
"""Take an mxn matrix (with m,n > 0) and return a nxm matrix with the transpose.
:param A: A mxn matrix.
:return: A nxm matrix.
"""
return A.T
start_time = time.time()
print(transposer_numpy(arg_matrix)[0][:5])
print(f"Runtime: {time.time() - start_time}")
[0 1 2 3 4] Runtime: 0.00023317337036132812
Problem 4: Construct a function which takes two matrices and returns their dot product.
def dot(A, B):
"""Take an mxn matrix and a nxk (with m,n, k > 0) and return a mxr matrix with the transpose.
:param A: A mxn matrix.
:param B: A nxp matrix.
:return: A mxp matrix.
"""
num_rows_output = A.shape[0]
num_cols_output = B.shape[1]
C = np.array([[0] * num_cols_output] * num_rows_output)
for i in range(num_rows_output):
for j in range(num_cols_output):
for k in range(A.shape[1]): # dot product between row of A and column of B.
C[i][j] += A[i, k] * B[k, j]
return C
start_time = time.time()
print(dot(arg_matrix, arg_matrix.T)[0][:5])
print(f"Runtime: {time.time() - start_time}")
[328350 333300 338250 343200 348150] Runtime: 2.051680088043213
def dot_numpy(A, B):
"""Take an mxn matrix and a nxk (with m,n, k > 0) and return a mxr matrix with the transpose.
:param A: A mxn matrix.
:param B: A nxr matrix.
:return: A nxr matrix.
"""
return np.dot(A, B)
start_time = time.time()
print(dot_numpy(arg_matrix, arg_matrix.T)[0][:5])
print(f"Runtime: {time.time() - start_time}")
[328350 333300 338250 343200 348150] Runtime: 0.0023589134216308594