Week 5 notebook

numpy arrays

In [2]:
import numpy as np

A key feature of numpy are numpy arrays that resemble lists.

A list can be converted into a numpy array using the np.array() function:

In [2]:
numbers = [1, 2, 3]
print(numbers)
[1, 2, 3]
In [3]:
a = np.array(numbers)
print(a)
[1 2 3]

We can use the type() function to verify that a is a numpy array:

In [4]:
type(numbers)
Out[4]:
list
In [5]:
type(a)
Out[5]:
numpy.ndarray
In [6]:
b = 10
In [7]:
type(b)
Out[7]:
int

Many mathematical operations can be performed on all elements of a numpy array at once:

In [8]:
print(a)
[1 2 3]
In [9]:
print(5*a)
[ 5 10 15]
In [10]:
print(5*numbers)
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
In [11]:
b = list(a)
In [12]:
print(b)
[1, 2, 3]
In [13]:
print(a**2)
[1 4 9]
In [14]:
a += 10
In [15]:
print(a)
[11 12 13]
In [16]:
b = np.array([100, 200, 300])
In [17]:
print(b)
[100 200 300]
In [18]:
print(a+b)
[111 212 313]
In [19]:
print(a*b)
[1100 2400 3900]

The numpy module contains versions of many math functions (trigonometric, logarithmic, etc.) that can be applied to whole arrays:

In [25]:
from math import pi
In [26]:
x = np.array([pi/8, pi/4, pi/2, pi])
In [27]:
y = np.sin(x)
In [28]:
print(y)
[  3.82683432e-01   7.07106781e-01   1.00000000e+00   1.22464680e-16]

Note: math module functions do not work with numpy arrays:

In [29]:
from math import sin
In [30]:
sin(x)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-30-60c5cd724141> in <module>()
----> 1 sin(x)

TypeError: only length-1 arrays can be converted to Python scalars

for loops work for numpy arrays:

In [31]:
print(a)
[11 12 13]
In [32]:
for x in a:
    print(2*x)
22
24
26

Indexing and slicing for numpy arrays work as for lists:

In [33]:
x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
In [34]:
x[0] = 1000
In [35]:
print(x)
[1000    2    3    4    5    6    7    8]
In [36]:
print(x[:4])
[1000    2    3    4]

Note: For lists slicing produces a new list, for numpy arrays it produces a "view" of the origianal array. Changing a slice of a numpy array will change the original array.

In [38]:
a = [1, 2, 3, 4]
b = a[:2]
In [40]:
b[0] = 1000
print(b)
print(a)
[1000, 2]
[1, 2, 3, 4]
In [41]:
a = np.array([1, 2, 3, 4])
b = a[:2]
print(a)
print(b)
[1 2 3 4]
[1 2]
In [42]:
b[0] =1000
print(a)
print(b)
[1000    2    3    4]
[1000    2]

To get an independent copy of a numpy use the copy() function:

In [43]:
a = np.array([1, 2, 3, 4])
b = a[:2].copy()
In [44]:
b[0] = 1000
print(b)
print(a)
[1000    2]
[1 2 3 4]
In [45]:
a = np.array([1, 2, 3, 4])
In [46]:
print(a)
[1 2 3 4]
In [47]:
a.append(100)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-47-8f179117e6ba> in <module>()
----> 1 a.append(100)

AttributeError: 'numpy.ndarray' object has no attribute 'append'

How to create numpy arrays

1) Use the np.array() function to convert a list into an array:

In [48]:
a = np.array([1, 2, 3])
print(a)
[1 2 3]

2) Use np.zeros(n) to create an array of n zeros:

In [50]:
b = np.zeros(10)
print(b)
[ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]

By default this creates a array of floats, but this can ve changed by specifying dtype:

In [51]:
c = np.zeros(10, dtype = 'int')
In [52]:
print(c)
[0 0 0 0 0 0 0 0 0 0]

3) The np.ones(n) function creates an array of n ones:

In [54]:
d = np.ones(10)
print(d)
[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
In [55]:
from math import pi

x = pi*d
print(x)
[ 3.14159265  3.14159265  3.14159265  3.14159265  3.14159265  3.14159265
  3.14159265  3.14159265  3.14159265  3.14159265]

4) The np.empty(n) function creates an array of length n with uninitialized values.

