├── README.md ├── chapter2 ├── 201-facebook-data-download.ipynb ├── 202-facebook-data-explore.ipynb ├── 203-networkx.ipynb ├── center.py ├── center2.py └── egos.py ├── chapter3 ├── 301-vector-computations.ipynb ├── 302-multiplication-tables.ipynb └── 303-cities-data-explore.ipynb ├── chapter4 ├── 401-matplotlib-intro.ipynb ├── 402-world-map.ipynb ├── 403-histograms.ipynb ├── 404-customization.ipynb ├── 405-image-processing.ipynb ├── 406-plot3d.ipynb └── gui.py ├── chapter5 ├── 501-parallel-computing.ipynb ├── 502-monte-carlo.ipynb ├── 503-mpi.ipynb ├── 504-cython-eratosthenes.ipynb ├── 505-cython-numpy.ipynb └── psum.py └── chapter6 ├── 601-lprof.ipynb ├── 602-cpp.ipynb ├── 603-notebook-rich-display.ipynb ├── cppmagic.py └── myscript.py /README.md: -------------------------------------------------------------------------------- 1 | Examples from the IPython mini-book 2 | =================================== 3 | 4 | This repository contains all code examples from the book [Learning IPython for Interactive Computing and Data Visualization](http://www.packtpub.com/learning-ipython-for-interactive-computing-and-data-visualization/book), [Packt Publishing](http://www.packtpub.com), by [Cyrille Rossant](http://cyrille.rossant.net). 5 | 6 | 7 | Book overview 8 | ------------- 9 | 10 | This book is a **beginner-level introduction to IPython** for *interactive Python programming*, *high-performance numerical computing*, and *data visualization*. It assumes nothing more than familiarity with Python. It targets developers, students, teachers, hobbyists who know Python a bit, and who want to learn IPython for the extended console, the Notebook, and for more advanced scientific applications. 11 | 12 | The book first introduces IPython for interactive Python and shell programming. It shows how IPython can considerably improve the productivity of a developer who creates, debugs, benchmarks and profiles Python code. 13 | 14 | Then, the reader learns the very basics of vector computing, and discovers how to load and analyze numerical and tabular data with NumPy and Pandas. The book shows the interactive visualization capabilities of the platform with Matplotlib, SciPy and PIL. It also contains a few image processing examples. 15 | 16 | Some techniques to accelerate Python code are also demonstrated, using either interactive parallel computing features from IPython (using MPI or not), or Cython to compile a portion of the code in C for really interesting speedups. 17 | 18 | Finally, the book shows how IPython can be customized for advanced uses, notably with the creation of new extensions and magic commands. 19 | 20 | 21 | Code examples 22 | ------------- 23 | 24 | Most files are IPython notebooks (`.ipynb` extension with JSON data). There are also some Python external scripts (`.py` extension). 25 | 26 | The following modules are used in at least one example: 27 | 28 | * Python 2.7 29 | * IPython 0.13+ 30 | * NumPy 31 | * Pandas 32 | * SciPy 33 | * Matplotlib 34 | * Matplotlib basemap 35 | * NetworkX 36 | * PyQt or PySide 37 | * Cython 38 | * PIL 39 | 40 | You can view the notebooks in the IPython notebook viewer (see links below). 41 | 42 | 43 | ### Chapter 2: Interactive Work with IPython 44 | 45 | * [Example 1](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter2/201-facebook-data-download.ipynb). We download and extract a social graph dataset (ego graphs of anonymous Facebook users, obtained on the [SNAP project](http://snap.stanford.edu/data/) from Stanford University). This example illustrates how to interact with the filesystem from IPython. 46 | 47 | * [Example 2](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter2/202-facebook-data-explore.ipynb). Here we explore with IPython the dataset downloaded in the previous example. 48 | 49 | * [Example 3](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter2/203-networkx.ipynb). We use the NetworkX package to process social graphs. We show how to explore simultaneously the data and a new Python module as well in an IPython interactive session. 50 | 51 | 52 | ### Chapter 3: Numerical Computing with IPython 53 | 54 | * [Example 1](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter3/301-vector-computations.ipynb). We introduce here the very basics of vector computing and NumPy multidimensional arrays. We show with a simple example what performance gains we can expect by using NumPy instead of pure Python loops. 55 | 56 | * [Example 2](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter3/302-multiplication-tables.ipynb). We generate multiplication tables with different methods, showing the performance benefits of using vectorized computations and broadcasting. 57 | 58 | * [Example 3](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter3/303-cities-data-explore.ipynb). We download and analyze a new dataset containing the geographical coordinates of all cities in the world, as well as the population for some of them. [This free dataset](http://www.maxmind.com/en/worldcities) has been created by [MaxMind](http://www.maxmind.com/). 59 | 60 | 61 | ### Chapter 4: Interactive Plotting and Graphical Interfaces 62 | 63 | * [Example 1](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter4/401-matplotlib-intro.ipynb). This is a short introduction to the most basic plotting features of Matplotlib. 64 | 65 | * [Example 2](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter4/402-world-map.ipynb). We use the world cities dataset from the previous example to create a human density world map with SciPy and Matplotlib. 66 | 67 | * [Example 3](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter4/403-histograms.ipynb). We show how to plot histograms of social data. 68 | 69 | * [Example 4](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter4/404-customization.ipynb). We show a few customization options with Matplotlib. 70 | 71 | * [Example 5](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter4/405-image-processing.ipynb). We show how to use PIL and SciPy for some basic image processing algorithms. 72 | 73 | * [Example 6](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter4/406-plot3d.ipynb). This is a 3D plot example with Matplotlib. 74 | 75 | 76 | ### Chapter 5: High Performance and Parallel Computing 77 | 78 | * [Example 1](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter5/501-parallel-computing.ipynb). We demonstrate the most basic interactive parallel computing features of IPython. 79 | 80 | * [Example 2](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter5/502-monte-carlo.ipynb). We show how Monte Carlo simulations can be parallelized with IPython. 81 | 82 | * [Example 3](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter5/503-mpi.ipynb). This is a simple MPI example executed from an interactive IPython session. 83 | 84 | * [Example 4](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter5/504-cython-eratosthenes.ipynb). We show how an imperative algorithm (Sieve of Eratosthenes) implemented in Python can be accelerated with Cython. 85 | 86 | * [Example 5](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter5/505-cython-numpy.ipynb). We show how to use Cython with NumPy-based algorithms for dramatic speed improvements. 87 | 88 | 89 | ### Chapter 6: Customizing IPython 90 | 91 | * [Example 1](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter6/601-lprof.ipynb). We show how to load IPython extensions, with an application to line-by-line profiling of Python code. 92 | 93 | * [Example 2](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter6/602-cpp.ipynb). We show how to create a new IPython extension. As an example, we create a very basic extension for writing and executing C++ code in the IPython notebook. 94 | 95 | * [Example 3](http://nbviewer.ipython.org/url/raw.github.com/rossant/ipython-minibook/master/chapter6/603-notebook-rich-display.ipynb). We illustrate the rich display features of the IPython notebook. 96 | -------------------------------------------------------------------------------- /chapter2/201-facebook-data-download.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_02_01" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 2, example 1\n", 15 | "====================\n", 16 | "\n", 17 | "In this example, we show how to use IPython to perform common system actions such as downloading a Zip file, extracting it in a new folder, etc. Specifically, we download some social data about anonymous volunteer Facebook users.\n", 18 | "\n", 19 | "The data is freely available on [Stanford's SNAP project](http://snap.stanford.edu/data/)." 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "We begin by importing native modules used to download and extract compressed files." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "collapsed": false, 32 | "input": [ 33 | "import urllib2, zipfile" 34 | ], 35 | "language": "python", 36 | "metadata": {}, 37 | "outputs": [], 38 | "prompt_number": 1 39 | }, 40 | { 41 | "cell_type": "code", 42 | "collapsed": false, 43 | "input": [ 44 | "url = 'http://ipython.rossant.net/'" 45 | ], 46 | "language": "python", 47 | "metadata": {}, 48 | "outputs": [], 49 | "prompt_number": 2 50 | }, 51 | { 52 | "cell_type": "code", 53 | "collapsed": false, 54 | "input": [ 55 | "filename = 'facebook.zip'" 56 | ], 57 | "language": "python", 58 | "metadata": {}, 59 | "outputs": [], 60 | "prompt_number": 3 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "We download the file in memory with `urllib2.urlopen`." 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "collapsed": false, 72 | "input": [ 73 | "downloaded = urllib2.urlopen(url + filename)" 74 | ], 75 | "language": "python", 76 | "metadata": {}, 77 | "outputs": [], 78 | "prompt_number": 4 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "Now, we create a new folder named `data` and we save the Zip file in it." 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "collapsed": false, 90 | "input": [ 91 | "folder = 'data'" 92 | ], 93 | "language": "python", 94 | "metadata": {}, 95 | "outputs": [], 96 | "prompt_number": 5 97 | }, 98 | { 99 | "cell_type": "code", 100 | "collapsed": false, 101 | "input": [ 102 | "mkdir $folder" 103 | ], 104 | "language": "python", 105 | "metadata": {}, 106 | "outputs": [], 107 | "prompt_number": 6 108 | }, 109 | { 110 | "cell_type": "code", 111 | "collapsed": false, 112 | "input": [ 113 | "cd $folder" 114 | ], 115 | "language": "python", 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "output_type": "stream", 120 | "stream": "stdout", 121 | "text": [ 122 | "chapter2\\data\n" 123 | ] 124 | } 125 | ], 126 | "prompt_number": 7 127 | }, 128 | { 129 | "cell_type": "code", 130 | "collapsed": false, 131 | "input": [ 132 | "with open(filename, 'wb') as f:\n", 133 | " f.write(downloaded.read())" 134 | ], 135 | "language": "python", 136 | "metadata": {}, 137 | "outputs": [], 138 | "prompt_number": 8 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": {}, 143 | "source": [ 144 | "We use the `zipfile` module to extract the Zip file in the `data` folder." 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "collapsed": false, 150 | "input": [ 151 | "with zipfile.ZipFile(filename) as zip:\n", 152 | " zip.extractall('.')" 153 | ], 154 | "language": "python", 155 | "metadata": {}, 156 | "outputs": [], 157 | "prompt_number": 9 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "Common system file commands such as `ls` just work in IPython, even on Windows systems!" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "collapsed": false, 169 | "input": [ 170 | "ls" 171 | ], 172 | "language": "python", 173 | "metadata": {}, 174 | "outputs": [ 175 | { 176 | "output_type": "stream", 177 | "stream": "stdout", 178 | "text": [ 179 | "facebook.zip\n", 180 | "" 181 | ] 182 | } 183 | ], 184 | "prompt_number": 10 185 | }, 186 | { 187 | "cell_type": "code", 188 | "collapsed": false, 189 | "input": [ 190 | "cd facebook" 191 | ], 192 | "language": "python", 193 | "metadata": {}, 194 | "outputs": [ 195 | { 196 | "output_type": "stream", 197 | "stream": "stdout", 198 | "text": [ 199 | "chapter2\\data\\facebook\n" 200 | ] 201 | } 202 | ], 203 | "prompt_number": 11 204 | }, 205 | { 206 | "cell_type": "code", 207 | "collapsed": false, 208 | "input": [ 209 | "ls" 210 | ], 211 | "language": "python", 212 | "metadata": {}, 213 | "outputs": [ 214 | { 215 | "output_type": "stream", 216 | "stream": "stdout", 217 | "text": [ 218 | "0.circles\n", 219 | "0.edges\n", 220 | "107.circles\n", 221 | "107.edges\n", 222 | "1684.circles\n", 223 | "1684.edges\n", 224 | "1912.circles\n", 225 | "1912.edges\n", 226 | "3437.circles\n", 227 | "3437.edges\n", 228 | "348.circles\n", 229 | "348.edges\n", 230 | "3980.circles\n", 231 | "3980.edges\n", 232 | "414.circles\n", 233 | "414.edges\n", 234 | "686.circles\n", 235 | "686.edges\n", 236 | "698.circles\n", 237 | "698.edges\n", 238 | "" 239 | ] 240 | } 241 | ], 242 | "prompt_number": 12 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "metadata": {}, 247 | "source": [ 248 | "We save the `data/facebook/` directory as an alias for later. We will be able to enter this directory just with `cd fbdata`." 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "collapsed": false, 254 | "input": [ 255 | "%bookmark fbdata" 256 | ], 257 | "language": "python", 258 | "metadata": {}, 259 | "outputs": [], 260 | "prompt_number": 13 261 | } 262 | ], 263 | "metadata": {} 264 | } 265 | ] 266 | } -------------------------------------------------------------------------------- /chapter2/202-facebook-data-explore.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_02_02" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 2, example 2\n", 15 | "====================\n", 16 | "\n", 17 | "Here we continue with the previous example: we write some Python commands to list all files in the downloaded data. We also show how to execute external Python scripts in IPython using the magic command `%run`.\n", 18 | "\n", 19 | "The following code should be stored in `egos.py`:\n", 20 | "\n", 21 | " import sys\n", 22 | " import os\n", 23 | " # we retrieve the folder as the first positional argument\n", 24 | " # to the command-line call\n", 25 | " if len(sys.argv) > 1:\n", 26 | " folder = sys.argv[1]\n", 27 | " # we list all files in the specified folder\n", 28 | " files = os.listdir(folder)\n", 29 | " # ids contains the sorted list of all unique idenfitiers\n", 30 | " ids = sorted(set(map(lambda file: int(file.split('.')[0]), files)))\n" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "The `egos.py` script accepts the facebook folder's relative path as an argument, and extracts all file identifiers in an `ids` variable. Each file in the dataset has the form `ID.extension`." 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "collapsed": false, 43 | "input": [ 44 | "%run egos.py data/facebook" 45 | ], 46 | "language": "python", 47 | "metadata": {}, 48 | "outputs": [], 49 | "prompt_number": 1 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "After using the `%run` command to execute this script, all variables defined in the script are available in the current user namespace. In particular, we can retrieve the `ids` variable here." 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "collapsed": false, 61 | "input": [ 62 | "ids" 63 | ], 64 | "language": "python", 65 | "metadata": {}, 66 | "outputs": [ 67 | { 68 | "output_type": "pyout", 69 | "prompt_number": 2, 70 | "text": [ 71 | "[0, 107, 348, 414, 686, 698, 1684, 1912, 3437, 3980]" 72 | ] 73 | } 74 | ], 75 | "prompt_number": 2 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "Whereas output variables are available in the namespace *after* the script's execution, variables available in IPython *before* its execution are not available within the script by default. For example, here we define the `folder` variable in the current namespace, and we call `%run egos.py` without an argument." 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "collapsed": false, 87 | "input": [ 88 | "folder = 'data/facebook'" 89 | ], 90 | "language": "python", 91 | "metadata": {}, 92 | "outputs": [], 93 | "prompt_number": 3 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "A `NameError` exception is expected here, because the `folder` variable is not defined in the script, although it is defined in the current namespace." 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "collapsed": false, 105 | "input": [ 106 | "%run egos.py" 107 | ], 108 | "language": "python", 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "ename": "NameError", 113 | "evalue": "name 'folder' is not defined", 114 | "output_type": "pyerr", 115 | "traceback": [ 116 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", 117 | "\u001b[1;32mIPython\\utils\\py3compat.pyc\u001b[0m in \u001b[0;36mexecfile\u001b[1;34m(fname, glob, loc)\u001b[0m\n\u001b[0;32m 169\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 170\u001b[0m \u001b[0mfilename\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfname\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 171\u001b[1;33m \u001b[1;32mexec\u001b[0m \u001b[0mcompile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mscripttext\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'exec'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mglob\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mloc\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 172\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 173\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mexecfile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfname\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0mwhere\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 118 | "\u001b[1;32mchapter2\\egos.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[0mfolder\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0margv\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;31m# we list all files in the specified folder\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0mfiles\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlistdir\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfolder\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 9\u001b[0m \u001b[1;31m# ids contains the sorted list of all unique idenfitiers\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[0mids\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msorted\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmap\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mfile\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfile\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msplit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'.'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfiles\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 119 | "\u001b[1;31mNameError\u001b[0m: name 'folder' is not defined" 120 | ] 121 | } 122 | ], 123 | "prompt_number": 4 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "metadata": {}, 128 | "source": [ 129 | "However, we can tell IPython *explicitely* to use the current user namespace for the external script's execution with the `-i` option." 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "collapsed": false, 135 | "input": [ 136 | "%run -i egos.py" 137 | ], 138 | "language": "python", 139 | "metadata": {}, 140 | "outputs": [], 141 | "prompt_number": 5 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "Now the script's execution works as expected, and the `ids` variable is available." 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "collapsed": false, 153 | "input": [ 154 | "ids" 155 | ], 156 | "language": "python", 157 | "metadata": {}, 158 | "outputs": [ 159 | { 160 | "output_type": "pyout", 161 | "prompt_number": 6, 162 | "text": [ 163 | "[0, 107, 348, 414, 686, 698, 1684, 1912, 3437, 3980]" 164 | ] 165 | } 166 | ], 167 | "prompt_number": 6 168 | } 169 | ], 170 | "metadata": {} 171 | } 172 | ] 173 | } -------------------------------------------------------------------------------- /chapter2/center.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | g = nx.read_edgelist('data/facebook/0.edges') 3 | sg = nx.connected_component_subgraphs(g)[0] 4 | center = [node for node in sg.nodes() if nx.eccentricity(sg, node) == nx.radius(sg)] 5 | print(center) 6 | -------------------------------------------------------------------------------- /chapter2/center2.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | g = nx.read_edgelist('data/facebook/0.edges') 3 | sg = nx.connected_component_subgraphs(g)[0] 4 | # we compute the eccentricity once, for all nodes 5 | ecc = nx.eccentricity(sg) 6 | # we compute the radius once 7 | r = nx.radius(sg) 8 | center = [node for node in sg.nodes() if ecc[node] == r] 9 | print(center) 10 | -------------------------------------------------------------------------------- /chapter2/egos.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | # we retrieve the folder as the first positional argument 4 | # to the command-line call 5 | if len(sys.argv) > 1: 6 | folder = sys.argv[1] 7 | # we list all files in the specified folder 8 | files = os.listdir(folder) 9 | # ids contains the sorted list of all unique idenfitiers 10 | ids = sorted(set(map(lambda file: int(file.split('.')[0]), files))) 11 | -------------------------------------------------------------------------------- /chapter3/301-vector-computations.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_03_01" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 3, example 1\n", 15 | "====================\n", 16 | "\n", 17 | "We illustrate the notion of array computation with a simple example consisting of finding, among a large list of locations, the closest one from a position of interest." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "## Pure Python version\n", 25 | "\n", 26 | "The pure Python version loops through all positions, computes the distance from the position of interest, and returns the index of the closest location." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "collapsed": false, 32 | "input": [ 33 | "def closest(position, positions):\n", 34 | " x0, y0 = position\n", 35 | " dbest, ibest = None, None\n", 36 | " for i, (x, y) in enumerate(positions):\n", 37 | " d = (x - x0) ** 2 + (y - y0) ** 2\n", 38 | " if dbest is None or d < dbest:\n", 39 | " dbest, ibest = d, i\n", 40 | " return ibest\n", 41 | "import random" 42 | ], 43 | "language": "python", 44 | "metadata": {}, 45 | "outputs": [], 46 | "prompt_number": 1 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "We generate a list of random positions." 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "collapsed": false, 58 | "input": [ 59 | "positions = [(random.random(), random.random()) for _ in xrange(10000000)]" 60 | ], 61 | "language": "python", 62 | "metadata": {}, 63 | "outputs": [], 64 | "prompt_number": 2 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "Now we evaluate the time required to compute the closest position from `(0.5, 0.5)`." 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "collapsed": false, 76 | "input": [ 77 | "%timeit closest((.5, .5), positions)" 78 | ], 79 | "language": "python", 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "output_type": "stream", 84 | "stream": "stdout", 85 | "text": [ 86 | "1 loops, best of 3: 12.8 s per loop\n" 87 | ] 88 | } 89 | ], 90 | "prompt_number": 3 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "## Vectorized version\n", 97 | "\n", 98 | "This version uses NumPy to compute all distances in a vectorized way, without using Python loops. This version is far more efficient than the pure Python version." 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "First, we need to activate the pylab mode so that NumPy is loaded and the NumPy objects are available in the current namespace." 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "collapsed": false, 111 | "input": [ 112 | "%pylab" 113 | ], 114 | "language": "python", 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "output_type": "stream", 119 | "stream": "stdout", 120 | "text": [ 121 | "\n", 122 | "Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].\n", 123 | "For more information, type 'help(pylab)'.\n" 124 | ] 125 | } 126 | ], 127 | "prompt_number": 4 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "Generating random positions with NumPy's `rand` function is much faster than using a list." 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "collapsed": false, 139 | "input": [ 140 | "positions = rand(10000000, 2)" 141 | ], 142 | "language": "python", 143 | "metadata": {}, 144 | "outputs": [], 145 | "prompt_number": 5 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "`positions` is a NumPy `ndarray` object." 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "collapsed": false, 157 | "input": [ 158 | "type(positions)" 159 | ], 160 | "language": "python", 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "output_type": "pyout", 165 | "prompt_number": 6, 166 | "text": [ 167 | "numpy.ndarray" 168 | ] 169 | } 170 | ], 171 | "prompt_number": 6 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "It has two dimensions and a shape of `(10000000, 2)`." 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "collapsed": false, 183 | "input": [ 184 | "positions.ndim, positions.shape" 185 | ], 186 | "language": "python", 187 | "metadata": {}, 188 | "outputs": [ 189 | { 190 | "output_type": "pyout", 191 | "prompt_number": 7, 192 | "text": [ 193 | "(2, (10000000, 2))" 194 | ] 195 | } 196 | ], 197 | "prompt_number": 7 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": {}, 202 | "source": [ 203 | "We can easily get the columns of this matrix, which contain here the x and y coordinates of all positions." 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "collapsed": false, 209 | "input": [ 210 | "x, y = positions[:,0], positions[:,1]" 211 | ], 212 | "language": "python", 213 | "metadata": {}, 214 | "outputs": [], 215 | "prompt_number": 8 216 | }, 217 | { 218 | "cell_type": "markdown", 219 | "metadata": {}, 220 | "source": [ 221 | "Now we compute the distances in a vectorized fashion, which is much more efficient than with a Python loop." 222 | ] 223 | }, 224 | { 225 | "cell_type": "code", 226 | "collapsed": false, 227 | "input": [ 228 | "distances = (x - .5) ** 2 + (y - .5) ** 2" 229 | ], 230 | "language": "python", 231 | "metadata": {}, 232 | "outputs": [], 233 | "prompt_number": 9 234 | }, 235 | { 236 | "cell_type": "code", 237 | "collapsed": false, 238 | "input": [ 239 | "%timeit exec In[9]" 240 | ], 241 | "language": "python", 242 | "metadata": {}, 243 | "outputs": [ 244 | { 245 | "output_type": "stream", 246 | "stream": "stdout", 247 | "text": [ 248 | "1 loops, best of 3: 341 ms per loop\n" 249 | ] 250 | } 251 | ], 252 | "prompt_number": 10 253 | }, 254 | { 255 | "cell_type": "code", 256 | "collapsed": false, 257 | "input": [ 258 | "%timeit ibest = distances.argmin()" 259 | ], 260 | "language": "python", 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "output_type": "stream", 265 | "stream": "stdout", 266 | "text": [ 267 | "10 loops, best of 3: 24.2 ms per loop\n" 268 | ] 269 | } 270 | ], 271 | "prompt_number": 11 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "Using NumPy is about 35 times faster than using pure Python code here." 278 | ] 279 | } 280 | ], 281 | "metadata": {} 282 | } 283 | ] 284 | } -------------------------------------------------------------------------------- /chapter3/302-multiplication-tables.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_03_02" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 3, example 2\n", 15 | "====================\n", 16 | "\n", 17 | "This example shows three different ways of creating multiplication tables:\n", 18 | "\n", 19 | " * one method in pure Python,\n", 20 | " * one method using NumPy,\n", 21 | " * one optimized method using NumPy." 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Version 1: Pure Python version\n", 29 | "\n", 30 | "This version uses list comprehensions." 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "collapsed": false, 36 | "input": [ 37 | "def mul1(n):\n", 38 | " return array([[(i + 1) * (j + 1) for i in xrange(n)] for j in xrange(n)])" 39 | ], 40 | "language": "python", 41 | "metadata": {}, 42 | "outputs": [], 43 | "prompt_number": 1 44 | }, 45 | { 46 | "cell_type": "code", 47 | "collapsed": false, 48 | "input": [ 49 | "mul1(4)" 50 | ], 51 | "language": "python", 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "output_type": "pyout", 56 | "prompt_number": 2, 57 | "text": [ 58 | "array([[ 1, 2, 3, 4],\n", 59 | " [ 2, 4, 6, 8],\n", 60 | " [ 3, 6, 9, 12],\n", 61 | " [ 4, 8, 12, 16]])" 62 | ] 63 | } 64 | ], 65 | "prompt_number": 2 66 | }, 67 | { 68 | "cell_type": "code", 69 | "collapsed": false, 70 | "input": [ 71 | "timeit mul1(100)" 72 | ], 73 | "language": "python", 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "output_type": "stream", 78 | "stream": "stdout", 79 | "text": [ 80 | "100 loops, best of 3: 5.24 ms per loop\n" 81 | ] 82 | } 83 | ], 84 | "prompt_number": 3 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "## Version 2: NumPy version\n", 91 | "\n", 92 | "This version uses array manipulation and operations." 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "collapsed": false, 98 | "input": [ 99 | "def mul2(n):\n", 100 | " M = arange(1, n + 1).reshape((-1, 1))\n", 101 | " M = tile(M, (1, n))\n", 102 | " N = arange(1, n + 1).reshape((1, -1))\n", 103 | " N = tile(N, (n, 1))\n", 104 | " return M * N" 105 | ], 106 | "language": "python", 107 | "metadata": {}, 108 | "outputs": [], 109 | "prompt_number": 4 110 | }, 111 | { 112 | "cell_type": "code", 113 | "collapsed": false, 114 | "input": [ 115 | "mul2(4)" 116 | ], 117 | "language": "python", 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "output_type": "pyout", 122 | "prompt_number": 5, 123 | "text": [ 124 | "array([[ 1, 2, 3, 4],\n", 125 | " [ 2, 4, 6, 8],\n", 126 | " [ 3, 6, 9, 12],\n", 127 | " [ 4, 8, 12, 16]])" 128 | ] 129 | } 130 | ], 131 | "prompt_number": 5 132 | }, 133 | { 134 | "cell_type": "code", 135 | "collapsed": false, 136 | "input": [ 137 | "timeit mul2(100)" 138 | ], 139 | "language": "python", 140 | "metadata": {}, 141 | "outputs": [ 142 | { 143 | "output_type": "stream", 144 | "stream": "stdout", 145 | "text": [ 146 | "1000 loops, best of 3: 251 us per loop\n" 147 | ] 148 | } 149 | ], 150 | "prompt_number": 6 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "Using NumPy is about 20 times faster here." 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "## Version 3: Optimized NumPy version\n", 164 | "\n", 165 | "This version is an optimized version of the previous example, using broadcasting instead of unnecessary array tiling." 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "collapsed": false, 171 | "input": [ 172 | "def mul3(n):\n", 173 | " M = arange(1, n + 1).reshape((-1, 1))\n", 174 | " N = arange(1, n + 1).reshape((1, -1))\n", 175 | " return M * N" 176 | ], 177 | "language": "python", 178 | "metadata": {}, 179 | "outputs": [], 180 | "prompt_number": 7 181 | }, 182 | { 183 | "cell_type": "code", 184 | "collapsed": false, 185 | "input": [ 186 | "mul3(4)" 187 | ], 188 | "language": "python", 189 | "metadata": {}, 190 | "outputs": [ 191 | { 192 | "output_type": "pyout", 193 | "prompt_number": 8, 194 | "text": [ 195 | "array([[ 1, 2, 3, 4],\n", 196 | " [ 2, 4, 6, 8],\n", 197 | " [ 3, 6, 9, 12],\n", 198 | " [ 4, 8, 12, 16]])" 199 | ] 200 | } 201 | ], 202 | "prompt_number": 8 203 | }, 204 | { 205 | "cell_type": "code", 206 | "collapsed": false, 207 | "input": [ 208 | "timeit mul3(100)" 209 | ], 210 | "language": "python", 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "output_type": "stream", 215 | "stream": "stdout", 216 | "text": [ 217 | "10000 loops, best of 3: 88.3 us per loop\n" 218 | ] 219 | } 220 | ], 221 | "prompt_number": 9 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "This optimized version is about 60 times faster than the original Python version." 228 | ] 229 | } 230 | ], 231 | "metadata": {} 232 | } 233 | ] 234 | } -------------------------------------------------------------------------------- /chapter3/303-cities-data-explore.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_03_03" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 3, example 3\n", 15 | "====================\n", 16 | "\n", 17 | "In this example, we will download and analyze some data about a large number of cities around the world and their population. This data has been created by MaxMind and is available for free at http://www.maxmind.com.\n", 18 | "\n", 19 | "We first download the Zip file and uncompress it in a folder. The Zip file is about 40MB so that downloading it may take a while." 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "collapsed": true, 25 | "input": [ 26 | "import urllib2, zipfile" 27 | ], 28 | "language": "python", 29 | "metadata": {}, 30 | "outputs": [], 31 | "prompt_number": 1 32 | }, 33 | { 34 | "cell_type": "code", 35 | "collapsed": false, 36 | "input": [ 37 | "url = 'http://ipython.rossant.net/'" 38 | ], 39 | "language": "python", 40 | "metadata": {}, 41 | "outputs": [], 42 | "prompt_number": 2 43 | }, 44 | { 45 | "cell_type": "code", 46 | "collapsed": false, 47 | "input": [ 48 | "filename = 'cities.zip'" 49 | ], 50 | "language": "python", 51 | "metadata": {}, 52 | "outputs": [], 53 | "prompt_number": 3 54 | }, 55 | { 56 | "cell_type": "code", 57 | "collapsed": false, 58 | "input": [ 59 | "downloaded = urllib2.urlopen(url + filename)" 60 | ], 61 | "language": "python", 62 | "metadata": {}, 63 | "outputs": [], 64 | "prompt_number": 4 65 | }, 66 | { 67 | "cell_type": "code", 68 | "collapsed": false, 69 | "input": [ 70 | "folder = 'data'" 71 | ], 72 | "language": "python", 73 | "metadata": {}, 74 | "outputs": [], 75 | "prompt_number": 5 76 | }, 77 | { 78 | "cell_type": "code", 79 | "collapsed": false, 80 | "input": [ 81 | "mkdir data" 82 | ], 83 | "language": "python", 84 | "metadata": {}, 85 | "outputs": [], 86 | "prompt_number": 6 87 | }, 88 | { 89 | "cell_type": "code", 90 | "collapsed": false, 91 | "input": [ 92 | "with open(filename, 'wb') as f:\n", 93 | " f.write(downloaded.read())" 94 | ], 95 | "language": "python", 96 | "metadata": {}, 97 | "outputs": [], 98 | "prompt_number": 7 99 | }, 100 | { 101 | "cell_type": "code", 102 | "collapsed": false, 103 | "input": [ 104 | "with zipfile.ZipFile(filename) as zip:\n", 105 | " zip.extractall(folder)" 106 | ], 107 | "language": "python", 108 | "metadata": {}, 109 | "outputs": [], 110 | "prompt_number": 8 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "Now, we're going to load the CSV file that has been extracted with Pandas. The `read_csv` function of Pandas can open any CSV file." 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "collapsed": false, 122 | "input": [ 123 | "import pandas as pd" 124 | ], 125 | "language": "python", 126 | "metadata": {}, 127 | "outputs": [], 128 | "prompt_number": 9 129 | }, 130 | { 131 | "cell_type": "code", 132 | "collapsed": false, 133 | "input": [ 134 | "filename = 'data/worldcitiespop.txt'" 135 | ], 136 | "language": "python", 137 | "metadata": {}, 138 | "outputs": [], 139 | "prompt_number": 10 140 | }, 141 | { 142 | "cell_type": "code", 143 | "collapsed": false, 144 | "input": [ 145 | "data = pd.read_csv(filename)" 146 | ], 147 | "language": "python", 148 | "metadata": {}, 149 | "outputs": [], 150 | "prompt_number": 11 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "Now, let's explore the newly created data object." 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "collapsed": false, 162 | "input": [ 163 | "type(data)" 164 | ], 165 | "language": "python", 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "output_type": "pyout", 170 | "prompt_number": 12, 171 | "text": [ 172 | "pandas.core.frame.DataFrame" 173 | ] 174 | } 175 | ], 176 | "prompt_number": 12 177 | }, 178 | { 179 | "cell_type": "markdown", 180 | "metadata": {}, 181 | "source": [ 182 | "The data object is a DataFrame, a Pandas type consisting of a two-dimensional labeled data structure with columns of potentially different types (like a Excel spreadsheet). Like a NumPy array, the shape attribute returns the shape of the table. But unlike NumPy, the DataFrame object has a richer structure, and in particular the keys methods returns the names of the different columns." 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "collapsed": false, 188 | "input": [ 189 | "data.shape, data.keys()" 190 | ], 191 | "language": "python", 192 | "metadata": {}, 193 | "outputs": [ 194 | { 195 | "output_type": "pyout", 196 | "prompt_number": 13, 197 | "text": [ 198 | "((3173958, 7),\n", 199 | " Index([Country, City, AccentCity, Region, Population, Latitude, Longitude], dtype=object))" 200 | ] 201 | } 202 | ], 203 | "prompt_number": 13 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "We can see that data has more than 3 million lines, and seven columns including the country, city, population and GPS coordinates of each city. The head and tail methods allow to take a quick look to the beginning and the end of the table, respectively." 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "collapsed": false, 215 | "input": [ 216 | "data.tail()" 217 | ], 218 | "language": "python", 219 | "metadata": {}, 220 | "outputs": [ 221 | { 222 | "html": [ 223 | "
\n", 224 | "\n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | "
CountryCityAccentCityRegionPopulationLatitudeLongitude
3173953 zw zimre park Zimre Park 4 NaN-17.866111 31.213611
3173954 zw ziyakamanas Ziyakamanas 0 NaN-18.216667 27.950000
3173955 zw zizalisari Zizalisari 4 NaN-17.758889 31.010556
3173956 zw zuzumba Zuzumba 6 NaN-20.033333 27.933333
3173957 zw zvishavane Zvishavane 7 79876-20.333333 30.033333
\n", 290 | "
" 291 | ], 292 | "output_type": "pyout", 293 | "prompt_number": 14, 294 | "text": [ 295 | " Country City AccentCity Region Population Latitude Longitude\n", 296 | "3173953 zw zimre park Zimre Park 4 NaN -17.866111 31.213611\n", 297 | "3173954 zw ziyakamanas Ziyakamanas 0 NaN -18.216667 27.950000\n", 298 | "3173955 zw zizalisari Zizalisari 4 NaN -17.758889 31.010556\n", 299 | "3173956 zw zuzumba Zuzumba 6 NaN -20.033333 27.933333\n", 300 | "3173957 zw zvishavane Zvishavane 7 79876 -20.333333 30.033333" 301 | ] 302 | } 303 | ], 304 | "prompt_number": 14 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "metadata": {}, 309 | "source": [ 310 | "We can see that these cities have NaN values as populations. The reason is that the population is not available for all cities in the data set, and Pandas handles those missing values transparently.\n", 311 | "\n", 312 | "We'll see in the next sections what we can actually do with these data." 313 | ] 314 | }, 315 | { 316 | "cell_type": "markdown", 317 | "metadata": {}, 318 | "source": [ 319 | "Each column of the DataFrame object can be accessed with its name. In IPython, tab completion proposes notably the different columns as attributes of the object. Here we get the series with the names of all cities (AccentCity is the full name of the city, with uppercase characters and accents)." 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "collapsed": false, 325 | "input": [ 326 | "data.AccentCity" 327 | ], 328 | "language": "python", 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "output_type": "pyout", 333 | "prompt_number": 15, 334 | "text": [ 335 | "0 Aix\ufffds\n", 336 | "1 Aixirivali\n", 337 | "2 Aixirivall\n", 338 | "3 Aixirvall\n", 339 | "4 Aixovall\n", 340 | "5 Andorra\n", 341 | "6 Andorra la Vella\n", 342 | "7 Andorra-Vieille\n", 343 | "8 Andorre\n", 344 | "9 Andorre-la-Vieille\n", 345 | "10 Andorre-Vieille\n", 346 | "11 Ansalonga\n", 347 | "12 Any\ufffds\n", 348 | "13 Arans\n", 349 | "14 Arinsal\n", 350 | "...\n", 351 | "3173943 Zandi\n", 352 | "3173944 Zanyika\n", 353 | "3173945 Zemalapala\n", 354 | "3173946 Zemandana\n", 355 | "3173947 Zemanda\n", 356 | "3173948 Zibalonkwe\n", 357 | "3173949 Zibunkululu\n", 358 | "3173950 Ziga\n", 359 | "3173951 Zikamanas Village\n", 360 | "3173952 Zimbabwe\n", 361 | "3173953 Zimre Park\n", 362 | "3173954 Ziyakamanas\n", 363 | "3173955 Zizalisari\n", 364 | "3173956 Zuzumba\n", 365 | "3173957 Zvishavane\n", 366 | "Name: AccentCity, Length: 3173958" 367 | ] 368 | } 369 | ], 370 | "prompt_number": 15 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "This column is an instance of the Series class. We can access to certain rows using indexing. In the following example, we get the name 30000th city (knowing that indexing is 0-based):" 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "collapsed": false, 382 | "input": [ 383 | "data.AccentCity[30000]" 384 | ], 385 | "language": "python", 386 | "metadata": {}, 387 | "outputs": [ 388 | { 389 | "output_type": "pyout", 390 | "prompt_number": 16, 391 | "text": [ 392 | "'Howasiyan'" 393 | ] 394 | } 395 | ], 396 | "prompt_number": 16 397 | }, 398 | { 399 | "cell_type": "markdown", 400 | "metadata": {}, 401 | "source": [ 402 | "So we can access to an element knowing its index. But how can we obtain a city from its name? For example, we'd like to obtain the population and GPS coordinates of New York. A possibility might be to loop through all cities and check their names, but it would be extremely slow because Python loops on millions on elements are not optimized at all. Pandas and NumPy offer a much more elegant and efficient way called boolean indexing. There are two steps that typically occur on the same line of code. First, we create an array with boolean values indicating, for each element, whether it satisfies a condition or not (if, whether the city name is New York). Then, we pass this array of booleans as an index to our original array: the result is then a subpart of the full array with only the elements corresponding to True. For example:" 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "collapsed": false, 408 | "input": [ 409 | "data[data.AccentCity=='New York']," 410 | ], 411 | "language": "python", 412 | "metadata": {}, 413 | "outputs": [ 414 | { 415 | "output_type": "pyout", 416 | "prompt_number": 17, 417 | "text": [ 418 | "( Country City AccentCity Region Population Latitude Longitude\n", 419 | "998166 gb new york New York H7 NaN 53.083333 -0.150000\n", 420 | "1087431 hn new york New York 16 NaN 14.800000 -88.366667\n", 421 | "1525856 jm new york New York 9 NaN 18.250000 -77.183333\n", 422 | "1525857 jm new york New York 10 NaN 18.116667 -77.133333\n", 423 | "1893972 mx new york New York 5 NaN 16.266667 -93.233333\n", 424 | "2929399 us new york New York FL NaN 30.838333 -87.200833\n", 425 | "2946036 us new york New York IA NaN 40.851667 -93.259722\n", 426 | "2951120 us new york New York KY NaN 36.988889 -88.952500\n", 427 | "2977571 us new york New York MO NaN 39.685278 -93.926667\n", 428 | "2986561 us new york New York NM NaN 35.058611 -107.526667\n", 429 | "2990572 us new york New York NY 8107916 40.714167 -74.006389\n", 430 | "3029084 us new york New York TX NaN 32.167778 -95.668889,)" 431 | ] 432 | } 433 | ], 434 | "prompt_number": 17 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "metadata": {}, 439 | "source": [ 440 | "The same syntax works in NumPy and Pandas. Here, we find a dozen of cities named New York, but only one happens to be in the New York state. To access a single element with Pandas, we can use the .ix attribute (for index):" 441 | ] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "collapsed": false, 446 | "input": [ 447 | "ny = 2990572\n", 448 | "data.ix[ny]" 449 | ], 450 | "language": "python", 451 | "metadata": {}, 452 | "outputs": [ 453 | { 454 | "output_type": "pyout", 455 | "prompt_number": 18, 456 | "text": [ 457 | "Country us\n", 458 | "City new york\n", 459 | "AccentCity New York\n", 460 | "Region NY\n", 461 | "Population 8107916\n", 462 | "Latitude 40.71417\n", 463 | "Longitude -74.00639\n", 464 | "Name: 2990572" 465 | ] 466 | } 467 | ], 468 | "prompt_number": 18 469 | }, 470 | { 471 | "cell_type": "markdown", 472 | "metadata": {}, 473 | "source": [ 474 | "Now, let's turn this Series object into a pure NumPy array. We go from the Pandas world to NumPy (keeping in mind that Pandas is built on top of NumPy). We'll mostly work with the population count of all cities." 475 | ] 476 | }, 477 | { 478 | "cell_type": "code", 479 | "collapsed": false, 480 | "input": [ 481 | "population = array(data.Population)" 482 | ], 483 | "language": "python", 484 | "metadata": {}, 485 | "outputs": [], 486 | "prompt_number": 19 487 | }, 488 | { 489 | "cell_type": "code", 490 | "collapsed": false, 491 | "input": [ 492 | "population.shape" 493 | ], 494 | "language": "python", 495 | "metadata": {}, 496 | "outputs": [ 497 | { 498 | "output_type": "pyout", 499 | "prompt_number": 20, 500 | "text": [ 501 | "(3173958,)" 502 | ] 503 | } 504 | ], 505 | "prompt_number": 20 506 | }, 507 | { 508 | "cell_type": "markdown", 509 | "metadata": {}, 510 | "source": [ 511 | "The population array is a one-dimensional vector with the populations of all cities (or NaN if the population is not available). The population of New York can be accessed in NumPy with basic indexing:" 512 | ] 513 | }, 514 | { 515 | "cell_type": "code", 516 | "collapsed": false, 517 | "input": [ 518 | "population[ny]" 519 | ], 520 | "language": "python", 521 | "metadata": {}, 522 | "outputs": [ 523 | { 524 | "output_type": "pyout", 525 | "prompt_number": 21, 526 | "text": [ 527 | "8107916.0" 528 | ] 529 | } 530 | ], 531 | "prompt_number": 21 532 | }, 533 | { 534 | "cell_type": "markdown", 535 | "metadata": {}, 536 | "source": [ 537 | "Let's find out how many cities do have an actual population count. To do this, we'll select all elements in the population array that have a value different to NaN. We can use the NumPy function isnan:" 538 | ] 539 | }, 540 | { 541 | "cell_type": "code", 542 | "collapsed": false, 543 | "input": [ 544 | "isnan(population)" 545 | ], 546 | "language": "python", 547 | "metadata": {}, 548 | "outputs": [ 549 | { 550 | "output_type": "pyout", 551 | "prompt_number": 22, 552 | "text": [ 553 | "array([ True, True, True, ..., True, True, False], dtype=bool)" 554 | ] 555 | } 556 | ], 557 | "prompt_number": 22 558 | }, 559 | { 560 | "cell_type": "code", 561 | "collapsed": false, 562 | "input": [ 563 | "x = population[~_]\n", 564 | "len(x), len(x) / float(len(population))" 565 | ], 566 | "language": "python", 567 | "metadata": {}, 568 | "outputs": [ 569 | { 570 | "output_type": "pyout", 571 | "prompt_number": 23, 572 | "text": [ 573 | "(47980, 0.015116772181610469)" 574 | ] 575 | } 576 | ], 577 | "prompt_number": 23 578 | }, 579 | { 580 | "cell_type": "markdown", 581 | "metadata": {}, 582 | "source": [ 583 | "There are about 1.5% of all cities in this data set that have a population count." 584 | ] 585 | }, 586 | { 587 | "cell_type": "markdown", 588 | "metadata": {}, 589 | "source": [ 590 | "Let's explore now some statistics on the cities population." 591 | ] 592 | }, 593 | { 594 | "cell_type": "code", 595 | "collapsed": false, 596 | "input": [ 597 | "x.mean()" 598 | ], 599 | "language": "python", 600 | "metadata": {}, 601 | "outputs": [ 602 | { 603 | "output_type": "pyout", 604 | "prompt_number": 24, 605 | "text": [ 606 | "47719.57063359733" 607 | ] 608 | } 609 | ], 610 | "prompt_number": 24 611 | }, 612 | { 613 | "cell_type": "code", 614 | "collapsed": false, 615 | "input": [ 616 | "x.sum() / 1e9" 617 | ], 618 | "language": "python", 619 | "metadata": {}, 620 | "outputs": [ 621 | { 622 | "output_type": "pyout", 623 | "prompt_number": 25, 624 | "text": [ 625 | "2.2895849990000001" 626 | ] 627 | } 628 | ], 629 | "prompt_number": 25 630 | }, 631 | { 632 | "cell_type": "code", 633 | "collapsed": false, 634 | "input": [ 635 | "len(x)/float(len(population))" 636 | ], 637 | "language": "python", 638 | "metadata": {}, 639 | "outputs": [ 640 | { 641 | "output_type": "pyout", 642 | "prompt_number": 26, 643 | "text": [ 644 | "0.015116772181610469" 645 | ] 646 | } 647 | ], 648 | "prompt_number": 26 649 | }, 650 | { 651 | "cell_type": "markdown", 652 | "metadata": {}, 653 | "source": [ 654 | "The total population of those cities is about 2.3 billion people, about a third of the current world population. Hence, according to this data set, roughly 30% of the population lives in less than 1.5% of the cities in the world!" 655 | ] 656 | }, 657 | { 658 | "cell_type": "code", 659 | "collapsed": false, 660 | "input": [ 661 | "data.Population.describe()" 662 | ], 663 | "language": "python", 664 | "metadata": {}, 665 | "outputs": [ 666 | { 667 | "output_type": "pyout", 668 | "prompt_number": 27, 669 | "text": [ 670 | "count 47980.000000\n", 671 | "mean 47719.570634\n", 672 | "std 302888.715626\n", 673 | "min 7.000000\n", 674 | "25% 3732.000000\n", 675 | "50% 10779.000000\n", 676 | "75% 27990.500000\n", 677 | "max 31480498.000000" 678 | ] 679 | } 680 | ], 681 | "prompt_number": 27 682 | }, 683 | { 684 | "cell_type": "markdown", 685 | "metadata": {}, 686 | "source": [ 687 | "Now, let's locate some geographical coordinates." 688 | ] 689 | }, 690 | { 691 | "cell_type": "code", 692 | "collapsed": false, 693 | "input": [ 694 | "locations = data[['Latitude','Longitude']].as_matrix()" 695 | ], 696 | "language": "python", 697 | "metadata": {}, 698 | "outputs": [], 699 | "prompt_number": 28 700 | }, 701 | { 702 | "cell_type": "code", 703 | "collapsed": false, 704 | "input": [ 705 | "def locate(x, y):\n", 706 | " d = locations - array([x, y])\n", 707 | " distances = d[:,0] ** 2 + d[:,1] ** 2\n", 708 | " closest = distances.argmin()\n", 709 | " return data.AccentCity[closest]" 710 | ], 711 | "language": "python", 712 | "metadata": {}, 713 | "outputs": [], 714 | "prompt_number": 29 715 | }, 716 | { 717 | "cell_type": "code", 718 | "collapsed": false, 719 | "input": [ 720 | "print(locate(48.861, 2.3358))" 721 | ], 722 | "language": "python", 723 | "metadata": {}, 724 | "outputs": [ 725 | { 726 | "output_type": "stream", 727 | "stream": "stdout", 728 | "text": [ 729 | "Paris\n" 730 | ] 731 | } 732 | ], 733 | "prompt_number": 30 734 | } 735 | ], 736 | "metadata": {} 737 | } 738 | ] 739 | } -------------------------------------------------------------------------------- /chapter4/401-matplotlib-intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_04_01" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 4, example 1\n", 15 | "====================\n", 16 | "\n", 17 | "Here, we show basic plotting examples with Matplotlib." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "We first plot a white noise signal, consisting of independent normal random values." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "collapsed": false, 30 | "input": [ 31 | "y = randn(1000)" 32 | ], 33 | "language": "python", 34 | "metadata": {}, 35 | "outputs": [], 36 | "prompt_number": 1 37 | }, 38 | { 39 | "cell_type": "code", 40 | "collapsed": false, 41 | "input": [ 42 | "plot(y)" 43 | ], 44 | "language": "python", 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "output_type": "pyout", 49 | "prompt_number": 2, 50 | "text": [ 51 | "[]" 52 | ] 53 | }, 54 | { 55 | "output_type": "display_data", 56 | "png": "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\nIqH/yU9+grvuuiutsng8Ho8nA3JBEARxDnz++edRU1OD++67D926dcObb76Jdu3aRRPP5VIppMfj\n8TQ3YkqzlJa6H6urq7Fx48a87RMmTMCkSZMwd+5cbaHSLKjH4/F44hHLol+xYgWGDh2KNm3aAADW\nrVuHzp0744033kCHDh1SL6TH4/F44hPbdUNRuW48Ho/HU3xSiaP3vniPx+MpXVIR+g8//DDPmp8z\nZw569+6Nnj174s4770wjm5KmtrYWp556Kvr164f+/ftj6tSpAIBNmzahuroavXr1whlnnIHNmzfv\nPmbSpEno2bMnevfuHenvKBcaGhowePBgjBgxAkDzrYvNmzdj1KhR6NOnD/r27YslS5Y027qYNGkS\n+vXrhwEDBmDMmDHYuXNns6mLyy67DB07dsSAAQN2b4tz7m+++SYGDBiAnj174rrrrrPLPMiA+vr6\noHv37sGaNWuCurq6YODAgcGqVauyyKpk+OSTT4Lly5cHQRAEX3/9ddCrV69g1apVwU033RTceeed\nQRAEweTJk4Obb745CIIgWLlyZTBw4MCgrq4uWLNmTdC9e/egoaGhaOXPgnvuuScYM2ZMMGLEiCAI\ngmZbF5dcckkwbdq0IAiCYNeuXcHmzZubZV2sWbMm6NatW7Bjx44gCILgggsuCB577LFmUxevvPJK\nsGzZsqB///67t7mce2NjYxAEQXDMMccES5YsCYIgCIYPHx7Mnj3bmHcmQv/6668Hw4YN2/190qRJ\nwaRJk7LIqmQ599xzg3nz5gWHH354sHHjxiAI2MPg8MMPD4IgCCZOnBhMnjx59/7Dhg0LFi1aVJSy\nZkFtbW0wdOjQ4OWXXw7OPvvsIAiCZlkXmzdvDrp165a3vTnWxRdffBH06tUr2LRpU7Br167g7LPP\nDubOndus6mLNmjURoXc99w0bNgS9e/fevf2pp54KrrzySmO+mcx1s379enTt2nX39y5dumD9+vVZ\nZFWSrF27FsuXL8eQIUPw6aefomPHjgCAjh074tNPPwUAbNiwAV26dNl9TLnV0Q033IC7774bFRVh\nE2uOdbFmzRq0b98el156KY488khcccUV2LZtW7Osi3bt2uHGG2/EIYccgoMPPhj77bcfqqurm2Vd\ncFzPXdzeuXNnqzrJROibc+fs1q1bcf7552PKlCnYe++9I7/lcjlt3ZRLvc2aNQsdOnTA4MGDlWMp\nmktd1NfXY9myZbj66quxbNky7LXXXpg8eXJkn+ZSFx988AF+9atfYe3atdiwYQO2bt2KJ554IrJP\nc6kLGaZzT0ImQt+5c2fU1tbu/l5bWxt5CpUru3btwvnnn49x48bhu9/9LgD2lOaDzj755JPd4wzE\nOuJjEcqB119/HTNnzkS3bt0wevRovPzyyxg3blyzrIsuXbqgS5cuOOaYYwAAo0aNwrJly9CpU6dm\nVxdLly7FCSecgAMOOAAtW7bEeeedh0WLFjXLuuC43BNdunRB586dsW7dush2mzrJROiPPvporF69\nGmvXrkVdXR1+//vf45xzzskiq5IhCAJcfvnl6Nu3L66//vrd28855xw8/vjjAIDHH3989wPgnHPO\nwdNPP426ujqsWbMGq1evxrHHHluUsqfNxIkTUVtbizVr1uDpp5/GaaedhunTpzfLuujUqRO6du2K\nv//97wCA+fPno1+/fhgxYkSzq4vevXtj8eLF2L59O4IgwPz589G3b99mWRcc13uiU6dO2GeffbBk\nyRIEQYDp06fvPkZLGh0MMl544YWgV69eQffu3YOJEydmlU3JsHDhwiCXywUDBw4MBg0aFAwaNCiY\nPXt28MUXXwRDhw4NevbsGVRXVwdffvnl7mMmTJgQdO/ePTj88MODOXPmFLH02VFTU7M76qa51sVb\nb70VHH300cERRxwRjBw5Mti8eXOzrYs777wz6Nu3b9C/f//gkksuCerq6ppNXVx00UXBQQcdFFRW\nVgZdunQJfvOb38Q696VLlwb9+/cPunfvHlx77bVWeacyMtbj8Xg8pYtfYcrj8XjKHC/0Ho/HU+Z4\nofd4PJ4yxwu9x+PxlDle6D0ej6fM8ULv8Xg8Zc7/BwKvEhrWpcFbAAAAAElFTkSuQmCC\n", 57 | "text": [ 58 | "" 59 | ] 60 | } 61 | ], 62 | "prompt_number": 2 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "We can also specify the x values, which just changes the x axis here." 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "collapsed": false, 74 | "input": [ 75 | "x = linspace(0., 1., 1000)" 76 | ], 77 | "language": "python", 78 | "metadata": {}, 79 | "outputs": [], 80 | "prompt_number": 3 81 | }, 82 | { 83 | "cell_type": "code", 84 | "collapsed": false, 85 | "input": [ 86 | "plot(x, y)" 87 | ], 88 | "language": "python", 89 | "metadata": {}, 90 | "outputs": [ 91 | { 92 | "output_type": "pyout", 93 | "prompt_number": 4, 94 | "text": [ 95 | "[]" 96 | ] 97 | }, 98 | { 99 | "output_type": "display_data", 100 | "png": "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\nzZo1pShq5rjUxRVXXJH/8Y9/nM/nWT3ssssu+e3bt5eiuJnyl7/8Jb9w4cL8gAEDlNuT6mZqS33B\nggXo06cPevbsidraWowfPx4zZsyI7fP444/j9NNPBwAMHToU69evx0cffZQ267LDpS4OOeQQdOjQ\nAQCri5UrV5aiqJnjUhcAcPPNN+Pkk0/GbrvtVoJSFgeXurj33ntx0kknoXv37gCATp06laKomeNS\nF127dsXGjRsBABs3bsSuu+6KmhpjoF6z5LDDDkPHjh2125PqZmpRX7VqFXr06PHF9+7du2PVqlXW\nfSpRzFzqQuT222/HMcccU4yiFR3XdjFjxgx897vfBVC5fTMudbF06VKsW7cOI0eOxIEHHoh77rmn\n2MUsCi51MXHiRLz11lvYY489MGjQIEyfPr3YxSwLkupm6sef642Yl4JsKvEG9jmnOXPm4I477sDL\nL7+cYYlKh0tdXHDBBZg2bRpyuRzy+XzFjmtwqYvt27dj4cKFeP755/HZZ5/hkEMOwcEHH4y+ffsW\noYTFw6Uupk6disGDB6O+vh7vv/8+Ro0ahcWLF6N9+/ZFKGF5kUQ3U4t6t27dsGLFii++r1ix4otX\nSN0+PK690nCpCwB4/fXXMXHiRMyaNcv4+tWccamL1157DePHjwfAOsdmzpyJ2tpaHH/88UUta9a4\n1EWPHj3QqVMntG3bFm3btsXw4cOxePHiihN1l7qYN28eLr/8cgBA79690atXL7zzzjs48MADi1rW\nUpNYN9M6+7dv357fa6+98suWLctv3brV2lH6yiuvVGznoEtd/Otf/8r37t07/8orr5SolMXBpS5E\nzjjjjPyf//znIpaweLjUxZIlS/JHHHFEvqGhIb958+b8gAED8m+99VaJSpwdLnVx4YUX5idPnpzP\n5/P51atX57t165b/5JNPSlHczFm2bJlTR6mPbqa21GtqanDLLbdg9OjRaGxsxNlnn41+/frhtttu\nAwB8+9vfxjHHHIOnn34affr0wQ477IA777wzbbZliUtdXHnllfj000+/8CPX1tZiwYIFpSx2JrjU\nRUvBpS722WcfjBkzBgMHDkRVVRUmTpyI/v37l7jk4XGpi8suuwxnnnkmBg0ahKamJlx33XUVObBx\nwoQJmDt3LtauXYsePXpgypQp2L59O4B0uhlkRClBEARRHtDKRwRBEBUEiTpBEEQFQaJOEARRQZCo\nEwRBVBAk6gRBEBUEiTpBEEQF8f/PonDSbJxxWgAAAABJRU5ErkJggg==\n", 101 | "text": [ 102 | "" 103 | ] 104 | } 105 | ], 106 | "prompt_number": 4 107 | } 108 | ], 109 | "metadata": {} 110 | } 111 | ] 112 | } -------------------------------------------------------------------------------- /chapter4/403-histograms.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_04_03" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 4, example 3\n", 15 | "====================\n", 16 | "\n", 17 | "In this example, we plot a histogram of the nodes degrees in the Facebook social graphs." 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "collapsed": false, 23 | "input": [ 24 | "cd fbdata" 25 | ], 26 | "language": "python", 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "output_type": "stream", 31 | "stream": "stdout", 32 | "text": [ 33 | "(bookmark:fbdata) -> chapter2\\data\\facebook\n", 34 | "chapter2\\data\\facebook\n" 35 | ] 36 | } 37 | ], 38 | "prompt_number": 1 39 | }, 40 | { 41 | "cell_type": "code", 42 | "collapsed": false, 43 | "input": [ 44 | "import networkx as nx" 45 | ], 46 | "language": "python", 47 | "metadata": {}, 48 | "outputs": [], 49 | "prompt_number": 2 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "We open a `edge` file with a social graph." 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "collapsed": false, 61 | "input": [ 62 | "g = nx.read_edgelist('0.edges')" 63 | ], 64 | "language": "python", 65 | "metadata": {}, 66 | "outputs": [], 67 | "prompt_number": 3 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "The `hist` function plots a histogram of an array of values." 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "collapsed": false, 79 | "input": [ 80 | "hist(g.degree().values(), bins=20);" 81 | ], 82 | "language": "python", 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "output_type": "display_data", 87 | "png": "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\nJgLSB/fshBUulTj3HAUGwlf0AcByFDkAWI4iBwDLUeRAAqZOdce+/JbMY+pU93j/CJjAONgJJICD\nrUhnFDkSNHnISzHEM/6n/40sP5DOKHIk6Lzs3iMdWX5pvPMDg2OOHAAsR5FjjEwe0cFCjMxIDtaO\n9EAtB4pHH1MrGCNMbYynkRysHem0GAeKRx975ABgOYocACxHkQOA5ZgjB8aEzefhj/c5+CPdfqak\nc+M2fiw+uxHtkb/22muaO3eubrrpJq1fvz5VmcZBaLwDTCCh8Q6QoNAYb6/vYO9wH7slmRFdi33k\nEsm+e4jXxmL7Qz3OJZgzkfHDf4zFZ5d0kV+4cEE//OEP9dprr+nQoUPasmWLDh8+nMpsYyg03gEm\nkNB4B0hQaLwDJCj0//9N99M3Q3HXSA+h8Q4wKpIu8nA4rBtvvFH5+fnKzMzUI488oj/84Q+pzAYg\nZqR7pZjIkp4j//TTTzVr1qzY87y8PL399tuDrj9pUoauvrpeV10VSmp7n3/elNQ4AJjoki7yRP+5\ndvl6Z8+OdPplpP9MHGz82nHefrpvezjjB/tdplv+RD/z0dp+ovpypvufvaF+n+n02Q/3cx/59kd7\neivpIr/++uvV1tYWe97W1qa8vLx+6xjDP+kAYLQlPUdeVlamv/71rzp27Jh6e3v129/+VlVVVanM\nBgBIQNJ75JMnT9amTZu0aNEiXbhwQatWrdK8efNSmQ0AkIARnUf+rW99S0eOHNHf/vY3PfPMM7Hl\n6Xp++cqVK+U4joqKimLLotGovF6vPB6PKisr1dXVNY4JL2lra9Ndd92lwsJCzZ8/Xxs3bpSUflnP\nnj2rBQsWqKSkRAUFBbE/A+mWU7p0umxpaakWL14sKT0z5ufn65ZbblFpaam+/vWvS0rPnF1dXVq6\ndKnmzZungoICvf3222mX88iRIyotLY09srKytHHjxrTLKUnr1q1TYWGhioqKtHz5cn3++efDz2lS\n7Pz582bOnDmmtbXV9Pb2muLiYnPo0KFUbyYpb775pmlqajLz58+PLfvxj39s1q9fb4wxxu/3m6ef\nfnq84sW0t7eb5uZmY4wx3d3dxuPxmEOHDqVl1p6eHmOMMefOnTMLFiwwe/bsScucP//5z83y5cvN\n4sWLjTHp+bnn5+ebzs7OfsvSMedjjz1m6uvrjTGXPveurq60zNnnwoULJjc313z88cdpl7O1tdXM\nnj3bnD171hhjTE1NjfnNb34z7JwpL/K9e/eaRYsWxZ6vW7fOrFu3LtWbSVpra2u/Ir/55ptNR0eH\nMeZSgd58883jFW1Q3/72t83OnTvTOmtPT48pKyszH3zwQdrlbGtrMxUVFWbXrl3m/vvvN8ak5+ee\nn59vjh8/3m9ZuuXs6uoys2fPvmJ5uuX8oj/96U/mzjvvNMakX87Ozk7j8XhMNBo1586dM/fff795\n/fXXh50z5RfNGuj88k8//TTVm0mZSCQix3EkSY7jKBKJjHOi/o4dO6bm5mYtWLAgLbNevHhRJSUl\nchwnNh2UbjmffPJJPffcc8rI+Pcf93TLKF06Re2ee+5RWVmZXnzxRUnpl7O1tVXZ2dl6/PHHdeut\nt+q73/2uenp60i7nF23dulXLli2TlH6/T7fbrTVr1uiGG27QzJkzdd1118nr9Q47Z8qL3Oa7uaTb\n3WhOnTqlBx98UBs2bNCUKVP6vZYuWTMyMnTw4EF98sknevPNN7V79+5+r493zldffVU5OTkqLS0d\n9HTY8c7Y56233lJzc7N27NihF154QXv27On3ejrkPH/+vJqamvSDH/xATU1Nuvbaa+X3+/utkw45\n+/T29uqPf/yjHnrooSteS4ecR48e1fPPP69jx47pH//4h06dOqXNmzf3WyeRnCkv8kTOL08njuOo\no6NDktTe3q6cnJxxTnTJuXPn9OCDD2rFihWqrq6WlL5ZJSkrK0v33Xef3n333bTKuXfvXjU2Nmr2\n7NlatmyZdu3apRUrVqRVxj4zZsyQJGVnZ2vJkiUKh8NplzMvL095eXm6/fbbJUlLly5VU1OTcnNz\n0ypnnx07dui2225Tdna2pPT7O3TgwAHdcccdmj59uiZPnqwHHnhA+/btG/bvM+VFbtv55VVVVQoE\nApKkQCAQK83xZIzRqlWrVFBQoNWrV8eWp1vW48ePx46mnzlzRjt37lRpaWla5Xz22WfV1tam1tZW\nbd26VXfffbdeeeWVtMooSadPn1Z3d7ckqaenR6+//rqKiorSLmdubq5mzZqllpYWSVIwGFRhYaEW\nL16cVjn7bNmyJTatIqXf36G5c+dq//79OnPmjIwxCgaDKigoGP7vczQm8Ldv3248Ho+ZM2eOefbZ\nZ0djE0l55JFHzIwZM0xmZqbJy8szL730kuns7DQVFRXmpptuMl6v15w4cWK8Y5o9e/YYl8tliouL\nTUlJiSkpKTE7duxIu6zvv/++KS0tNcXFxaaoqMj87Gc/M8aYtMvZJxQKxc5aSbeMf//7301xcbEp\nLi42hYWFsb836ZbTGGMOHjxoysrKzC233GKWLFliurq60jLnqVOnzPTp083Jkydjy9Ix5/r1601B\nQYGZP3++eeyxx0xvb++wc7qM4Xv0AGAzbvUGAJajyAHAchQ5AFiOIgcAy1HkAGA5ihwALPd/FaJg\nVmLA8lUAAAAASUVORK5CYII=\n" 88 | } 89 | ], 90 | "prompt_number": 4 91 | } 92 | ], 93 | "metadata": {} 94 | } 95 | ] 96 | } -------------------------------------------------------------------------------- /chapter4/gui.py: -------------------------------------------------------------------------------- 1 | """Basic GUI example with PyQt.""" 2 | from PyQt4 import QtGui 3 | 4 | class HelloWorld(QtGui.QWidget): 5 | def __init__(self): 6 | super(HelloWorld, self).__init__() 7 | # create the button 8 | self.button = QtGui.QPushButton('Click me', self) 9 | self.button.clicked.connect(self.clicked) 10 | # create the layout 11 | vbox = QtGui.QVBoxLayout() 12 | vbox.addWidget(self.button) 13 | self.setLayout(vbox) 14 | # show the window 15 | self.show() 16 | 17 | def clicked(self): 18 | msg = QtGui.QMessageBox(self) 19 | msg.setText("Hello World !") 20 | msg.show() 21 | 22 | window = HelloWorld() 23 | -------------------------------------------------------------------------------- /chapter5/501-parallel-computing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "501-parallel-computing" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 5, example 1\n", 15 | "====================\n", 16 | "\n", 17 | "Here we illustrate the basic parallel computing capabilities of IPython." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "First, IPython engines must be started, for example with the following command to launch 2 engines (one per core):\n", 25 | "\n", 26 | " ipcluster start -n 2" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "collapsed": false, 32 | "input": [ 33 | "from IPython.parallel import Client" 34 | ], 35 | "language": "python", 36 | "metadata": {}, 37 | "outputs": [], 38 | "prompt_number": 1 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "The `Client` allows to start jobs on the engines." 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "collapsed": false, 50 | "input": [ 51 | "rc = Client()" 52 | ], 53 | "language": "python", 54 | "metadata": {}, 55 | "outputs": [], 56 | "prompt_number": 2 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "We can obtain the engines identifiers through the client." 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "collapsed": false, 68 | "input": [ 69 | "rc.ids" 70 | ], 71 | "language": "python", 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "metadata": {}, 76 | "output_type": "pyout", 77 | "prompt_number": 3, 78 | "text": [ 79 | "[0, 1]" 80 | ] 81 | } 82 | ], 83 | "prompt_number": 3 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "**ERRATUM**: the original code did not contain `%px` before the `import os` statement. This magic command is necessary so that the import occurs on all engines." 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "collapsed": false, 95 | "input": [ 96 | "%px import os" 97 | ], 98 | "language": "python", 99 | "metadata": {}, 100 | "outputs": [], 101 | "prompt_number": 4 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "metadata": {}, 106 | "source": [ 107 | "The `%px` magic commands allows to execute commands in parallel on every engine." 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "collapsed": false, 113 | "input": [ 114 | "%px print(os.getpid())" 115 | ], 116 | "language": "python", 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "output_type": "stream", 121 | "stream": "stdout", 122 | "text": [ 123 | "[stdout:0] 3256\n", 124 | "[stdout:1] 1056\n" 125 | ] 126 | } 127 | ], 128 | "prompt_number": 5 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "We can specify with `%pxconfig` the engine identifiers which the commands should be executed on (here, the second engine)." 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "collapsed": false, 140 | "input": [ 141 | "%pxconfig --targets 1" 142 | ], 143 | "language": "python", 144 | "metadata": {}, 145 | "outputs": [], 146 | "prompt_number": 6 147 | }, 148 | { 149 | "cell_type": "code", 150 | "collapsed": false, 151 | "input": [ 152 | "%px print(os.getpid())" 153 | ], 154 | "language": "python", 155 | "metadata": {}, 156 | "outputs": [ 157 | { 158 | "output_type": "stream", 159 | "stream": "stdout", 160 | "text": [ 161 | "1056\n" 162 | ] 163 | } 164 | ], 165 | "prompt_number": 7 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": {}, 170 | "source": [ 171 | "Another possibility is to use the `%%px` cell magic to run an entire cell on all engines. The `--targets` option can accept a slice object (here, all engines except the last one)." 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "collapsed": false, 177 | "input": [ 178 | "%%px --targets :-1\n", 179 | "print(os.getpid())" 180 | ], 181 | "language": "python", 182 | "metadata": {}, 183 | "outputs": [ 184 | { 185 | "output_type": "stream", 186 | "stream": "stdout", 187 | "text": [ 188 | "[stdout:0] 3256\n" 189 | ] 190 | } 191 | ], 192 | "prompt_number": 8 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "By default, the parallel calls are synchronous (blocking) but we can ask IPython to make asynchronous calls." 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "collapsed": false, 204 | "input": [ 205 | "%%px --noblock\n", 206 | "import time\n", 207 | "time.sleep(1)\n", 208 | "os.getpid()" 209 | ], 210 | "language": "python", 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "metadata": {}, 215 | "output_type": "pyout", 216 | "prompt_number": 9, 217 | "text": [ 218 | "" 219 | ] 220 | } 221 | ], 222 | "prompt_number": 9 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "metadata": {}, 227 | "source": [ 228 | "With asynchronous (non-blocking) calls, the results can be obtained synchronously from the engines with `%pxresult`. This call is blocking." 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "collapsed": false, 234 | "input": [ 235 | "%pxresult" 236 | ], 237 | "language": "python", 238 | "metadata": {}, 239 | "outputs": [ 240 | { 241 | "metadata": {}, 242 | "output_type": "display_data", 243 | "text": [ 244 | "\u001b[0;31mOut[1:4]: \u001b[0m1056" 245 | ] 246 | } 247 | ], 248 | "prompt_number": 10 249 | }, 250 | { 251 | "cell_type": "markdown", 252 | "metadata": {}, 253 | "source": [ 254 | "Another option to run tasks on the engines is to use `map`. First, we need to retrieve a view on the engines, which represents a particular set of engines among the ones that are running." 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "collapsed": false, 260 | "input": [ 261 | "v = rc[:]" 262 | ], 263 | "language": "python", 264 | "metadata": {}, 265 | "outputs": [], 266 | "prompt_number": 11 267 | }, 268 | { 269 | "cell_type": "markdown", 270 | "metadata": {}, 271 | "source": [ 272 | "We import a module on each engine." 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "collapsed": false, 278 | "input": [ 279 | "with v.sync_imports():\n", 280 | " import time" 281 | ], 282 | "language": "python", 283 | "metadata": {}, 284 | "outputs": [ 285 | { 286 | "output_type": "stream", 287 | "stream": "stdout", 288 | "text": [ 289 | "importing time on engine(s)\n" 290 | ] 291 | } 292 | ], 293 | "prompt_number": 12 294 | }, 295 | { 296 | "cell_type": "markdown", 297 | "metadata": {}, 298 | "source": [ 299 | "We define a simple function." 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "collapsed": false, 305 | "input": [ 306 | "def f(x):\n", 307 | " time.sleep(1)\n", 308 | " return x * x" 309 | ], 310 | "language": "python", 311 | "metadata": {}, 312 | "outputs": [], 313 | "prompt_number": 13 314 | }, 315 | { 316 | "cell_type": "markdown", 317 | "metadata": {}, 318 | "source": [ 319 | "Now, we call `map_sync`, which is a synchronous and parallel version of Python's built-in `map` function. We execute `f` on all integers between 0 and 9 in parallel across all engines." 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "collapsed": false, 325 | "input": [ 326 | "v.map_sync(f, range(10))" 327 | ], 328 | "language": "python", 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "metadata": {}, 333 | "output_type": "pyout", 334 | "prompt_number": 14, 335 | "text": [ 336 | "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]" 337 | ] 338 | } 339 | ], 340 | "prompt_number": 14 341 | }, 342 | { 343 | "cell_type": "markdown", 344 | "metadata": {}, 345 | "source": [ 346 | "We check how much time the native function takes." 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "collapsed": false, 352 | "input": [ 353 | "timeit -n 1 -r 1 map(f, range(10))" 354 | ], 355 | "language": "python", 356 | "metadata": {}, 357 | "outputs": [ 358 | { 359 | "output_type": "stream", 360 | "stream": "stdout", 361 | "text": [ 362 | "1 loops, best of 1: 10 s per loop\n" 363 | ] 364 | } 365 | ], 366 | "prompt_number": 15 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": {}, 371 | "source": [ 372 | "And we compare with the time taken by the parallel version." 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "collapsed": false, 378 | "input": [ 379 | "r = v.map(f, range(10))" 380 | ], 381 | "language": "python", 382 | "metadata": {}, 383 | "outputs": [], 384 | "prompt_number": 16 385 | }, 386 | { 387 | "cell_type": "code", 388 | "collapsed": false, 389 | "input": [ 390 | "r.ready(), r.elapsed" 391 | ], 392 | "language": "python", 393 | "metadata": {}, 394 | "outputs": [ 395 | { 396 | "metadata": {}, 397 | "output_type": "pyout", 398 | "prompt_number": 17, 399 | "text": [ 400 | "(False, 0.065)" 401 | ] 402 | } 403 | ], 404 | "prompt_number": 17 405 | }, 406 | { 407 | "cell_type": "markdown", 408 | "metadata": {}, 409 | "source": [ 410 | "We wait and get the results." 411 | ] 412 | }, 413 | { 414 | "cell_type": "code", 415 | "collapsed": false, 416 | "input": [ 417 | "r.get()" 418 | ], 419 | "language": "python", 420 | "metadata": {}, 421 | "outputs": [ 422 | { 423 | "metadata": {}, 424 | "output_type": "pyout", 425 | "prompt_number": 18, 426 | "text": [ 427 | "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]" 428 | ] 429 | } 430 | ], 431 | "prompt_number": 18 432 | }, 433 | { 434 | "cell_type": "code", 435 | "collapsed": false, 436 | "input": [ 437 | "r.elapsed, r.serial_time" 438 | ], 439 | "language": "python", 440 | "metadata": {}, 441 | "outputs": [ 442 | { 443 | "metadata": {}, 444 | "output_type": "pyout", 445 | "prompt_number": 19, 446 | "text": [ 447 | "(5.009, 10.0)" 448 | ] 449 | } 450 | ], 451 | "prompt_number": 19 452 | } 453 | ], 454 | "metadata": {} 455 | } 456 | ] 457 | } -------------------------------------------------------------------------------- /chapter5/502-monte-carlo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_05_02" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 5, example 2\n", 15 | "====================\n", 16 | "\n", 17 | "Here we show how to parallelize a simple Monte-Carlo simulation for estimating pi." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "This function counts the number of points within a quarter of disc centered at the origin, among all points randomly sampled within the unit square." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "collapsed": false, 30 | "input": [ 31 | "def sample(n):\n", 32 | " return (rand(n) ** 2 + rand(n) ** 2 <= 1).sum()" 33 | ], 34 | "language": "python", 35 | "metadata": {}, 36 | "outputs": [], 37 | "prompt_number": 1 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "Pi is approximately equal to four times the ratio of points within that quarter of disc." 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "collapsed": false, 49 | "input": [ 50 | "n = 1000000.\n", 51 | "4 * sample(n) / n" 52 | ], 53 | "language": "python", 54 | "metadata": {}, 55 | "outputs": [ 56 | { 57 | "output_type": "pyout", 58 | "prompt_number": 2, 59 | "text": [ 60 | "3.1425920000000001" 61 | ] 62 | } 63 | ], 64 | "prompt_number": 2 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "Now, we create a parallel client and import the `rand` function on all engines." 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "collapsed": false, 76 | "input": [ 77 | "from IPython.parallel import Client\n", 78 | "rc = Client()\n", 79 | "v = rc[:]\n", 80 | "with v.sync_imports():\n", 81 | " from numpy.random import rand" 82 | ], 83 | "language": "python", 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "output_type": "stream", 88 | "stream": "stdout", 89 | "text": [ 90 | "importing rand from numpy.random on engine(s)\n" 91 | ] 92 | } 93 | ], 94 | "prompt_number": 3 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "Finally, we execute the simulation in parallel over all engines (each engine samples _n_ points, and there are _nk_ points in total if there are _k_ engines), and we combine the results (reduce operation)." 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "collapsed": false, 106 | "input": [ 107 | "4 * sum(v.map_sync(sample, [n] * len(v))) / (n * len(v))" 108 | ], 109 | "language": "python", 110 | "metadata": {}, 111 | "outputs": [ 112 | { 113 | "output_type": "pyout", 114 | "prompt_number": 4, 115 | "text": [ 116 | "3.1406360000000002" 117 | ] 118 | } 119 | ], 120 | "prompt_number": 4 121 | } 122 | ], 123 | "metadata": {} 124 | } 125 | ] 126 | } -------------------------------------------------------------------------------- /chapter5/503-mpi.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_05_03" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 5, example 3\n", 15 | "====================\n", 16 | "\n", 17 | "In this example we show how to use MPI from IPython." 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "collapsed": false, 23 | "input": [ 24 | "from IPython.parallel import Client" 25 | ], 26 | "language": "python", 27 | "metadata": {}, 28 | "outputs": [] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "We first need to create a MPI profile with:\n", 35 | "\n", 36 | " ipython profile create --parallel --profile=mpi\n", 37 | "\n", 38 | "Then specify the following in the cluster configuration file:\n", 39 | "\n", 40 | " c.IPClusterEngines.engine_launcher_class = 'MPIEngineSetLauncher'\n", 41 | "\n", 42 | "and run the engines with:\n", 43 | "\n", 44 | " ipcluster start -n 4 --profile=mpi\n", 45 | "\n", 46 | "Now, we can create a MPI client." 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "collapsed": false, 52 | "input": [ 53 | "c = Client(profile='mpi')" 54 | ], 55 | "language": "python", 56 | "metadata": {}, 57 | "outputs": [] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "collapsed": false, 62 | "input": [ 63 | "view = c[:]" 64 | ], 65 | "language": "python", 66 | "metadata": {}, 67 | "outputs": [] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "collapsed": false, 72 | "input": [ 73 | "view.activate() # enable magics" 74 | ], 75 | "language": "python", 76 | "metadata": {}, 77 | "outputs": [] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": {}, 82 | "source": [ 83 | "We will compute the sum of all integers between 1 and 16 in parallel over four cores. The script `psum.py` contains the following code:\n", 84 | "\n", 85 | " from mpi4py import MPI\n", 86 | " import numpy as np\n", 87 | " \n", 88 | " # This function will be executed on all processes.\n", 89 | " def psum(a):\n", 90 | " # \"a\" only contains a subset of all integers.\n", 91 | " # They are summed locally on this process. \n", 92 | " locsum = np.sum(a)\n", 93 | " \n", 94 | " # We allocate a variable that will contain the final result, that is,\n", 95 | " # the sum of all our integers.\n", 96 | " rcvBuf = np.array(0.0,'d')\n", 97 | " \n", 98 | " # We use a MPI reduce operation:\n", 99 | " # * locsum is combined from all processes\n", 100 | " # * these local sums are summed with the MPI.SUM operation\n", 101 | " # * the result (total sum) is distributed back to all processes in\n", 102 | " # the rcvBuf variable\n", 103 | " MPI.COMM_WORLD.Allreduce([locsum, MPI.DOUBLE],\n", 104 | " [rcvBuf, MPI.DOUBLE],\n", 105 | " op=MPI.SUM)\n", 106 | " return rcvBuf" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "We execute this script on all engines so that the function is available everywhere." 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "collapsed": false, 119 | "input": [ 120 | "view.run('psum.py') # the script runs on all processes" 121 | ], 122 | "language": "python", 123 | "metadata": {}, 124 | "outputs": [] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "Now we distribute the array with the 16 values across the engines (each engine gets a subarray)." 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "collapsed": false, 136 | "input": [ 137 | "view.scatter('a', np.arange(16)) # this array is scattered across processes" 138 | ], 139 | "language": "python", 140 | "metadata": {}, 141 | "outputs": [] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "We compute the total sum in parallel using MPI." 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "collapsed": false, 153 | "input": [ 154 | "%px totalsum = psum(a) # psum is executed on all processes" 155 | ], 156 | "language": "python", 157 | "metadata": {}, 158 | "outputs": [] 159 | }, 160 | { 161 | "cell_type": "markdown", 162 | "metadata": {}, 163 | "source": [ 164 | "Finally, the result is available on all engines thanks to the MPI `Allreduce` function." 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "collapsed": false, 170 | "input": [ 171 | "view['totalsum']" 172 | ], 173 | "language": "python", 174 | "metadata": {}, 175 | "outputs": [] 176 | } 177 | ], 178 | "metadata": {} 179 | } 180 | ] 181 | } -------------------------------------------------------------------------------- /chapter5/504-cython-eratosthenes.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_05_04" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 5, example 4\n", 15 | "====================\n", 16 | "\n", 17 | "In this example, we show how to accelerate a pure Python algorithm with Cython, just by giving some type information about the local variables." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "We will implement the Eratosthenes Sieve algorithm to find all prime numbers smaller than a given number. The first version is coded in pure Python." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "collapsed": false, 30 | "input": [ 31 | "def primes1(n):\n", 32 | " primes = [False, False] + [True] * (n - 2)\n", 33 | " i = 2\n", 34 | " while i < n:\n", 35 | " # we do not deal with composite numbers\n", 36 | " if not primes[i]:\n", 37 | " i += 1\n", 38 | " continue\n", 39 | " k = i * i\n", 40 | " # mark multiples of i as composite numbers\n", 41 | " while k < n:\n", 42 | " primes[k] = False\n", 43 | " k += i\n", 44 | " i += 1\n", 45 | " return [i for i in xrange(2, n) if primes[i]]" 46 | ], 47 | "language": "python", 48 | "metadata": {}, 49 | "outputs": [], 50 | "prompt_number": 1 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "Let's evaluate the performance of this first version." 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "collapsed": false, 62 | "input": [ 63 | "n = 10000" 64 | ], 65 | "language": "python", 66 | "metadata": {}, 67 | "outputs": [], 68 | "prompt_number": 2 69 | }, 70 | { 71 | "cell_type": "code", 72 | "collapsed": false, 73 | "input": [ 74 | "primes1(20)" 75 | ], 76 | "language": "python", 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "output_type": "pyout", 81 | "prompt_number": 3, 82 | "text": [ 83 | "[2, 3, 5, 7, 11, 13, 17, 19]" 84 | ] 85 | } 86 | ], 87 | "prompt_number": 3 88 | }, 89 | { 90 | "cell_type": "code", 91 | "collapsed": false, 92 | "input": [ 93 | "%timeit primes1(n)" 94 | ], 95 | "language": "python", 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "output_type": "stream", 100 | "stream": "stdout", 101 | "text": [ 102 | "100 loops, best of 3: 10.8 ms per loop\n" 103 | ] 104 | } 105 | ], 106 | "prompt_number": 4 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "Now, we load the Cython magic extension to write Cython code right in the notebook." 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "collapsed": false, 118 | "input": [ 119 | "%load_ext cythonmagic" 120 | ], 121 | "language": "python", 122 | "metadata": {}, 123 | "outputs": [], 124 | "prompt_number": 5 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "All we do is to add `%%cython` in the first line of the cell." 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "collapsed": false, 136 | "input": [ 137 | "%%cython\n", 138 | "def primes2(n):\n", 139 | " primes = [False, False] + [True] * (n - 2)\n", 140 | " i = 2\n", 141 | " while i < n:\n", 142 | " if not primes[i]:\n", 143 | " i += 1\n", 144 | " continue\n", 145 | " k = i * i\n", 146 | " while k < n:\n", 147 | " primes[k] = False\n", 148 | " k += i\n", 149 | " i += 1\n", 150 | " return [i for i in xrange(2, n) if primes[i]]" 151 | ], 152 | "language": "python", 153 | "metadata": {}, 154 | "outputs": [], 155 | "prompt_number": 6 156 | }, 157 | { 158 | "cell_type": "code", 159 | "collapsed": false, 160 | "input": [ 161 | "primes2(20)" 162 | ], 163 | "language": "python", 164 | "metadata": {}, 165 | "outputs": [ 166 | { 167 | "output_type": "pyout", 168 | "prompt_number": 7, 169 | "text": [ 170 | "[2, 3, 5, 7, 11, 13, 17, 19]" 171 | ] 172 | } 173 | ], 174 | "prompt_number": 7 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": {}, 179 | "source": [ 180 | "The speed up improvement is modest." 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "collapsed": false, 186 | "input": [ 187 | "timeit primes2(n)" 188 | ], 189 | "language": "python", 190 | "metadata": {}, 191 | "outputs": [ 192 | { 193 | "output_type": "stream", 194 | "stream": "stdout", 195 | "text": [ 196 | "100 loops, best of 3: 6.97 ms per loop\n" 197 | ] 198 | } 199 | ], 200 | "prompt_number": 8 201 | }, 202 | { 203 | "cell_type": "markdown", 204 | "metadata": {}, 205 | "source": [ 206 | "Now, we will precise the type of each local variable so that Cython can considerably optimize the code." 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "collapsed": false, 212 | "input": [ 213 | "%%cython\n", 214 | "def primes3(int n):\n", 215 | " primes = [False, False] + [True] * (n - 2)\n", 216 | " cdef int i = 2\n", 217 | " cdef int k = 0\n", 218 | " while i < n:\n", 219 | " if not primes[i]:\n", 220 | " i += 1\n", 221 | " continue\n", 222 | " k = i * i\n", 223 | " while k < n:\n", 224 | " primes[k] = False\n", 225 | " k += i\n", 226 | " i += 1\n", 227 | " return [i for i in xrange(2, n) if primes[i]]" 228 | ], 229 | "language": "python", 230 | "metadata": {}, 231 | "outputs": [], 232 | "prompt_number": 9 233 | }, 234 | { 235 | "cell_type": "code", 236 | "collapsed": false, 237 | "input": [ 238 | "timeit primes3(n)" 239 | ], 240 | "language": "python", 241 | "metadata": {}, 242 | "outputs": [ 243 | { 244 | "output_type": "stream", 245 | "stream": "stdout", 246 | "text": [ 247 | "1000 loops, best of 3: 1.36 ms per loop\n" 248 | ] 249 | } 250 | ], 251 | "prompt_number": 10 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "We achieve a 8x speed improvement just by specifying the variable types." 258 | ] 259 | } 260 | ], 261 | "metadata": {} 262 | } 263 | ] 264 | } -------------------------------------------------------------------------------- /chapter5/505-cython-numpy.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_05_05" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 5, example 5\n", 15 | "====================\n", 16 | "\n", 17 | "Here we show how to use Cython with NumPy to accelerate Python algorithms operating on arrays. The code consists in simulating a stochastic process." 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "collapsed": false, 23 | "input": [ 24 | "%load_ext cythonmagic" 25 | ], 26 | "language": "python", 27 | "metadata": {}, 28 | "outputs": [], 29 | "prompt_number": 1 30 | }, 31 | { 32 | "cell_type": "code", 33 | "collapsed": false, 34 | "input": [ 35 | "n = 10000" 36 | ], 37 | "language": "python", 38 | "metadata": {}, 39 | "outputs": [], 40 | "prompt_number": 2 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "This function simulates a brownian motion with random, independent steps (up or down). We use a Python loop here." 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "collapsed": false, 52 | "input": [ 53 | "def step():\n", 54 | " return sign(rand(1) - .5)\n", 55 | "\n", 56 | "def sim1(n):\n", 57 | " x = zeros(n)\n", 58 | " dx = 1./n\n", 59 | " for i in xrange(n - 1):\n", 60 | " x[i+1] = x[i] + dx * step()\n", 61 | " return x" 62 | ], 63 | "language": "python", 64 | "metadata": {}, 65 | "outputs": [], 66 | "prompt_number": 3 67 | }, 68 | { 69 | "cell_type": "code", 70 | "collapsed": false, 71 | "input": [ 72 | "plot(sim1(10000))" 73 | ], 74 | "language": "python", 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "output_type": "pyout", 79 | "prompt_number": 4, 80 | "text": [ 81 | "[]" 82 | ] 83 | }, 84 | { 85 | "output_type": "display_data", 86 | "png": "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\n" 87 | } 88 | ], 89 | "prompt_number": 4 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "Let's evaluate the performance of this function." 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "collapsed": false, 101 | "input": [ 102 | "%timeit sim1(n)" 103 | ], 104 | "language": "python", 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "output_type": "stream", 109 | "stream": "stdout", 110 | "text": [ 111 | "1 loops, best of 3: 216 ms per loop\n" 112 | ] 113 | } 114 | ], 115 | "prompt_number": 5 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "Now we convert it in Cython. We specify the type of each variable, and we rewrite the step function in C so that it only uses pure C functions." 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "collapsed": false, 127 | "input": [ 128 | "%%cython\n", 129 | "import numpy as np\n", 130 | "# We need to import NumPy with cimport\n", 131 | "cimport numpy as np\n", 132 | "DTYPE = np.double\n", 133 | "# We define the type of the array for Cython\n", 134 | "ctypedef np.double_t DTYPE_t\n", 135 | "\n", 136 | "# We rewrite the step function in C using the standard library\n", 137 | "from libc.stdlib cimport rand, RAND_MAX\n", 138 | "from libc.math cimport round\n", 139 | "\n", 140 | "cdef double step():\n", 141 | " return 2 * round(float(rand()) / RAND_MAX) - 1\n", 142 | "\n", 143 | "def sim2(int n):\n", 144 | " # here we specify the type of each variable with cdef, including the type of the array\n", 145 | " # with a special syntax so that Cython knows at compile-time the number of dimensions of this array.\n", 146 | " cdef int i\n", 147 | " cdef double dx = 1. / n\n", 148 | " cdef np.ndarray[DTYPE_t, ndim=1] x = np.zeros(n, dtype=DTYPE)\n", 149 | " for i in range(n - 1):\n", 150 | " x[i+1] = x[i] + dx * step()\n", 151 | " return x" 152 | ], 153 | "language": "python", 154 | "metadata": {}, 155 | "outputs": [], 156 | "prompt_number": 6 157 | }, 158 | { 159 | "cell_type": "code", 160 | "collapsed": false, 161 | "input": [ 162 | "%timeit sim2(n)" 163 | ], 164 | "language": "python", 165 | "metadata": {}, 166 | "outputs": [ 167 | { 168 | "output_type": "stream", 169 | "stream": "stdout", 170 | "text": [ 171 | "1000 loops, best of 3: 900 us per loop\n" 172 | ] 173 | } 174 | ], 175 | "prompt_number": 7 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "We achieve a 240x speed improvement here!" 182 | ] 183 | } 184 | ], 185 | "metadata": {} 186 | } 187 | ] 188 | } -------------------------------------------------------------------------------- /chapter5/psum.py: -------------------------------------------------------------------------------- 1 | from mpi4py import MPI 2 | import numpy as np 3 | 4 | # This function will be executed on all processes. 5 | def psum(a): 6 | # "a" only contains a subset of all integers. 7 | # They are summed locally on this process. 8 | locsum = np.sum(a) 9 | 10 | # We allocate a variable that will contain the final result, that is, 11 | # the sum of all our integers. 12 | rcvBuf = np.array(0.0,'d') 13 | 14 | # We use a MPI reduce operation: 15 | # * locsum is combined from all processes 16 | # * these local sums are summed with the MPI.SUM operation 17 | # * the result (total sum) is distributed back to all processes in 18 | # the rcvBuf variable 19 | MPI.COMM_WORLD.Allreduce([locsum, MPI.DOUBLE], 20 | [rcvBuf, MPI.DOUBLE], 21 | op=MPI.SUM) 22 | return rcvBuf 23 | -------------------------------------------------------------------------------- /chapter6/601-lprof.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_06_01" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 6, example 1\n", 15 | "====================\n", 16 | "\n", 17 | "**Note**: the profilers uses here display their results in an external window in the notebook, so that these results are not shown here. You will need to execute this notebook yourself if you want to see the actual outputs.", 18 | "\n", 19 | "Here we illustrate how to use some line-by-line profilers on a function defined in `myscript.py`:\n", 20 | "\n", 21 | " import numpy as np\n", 22 | " import matplotlib.pyplot as plt\n", 23 | " def myfun():\n", 24 | " dx = np.random.randn(1000, 10000)\n", 25 | " x = np.sum(dx, axis=0)\n", 26 | " plt.hist(x, bins=np.linspace(-100, 100, 20))\n", 27 | " " 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "We first need to load the extensions provided by the `line_profiler` and `memory_profiler` modules." 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "collapsed": false, 40 | "input": [ 41 | "%load_ext line_profiler" 42 | ], 43 | "language": "python", 44 | "metadata": {}, 45 | "outputs": [], 46 | "prompt_number": 1 47 | }, 48 | { 49 | "cell_type": "code", 50 | "collapsed": false, 51 | "input": [ 52 | "%load_ext memory_profiler" 53 | ], 54 | "language": "python", 55 | "metadata": {}, 56 | "outputs": [], 57 | "prompt_number": 2 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "We import and execute the function once." 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "collapsed": false, 69 | "input": [ 70 | "from myscript import myfun" 71 | ], 72 | "language": "python", 73 | "metadata": {}, 74 | "outputs": [], 75 | "prompt_number": 3 76 | }, 77 | { 78 | "cell_type": "code", 79 | "collapsed": false, 80 | "input": [ 81 | "myfun()" 82 | ], 83 | "language": "python", 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "output_type": "display_data", 88 | "png": "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\n+z//2KZJFdb2lQAAAABJRU5ErkJggg==\n" 89 | } 90 | ], 91 | "prompt_number": 4 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "Now, let's profile it line by line with `%lprun`." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "collapsed": false, 103 | "input": [ 104 | "%lprun -f myfun myfun()" 105 | ], 106 | "language": "python", 107 | "metadata": {}, 108 | "outputs": [ 109 | { 110 | "output_type": "stream", 111 | "stream": "stdout", 112 | "text": [ 113 | "\n" 114 | ] 115 | }, 116 | { 117 | "output_type": "display_data", 118 | "png": "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\nZKWHN90AAAAASUVORK5CYII=\n" 119 | } 120 | ], 121 | "prompt_number": 5 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "Let's find out the amount of memory used by this function with `%memit`." 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "collapsed": false, 133 | "input": [ 134 | "%memit -i myfun()" 135 | ], 136 | "language": "python", 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "output_type": "stream", 141 | "stream": "stdout", 142 | "text": [ 143 | "maximum of 1: 125.195312 MB per loop\n" 144 | ] 145 | }, 146 | { 147 | "output_type": "display_data", 148 | "png": "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\nE3C73XrhhRd077336vLly9q3b9+UD4UBAPNrXi8bcd999+ntt99WS0uLXnrpJX3iE5/Q6dOnJz2m\npaVFwWBQoVBIfX19hfFTp06purpawWBQhw4dms+2F5Wmpib5/X5t2LBBGzZs0Msvv1y4b7q5xcx6\ne3sVCoUUDAZ15MiRUrez6AQCAa1fv14bNmxQJBKRJI2NjSkWi6mqqkq1tbUaHx8vcZcL1969e+X1\nelVdXV0Ym2n+Zr2dWyVw5swZ6+2337ai0ah16tSpwvhbb71l1dTUWPl83kqn09aaNWusK1euWJZl\nWZs2bbL6+/sty7Ks++67z3r55ZdL0fqC19TUZD3zzDNTxm80t5cvXy5Bh4vLpUuXrDVr1ljpdNrK\n5/NWTU2NlUwmS93WohIIBKz33ntv0thjjz1mHTlyxLIsy2ptbbWeeOKJUrS2KPzud7+zTp8+bd12\n222Fsenmz852XpILyIVCIVVVVU0Z7+7uVkNDgzwejwKBgCorK9Xf36+RkRFNTEwUXkXs3r1bXV1d\n8932omHd4AP2G83twMBACbpbXD58fovH4ymc34LZuf7/ZE9PjxobGyVJjY2NbM8z2LJli1asWDFp\nbLr5s7OdL6iriA4PD086Ysjv9yubzU4Z9/l8ymazpWhxUXj++edVU1Ojffv2Fd4mTje3mNmNzm9h\n3mbH5XLpnnvu0caNG/WLX/xCkpTL5eT1eiVJXq9XuVyulC0uOtPNn53tfM4+GI7FYhodHZ0yfvjw\nYe3YYf+EMEw/t0899ZQOHDigH//4x5KkH/3oR3r00UfV3t5+wzqlvmbJYsAcFe+Pf/yjVq1apX/+\n85+KxWIKhUKT7ne5XMxzET5q/j5qbucsBF555ZVZL3P9uQSZTEZ+v18+n0+ZTGbSuM/nc6TPxejj\nzu3+/fsLgXujuTV5Dj+uj3N+C2a2atUqSdKtt96qb37zmxoYGJDX69Xo6KgqKio0MjKi8vLyEne5\nuEw3f3a285LvDvrwvsJ4PK7Ozk7l83ml02mlUilFIhFVVFSorKxM/f39sixLx44dU11dXQm7XrhG\nRkYKP//6178uHFEw3dxiZpzfUpyLFy9qYmJCkvSvf/1LfX19qq6uVjweV0dHhySpo6OD7XmWpps/\nW9v53HyePbNf/epXlt/vt2666SbL6/Va27ZtK9z31FNPWWvWrLG+/OUvW729vYXxN954w7rtttus\nNWvWWN///vdL0faisGvXLqu6utpav3699Y1vfMMaHR0t3Dfd3GJmJ0+etKqqqqw1a9ZYhw8fLnU7\ni8rf//53q6amxqqpqbHWrVtXmL/33nvP2rp1qxUMBq1YLGadO3euxJ0uXA899JC1atUqy+PxWH6/\n3zp69OiM8zfb7XxBfakMAGB+lXx3EACgdAgBADAYIQAABiMEAMBghAAAGIwQAACD/R+hn2U6X9G0\nYQAAAABJRU5ErkJggg==\n" 149 | } 150 | ], 151 | "prompt_number": 6 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "We can also do line-by-line profiling with memory consumption, using `%mprun`." 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "collapsed": false, 163 | "input": [ 164 | "%mprun -f myfun myfun()" 165 | ], 166 | "language": "python", 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "output_type": "stream", 171 | "stream": "stdout", 172 | "text": [ 173 | "('',)\n" 174 | ] 175 | }, 176 | { 177 | "output_type": "display_data", 178 | "png": "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\n" 179 | } 180 | ], 181 | "prompt_number": 7 182 | } 183 | ], 184 | "metadata": {} 185 | } 186 | ] 187 | } -------------------------------------------------------------------------------- /chapter6/602-cpp.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_06_02" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 6, example 2\n", 15 | "====================\n", 16 | "\n", 17 | "In this example, we show how to create a simple IPython extension that allows to write and evaluate C++ code directly in the notebook.\n", 18 | "\n", 19 | "The `cppmagic.py` script contains the following code:\n", 20 | "\n", 21 | " import IPython.core.magic as ipym\n", 22 | " \n", 23 | " @ipym.magics_class\n", 24 | " class CppMagics(ipym.Magics):\n", 25 | " @ipym.cell_magic\n", 26 | " def cpp(self, line, cell=None):\n", 27 | " \"\"\"Compile, execute C++ code, and return the standard output.\"\"\"\n", 28 | " # Define the source and executable filenames.\n", 29 | " source_filename = 'temp.cpp'\n", 30 | " program_filename = 'temp.exe'\n", 31 | " # Write the code contained in the cell to the C++ file.\n", 32 | " with open(source_filename, 'w') as f:\n", 33 | " f.write(cell)\n", 34 | " # Compile the C++ code into an executable.\n", 35 | " compile = self.shell.getoutput(\"g++ {0:s} -o {1:s}\".format(\n", 36 | " source_filename, program_filename))\n", 37 | " # Execute the executable and return the output.\n", 38 | " output = self.shell.getoutput(program_filename)\n", 39 | " return output\n", 40 | " \n", 41 | " def load_ipython_extension(ipython):\n", 42 | " ipython.register_magics(CppMagics)\n" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "We load the extension as if it was a simple Python module. The `load_ipython_extension` function is called with the IPython interpreter instance as an argument." 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "collapsed": false, 55 | "input": [ 56 | "%load_ext cppmagic" 57 | ], 58 | "language": "python", 59 | "metadata": {}, 60 | "outputs": [], 61 | "prompt_number": 1 62 | }, 63 | { 64 | "cell_type": "code", 65 | "collapsed": false, 66 | "input": [ 67 | "cpp?" 68 | ], 69 | "language": "python", 70 | "metadata": {}, 71 | "outputs": [], 72 | "prompt_number": 2 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "We now have access to the `cpp` cell magic, which allows to write C++ code in the notebook, compile it, execute it, and return the result." 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "collapsed": false, 84 | "input": [ 85 | "%%cpp\n", 86 | "#include\n", 87 | "int main()\n", 88 | "{\n", 89 | " std::cout << \"Hello world!\";\n", 90 | "}" 91 | ], 92 | "language": "python", 93 | "metadata": {}, 94 | "outputs": [ 95 | { 96 | "output_type": "pyout", 97 | "prompt_number": 3, 98 | "text": [ 99 | "['Hello world!']" 100 | ] 101 | } 102 | ], 103 | "prompt_number": 3 104 | } 105 | ], 106 | "metadata": {} 107 | } 108 | ] 109 | } -------------------------------------------------------------------------------- /chapter6/603-notebook-rich-display.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "9932_06_03" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Chapter 6, example 3\n", 15 | "====================\n", 16 | "\n", 17 | "Here we show how to use rich representations in the notebook." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "We first define a standard Python class that admits a SVG representation method. A Disc instance can be rendered as SVG in the notebook." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "collapsed": false, 30 | "input": [ 31 | "class Disc(object):\n", 32 | " def __init__(self, size, color='red'):\n", 33 | " self.size = size\n", 34 | " self.color = color\n", 35 | " \n", 36 | " def _repr_svg_(self):\n", 37 | " return \"\"\"\n", 38 | " \n", 39 | " \"\"\".format(self.size, self.color)" 40 | ], 41 | "language": "python", 42 | "metadata": {}, 43 | "outputs": [], 44 | "prompt_number": 1 45 | }, 46 | { 47 | "cell_type": "code", 48 | "collapsed": false, 49 | "input": [ 50 | "Disc(80, 'purple')" 51 | ], 52 | "language": "python", 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "output_type": "pyout", 57 | "prompt_number": 2, 58 | "svg": [ 59 | "\n", 60 | " \n", 61 | " " 62 | ], 63 | "text": [ 64 | "<__main__.Disc at 0x582c790>" 65 | ] 66 | } 67 | ], 68 | "prompt_number": 2 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "Other rich representation types are available in `IPython.display`." 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "collapsed": false, 80 | "input": [ 81 | "import IPython.display as dsp" 82 | ], 83 | "language": "python", 84 | "metadata": {}, 85 | "outputs": [], 86 | "prompt_number": 3 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "Here, we can type mathematical equations in LaTeX, and they are nicely rendered in the notebook." 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "collapsed": false, 98 | "input": [ 99 | "dsp.Math(r\"\\sum_{n=1}^\\infty \\frac{1}{n^2} = \\frac{\\pi^2}{6}\")" 100 | ], 101 | "language": "python", 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "latex": [ 106 | "$$\\sum_{n=1}^\\infty \\frac{1}{n^2} = \\frac{\\pi^2}{6}$$" 107 | ], 108 | "output_type": "pyout", 109 | "prompt_number": 4, 110 | "text": [ 111 | "" 112 | ] 113 | } 114 | ], 115 | "prompt_number": 4 116 | } 117 | ], 118 | "metadata": {} 119 | } 120 | ] 121 | } -------------------------------------------------------------------------------- /chapter6/cppmagic.py: -------------------------------------------------------------------------------- 1 | import IPython.core.magic as ipym 2 | import os 3 | 4 | @ipym.magics_class 5 | class CppMagics(ipym.Magics): 6 | @ipym.cell_magic 7 | def cpp(self, line, cell=None): 8 | """Compile, execute C++ code, and return the standard output.""" 9 | # Define the source and executable filenames. 10 | source_filename = os.path.abspath('temp.cpp') 11 | program_filename = os.path.abspath('temp.exe') 12 | # Write the code contained in the cell to the C++ file. 13 | with open(source_filename, 'w') as f: 14 | f.write(cell) 15 | # Compile the C++ code into an executable. 16 | compile = self.shell.getoutput("g++ {0:s} -o {1:s}".format( 17 | source_filename, program_filename)) 18 | # Execute the executable and return the output. 19 | output = self.shell.getoutput(program_filename) 20 | return output 21 | 22 | def load_ipython_extension(ipython): 23 | ipython.register_magics(CppMagics) 24 | -------------------------------------------------------------------------------- /chapter6/myscript.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | def myfun(): 4 | dx = np.random.randn(1000, 10000) 5 | x = np.sum(dx, axis=0) 6 | plt.hist(x, bins=np.linspace(-100, 100, 20)) 7 | --------------------------------------------------------------------------------