IPython magics

Magics are special instructions to the IPython interpreter that perform specialized actions. There are two types of magics:

  • Line-oriented: This type of magics start with a single percent (%) sign
  • Cell-oriented: This type of magics start with double percent (%%) signs

We are already familiar with one of the magic command, that is, %pylab inline. This particular magic does two of the following things: it imports NumPy and matplotlib, and sets up the notebook for inline plots. To see one of the other options, change the cell to %pylab.

Run this cell and then run the cell that produces the plot again. Instead of drawing the graph inline, IPython will now open a new window with the plot as shown in the following screenshot:

IPython magics

This window is interactive and you can resize the graph, move it, and save it to a file from here.

Another useful magic is %timeit, which records the time it takes to run a line of Python code. Run the following code in a new cell in the notebook:

%timeit return_on_investment(principal, interest_rate, tvalues)

The output will be something like this:

100000 loops, best of 3: 3.73 µs per loop

To obtain a better estimate, the command is run 10,000 times and the runtime is averaged. This is done three times and the best result is reported.

The %timeit magic is also available in the Edit mode. To demonstrate this, run the following command in a cell:

principal = 250
interest_rates = [0.0001 * i for i in range(100000)]
tfinal = 10

In the next cell, run the following command:

%%timeit
returns = []
for r in interest_rates:
    returns.append(return_on_investment(principal, r, tfinal))

The preceding code computes a list with the returns for 100,000 different values of the interest rate, but uses plain Python code only. The reported time for this code is displayed in the following output:

10 loops, best of 3: 31.6 ms per loop

Let's now rewrite the same computation using NumPy arrays. Run the following command in a cell:

principal = 250
interest_rates = arange(0, 10, 0.0001)
tfinal = 10

In the next cell, run the following command:

%%timeit
returns = return_on_investment(principal, interest_rates, tfinal)

Now, the runtime is displayed in the following output:

100 loops, best of 3: 5.53 ms per loop

When comparing the two outputs, we can see the speed gain obtained using NumPy.

To list all magics that are available, run the following command in a cell:

%lsmagic

Once you have the list of all magics, you can inquire about a particular one by running a cell with the magic name appended by a question mark: %pylab?.

This will display the information about the %pylab magic in a separate window at the bottom of the browser.

Another interesting feature is the capability to run code that is written in other languages. Just to illustrate the possibilities, we'll see how to accelerate the code using Cython, because Cython compiles Python code into C. Let's write a function that computes approximations of areas bounded by a sine curve. Here is how we could define the function in pure Python:

import math
def sin_area(a, b, nintervals):
    dx = (b-a)/nintervals
    sleft = 0.0
    sright = 0.0
    for i in range(nintervals):
        sleft += math.sin(a + i * dx)
        sright += math.sin(a + (i + 1) * dx)
    return dx * (sright + sleft) / 2 

We will approximate the area by taking the average of the left and right endpoint rules (which is equivalent to the Trapezoidal rule). The code is admittedly inefficient and unpythonic. Notice in particular that we use the Python library version of the sin() function, instead of the NumPy implementation. The NumPy implementation, in this case, actually yields a slower code due to the repeated conversions between lists and arrays.

To run a simple test, execute the following command in a cell:

sin_area(0, pi, 10000)

We get the following output after running the preceding cell:

1.9999999835506606

The output makes sense, since the actual value of the area is 2. Let's now time the execution using the following command:

%timeit sin_area(0, pi, 10000)

We will get the following output:

100 loops, best of 3: 3.7 ms per loop

Let's now implement the same function in Cython. Since the Cython magic is in an extension module, we need to load that module first. We will load the extension module using the following command:

%load_ext cythonmagic

Now, we will define the Cython function. We will not discuss the syntax in detail, but notice that it is pretty similar to Python (the main difference in this example is that we must declare the variables to specify their C type):

%%cython
cimport cython
from libc.math cimport sin

@cython.cdivision(True)
def sin_area_cython(a, b, nintervals):
    cdef double dx, sleft, sright
    cdef int i
    dx = (b-a)/nintervals
    sleft = 0.0
    sright = 0.0
    for i in range(nintervals):
        sleft += sin(a + i * dx)
        sright += sin(a + (i + 1) * dx)
    return dx * (sright + sleft) / 2

Test the preceding function using the following command:

sin_area_cython(0, pi, 10000)

After running the preceding function, we get the same output as earlier:

1.9999999835506608

Let's now time the function using the following command:

%timeit sin_area_cython(0, pi, 10000)

The runtime is displayed in the following output:

1000 loops, best of 3: 1.12 ms per loop

We see that the Cython code runs in about 30 percent of the total time taken by the Python code. It is important to emphasize that this is not the recommended way to speed up this code. A simpler solution would be to use NumPy to vectorize the computation:

def sin_area_numpy(a, b, nintervals):
    dx = (b - a) / nintervals
    xvalues = arange(a, b, dx)
    sleft = sum(sin(xvalues))
    sright = sum(sin(xvalues + dx))
    return dx * (sleft + sright) / 2

The time after running the preceding code is displayed in the following output:

1000 loops, best of 3: 248 µs per loop

There is a lesson here; when we try to speed up the code, the first thing to try is to always write it using NumPy arrays, taking the advantage of vectorized functions. If further speedups are needed, we can use specialized libraries such as Numba and NumbaPro (which will be discussed later in this book) to accelerate the code. In fact, these libraries provide a simpler approach to compile the code into C than using Cython directly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset