{ "cells": [ { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-33372ef05bccfcb0", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "# Extracting elements \n", "\n", "```{admonition} Interactive page\n", ":class: warning, dropdown\n", "This is an interactive book page. Press launch button at the top right side.\n", "```\n", "\n", "It will often be useful to extract one or multiple elements from a NumPy array. To that end, we can use indexing and slicing. Let's see how they work!" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-aa801acee39c518f", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Indexing NumPy arrays \n", "\n", "We often need to access elements of an array, and we can do that in Python using square brackets:\n", "\n", "`a[n]` will give you the $n^{th}$ element of array `a`. \n", "\n", "This process of **extracting a single element from an array is called indexing**. \n", "If we create an array such as this:\n", "\n", "```\n", "a = np.array([1, 2, 3, 4, 5])\n", "```\n", "\n", "you would perhaps expect that the first element of `a` is `1`, and you can therefore access the first element of `a` using `a[1]`. \n", "Let's try it:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "import numpy as np\n", "a = np.array([1, 2, 3, 4, 5])\n", "print(a[1])" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-992a7aa5df6186e4", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "However, this is wrong. Why? Because Python **starts counting from zero**: the first element of `a` is actually `a[0]`. \n", "\n", "```{admonition} Why counting from zero?\n", ":class: note, dropdown\n", "This is a long-standing [discussion among computer scientists](https://en.wikipedia.org/wiki/Zero-based_numbering), and the convention is [different](https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(array)#Array_dimensions) in many different programming languages. There are advantages and disadvantages of both, and even essays written about it. In any case, Python chose to start arrays at zero.\n", "```\n", "\n", "This also helps to better understand the `range()` function: for example, to loop over all the elements of `a`, we can use this code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "for i in range(len(a)):\n", " n = a[i]\n", " print('a[%d] is %d' % (i,n))" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-ab7bf8fa5a2ac10f", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Here the `len` function returns the length of the array `a`, as we've seen before. Python has very smart `for` loops that can automatically iterate over many types of objects, which means we can also print out all the elements of our array like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "for n in a:\n", " print(n)" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-e1299e2159378fdb", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "In Python, if you try to index beyond the end of the array, you will get an error: " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a[5]" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-77aff5e6ccdff810", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "*Remember: indexing starts at zero!*\n", "\n", "Python also has a handy feature: **negative indices count backwards from the end**, so index `-1` corresponds to the last element in the array." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a[-1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a[-2]" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-8398fd216f6b2f58", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "We can also use indexing to change the values of elements in our array:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "print(a)\n", "a[2] = -1\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-3dae75f8494e44f3", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "```{exercise}\n", ":class: dropdown\n", "Set the first three and the last two entries of the following array to zero.\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 32, 55, 78, 22, 99, 55, 33.2, 55.77, 99, 101.3])\n", "\n", "# Add code to set the first three and last two entries to zero \n", "\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Indexing two-dimensional arrays works by using commas** inside square brackets to **specify the index** of the first and second dimension:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = np.array(range(1,6))\n", "m = np.outer(a,a)\n", "print(\"Initial matrix:\")\n", "print(m)\n", "\n", "# First index in the row number (counting from zero), second index in the column number\n", "m[2,3] = -1 \n", "print(\"\\nAfter changing entry [2,3] to -1:\")\n", "print(m)" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-3b080cba952a146f", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Slicing NumPy arrays\n", "\n", "NumPy arrays also support a special type of indexing called slicing. **Slicing returns a whole part of an array** rather than just a single element.\n", "To do this, we use not just a single number inside the square brackets, but instead two numbers, separated by a colon `:`\n", "\n", "`a[n:m]` will return all the elements of `a`, starting at element `n` and ending at element `m-1`. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = np.array(range(10))\n", "print(a)\n", "print(a[0:5])" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-70abffff9b88cf27", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "The notation `a[0:5]` has \"sliced\" out the first five elements of array $a$.\n", "\n", "With slicing, you can also **leave out** either `n` or `m` from the slice: if you leave out `n`, it will default to `n = 0`, and if you leave out `m`, it will default to the end of the array (the same as `m = -1` in Python indexing)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "print(a[:5])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "print(a[5:])" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-a8b2ffcd10cfc7b1", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Also handy: you can have Python slice an array with a **\"step\" size** that is more than 1 by adding another `:` and a number after that. Explore how it works:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "print(a[0:10:2])" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-24b9d17391ceeb7e", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Fun: you can also use negative steps!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "print(a[-1:-11:-1])" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-6ee08109e60cb51f", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Unlike with indexing, Python is a bit lenient if you slice off the end of an array:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "print(a[0:20])" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-8d1518c5eafa34e8", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "```{exercise}\n", ":class: dropdown\n", "Slicing can also be used to *set* multiple values in an array at the same time. Use slicing to set the first ten entries of the array below to zero in one line of code.\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = np.array(range(20))+1\n", "print(a)\n", "\n", "# Add code that sets the first 10 entries to zero\n", "\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use slicing to assign values to an array from a vector, which can be a handy way to enter a matrix by hand:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "m = np.zeros([3,3])\n", "m[0,:] = [1,2,3]\n", "m[1,:] = [4,5,6]\n", "m[2,:] = [7,8,9]\n", "print(m)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, slicing also can be used to **extract rows, columns, or blocks of a matrix**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "# A row\n", "print(m[1,:])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "# A column\n", "print(m[:,1])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "# Extract a block as a sub-matrix\n", "print(m[1:,1:])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "thebe-remove-input-init" ] }, "outputs": [], "source": [ "import micropip\n", "await micropip.install(\"jupyterquiz\")\n", "from jupyterquiz import display_quiz\n", "import json\n", "\n", "with open(\"questions7.json\", \"r\") as file:\n", " questions=json.load(file)\n", " \n", "display_quiz(questions, border_radius=0)" ] } ], "metadata": { "jupytext": { "formats": "ipynb,md" }, "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.4" } }, "nbformat": 4, "nbformat_minor": 4 }