NB: Python Timing Experiment

Purpose

Using time

One way to get the runtime of a code block is to use the time module.

About time

The time module provides a number of functions to get and compute time.

The simplest function is time(), which just returns the number of seconds elapsed since the Epoch.

The Epoch is 00:00:00 UTC on 1 January 1970, excluding leapseconds.

It corresponds roughly to when Unix was invented.

from time import time
t0 = time()

for i in range(10):
    print(i, end=' ')

t1 = time()

delta_t = t1 - t0
0 1 2 3 4 5 6 7 8 9 
print('t0 =', t0)
print('t1 =', t1)
print('runtime:', delta_t)
t0 = 1663428793.540521
t1 = 1663428793.541329
runtime: 0.0008080005645751953

Using timeit

To get a better measure of runtime, we can use timeit, which measures timing across many runs.

Note that timeit() will return the runtime across ALL runs. To get the mean runtime, you need to divide by the number of runs.

timeit() works by evaluating code blocks written as strings.

from timeit import timeit
  
NUM_RUNS = 100

Define code blocks to compare.

loop_code = ''' 
vals = []
for i in range(1, 100001):
    if i % 2 == 1:
        i *= -1
    vals.append(i)
'''

listcomp_code = ''' 
vals = [i*-1 for i in range(1,100001) if i % 2 == 1 ]
'''

Pass code block strings to timeit functions.

loop_mean_time = timeit(stmt = loop_code, number = NUM_RUNS) / NUM_RUNS
listcomp_mean_time = timeit(stmt = listcomp_code, number = NUM_RUNS) / NUM_RUNS

Print the results

t_diff = loop_mean_time / listcomp_mean_time
print('loop =', loop_mean_time)
print('comp =', listcomp_mean_time)
print('loop/list =', t_diff)
print('list/loop =', 1/t_diff)
loop = 0.011182495189999885
comp = 0.00927148506000009
loop/list = 1.2061169400190757
list/loop = 0.8291070018336566

Using Magic

Instead of calling time and timeit directly, we can use the so-called magic commands.

Magic commands are % or %% prefixed commands that work in Jupyter notebooks and other IPython environments.

% commands apply to single lines; they go at the beginning of the line.

%% commands apply to cell blocks; they go at the top of the cell.

Magic commands can take arguments. For more info, see * Chapter 3 in Wes McKinney’s Python for Data Analysis. * The official documentation

Placing %%timeit or %%time at the top of a cell will appy these functions to the cell block.

Placing %timeit or %time as the first item on a line of code will apply the to a single line.

Types of Time

  • Wall clock time measures how much time has passed, as if you were looking at the clock on your wall.
  • CPU time refers to how many seconds the CPU was actually busy.
imax = 10000

Using time to compare loop and comprehension

%%time

vals = []
for i in range(1, imax+1):
    if i % 2 == 1:
        i *= -1
    vals.append(i)
CPU times: user 1.69 ms, sys: 35 µs, total: 1.72 ms
Wall time: 1.73 ms
%time vals = [i*-1 if i % 2 == 1 else i for i in range(1,imax+1)] 
CPU times: user 940 µs, sys: 32 µs, total: 972 µs
Wall time: 975 µs

Using timeit to compare loop and comprehension

%%timeit

vals = []
imax = 10000
for i in range(1, imax+1):
    if i % 2 == 1:
        i *= -1
    vals.append(i)
1.08 ms ± 88 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
vals[:10]
[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]
%timeit vals = [i*-1 if i % 2 == 1 else i for i in range(1,imax+1)] 
749 µs ± 3.32 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)