In [5]:
y = np.empty(10, dtype= 'int')
print(y)
[-5764607523034234880 -5764607523034234880                    9
                    0                    0                    0
                    0                    0                    0
                    0]

5) np.arange() is similar to range() but it produces an array:

In [60]:
numbers = np.arange(10)
print(numbers)
[0 1 2 3 4 5 6 7 8 9]
In [61]:
evens = np.arange(10, 20, 2)
print(evens)
[10 12 14 16 18]

Note: Arguments of np.arange() can be floats:

In [62]:
w = np.arange(0.3, 1.0, 0.2)
In [63]:
print(w)
[ 0.3  0.5  0.7  0.9]

6) np.linspace(a, b, n) creates an array of n evenly spaces numbers between a and b:

In [64]:
z = np.linspace(0, 1, 5)
print(z)
[ 0.    0.25  0.5   0.75  1.  ]

Note: Array functions in general work much faster than functions applied to every element of a list:

In [65]:
from time import time
from math import sin

st = time()
mylist = [sin(x) for x in range(10**7)]
print(time() - st)
1.5520219802856445
In [66]:
st = time()
myarray = np.sin(np.arange(10**7))
print(time() - st)
0.3206050395965576

numpy arrays and matplotlib

matplotlib works directly with numpy arrays:

In [67]:
import matplotlib.pyplot as plt
In [68]:
x = np.linspace(-np.pi, np.pi, 1000)
In [69]:
y = np.sin(x)
In [70]:
plt.plot(x, y)
plt.show()

Subplots

The matplotlib subplot() function allows to create a matplot figure consisting of several subplots. The syntax is: plt.subplot(r, c, n) where:

  • r = the number of rows in the grid
  • c = the number of columns in the grid
  • n = the number of subplot in the grid
In [79]:
plt.figure(figsize =(8, 5))

plt.subplot(2, 2, 1) # plot nr 1 on a grid with 2 rows 2 columns
x = np.linspace(-3, 3, 500)
y = np.sin(x)
plt.plot(x, y, 'r')
plt.title('subplot(2,2,1)')


plt.subplot(2, 2, 2) # plot nr 2 on a grid with 2 rows 2 columns
y = np.cos(x)
plt.plot(x, y, 'b')
plt.title('subplot(2,2,2)')


plt.subplot(2, 2, 3) # plot nr 3 on a grid with 2 rows 2 columns
y = x**2
plt.plot(x, y, 'g')
plt.title('subplot(2,2,3)')

plt.subplot(2, 2, 4) # plot nr 4 on a grid with 2 rows 2 columns
y = x
plt.plot(x, y, 'y')
plt.title('subplot(2,2,4)')



plt.show()

Spacing between subplots can be adjusted:

In [98]:
plt.figure(figsize =(8, 5))

# wspace = width space, hspace = height space
plt.subplots_adjust(wspace = 0.2, hspace = 0.4)

plt.subplot(2, 2, 1) # plot nr 1 on a grid with 2 rows 2 columns
x = np.linspace(-3, 3, 500)
y = np.sin(x)
plt.plot(x, y, 'r')
plt.title('subplot(2,2,1)')


plt.subplot(2, 2, 2) # plot nr 2 on a grid with 2 rows 2 columns
y = np.cos(x)
plt.plot(x, y, 'b')
plt.title('subplot(2,2,2)')


plt.subplot(2, 2, 3) # plot nr 3 on a grid with 2 rows 2 columns
y = x**2
plt.plot(x, y, 'g')
plt.title('subplot(2,2,3)')

plt.subplot(2, 2, 4) # plot nr 4 on a grid with 2 rows 2 columns
y = x
plt.plot(x, y, 'y')
plt.title('subplot(2,2,4)')



plt.show()
In [7]:
import numpy as np
import matplotlib.pyplot as plt
In [6]:
x = np.linspace(-3, 3, 1000)

plt.figure(figsize=(10, 3))

plt.subplot(1, 2, 1)
y = np.sin(x)
plt.plot(x, y)

plt.subplot(1, 2, 2)
y = np.cos(x)
plt.plot(x, y, 'r')


plt.show()
In [10]:
ab = [[a, b] for a in range(1, r+1) for b in range(1, r+1)]

