Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Lecture 01: Python primer

University of Lausanne

Course: Deep Learning for Solving and Estimating Dynamic Models in Economics and Finance
Script reference: Front matter and Appendix~E — for / while loops, range, enumerate
Notebook role: primer (pre-course self-study; skip if you write Python every day)
Author: Simon Scheidegger

Python Basics 6: Loops

Loops are used when you need to run the same expression of similar data. There are two kinds of loops in Python: for loops and while loops.

for loops

The syntax of for loops is as follows:

for <variable> in <collection>:
    # run an expression potentially using <variable>
    # run another expression ...

The idea is that <collection> is an iterable object like a tuple or a list and that <variable> takes sequentially each one of the values in that iterable object. Here are a few examples:

for x in (1, 5, 6, 10, 20):
    print('x = {0:d}'.format(x))
x = 1
x = 5
x = 6
x = 10
x = 20
for x in [1, 5, 6, 10, 20]:
    print('x = {0:d}'.format(x))
x = 1
x = 5
x = 6
x = 10
x = 20
for c in 'This is a string':
    print('c = \'{0:s}\''.format(c))
c = 'T'
c = 'h'
c = 'i'
c = 's'
c = ' '
c = 'i'
c = 's'
c = ' '
c = 'a'
c = ' '
c = 's'
c = 't'
c = 'r'
c = 'i'
c = 'n'
c = 'g'

Very often, we want to loop over all values from 0 to a given number. We can do this with range:

for i in range(10):
    print('i = {0:d}'.format(i))
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9

You don’t have to start at 0:

for i in range(2, 10):
    print('i = {0:d}'.format(i))
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9

And you can skip numbers:

for i in range(2, 10, 2):
    print('i = {0:d}'.format(i))
i = 2
i = 4
i = 6
i = 8

And you can also go backwards:

for i in range(10, 0, -1):
    print('i = {0:d}'.format(i))
i = 10
i = 9
i = 8
i = 7
i = 6
i = 5
i = 4
i = 3
i = 2
i = 1

Let’s now create some random data and write code to calculate the average:

data = [0.16295757, 0.06804887, 0.76082389, 0.39089033, 0.63845432,
       0.12555193, 0.98251807, 0.38759292, 0.75819177, 0.63329008,
       0.94419572, 0.95363126, 0.60753037, 0.55727347, 0.55989237,
       0.2482676 , 0.13208943, 0.25090889, 0.7912593 , 0.30045856]

Recall that the average of NN numbers x1,x2,,xNx_1, x_2,\dots,x_N is:

xˉ=x1++xNN.\bar{x} = \frac{x_1+\dots+x_N}{N}.

Here is how we can code this with a for loop:

# The number of observations
N = len(data)
# A variable that stores the sum of all the x's as we go through
# the data
s = 0.0
# The loop
for i in range(len(data)):
    x = data[i]
    # This is just a shortcut for s = s + x
    s += x
average = s / N
print('Average = {0:1.2f}'.format(average))
Average = 0.51

Let’s compare this to the other way we have learned:

print('Average the other way = {0:1.2f}'.format(sum(data) / N))
Average the other way = 0.51

Okay. It worked fine. Here is another way to do the same thing. Instead of using an index, we can directly go over each element in the list like this:

s = 0.0
for x in data:
    s += x
average = s / N
print('Average = {0:1.2f}'.format(average))
Average = 0.51

Questions

  • Write a code block that calculates the average of all the data elements that are greater than 0.5.

# Your code here
  • Write a for loop to calculate the second moment of the data, i.e., this expression:

    xˉ2=x12++xN2N\bar{x}_2 = \frac{x_1^2 + \dots + x_N^2}{N}
# Your code here
  • In the code block provided below, write a for loop that finds the maximum of the data.

# Your code here

while loops

While loops are a bit more general than for loops as stopping depends on a boolean expression. Their syntax is like this:

while <boolean_expression>:
    # Some expressions to execute
    # Some other epxression to execute

Let’s see some examples of this:

i = 0
while i < 10:
    print('i = {0:d}'.format(i))
    i += 1
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9

Let’s do a more mathematical example. We are going to write code that calculates the sum of a series to a given tolerance. That is, given a sequence of numbers: a1,a2,,a_1, a_2, \dots,, we will write code that approximates:

