{"cells":[{"cell_type":"markdown","id":"733f8cec","metadata":{"id":"733f8cec"},"source":["# Python Tutorial"]},{"cell_type":"markdown","id":"347cd487","metadata":{"id":"347cd487"},"source":["## Collections"]},{"cell_type":"markdown","id":"e691f94d","metadata":{"id":"e691f94d"},"source":["Python has several built-in types that are useful for storing and manipulating data: list, tuple, dict. Here is the official Python documentation on these types (and many others): https://docs.python.org/3/library/stdtypes.html."]},{"cell_type":"markdown","id":"635401d7","metadata":{"id":"635401d7"},"source":["### Lists"]},{"cell_type":"markdown","id":"ce42dfd9","metadata":{"id":"ce42dfd9"},"source":["Lists are mutable arrays. Let's see how they work."]},{"cell_type":"code","execution_count":1,"id":"3f24605e","metadata":{"id":"3f24605e","executionInfo":{"status":"ok","timestamp":1673649533739,"user_tz":480,"elapsed":4,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[],"source":["names = [\"Zach\", \"Jay\"]"]},{"cell_type":"code","execution_count":2,"id":"ae2fb323","metadata":{"id":"ae2fb323","outputId":"504fa423-23f8-42f9-9de1-183600722e3e","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649550431,"user_tz":480,"elapsed":311,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["Zach\n"]}],"source":["# Index into list by index\n","print(names[0])"]},{"cell_type":"code","execution_count":3,"id":"64066853","metadata":{"id":"64066853","outputId":"4de8cc78-90ae-496a-9960-32b2bca0efcb","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649560769,"user_tz":480,"elapsed":293,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["['Zach', 'Jay', 'Richard']\n"]}],"source":["# Append to list (appends to end of list)\n","names.append(\"Richard\")\n","print(names)"]},{"cell_type":"code","execution_count":4,"id":"357799cc","metadata":{"id":"357799cc","outputId":"0d92d03d-3a15-4ef6-83a7-96d6e6f36c61","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649576161,"user_tz":480,"elapsed":273,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["3\n"]}],"source":["# Get length of list\n","print(len(names))"]},{"cell_type":"code","execution_count":5,"id":"8977adcf","metadata":{"id":"8977adcf","outputId":"74b3cbe0-a3c6-4aaf-90b8-3f4335abe8c0","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649602924,"user_tz":480,"elapsed":282,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["['Zach', 'Jay', 'Richard', 'Abi', 'Kevin']\n"]}],"source":["# Concatenate two lists\n","# += operator is a short hand for list1 = list1 + list2 (can also be used for -, *, / and on other types of variables)\n","names += [\"Abi\", \"Kevin\"]\n","print(names)"]},{"cell_type":"code","execution_count":6,"id":"57c178a7","metadata":{"id":"57c178a7","executionInfo":{"status":"ok","timestamp":1673649607684,"user_tz":480,"elapsed":266,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[],"source":["# Two ways to create an empty list\n","more_names = []\n","more_names = list()"]},{"cell_type":"code","execution_count":7,"id":"7913fce7","metadata":{"scrolled":true,"id":"7913fce7","outputId":"0f91fe15-6e63-4894-a4dc-87ea34ccb531","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649622335,"user_tz":480,"elapsed":10,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[1, ['hi', 'bye'], -0.12, None]\n"]}],"source":["# Create a list that contains different data types, this is allowed in Python\n","stuff = [1, [\"hi\", \"bye\"], -0.12, None]\n","print(stuff)"]},{"cell_type":"markdown","id":"68682c20","metadata":{"id":"68682c20"},"source":["List slicing is a useful way to access a slice of elements in a list."]},{"cell_type":"code","execution_count":8,"id":"8fc049ef","metadata":{"id":"8fc049ef","outputId":"37a1b397-b34f-4f07-82a2-5392bd614ea3","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649650580,"user_tz":480,"elapsed":14,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[0, 1, 2]\n"]}],"source":["numbers = [0, 1, 2, 3, 4, 5, 6]\n","\n","# Slices from start index (inclusive) to end index (exclusive)\n","print(numbers[0:3])"]},{"cell_type":"code","execution_count":9,"id":"3e34a509","metadata":{"id":"3e34a509","outputId":"764bdcdb-794b-48e7-d12b-1095e91b0cbf","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649684834,"user_tz":480,"elapsed":281,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[0, 1, 2]\n","[5, 6]\n"]}],"source":["# When start index is not specified, it is start of list\n","# When end index is not specified, it is end of list\n","print(numbers[:3])\n","print(numbers[5:])"]},{"cell_type":"code","execution_count":10,"id":"813da35a","metadata":{"id":"813da35a","outputId":"bc547329-e265-4659-82ef-e30b0ef409fd","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649714675,"user_tz":480,"elapsed":275,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[0, 1, 2, 3, 4, 5, 6]\n"]}],"source":["# : takes the slice of all elements along a dimension, is very useful when working with numpy arrays\n","print(numbers[:])"]},{"cell_type":"code","execution_count":11,"id":"eaa197af","metadata":{"id":"eaa197af","outputId":"4c1738c0-3cc2-46a5-ea02-ae37f426f6ae","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649760432,"user_tz":480,"elapsed":808,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["6\n","[4, 5, 6]\n","[3, 4]\n"]}],"source":["# Negative index wraps around, start counting from the end of list\n","print(numbers[-1])\n","print(numbers[-3:])\n","print(numbers[3:-2])"]},{"cell_type":"markdown","id":"22371049","metadata":{"id":"22371049"},"source":["### Tuples"]},{"cell_type":"markdown","id":"bfca6098","metadata":{"id":"bfca6098"},"source":["Tuples are immutable arrays. Let's see how they work."]},{"cell_type":"code","execution_count":12,"id":"b542e470","metadata":{"id":"b542e470","executionInfo":{"status":"ok","timestamp":1673649778779,"user_tz":480,"elapsed":274,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[],"source":["# Use parentheses for tuples, square brackets for lists\n","names = (\"Zach\", \"Jay\")"]},{"cell_type":"code","execution_count":13,"id":"3906a033","metadata":{"id":"3906a033","outputId":"d589ddd8-c62f-4f23-8790-9b9f9dd2b744","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649783291,"user_tz":480,"elapsed":277,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["Zach\n","2\n"]}],"source":["# Syntax for accessing an element and getting length are the same as lists\n","print(names[0])\n","print(len(names))"]},{"cell_type":"code","execution_count":14,"id":"8799a4c5","metadata":{"id":"8799a4c5","outputId":"d85ff2f2-9d9c-40ee-bda3-5dbcb4b5841e","colab":{"base_uri":"https://localhost:8080/","height":182},"executionInfo":{"status":"error","timestamp":1673649786255,"user_tz":480,"elapsed":286,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"error","ename":"TypeError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)","\u001b[0;32m<ipython-input-14-8ab9a31bdd3d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# But unlike lists, tuples do not support item re-assignment\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"Richard\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"]}],"source":["# But unlike lists, tuples do not support item re-assignment\n","names[0] = \"Richard\""]},{"cell_type":"code","execution_count":16,"id":"9918ac4b","metadata":{"id":"9918ac4b","outputId":"5df94620-0758-4a17-9b78-11840d7ed227","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673649824090,"user_tz":480,"elapsed":755,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["()\n","(10,)\n"]}],"source":["# Create an empty tuple\n","empty = tuple()\n","print(empty)\n","\n","# Create a tuple with a single item, the comma is important\n","single = (10,)\n","print(single)"]},{"cell_type":"markdown","id":"00800704","metadata":{"id":"00800704"},"source":["## Dictionary"]},{"cell_type":"markdown","id":"8111c6c3","metadata":{"id":"8111c6c3"},"source":["Dictionaries are hash maps. Let's see how they work."]},{"cell_type":"code","execution_count":17,"id":"646bda2f","metadata":{"id":"646bda2f","executionInfo":{"status":"ok","timestamp":1673649888624,"user_tz":480,"elapsed":270,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[],"source":["# Two ways to create an empty dictionary\n","phonebook = {}\n","phonebook = dict()"]},{"cell_type":"code","execution_count":null,"id":"65c67196","metadata":{"id":"65c67196"},"outputs":[],"source":["# Create dictionary with one item \n","phonebook = {\"Zach\": \"12-37\"}\n","# Add another item\n","phonebook[\"Jay\"] = \"34-23\""]},{"cell_type":"code","execution_count":null,"id":"1bc431d9","metadata":{"id":"1bc431d9","outputId":"f854999e-2bf3-4ad9-af67-0b9f214bf143","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585243248,"user_tz":480,"elapsed":186,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["True\n","False\n"]}],"source":["# Check if a key is in the dictionary\n","print(\"Zach\" in phonebook)\n","print(\"Kevin\" in phonebook)"]},{"cell_type":"code","execution_count":null,"id":"87018123","metadata":{"id":"87018123","outputId":"6706a4e5-aec7-40a7-9d1f-915558b9a582","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585244341,"user_tz":480,"elapsed":173,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["34-23\n"]}],"source":["# Get corresponding value for a key\n","print(phonebook[\"Jay\"])"]},{"cell_type":"code","execution_count":null,"id":"18555a3a","metadata":{"id":"18555a3a","outputId":"def9ea35-d497-4278-ca9e-1777542a7357","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585245996,"user_tz":480,"elapsed":9,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["{'Jay': '34-23'}\n"]}],"source":["# Delete an item\n","del phonebook[\"Zach\"]\n","print(phonebook)"]},{"cell_type":"markdown","id":"60aceb86","metadata":{"id":"60aceb86"},"source":["## Loops"]},{"cell_type":"code","execution_count":18,"id":"f7189f9d","metadata":{"id":"f7189f9d","outputId":"fca407da-ccfc-4c8d-b3f8-2cb056ee16e7","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673650022884,"user_tz":480,"elapsed":9,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["0\n","1\n","2\n","3\n","4\n"]}],"source":["# Basic for loop\n","for i in range(5):\n","    print(i)"]},{"cell_type":"code","execution_count":19,"id":"10ae15db","metadata":{"id":"10ae15db","outputId":"04a5147c-fc24-4376-9f87-31cc7d0ef041","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673650052657,"user_tz":480,"elapsed":404,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["Zach\n","Jay\n","Richard\n"]}],"source":["# To iterate over a list\n","names = [\"Zach\", \"Jay\", \"Richard\"]\n","for name in names:\n","    print(name)"]},{"cell_type":"code","execution_count":20,"id":"00d5035b","metadata":{"id":"00d5035b","outputId":"e5f8d3f3-02c5-48fe-833e-93123a3ad5f5","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673650087572,"user_tz":480,"elapsed":269,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["0 Zach\n","1 Jay\n","2 Richard\n","---\n","0 Zach\n","1 Jay\n","2 Richard\n"]}],"source":["# To iterate over indices and values in a list\n","# Way 1\n","for i in range(len(names)):\n","    print(i, names[i])\n","    \n","print(\"---\")\n","\n","# Way 2\n","for i, name in enumerate(names):\n","    print(i, name)"]},{"cell_type":"code","execution_count":21,"id":"f18b7ce6","metadata":{"id":"f18b7ce6","outputId":"68d2057f-4d63-4a7f-c5a2-359add5a71c3","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673650121992,"user_tz":480,"elapsed":807,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["Zach\n","Jay\n","---\n","12-37\n","34-23\n","---\n","Zach 12-37\n","Jay 34-23\n"]}],"source":["# To iterate over a dictionary\n","phonebook = {\"Zach\": \"12-37\", \"Jay\": \"34-23\"}\n","\n","# Iterate over keys\n","for name in phonebook:\n","    print(name)\n","\n","print(\"---\")\n","\n","# Iterate over values\n","for number in phonebook.values():\n","    print(number)\n","\n","print(\"---\")\n","\n","# Iterate over keys and values\n","for name, number in phonebook.items():\n","    print(name, number)"]},{"cell_type":"markdown","id":"e9661ef4","metadata":{"id":"e9661ef4"},"source":["## NumPy\n","NumPy is a Python library, which adds support for large, multi-dimensional arrays and matrices, along with a large collection of optimized, high-level mathematical functions to operate on these arrays."]},{"cell_type":"markdown","id":"ecdb0df8","metadata":{"id":"ecdb0df8"},"source":["You may need to install numpy first before importing it in the next cell. \n","\n","There are many ways to manage your packages, but the workflow we suggest for this class is to use Anaconda.\n"," - Download Anaconda. Create a conda environment when you work on a new project.\n"," - Activate your conda environment and install libraries using conda or pip if they are not available in conda.\n"," - If you are running scripts on command line, run inside your conda environment.\n"," - If you are using a Jupyter notebook, add your conda environment to your Jupyter notebook: https://towardsdatascience.com/get-your-conda-environment-to-show-in-jupyter-notebooks-the-easy-way-17010b76e874. Create your Jupyter notebook and verify you're in your conda environment kernel (top right of notebook should display the name). If you're not, go to the Kernel tab on the top left and click Change kernel to change to your conda environment kernel."]},{"cell_type":"code","execution_count":23,"id":"ab7d3f32","metadata":{"id":"ab7d3f32","executionInfo":{"status":"ok","timestamp":1673650783782,"user_tz":480,"elapsed":275,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[],"source":["# Import numpy\n","import numpy as np"]},{"cell_type":"code","execution_count":null,"id":"6596eb30","metadata":{"scrolled":false,"id":"6596eb30","outputId":"b08c870b-0e1a-4129-bfb8-b94ca4fca602","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585453555,"user_tz":480,"elapsed":192,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["(3,)\n","(1, 3)\n","\n","[[6 7]\n"," [8 9]]\n","(2, 2)\n"]}],"source":["# Create numpy arrays from lists\n","x = np.array([1,2,3])\n","a = np.array([[1,2,3]])\n","\n","\n","y = np.array([[3,4,5]]) \n","z = np.array([[6,7],[8,9]])\n","\n","# Let's take a look at their shapes.\n","# When working with numpy arrays, .shape will be a very useful debugging tool \n","print(x.shape)\n","print(y.shape)\n","print()\n","print(z)\n","print(z.shape)"]},{"cell_type":"markdown","id":"f4b465bf","metadata":{"id":"f4b465bf"},"source":["Vectors can be represented as 1-D arrays of shape (N,) or 2-D arrays of shape (N, 1) or (1, N). But it's important to note that the shapes (N,), (N, 1), and (1,N) are not the same and may result in different behavior (we'll see some examples below involving matrix multiplication and broadcasting).\n","\n","Matrices are generally represented as 2-D arrays of shape (M, N).\n","\n","The best way to ensure your code gives you the behavior you expect is to keep track of your array shapes and try out small test cases or refer back to documentation when you are unsure."]},{"cell_type":"code","source":["a = np.arange(10)\n","b = a.reshape((5, 2))\n","print(a)\n","print()\n","print(b)"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"A0Wl4qioLmb-","executionInfo":{"status":"ok","timestamp":1673650787123,"user_tz":480,"elapsed":266,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}},"outputId":"120b2e64-68d3-4f7a-e643-6b7a0a91aece"},"id":"A0Wl4qioLmb-","execution_count":24,"outputs":[{"output_type":"stream","name":"stdout","text":["[0 1 2 3 4 5 6 7 8 9]\n","\n","[[0 1]\n"," [2 3]\n"," [4 5]\n"," [6 7]\n"," [8 9]]\n"]}]},{"cell_type":"markdown","id":"bcb3f37c","metadata":{"id":"bcb3f37c"},"source":["### Array Operations"]},{"cell_type":"markdown","id":"18a8a694","metadata":{"id":"18a8a694"},"source":["There are many NumPy operations that can be used to reduce a numpy array along an axis.\n","\n","Let's look at the np.max operation (documentation: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.max.html)."]},{"cell_type":"code","execution_count":25,"id":"1fcf4220","metadata":{"id":"1fcf4220","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673650844528,"user_tz":480,"elapsed":296,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}},"outputId":"4b63370e-2eb1-4891-9e2b-051a8484276e"},"outputs":[{"output_type":"stream","name":"stdout","text":["[[1 2]\n"," [3 4]\n"," [5 6]]\n","\n","(3, 2)\n"]}],"source":["x = np.array([[1,2],[3,4], [5, 6]]) \n","print(x)\n","print()\n","print(x.shape)"]},{"cell_type":"code","execution_count":null,"id":"df82f62e","metadata":{"id":"df82f62e","outputId":"e5dffa24-26d4-47b2-fbb4-7853d049bdee","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585872119,"user_tz":480,"elapsed":9,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[2 4 6]\n"]}],"source":["print(np.max(x, axis = 1))"]},{"cell_type":"code","source":["print(np.max(x, axis = 1).shape)"],"metadata":{"id":"WDWPbijv7xsw","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585872405,"user_tz":480,"elapsed":6,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}},"outputId":"a595b672-585a-4ef4-c62c-debff4c1cf61"},"id":"WDWPbijv7xsw","execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["(3,)\n"]}]},{"cell_type":"code","execution_count":null,"id":"0e888b74","metadata":{"id":"0e888b74","outputId":"3548a983-7500-4f6b-c3e9-65b1a99275fa","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585877940,"user_tz":480,"elapsed":178,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[[2]\n"," [4]\n"," [6]]\n"]}],"source":["print(np.max(x, axis = 1, keepdims = True))"]},{"cell_type":"code","source":["print(np.max(x, axis = 1, keepdims = True).shape)"],"metadata":{"id":"bs1NM9oR703c","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585880202,"user_tz":480,"elapsed":261,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}},"outputId":"31c8119a-2e77-4451-8f9a-d3968a4d2b60"},"id":"bs1NM9oR703c","execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["(3, 1)\n"]}]},{"cell_type":"markdown","id":"29ff27ec","metadata":{"id":"29ff27ec"},"source":["Next, let's look at some matrix operations. Let's take an element-wise product (Hadamard product)."]},{"cell_type":"code","execution_count":null,"id":"25aeb52d","metadata":{"id":"25aeb52d","outputId":"e4bfaf4f-7bfa-472e-eac7-ac2e6390c13c","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585910580,"user_tz":480,"elapsed":269,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[[1 2]\n"," [3 4]]\n","[[3 3]\n"," [3 3]]\n","---\n","[[ 3  6]\n"," [ 9 12]]\n"]}],"source":["A = np.array([[1, 2], [3, 4]])\n","B = np.array([[3, 3], [3, 3]])\n","print(A)\n","print(B)\n","print(\"---\")\n","print(A * B)"]},{"cell_type":"markdown","id":"689f2a8d","metadata":{"id":"689f2a8d"},"source":["We can do matrix multiplication with np.matmul or @."]},{"cell_type":"code","execution_count":null,"id":"c76ec303","metadata":{"id":"c76ec303","outputId":"d36b6d3d-5cad-497b-d263-25f6107a7fd2","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585950055,"user_tz":480,"elapsed":246,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[[ 9  9]\n"," [21 21]]\n","[[ 9  9]\n"," [21 21]]\n"]}],"source":["# One way to do matrix multiplication\n","print(np.matmul(A, B))\n","\n","# Another way to do matrix multiplication\n","print(A @ B)"]},{"cell_type":"markdown","id":"62696957","metadata":{"id":"62696957"},"source":["We can take the dot product or a matrix vector product with np.dot. "]},{"cell_type":"code","execution_count":null,"id":"0caf84b9","metadata":{"id":"0caf84b9","outputId":"a9feee27-6a8f-4e75-9ba3-243569a1e62f","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585960240,"user_tz":480,"elapsed":172,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["321\n","321\n"]}],"source":["u = np.array([1, 2, 3])\n","v = np.array([1, 10, 100])\n","\n","print(np.dot(u, v))\n","\n","# Can also call numpy operations on the numpy array, useful for chaining together multiple operations\n","print(u.dot(v))"]},{"cell_type":"code","execution_count":null,"id":"43e635bb","metadata":{"id":"43e635bb","outputId":"62cb79e7-a050-4e1c-a9b8-caedbe19a441","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673585976553,"user_tz":480,"elapsed":192,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["(3,)\n","(3, 2)\n","[531 642]\n","(2,)\n"]}],"source":["W = np.array([[1, 2], [3, 4], [5, 6]])\n","print(v.shape)\n","print(W.shape)\n","\n","# This works.\n","print(np.dot(v, W))\n","print(np.dot(v, W).shape)"]},{"cell_type":"code","execution_count":null,"id":"683dd6ee","metadata":{"id":"683dd6ee","outputId":"f336b678-ff97-4192-bf69-fac68817342a","colab":{"base_uri":"https://localhost:8080/","height":217},"executionInfo":{"status":"error","timestamp":1673585979556,"user_tz":480,"elapsed":196,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"error","ename":"ValueError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)","\u001b[0;32m<ipython-input-42-c21878d615cb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# This does not. Why?\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mW\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[0;32m<__array_function__ internals>\u001b[0m in \u001b[0;36mdot\u001b[0;34m(*args, **kwargs)\u001b[0m\n","\u001b[0;31mValueError\u001b[0m: shapes (3,2) and (3,) not aligned: 2 (dim 1) != 3 (dim 0)"]}],"source":["# This does not. Why?\n","print(np.dot(W, v))"]},{"cell_type":"code","execution_count":null,"id":"9e8b2184","metadata":{"id":"9e8b2184","outputId":"b89a0299-edda-47fb-87a5-1b28b85b5242","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586004681,"user_tz":480,"elapsed":181,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[531 642]\n","(2,)\n"]}],"source":["# We can fix the above issue by transposing W.\n","print(np.dot(W.T, v))\n","print(np.dot(W.T, v).shape)"]},{"cell_type":"markdown","id":"c13199d8","metadata":{"id":"c13199d8"},"source":["###  Indexing"]},{"cell_type":"markdown","id":"d3d3d5c2","metadata":{"id":"d3d3d5c2"},"source":["Slicing / indexing numpy arrays is a extension of the Python concept of slicing (lists) to N dimensions."]},{"cell_type":"code","execution_count":26,"id":"bb930e29","metadata":{"scrolled":true,"id":"bb930e29","outputId":"6bc7bcbe-3313-456b-c4e2-a542d4a63a06","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673651476467,"user_tz":480,"elapsed":334,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[[0.59539247 0.44943372 0.6974783  0.74086032]\n"," [0.05439564 0.49684488 0.53743562 0.45502382]\n"," [0.84378783 0.14212709 0.65069361 0.81998942]]\n"]}],"source":["x = np.random.random((3, 4))\n","\n","# Selects all of x\n","print(x[:])"]},{"cell_type":"code","execution_count":null,"id":"16d0fe9a","metadata":{"id":"16d0fe9a","outputId":"07b3702f-64f6-437f-8b5d-26d72ffd1d00","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586184852,"user_tz":480,"elapsed":195,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[[0.08741133 0.23348194 0.10838167 0.22120641]\n"," [0.77255779 0.00482836 0.10692647 0.11250782]]\n","---\n","[0.02177989 0.17319822]\n"]}],"source":["# Selects the 0th and 2nd rows \n","print(x[np.array([0, 2]), :])\n","\n","print(\"---\")\n","\n","# Selects 1st row as 1-D vector and and 1st through 2nd elements\n","print(x[1, 1:3])"]},{"cell_type":"code","execution_count":27,"id":"04bf1911","metadata":{"id":"04bf1911","outputId":"9fa8d581-f646-46cf-a752-f01a1ced48ca","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673651486299,"user_tz":480,"elapsed":275,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[0.59539247 0.6974783  0.74086032 0.53743562 0.84378783 0.65069361\n"," 0.81998942]\n"]}],"source":["# Boolean indexing\n","print(x[x > 0.5])"]},{"cell_type":"code","execution_count":null,"id":"118924a3","metadata":{"id":"118924a3","outputId":"79d5d19b-1230-4728-8f6e-039aa56fe7f0","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586204662,"user_tz":480,"elapsed":206,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["[[[0.08741133]\n","  [0.23348194]\n","  [0.10838167]\n","  [0.22120641]]\n","\n"," [[0.36210074]\n","  [0.02177989]\n","  [0.17319822]\n","  [0.19521131]]\n","\n"," [[0.77255779]\n","  [0.00482836]\n","  [0.10692647]\n","  [0.11250782]]]\n"]}],"source":["# 3-D vector of shape (3, 4, 1)\n","print(x[:, :, np.newaxis])"]},{"cell_type":"markdown","id":"48e1704f","metadata":{"id":"48e1704f"},"source":["### Broadcasting"]},{"cell_type":"markdown","id":"40d35521","metadata":{"id":"40d35521"},"source":["The term broadcasting describes how NumPy treats arrays with different shapes during arithmetic operations.\n","\n","**General Broadcasting Rules**\n","\n","When operating on two arrays, NumPy compares their shapes element-wise. It starts with the trailing (i.e. rightmost) dimensions and works its way left. Two dimensions are compatible when:\n","- they are equal, or\n","- one of them is 1 (in which case, elements on the axis are repeated along the dimension)\n","\n","More details: https://numpy.org/doc/stable/user/basics.broadcasting.html"]},{"cell_type":"code","execution_count":28,"id":"e3f0c8b1","metadata":{"id":"e3f0c8b1","executionInfo":{"status":"ok","timestamp":1673651845027,"user_tz":480,"elapsed":279,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[],"source":["x = np.random.random((3, 4))\n","\n","y = np.random.random((3, 1))\n","z = np.random.random((1, 4))\n","\n","# In this example, y and z are broadcasted to match the shape of x. \n","# y is broadcasted along dim 1.\n","s = x + y\n","# z is broadcasted along dim 0.\n","p = x * z"]},{"cell_type":"code","execution_count":29,"id":"93cdfc8a","metadata":{"id":"93cdfc8a","outputId":"a350d379-ffc0-4366-d430-1e04af352fac","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673651846102,"user_tz":480,"elapsed":8,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["(3, 4)\n","\n","(3, 1)\n","(3, 4)\n"]}],"source":["print(x.shape)\n","print()\n","print(y.shape)\n","print(s.shape)"]},{"cell_type":"code","execution_count":null,"id":"a77b76bc","metadata":{"id":"a77b76bc","outputId":"e7086c7a-51b8-45a7-838f-4d7f270e2bcd","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586493536,"user_tz":480,"elapsed":14,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["(3, 4)\n","\n","(3, 4)\n","(3, 4)\n"]}],"source":["print(x.shape)\n","print()\n","print(s.shape)\n","print(p.shape)"]},{"cell_type":"code","source":["a = np.zeros((3, 3))\n","b = np.array([[1, 2, 3]])\n","print(a)\n","print()\n","print(a+b)"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"FICMa8RiMR08","executionInfo":{"status":"ok","timestamp":1673651977203,"user_tz":480,"elapsed":278,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}},"outputId":"38f90bfd-f567-4e14-d18e-d54ac7a23d79"},"id":"FICMa8RiMR08","execution_count":30,"outputs":[{"output_type":"stream","name":"stdout","text":["[[0. 0. 0.]\n"," [0. 0. 0.]\n"," [0. 0. 0.]]\n","\n","[[1. 2. 3.]\n"," [1. 2. 3.]\n"," [1. 2. 3.]]\n"]}]},{"cell_type":"markdown","id":"fec8ae1e","metadata":{"id":"fec8ae1e"},"source":["Let's look at a more complex example."]},{"cell_type":"code","execution_count":null,"id":"2b1b271d","metadata":{"id":"2b1b271d"},"outputs":[],"source":["a = np.random.random((3, 4))\n","b = np.random.random((3, 1))\n","c = np.random.random((3, ))"]},{"cell_type":"markdown","id":"972fda59","metadata":{"id":"972fda59"},"source":["What is the expected broadcasting behavior for these operations? What do the following operations give us? What are the resulting shapes?"]},{"cell_type":"code","execution_count":null,"id":"ab0e1d5b","metadata":{"id":"ab0e1d5b","outputId":"95735143-16d4-4d23-994c-3220e7caa718","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586530771,"user_tz":480,"elapsed":12,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["(3, 1)\n","(1, 3)\n","(3, 3)\n","[[0.11647105 0.94317868 0.80520919]\n"," [0.94317868 1.76988632 1.63191683]\n"," [0.80520919 1.63191683 1.49394734]]\n"]}],"source":["result1 = b + b.T\n","\n","print(b.shape)\n","print(b.T.shape)\n","print(result1.shape)\n","print(result1)"]},{"cell_type":"code","execution_count":null,"id":"d7e113be","metadata":{"scrolled":true,"id":"d7e113be","outputId":"67f13069-0f4c-4230-a3e7-05ba480acb73","colab":{"base_uri":"https://localhost:8080/","height":235},"executionInfo":{"status":"error","timestamp":1673586536407,"user_tz":480,"elapsed":200,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"error","ename":"ValueError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)","\u001b[0;32m<ipython-input-59-490e280e0ca0>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mresult2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (3,4) (3,) "]}],"source":["result2 = a + c\n","\n","print(a.shape)\n","print(c.shape)\n","print(result2.shape)\n","print(result2)"]},{"cell_type":"code","execution_count":null,"id":"e91c0c70","metadata":{"id":"e91c0c70","outputId":"0a6f644c-9e73-43e9-9215-207a8f3f7dc2","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586549856,"user_tz":480,"elapsed":205,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["(3, 1)\n","(3,)\n","(3, 3)\n","[[0.70180112 0.31264318 0.20256093]\n"," [1.52850876 1.13935081 1.02926857]\n"," [1.39053927 1.00138132 0.89129908]]\n"]}],"source":["result3 = b + c\n","\n","print(b.shape)\n","print(c.shape)\n","print(result3.shape)\n","print(result3)"]},{"cell_type":"markdown","id":"0a845479","metadata":{"id":"0a845479"},"source":["### Efficient NumPy Code"]},{"cell_type":"markdown","id":"55c8d74f","metadata":{"id":"55c8d74f"},"source":["When working with numpy arrays, avoid explicit for-loops over indices/axes at all costs. For-loops will dramatically slow down your code (~10-100x)."]},{"cell_type":"markdown","id":"e1285d83","metadata":{"id":"e1285d83"},"source":["We can time code using the %%timeit magic. Let's compare using explicit for-loop vs. using numpy operations."]},{"cell_type":"code","execution_count":null,"id":"ba02c912","metadata":{"id":"ba02c912","outputId":"62191287-3cdf-420a-c4e9-c7bcac31ad57","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586581653,"user_tz":480,"elapsed":3543,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["459 ms ± 10.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"]}],"source":["%%timeit\n","x = np.random.rand(1000, 1000)\n","for i in range(100, 1000):\n","    for j in range(x.shape[1]): \n","        x[i, j] += 5"]},{"cell_type":"code","execution_count":null,"id":"3c96fc83","metadata":{"id":"3c96fc83","outputId":"95c8a7c3-638c-4c2a-8f86-51492f60d85f","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1673586591781,"user_tz":480,"elapsed":10134,"user":{"displayName":"Manasi Sharma","userId":"12687714104299829826"}}},"outputs":[{"output_type":"stream","name":"stdout","text":["12.2 ms ± 143 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"]}],"source":["%%timeit\n","x = np.random.rand(1000, 1000)\n","x[np.arange(100,1000), :] += 5 "]},{"cell_type":"code","execution_count":null,"id":"72b832dd","metadata":{"id":"72b832dd"},"outputs":[],"source":[]}],"metadata":{"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.9.7"},"colab":{"provenance":[]}},"nbformat":4,"nbformat_minor":5}