print(ab)
[[1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5]]
In [22]:
plt.figure(figsize = (10, 8))

t = np.linspace(-np.pi, np.pi, 500)

for i in range(r**2):
    plt.axis('equal')
    plt.subplot(r, r, i+1)
    a, b = ab[i]
    x = np.sin(a*t)
    y = np.cos(b*t)
    plt.xticks([])
    plt.yticks([])
    plt.title('a={}, b={}'.format(a, b))
    plt.plot(x, y)

plt.suptitle('Lissajous curves')
plt.show()   
In [16]:
plt.plot([1, 2, 3], [1, 2,3])
plt.xticks([1, 1.3, 2, 2.25])
plt.show()

Subplots of different shapes can be combined as long as they don't overlap:

In [9]:
plt.figure(figsize=(8,5))

x = np.linspace(-6, 6, 500)

plt.subplot(2, 2, 1)
plt.plot(x, np.sin(x))
plt.title('subplot (2,2,1)')

plt.subplot(2, 2, 3)
plt.plot(x, x*np.cos(x))
plt.title('subplot (2,2,2)')

plt.subplot(1, 2, 2)
plt.plot(x, np.cos(10*x))
plt.title('subplot (1,2,2)')

plt.show()

matplotlib axes objects

The plt.subplot() function returns an axes object which can be used to specify which subplot is active for plotting:

In [28]:
plt.figure(figsize=(8,5))

x = np.linspace(0,6, 500)

ax1 = plt.subplot(2, 1, 1)
plt.plot(x, np.sin(x))

ax2 = plt.subplot(2, 1, 2)
plt.plot(x, np.cos(x), 'g')


plt.axes(ax1) #activate subplot (2,1,1)
plt.plot(x, np.cos(10*x), 'r--')

plt.show()

We can also use the plt.axes() function to create an axes object and position it any way we want. Syntax is: plt.axes([x, y, w, h]) where:

  • (x, y) - coords of the lower left corner of the axes object
  • w - width
  • h - height
In [31]:
plt.figure(figsize=(8, 5))

x = np.linspace(0,6, 500)

ax1 = plt.axes([0.2, 0.1, 0.7, 0.5])
ax2 = plt.axes([0.5, 0.4, 0.5, 0.5])

plt.axes(ax1)
plt.plot(x, np.sin(x))

plt.axes(ax2)
plt.plot(x, np.cos(x), 'r')


plt.show()

Project 3: The mayfly model

The simplest population model:

$$x_n = a\cdot x_{n-1}$$

Note: This model depends on $a$ and $x_0$-the initial population.

In [33]:
a = 1.1

x = 10000
list1 = []
for n in range(50):
    x = a*x
    list1.append(int(x))
print(list1)
[11000, 12100, 13310, 14641, 16105, 17715, 19487, 21435, 23579, 25937, 28531, 31384, 34522, 37974, 41772, 45949, 50544, 55599, 61159, 67274, 74002, 81402, 89543, 98497, 108347, 119181, 131099, 144209, 158630, 174494, 191943, 211137, 232251, 255476, 281024, 309126, 340039, 374043, 411447, 452592, 497851, 547636, 602400, 662640, 728904, 801795, 881974, 970172, 1067189, 1173908]
In [10]:
a = 0.9

x = 10000
list2 = []
for n in range(100):
    x = a*x
    list2.append(int(x))
print(list2)
[9000, 8100, 7290, 6561, 5904, 5314, 4782, 4304, 3874, 3486, 3138, 2824, 2541, 2287, 2058, 1853, 1667, 1500, 1350, 1215, 1094, 984, 886, 797, 717, 646, 581, 523, 471, 423, 381, 343, 309, 278, 250, 225, 202, 182, 164, 147, 133, 119, 107, 96, 87, 78, 70, 63, 57, 51, 46, 41, 37, 33, 30, 27, 24, 22, 19, 17, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
In [35]:
plt.plot(list1, 'ro')
plt.show()
In [12]:
plt.plot(list2, 'go')
plt.savefig('test.png')
plt.show()

The mayfly model:

$$y_n = b(1-y_{n-1})y_{n-1}$$

Note: this depends on $y_0$ and the parameter $b$.

Note: We consider only $0\le y_0 \le 1$ and $0 \le b \le 4$.