Warm up

What will the following code spit out? (Don't just type it -- pencil and paper it).


In [ ]:
x = []
for i in range(1,11):
    if i > 2:
        x.append(i**2)
print(x[3])

How would you fix the following code so it does what you expect it to do?


In [ ]:
some_list = [1,2,3]
a_list_copy = some_list
some_list[1] = 273

Numpy Arrays

Python lists are powerful

  • Can store any python object
  • Can be expanded or contracted at will (append, insert,extend, remove, pop)

But would you want to cook with a swiss army knife?

Numpy arrays are the speciality knives of python programming

numpy arrays are:

  • Less flexible than lists:
    • Each array can only store one type of value
    • Arrays cannot be resized after they're made
  • But numpy arrays are fast and set up to do math
  • If you've ever done matlab programming, numpy arrays use the same syntax

Predict what the following code will print out (and be ready to explain each line)


In [5]:
import numpy as np
an_array = np.array([1,2,3,4,5,6,7,8,9,10],dtype=np.uint8)
print(an_array[3])


4

In [ ]:
import numpy as np # IMPORT numpy (calling it "np" for convenience)
an_array = np.array([1,2,3,4,5,6,7,8,9,10],dtype=int) # Create a numpy array of integers
print(an_array[3]) # print the fourth element

numpy arrays are an extension of python, not built in.

A quick return to lists:

Predict what this code will do.


In [6]:
some_list = [1,2,3]
print(some_list)
print(some_list + 5)


[1, 2, 3]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-b0f1de6054aa> in <module>()
      1 some_list = [1,2,3]
      2 print(some_list)
----> 3 print(some_list + 5)

TypeError: can only concatenate list (not "int") to list

Write a program to add 5 to every entry in the list [1,2,3]


In [7]:
some_list = [1,2,3]

for i in range(len(some_list)):
    some_list[i] = some_list[i] + 5

Predict what this code will do


In [8]:
import numpy as np  
some_array = np.array([1,2,3])
some_array = some_array + 5
print(some_array)


[6 7 8]

You can do math on numpy arrays in an "element-wise" fashion.

numpy arrays are fast


In [9]:
import numpy as np

a_list = list(range(100000))
an_array = np.array(range(100000),dtype=int)

In [10]:
%timeit for i in range(100000):  a_list[i] + 5
%timeit an_array + 5


7.13 ms ± 196 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
43.7 µs ± 731 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Can you explain what just happened?

  • for i in range(blah blah) is in pure python. This is convenient, but slow.
  • an_array + 5 actually runs the loop, but in compiled C. This is super fast.

moral: don't use loops when working with numpy arrays.

Predict what the following code will do


In [1]:
import numpy as np
x = np.array([1,2,3])
y = np.array([4,5,6])


print(x + y)


[5 7 9]

In [2]:
print(np.sin(y))


[-0.7568025  -0.95892427 -0.2794155 ]

Summarize

How does math work with numpy arrays?

You can do any math you want on all elements of the array at once.

Predict what the following code will do


In [3]:
an_array = np.array([[1,2],[3,4]],dtype=int)
print(an_array)


[[1 2]
 [3 4]]

In [4]:
an_array = np.zeros((2,2),dtype=float)
print(an_array)
an_array[0,0] = 1
an_array[0,1] = 2
an_array[1,0] = 3
an_array[1,1] = 4
print(an_array)


[[0. 0.]
 [0. 0.]]
[[1. 2.]
 [3. 4.]]

Summarize

How can you construct arrays?

  • you can cast them via np.array(ARRAY_LIKE_THING).
  • you can construct arrays from templates (like np.zeros, np.ones, np.eye)

Predict what the following code will do


In [12]:
an_array = np.array([[1,2,3],[4,5,6],[7,8,9]],dtype=int)
print(an_array[-1])
print("")
print(an_array[0,0])
print("")
print(an_array[:,0].reshape(3,1))
print("")
print(an_array[:,:])
an_array.shape[1]


[7 8 9]

1

[[1]
 [4]
 [7]]

[[1 2 3]
 [4 5 6]
 [7 8 9]]
Out[12]:
3

Summarize

How do you access elements inside multidimensional arrays?

Like lists, but with commas between dimensions:

  • some_array[i,j] would access the $(i-1)^{th},(j-1)^{th}$ element.
  • some_array[:,:] would spit out the whole first two dimensions.
  • some_array[i,j,k,l,m,n] would also work for a 6th dimensional array.

Numpy arrays are real vectors and matrices

One major motivation for the authors who created numpy was to speed-up mathematical operations on vector, matrix, and tensor-like data structures.

Numpy vector math operations


In [14]:
# Define two vector-like arrays
x = np.array([3,5])
y = np.array([4,6])

print("Element wise sum:" ,          x + y )         # Addition
print("Element wise difference:",    x - y )         # Substraction
print("Element wise product:",       x * y)          # Product
print("Element wise division:",      x / y)          # division
print("Dot product:",                x @ y)   # Dot product


Element wise sum: [ 7 11]
Element wise difference: [-1 -1]
Element wise product: [12 30]
Element wise division: [0.75       0.83333333]
Dot product: 42

Numpy matrix math operations


In [15]:
# Define a matrix
M = np.array([
    [5, 3],
    [2, 7]
])

print("Matrix transpose:\n",          M.T)                # Transpose
print("Vector-matrix dot product",    np.dot(M, x))       # Dot product
print("Matrix determinant:",          np.linalg.det(M))   # Determinant
print("Matrix inverse:\n",            np.linalg.inv(M))   # inverse


Matrix transpose:
 [[5 2]
 [3 7]]
Vector-matrix dot product [30 41]
Matrix determinant: 28.99999999999999
Matrix inverse:
 [[ 0.24137931 -0.10344828]
 [-0.06896552  0.17241379]]

Solve a system of equations

Solve a system of equations using numpy.linalg.solve function.

Example: $$ 3 x + 2y - z = 1 \\ 2 x - 5y + 4z = -2 \\ -x + \frac{1}{2} y - z = 0 $$

Written in matrix form: $$ A \vec{x} = \vec{b} $$

$$ \left[ \begin{array}{ccc} 3 & 2 & -1 \\ 2 & -5 & 4 \\ -1 & \frac{1}{2} & -1 \\ \end{array} \right] % \left[ \begin{array}{c} x \\ y \\ z \end{array} \right] = \left[ \begin{array}{c} 1 \\ -2 \\ 0 \end{array} \right] $$

</small>


In [16]:
A = np.array([
    [ 3,   2, -1],
    [ 2,  -2,  4],
    [-1, 0.5, -1]
])
b = np.array([1, -2, 0])

print("x :",  np.linalg.solve(A, b))


x : [ 1. -2. -2.]

Numpy to eigensystems

Easily diagonalize a matrix using numpy.linalg.eig function.

Example: $$ M \vec{v} = \lambda \vec{v} $$ </small>


In [17]:
M = np.array([
    [5, 3],
    [2, 7]
])

λs, eigvec = np.linalg.eig(M)

print("λ 1:",                λs[0])
print("Eigen vector 1:",     eigvec[0])
print("\n")
print("λ 2:",                λs[1])
print("Eigen vector 2:",     eigvec[1])


λ 1: 3.3542486889354093
Eigen vector 1: [-0.8767397 -0.6354064]


λ 2: 8.64575131106459
Eigen vector 2: [ 0.48096517 -0.7721779 ]

Summary

  1. To get a numpy array, put import numpy as np at the top of your code
  2. Arrays are fast, but less flexible than list
  3. You can do element-wise math on each array
  4. You create N-dimensional arrays and slice by some_array[i,j,k]
  5. Arrays are vectors and matrices that allow linear algebra

In [ ]: