{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# The Basics of NumPy Arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Data manipulation in Python is nearly synonymous with NumPy array manipulation: even newer tools like Pandas ([Part 3](03.00-Introduction-to-Pandas.ipynb)) are built around the NumPy array.\n", "This chapter will present several examples of using NumPy array manipulation to access data and subarrays, and to split, reshape, and join the arrays.\n", "While the types of operations shown here may seem a bit dry and pedantic, they comprise the building blocks of many other examples used throughout the book.\n", "Get to know them well!\n", "\n", "We'll cover a few categories of basic array manipulations here:\n", "\n", "- *Attributes of arrays*: Determining the size, shape, memory consumption, and data types of arrays\n", "- *Indexing of arrays*: Getting and setting the values of individual array elements\n", "- *Slicing of arrays*: Getting and setting smaller subarrays within a larger array\n", "- *Reshaping of arrays*: Changing the shape of a given array\n", "- *Joining and splitting of arrays*: Combining multiple arrays into one, and splitting one array into many" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## NumPy Array Attributes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First let's discuss some useful array attributes.\n", "We'll start by defining random arrays of one, two, and three dimensions.\n", "We'll use NumPy's random number generator, which we will *seed* with a set value in order to ensure that the same random arrays are generated each time this code is run:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "import numpy as np\n", "rng = np.random.default_rng(seed=1701) # seed for reproducibility\n", "\n", "x1 = rng.integers(10, size=6) # one-dimensional array\n", "x2 = rng.integers(10, size=(3, 4)) # two-dimensional array\n", "x3 = rng.integers(10, size=(3, 4, 5)) # three-dimensional array" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each array has attributes including `ndim` (the number of dimensions), `shape` (the size of each dimension), `size` (the total size of the array), and `dtype` (the type of each element):" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x3 ndim: 3\n", "x3 shape: (3, 4, 5)\n", "x3 size: 60\n", "dtype: int64\n" ] } ], "source": [ "print(\"x3 ndim: \", x3.ndim)\n", "print(\"x3 shape:\", x3.shape)\n", "print(\"x3 size: \", x3.size)\n", "print(\"dtype: \", x3.dtype)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more discussion of data types, see [Understanding Data Types in Python](02.01-Understanding-Data-Types.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Array Indexing: Accessing Single Elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you are familiar with Python's standard list indexing, indexing in NumPy will feel quite familiar.\n", "In a one-dimensional array, the $i^{th}$ value (counting from zero) can be accessed by specifying the desired index in square brackets, just as with Python lists:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([9, 4, 0, 3, 8, 6])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[0]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[4]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To index from the end of the array, you can use negative indices:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[-1]" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[-2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In a multidimensional array, items can be accessed using a comma-separated `(row, column)` tuple:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[3, 1, 3, 7],\n", " [4, 0, 2, 3],\n", " [0, 0, 6, 9]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[0, 0]" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[2, 0]" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[2, -1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Values can also be modified using any of the preceding index notation:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[12, 1, 3, 7],\n", " [ 4, 0, 2, 3],\n", " [ 0, 0, 6, 9]])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[0, 0] = 12\n", "x2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Keep in mind that, unlike Python lists, NumPy arrays have a fixed type.\n", "This means, for example, that if you attempt to insert a floating-point value into an integer array, the value will be silently truncated. Don't be caught unaware by this behavior!" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([3, 4, 0, 3, 8, 6])" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[0] = 3.14159 # this will be truncated!\n", "x1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Array Slicing: Accessing Subarrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just as we can use square brackets to access individual array elements, we can also use them to access subarrays with the *slice* notation, marked by the colon (`:`) character.\n", "The NumPy slicing syntax follows that of the standard Python list; to access a slice of an array `x`, use this:\n", "``` python\n", "x[start:stop:step]\n", "```\n", "If any of these are unspecified, they default to the values `start=0`, `stop=`, `step=1`.\n", "Let's look at some examples of accessing subarrays in one dimension and in multiple dimensions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### One-Dimensional Subarrays\n", "\n", "Here are some examples of accessing elements in one-dimensional subarrays:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([3, 4, 0, 3, 8, 6])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([3, 4, 0])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[:3] # first three elements" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([3, 8, 6])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[3:] # elements after index 3" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([4, 0, 3])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[1:4] # middle subarray" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([3, 0, 8])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[::2] # every second element" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([4, 3, 6])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[1::2] # every second element, starting at index 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A potentially confusing case is when the `step` value is negative.\n", "In this case, the defaults for `start` and `stop` are swapped.\n", "This becomes a convenient way to reverse an array:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([6, 8, 3, 0, 4, 3])" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[::-1] # all elements, reversed" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([8, 0, 3])" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1[4::-2] # every second element from index 4, reversed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Multidimensional Subarrays\n", "\n", "Multidimensional slices work in the same way, with multiple slices separated by commas.\n", "For example:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[12, 1, 3, 7],\n", " [ 4, 0, 2, 3],\n", " [ 0, 0, 6, 9]])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[12, 1, 3],\n", " [ 4, 0, 2]])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[:2, :3] # first two rows & three columns" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[12, 3],\n", " [ 4, 2],\n", " [ 0, 6]])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[:3, ::2] # three rows, every second column" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[ 9, 6, 0, 0],\n", " [ 3, 2, 0, 4],\n", " [ 7, 3, 1, 12]])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[::-1, ::-1] # all rows & columns, reversed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Accessing array rows and columns\n", "\n", "One commonly needed routine is accessing single rows or columns of an array.\n", "This can be done by combining indexing and slicing, using an empty slice marked by a single colon (`:`):" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([12, 4, 0])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[:, 0] # first column of x2" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([12, 1, 3, 7])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[0, :] # first row of x2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the case of row access, the empty slice can be omitted for a more compact syntax:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([12, 1, 3, 7])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x2[0] # equivalent to x2[0, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Subarrays as No-Copy Views\n", "\n", "Unlike Python list slices, NumPy array slices are returned as *views* rather than *copies* of the array data.\n", "Consider our two-dimensional array from before:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[12 1 3 7]\n", " [ 4 0 2 3]\n", " [ 0 0 6 9]]\n" ] } ], "source": [ "print(x2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's extract a $2 \\times 2$ subarray from this:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[12 1]\n", " [ 4 0]]\n" ] } ], "source": [ "x2_sub = x2[:2, :2]\n", "print(x2_sub)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now if we modify this subarray, we'll see that the original array is changed! Observe:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[99 1]\n", " [ 4 0]]\n" ] } ], "source": [ "x2_sub[0, 0] = 99\n", "print(x2_sub)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[99 1 3 7]\n", " [ 4 0 2 3]\n", " [ 0 0 6 9]]\n" ] } ], "source": [ "print(x2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some users may find this surprising, but it can be advantageous: for example, when working with large datasets, we can access and process pieces of these datasets without the need to copy the underlying data buffer." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating Copies of Arrays\n", "\n", "Despite the nice features of array views, it is sometimes useful to instead explicitly copy the data within an array or a subarray. This can be most easily done with the `copy` method:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[99 1]\n", " [ 4 0]]\n" ] } ], "source": [ "x2_sub_copy = x2[:2, :2].copy()\n", "print(x2_sub_copy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we now modify this subarray, the original array is not touched:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[42 1]\n", " [ 4 0]]\n" ] } ], "source": [ "x2_sub_copy[0, 0] = 42\n", "print(x2_sub_copy)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[99 1 3 7]\n", " [ 4 0 2 3]\n", " [ 0 0 6 9]]\n" ] } ], "source": [ "print(x2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reshaping of Arrays\n", "\n", "Another useful type of operation is reshaping of arrays, which can be done with the `reshape` method.\n", "For example, if you want to put the numbers 1 through 9 in a $3 \\times 3$ grid, you can do the following:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1 2 3]\n", " [4 5 6]\n", " [7 8 9]]\n" ] } ], "source": [ "grid = np.arange(1, 10).reshape(3, 3)\n", "print(grid)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that for this to work, the size of the initial array must match the size of the reshaped array, and in most cases the `reshape` method will return a no-copy view of the initial array." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A common reshaping operation is converting a one-dimensional array into a two-dimensional row or column matrix:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3]])" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.array([1, 2, 3])\n", "x.reshape((1, 3)) # row vector via reshape" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1],\n", " [2],\n", " [3]])" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.reshape((3, 1)) # column vector via reshape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A convenient shorthand for this is to use `np.newaxis` in the slicing syntax:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3]])" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[np.newaxis, :] # row vector via newaxis" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[1],\n", " [2],\n", " [3]])" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:, np.newaxis] # column vector via newaxis" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a pattern that we will utilize often throughout the remainder of the book." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Array Concatenation and Splitting\n", "\n", "All of the preceding routines worked on single arrays. NumPy also provides tools to combine multiple arrays into one, and to conversely split a single array into multiple arrays." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Concatenation of Arrays\n", "\n", "Concatenation, or joining of two arrays in NumPy, is primarily accomplished using the routines `np.concatenate`, `np.vstack`, and `np.hstack`.\n", "`np.concatenate` takes a tuple or list of arrays as its first argument, as you can see here:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 3, 2, 1])" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.array([1, 2, 3])\n", "y = np.array([3, 2, 1])\n", "np.concatenate([x, y])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also concatenate more than two arrays at once:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 1 2 3 3 2 1 99 99 99]\n" ] } ], "source": [ "z = np.array([99, 99, 99])\n", "print(np.concatenate([x, y, z]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And it can be used for two-dimensional arrays:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "grid = np.array([[1, 2, 3],\n", " [4, 5, 6]])" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3],\n", " [4, 5, 6],\n", " [1, 2, 3],\n", " [4, 5, 6]])" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# concatenate along the first axis\n", "np.concatenate([grid, grid])" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3, 1, 2, 3],\n", " [4, 5, 6, 4, 5, 6]])" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# concatenate along the second axis (zero-indexed)\n", "np.concatenate([grid, grid], axis=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For working with arrays of mixed dimensions, it can be clearer to use the `np.vstack` (vertical stack) and `np.hstack` (horizontal stack) functions:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3],\n", " [1, 2, 3],\n", " [4, 5, 6]])" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# vertically stack the arrays\n", "np.vstack([x, grid])" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, 2, 3, 99],\n", " [ 4, 5, 6, 99]])" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# horizontally stack the arrays\n", "y = np.array([[99],\n", " [99]])\n", "np.hstack([grid, y])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, for higher-dimensional arrays, `np.dstack` will stack arrays along the third axis." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Splitting of Arrays\n", "\n", "The opposite of concatenation is splitting, which is implemented by the functions `np.split`, `np.hsplit`, and `np.vsplit`. For each of these, we can pass a list of indices giving the split points:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 2 3] [99 99] [3 2 1]\n" ] } ], "source": [ "x = [1, 2, 3, 99, 99, 3, 2, 1]\n", "x1, x2, x3 = np.split(x, [3, 5])\n", "print(x1, x2, x3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that *N* split points leads to *N* + 1 subarrays.\n", "The related functions `np.hsplit` and `np.vsplit` are similar:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11],\n", " [12, 13, 14, 15]])" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid = np.arange(16).reshape((4, 4))\n", "grid" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[0 1 2 3]\n", " [4 5 6 7]]\n", "[[ 8 9 10 11]\n", " [12 13 14 15]]\n" ] } ], "source": [ "upper, lower = np.vsplit(grid, [2])\n", "print(upper)\n", "print(lower)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 0 1]\n", " [ 4 5]\n", " [ 8 9]\n", " [12 13]]\n", "[[ 2 3]\n", " [ 6 7]\n", " [10 11]\n", " [14 15]]\n" ] } ], "source": [ "left, right = np.hsplit(grid, [2])\n", "print(left)\n", "print(right)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, for higher-dimensional arrays, `np.dsplit` will split arrays along the third axis." ] } ], "metadata": { "anaconda-cloud": {}, "jupytext": { "formats": "ipynb,md" }, "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.9.2" } }, "nbformat": 4, "nbformat_minor": 4 }