{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a1a1d4b6-1251-4f8e-8ecc-8fd8125a7c03",
   "metadata": {},
   "source": [
    "# Arrays Basics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9b4a43d5-5f3f-4da2-a4d3-3517d08be6ab",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.594056Z",
     "iopub.status.busy": "2026-08-31T06:00:38.593819Z",
     "iopub.status.idle": "2026-08-31T06:00:38.929129Z",
     "shell.execute_reply": "2026-08-31T06:00:38.928793Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input",
     "thebe-init",
     "runnable"
    ]
   },
   "outputs": [],
   "source": [
    "import sys\n",
    "from pathlib import Path\n",
    "\n",
    "current = Path.cwd()\n",
    "for parent in [current, *current.parents]:\n",
    "    if (parent / '_config.yml').exists():\n",
    "        project_root = parent  # ← Add project root, not chapters\n",
    "        break\n",
    "else:\n",
    "    project_root = Path.cwd().parent.parent\n",
    "\n",
    "sys.path.insert(0, str(project_root))\n",
    "\n",
    "from shared import thinkpython, diagram, jupyturtle"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{contents}\n",
    ":local:\n",
    ":depth: 2\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bef5b825",
   "metadata": {},
   "source": [
    "## Numpy Arrays\n",
    "\n",
    "NumPy arrays, (N-dimensional arrays, or **`ndarray`**) are a powerful extension of Python lists, offering compact storage and fast operations for numerical data in rows and columns.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39ecf766",
   "metadata": {},
   "source": [
    "In NumPy, the terms scalar, vector, and matrix refer to specific dimensions of these arrays.\n",
    "\n",
    "```{figure} ../../figures/scalar-vector-matrix-tensor.png\n",
    "---\n",
    "width: 400px\n",
    "name: scalar-vector-matrix-tensor\n",
    "alt: scalar-vector-matrix-tensor\n",
    "align: center\n",
    "---\n",
    "Scalar, Vector, Mmatrix, and Tensor ([Harshit Tyagi](https://medium.com/data-science/introduction-to-vectors-and-matrices-using-python-for-data-science-e836e014eb12))\n",
    "```\n",
    "\n",
    "NumPy is Python's linear algebra library; therefore, its terminology is commonly used for data science. Some of the essential terms are {cite}``:\n",
    "\n",
    "- **Scalar**: Any single numerical value is a scalar, as shown in the image above. It is simply denoted by lowercase and italics. For example: _`n`_.\n",
    "- **Vector**: An array of numbers(data) is a vector. You can assume a column in a dataset to be a feature vector.\n",
    "- **Matrix**: A matrix is a 2-D array of shape (m×n) with m rows and n columns.\n",
    "- **Tensor**: Generally, an n-dimensional array where n>2 is called a Tensor. But a matrix or a vector is also a valid tensor.\n",
    "\n",
    "While NumPy arrays can have any number of dimensions, the most common are:\n",
    "- **Vectors**: **1-dimensional arrays** with a single axis\n",
    "- **Matrices**: **2-dimensional arrays** with two axes (rows and columns)\n",
    "\n",
    "\n",
    "<!-- <img src=\"../figures/c-vs-python-list.png\"\n",
    "alt=\"c-vs-python-list\"\n",
    "style = \"width: 350px\"> \n",
    "name= \"c-vs-python-list\"\n",
    "caption = Difference between C and Python lists {cite}`Vanderplas_2022`\n",
    "-->"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dfc7b50d-62d6-4a0f-88d7-55e9366c8b33",
   "metadata": {},
   "source": [
    "## Data Structure\n",
    "\n",
    "The primary data structure in NumPy is the N-dimensional array, or **`ndarray`**. NumPy's arrays are a list of lists in Python, but are more compact than Python lists. In essence, a Python list is an array of pointers to heterogeneous Python objects, while a NumPy array is an array of **uniform** values of the same type (e.g., all integers, all floats) and array elements are stored in one continuous block of memory, similar to how arrays work in C ({numref}`c-vs-python-list`). Python lists are more flexible, but Numpy arrays are smaller in file size, and access in reading and writing items is much faster {cite}`Martelli_2009`, which is a huge advantage when dealing with large datasets. \n",
    "\n",
    "<!-- , at least 4 bytes per pointer plus 16 bytes for even the smallest Python object (4 for type pointer, 4 for reference count, 4 for value -- and the memory allocators rounds up to 16).  -->\n",
    "\n",
    "<!-- (4 bytes each for single-precision numbers and 8 bytes double-precision).  -->\n",
    "\n",
    "\n",
    "\n",
    "```{figure} ../../figures/c-vs-python-list.png\n",
    "---\n",
    "width: 350px\n",
    "name: c-vs-python-list\n",
    "alt: c-vs-python-list\n",
    "align: center\n",
    "---\n",
    "Difference between NumPy array (C) and Python lists {cite}`Vanderplas_2022`\n",
    "```\n",
    "\n",
    "In short, NumPy's primary data structure is the **`ndarray`** (N-dimensional array), which is a **homogeneous**, **multidimensional** array of fixed-size items. This means all elements within a **`ndarray`** must be of the same data type (note: To store heterogeneous data, NumPy uses structured arrays). While Python defines only one type of a particular data class (there is only one integer type, one floating-point type, etc.), there are 24 new fundamental Python types to describe different types of scalars in NumPy.\n",
    "\n",
    "\n",
    "```{figure} ../../figures/np-array-data-types.png\n",
    "---\n",
    "width: 450px\n",
    "name: np-array-data-types\n",
    "alt: np-array-data-types\n",
    "align: center\n",
    "---\n",
    "Hierarchy of type objects representing the array data types ([NumPy: Scalars](https://numpy.org/doc/stable/reference/arrays.scalars.html))\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fcb40036-3bc4-417c-9e17-1378a851bfa3",
   "metadata": {},
   "source": [
    "[Compared](https://numpy.org/doc/stable/reference/arrays.dtypes.html) some of the NumPy built-in types to Python built-in types:\n",
    "\n",
    "| Python type | NumPy type | Type name | Type code |\n",
    "|---|---|---|---|\n",
    "| `int` | `int_` | **`int64`** (or `int32` on some systems) | `i8` (or `i4`) |\n",
    "| `bool` | `bool_` | `bool_` | `b1` |\n",
    "| `float` | `float64` | **`float64`** | `f8` |\n",
    "| `complex` | `complex128` | `complex128` | `c16` |\n",
    "| `bytes` | `bytes_` | variable-length | `S<n>` |\n",
    "| `str` | `str_` | `str_` | `**U<n>**` |\n",
    "| `memoryview` | `void` | variable-length | `V<n>` |\n",
    "| (all others) | `object_` | `object_` | `O` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcaa72eb",
   "metadata": {},
   "source": [
    "## Using NumPy"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7311897",
   "metadata": {},
   "source": [
    "### Installing NumPy\n",
    "\n",
    "To install NumPy, you would:\n",
    "1. Go to the command line\n",
    "2. Navigate to your project directory (dsm)\n",
    "3. Activate the virtual environment \n",
    "4. Issue the `pip install [package]` syntax to install: \n",
    "\n",
    "```python\n",
    "pip install numpy\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d0fab69",
   "metadata": {},
   "source": [
    "You should see the installation happens like:\n",
    "\n",
    "```text\n",
    "(.venv) [username]@[computer]ː~/workspace/dsm$ pip install numpy\n",
    "Collecting numpy\n",
    "Downloading numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl.metadata (62 kB)\n",
    "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.1/62.1 kB 1.3 MB/s eta 0:00:00\n",
    "Downloading numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl (5.1 MB)\n",
    "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.1/5.1 MB 4.1 MB/s eta 0:00:00\n",
    "Installing collected packages: numpy\n",
    "Successfully installed numpy-2.3.3\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8b7d18c2",
   "metadata": {},
   "source": [
    "```{note}\n",
    "Alternatively, in a Jupyter notebook, you may use the `%pip install [package]` syntax in a code cell to install packages just like `pip install [package]` in the command line. You will also see people use the older syntax `!pip install`, which runs `pip` as a shell command, while `%pip` is a Jupyter magic function that runs in the current notebook kernel, allowing you to customize your notebooks. \n",
    "\n",
    "Don't forget to comment out (`#`) your `pip` commands in the cells after installation, or they'll run every time you run the cell.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fcc02d5",
   "metadata": {},
   "source": [
    "### `import` NumPy\n",
    "\n",
    "Once you've installed NumPy, you can import it as a library and give it an **alias**; conventionally we calle it `np`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "333ff137",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.933692Z",
     "iopub.status.busy": "2026-08-31T06:00:38.933622Z",
     "iopub.status.idle": "2026-08-31T06:00:38.934894Z",
     "shell.execute_reply": "2026-08-31T06:00:38.934726Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c5af04d-fdcb-4cf3-95c9-9c93ad2c6c29",
   "metadata": {},
   "source": [
    "Here, `np` is an **alias** for numpy, and the dot notation gives us access to the contained objects, such as `array()` in this case."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1891c5c-fb52-4e5b-9716-1bfa9b88fc52",
   "metadata": {},
   "source": [
    "After you import the library, you use the **dot operator** to access the **methods**/functions and attributes inside the module/library. Just type the **name** of the object, and then the **dot** (**`.`**) and the `Tab` key to show the menu. You can scroll down to select the methods. In this case, we choose the `array` method (note: the Tab key can also do autocompletion). \n",
    "\n",
    "```{figure} ../../figures/dot-operator-numpy.png\n",
    "---\n",
    "width: 300px\n",
    "name: dot-operator-numpy\n",
    "---\n",
    "Using the dot operator and Tab completion in NumPy\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00045701-be33-4b2b-81f4-ff59df8397c3",
   "metadata": {},
   "source": [
    "### Functions/Methods\n",
    "\n",
    "NumPy provides many functions for creating and operating on arrays. NumPy **functions** are called through the np namespace, such as np.array() and np.sum(). Many operations that act on an existing array are also available as array **methods**, called through the array object, such as arr.reshape() and arr.sum().\n",
    "\n",
    "Array-creation routines such as np.array(), np.arange(), np.zeros(), and np.linspace() are naturally expressed as functions because they do not require an existing array. Other operations may be available as a function, a method, or both.\n",
    "\n",
    "| Category | Function / Method | Description | Example |\n",
    "|---|---|---|---|\n",
    "| **Array Creation** | `np.array()` | Create an array from array-like data | `np.array([1, 2, 3])` |\n",
    "| | `np.arange()` | Create evenly spaced values within an interval | `np.arange(0, 10, 2)` |\n",
    "| | `np.linspace()` | Create a specified number of evenly spaced values | `np.linspace(0, 10, 5)` |\n",
    "| | `np.zeros()` | Create an array filled with zeros | `np.zeros((3, 4))` |\n",
    "| | `np.ones()` | Create an array filled with ones | `np.ones((2, 3))` |\n",
    "| | `np.eye()` | Create a 2-D array with ones on the diagonal | `np.eye(3)` |\n",
    "| | `np.full()` | Create an array filled with a specified value | `np.full((2, 3), 7)` |\n",
    "| **Shape Operations** | `np.reshape()` / `arr.reshape()` | Return an array with a new shape | `arr.reshape(2, 5)` |\n",
    "| | `arr.flatten()` | Return a flattened copy of an array | `arr.flatten()` |\n",
    "| | `np.transpose()` / `arr.transpose()` | Permute an array's axes | `arr.T` |\n",
    "| | `np.concatenate()` | Join arrays along an existing axis | `np.concatenate((arr1, arr2))` |\n",
    "| | `np.stack()` | Join arrays along a new axis | `np.stack((arr1, arr2))` |\n",
    "| **Indexing / Selection** | `np.where()` | Return indices satisfying a condition, or select values conditionally | `np.where(arr > 5)` |\n",
    "| | `np.nonzero()` / `arr.nonzero()` | Return indices of nonzero elements | `np.nonzero(arr)` |\n",
    "| | `np.select()` | Select values using multiple conditions | `np.select([cond1, cond2], [val1, val2])` |\n",
    "| **Array Operations** | `np.sum()` / `arr.sum()` | Sum array elements | `arr.sum()` |\n",
    "| | `np.sort()` / `arr.sort()` | Sort array elements | `np.sort(arr)` |\n",
    "| | `np.argsort()` / `arr.argsort()` | Return indices that would sort an array | `np.argsort(arr)` |\n",
    "| | `np.unique()` | Return the unique values in an array | `np.unique(arr)` |\n",
    "| **Random Numbers** | `np.random.default_rng()` | Create a random number generator | `rng = np.random.default_rng()` |\n",
    "| | `rng.random()` | Generate random values uniformly distributed over `[0, 1)` | `rng.random((3, 4))` |\n",
    "| | `rng.standard_normal()` | Generate values from the standard normal distribution | `rng.standard_normal(5)` |\n",
    "| | `rng.integers()` | Generate random integers | `rng.integers(0, 10, size=5)` |\n",
    "| | `rng.choice()` | Randomly select values from an array | `rng.choice(arr, size=3)` |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c91e8f65",
   "metadata": {},
   "source": [
    ":::{Note}\n",
    "You may encounter older NumPy code that uses functions such as np.random.rand(), np.random.randn(), and np.random.randint(). New code generally uses a random number generator created with np.random.default_rng().\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7020df08",
   "metadata": {},
   "source": [
    "## Creating NumPy Arrays\n",
    "\n",
    "### `array([sequence])`\n",
    "\n",
    "You can create an array by directly **converting** a list to an array. Let us create a list first:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "722b7f83-c68a-4ab0-84a7-544357facfac",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.935974Z",
     "iopub.status.busy": "2026-08-31T06:00:38.935915Z",
     "iopub.status.idle": "2026-08-31T06:00:38.937351Z",
     "shell.execute_reply": "2026-08-31T06:00:38.937142Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num_list:  [1, 2, 3, 4, 5]\n",
      "num_list type: <class 'list'>\n"
     ]
    }
   ],
   "source": [
    "num_list = [1,2,3, 4, 5]\n",
    "print(\"num_list: \", num_list)\n",
    "print(\"num_list type:\", type(num_list))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f78b8209",
   "metadata": {},
   "source": [
    "Now let's convert the **list** into a numpy array using numpy's `array()` function to create a **1-D** array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "80d03d55",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.938262Z",
     "iopub.status.busy": "2026-08-31T06:00:38.938211Z",
     "iopub.status.idle": "2026-08-31T06:00:38.940494Z",
     "shell.execute_reply": "2026-08-31T06:00:38.940283Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 5])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array(num_list)       ### casting a list to a numpy array\n",
    "arr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14e1c4e7-1f7c-4e27-8bb2-f3ba388574ce",
   "metadata": {},
   "source": [
    "Now let's create a **2-D** (rows and columns) array using a 2-D **tuple**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d61a89cf-fd87-432a-a43d-e4a2e75c8dec",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.941454Z",
     "iopub.status.busy": "2026-08-31T06:00:38.941397Z",
     "iopub.status.idle": "2026-08-31T06:00:38.943081Z",
     "shell.execute_reply": "2026-08-31T06:00:38.942793Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6],\n",
       "       [7, 8, 9]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_2d = np.array(\n",
    "    (\n",
    "        [1,2,3],\n",
    "        [4,5,6],\n",
    "        [7,8,9]\n",
    "    )\n",
    ")\n",
    "arr_2d"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "863694eb-5592-45ee-8da5-44ada09ba6bb",
   "metadata": {},
   "source": [
    "An example of Python **3-D** list, which is a list of lists: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "91cdb251",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.944096Z",
     "iopub.status.busy": "2026-08-31T06:00:38.944011Z",
     "iopub.status.idle": "2026-08-31T06:00:38.946233Z",
     "shell.execute_reply": "2026-08-31T06:00:38.945980Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[[1, 2, 3], [2, 2, 3]], [[3, 2, 3], [4, 2, 3]], [[5, 2, 3], [6, 2, 3]]]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list_of_list = [\n",
    "    [\n",
    "        [1, 2, 3], \n",
    "        [2, 2, 3], \n",
    "    ], \n",
    "    [\n",
    "        [3, 2, 3],\n",
    "        [4, 2, 3]\n",
    "    ],\n",
    "    [\n",
    "        [5, 2, 3], \n",
    "        [6, 2, 3]\n",
    "    ]\n",
    "]\n",
    "list_of_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f28cb032-1e95-4ec2-baf6-1bd50c883e31",
   "metadata": {},
   "source": [
    "Compare the output of the Python list above with the NumPy array created from the list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a12ca634",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.947315Z",
     "iopub.status.busy": "2026-08-31T06:00:38.947250Z",
     "iopub.status.idle": "2026-08-31T06:00:38.949009Z",
     "shell.execute_reply": "2026-08-31T06:00:38.948818Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[1, 2, 3],\n",
       "        [2, 2, 3]],\n",
       "\n",
       "       [[3, 2, 3],\n",
       "        [4, 2, 3]],\n",
       "\n",
       "       [[5, 2, 3],\n",
       "        [6, 2, 3]]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.array(list_of_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f546bb1-a98e-465f-b937-1c7b86d8c8e5",
   "metadata": {},
   "source": [
    "We can check the data **type** of the arrays to see they are truely arrays:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "6ba59b38",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.949938Z",
     "iopub.status.busy": "2026-08-31T06:00:38.949883Z",
     "iopub.status.idle": "2026-08-31T06:00:38.951215Z",
     "shell.execute_reply": "2026-08-31T06:00:38.951074Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n",
      "<class 'numpy.ndarray'>\n"
     ]
    }
   ],
   "source": [
    "print(type(arr))\n",
    "print(type(arr_2d))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4cd1a0b8",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.951999Z",
     "iopub.status.busy": "2026-08-31T06:00:38.951941Z",
     "iopub.status.idle": "2026-08-31T06:00:38.953347Z",
     "shell.execute_reply": "2026-08-31T06:00:38.953182Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### 1 Exercise: Create a 3-D NumPy array from the following \n",
    "### list of lists and print its type and shape:\n",
    "import numpy as np\n",
    "data_3d = [\n",
    "    [[1, 2], [3, 4]],\n",
    "    [[5, 6], [7, 8]],\n",
    "    [[9, 10], [11, 12]]\n",
    "]\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f5f9ea4",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n",
      "(3, 2, 2)\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "import numpy as np\n",
    "\n",
    "data_3d = [\n",
    "    [[1, 2], [3, 4]],\n",
    "    [[5, 6], [7, 8]],\n",
    "    [[9, 10], [11, 12]]\n",
    "]\n",
    "\n",
    "array_3d = np.array(data_3d)\n",
    "print(type(array_3d))\n",
    "print(array_3d.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41884243-502c-4d71-8ade-502ea0315f14",
   "metadata": {},
   "source": [
    "### The `arange()` Function\n",
    "\n",
    "**`numpy.arange()`** is a NumPy function used to create arrays with evenly spaced values with a specified interval. It is similar to Python's built-in `range()` function, but returns a NumPy **`ndarray`** instead of a `range` object, which is more efficient for numerical operations.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "37a295ae-f7a7-42c9-85d8-6e182643e59b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.956403Z",
     "iopub.status.busy": "2026-08-31T06:00:38.956355Z",
     "iopub.status.idle": "2026-08-31T06:00:38.957847Z",
     "shell.execute_reply": "2026-08-31T06:00:38.957669Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a62bece1-cc73-4193-af00-b145088acfaf",
   "metadata": {},
   "source": [
    "Using the range **parameters**: **start**, **stop** exclusive, **step**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "f4b5a9bc-f71b-4e02-a65a-23e4a6aa570c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.958768Z",
     "iopub.status.busy": "2026-08-31T06:00:38.958709Z",
     "iopub.status.idle": "2026-08-31T06:00:38.960447Z",
     "shell.execute_reply": "2026-08-31T06:00:38.960279Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5,  7,  9, 11, 13, 15, 17, 19])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(5, 21, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "4c546ff5",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.961766Z",
     "iopub.status.busy": "2026-08-31T06:00:38.961693Z",
     "iopub.status.idle": "2026-08-31T06:00:38.962990Z",
     "shell.execute_reply": "2026-08-31T06:00:38.962815Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### 2 Exercise: Create an array of values from 10 to 50 with a step of \n",
    "### 5 using `arange()`. What is the length of the resulting array?\n",
    "### Produce the same output as the cell below.\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fbd42072",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[10 15 20 25 30 35 40 45 50]\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "import numpy as np\n",
    "\n",
    "values = np.arange(10, 51, 5)\n",
    "print(values)\n",
    "print(len(values))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "2f661689",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.978259Z",
     "iopub.status.busy": "2026-08-31T06:00:38.978180Z",
     "iopub.status.idle": "2026-08-31T06:00:38.979591Z",
     "shell.execute_reply": "2026-08-31T06:00:38.979442Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Array: [  1   9  25  49  81 121 169 225 289 361]\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "odd_squares = np.array([x**2 for x in range(1, 20, 2)])\n",
    "print(\"Array:\", odd_squares)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69f03c87-03dd-4752-8bc5-275b8cce1fe2",
   "metadata": {},
   "source": [
    "### Other `np` Functions: \n",
    "\n",
    "1. zeros( ):\n",
    "  `np.zeros(shape, dtype=float, order='C')`\n",
    "2. ones( ): `np.ones(shape, dtype=float, order='C')`\n",
    "3. full( ): create an array filled with a certain value \n",
    "  \n",
    "    `np.full(shape, fill_value, dtype=None, order='C')`\n",
    "4. linspace( ): `np.linspace(start, stop, num=50 default, endpoint=True, retstep=False, dtype=None, axis=0)`\n",
    "5. eye( ): `np.eye(N, M=None, k=0, dtype=float, order='C')`\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac4266e2",
   "metadata": {},
   "source": [
    "#### zeros(), ones(), and full()\n",
    "\n",
    "These functions initialize arrays of a specified **shape** filled with zeros, ones, or a constant value, respectively. The syntax for numpy.ones(), zeros(), and full() functions is:\n",
    "\n",
    "<code>numpy.ones(shape, dtype=None, order='C', *, like=None)</code>\n",
    "\n",
    "Note that we pass the shape argument using a list or a tuple or list. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9ebe4bdb-5e68-4cab-968d-450c45ead016",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.980517Z",
     "iopub.status.busy": "2026-08-31T06:00:38.980462Z",
     "iopub.status.idle": "2026-08-31T06:00:38.982042Z",
     "shell.execute_reply": "2026-08-31T06:00:38.981872Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, 0, 0])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### zero() function creates an array filled with zeros. \n",
    "### You can specify the shape and data type of the array.\n",
    "\n",
    "np.zeros((3, 4))     ### passing shape parameter with a tuple   \n",
    "                     ### by default, the dtype is float64"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a37b283d-9ee4-446b-b312-c561acf3c439",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.982895Z",
     "iopub.status.busy": "2026-08-31T06:00:38.982845Z",
     "iopub.status.idle": "2026-08-31T06:00:38.984760Z",
     "shell.execute_reply": "2026-08-31T06:00:38.984602Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., 0.],\n",
       "       [0., 0., 0., 0.],\n",
       "       [0., 0., 0., 0.]])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "np.zeros(5, dtype=int)  ###  passing shape parameter with an integer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "868d3bd5-7edc-49a4-9d75-363faf232334",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.985626Z",
     "iopub.status.busy": "2026-08-31T06:00:38.985558Z",
     "iopub.status.idle": "2026-08-31T06:00:38.987066Z",
     "shell.execute_reply": "2026-08-31T06:00:38.986899Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1., 1., 1.])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### one() function creates an array filled with ones.\n",
    "\n",
    "arr_ones = np.ones(3)   ### vector array of 1's \n",
    "arr_ones                ### type float64 by default"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "2ac7980f-3c72-4230-87eb-578ed7bb9aea",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.987863Z",
     "iopub.status.busy": "2026-08-31T06:00:38.987810Z",
     "iopub.status.idle": "2026-08-31T06:00:38.989291Z",
     "shell.execute_reply": "2026-08-31T06:00:38.989131Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_ones.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d38a6ee5-3c7f-4e88-88c6-e727258a2992",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.990087Z",
     "iopub.status.busy": "2026-08-31T06:00:38.990041Z",
     "iopub.status.idle": "2026-08-31T06:00:38.991416Z",
     "shell.execute_reply": "2026-08-31T06:00:38.991269Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 1 1]\n",
      " [1 1 1]]\n",
      "\n",
      "<class 'numpy.ndarray'>\n",
      "int64\n"
     ]
    }
   ],
   "source": [
    "arr_ints = np.ones([2,3], int)     ### specify dtype to int\n",
    "\n",
    "print(arr_ints)\n",
    "\n",
    "print()\n",
    "\n",
    "print(type(arr_ints))   ### check the type of arr_ints using the built-in type() function\n",
    "print(arr_ints.dtype)   ### check the np data type of arr_ints using the built-in dtype attribute"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "713b7c4d-36be-4163-8ab7-13587414c0a4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.992176Z",
     "iopub.status.busy": "2026-08-31T06:00:38.992130Z",
     "iopub.status.idle": "2026-08-31T06:00:38.993861Z",
     "shell.execute_reply": "2026-08-31T06:00:38.993634Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([5, 5, 5, 5, 5])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "##### 3 Exercise: Create a 1-D NumPy array of length 5 filled with the\n",
    "##### value 5 using the `full()` function. What is the data type of the\n",
    "\n",
    "np.full( (5) , 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "53e02020-0bfa-4345-92ab-df3d23adc20b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.996006Z",
     "iopub.status.busy": "2026-08-31T06:00:38.995908Z",
     "iopub.status.idle": "2026-08-31T06:00:38.997735Z",
     "shell.execute_reply": "2026-08-31T06:00:38.997553Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[5, 5, 5],\n",
       "       [5, 5, 5]])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.full((2, 3), 5)      ### fill the shape (2x3) with 5"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7595a8d1",
   "metadata": {},
   "source": [
    "#### linspace()\n",
    "\n",
    "`linspace( )` stands for linear space. linspace returns evenly spaced numbers over a specified interval. `linspace`() takes three main arguments: the **start** value, the **stop** value, and the **number** of elements to generate. Note that the **stop** parameter is <span style=\"color: darkred\">**inclusive**</span>. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "a92ad757",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:38.998659Z",
     "iopub.status.busy": "2026-08-31T06:00:38.998608Z",
     "iopub.status.idle": "2026-08-31T06:00:39.000412Z",
     "shell.execute_reply": "2026-08-31T06:00:39.000251Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  2,  5,  7, 10])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### Create an array of five values evenly spaced between 0 and 1\n",
    "\n",
    "np.linspace(0, 10, 5, dtype=int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "313c7fd9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.001300Z",
     "iopub.status.busy": "2026-08-31T06:00:39.001254Z",
     "iopub.status.idle": "2026-08-31T06:00:39.002658Z",
     "shell.execute_reply": "2026-08-31T06:00:39.002499Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n",
      " 24 25 26]\n"
     ]
    }
   ],
   "source": [
    "arr = np.linspace(0, 26, 27, dtype=int)\n",
    "\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0070527b",
   "metadata": {},
   "source": [
    "#### eye()\n",
    "\n",
    "An identity matrix is a square matrix with 1s on the main diagonal and 0s everywhere else. It plays the same role in matrix multiplication that the number 1 plays in ordinary multiplication.\n",
    "\n",
    "To creates an identity matrix:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "757475bd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.003503Z",
     "iopub.status.busy": "2026-08-31T06:00:39.003452Z",
     "iopub.status.idle": "2026-08-31T06:00:39.004970Z",
     "shell.execute_reply": "2026-08-31T06:00:39.004819Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 0., 0., 0.],\n",
       "       [0., 1., 0., 0.],\n",
       "       [0., 0., 1., 0.],\n",
       "       [0., 0., 0., 1.]])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.eye(4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b1b68bf-5940-41dc-9825-b6e77b62e862",
   "metadata": {},
   "source": [
    "### `reshape()` \n",
    "The reshape() function changes the shape of a NumPy array without altering its underlying data. It **returns a new array** (or a view of the original array if possible) with the specified new shape."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "7a1c126d-7c09-4fa8-a51e-57f3623f3681",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.005817Z",
     "iopub.status.busy": "2026-08-31T06:00:39.005759Z",
     "iopub.status.idle": "2026-08-31T06:00:39.007170Z",
     "shell.execute_reply": "2026-08-31T06:00:39.006994Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n",
      " 24 25 26]\n",
      "[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n",
      " 24 25 26]\n"
     ]
    }
   ],
   "source": [
    "arr = np.linspace(0, 26, 27, dtype=int)\n",
    "print(arr)\n",
    "arr.reshape(3, 9)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "d56cd046-d53f-42a8-b29b-aff05b252309",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.008075Z",
     "iopub.status.busy": "2026-08-31T06:00:39.008023Z",
     "iopub.status.idle": "2026-08-31T06:00:39.009688Z",
     "shell.execute_reply": "2026-08-31T06:00:39.009524Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### arr\n",
    "arr = np.array(\n",
    "    [num for num in range(16)]\n",
    ")\n",
    "\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "c3165f47-e9d6-44a0-9078-69986987fd29",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.010755Z",
     "iopub.status.busy": "2026-08-31T06:00:39.010685Z",
     "iopub.status.idle": "2026-08-31T06:00:39.012394Z",
     "shell.execute_reply": "2026-08-31T06:00:39.012191Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,\n",
       "       17, 18, 19, 20, 21, 22, 23, 24])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### np.array([list comprehension])\n",
    "arr_25 = np.array([ num for num in range(25)])\n",
    "arr_25"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "093158e6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.013234Z",
     "iopub.status.busy": "2026-08-31T06:00:39.013172Z",
     "iopub.status.idle": "2026-08-31T06:00:39.014841Z",
     "shell.execute_reply": "2026-08-31T06:00:39.014669Z"
    },
    "tags": []
   },
   "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": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### reshape\n",
    "arr = arr.reshape(4, 4)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "59ab64c1-d121-450e-8b2e-026fc1b13488",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.015715Z",
     "iopub.status.busy": "2026-08-31T06:00:39.015648Z",
     "iopub.status.idle": "2026-08-31T06:00:39.017166Z",
     "shell.execute_reply": "2026-08-31T06:00:39.017008Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4,  5,  6,  7],\n",
       "       [ 8,  9, 10, 11, 12, 13, 14, 15]])"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.reshape(2, 8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "ccec32e5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.017981Z",
     "iopub.status.busy": "2026-08-31T06:00:39.017926Z",
     "iopub.status.idle": "2026-08-31T06:00:39.019106Z",
     "shell.execute_reply": "2026-08-31T06:00:39.018923Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "### this will not work\n",
    "\n",
    "# arr.reshape(5,5)  ### ValueError: cannot reshape array of size 16 into shape (5,5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "7e3cca91-0d30-45c1-b62b-aaaf4180ff25",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.019919Z",
     "iopub.status.busy": "2026-08-31T06:00:39.019865Z",
     "iopub.status.idle": "2026-08-31T06:00:39.021303Z",
     "shell.execute_reply": "2026-08-31T06:00:39.021122Z"
    },
    "tags": []
   },
   "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": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_25 = np.arange(25)  ### create an array of 25 values from 0 to 24\n",
    "arr_25.reshape(5, 5)    ### reshape it to 5 rows and 5 columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "4871e3a5-5539-41a5-b462-b290a2a8e141",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.022289Z",
     "iopub.status.busy": "2026-08-31T06:00:39.022210Z",
     "iopub.status.idle": "2026-08-31T06:00:39.023758Z",
     "shell.execute_reply": "2026-08-31T06:00:39.023569Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(5, 5)"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_25.reshape(5, 5).shape  ### check the shape of the reshaped array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "b8e9baf8-819f-4ecf-8d62-32895839d5fa",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.024862Z",
     "iopub.status.busy": "2026-08-31T06:00:39.024809Z",
     "iopub.status.idle": "2026-08-31T06:00:39.026339Z",
     "shell.execute_reply": "2026-08-31T06:00:39.026178Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,\n",
       "       17, 18, 19, 20, 21, 22, 23, 24])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### reshape does not change the original object\n",
    "\n",
    "arr_25"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "e970daa5-196f-4f1b-ba33-1259abd9b255",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.027406Z",
     "iopub.status.busy": "2026-08-31T06:00:39.027352Z",
     "iopub.status.idle": "2026-08-31T06:00:39.028905Z",
     "shell.execute_reply": "2026-08-31T06:00:39.028726Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(25,)"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_25.shape        ### check the shape of the original array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "149b926a",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.029716Z",
     "iopub.status.busy": "2026-08-31T06:00:39.029664Z",
     "iopub.status.idle": "2026-08-31T06:00:39.030871Z",
     "shell.execute_reply": "2026-08-31T06:00:39.030703Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### 4 Exercise: Create an array with 24 elements using `np.arange()`. \n",
    "### Reshape it into a 4x6 array, then reshape it again into a 2x12 array. \n",
    "### Print the shape after each reshape operation.\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a09a0170",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original shape: (24,)\n",
      "4x6 shape: (4, 6)\n",
      "2x12 shape: (2, 12)\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "import numpy as np\n",
    "\n",
    "values = np.arange(24)\n",
    "reshaped_4_by_6 = values.reshape(4, 6)\n",
    "reshaped_2_by_12 = values.reshape(2, 12)\n",
    "\n",
    "print(\"Original shape:\", values.shape)\n",
    "print(\"4x6 shape:\", reshaped_4_by_6.shape)\n",
    "print(\"2x12 shape:\", reshaped_2_by_12.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "81ee2d18",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.031601Z",
     "iopub.status.busy": "2026-08-31T06:00:39.031555Z",
     "iopub.status.idle": "2026-08-31T06:00:39.033169Z",
     "shell.execute_reply": "2026-08-31T06:00:39.033001Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original shape: (24,)\n",
      "After first reshape (4, 6): (4, 6)\n",
      "After second reshape (2, 12): (2, 12)\n",
      "\n",
      "Final array:\n",
      " [[ 0  1  2  3  4  5  6  7  8  9 10 11]\n",
      " [12 13 14 15 16 17 18 19 20 21 22 23]]\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "arr = np.arange(24)\n",
    "print(\"Original shape:\", arr.shape)\n",
    "\n",
    "arr_4x6 = arr.reshape(4, 6)\n",
    "print(\"After first reshape (4, 6):\", arr_4x6.shape)\n",
    "\n",
    "arr_2x12 = arr_4x6.reshape(2, 12)\n",
    "print(\"After second reshape (2, 12):\", arr_2x12.shape)\n",
    "print(\"\\nFinal array:\\n\", arr_2x12)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21b74cc8-9600-4813-b3ec-7aa4181aa3d2",
   "metadata": {},
   "source": [
    "## Array Attributes\n",
    "\n",
    "Commonly used NumPy array attributes include:\n",
    "\n",
    "- `dtype`: shows data type of elements (e.g., float64, int32, complex128)\n",
    "- `ndim`: shows number of dimensions (rank)\n",
    "- `shape`: shows a tuple of lengths per axis (assignable to reshape if sizes match)\n",
    "- `size`: shows the total number of elements in the array\n",
    "- - `itemsize`: shows the size in bytes of each element\n",
    "- `nbytes`: shows the total memory (in bytes) the array occupies (size × itemsize)\n",
    "- `T`: returns the transposed array (an attribute, not a method — no parentheses needed)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3436285-0319-4ac5-8c33-dc23a86d8518",
   "metadata": {},
   "source": [
    "### dtype\n",
    "\n",
    "The **dtype** property in NumPy is an attribute of a NumPy array (**`ndarray`**) that displays the data type of its elements. You can get the data type of the object in the array. \n",
    "\n",
    "Note that in the example below, **`i4`** means a 4-byte signed integer (int32). Because 4 = 4 bytes, 4 bytes × 8 bits = 32 bits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ca3c5549",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3 4]\n",
      "int32\n"
     ]
    }
   ],
   "source": [
    "arr = np.array([1, 2, 3, 4], dtype='i4')\n",
    "\n",
    "print(arr)\n",
    "print(arr.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3c187cd6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3 4]\n",
      "int64\n"
     ]
    }
   ],
   "source": [
    "### without specifying the dtype, NumPy will infer the data type \n",
    "### based on the input values. In this case, it will default to `int64` on most systems.\n",
    "\n",
    "arr = np.array([1, 2, 3, 4])\n",
    "print(arr)\n",
    "print(arr.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f5701ea6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1., 2., 3., 4.], dtype=float32)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "### Create an array with a specific data type\n",
    "\n",
    "np.array([1, 2, 3, 4], dtype=np.float32)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef85bedd",
   "metadata": {},
   "source": [
    "Common dtype options:\n",
    "```\n",
    "int, int32, int64           # integer types\n",
    "float, float32, float64     # floating-point types\n",
    "complex, complex64          # complex numbers\n",
    "bool                        # boolean\n",
    "str, 'U10'                  # string (U10 = Unicode string, max 10 chars)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "d78db85c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "int64\n",
      "float64\n",
      "int64\n",
      "float64\n",
      "\n",
      " [0 1 2 3 4]\n",
      "[0. 1. 2. 3. 4.]\n",
      "[0 0 0 0 0]\n",
      "[[1. 1. 1. 1.]\n",
      " [1. 1. 1. 1.]\n",
      " [1. 1. 1. 1.]]\n"
     ]
    }
   ],
   "source": [
    "num1 = np.arange(5, dtype=int)        # [0 1 2 3 4] as integers\n",
    "num2 = np.arange(5, dtype=float)      # [0. 1. 2. 3. 4.] as floats\n",
    "num3 = np.zeros(5, dtype=int)         # [0 0 0 0 0]\n",
    "num4 = np.ones((3, 4), dtype=float)   # 3x4 array of 1.0s\n",
    "\n",
    "print(num1.dtype)\n",
    "print(num2.dtype)\n",
    "print(num3.dtype)\n",
    "print(num4.dtype)\n",
    "\n",
    "print('\\n',num1)\n",
    "print(num2)\n",
    "print(num3)\n",
    "print(num4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb973ce3",
   "metadata": {},
   "source": [
    "#### Understanding String Dtypes\n",
    "\n",
    "When NumPy creates an array of strings, it automatically determines the data type based on the longest string in the array. The notation **`<U6`** means:\n",
    "- **`U`** = Unicode string\n",
    "- **`6`** = Maximum length of 6 characters\n",
    "\n",
    "For example, if you create an array with the strings `'apple'`, `'banana'`, and `'cherry'`, the longest string is 6 characters, so the dtype becomes `<U6`. This ensures all strings fit within the allocated space."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bab9ae8c-77fb-4062-8559-7124eb265664",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.095844Z",
     "iopub.status.busy": "2026-08-31T06:00:39.095803Z",
     "iopub.status.idle": "2026-08-31T06:00:39.096953Z",
     "shell.execute_reply": "2026-08-31T06:00:39.096799Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<U6\n",
      "<U10\n",
      "\n",
      "'U6' means: Unicode string with maximum length of 6 characters\n"
     ]
    }
   ],
   "source": [
    "arr_string1 = np.array(['apple', 'banana', 'cherry'])\n",
    "arr_string2 = np.array(['apple', 'banana', 'cherry', 'date', 'elderberry'])\n",
    "\n",
    "print(arr_string1.dtype)   ### U means UTF8, 6 is the longest string\n",
    "print(arr_string2.dtype)\n",
    "print(\"\\n'U6' means: Unicode string with maximum length of 6 characters (cherry)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6b7af7f-83d2-4397-b7f4-b3f7bc401c0f",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "source": [
    "### ndim\n",
    "The ndim attribute represents the number of dimensions (or **axes**) of the array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "7a082a6c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.100053Z",
     "iopub.status.busy": "2026-08-31T06:00:39.099996Z",
     "iopub.status.idle": "2026-08-31T06:00:39.101401Z",
     "shell.execute_reply": "2026-08-31T06:00:39.101242Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3 4 5]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.arange(1, 6)\n",
    "print(arr)\n",
    "arr.ndim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "d7b1fbf9-ff6e-4e94-93fb-a65067c5e3ed",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.102215Z",
     "iopub.status.busy": "2026-08-31T06:00:39.102176Z",
     "iopub.status.idle": "2026-08-31T06:00:39.103587Z",
     "shell.execute_reply": "2026-08-31T06:00:39.103432Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_25 = np.arange(25)\n",
    "arr_55 = arr_25.reshape(5, 5)\n",
    "arr_55.ndim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48353b58",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.104406Z",
     "iopub.status.busy": "2026-08-31T06:00:39.104365Z",
     "iopub.status.idle": "2026-08-31T06:00:39.105503Z",
     "shell.execute_reply": "2026-08-31T06:00:39.105356Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Use arrange to create arrays of different \n",
    "### dimensions and check their ndim attribute:\n",
    "# - Create a 1-D array with 5 elements\n",
    "# - Create a 2-D array with shape (3, 4)\n",
    "# - Create a 3-D array with shape (2, 3, 2)\n",
    "# - Print the ndim for each array\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5910ef7f",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1-D ndim: 1\n",
      "2-D ndim: 2\n",
      "3-D ndim: 3\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "import numpy as np\n",
    "\n",
    "array_1d = np.arange(5)\n",
    "array_2d = np.arange(12).reshape(3, 4)\n",
    "array_3d = np.arange(12).reshape(2, 3, 2)\n",
    "\n",
    "print(\"1-D ndim:\", array_1d.ndim)\n",
    "print(\"2-D ndim:\", array_2d.ndim)\n",
    "print(\"3-D ndim:\", array_3d.ndim)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31e8bd54-75d7-4318-83a8-1dac9957a182",
   "metadata": {},
   "source": [
    "### shape\n",
    "\n",
    "The shape attribute **returns a tuple** of integers at every index tells about the number of elements the corresponding dimension has."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "1871c480-7932-4c30-af3a-8b7ff1a66987",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.108740Z",
     "iopub.status.busy": "2026-08-31T06:00:39.108701Z",
     "iopub.status.idle": "2026-08-31T06:00:39.110139Z",
     "shell.execute_reply": "2026-08-31T06:00:39.109970Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 3)"
      ]
     },
     "execution_count": 78,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_2d = np.array([ [1, 2, 3], [4, 5, 6] ])\n",
    "arr_2d.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "4da4824e-ba19-425e-bf16-7e75de5967c1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.111004Z",
     "iopub.status.busy": "2026-08-31T06:00:39.110961Z",
     "iopub.status.idle": "2026-08-31T06:00:39.112255Z",
     "shell.execute_reply": "2026-08-31T06:00:39.112122Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the vector: [1 3 5 7 9]\n",
      "the shape: (5,)\n"
     ]
    }
   ],
   "source": [
    "### np.arange creating a 1-D array\n",
    "\n",
    "arr_vec = np.arange(1, 10, 2)\n",
    "print(\"the vector:\", arr_vec)\n",
    "print(\"the shape:\", arr_vec.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "f4c3d5da",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.112982Z",
     "iopub.status.busy": "2026-08-31T06:00:39.112940Z",
     "iopub.status.idle": "2026-08-31T06:00:39.114420Z",
     "shell.execute_reply": "2026-08-31T06:00:39.114279Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(25,)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_25 = np.arange(25)\n",
    "arr_25.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "41170132",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.115216Z",
     "iopub.status.busy": "2026-08-31T06:00:39.115175Z",
     "iopub.status.idle": "2026-08-31T06:00:39.116376Z",
     "shell.execute_reply": "2026-08-31T06:00:39.116170Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### 11 Exercise: Examine the shape attribute of different arrays:\n",
    "### - Create a 1-D array with 10 elements and print its shape\n",
    "### - Create a 2-D array with 3 rows and 5 columns, print its shape\n",
    "### - Reshape a 1-D array of 20 elements into a 4x5 array and print the shape before and after\n",
    "### - What does the trailing comma in (10,) mean?\n",
    "### Your code starts here: (use the space on the right when needed)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "b9706eab",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.117187Z",
     "iopub.status.busy": "2026-08-31T06:00:39.117147Z",
     "iopub.status.idle": "2026-08-31T06:00:39.118666Z",
     "shell.execute_reply": "2026-08-31T06:00:39.118516Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1-D array shape: (10,)\n",
      "2-D array shape: (3, 5)\n",
      "Before reshape - shape: (20,)\n",
      "After reshape - shape: (4, 5)\n",
      "Note: The trailing comma in (10,) indicates it's a 1-D array (tuple with one element)\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "# 1-D array\n",
    "arr_1d = np.arange(10)\n",
    "print(\"1-D array shape:\", arr_1d.shape)\n",
    "\n",
    "# 2-D array\n",
    "arr_2d = np.arange(15).reshape(3, 5)\n",
    "print(\"2-D array shape:\", arr_2d.shape)\n",
    "\n",
    "# Reshape example\n",
    "arr_original = np.arange(20)\n",
    "print(\"Before reshape - shape:\", arr_original.shape)\n",
    "\n",
    "arr_reshaped = arr_original.reshape(4, 5)\n",
    "print(\"After reshape - shape:\", arr_reshaped.shape)\n",
    "\n",
    "print(\"Note: The trailing comma in (10,) indicates it's a 1-D array (tuple with one element)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "array-size-heading",
   "metadata": {},
   "source": [
    "### size\n",
    "\n",
    "The `size` attribute returns the total number of elements in an array. For a 2-D array, this is the number of rows times the number of columns.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "array-size-example",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "shape: (2, 3)\n",
      "size: 6\n"
     ]
    }
   ],
   "source": [
    "arr_2d = np.array([[1, 2, 3],\n",
    "                   [4, 5, 6]])\n",
    "\n",
    "print(\"shape:\", arr_2d.shape)\n",
    "print(\"size:\", arr_2d.size)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c8afb95",
   "metadata": {},
   "source": [
    "## Indexing and Selection\n",
    "\n",
    "Just like Python lists, square brackets `[ ]` are used for selecting the elements or groups of elements from an array:\n",
    "1. Accessing individual elements of a list (**indexing**).\n",
    "2. Selecting sub-sequences (**slicing** with parameters: start, stop exclusive, and step). Note that slicing returns a numpy array.\n",
    "3. **Negative** indexing: begins with -1 from the end of the sequence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "5b859963",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.046244Z",
     "iopub.status.busy": "2026-08-31T06:00:39.046187Z",
     "iopub.status.idle": "2026-08-31T06:00:39.047731Z",
     "shell.execute_reply": "2026-08-31T06:00:39.047581Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.arange(0,10)   ### creating sample array\n",
    "arr             ### evaluate the array to display its contents\n",
    "                ### array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "3ddb4ade",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.048571Z",
     "iopub.status.busy": "2026-08-31T06:00:39.048510Z",
     "iopub.status.idle": "2026-08-31T06:00:39.049770Z",
     "shell.execute_reply": "2026-08-31T06:00:39.049623Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1 2 3 4 5 6 7 8 9]\n"
     ]
    }
   ],
   "source": [
    "print(arr)                  ### better looking of array output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "144b5e99",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.050520Z",
     "iopub.status.busy": "2026-08-31T06:00:39.050470Z",
     "iopub.status.idle": "2026-08-31T06:00:39.051607Z",
     "shell.execute_reply": "2026-08-31T06:00:39.051474Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape: (10,)\n",
      "Dim  : 1\n"
     ]
    }
   ],
   "source": [
    "\n",
    "print(\"Shape:\", arr.shape)  ### shape of the array\n",
    "print(\"Dim  :\", arr.ndim)   ### dimension of the array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "cff9d120-a679-4031-8b51-af94d13af281",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.052349Z",
     "iopub.status.busy": "2026-08-31T06:00:39.052303Z",
     "iopub.status.idle": "2026-08-31T06:00:39.053756Z",
     "shell.execute_reply": "2026-08-31T06:00:39.053590Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "[0 1 2]\n",
      "[0 2 4]\n",
      "9\n",
      "[7 8]\n"
     ]
    }
   ],
   "source": [
    "print(arr[1])               ### indexing \n",
    "print(arr[0:3])             ### slicing\n",
    "print(arr[0:5:2])           ### slicing with step size\n",
    "print(arr[-1])              ### negative indexing\n",
    "print(arr[-3:-1])           ### slicing with negative indices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75dee063",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.054570Z",
     "iopub.status.busy": "2026-08-31T06:00:39.054522Z",
     "iopub.status.idle": "2026-08-31T06:00:39.055788Z",
     "shell.execute_reply": "2026-08-31T06:00:39.055607Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Create an array from 0 to 9 using `np.arange()`. \n",
    "### Then perform the following operations:\n",
    "### - Get the element at index 5\n",
    "### - Get elements from index 2 to 6 (exclusive)\n",
    "### - Get every second element starting from index 1\n",
    "### - Get the last 3 elements using negative indexing\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "44787c86",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.056661Z",
     "iopub.status.busy": "2026-08-31T06:00:39.056597Z",
     "iopub.status.idle": "2026-08-31T06:00:39.058163Z",
     "shell.execute_reply": "2026-08-31T06:00:39.057989Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Element at index 5: 5\n",
      "Elements from index 2 to 6: [2 3 4 5]\n",
      "Every second element from index 1: [1 3 5 7 9]\n",
      "Last 3 elements: [7 8 9]\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "arr = np.arange(0, 10)\n",
    "\n",
    "print(\"Element at index 5:\", arr[5])\n",
    "print(\"Elements from index 2 to 6:\", arr[2:6])\n",
    "print(\"Every second element from index 1:\", arr[1::2])\n",
    "print(\"Last 3 elements:\", arr[-3:])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93b06c22-5a6e-4dba-8c44-702dc4c9adf8",
   "metadata": {},
   "source": [
    "### Indexing/Slicing 2-D Arrays\n",
    "\n",
    "To access a 2-D array (matrices), use the syntax `array[row_index, column_index]`. The general format is **arr[row][col]** or **arr[row, col]**. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "5a65781b-cbce-430c-a874-7b60f6073804",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.059070Z",
     "iopub.status.busy": "2026-08-31T06:00:39.059019Z",
     "iopub.status.idle": "2026-08-31T06:00:39.060589Z",
     "shell.execute_reply": "2026-08-31T06:00:39.060432Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 5, 10, 15],\n",
       "       [20, 25, 30],\n",
       "       [35, 40, 45]])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### creating a 2-d array\n",
    "\n",
    "arr_2d = np.array(([5,10,15],[20,25,30],[35,40,45]))\n",
    "arr_2d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "5f78ea18-68c2-45b6-b149-b689aa76a3c2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.061399Z",
     "iopub.status.busy": "2026-08-31T06:00:39.061344Z",
     "iopub.status.idle": "2026-08-31T06:00:39.062783Z",
     "shell.execute_reply": "2026-08-31T06:00:39.062643Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5, 10, 15])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### 0-based indexing; 1st row. It will return the first row of the \n",
    "### 2D array, which is [5, 10, 15].\n",
    "arr_2d[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "58d30410-828d-4609-85b3-6edb343cd84f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.063627Z",
     "iopub.status.busy": "2026-08-31T06:00:39.063586Z",
     "iopub.status.idle": "2026-08-31T06:00:39.065027Z",
     "shell.execute_reply": "2026-08-31T06:00:39.064862Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.int64(30)"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### 0-based indexing; 2nd row, 3rd column. It will return the \n",
    "### element at the second row and third column of the 2D array, which is 30.\n",
    "arr_2d[1, 2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "af96dac7-e2fc-41a4-9751-930afad9620c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.065852Z",
     "iopub.status.busy": "2026-08-31T06:00:39.065808Z",
     "iopub.status.idle": "2026-08-31T06:00:39.067232Z",
     "shell.execute_reply": "2026-08-31T06:00:39.067072Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[10, 15],\n",
       "       [25, 30]])"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### 2D array slicing\n",
    "### shape (2,2) from top right corner\n",
    "\n",
    "arr_2d[:2, 1:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "5efc414e",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T06:00:39.087218Z",
     "iopub.status.busy": "2026-08-31T06:00:39.087176Z",
     "iopub.status.idle": "2026-08-31T06:00:39.088381Z",
     "shell.execute_reply": "2026-08-31T06:00:39.088224Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### 8 Exercise: Create a 3x4 2-D array containing the values 1 through 12. Then:\n",
    "### - Extract the first and last rows\n",
    "### - Extract the middle two columns\n",
    "### - Extract a 2x2 subarray from the center of the matrix\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f95e6402",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First and last rows:\n",
      "[[ 1  2  3  4]\n",
      " [ 9 10 11 12]]\n",
      "Middle two columns:\n",
      "[[ 2  3]\n",
      " [ 6  7]\n",
      " [10 11]]\n",
      "Center 2x2 subarray:\n",
      "[[2 3]\n",
      " [6 7]]\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "import numpy as np\n",
    "\n",
    "matrix = np.arange(1, 13).reshape(3, 4)\n",
    "\n",
    "print(\"First and last rows:\")\n",
    "print(matrix[[0, -1], :])\n",
    "print(\"Middle two columns:\")\n",
    "print(matrix[:, 1:3])\n",
    "print(\"Center 2x2 subarray:\")\n",
    "print(matrix[:2, 1:3])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eae1f027-20ea-46c5-8bee-5361be7967e4",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Summary\n",
    "\n",
    "This section covered the fundamental concepts of NumPy arrays. Below is a reference guide for the key concepts introduced above.\n",
    "\n",
    "### Array Creation\n",
    "\n",
    "- `np.array()`: Convert lists/tuples to arrays\n",
    "- `np.arange()`: Create arrays with evenly spaced values\n",
    "- `np.linspace()`: Create arrays with specified number of elements\n",
    "- `np.zeros()`, `np.ones()`: Create arrays filled with 0s or 1s\n",
    "- `np.eye()`: Create identity matrices\n",
    "- `np.full()`: Fill arrays with a specific value\n",
    "\n",
    "```python\n",
    "import numpy as np\n",
    "\n",
    "a = np.array([1, 2, 3])\n",
    "z = np.zeros((2, 3))\n",
    "o = np.ones((3, 2))\n",
    "f = np.full((2, 2), 7)\n",
    "r = np.arange(0, 10, 2)\n",
    "l = np.linspace(0, 1, 5)\n",
    "i = np.eye(3)\n",
    "```\n",
    "\n",
    "### Array Attributes\n",
    "\n",
    "| Attribute | Description | Example |\n",
    "|---|---|---|\n",
    "| `shape` | Dimensions of array (returns tuple) | `arr.shape` → `(3, 4)` |\n",
    "| `dtype` | Data type of elements | `arr.dtype` → `int64` |\n",
    "| `ndim` | Number of dimensions | `arr.ndim` → `2` |\n",
    "\n",
    "```python\n",
    "a.shape\n",
    "a.ndim\n",
    "a.dtype\n",
    "```\n",
    "\n",
    "### Indexing Patterns\n",
    "\n",
    "**1-D arrays:**\n",
    "\n",
    "```python\n",
    "arr = np.array([10, 20, 30, 40, 50])\n",
    "arr[0]          # → 10 (first element)\n",
    "arr[-1]         # → 50 (last element)\n",
    "arr[1:4]        # → [20, 30, 40] (slice, stop exclusive)\n",
    "arr[::2]        # → [10, 30, 50] (every 2nd element)\n",
    "```\n",
    "\n",
    "**2-D arrays:**\n",
    "\n",
    "```python\n",
    "arr_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
    "arr_2d[0]       # → [1, 2, 3] (first row)\n",
    "arr_2d[1, 2]    # → 6 (row 1, column 2)\n",
    "arr_2d[:2, 1:]  # → [[2, 3], [5, 6]] (subarray)\n",
    "arr_2d[:, 0]    # → [1, 4, 7] (first column)\n",
    "```\n",
    "\n",
    "### Reshaping\n",
    "\n",
    "```python\n",
    "arr = np.arange(12)\n",
    "arr.reshape(3, 4)    # Reshape to 3x4 (returns new view/array)\n",
    "arr.shape            # Still (12,) - reshape doesn't modify original\n",
    "arr_reshaped = arr.reshape(3, 4)  # Assign to see changes\n",
    "```\n",
    "\n",
    "### Common Functions Summary\n",
    "\n",
    "- **Creation:** `array()`, `arange()`, `linspace()`, `zeros()`, `ones()`, `eye()`, `full()`\n",
    "- **Reshaping:** `reshape()`, `transpose()`, `concatenate()`\n",
    "- **Selection:** `where()`, `nonzero()`, `select()`\n",
    "- **Operations:** `sum()`, `mean()`, `std()`, `min()`, `max()`, `sort()`\n",
    "- **Math:** `abs()`, `round()`, `clip()`, `sqrt()`, `exp()`\n",
    "\n",
    "### Data Types\n",
    "\n",
    "```python\n",
    "np.array([1, 2, 3], dtype='int32')       # 32-bit integer\n",
    "np.array([1, 2, 3], dtype='float64')     # 64-bit float\n",
    "np.array([1, 2, 3], dtype='complex128')  # Complex number\n",
    "np.array(['a', 'b'], dtype='U5')         # Unicode string (max 5 chars)\n",
    "```\n",
    "\n",
    "```{note}\n",
    "A few related tools you'll meet soon: `size` and `nbytes` (memory usage), `astype()` (converting dtype), `flatten()`/`ravel()` (collapsing to 1-D), `.T`/`transpose()` (flipping axes), boolean indexing (`arr[arr > 2]`), fancy indexing (`arr[[0, 1], [1, 0]]`), and broadcasting (`arr + 5`). These build directly on the attributes and indexing covered here, and are introduced with worked examples in the sections ahead.\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "303cc7cd",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv (3.13.13)",
   "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.13.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
