NumPy, SciPy and MatPlotLib
NumPy, SciPy and MatPlotLib
NumPy, SciPy and MatPlotLib
Python
Python is a high-level, dynamically typed multiparadigm programming language. Python code is often
said to be almost like pseudocode, since it allows you to express very powerful ideas in very few lines of
code while being very readable. As an example, here is an implementation of the classic quicksort
algorithm in Python:
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)
print(quicksort([3,6,8,10,1,2,1]))
# Prints "[1, 1, 2, 3, 6, 8, 10]"
Python versions
There are currently two different supported versions of Python, 2.7 and 3.5. Somewhat confusingly,
Python 3.0 introduced many backwards-incompatible changes to the language, so code written for 2.7
may not work under 3.5 and vice versa. For this class all code will use Python 3.5.
You can check your Python version at the command line by running python --version .
Basic data types
Like most languages, Python has a number of basic types including integers, floats, booleans, and
strings. These data types behave in ways that are familiar from other programming languages.
Numbers: Integers and floats work as you would expect from other languages:
x = 3
print(type(x)) # Prints "<class 'int'>"
print(x) # Prints "3"
print(x + 1) # Addition; prints "4"
print(x - 1) # Subtraction; prints "2"
print(x * 2) # Multiplication; prints "6"
print(x ** 2) # Exponentiation; prints "9"
x += 1
print(x) # Prints "4"
x *= 2
print(x) # Prints "8"
y = 2.5
print(type(y)) # Prints "<class 'float'>"
print(y, y + 1, y * 2, y ** 2) # Prints "2.5 3.5 5.0 6.25"
Note that unlike many languages, Python does not have unary increment ( x++ ) or decrement ( x-- )
operators.
Python also has built-in types for complex numbers; you can find all of the details in the documentation.
Booleans: Python implements all of the usual operators for Boolean logic, but uses English words rather
than symbols ( && , || , etc.):
t = True
f = False
print(type(t)) # Prints "<class 'bool'>"
print(t and f) # Logical AND; prints "False"
print(t or f) # Logical OR; prints "True"
print(not t) # Logical NOT; prints "False"
print(t != f) # Logical XOR; prints "True"
Strings: Python has great support for strings:
hello = 'hello' # String literals can use single quotes
world = "world" # or double quotes; it does not matter.
print(hello) # Prints "hello"
print(len(hello)) # String length; prints "5"
hw = hello + ' ' + world # String concatenation
print(hw) # prints "hello world"
hw12 = '%s %s %d' % (hello, world, 12) # sprintf style string formatting
print(hw12) # prints "hello world 12"
String objects have a bunch of useful methods; for example:
s = "hello"
print(s.capitalize()) # Capitalize a string; prints "Hello"
print(s.upper()) # Convert a string to uppercase; prints "HELLO"
print(s.rjust(7)) # Right-justify a string, padding with spaces;
prints " hello"
print(s.center(7)) # Center a string, padding with spaces; prints "
hello "
print(s.replace('l', '(ell)')) # Replace all instances of one substring
with another;
# prints "he(ell)(ell)o"
print(' world '.strip()) # Strip leading and trailing whitespace;
prints "world"
You can find a list of all string methods in the documentation.
Containers
Python includes several built-in container types: lists, dictionaries, sets, and tuples.
Lists
A list is the Python equivalent of an array, but is resizeable and can contain elements of different types:
xs = [3, 1, 2] # Create a list
print(xs, xs[2]) # Prints "[3, 1, 2] 2"
print(xs[-1]) # Negative indices count from the end of the list;
prints "2"
xs[2] = 'foo' # Lists can contain elements of different types
print(xs) # Prints "[3, 1, 'foo']"
xs.append('bar') # Add a new element to the end of the list
print(xs) # Prints "[3, 1, 'foo', 'bar']"
x = xs.pop() # Remove and return the last element of the list
print(x, xs) # Prints "bar [3, 1, 'foo']"
As usual, you can find all the gory details about lists in the documentation.
Slicing: In addition to accessing list elements one at a time, Python provides concise syntax to access
sublists; this is known as slicing:
nums = list(range(5)) # range is a built-in function that creates a
list of integers
print(nums) # Prints "[0, 1, 2, 3, 4]"
print(nums[2:4]) # Get a slice from index 2 to 4 (exclusive);
prints "[2, 3]"
print(nums[2:]) # Get a slice from index 2 to the end; prints
"[2, 3, 4]"
print(nums[:2]) # Get a slice from the start to index 2
(exclusive); prints "[0, 1]"
print(nums[:]) # Get a slice of the whole list; prints "[0, 1,
2, 3, 4]"
print(nums[:-1]) # Slice indices can be negative; prints "[0, 1,
2, 3]"
nums[2:4] = [8, 9] # Assign a new sublist to a slice
print(nums) # Prints "[0, 1, 8, 9, 4]"
We will see slicing again in the context of numpy arrays.
Loops: You can loop over the elements of a list like this:
animals = ['cat', 'dog', 'monkey']
for animal in animals:
print(animal)
# Prints "cat", "dog", "monkey", each on its own line.
If you want access to the index of each element within the body of a loop, use the built-
in enumerate function:
animals = ['cat', 'dog', 'monkey']
for idx, animal in enumerate(animals):
print('#%d: %s' % (idx + 1, animal))
# Prints "#1: cat", "#2: dog", "#3: monkey", each on its own line
List comprehensions: When programming, frequently we want to transform one type of data into
another. As a simple example, consider the following code that computes square numbers:
nums = [0, 1, 2, 3, 4]
squares = []
for x in nums:
squares.append(x ** 2)
print(squares) # Prints [0, 1, 4, 9, 16]
You can make this code simpler using a list comprehension:
nums = [0, 1, 2, 3, 4]
squares = [x ** 2 for x in nums]
print(squares) # Prints [0, 1, 4, 9, 16]
List comprehensions can also contain conditions:
nums = [0, 1, 2, 3, 4]
even_squares = [x ** 2 for x in nums if x % 2 == 0]
print(even_squares) # Prints "[0, 4, 16]"
Dictionaries
A dictionary stores (key, value) pairs, similar to a Map in Java or an object in Javascript. You can use it
like this:
d = {'cat': 'cute', 'dog': 'furry'} # Create a new dictionary with some
data
print(d['cat']) # Get an entry from a dictionary; prints "cute"
print('cat' in d) # Check if a dictionary has a given key; prints
"True"
d['fish'] = 'wet' # Set an entry in a dictionary
print(d['fish']) # Prints "wet"
# print(d['monkey']) # KeyError: 'monkey' not a key of d
print(d.get('monkey', 'N/A')) # Get an element with a default; prints
"N/A"
print(d.get('fish', 'N/A')) # Get an element with a default; prints
"wet"
del d['fish'] # Remove an element from a dictionary
print(d.get('fish', 'N/A')) # "fish" is no longer a key; prints "N/A"
You can find all you need to know about dictionaries in the documentation.
Loops: It is easy to iterate over the keys in a dictionary:
d = {'person': 2, 'cat': 4, 'spider': 8}
for animal in d:
legs = d[animal]
print('A %s has %d legs' % (animal, legs))
# Prints "A person has 2 legs", "A cat has 4 legs", "A spider has 8 legs"
If you want access to keys and their corresponding values, use the items method:
d = {'person': 2, 'cat': 4, 'spider': 8}
for animal, legs in d.items():
print('A %s has %d legs' % (animal, legs))
# Prints "A person has 2 legs", "A cat has 4 legs", "A spider has 8 legs"
Dictionary comprehensions: These are similar to list comprehensions, but allow you to easily construct
dictionaries. For example:
nums = [0, 1, 2, 3, 4]
even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0}
print(even_num_to_square) # Prints "{0: 0, 2: 4, 4: 16}"
Sets
A set is an unordered collection of distinct elements. As a simple example, consider the following:
animals = {'cat', 'dog'}
print('cat' in animals) # Check if an element is in a set; prints
"True"
print('fish' in animals) # prints "False"
animals.add('fish') # Add an element to a set
print('fish' in animals) # Prints "True"
print(len(animals)) # Number of elements in a set; prints "3"
animals.add('cat') # Adding an element that is already in the set
does nothing
print(len(animals)) # Prints "3"
animals.remove('cat') # Remove an element from a set
print(len(animals)) # Prints "2"
As usual, everything you want to know about sets can be found in the documentation.
Loops: Iterating over a set has the same syntax as iterating over a list; however since sets are unordered,
you cannot make assumptions about the order in which you visit the elements of the set:
animals = {'cat', 'dog', 'fish'}
for idx, animal in enumerate(animals):
print('#%d: %s' % (idx + 1, animal))
# Prints "#1: fish", "#2: dog", "#3: cat"
Set comprehensions: Like lists and dictionaries, we can easily construct sets using set comprehensions:
from math import sqrt
nums = {int(sqrt(x)) for x in range(30)}
print(nums) # Prints "{0, 1, 2, 3, 4, 5}"
Tuples
A tuple is an (immutable) ordered list of values. A tuple is in many ways similar to a list; one of the
most important differences is that tuples can be used as keys in dictionaries and as elements of sets,
while lists cannot. Here is a trivial example:
d = {(x, x + 1): x for x in range(10)} # Create a dictionary with tuple
keys
t = (5, 6) # Create a tuple
print(type(t)) # Prints "<class 'tuple'>"
print(d[t]) # Prints "5"
print(d[(1, 2)]) # Prints "1"
The documentation has more information about tuples.
Functions
Python functions are defined using the def keyword. For example:
def sign(x):
if x > 0:
return 'positive'
elif x < 0:
return 'negative'
else:
return 'zero'
# Constructor
def __init__(self, name):
self.name = name # Create an instance variable
# Instance method
def greet(self, loud=False):
if loud:
print('HELLO, %s!' % self.name.upper())
else:
print('Hello, %s' % self.name)
Numpy
Numpy is the core library for scientific computing in Python. It provides a high-performance
multidimensional array object, and tools for working with these arrays. If you are already familiar with
MATLAB, you might find this tutorial useful to get started with Numpy.
Arrays
A numpy array is a grid of values, all of the same type, and is indexed by a tuple of nonnegative
integers. The number of dimensions is the rank of the array; the shape of an array is a tuple of integers
giving the size of the array along each dimension.
We can initialize numpy arrays from nested Python lists, and access elements using square brackets:
import numpy as np
# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
# [6 7]]
b = a[:2, 1:3]
# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :] # Rank 1 view of the second row of a
row_r2 = a[1:2, :] # Rank 2 view of the second row of a
print(row_r1, row_r1.shape) # Prints "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape) # Prints "[[5 6 7 8]] (1, 4)"
# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]]) # Prints "[2 2]"
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])
v = np.array([9,10])
w = np.array([11, 12])
# Matrix / vector product; both produce the rank 1 array [29 67]
print(x.dot(v))
print(np.dot(x, v))
x = np.array([[1,2],[3,4]])
x = np.array([[1,2], [3,4]])
print(x) # Prints "[[1 2]
# [3 4]]"
print(x.T) # Prints "[[1 3]
# [2 4]]"
# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v) # Prints "[1 2 3]"
print(v.T) # Prints "[1 2 3]"
Numpy provides many more functions for manipulating arrays; you can see the full list in the
documentation.
Broadcasting
Broadcasting is a powerful mechanism that allows numpy to work with arrays of different shapes when
performing arithmetic operations. Frequently we have a smaller array and a larger array, and we want to
use the smaller array multiple times to perform some operation on the larger array.
For example, suppose that we want to add a constant vector to each row of a matrix. We could do it like
this:
import numpy as np
# Add the vector v to each row of the matrix x with an explicit loop
for i in range(4):
y[i, :] = x[i, :] + v
SciPy
Numpy provides a high-performance multidimensional array and basic tools to compute with and
manipulate these arrays. SciPy builds on this, and provides a large number of functions that operate on
numpy arrays and are useful for different types of scientific and engineering applications.
The best way to get familiar with SciPy is to browse the documentation. We will highlight some parts of
SciPy that you might find useful for this class.
Image operations
SciPy provides some basic functions to work with images. For example, it has functions to read images
from disk into numpy arrays, to write numpy arrays to disk as images, and to resize images. Here is a
simple example that showcases these functions:
from scipy.misc import imread, imsave, imresize
Left: The original image. Right: The tinted and resized image.
MATLAB files
The functions scipy.io.loadmat and scipy.io.savemat allow you to read and write
MATLAB files. You can read about them in the documentation.
Distance between points
SciPy defines some useful functions for computing distances between sets of points.
The function scipy.spatial.distance.pdist computes the distance between all pairs of points
in a given set:
import numpy as np
from scipy.spatial.distance import pdist, squareform
Matplotlib
Matplotlib is a plotting library. In this section give a brief introduction to
the matplotlib.pyplot module, which provides a plotting system similar to that of MATLAB.
Plotting
The most important function in matplotlib is plot , which allows you to plot 2D data. Here is a simple
example:
import numpy as np
import matplotlib.pyplot as plt
With just a little bit of extra work we can easily plot multiple lines at once, and add a title, legend, and
axis labels:
import numpy as np
import matplotlib.pyplot as plt
# Compute the x and y coordinates for points on sine and cosine curves
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)
You can read much more about the plot function in the documentation.
Subplots
You can plot different things in the same figure using the subplot function. Here is an example:
import numpy as np
import matplotlib.pyplot as plt
# Compute the x and y coordinates for points on sine and cosine curves
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)
# Set the second subplot as active, and make the second plot.
plt.subplot(2, 1, 2)
plt.plot(x, y_cos)
plt.title('Cosine')
img = imread('assets/cat.jpg')
img_tinted = img * [1, 0.95, 0.9]