{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# More on NumPy Arrays: Slicing and `np.linalg`\n", "\n", "## Overview, Objectives, and Key Terms\n", " \n", "In this lesson, we'll continue our investigation started in [Lesson 3](ME400_Lecture_3.ipynb) and look multidimensional arrays and how to access multiple elements via *slicing*. \n", "\n", "### Objectives\n", "\n", "By the end of this lesson, you should be able to\n", "\n", "- *define and manipulate two-dimensional NumPy arrays*\n", "- *visualize two-dimensional arrays*\n", "- *slicing and other indexing of one- and two-dimensional arrays*\n", "\n", "### Key Terms\n", "\n", "- `np.ones` (for 2-D arrays)\n", "- `np.zeros` (for 2-D arrays)\n", "- `np.array` (for 2-D arrays)\n", "- `np.meshgrid`\n", "- `plt.contour`\n", "- `plt.contourf`\n", "- `plt.colorbar`\n", "- colormap\n", "- slice\n", "- stride\n", "- `np.reshape`\n", "- `np.random.rand`\n", "- matrix-vector multiplication\n", "- `np.dot` (for 2-D arrays)\n", "- `np.matmul`" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from IPython.core.interactiveshell import InteractiveShell \n", "InteractiveShell.ast_node_interactivity = \"all\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Making Two-Dimensional Arrays\n", "\n", "A lot of data lives in tabulated structures that are logically equivalent to two-dimensional arrays. We actually saw that in [Lesson 3](ME400_Lecture_3.ipynb) with our time, velocity, and acceleration example. When loaded in via `np.loadtxt`, that data was stored as an array having a shape of `(3, 10)`.\n", "\n", "We can make such two-dimensional arrays. The easiest ways are the `np.ones` and `np.zeros` functions, e.g.," ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 1., 1.],\n", " [1., 1., 1.],\n", " [1., 1., 1.]])" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "A = np.ones((3, 3))\n", "A" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0., 0., 0.],\n", " [0., 0., 0.],\n", " [0., 0., 0.]])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B = np.zeros((3, 3))\n", "B" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can access and modify individual elements of these arrays just like we can their one-dimensional cousins. For example, let's change the lower-right element of `B` to 99:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0., 0., 0.],\n", " [ 0., 0., 0.],\n", " [99., 0., 0.]])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B[2, 0] = 99\n", "B" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When indexing a two-dimensional array, the syntax is always like `B[i, j]`, where `i` is the *row* and `j` is the *column*. \n", "\n", "Two-dimensional arrays can also be made directly from existing data, e.g.," ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C = np.array([[1, 2], \n", " [3, 4]]) # By splitting this line, the structure is much easier to see.\n", "C" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the input to `np.array` is `[[1, 2], [3, 4]]`, which is actually a `list` with elements that are themselves `list`'s. The key is that we need each row to have the form `[x, y, ...]`, and all rows need to be separated by commas and surrounded by an additional pair of `[]`'s." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Recall that often we need to evaluate a function $f(x)$ at evenly-spaced points in some range. The same is true in two and three dimensions. We'll stick in 2-D for now and consider evaluation of the two-dimensional function \n", "\n", "$$\n", "f(x, y) = (x + 2y + 7)^2 + (2x + y - 5)^2\n", "$$\n", "\n", "which is known as [Booth's function](https://www.sfu.ca/~ssurjano/booth.html). Here, we want to evaluate $f(x, y)$ for $x, y \\in [-10, 10]$. First, we'll define the arrays `x` and `y` using evenly-spaced points in the range $[-10, 10]$. " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "x = np.linspace(-10, 10, 5) \n", "y = np.linspace(-10, 10, 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, imagine these points as defining a *grid* in the $xy$ plane. How can we evaluate $f(x, y)$ at each possible pair of points $(x_i, y_j)$? The \"programming\" approach---and one we'll learn later---would be to employ *loops*. However, NumPy provides an easy and *efficient* way to do this for us in its `np.meshgrid` function." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-10., -5., 0., 5., 10.],\n", " [-10., -5., 0., 5., 10.],\n", " [-10., -5., 0., 5., 10.],\n", " [-10., -5., 0., 5., 10.],\n", " [-10., -5., 0., 5., 10.]])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xx, yy = np.meshgrid(x, y) \n", "xx" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-10., -10., -10., -10., -10.],\n", " [ -5., -5., -5., -5., -5.],\n", " [ 0., 0., 0., 0., 0.],\n", " [ 5., 5., 5., 5., 5.],\n", " [ 10., 10., 10., 10., 10.]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "yy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that these new arrays (named `xx` and `yy` so that we don't *overwrite* `x` and `y`) are two dimensional. However, by marching through, for example, the top rows, we see that the resulting pairs of numbers are $(-10, -10)$, $(-5, -10)$, $(0, -10)$ and so on. Hence, all of the 5 possible values of $x$ are paired with the value $y = -10$ (first row) and then $y = -5$ (second row), etc.\n", "\n", "We can now evaluate the desired function." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1754., 949., 394., 89., 34.],\n", " [1069., 464., 109., 4., 149.],\n", " [ 634., 229., 74., 169., 514.],\n", " [ 449., 244., 289., 584., 1129.],\n", " [ 514., 509., 754., 1249., 1994.]])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = (xx + 2*yy + 7)**2 + (2*xx + yy - 5)**2\n", "f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualizing 2-D Arrays\n", "\n", "We saw in [Lesson 3](ME400_Lecture_3.ipynb) how easily one can produce a plot of 1-D data (in the form of NumPy arrays) by using Matplotlib. We can also visualize 2-D data. First, let's give ourselves a somewhat richer set of data to visualize by increasing the number of $x$ and $y$ points we use to evaluate $f(x, y)$." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "x, y = np.linspace(-10, 10, 100), np.linspace(-10, 10, 100)\n", "# note how two assignments can be written in one line \n", "xx, yy = np.meshgrid(x, y)\n", "f = (xx + 2*yy + 7)**2 + (2*xx + yy - 5)**2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One way to visualize $f(x, y)$ is through use of *[contour](http://www.itl.nist.gov/div898/handbook/eda/section3/contour.htm)* plots. Matplotlib offers two versions of a contour plot: `plt.contour` and `plt.contourf`, where the latter is a \"filled\" version. Here they are for our data:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "Text(0.5,0,'x')" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "Text(0,0.5,'y')" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "Text(0.5,1,\"Booth's function via plt.contour\")" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "plt.contour(x, y, f)\n", "plt.xlabel('x')\n", "plt.ylabel('y')\n", "plt.title(\"Booth's function via plt.contour\") # Sometimes, a title is useful if no caption can be provided.\n", "plt.colorbar() # The colorbar function produces the color legend at the right.\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "Text(0.5,0,'x')" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "Text(0,0.5,'y')" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "Text(0.5,1,\"Booth's function via plt.contourf\")" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.contourf(x, y, f, cmap=plt.cm.inferno)\n", "plt.xlabel('x')\n", "plt.ylabel('y')\n", "plt.title(\"Booth's function via plt.contourf\") \n", "plt.colorbar()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, I've added the `cmap` argument to `plt.contourf`, which changes the colormap (i.e., color scheme) of the image. Matplotlib provides [dozens of options](https://matplotlib.org/examples/color/colormaps_reference.html), but it's strongly recommended to use one of the \"perceptually uniform sequential\" colormaps, which provide good contrast in black and white and are more easily interpreted by folks with colorblindness than more traditional colormaps like \"jet.\"\n", "\n", "Other functions of interest include `plt.pcolor` and `plt.imshow`, which are left to the reader to explore using `help` and online documentation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Slicing\n", "\n", "Now we turn to a useful operation known as *slicing*, a process by which we can access more than one element of an array. We'll find that slicing is also applicable to other data types, including the container types `list` and `tuple` that will be explored later on.\n", "\n", "### Slicing in 1-D\n", "\n", "For starters, let's create a one dimensional array of the numbers $0, 1, \\ldots, 9$:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "a = np.arange(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We already saw that individual elements of an array like `a` can be accessed via the `[]` operator, e.g., `a[2]` gives us the third element (because numbering starts at zero). Suppose we want to define a new array `b` that has the first three elements of `a`. We can *slice* `a` by doing" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "b = a[0:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the `:` is the key, and the syntax `0:3` can be read as `from 0 up to but not including 3`. That's key: we get `a[0]`, `a[1]`, and `a[2]`, but *not* `a[3]`.\n", "\n", "> **Note**. Basic slicing of an array `a` has the form `a[start:end]`, where the second number `end` is one plus the location of the last element desired." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The slicing syntax also allows a third number called the *stride*. For example, a stride of two lets one select only every other element. Here, we can get let `c` be all the even-indexed elements of `a`:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "c = a[0:10:2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again, the syntax `0:10:2` can be read as `from 0 up to 10, skipping every other element`. \n", "\n", "\n", "There are a couple of shortcuts one can use in slicing. For example, each of the three numbers has a *default* value. The starting value defaults to the beginning of the array, i.e., element zero, while the ending value defaults to the length of the array. The stride, by default, is one, which means no elements are skipped. When the stride is not defined, the second `:` can be omitted. Because these defaults are defined, the following are equivalent:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[0:10:1]\n", "a[0:10]\n", "a[:10:1]\n", "a[0::1]\n", "a[0::]\n", "a[:10:]\n", "a[::1]\n", "a[::]\n", "a[:]\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Note**. The complete slicing syntax for an array `a` is `a[start:end:stride]`. By default, `start = 0`, `end = len(a)`, and `stride = 1`. Hence, any or all of `start`, `end`, and `stride` may be omitted. When `stride` is omitted, the second `:` may also be omitted." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Slicing of NumPy arrays provides not just access to selected elements: it also lets one modify those elements. Given the zeros array" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "z = np.zeros(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "we can set all the odd elements to unity" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "z[1::2] = 1.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could then set the even elements to $1, 2, 3, 4, 5$ via" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "z[::2] = np.arange(1, 6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "because `z[::2]` and `np.arange(5)` have the same length---we'd get an error otherwise!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slicing in 2-D\n", "\n", "Slicing applies equally to two-dimensional arrays. Consider the following code, in which the 1-D array of numbers `0, 1, 2, \\ldots 24` is reshaped into a square 2-D array:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3, 4],\n", " [ 5, 6, 7, 8, 9],\n", " [10, 11, 12, 13, 14],\n", " [15, 16, 17, 18, 19],\n", " [20, 21, 22, 23, 24]])" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "D = np.arange(25).reshape((5, 5))\n", "D" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just as we can access individual elements of a 1-D array, so too can we access an element of a 2-D array. Here, to get the first element of the first row, we would use" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "D[0, 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want the whole first row, we can replace the column index by a `:`, i.e.," ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "D[0, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and similarly for the first column," ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 5, 10, 15, 20])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "D[:, 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same syntax used in 1-D, i.e., `start:end:stride` works for the row and column indices of a 2-D array independently. For example, we can double the elements of the odd columns (i.e., columns 1 and 3) of `D` by using" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "D[:, 1::2] *= 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Other Indexing\n", "\n", "Slicing is extremely powerful, but there are [other ways](https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#arrays-indexing) to access elements of an array that are particularly well suited to special applications. One method that is useful when processing tabulated data is based on conditional selection of array elements. \n", "\n", "Consider the following two-dimensional array, in which the elements are random numbers distributed evenly between 0 and 1:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0.94186834, 0.64547139, 0.15322779, 0.16304291, 0.4661734 ],\n", " [0.87379668, 0.81482831, 0.28383103, 0.59685898, 0.89252992],\n", " [0.52517944, 0.79366051, 0.55013028, 0.84990704, 0.81530478],\n", " [0.32832184, 0.33208004, 0.26212632, 0.61609737, 0.89364675],\n", " [0.29166547, 0.47505599, 0.02964755, 0.27334342, 0.40288735]])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E = np.random.rand(5, 5)\n", "E" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The array `E` will, by default, be different every time this line is executed, but on the average, half the elements will be greater than 0.5. How can we select those elements? We can do so with the comparison operator `>`. For example, we can get a boolean map of the elements of `E` that are larger than 0.5 via" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ True, True, False, False, False],\n", " [ True, True, False, True, True],\n", " [ True, True, True, True, True],\n", " [False, False, False, True, True],\n", " [False, False, False, False, False]])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E > 0.5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The actual elements that satisfy that criterion can be accessed with" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.94186834, 0.64547139, 0.87379668, 0.81482831, 0.59685898,\n", " 0.89252992, 0.52517944, 0.79366051, 0.55013028, 0.84990704,\n", " 0.81530478, 0.61609737, 0.89364675])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E[E > 0.5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If, for example, we want to change all of those elements to 1.0, we could do" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1. , 1. , 0.15322779, 0.16304291, 0.4661734 ],\n", " [1. , 1. , 0.28383103, 1. , 1. ],\n", " [1. , 1. , 1. , 1. , 1. ],\n", " [0.32832184, 0.33208004, 0.26212632, 1. , 1. ],\n", " [0.29166547, 0.47505599, 0.02964755, 0.27334342, 0.40288735]])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E[E > 0.5] = 1.0\n", "E" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The basic ingredients for this approach are an array of interest (here, that's `E`) and an array of the same size that has elements of the `bool` type. Most often, the array of `bool`'s comes from a conditional statement involving the original array (e.g., `E > 0.5`). However, we can also creat them explicitly. To get the second and fifth element of `np.arange(5)`, we could do" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 4])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.arange(5)[np.array([False, True, False, False, True])]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Matrix-Vector and Matrix-Matrix Operations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a final topic for our introduction to Python \"as a calculator\" is its use---via NumPy--for handling matrix and vector operations. We've not seen ways to create and manipulate one- and two-dimensional arrays. In [Lesson 3](ME400_Lecture_3.ipynb), `np.dot` was introduced for dot (sometimes scalar or inner) products of vectors (represented by `ndarray`'s). \n", "\n", "### Matrix-Vector Multiplication\n", "\n", "In NumPy, `np.dot` can also be used for matrix-vector multiplication. First, recall that the multiplication of an $m \\times n$ matrix $\\mathbf{A}$ by a $n \\times 1$ vector $\\mathbf{v}$ is defined formally as\n", "\n", "$$\n", "\\begin{bmatrix} \n", " a_{0,0} & a_{0,1} & \\cdots & a_{0,n-1} \\\\\n", " a_{1,0} & a_{1,1} & \\cdots & a_{1,n-1} \\\\\n", " \\vdots & \\vdots & \\ddots & \\vdots \\\\\n", " a_{m-1,0} & a_{m,2} & \\cdots & a_{m,n} \n", "\\end{bmatrix} \n", "\\times \n", "\\left[ \\begin{array}{c} \n", " v_0 \\\\ \n", " v_1 \\\\\n", " \\vdots \\\\\n", " v_{n-1} \n", " \\end{array} \\right] = \n", " \\left[ \\begin{array}{c} \n", " \\sum_{j=0}^{n-1} A_{0, j} v_j \\\\ \n", " \\sum_{j=0}^{n-1} A_{1, j} v_j \\\\\n", " \\vdots \\\\\n", " \\sum_{j=0}^{n-1} A_{m-1, j} v_j \\end{array} \\right]\n", "$$\n", "\n", "where the indices start at zero and end with $m-1$ or $n-1$ for consistency with Python indexing. Note that the result on the right-hand side is an $m \\times 1$ vector. Its $i$th element has the form $\\sum_{j=0}^{n-1} A_{i, j} v_j$, which is just the dot product of the vector $\\mathbf{v}$ and the vector formed by $i$th row of $\\mathbf{A}$. In other words, matrix-vector multiplication is just a sequence of dot products.\n", "\n", "Let's try an example. First, let us construct a two-dimensional array to represent the following matrix:\n", "\n", "$$\n", "\\mathbf{A} = \n", "\\begin{bmatrix} \n", " 2 & -1 & 0 & 0 & 0 \\\\\n", " -1 & 2 & -1 & 0 & 0 \\\\\n", " 0 & -1 & 2 & -1 & 0 \\\\\n", " 0 & 0 & -1 & 2 & -1 \\\\\n", " 0& 0 & 0 & -1 & 2 \n", "\\end{bmatrix} \n", "$$\n", "\n", "In NumPy, one pretty nifty way to do that is" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 2., -1., 0., 0., 0.],\n", " [-1., 2., -1., 0., 0.],\n", " [ 0., -1., 2., -1., 0.],\n", " [ 0., 0., -1., 2., -1.],\n", " [ 0., 0., 0., -1., 2.]])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = 2*np.diag(np.ones(5)) - np.diag(np.ones(4), -1) - np.diag(np.ones(4), 1)\n", "A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "although there are other ways that would work, too. We'll multiply $\\mathbf{A}$ by $\\mathbf{v}$, a $5 \\times 1$ vector of ones, which we can represent as the NumPy array" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "v = np.ones(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The matrix-vector product can be computed via" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1., 0., 0., 0., 1.])" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.dot(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Admittedly, use of `dot` for matrix-vector multiplication is somewhat unintuitive. For many years, that's all NumPy offered. In recent versions, the `matmul` function was added, which lets us do the same thing:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1., 0., 0., 0., 1.])" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.matmul(A, v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrix-Matrix Multiplication\n", "\n", "Both approached work just fine, and both can also be used to compute a matrix-matrix product (which is defined in much the same way as the matrix-vector product). For example, $A \\times A$ can be computed using" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 5., -4., 1., 0., 0.],\n", " [-4., 6., -4., 1., 0.],\n", " [ 1., -4., 6., -4., 1.],\n", " [ 0., 1., -4., 6., -4.],\n", " [ 0., 0., 1., -4., 5.]])" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.dot(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 5., -4., 1., 0., 0.],\n", " [-4., 6., -4., 1., 0.],\n", " [ 1., -4., 6., -4., 1.],\n", " [ 0., 1., -4., 6., -4.],\n", " [ 0., 0., 1., -4., 5.]])" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.matmul(A, A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Linear Systems\n", "\n", "Beyond dot products and matrix-vector products, a key task involving matrices and vectors is the solution of linear systems. Such systems are essential to much engineering analysis, and often, they are best represented using matrices and vectors. Consider the particular set of equations\n", "\n", "$$\n", "2 x + 3 y = 1 \\\\\n", "3 x + y = 2 \\, .\n", "$$\n", "\n", "In matrix-vector form, these equations can be written\n", "\n", "$$\n", "\\begin{bmatrix} \n", " 2 & 3 \\\\\n", " 3 & 1\n", "\\end{bmatrix} \n", "\\times\n", "\\left[ \\begin{array}{c} \n", " x \\\\ \n", " y \n", " \\end{array} \\right] = \n", "\\left[ \\begin{array}{c} \n", " 1 \\\\ \n", " 2 \n", " \\end{array} \\right] \\, .\n", "$$\n", "\n", "Using NumPy, we can solve this system via just a few lines of code:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.7142857142857143" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "-0.14285714285714282" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# define the system matrix\n", "A = np.array([[2, 3], [3, 1]])\n", "# define the right-hand side\n", "b = np.array([1, 2])\n", "# solve the system\n", "sol = np.linalg.solve(A, b)\n", "# extract the elements that represent x and y and display\n", "x, y = sol\n", "x\n", "y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a final comment, one will readily find that NumPy does include a `matrix` type. Although `matrix` does offer some nice features (e.g., `*` can be used in place of `dot` or `matmul`), one loses some of the expected element-wise and other behavior of `ndarray` functions. \n", "\n", "> **Note**: Be aware that `np.matrix` exists, but feel encouraged to use `np.ndarray` for both one- and two-dimensional array, vector, and/or matrix operations." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Further Reading\n", "\n", "More details on array indexing can be found in the [NumPy documentation](https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#arrays-indexing)." ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "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.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }