{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "S1_2_Numpy.ipynb", "provenance": [], "toc_visible": true, "include_colab_link": true }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "view-in-github", "colab_type": "text" }, "source": [ "\"Open" ] }, { "cell_type": "markdown", "source": [ "# Scientific Computing with `NumPy`" ], "metadata": { "id": "MyiDxofYIpEC" } }, { "cell_type": "markdown", "source": [ "![1280px-NumPy_logo_2020.svg.png](data:image/png;base64,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)" ], "metadata": { "id": "eO5PUDbQxFF4" } }, { "cell_type": "markdown", "source": [ "**Numpy** is the fundamental package for scientific computing with Python\n", "\n", "Website: https://numpy.org/\n", "\n", "GitHub: https://github.com/numpy/numpy" ], "metadata": { "id": "gOa6QUTgx6pG" } }, { "cell_type": "markdown", "source": [ "## Importing and Examining a New Package" ], "metadata": { "id": "YpN9ITCsyzTQ" } }, { "cell_type": "markdown", "source": [ "This will be our first experience with importing a package which is not part of the Python standard library." ], "metadata": { "id": "XMDjUdcyy17C" } }, { "cell_type": "code", "source": [ "import numpy as np" ], "metadata": { "id": "XTH2r-RIy4wN" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "What did we just do? We *imported* a package. This brings new variables (mostly functions) into our interpreter. We access them as follows." ], "metadata": { "id": "BoLrluOLy8o-" } }, { "cell_type": "code", "source": [ "# find out what is in our namespace\n", "dir()" ], "metadata": { "id": "eMjwKsQ4zB1n" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# find out what's in numpy\n", "dir(np)" ], "metadata": { "id": "6Pzxa_LqyEWq" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# find out what version we have\n", "np.__version__" ], "metadata": { "id": "Ud5-mbmxzHIz" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "There is no way we could explicitly learn/teach each of these functions.\n", "Therefore, the numpy documentation is crucial!\n", "\n", "https://numpy.org/doc/stable/reference/" ], "metadata": { "id": "cQO5bE3fzR8A" } }, { "cell_type": "markdown", "source": [ "\n", "## NDArrays" ], "metadata": { "id": "DqstYumlzYk_" } }, { "cell_type": "markdown", "source": [ "The core class is the numpy ndarray (n-dimensional array).\n", "\n", "The main difference between a numpy array an a more general data container such as `list` are the following:\n", "\n", "* Numpy arrays can have N dimensions (while `lists`, `tuples`, etc. only have 1)\n", "* Numpy arrays hold values of the same datatype (e.g. `int`, `float`), while `lists` can contain anything.\n", "* Numpy optimizes numerical operations on arrays. Numpy is *fast*!" ], "metadata": { "id": "-Gp2tbMpzfwJ" } }, { "cell_type": "code", "source": [ "from IPython.display import Image\n", "Image(url='http://docs.scipy.org/doc/numpy/_images/threefundamental.png')" ], "metadata": { "id": "IsR449NHznch" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# create an array from a list\n", "a = np.array([9,0,2,1,0])" ], "metadata": { "id": "7QZ3r1QGz0_q" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# find out the datatype\n", "a.dtype" ], "metadata": { "id": "TnuWVAETz81r" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# find out the shape\n", "a.shape" ], "metadata": { "id": "XQFjwyppz-zB" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# what is the shape\n", "type(a.shape)" ], "metadata": { "id": "4tG7sV8F0BCL" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# another array with a different datatype and shape\n", "b = np.array([[5,3,1,9],[9,2,3,0]], dtype=np.float64)\n", "\n", "# check dtype and shape\n", "b.dtype, b.shape" ], "metadata": { "id": "MvR8Fp4v0CXw" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "**Note**\n", "\n", "The fastest varying dimension is the last dimension! The outer level of the hierarchy is the first dimension. (This is called “c-style” indexing)" ], "metadata": { "id": "XhzNeMr10IaG" } }, { "cell_type": "markdown", "source": [ "## Array Creation" ], "metadata": { "id": "R5IGPWkN0Lw2" } }, { "cell_type": "markdown", "source": [ "There are lots of ways to create arrays." ], "metadata": { "id": "xIFpjR_k0TMM" } }, { "cell_type": "code", "source": [ "# create some uniform arrays\n", "c = np.zeros((9,9))\n", "d = np.ones((3,6,3), dtype=np.complex128)\n", "e = np.full((3,3), np.pi)\n", "e = np.ones_like(c)\n", "f = np.zeros_like(d)" ], "metadata": { "id": "AGhmRbTV0U5N" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "`arange` works very similar to `range`, but it populates the array “eagerly” (i.e. immediately), rather than generating the values upon iteration." ], "metadata": { "id": "teVvvR3K0Wv1" } }, { "cell_type": "code", "source": [ "np.arange(10)" ], "metadata": { "id": "siVUkgkY0eKX" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "`arange` is left inclusive, right exclusive, just like `range`,\n", "but also works with floating-point numbers." ], "metadata": { "id": "SH2ScrQW0isJ" } }, { "cell_type": "code", "source": [ "np.arange(2,4,0.25)" ], "metadata": { "id": "o5KX5EM30obn" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "A frequent need is to generate an array of N numbers, evenly spaced between two values. That is what `linspace` is for." ], "metadata": { "id": "NVwSS6kw0pwW" } }, { "cell_type": "code", "source": [ "np.linspace(2,4,20)" ], "metadata": { "id": "9czR_sB-0zrd" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# log spaced\n", "np.logspace(1,2,10)" ], "metadata": { "id": "HoKVMDyy01d_" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Numpy also has some utilities for helping us generate multi-dimensional arrays. `meshgrid` creates 2D arrays out of a combination of 1D arrays." ], "metadata": { "id": "mnwG4YU9031H" } }, { "cell_type": "code", "source": [ "x = np.linspace(-2*np.pi, 2*np.pi, 100)\n", "y = np.linspace(-np.pi, np.pi, 50)\n", "xx, yy = np.meshgrid(x, y)\n", "xx.shape, yy.shape" ], "metadata": { "id": "Ca7KhJAu1SC4" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Indexing" ], "metadata": { "id": "jxpFkeyX1TWd" } }, { "cell_type": "markdown", "source": [ "Basic indexing is similar to lists" ], "metadata": { "id": "5BD5fyHq1Wmo" } }, { "cell_type": "code", "source": [ "# get some individual elements of xx\n", "xx[0,0], xx[-1,-1], xx[3,-5]" ], "metadata": { "id": "xUpHG8-J1e8y" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# get some whole rows and columns\n", "xx[0].shape, xx[:,-1].shape" ], "metadata": { "id": "DKIcHeGl1gMq" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# get some ranges\n", "xx[3:10,30:40].shape" ], "metadata": { "id": "Z6hTG-gQ1hvY" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "There are many advanced ways to index arrays. You can [read about them](https://numpy.org/doc/stable/reference/arrays.indexing.html) in the manual. Here is one example." ], "metadata": { "id": "DGBuA2kQ1jS5" } }, { "cell_type": "code", "source": [ "# use a boolean array as an index\n", "idx = xx<0\n", "yy[idx].shape" ], "metadata": { "id": "DXNzxd7m2AWc" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# the array got flattened\n", "xx.ravel().shape" ], "metadata": { "id": "8fxal8712Byv" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Visualizing Arrays with Matplotlib" ], "metadata": { "id": "BUFFnj3e2DQA" } }, { "cell_type": "markdown", "source": [ "It can be hard to work with big arrays without actually seeing anything with our eyes! We will now bring in Matplotib to start visualizating these arrays. For now we will just skim the surface of Matplotlib. Much more depth will be provided in the next notebook." ], "metadata": { "id": "hfavOorK2GyH" } }, { "cell_type": "code", "source": [ "from matplotlib import pyplot as plt" ], "metadata": { "id": "JJttyGEw2JMG" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "For plotting a 1D array as a line, we use the `plot` command." ], "metadata": { "id": "5X2My4vq43Lz" } }, { "cell_type": "code", "source": [ "plt.plot(x)" ], "metadata": { "id": "Wp_aN7Yl465b" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "There are many ways to visualize 2D data. He we use `pcolormesh`." ], "metadata": { "id": "Mwu42gZq48zH" } }, { "cell_type": "code", "source": [ "plt.pcolormesh(xx)" ], "metadata": { "id": "mUMNhE3U5ALD" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "plt.pcolormesh(yy)" ], "metadata": { "id": "SKObF-8I5Ck8" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Array Operations" ], "metadata": { "id": "E7QGjxYR5EQ3" } }, { "cell_type": "markdown", "source": [ "There are a huge number of operations available on arrays. All the familiar arithemtic operators are applied on an element-by-element basis." ], "metadata": { "id": "NLI1NnH25LmT" } }, { "cell_type": "markdown", "source": [ "### Basic Math" ], "metadata": { "id": "6H3j9aNy5Not" } }, { "cell_type": "code", "source": [ "f = np.sin(xx) * np.cos(0.5*yy)" ], "metadata": { "id": "H_UzxfKi5QMR" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "plt.pcolormesh(f)" ], "metadata": { "id": "ErTACPHh5RNV" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "### Manipulating Array Dimensions" ], "metadata": { "id": "7XlSuedn5SYv" } }, { "cell_type": "markdown", "source": [ "Swapping the dimension order is accomplished by calling `transpose`." ], "metadata": { "id": "bvdIloeH5VvG" } }, { "cell_type": "code", "source": [ "f_transposed = f.transpose()\n", "plt.pcolormesh(f_transposed)" ], "metadata": { "id": "U4Hr-7o25bmo" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "We can also manually change the shape of an array… as long as the new shape has the same number of elements." ], "metadata": { "id": "namRwhmd5eha" } }, { "cell_type": "code", "source": [ "g = np.reshape(f, (8,9))" ], "metadata": { "id": "EsXbyvFi5hI0" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "However, be careful with reshaping data! You can accidentally lose the structure of the data." ], "metadata": { "id": "QGfZvloR5kQT" } }, { "cell_type": "code", "source": [ "g = np.reshape(f, (200,25))\n", "plt.pcolormesh(g)" ], "metadata": { "id": "9cvae1W85pA8" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "We can also “tile” an array to repeat it many times." ], "metadata": { "id": "Xuzh7ved5qWs" } }, { "cell_type": "code", "source": [ "f_tiled = np.tile(f,(3, 2))\n", "plt.pcolormesh(f_tiled)" ], "metadata": { "id": "d-pl13Sc7C9l" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Another common need is to add an extra dimension to an array. This can be accomplished via indexing with `None`." ], "metadata": { "id": "iOJg0CvD7EJB" } }, { "cell_type": "code", "source": [ "x.shape" ], "metadata": { "id": "Ceb8XgSK7IQA" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "x[None, :].shape" ], "metadata": { "id": "m8JCLxTm7Jkk" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "x[None, :, None, None].shape" ], "metadata": { "id": "1uUW24wT7Kjn" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Broadcasting" ], "metadata": { "id": "adiNcUPp7Lkr" } }, { "cell_type": "markdown", "source": [ "Not all the arrays we want to work with will have the same size. One approach would be to manually “expand” our arrays to all be the same size, e.g. using `tile`. *Broadcasting* is a more efficient way to multiply arrays of different sizes Numpy has specific rules for how broadcasting works. These can be confusing but are worth learning if you plan to work with Numpy data a lot." ], "metadata": { "id": "wlt3_Eyt7Zyr" } }, { "cell_type": "markdown", "source": [ "The core concept of broadcasting is telling Numpy which dimensions are supposed to line up with each other." ], "metadata": { "id": "HhIvFyYC7gsL" } }, { "cell_type": "code", "source": [ "Image(url='http://scipy-lectures.github.io/_images/numpy_broadcasting.png',\n", " width=720)" ], "metadata": { "id": "1CeXfc517pnP" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "Dimensions are automatically aligned *starting with the last dimension*. If the last two dimensions have the same length, then the two arrays can be broadcast." ], "metadata": { "id": "AyqfBTLH7r6n" } }, { "cell_type": "code", "source": [ "print(f.shape, x.shape)\n", "g = f * x\n", "print(g.shape)" ], "metadata": { "id": "XnE3mFfD7yDq" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "plt.pcolormesh(g)" ], "metadata": { "id": "H8XeOTma-wHt" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "However, if the last two dimensions are *not* the same, Numpy cannot just automatically figure it out." ], "metadata": { "id": "Tu2A4Q_5-xZe" } }, { "cell_type": "code", "source": [ "# multiply f by y\n", "print(f.shape, y.shape)\n", "h = f * y" ], "metadata": { "id": "GLDWYS1X-35T" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "We can help numpy by adding an extra dimension to `y` at the end. Then the length-50 dimensions will line up." ], "metadata": { "id": "GXOfcm4U-5dt" } }, { "cell_type": "code", "source": [ "print(f.shape, y[:, None].shape)\n", "h = f * y[:, None]\n", "print(h.shape)" ], "metadata": { "id": "utD_kxl2-73_" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "plt.pcolormesh(h)" ], "metadata": { "id": "tpTw9B_s-_T_" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "\n", "## Reduction Operations" ], "metadata": { "id": "TI2IdcyZ_A-B" } }, { "cell_type": "markdown", "source": [ "In scientific data analysis, we usually start with a lot of data and want to reduce it down in order to make plots of summary tables. Operations that reduce the size of numpy arrays are called “reductions”. There are many different reduction operations. Here we will look at some of the most common ones." ], "metadata": { "id": "iSs5V3Rr_F4S" } }, { "cell_type": "code", "source": [ "# sum\n", "g.sum()" ], "metadata": { "id": "q7DDAwoi_Jac" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# mean\n", "g.mean()" ], "metadata": { "id": "rjp3WnND_LZX" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# standard deviation\n", "g.std()" ], "metadata": { "id": "_zZ6M73c_MmS" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "A key property of numpy reductions is the ability to operate on just one axis." ], "metadata": { "id": "ooAtQGpS_Nvk" } }, { "cell_type": "code", "source": [ "# apply on just one axis\n", "g_ymean = g.mean(axis=0)\n", "g_xmean = g.mean(axis=1)" ], "metadata": { "id": "YiBjIdFB_Qcc" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "plt.plot(x, g_ymean)" ], "metadata": { "id": "5yLYM58L_Rou" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "plt.plot(g_xmean, y)" ], "metadata": { "id": "coQxmUi7_SlI" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "\n", "## Data Files" ], "metadata": { "id": "bb_14NVY_UgV" } }, { "cell_type": "markdown", "source": [ "It can be useful to save numpy data into files." ], "metadata": { "id": "bgcm4Wji_WkQ" } }, { "cell_type": "code", "source": [ "np.save('g.npy', g)" ], "metadata": { "id": "Pbm9DyDs_YIS" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "**Warning**\n", "\n", "Numpy `.npy` files are a convenient way to store temporary data, but they are not considered a robust archival format. Later we will learn about NetCDF, the recommended way to store earth and environmental data." ], "metadata": { "id": "g9G52zZg_aIY" } }, { "cell_type": "code", "source": [ "g_loaded = np.load('g.npy')\n", "\n", "np.testing.assert_equal(g, g_loaded)" ], "metadata": { "id": "6LR5ugEB_gND" }, "execution_count": null, "outputs": [] } ] }