a=n=0an.a = \sum_{n=0}^\infty a_n.

To be specific, we are going to sum this series:

113+1517+=π4,1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \dots = \frac{\pi}{4},

and use it to approximate π\pi. This is known as the Leibniz formula. In terms of the αn\alpha_n notation above, the formula is:

n=0an=n=0(1)n2n+1.\sum_{n=0}^\infty a_n = \sum_{n=0}^\infty\frac{(-1)^{n}}{2n + 1}.

Here is our first attempt:

# The maximum number of iterations you are willing to do:
max_iter = 100000
# The result
a = 0.0
# Start a counter
n = 0
# Start the loop
while n <= max_iter:
    # Compute the new term
    a_n = (-1) ** n / (2 * n + 1)
    # Add it to the sum
    a += a_n
    # and increase the counter
    n += 1
print('4 * a ~= {0:1.12f}'.format(4 * a))
4 * a ~= 3.141602653490

Let’s now make our code print something every few iterations (say every 10,000 iterations).

# The maximum number of iterations you are willing to do:
max_iter = 100000
# The result
a = 0.0
# Start a counter
n = 0
# Start the loop
while n <= max_iter:
    # Compute the new term
    a_n = (-1) ** n / (2 * n + 1)
    # Add it to the sum
    a += a_n
    # Print something about the current iteration
    if n % 10000 == 0:
        print('Current iteration n = {0:10d}, sum so far: {1:1.12f}'.format(n, a))
    # and increase the counter
    n += 1
print('')
print('4 * a ~= {0:1.12f}'.format(4 * a))
Current iteration n =          0, sum so far: 1.000000000000
Current iteration n =      10000, sum so far: 0.785423160898
Current iteration n =      20000, sum so far: 0.785410662772
Current iteration n =      30000, sum so far: 0.785406496453
Current iteration n =      40000, sum so far: 0.785404413241
Current iteration n =      50000, sum so far: 0.785403163297
Current iteration n =      60000, sum so far: 0.785402329995
Current iteration n =      70000, sum so far: 0.785401734775
Current iteration n =      80000, sum so far: 0.785401288358
Current iteration n =      90000, sum so far: 0.785400941144
Current iteration n =     100000, sum so far: 0.785400663372

4 * a ~= 3.141602653490

Now, let’s not run forever. We are going to modify the code so that it loops over nn until an+1<ϵ|a_{n+1}| < \epsilon, where ϵ\epsilon is a small positive number typically called a tolerance. We are going to use the keyword break to achieve this. break is a command to exit the loop (note that it also works in for loops). Here we go:

# The maximum number of iterations you are willing to do.
# You always add something like this to avoid looping forever
max_iter = 1000000
# The tolerance you wish to reach:
epsilon = 1e-4
# The result
a = 0.0
# Start a counter
n = 0
# Start the loop
while n <= max_iter:
    # Compute the new term
    a_n = (-1) ** n / (2 * n + 1)
    # Check if the absolute value of the new term is smaller than the tolerance
    if abs(a_n) < epsilon:
        # If it is indeed smaller, exit the loop
        # you do this with the command
        print('Current iteration n = {0:10d}, sum so far: {1:1.12f}'.format(n, a))
        print('*** Converged in {0:d} iterations! ***'.format(n+1))
        break
    # Otherwise we just add the new term to our running sum
    a += a_n
    # Print something about the current iteration
    if n % 1000 == 0:
        print('Current iteration n = {0:10d}, sum so far: {1:1.12f}'.format(n, a))
    # and increase the counter
    n += 1
if n == max_iter + 1:
    print('*** Stopped when maximum number of iterations ({0:d}) were reached! ***'.format(max_iter))
print('4 * a ~= {0:1.12f}'.format(4 * a))
Current iteration n =          0, sum so far: 1.000000000000
Current iteration n =       1000, sum so far: 0.785647913585
Current iteration n =       2000, sum so far: 0.785523100921
Current iteration n =       3000, sum so far: 0.785481468960
Current iteration n =       4000, sum so far: 0.785460647775
Current iteration n =       5000, sum so far: 0.785348163398
*** Converged in 5001 iterations! ***
4 * a ~= 3.141392653592

Questions

  • Modify the code above so that you estimate the series:

    n=012n,\sum_{n=0}^\infty\frac{1}{2^n},

    which converges to 2.