2024-heraklion-data/notebooks/020_numpy/if_time_003_vectorization.ipynb
2024-08-27 15:27:53 +03:00

14 KiB

In [4]:
import numpy as np
import matplotlib.pyplot as plt

Avoid for-loops (element-after-element operations)

In [5]:
def compute_reciprocals(values):
    output = np.empty(len(values))
    for i in range(len(values)):
        output[i] = 1.0 / values[i]
    return output
In [6]:
%%timeit

np.random.seed(0)
        
values = np.random.randint(1, 10, size=5)
compute_reciprocals(values)
18.4 µs ± 155 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

Very slow! Each time the reciprocal is computed, Python first examines the object's type and does a dynamic lookup of the correct function to use for that type

Basic functions

In NumPy - convenient interface for just this kind of statically typed, compiled routine. --> vectorized operations

  • performing an operation on the array, which will then be applied to each element
  • pushes the loop into the compiled layer that underlies NumPy --> much faster execution

  • basic funcs quickly execute repeated operations on values in NumPy arrays --> extremely flexible

In [7]:
%%timeit
values = np.random.randint(1, 10, size=5)
#compute_reciprocals(values)
1.0 / values
8.81 µs ± 173 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
In [5]:
# simple vectorized functions 
x = np.arange(4)
print("x     =", x)
print("x + 5 =", x + 5)
print("x - 5 =", x - 5)
print("x * 2 =", x * 2)
x     = [0 1 2 3]
x + 5 = [5 6 7 8]
x - 5 = [-5 -4 -3 -2]
x * 2 = [0 2 4 6]
In [6]:
# exponents and logarithms
x = [1, 2, 3]
print("x     =", x)
print("e^x   =", np.exp(x))
print("2^x   =", np.exp2(x))
print("3^x   =", np.power(3, x))
x     = [1, 2, 3]
e^x   = [ 2.71828183  7.3890561  20.08553692]
2^x   = [2. 4. 8.]
3^x   = [ 3  9 27]

Mgrid

In [7]:
x = np.arange(1,10) # timepoints
y = np.arange(-70, 100, 10) # voltage change

# for loop solution
xx, yy = np.zeros((len(x), len(y))), np.zeros((len(y), len(x)))
for a, i in enumerate(x):
    xx[a] = np.repeat(i, len(y))

for b, j in enumerate(y):
    yy[b] = np.repeat(j, len(x))
yy = yy.T

# 1-line mgrid solution
# works like broadcasting
XX, YY = np.mgrid[1:10:1, -70:100:10] # two arrays with shape (9,17); (len(x), len(y))
In [8]:
fig = plt.figure()
ax = fig.add_subplot()
ax.scatter(xx, yy)
plt.show()

Hands on exercises

  • Open notebook exercises/numpy_vectorize.ipynb
In [ ]: