{ "cells": [ { "cell_type": "code", "execution_count": 4, "id": "807f94ad", "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "id": "aa4ee33f", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Avoid for-loops (element-after-element operations)" ] }, { "cell_type": "code", "execution_count": 5, "id": "c4290b53", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def compute_reciprocals(values):\n", " output = np.empty(len(values))\n", " for i in range(len(values)):\n", " output[i] = 1.0 / values[i]\n", " return output" ] }, { "cell_type": "code", "execution_count": 6, "id": "b6e6dca6", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "18.4 µs ± 155 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n" ] } ], "source": [ "%%timeit\n", "\n", "np.random.seed(0)\n", " \n", "values = np.random.randint(1, 10, size=5)\n", "compute_reciprocals(values)" ] }, { "cell_type": "markdown", "id": "bd70d5d3", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Very slow! Each time the reciprocal is computed, Python first examines the object's **type** and does a dynamic lookup of the **correct function** to use for that type" ] }, { "cell_type": "markdown", "id": "cfd3f5d5", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Basic functions\n", "\n", "In NumPy - convenient interface for just this kind of statically typed, compiled routine. --> vectorized operations\n", "- performing an operation on the array, which will then be applied to each element\n", "- pushes the loop into the compiled layer that underlies NumPy --> much faster execution\n", "\n", "- basic funcs quickly execute repeated operations on values in NumPy arrays --> extremely flexible" ] }, { "cell_type": "code", "execution_count": 7, "id": "28eb2782", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8.81 µs ± 173 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n" ] } ], "source": [ "%%timeit\n", "values = np.random.randint(1, 10, size=5)\n", "#compute_reciprocals(values)\n", "1.0 / values" ] }, { "cell_type": "code", "execution_count": 5, "id": "8fa81fb7", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x = [0 1 2 3]\n", "x + 5 = [5 6 7 8]\n", "x - 5 = [-5 -4 -3 -2]\n", "x * 2 = [0 2 4 6]\n" ] } ], "source": [ "# simple vectorized functions \n", "x = np.arange(4)\n", "print(\"x =\", x)\n", "print(\"x + 5 =\", x + 5)\n", "print(\"x - 5 =\", x - 5)\n", "print(\"x * 2 =\", x * 2)" ] }, { "cell_type": "code", "execution_count": 6, "id": "84b8ac14", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x = [1, 2, 3]\n", "e^x = [ 2.71828183 7.3890561 20.08553692]\n", "2^x = [2. 4. 8.]\n", "3^x = [ 3 9 27]\n" ] } ], "source": [ "# exponents and logarithms\n", "x = [1, 2, 3]\n", "print(\"x =\", x)\n", "print(\"e^x =\", np.exp(x))\n", "print(\"2^x =\", np.exp2(x))\n", "print(\"3^x =\", np.power(3, x))" ] }, { "cell_type": "markdown", "id": "10ec3b82", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Mgrid" ] }, { "cell_type": "code", "execution_count": 7, "id": "289495f1", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "x = np.arange(1,10) # timepoints\n", "y = np.arange(-70, 100, 10) # voltage change\n", "\n", "# for loop solution\n", "xx, yy = np.zeros((len(x), len(y))), np.zeros((len(y), len(x)))\n", "for a, i in enumerate(x):\n", " xx[a] = np.repeat(i, len(y))\n", "\n", "for b, j in enumerate(y):\n", " yy[b] = np.repeat(j, len(x))\n", "yy = yy.T\n", "\n", "# 1-line mgrid solution\n", "# works like broadcasting\n", "XX, YY = np.mgrid[1:10:1, -70:100:10] # two arrays with shape (9,17); (len(x), len(y))" ] }, { "cell_type": "code", "execution_count": 8, "id": "25bce1f0", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig = plt.figure()\n", "ax = fig.add_subplot()\n", "ax.scatter(xx, yy)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "7b8a8d1e", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Hands on exercises\n", "\n", "- Open notebook exercises/numpy_vectorize.ipynb\n" ] }, { "cell_type": "code", "execution_count": null, "id": "1fb78b62", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.3" } }, "nbformat": 4, "nbformat_minor": 5 }