{ "cells": [ { "cell_type": "markdown", "id": "09b45faf-3240-429f-9ba3-9a2185094d6f", "metadata": {}, "source": [ "# Cut material from Python tutorial\n", "\n", "Imported stuff from [`python_tutorial.ipynb`](./python_tutorial.ipynb)." ] }, { "cell_type": "code", "execution_count": null, "id": "9f5e7830-4708-4f00-91ef-e97afac0475a", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "a4e9450d-c741-4a3d-aa9a-3e4937cf76a4", "metadata": {}, "source": [ "### Python for data science and statistics\n", "\n", "Python is a popular language for data analysis\n", "because of the numerous functions it provides for data management, \n", "data visualization, and statistics.\n", "\n", "Learning to use these Python functions will \n", " y\n", "\n", "Learning a few basic Python constructs like the `for` loop\n", "will enable you to simulate probability distributions and experimentally verify how statistics procedures work.\n", "This is a really big deal!\n", "If's good to know the statistical formula and recipes,\n", "but it's even better when you can run your own simulations and check when the formulas work and when they fail.\n", "\n", "Once you learn the basics of Python syntax,\n", "you'll have access to the best-in-class tools for\n", "data management (Pandas, see [pandas_tutorial.ipynb](./pandas_tutorial.ipynb)),\n", "data visualization (Seaborn, see [seaborn_tutorial.ipynb](./seaborn_tutorial.ipynb)),\n", "statistics (`scipy` and `statsmodels`).\n", "\n", "Don't worry there won't be any advanced math—just sums, products, exponents, logs, and square roots.\n", "Nothing fancy, I promise.\n", "If you've ever created a formula in a spreadsheet,\n", "then you're familiar with all the operations we'll see.\n", "In a spreadsheet formula you'd use `SUM(` in Python we write `sum(`.\n", "You see, it's nothing fancy.\n", "\n", "Yes, there will be a lot of code (paragraphs of Python commands) in this tutorial,\n", "but you can totally handle this.\n", "If you ever start to freak out an think \"OMG this is too complicated!\" remember that Python is just a fancy calculator." ] }, { "cell_type": "markdown", "id": "76fb25dc-6cb8-47ab-ac84-13226e4d066e", "metadata": {}, "source": [ "\n", "All in all, learning Python gives lots of tools to help you understand math and science topics.\n", "\n", "---\n", "\n", "take advantage of everything Python has to offer for data analysis and statistics.\n", "\n", "You can run JupyterLab on your computer or run JupyterLab on a remote server using a [binder link](https://mybinder.org/v2/gh/minireference/noBSstats/HEAD?labpath=tutorials/python_tutorial.ipynb).\n", "\n", "[`bit.ly/pytut3`](https://bit.ly/pytut3)\n", "\n", "**Alternatives**: If you don't want to install anything on your computer yet, you have two other options for playing with this notebook:\n", "- Run JupyterLab instance in the cloud via the binder link. Click [here](https://mybinder.org/v2/gh/minireference/noBSstats/HEAD?labpath=tutorials/python_tutorial.ipynb) to launch an interactive notebook of this tutorial.\n", "- You can also enable the \"Live Code\" feature while reading this tutorial online at [noBSstats.com](https://nobsstats.com/tutorials/python_tutorial.html). Use the rocket button in the top right, and choose the `Live Code` option to make all the cells in this notebook interactive.\n", "\n", "The notebook interface offers many useful features,\n", "but for now,\n", "I just want you to think of notebooks as an easy way to run Python code.\n" ] }, { "cell_type": "markdown", "id": "8d0f538f-ed54-4b98-9abf-ffff3911fa3d", "metadata": {}, "source": [ "Here is another example of an expression that uses the function `len` to compute the length of a list of numbers." ] }, { "cell_type": "code", "execution_count": 1, "id": "5fcd876f-644c-4b07-8447-ccbcdf61fcfb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len([1, 2, 3])" ] }, { "cell_type": "markdown", "id": "7bafc472-ed17-4eb8-bedc-7509093a2aa8", "metadata": {}, "source": [ "Here the function `len` received the list of numbers `[1, 2, 3]` as input, and produced the output `3` as output, which is the length of the list." ] }, { "cell_type": "code", "execution_count": null, "id": "b26855da-b4c0-421e-a2e8-132c1e2a8f6f", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "cfd79197-1b41-40d8-ba75-c79c81d46759", "metadata": {}, "source": [ "To store the result of an expression as a variable,\n", "we use the assignment operator `=` as follows, from left to right:\n", "\n", "* we start by writing the name of the variable\n", "* then, we add the symbol `=` (which stands for **assign to**)\n", "* finally, we write an expression for the value we want to store in the variable\n" ] }, { "cell_type": "code", "execution_count": null, "id": "3bc52183-385e-44af-8def-e0a16c2c4a95", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "cb9cbc00-61da-4438-bd02-02b6b71d47b6", "metadata": {}, "source": [ "Running the above code cell doesn't print anything,\n", "because we have only defined variables: `score`, `average`, `scores`, `message`, and `above_the_average`, but we didn't display them." ] }, { "cell_type": "markdown", "id": "49ac41dc-8ea2-4b09-8648-96884262292a", "metadata": {}, "source": [ "We'll use the generic variable name `obj` to refer to an object of any type." ] }, { "cell_type": "code", "execution_count": null, "id": "c16ef0b0-f042-41c8-9f02-8ce12ec1e4e9", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "412f5cfa-30f4-450a-84c6-75f6a47876ba", "metadata": {}, "source": [ "Notebooks allow us run Python commands interactively,\n", "which is the best way to learn!\n", "Try some Python commands to get a feeling of how code cells work.\n", "\n", "Remember you can click the play button in the toolbar\n", "(the first button in box (4) in the screenshot)\n", "or use the keyboard shortcut **SHIFT+ENTER** to run the code.\n", "\n", "I encourage you to play around with the notebook execution buttons in box (4).\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "fc959a3d-8688-41ca-8fdc-b75e12a5213c", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "e2919f6f-26c2-467b-8b1b-533e5b051020", "metadata": {}, "source": [ "## Review of math functions\n", "\n", "The Python syntax for functions is inspired by the syntax used for math functions,\n", "so we'll start with a quick overview the concepts of a function in mathematics.\n", "The convention in math to call functions with single letters like $f$, $g$, $h$, etc.\n", "We call denote the function inputs as $x$ and its outputs as $y$.\n", "\n", "We define the function $f$ by writing expression to compute for a given input $x$. \n", "\n", "$$ y = f(x) = \\text{some expression involving } x $$\n", "\n", "For example $f(x) = 2x+3$.\n", "\n", "Once we have defined the function $f$,\n", "we can evaluate the function for any possible input $x$.\n", "For example,\n", "the value of the function $f$ when $x=5$ is\n", "denoted $f(5)$ and is equal to $2(5) +3 = 10 + 3 = 13$.\n", "In other words, $f(5) = 13$.\n", "\n", "\n", "## Python functions\n", "Functions in Python are similar to functions in math: \n", "\n", "...\n", "\n", "In the above example,\n", "we intentionally chose the function name,\n", "and the name of its input and output\n", "to highlight the connection with with the math function example we saw earlier.\n" ] }, { "cell_type": "markdown", "id": "0b581e16-7884-41c8-bd7a-9c8e44369bd3", "metadata": {}, "source": [ "\n", "- `plotnine` another high-level library for data visualization base don the grammar of graphics principles\n", "- `scikit-learn` tools and algorithms for machine learning\n" ] }, { "cell_type": "code", "execution_count": null, "id": "89fae464-22ba-4a23-8103-135147507b43", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "29142e2c-2898-4ecf-91a4-abe9b13086ca", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "c3156c2c-b74a-4e8e-a05b-dbaa0184fdeb", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "1c810beb-433c-4905-be26-39dc0dc04f5b", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "6402c1f2-8752-4076-9894-7599457d0e2b", "metadata": {}, "source": [ "### Overview of the material in this tutorial\n", "\n", "We'll cover all essential topics required to get to know Python, including:\n", "\n", "- [Getting started](#Getting-started) where we'll install JupyterLab Desktop coding environment\n", "\n", "- [Expressions and variables](#Expressions-and-variables): basic building blocks of any program.\n", "\n", "- [Getting comfortable with Python](#Getting-comfortable-with-Python): looking around and getting help.\n", "\n", "- [Lists and for loops](#Lists-and-for-loops): repeating steps and procedures.\n", "\n", "- [Functions](#Functions) are reusable code blocks.\n", "\n", "- [Other data structures](#Other-data-structures): sets, tuples, etc. \n", " - [Boolean variables and conditional statements](#Boolean-variables-and-conditional-statements): conditional code execution.\n", " - [Dictionaries](#Dictionaries) are a versatile way to store data. \n", "\n", "- [Objects and classes](#Objects-and-classes): creating custom objects.\n", "\n", "- [Python grammar and syntax](#Python-grammar-and-syntax): review of all the syntax.\n", "\n", "- [Python libraries and modules](#Python-libraries-and-modules): learn why people say Python comes with \"batteries included\"\n", "\n", "After you're done with this tutorial, you'll be ready to read the other two:\n", "- Pandas (see [pandas_tutorial.ipynb](./pandas_tutorial.ipynb))\n", "- Seaborn (see [seaborn_tutorial.ipynb](./seaborn_tutorial.ipynb)) \n", "\n", "It's important for you to try solving the exercises that you'll encounter as you read along. The exercises are a great way to practice what you've been learning.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "3288af5c-2671-480a-b7e4-28e369b10a18", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 2, "id": "7a96667a-38eb-4275-9084-7695a5b88844", "metadata": {}, "outputs": [], "source": [ "## ALT. display both value and type on the same line (as a tuple)\n", "# score, type(score)" ] }, { "cell_type": "markdown", "id": "a838d3b7-b675-40cd-958d-2d7103f9be99", "metadata": {}, "source": [ "Python is a \"civilized\" language\n", " \n", " We'll now learn about some of these tools including, \"doc strings\" (help menus) and the different ways at learning\n", " \n", " at what attributes and methods are available to use.\n", "\n", " \n", "We'll now learn about some of these tools including,\n", "\n", "Above all, Python has a culture of being beginner friendly so \n", "\n", "This combination of tools allows programmers to answer common questions about Python objects and functions without leaving the JupyterLab environment. Basically, in Python all the necessary info is accessible directly in the coding environment.\n", "For example, at the end of this section you'll be able to answer the following questions on your own:\n", "\n", "- How many and what type of arguments does the function `print` expect?\n", "- What kind of optional, keyword arguments does the function `print` accept?\n", "- What attributes and methods does the Python object `obj` have?\n", "- What variables and functions are defined in the current namespace?\n", "\n", "More than 50% of any programmer's time is spent looking at help info and trying to understand the variables, functions, objects, and methods they are working with, so it's important for you to learn these meta-skills." ] }, { "cell_type": "code", "execution_count": null, "id": "af0d6704-8a21-4ff1-abde-fd49307bd349", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "367f79df-7641-4f9e-9113-7233cd16b8ff", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "4e5327fb-7ab9-4df9-950c-d366770896ef", "metadata": {}, "source": [ "You can also add longer, multi-line comments using triple-quoted text." ] }, { "cell_type": "code", "execution_count": 3, "id": "8ef94548-70bc-406c-8752-180ebb7f7730", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'\\nThis is a longer comment,\\nwhich is written on two lines.\\n'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"\n", "This is a longer comment,\n", "which is written on two lines.\n", "\"\"\"" ] }, { "cell_type": "markdown", "id": "5a016467-88b9-45c0-b0d4-56dbf20e84d5", "metadata": {}, "source": [ "The doc-strings we talked about earlier,\n", "were created by this kind of multi-line strings included in the source code of the functions `abs`, `len`, `sum`, `print`, etc." ] }, { "cell_type": "code", "execution_count": 4, "id": "5d2df7ae-b1c1-4e45-a702-a247530ad39b", "metadata": {}, "outputs": [], "source": [ "#### More exceptions " ] }, { "cell_type": "code", "execution_count": 5, "id": "9bb07b04-3ac7-49ed-8394-ee40e542262e", "metadata": {}, "outputs": [], "source": [ "\n", "# ValueError\n", "# int(\"zz\")\n", "\n", "# ZeroDivisionError\n", "# 5/0\n", "\n", "# KeyError\n", "# d = {}\n", "# d[\"zz\"]\n", "\n", "# ImportError\n", "# from math import zz\n", "\n", "# AttributeError\n", "# \"hello\".zz" ] }, { "cell_type": "markdown", "id": "01ab9e26-d5bb-4492-bfad-d6e2b1f8c5fb", "metadata": {}, "source": [ "## Exceptions\n", "The computer doesn't like what you entered.\n", "The output is a big red box,\n", "that tells you your input was REJECTED!\n", "\n", "if you type invalid syntax, assign to non-existing variables, or otherwise input something that Python doesn't like, Python will throw an \"exception,\" which is like saying \"Yo, I don't understand this, or I can't run this, or the code refers to some data that doesn't exist, etc.\" You'll see the name of the error that occurred and a message to explain what went wrong.\n" ] }, { "cell_type": "markdown", "id": "00dad10a-c674-480c-b781-aba0d70ab7d9", "metadata": {}, "source": [ "### Example: Learning about the `abs` function\n", "\n", "Let's say you're reading some Python code written by a friend,\n", "and they use the function `abs` in their code.\n", "Suppose you've never seen this function before,\n", "and you have no idea what it does." ] }, { "cell_type": "code", "execution_count": 6, "id": "6214555d-1127-4074-b073-bfaa98d56aea", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# put cursor in the middle of function and press SHIFT+TAB\n", "abs(-3)" ] }, { "cell_type": "markdown", "id": "d86153b6-e712-4bef-adce-4f3ee65104b5", "metadata": {}, "source": [ "We can also obtain the same information using the `help()` function on `abs`." ] }, { "cell_type": "code", "execution_count": 7, "id": "7d8a6601-9a67-409a-8a93-bae83e282187", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function abs in module builtins:\n", "\n", "abs(x, /)\n", " Return the absolute value of the argument.\n", "\n" ] } ], "source": [ "help(abs)" ] }, { "cell_type": "markdown", "id": "72f064cc-95b0-4655-9b28-c32248a7c93b", "metadata": {}, "source": [ "The help menu tells you that `abs(x)` is the absolute value function,\n", "which is written $|x|$ in math notation, and defined as\n", "\n", "$$\n", " |x| = \\begin{cases} x & \\text{if } x \\geq 0 \\\\ -x & \\text{if } x < 0 \\end{cases}\n", "$$\n" ] }, { "cell_type": "markdown", "id": "3cf1a3c6-28ec-462f-93c1-2e2363e03ea7", "metadata": {}, "source": [ "We refer to the help menu associated with an object as its \"doc string\",\n", "since the information is stored as `obj.__doc__`." ] }, { "cell_type": "code", "execution_count": 8, "id": "f885ebf6-1c6c-4dbc-83da-b7b2efa3a47c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Return the absolute value of the argument.'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs.__doc__" ] }, { "cell_type": "code", "execution_count": null, "id": "5ca185e9-3019-4bb9-b335-7a9b6234f0a4", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "d47b0d7c-278d-402a-830f-3f862b2feb5e", "metadata": { "tags": [] }, "source": [ "We've already used both `type` and `print`, so there is nothing new here.\n", "I just wanted to remind you you can always use these functions as first line of inspection." ] }, { "cell_type": "code", "execution_count": 9, "id": "66e4d22e-0932-46b2-9431-3e61f7ec056b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n" ] } ], "source": [ "obj = 3\n", "\n", "print(obj)" ] }, { "cell_type": "code", "execution_count": 10, "id": "6a2a9486-81fb-49fe-94dd-2bfa5767ca6d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(obj)" ] }, { "cell_type": "code", "execution_count": 11, "id": "93355970-9d83-45d0-a5d2-0d424c53c19f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'3'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "repr(obj)" ] }, { "cell_type": "markdown", "id": "8d834c81-f2d8-479a-a473-a8bbd1e92452", "metadata": {}, "source": [ "### DICTS \n", "**Side note**: You can think of a list as a special type of dictionary that has the integers `0`, `1`, `2`, as keys. Alternatively, you can think of dictionaries as \"fancy lists\" that allow keys to be arbitrary instead of being limited to sequential integer indices." ] }, { "cell_type": "markdown", "id": "d8e13209-ef32-49e4-87a4-ce67257906e7", "metadata": {}, "source": [ "Recall the general syntax of an assignment statement is as follows:\n", "\n", "```Python\n", " = \n", "```\n", "\n", "In the above examples, the `` refers the the location inside the `profile` dictionary identified by a particular key. In the first example,\n", " we assigned the value `77` to the place `profile[\"score\"]` which modified the value that was previously stored there. In the second example we assigned the value `42` to the new place `profile[\"age\"]`, so Python created it." ] }, { "cell_type": "code", "execution_count": null, "id": "09f63bb3-0caa-443d-8154-6dc9ee51f07e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "de5189a1-4a4c-4cb5-b709-f79d35f4d1c6", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 12, "id": "2f72cf02-9d17-4067-87a6-b7901cc87859", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(True, False, False, False)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "True and True, True and False, False and True, False and False" ] }, { "cell_type": "code", "execution_count": 13, "id": "05ceb35d-d994-4162-9887-7a7e5b5c2584", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(True, True, True, False)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "True or True, True or False, False or True, False or False" ] }, { "cell_type": "markdown", "id": "f9fabce0-3ccb-4b86-9003-d550e50d6764", "metadata": {}, "source": [ "## Inline if statements (bonus topic)\n", "\n", "We can also use `if`-`else` keywords to write conditional expressions on a single line.\n", "The general syntax for these is:\n", "\n", "```Python\n", " if else \n", "```\n", "\n", "This expressions evaluates to `` if `` is `True`,\n", "else it evaluates to `` when `` is `False`." ] }, { "cell_type": "code", "execution_count": 14, "id": "9f7c4528-156f-4aa3-a676-76c9e8a11aa2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"It's hot!\"" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "temp = 25\n", "msg = \"It's hot!\" if temp > 22 else \"It's OK.\"\n", "msg" ] }, { "cell_type": "code", "execution_count": null, "id": "04c2f490-ba4b-4d05-932e-a175d49336a5", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "210cc65c-5f8a-4b88-83bd-f8781dffb2d9", "metadata": {}, "source": [ "## LISTS\n", "Recall you can see a complete list of all the methods on list objects by typing `scores.` then pressing the TAB button to trigger the auto-complete suggestions.\n", "Uncomment the following code block,\n", "place your cursor after the dot,\n", "and try pressing TAB to see what happens." ] }, { "cell_type": "code", "execution_count": 15, "id": "91a4a80a-a851-4c08-ba3b-eea474812d6c", "metadata": {}, "outputs": [], "source": [ "# scores." ] }, { "cell_type": "markdown", "id": "7bd81ea2-0ac7-4910-8f64-36d805c8b72c", "metadata": {}, "source": [ "**Exercise 12**: The default behaviour of the method `.sort()` is to \n", "sort the elements in *increasing* order.\n", "Suppose you want sort the elements in *decreasing* order instead.\n", "You can pass a keyword argument to the method `.sort()`\n", "to request the sorting be done in \"revese\" order (decreasing instead of increasing).\n", "Consult the docstring of the `.sort()` method to find the name of the keyword argument\n", "that does this,\n", "then modify the code below to sort the elements of the list `scores` in decreasing order." ] }, { "cell_type": "code", "execution_count": 16, "id": "799dd093-dfcf-4b67-9a07-fc5ff62fc0c4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[61, 72, 79, 98]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "scores = [61, 79, 98, 72]\n", "\n", "scores.sort()\n", "scores" ] }, { "cell_type": "code", "execution_count": 17, "id": "f6efe3a1-8877-4817-91c5-d65eac3e6176", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[98, 79, 72, 61]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#@titlesolution Exercise 12 sorted-reverse\n", "# help(scores.sort)\n", "scores.sort(reverse=True)\n", "scores" ] }, { "cell_type": "markdown", "id": "d59cc62c-e214-46f0-9c2c-b060e0483670", "metadata": { "tags": [] }, "source": [ "### See what's in the global namespace (bonus)\n", "\n", "In a Jupyter notebook,\n", "you can run the command `%whos` to print all the variables and functions that defined in the current namespace." ] }, { "cell_type": "code", "execution_count": 18, "id": "4e4ac7de-3b90-40eb-8f62-3933c1357c86", "metadata": {}, "outputs": [], "source": [ "# %whos" ] }, { "cell_type": "code", "execution_count": null, "id": "7401e747-e806-41e6-8770-9bd4dae5fb32", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "c01ba35b-2fac-4240-a482-c0f004c82e8b", "metadata": {}, "source": [ "**Exercise 7**: Display the doc-string of the function `sum`." ] }, { "cell_type": "code", "execution_count": 19, "id": "6556a136-c3e8-4cdd-b7aa-78f3bc046c39", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function sum in module builtins:\n", "\n", "sum(iterable, /, start=0)\n", " Return the sum of a 'start' value (default: 0) plus an iterable of numbers\n", " \n", " When the iterable is empty, return the start value.\n", " This function is intended specifically for use with numeric values and may\n", " reject non-numeric types.\n", "\n" ] } ], "source": [ "#@titlesolution Exercise 7 help-sum\n", "help(sum)" ] }, { "cell_type": "markdown", "id": "bb1c11a4-5641-482c-9dcc-9ad367b99356", "metadata": {}, "source": [ "**Exercise 8**:\n", "Display the doc string of for the function `print`." ] }, { "cell_type": "code", "execution_count": 20, "id": "c14009f5-a885-456a-9db4-adad29d11c46", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function print in module builtins:\n", "\n", "print(...)\n", " print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n", " \n", " Prints the values to a stream, or to sys.stdout by default.\n", " Optional keyword arguments:\n", " file: a file-like object (stream); defaults to the current sys.stdout.\n", " sep: string inserted between values, default a space.\n", " end: string appended after the last value, default a newline.\n", " flush: whether to forcibly flush the stream.\n", "\n" ] } ], "source": [ "#@titlesolution Exercise 8 help-print\n", "help(print)" ] }, { "cell_type": "code", "execution_count": null, "id": "9fe10d9b-21d7-48a5-a690-46acbf9f8816", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "e454f38f-296e-4a61-a4b5-fb267385924f", "metadata": {}, "source": [ "#### Application: changing the separator when printing multiple values\n", "\n", "We can choose a different separator between arguments of the `print` function\n", "by specifying the value for the keyword argument `sep`." ] }, { "cell_type": "code", "execution_count": 21, "id": "a6cecf99-87b2-404b-83fa-c1f07e566153", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3 2.3\n" ] } ], "source": [ "x = 3\n", "y = 2.3\n", "print(x, y)" ] }, { "cell_type": "code", "execution_count": 22, "id": "89fa112d-42ff-4766-ba0a-44baa991b400", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3 --- 2.3\n" ] } ], "source": [ "print(x, y, sep=\" --- \")" ] }, { "cell_type": "code", "execution_count": null, "id": "7511a44a-d17b-4231-b733-4f3edaab350d", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "8791431f-d0e2-49ab-af16-8f9bd5156264", "metadata": {}, "source": [ "### Question 2: Sample standard deviation\n", "\n", "The formula for the sample standard seviation of a list of numbers is:\n", "$$\n", " \\text{std}(\\textbf{x}) = s\n", " = \\sqrt{ \\tfrac{1}{n-1}\\sum_{i=1}^n (x_i-\\overline{x})^2 }\n", " = \\sqrt{ \\tfrac{1}{n-1}\\left[ (x_1-\\overline{x})^2 + (x_2-\\overline{x})^2 + \\cdots + (x_n-\\overline{x})^2\\right]}.\n", "$$\n", "\n", "Note the division is by $(n-1)$ and not $n$. Strange, no? You'll have to wait until stats to see why this is the case.\n", "\n", "Write `compute_std(numbers)`: computes the sample standard deviation" ] }, { "cell_type": "code", "execution_count": 23, "id": "5e3a7f23-d2fa-40df-929e-6d76cf06d221", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "29.011491975882016" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import math\n", "\n", "def mean(numbers):\n", " return sum(numbers)/len(numbers)\n", "\n", "def std(numbers):\n", " \"\"\"\n", " Computes the sample standard deviation (square root of the sample variance)\n", " using a for loop.\n", " \"\"\"\n", " avg = mean(numbers) \n", " total = 0\n", " for number in numbers:\n", " total = total + (number-avg)**2\n", " var = total/(len(numbers)-1) \n", " return math.sqrt(var)\n", "\n", "numbers = list(range(0,100))\n", "std(numbers)" ] }, { "cell_type": "code", "execution_count": 24, "id": "0f6a10fe-caff-4242-bcd8-402bf742f2e5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "29.011491975882016" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# compare to known good function...\n", "import statistics\n", "statistics.stdev(numbers)" ] }, { "cell_type": "code", "execution_count": null, "id": "2b987984-255e-4cc1-af07-818cd41c21db", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "b86a4f62-c68b-4932-83f1-07296ab7813e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "489ef88c-36b9-4345-9476-cf63d1c53e8e", "metadata": {}, "source": [ "Functions!\n", "Finally we get to the good stuff!\n", "\n", "Functions allow us to build chunks of reusable code that we can later reuse in other programs. \n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "485dc9ca-c2d8-41b8-877c-a0ba643aeef0", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 25, "id": "c6bd4735-9bb3-4ecc-beb6-02eaad95b31f", "metadata": {}, "outputs": [], "source": [ "# # ALT. using the `range` function\n", "# numbers = range(1,6)\n", "# squares = [n**2 for n in numbers]\n", "# squares" ] }, { "cell_type": "code", "execution_count": null, "id": "f7acda1b-78e2-4ae6-be65-c23ce03a3b40", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "93699e42-d851-4468-953f-8446119d38d9", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "1e08c984-bc18-48e7-8986-50a4e0a241ba", "metadata": {}, "source": [ "## Sets\n", "\n", "Python sets are a representation of the mathematical sets,\n", "that is,\n", "collections of elements." ] }, { "cell_type": "code", "execution_count": 26, "id": "e16e759b-3032-407f-8300-3d5e57b97397", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "set()" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = set()\n", "s" ] }, { "cell_type": "code", "execution_count": 27, "id": "9f12589e-70c9-43f8-932e-fee5595b093f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{3, 5}" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.add(3)\n", "s.add(5)\n", "s" ] }, { "cell_type": "code", "execution_count": 28, "id": "500df758-3e03-4671-9b2b-15209cec5001", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 in s" ] }, { "cell_type": "code", "execution_count": 29, "id": "6bb25883-5ca0-48a1-9bf5-7fc56a8ad7ac", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The set s contains the elements:\n", "3\n", "5\n" ] } ], "source": [ "print(\"The set s contains the elements:\")\n", "for el in s:\n", " print(el)" ] }, { "cell_type": "markdown", "id": "e6df152a-5dff-4d18-a949-b769ded52658", "metadata": {}, "source": [ "Sets are sometimes useful when we want to keep track of which elements have been encountered, but don't care how many times." ] }, { "cell_type": "code", "execution_count": 30, "id": "45147b28-ade8-4299-b0a2-4ccd34993000", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{3, 5}" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.add(3)\n", "s.add(3)\n", "s" ] }, { "cell_type": "code", "execution_count": null, "id": "ff23229e-4a70-4af1-ab8c-79225e4b422c", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "127f22ab-614f-491b-9337-b0216dd4cb24", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "ea1d4676-1f87-4ba9-bfbd-ef8374ebcb29", "metadata": {}, "source": [ "## Tuples\n", "\n", "Tuples are similar to lists but with less features." ] }, { "cell_type": "code", "execution_count": 31, "id": "f821575c-c1db-46ea-972e-081add64c7c4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2, 3)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2,3" ] }, { "cell_type": "code", "execution_count": 32, "id": "48fd3e97-7206-4aa8-a810-f8d0f559e8cf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2, 3)" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(2,3)" ] }, { "cell_type": "markdown", "id": "f54c34f6-79be-4fd0-927f-dfa8165f7cc7", "metadata": {}, "source": [ "We can use the tuples syntax to assign to multiple variables on a single line:" ] }, { "cell_type": "code", "execution_count": 33, "id": "5191c2b2-e541-40aa-a25a-bfbb01b6e54e", "metadata": {}, "outputs": [], "source": [ "x, y = 3, 4" ] }, { "cell_type": "markdown", "id": "772e6e6b-f690-40cd-b8fc-5c019dde756d", "metadata": {}, "source": [ "We can also use tuples to \"swap\" two values." ] }, { "cell_type": "code", "execution_count": 34, "id": "28044be9-8e9a-44eb-837e-fad54a16eb95", "metadata": {}, "outputs": [], "source": [ "# Swap the contexts of the variables x and y\n", "tmp = x\n", "y = x\n", "x = tmp" ] }, { "cell_type": "code", "execution_count": 35, "id": "52d0b5d3-849e-47b0-b937-cb7448ae74f0", "metadata": {}, "outputs": [], "source": [ "# Equivalent operation on one line\n", "x, y = y, x" ] }, { "cell_type": "markdown", "id": "2a1c0d28-ec55-4f60-97ac-59efef137d5a", "metadata": {}, "source": [ "## Defining new types of objects\n", "\n", "Using the Python keyword `class` can be used to define new kinds of objects.\n" ] }, { "cell_type": "markdown", "id": "a5294678-ec20-40fc-919e-d8c7f64c6189", "metadata": {}, "source": [ "Let's create a custom class of objects `Interval` that represent intervals of real numbers like $[a,b] \\subset \\mathbb{R}$.\n", "We want to be able to use the new interval objects in `if` statements to check if a number $x$ is in the interval $[a,b]$ or not.\n", "\n", "Recall the `in` operator that we can use to check if an element is part of a list\n", "```Python\n", ">>> 3 in [1,2,3,4]\n", "True\n", "```\n", "\n", "we want the new objects of type `Interval` to test for membership.\n", "\n", "Example usage:\n", "```Python\n", ">>> 3 in Interval(2,4)\n", "True\n", ">>> 5 in Interval(2,4)\n", "False\n", "```\n", "The expression `x in Y` is corresponds to calling the method `__contains__` on the container object `Y`:\n", "`Y.__contains__(x)` and it will return a `bool`ean value (`True` or `False`).\n", "\n", "If we want to support checks like `3 in Interval(2,4)` we therefore have to implement \n", "the method `__contains__` on the `Interval` class." ] }, { "cell_type": "code", "execution_count": 36, "id": "157a0a66-e352-418d-b919-7db7e290be53", "metadata": {}, "outputs": [], "source": [ "class Interval:\n", " \"\"\"\n", " Object that embodies the mathematical concept of an interval.\n", " `Interval(a,b)` is equivalent to math interval [a,b] = {𝑥 | 𝑎 ≤ 𝑥 ≤ 𝑏}.\n", " \"\"\"\n", "\n", " def __init__(self, lowerbound, upperbound):\n", " \"\"\"\n", " This method is called when the object is created, and is used to\n", " set the object attributes from the arguments passed in.\n", " \"\"\"\n", " self.lowerbound = lowerbound\n", " self.upperbound = upperbound\n", "\n", " def __str__(self):\n", " \"\"\"\n", " Return a representation of the interval as a string like \"[a,b]\".\n", " \"\"\"\n", " return \"[\" + str(self.lowerbound) + \",\" + str(self.upperbound) + \"]\"\n", "\n", " def __contains__(self, x):\n", " \"\"\"\n", " This method is called to check membership using the `in` keyword.\n", " \"\"\"\n", " return self.lowerbound <= x and x <= self.upperbound\n", "\n", " def __len__(self):\n", " \"\"\"\n", " This method will get called when you call `len` on the object.\n", " \"\"\"\n", " return self.upperbound - self.lowerbound\n" ] }, { "cell_type": "markdown", "id": "4588d4af-3150-40bb-a625-e90c876092fc", "metadata": {}, "source": [ "Create an object that corresponds to the interval $[2,4]$." ] }, { "cell_type": "code", "execution_count": 37, "id": "3d2c7f8a-b671-4f43-a139-0be575fbb12e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "<__main__.Interval at 0x1041639d0>" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "interval2to4 = Interval(2,4)\n", "interval2to4" ] }, { "cell_type": "code", "execution_count": 38, "id": "4023c898-42f8-4c71-b894-6f7d2ddfcaeb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "__main__.Interval" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(interval2to4)" ] }, { "cell_type": "code", "execution_count": 39, "id": "c9871fad-beea-47c5-8192-71d6bf105b5a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'[2,4]'" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str(interval2to4)" ] }, { "cell_type": "code", "execution_count": 40, "id": "98169b25-3b0a-41d3-9b2f-25d1011db642", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3.3 in interval2to4" ] }, { "cell_type": "code", "execution_count": 41, "id": "ed745907-30f6-4de1-b119-c83009b4e326", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 in interval2to4" ] }, { "cell_type": "code", "execution_count": 42, "id": "096dad0a-a124-4f66-a188-95e291e147a5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(interval2to4)" ] }, { "cell_type": "code", "execution_count": null, "id": "d1459c2b-5963-4eb9-a88b-9cc916f0cfcd", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "223d9867-b221-46a0-9528-fc0012ded71d", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "c3596647-f291-4290-bff2-d8716c1f5e8d", "metadata": {}, "source": [ "### Note for Windows users\n", "\n", "If you're on macOS or Linux you can ignore this section—skip to the next section **Data management with Pandas**.\n", "\n", "File paths on Windows use the backslash character (`\\`) as path separator,\n", "while UNIX operating systems like Linux and macOS use forward slash separator `/` as path separator. \n", "\n", "If you you're on Windows you'll need to manually edit the code examples below to make them work by replacing all occurrences of \"`/`\" with \"`\\\\`\". The double backslash is required to get a literal backslash because the character `\\` has special meaning as an escape character." ] }, { "cell_type": "code", "execution_count": 43, "id": "f880c1c6-8aac-4540-b775-0837b2c89d18", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "You're on a UNIX system (Linux or macOS).\n", "Enjoy civilization!\n" ] } ], "source": [ "import os\n", "\n", "if os.path.sep == \"/\":\n", " print(\"You're on a UNIX system (Linux or macOS).\")\n", " print(\"Enjoy civilization!\")\n", "elif os.path.sep == \"\\\\\":\n", " print(\"You're on Windows so you should use \\\\ as path separator.\")\n", " print(\"Replace any occurence of / (forward slash) in paths with \\\\\\\\ (double-backslash).\")" ] }, { "cell_type": "markdown", "id": "82c6db9c-6355-4872-a93c-18acbfeba600", "metadata": {}, "source": [ "The current working directory is a path on your computer where this notebook is running.\n", "The code cell below shows you can **get** you **c**urrent **w**orking **d**irectory." ] }, { "cell_type": "code", "execution_count": 44, "id": "bab510f7-4d9a-4248-8699-bd161ee6f109", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'/Users/ivan/Projects/Minireference/STATSbook/noBSstatsnotebooks/tutorials'" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "os.getcwd()" ] }, { "cell_type": "markdown", "id": "7cb4b570-cc64-4dd8-9bce-3603db7debce", "metadata": {}, "source": [ "You're in the `notebooks/` directory, which is inside the parent directory `noBSstats/`.\n", "\n", "The datasets we'll be using in this notebook are located in the `datasets/` directory, which is sibling of the `notebooks/` directory, inside the parent `noBSstats/`. To access data file `minimal.csv` in the `datasets/` directory from the current directory, we must specify a path that includes the `..` directive (go to parent), then go into the `datasets` directory, then open the file `minimal.csv`.\n", "\n", "This combination of \"directions\" for getting to the file will look different if you're on a Windows system or on a UNIX system. The code below shows the correct path you should access." ] }, { "cell_type": "code", "execution_count": 45, "id": "efdc6069-4069-4e78-9df5-4113cd9c8a12", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The path to the file players.csv in the datasets/ directory is\n" ] }, { "data": { "text/plain": [ "'../datasets/players.csv'" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "if os.path.sep == \"/\":\n", " # UNIX path separators\n", " path = \"../datasets/players.csv\"\n", "else:\n", " # Windows path separators\n", " path = \"..\\\\datasets\\\\players.csv\"\n", "\n", "print(\"The path to the file players.csv in the datasets/ directory is\")\n", "path" ] }, { "cell_type": "markdown", "id": "c46f1208-b523-4407-aa20-f93125316bef", "metadata": {}, "source": [ "All the code examples provided below assume you're on a UNIX system,\n", "hence the need to manually modify them to use double-backslashes in path strings for the code to work." ] }, { "cell_type": "code", "execution_count": 46, "id": "c6556c4c-fec7-4732-a619-564ac4253f13", "metadata": {}, "outputs": [], "source": [ "# ALT.\n", "import os\n", "import pandas as pd\n", "filepath = os.path.join(\"..\", \"datasets\", \"players.csv\")\n", "players = pd.read_csv(filepath)" ] }, { "cell_type": "code", "execution_count": null, "id": "451e5475-8aed-4a0d-81a9-f6f6a5d53e4c", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "261920bf-40a2-46b4-a2e8-770dd0307fcc", "metadata": {}, "source": [ "### Converting lists to strings\n", "\n", "The code `\"\".join(msgs)` can be used to concatenate the a list of strings `msgs`." ] }, { "cell_type": "code", "execution_count": 47, "id": "d47d3ede-f83b-4ba9-a9e4-01711eeace05", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'HelloHiWhatsup?'" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "msgs = [\"Hello\", \"Hi\", \"Whatsup?\"]\n", "\"\".join(msgs)" ] }, { "cell_type": "code", "execution_count": 48, "id": "c007ed21-d40d-440b-bec7-95399f1e4fc1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello Hi Whatsup?'" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# join-together using once space \" \" as separator\n", "\" \".join(msgs)" ] }, { "cell_type": "code", "execution_count": null, "id": "3461c376-ec13-45a8-b944-5c5351fc9052", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "6ed52327-271d-4505-9f30-7888a8dbe95a", "metadata": {}, "source": [ "### Example: file `open` and the `readlines()` method" ] }, { "cell_type": "markdown", "id": "64aebb19-c420-4e5d-aa19-7f88b87f5fed", "metadata": {}, "source": [ "TODO: create a file called `story.txt` in the current working directory,\n", "and write a few lines in it.\n", "The code examples below are based on [this sample `story.txt`](https://raw.githubusercontent.com/minireference/noBSstatsnotebooks/main/tutorials/story.txt) (use save as if you want to have the same file)." ] }, { "cell_type": "code", "execution_count": 49, "id": "f134a8b8-7809-43ed-9144-c99c331a931a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['This is a short story.\\n',\n", " 'It is very short.\\n',\n", " 'It has only four lines.\\n',\n", " 'It ends with the word cat.\\n']" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "file = open(\"story.txt\")\n", "lines = file.readlines()\n", "lines" ] }, { "cell_type": "code", "execution_count": 50, "id": "8255f0f6-4939-4eda-964a-690f284d31ef", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This is a short story.\n", "\n", "It is very short.\n", "\n", "It has only four lines.\n", "\n", "It ends with the word cat.\n", "\n" ] } ], "source": [ "for line in lines:\n", " print(line)" ] }, { "cell_type": "code", "execution_count": 51, "id": "9d88841b-9584-4430-be06-9374d031181e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This is a short story.\n", "It is very short.\n", "It has only four lines.\n", "It ends with the word cat.\n" ] } ], "source": [ "# we can pass a custom `end` keyword argument to avoid double newlines:\n", "for line in lines:\n", " print(line, end=\"\")" ] }, { "cell_type": "code", "execution_count": null, "id": "60099863-9c5d-4acf-afed-c956df934c98", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "a4ee0116-9f4e-4921-b475-cb2ea89c4117", "metadata": {}, "source": [ "**Exercise**: write the code that counts the number of words in the string `text`.\n", "\n", "Here are some examples:\n", " - The number of words in `\"Hello world\"` is 2.\n", " - The number of words in `\"Whether it is nobler in the mind to suffer the slings and arrows of outrageous fortune, or to take arms against a sea of troubles, and by opposing end them?\"` is 30.\n", " - The number of words in `len.__doc__` is 8.\n", "\n", "Hint: the string method `.split()` might come in handy." ] }, { "cell_type": "code", "execution_count": 52, "id": "fe066794-1839-4506-9c4b-03ac650afc2c", "metadata": {}, "outputs": [], "source": [ "text = \"Hello world\"\n", "\n", "# write here the code that counts the number of words in `text`\n", "# ..." ] }, { "cell_type": "code", "execution_count": 53, "id": "4decb1cc-1628-4260-9375-3c9f6c195811", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#@titlesolution\n", "text = \"Hello world\"\n", "# \n", "# text = len.__doc__\n", "# \n", "# text = \"\"\"Whether it is nobler in the mind to suffer\n", "# the slings and arrows of outrageous fortune,\n", "# or to take arms against a sea of troubles,\n", "# and by opposing end them?\"\"\"\n", "\n", "words = text.split()\n", "wordcount = 0\n", "for word in words:\n", " wordcount = wordcount + 1\n", "wordcount" ] }, { "cell_type": "code", "execution_count": null, "id": "4b6fefe9-bdf2-4670-b421-643907b46f84", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "14fe4db2-3bf4-43df-8804-2692ffeffca5", "metadata": {}, "source": [ "**Exercise** write the Python code that `open`s the file `story.txt`, `read`s the contexts of the file to a string `text`, then computes their word count.\n", "\n", "Hint: reuse the code we saw earlier for opening file\n", "\n", "Hint 2: try the `.read()` method on file object\n", "\n", "Hint 3: reuse the code you wrote earlier for doing the word count of the string `text`" ] }, { "cell_type": "code", "execution_count": 54, "id": "535a93f3-8e5e-4368-b578-6623a6ae4af5", "metadata": {}, "outputs": [], "source": [ "file = open(\"story.txt\")\n", "text = file.read()\n", "# ... (continue your code here)" ] }, { "cell_type": "code", "execution_count": 55, "id": "3270bc4c-8896-4060-b191-cd1dc429a21c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "20" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#@titlesolution\n", "file = open(\"story.txt\")\n", "text = file.read()\n", "words = text.split()\n", "wordcount = 0\n", "for word in words:\n", " wordcount = wordcount + 1\n", "wordcount" ] }, { "cell_type": "code", "execution_count": null, "id": "bd464266-ee65-4606-9409-5e79e3ce244a", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "8342e5d7-af43-4ee4-9602-966324a56c1b", "metadata": { "tags": [] }, "source": [ "#### Example: bag of words representation\n", "\n", "Given the string `text`, we want to count the number of occurrences of each word in the text.\n", "The words \"HELLO\", \"Hello\", \"Hello,\" should all be considered the same as \"hello\".\n", "\n", "In other words, we want to convert all letters to lowercase and strip punctuation signs.\n", "\n", "Given the string `\"HELLO Hello Hello, hello\"`,\n", "the bag of words representation corresponds to the dictionary\n", "```\n", "wcounts = {\"hello\":4}\n", "```\n" ] }, { "cell_type": "code", "execution_count": 56, "id": "4c294ff3-2848-4071-82dc-179d2938e6d1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'hello': 1, 'world': 1}" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "text = \"Hello world\"\n", "# \n", "# text = len.__doc__\n", "# \n", "# text = \"\"\"Whether it is nobler in the mind to suffer\n", "# the slings and arrows of outrageous fortune,\n", "# or to take arms against a sea of troubles,\n", "# and by opposing end them?\"\"\"\n", "\n", "words = text.split()\n", "clean_words = [word.strip(\",.?\") for word in words]\n", "words_lower = [word.lower() for word in clean_words]\n", "\n", "wcounts = {}\n", "for word in words_lower:\n", " if word not in wcounts:\n", " wcounts[word] = 0\n", " wcounts[word] += 1\n", "\n", "wcounts" ] }, { "cell_type": "code", "execution_count": null, "id": "0dd554b3-61be-4e10-8e8c-65f222bef6a3", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "c90d7d50-ebbe-4180-b52d-ca75c847c859", "metadata": {}, "source": [ "\n", "\n", "**Exercise** Write the Python code that computes the final score for each student,\n", "based on the data in [this spreadsheet](https://docs.google.com/spreadsheets/d/1_DRn3FXpLERVhO71pHsYbf_jwxQF8p54M6Niy3If3x0/edit#gid=0).\n", "The final score is computed as:\n", " - 50% homework assignments (each homework counts for 10%)\n", " - 20% midterm\n", " - 30% final\n", "\n", "Once you get the `score` for each student, \n", "you should also convert it to a letter `grade`.\n", "Print the student name, their final score, and their letter grade.\n", "\n", "Hint: use a for loop to iterate over all students\n", "\n", "Hint 2: reuse the code you wrote earlier for converting numeric `score` to letter `grade`" ] }, { "cell_type": "code", "execution_count": 57, "id": "a3ace802-0462-4972-9133-b2da4773e9ef", "metadata": {}, "outputs": [], "source": [ "# via https://stackoverflow.com/a/33727897/127114\n", "# \n", "url_tpl = \"https://docs.google.com/spreadsheets/d/{key}/gviz/tq?tqx=out:csv&sheet={name}\"\n", "sheet_id = \"1_DRn3FXpLERVhO71pHsYbf_jwxQF8p54M6Niy3If3x0\"\n", "sheet_name = \"Grades\"\n", "url = url_tpl.format(key=sheet_id, name=sheet_name)\n", "\n", "import requests\n", "response = requests.get(url)\n", "\n", "# response.text" ] }, { "cell_type": "code", "execution_count": 58, "id": "d943452b-ecdb-4a32-9c3d-43234c8ec463", "metadata": {}, "outputs": [], "source": [ "# Convert CSV text (contents of a file) to a list of dictionaries\n", "import csv, io\n", "studentsf = io.StringIO(response.text)\n", "rows = list(csv.DictReader(studentsf))\n", "# rows" ] }, { "cell_type": "code", "execution_count": 59, "id": "51b7e3ff-6d6f-4012-9b35-fb76f6530488", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 11 name = Haydon Jeffery got 12 on the first homework\n", " 11 name = Julie Beattie got 13 on the first homework\n", " 11 name = Malachy Hull got 15 on the first homework\n", " 11 name = Sheila Solis got 14 on the first homework\n", " 11 name = Joni Rowe got 12 on the first homework\n", " 11 name = Husna Millar got 11 on the first homework\n", " 11 name = Tonya Fleming got 11 on the first homework\n", " 11 name = Jak Rennie got 19 on the first homework\n", " 11 name = Noor Odonnell got 14 on the first homework\n", " 11 name = Krystal Dickerson got 13 on the first homework\n", " 11 name = Joe Pickett got 3 on the first homework\n", " 11 name = Alicia Rosario got 10 on the first homework\n", " 11 name = Ailish Hensley got 13 on the first homework\n", " 11 name = Aliyah Duncan got 12 on the first homework\n", " 11 name = Jad Kumar got 15 on the first homework\n", " 11 name = Margaret Parry got 14 on the first homework\n", " 11 name = Danica Chen got 11 on the first homework\n", " 11 name = Jose Hernandez got 13 on the first homework\n", " 11 name = Rimsha Carlson got 20 on the first homework\n", " 11 name = Giselle Thompson got 18 on the first homework\n" ] } ], "source": [ "for row in rows:\n", " # row is a dict containing a student's results\n", " # the keys are ['id', 'name', 'hw1', 'hw2', 'hw3', 'midterm',\n", " # 'hw4', 'hw5', 'final', 'score', 'grade']\n", " # the values are strings\n", " name = row[\"name\"] # access value under the key \"name\" in this row\n", " hw1 = int(row[\"hw1\"]) # access key \"hw1\" and convert it to `int`\n", " print(type(row), len(row), \"name =\", name, \"got\", hw1, \"on the first homework\")\n", " \n", " # continue your code at the ... below\n", " # PART 1: computing the final scrore\n", " # PART 2: assigning a letter\n", " # ..." ] }, { "cell_type": "code", "execution_count": 60, "id": "47021217-4340-4642-8ffe-4b32318c9cc4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processing results of Haydon Jeffery ...\n", " - final score = 79.39999999999999\n", " - final grade = B+\n", "Processing results of Julie Beattie ...\n", " - final score = 69.19999999999999\n", " - final grade = B-\n", "Processing results of Malachy Hull ...\n", " - final score = 78.8\n", " - final grade = B+\n", "Processing results of Sheila Solis ...\n", " - final score = 77.8\n", " - final grade = B+\n", "Processing results of Joni Rowe ...\n", " - final score = 81.6\n", " - final grade = A-\n", "Processing results of Husna Millar ...\n", " - final score = 77.89999999999999\n", " - final grade = B+\n", "Processing results of Tonya Fleming ...\n", " - final score = 74.69999999999999\n", " - final grade = B\n", "Processing results of Jak Rennie ...\n", " - final score = 86.2\n", " - final grade = A\n", "Processing results of Noor Odonnell ...\n", " - final score = 79.5\n", " - final grade = B+\n", "Processing results of Krystal Dickerson ...\n", " - final score = 78.2\n", " - final grade = B+\n", "Processing results of Joe Pickett ...\n", " - final score = 46.0\n", " - final grade = F\n", "Processing results of Alicia Rosario ...\n", " - final score = 77.3\n", " - final grade = B+\n", "Processing results of Ailish Hensley ...\n", " - final score = 76.8\n", " - final grade = B+\n", "Processing results of Aliyah Duncan ...\n", " - final score = 77.8\n", " - final grade = B+\n", "Processing results of Jad Kumar ...\n", " - final score = 81.5\n", " - final grade = A-\n", "Processing results of Margaret Parry ...\n", " - final score = 76.5\n", " - final grade = B+\n", "Processing results of Danica Chen ...\n", " - final score = 79.4\n", " - final grade = B+\n", "Processing results of Jose Hernandez ...\n", " - final score = 76.19999999999999\n", " - final grade = B+\n", "Processing results of Rimsha Carlson ...\n", " - final score = 90.0\n", " - final grade = A\n", "Processing results of Giselle Thompson ...\n", " - final score = 89.4\n", " - final grade = A\n" ] } ], "source": [ "#@titlesolution\n", "import csv\n", "import io\n", "\n", "studentsf = io.StringIO(response.text)\n", "rows = list(csv.DictReader(studentsf))\n", "for row in rows:\n", " # row is a dict containing a student's results\n", " # the keys are ['id', 'name', 'hw1', 'hw2', 'hw3', 'midterm',\n", " # 'hw4', 'hw5', 'final', 'score', 'grade']\n", " # the values are strings\n", " name = row[\"name\"] # access value under the key \"name\" in this row\n", " print(\"Processing results of\", name, \"...\")\n", " \n", " \n", " # PART 1: computing the final scrore\n", " ####################################################################################\n", " # Convert all available student results to integers\n", " hw1 = int(row[\"hw1\"]) # out of 20\n", " hw2 = int(row[\"hw2\"]) # out of 20\n", " hw3 = int(row[\"hw3\"]) # out of 20\n", " midterm = int(row[\"midterm\"]) # out of 100\n", " hw4 = int(row[\"hw4\"]) # out of 20\n", " hw5 = int(row[\"hw5\"]) # out of 20\n", " final = int(row[\"final\"]) # out of 100\n", "\n", " # compute homeworks average out of 100,\n", " # which is simple because each homework is out of 20 and there are 5 of them\n", " homeworks = hw1 + hw2 + hw3 + hw4 + hw5\n", " \n", " # we now need to make a \"mix\" of homeworks, midterm, and final\n", " # to create the student's final score (out of 100)\n", " score = 0.5*homeworks + 0.2*midterm + 0.3*final\n", " print(\" - final score = \", score)\n", " \n", " \n", " # PART 2: assigning a letter \n", " ####################################################################################\n", " if score >= 85:\n", " grade = \"A\"\n", " elif score >= 80:\n", " grade = \"A-\"\n", " elif score >= 75:\n", " grade = \"B+\"\n", " elif score >= 70:\n", " grade = \"B\"\n", " elif score >= 65:\n", " grade = \"B-\"\n", " elif score >= 60:\n", " grade = \"C+\"\n", " elif score >= 55:\n", " grade = \"C\"\n", " elif score >= 50:\n", " grade = \"D\"\n", " else:\n", " grade = \"F\"\n", " print(\" - final grade = \", grade)\n", " \n", " \n", " # PART 3: (optional) save the results in the `row` dictionary\n", " ####################################################################################\n", " row[\"score\"] = score\n", " row[\"grade\"] = grade\n" ] }, { "cell_type": "code", "execution_count": 61, "id": "2e84d030-f9a3-4dbb-88c6-9d18c387e85b", "metadata": {}, "outputs": [], "source": [ "# # Display last row\n", "# rows[-1]" ] }, { "cell_type": "markdown", "id": "15d4b552-a4f3-477c-9d57-0392c6100542", "metadata": {}, "source": [ "### Lists of booleans\n", "\n", "Lists of `bool`eans can be \"joined\" together\n", "using `and` or `or` operations,\n", "but calling `all` and `any` list-related built-in functions.\n", "\n", "- `all(conditions)`: `and`-together all elements in list of conditions\n", "- `any(conditions)`: `or`-together all elements in list of conditions" ] }, { "cell_type": "code", "execution_count": 62, "id": "57ed17ca-79e7-4c50-854a-3c222bf55f62", "metadata": {}, "outputs": [], "source": [ "# list of three conditions, all being True\n", "alltrue = [True, True, True]\n", "\n", "# list of conditions where only one condition is True\n", "onetrue = [True, False, False]\n", "\n", "# list of conditions that are all False\n", "allfalse = [False, False, False]" ] }, { "cell_type": "code", "execution_count": 63, "id": "f1e13dd9-f092-4100-a794-40ec91ad1b1a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(True, False, False)" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all(alltrue), all(onetrue), all(allfalse)" ] }, { "cell_type": "code", "execution_count": 64, "id": "f01476f6-ec79-4e5b-b722-76e075d7b531", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(True, True, False)" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "any(alltrue), any(onetrue), any(allfalse)" ] }, { "cell_type": "code", "execution_count": null, "id": "c92a9a7d-a6b6-4d96-84fe-ef8b99625c80", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "6fada858-1ea3-4505-a11b-e67f6e05e745", "metadata": {}, "source": [ "## Example function `head`\n", "\n", "We often want to print first few lines from a file to see what data it contains." ] }, { "cell_type": "code", "execution_count": 65, "id": "29e553b6-c65b-42a4-8425-e824031b0d96", "metadata": {}, "outputs": [], "source": [ "# TODO" ] }, { "cell_type": "code", "execution_count": null, "id": "847911b1-19a8-4d7e-acd4-44d220c8456f", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "7cb14868-bd0b-43a3-a9aa-030209603619", "metadata": {}, "source": [ "## Function tricks" ] }, { "cell_type": "markdown", "id": "9decd583-99e6-4180-9678-a4daa395636e", "metadata": {}, "source": [ "### Lambda functions\n", "\n", "Python supports and alternative syntax for defining functions,\n", "that is sometimes used to define simple functions.\n", "For example,\n", "let's say you need a function that computes the square of the input,\n", "which is written as $f(x) = x^2$ in math notation.\n", "\n", "You can use the standard Python syntax ...\n", "```Python\n", "def f(x):\n", " return x**2\n", "f\n", "```\n", "\n", "... or you can use the `lambda` expression for defining that function:\n", "```Python\n", "lambda x: x**2\n", "```\n", "\n", "The general syntax is `lambda : `." ] }, { "cell_type": "markdown", "id": "4df8c33a-b608-4b88-b171-94f34d23b323", "metadata": {}, "source": [ "This `lambda`-shortcut for defining functions is useful\n", "when calling other functions that expect functions as their arguments.\n", "To illustrate what is going on,\n", "let's define a python function `plot_function(f)` that plots\n", "the graph of the function `f` it receives as its input.\n", "\n", "The graph of the function $f(x)$\n", "is the set of points $(x,f(x))$ in the Cartesian plane,\n", "over the interval of $x$ inputs (we'll use the $x$-limits -10 as the starting point and until x=10 as the end point)." ] }, { "cell_type": "code", "execution_count": 66, "id": "701b92f6-9938-4517-8d32-65ea9a614100", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "def plot_function(f, xlims=[-10,10]):\n", " xstart, xend = xlims\n", " xs = np.linspace(xstart, xend, 1000)\n", " ys = [f(x) for x in xs]\n", " plt.plot(xs,ys) " ] }, { "cell_type": "markdown", "id": "a4440447-e7d2-46c9-a5fd-fb2baf72d695", "metadata": {}, "source": [ "If we want to use the function `plot_function` to plot the graph of the function $f(x)=x^2$,\n", "we can define a Python function `f` using the standard `def`-syntax and then pass the function `f` to `plot_function` to generate the graph,\n", "as shown below:" ] }, { "cell_type": "code", "execution_count": 67, "id": "4054433d-7f58-4862-98e8-3d8fb26079e5", "metadata": {}, "outputs": [ { "data": { "image/png": "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Gwtvb28kJCRg9+7dl91+xYoV6NKlC7y9vdGzZ09s2LChhZI23dy5czFgwAAEBAQgPDwc48aNw/Hjxy/7nEWLFl20v7y9vVsocdP84x//uChrly5dLvscZ9p/jf08USgUmD59eqPbO8O+2759O8aMGYOoqCgoFAqsWrWqweNCCMyZMweRkZHw8fFBUlISTp48ecXXber3cVO5XUGpqanB+PHj8fjjjzf6uMlkwujRo1FTU4OdO3di8eLFWLRoEebMmXPZ1500aRIOHz6MTZs2Yd26ddi+fTumTZtmj7fQJIMHD0Z+fn6D28MPP4y4uDj079//ss995JFHGjxv3rx5LZS66V599dUGWZ988snLbv/MM89g7dq1WLFiBbZt24a8vDzceeedLZT26h07dgxmsxmffPIJDh8+jPfeew8LFizAX//61ys+11H337fffotZs2bh5Zdfxr59+9C7d2+MHDkSRUVFjW6/c+dOTJw4EVOnTkVaWhrGjRuHcePG4dChQy2c/Ops27YN06dPx65du7Bp0ybU1tZixIgRqKysvOzzAgMDG+yvs2fPtlDipuvevXuDrDt27Ljkts62//bs2dPgvW3atAkAMH78+Es+x9H3XWVlJXr37o2PPvqo0cfnzZuH+fPnY8GCBUhJSYGfnx9GjhyJ6urqS75mU7+Pm0W4qYULFwqNRnPR/Rs2bBBKpVIUFBRY7/v4449FYGCgMBgMjb7WkSNHBACxZ88e630//vijUCgUIjc31+bZr0VNTY0ICwsTr7766mW3GzZsmHj66adbJtQ1atu2rXjvvfeuevuysjKhVqvFihUrrPcdPXpUABDJycl2SGhb8+bNE3FxcZfdxpH338CBA8X06dOtfzeZTCIqKkrMnTu30e3vueceMXr06Ab3JSQkiEcffdSuOW2lqKhIABDbtm275DaX+nnkiF5++WXRu3fvq97e2fff008/Ldq3by/MZnOjjzvTvhNCCABi5cqV1r+bzWah1WrF22+/bb2vrKxMeHl5iW+++eaSr9PU7+PmcLsjKFeSnJyMnj17IiIiwnrfyJEjodfrcfjw4Us+JygoqMERiaSkJCiVSqSkpNg9c1OsWbMG58+fx5QpU6647ddff43Q0FD06NEDs2fPRlVVVQskbJ4333wTISEhiI+Px9tvv33ZU3Kpqamora1FUlKS9b4uXbogJiYGycnJLRH3muh0OgQHB19xO0fcfzU1NUhNTW3wtVcqlUhKSrrk1z45ObnB9oDle9IZ9hVg2V8ArrjPKioq0LZtW0RHR2Ps2LGX/HnjCE6ePImoqCi0a9cOkyZNQlZW1iW3deb9V1NTgyVLluChhx667MK0zrTv/iwjIwMFBQUN9pFGo0FCQsIl91Fzvo+bwykXC7SngoKCBuUEgPXvBQUFl3xOeHh4g/s8PDwQHBx8yefI8vnnn2PkyJFXXGzxvvvuQ9u2bREVFYUDBw7ghRdewPHjx/HDDz+0UNKr99RTT6Fv374IDg7Gzp07MXv2bOTn5+Pdd99tdPuCggJ4enpeNAYpIiLC4fbXn506dQoffPAB3nnnnctu56j779y5czCZTI1+jx07dqzR51zqe9LR9xVgWXl95syZGDJkCHr06HHJ7Tp37owvvvgCvXr1gk6nwzvvvIPBgwfj8OHDdl8YtakSEhKwaNEidO7cGfn5+XjllVdw/fXX49ChQwgICLhoe2fef6tWrUJZWRn+8pe/XHIbZ9p3janfD03ZR835Pm4OlygoL774It56663LbnP06NErDuRyJs15zzk5Ofjpp5+wfPnyK77+H8fP9OzZE5GRkRg+fDhOnz6N9u3bNz/4VWrK+5s1a5b1vl69esHT0xOPPvoo5s6d67BTUTdn/+Xm5uKWW27B+PHj8cgjj1z2ubL3H1lMnz4dhw4duuwYDQBITExEYmKi9e+DBw9G165d8cknn+C1116zd8wmGTVqlPXPvXr1QkJCAtq2bYvly5dj6tSpEpPZ3ueff45Ro0YhKirqkts4075zNi5RUJ599tnLNlwAaNeu3VW9llarvWgkcv3VHVqt9pLP+fPAIKPRiJKSkks+51o15z0vXLgQISEhuP3225v87yUkJACw/AbfEh9w17JPExISYDQakZmZic6dO1/0uFarRU1NDcrKyhocRSksLLTb/vqzpr6/vLw83HjjjRg8eDA+/fTTJv97Lb3/LiU0NBQqleqiK6Yu97XXarVN2t5RzJgxwzpgvqm/SavVasTHx+PUqVN2Smc7QUFB6NSp0yWzOuv+O3v2LH755ZcmH3V0pn0H/O9zrbCwEJGRkdb7CwsL0adPn0af05zv42ax2WgWJ3OlQbKFhYXW+z755BMRGBgoqqurG32t+kGye/futd73008/OdQgWbPZLOLi4sSzzz7brOfv2LFDABD79++3cTLbW7JkiVAqlaKkpKTRx+sHyX733XfW+44dO+awg2RzcnJEx44dxYQJE4TRaGzWazjS/hs4cKCYMWOG9e8mk0m0bt36soNkb7vttgb3JSYmOuwgS7PZLKZPny6ioqLEiRMnmvUaRqNRdO7cWTzzzDM2Tmd75eXlolWrVuLf//53o4872/6r9/LLLwutVitqa2ub9DxH33e4xCDZd955x3qfTqe7qkGyTfk+blZWm72Skzh79qxIS0sTr7zyivD39xdpaWkiLS1NlJeXCyEs/7l69OghRowYIdLT08XGjRtFWFiYmD17tvU1UlJSROfOnUVOTo71vltuuUXEx8eLlJQUsWPHDtGxY0cxceLEFn9/l/LLL78IAOLo0aMXPZaTkyM6d+4sUlJShBBCnDp1Srz66qti7969IiMjQ6xevVq0a9dODB06tKVjX9HOnTvFe++9J9LT08Xp06fFkiVLRFhYmJg8ebJ1mz+/PyGEeOyxx0RMTIz49ddfxd69e0ViYqJITEyU8RYuKycnR3To0EEMHz5c5OTkiPz8fOvtj9s40/5btmyZ8PLyEosWLRJHjhwR06ZNE0FBQdYr5x544AHx4osvWrf//fffhYeHh3jnnXfE0aNHxcsvvyzUarU4ePCgrLdwWY8//rjQaDRi69atDfZXVVWVdZs/v8dXXnlF/PTTT+L06dMiNTVVTJgwQXh7e4vDhw/LeAuX9eyzz4qtW7eKjIwM8fvvv4ukpCQRGhoqioqKhBDOv/+EsHzYxsTEiBdeeOGix5xx35WXl1s/6wCId999V6SlpYmzZ88KIYR48803RVBQkFi9erU4cOCAGDt2rIiLixMXLlywvsZNN90kPvjgA+vfr/R9bAtuV1AefPBBAeCi25YtW6zbZGZmilGjRgkfHx8RGhoqnn322QYtesuWLQKAyMjIsN53/vx5MXHiROHv7y8CAwPFlClTrKXHEUycOFEMHjy40ccyMjIafA2ysrLE0KFDRXBwsPDy8hIdOnQQzz33nNDpdC2Y+OqkpqaKhIQEodFohLe3t+jatat44403Ghzt+vP7E0KICxcuiCeeeEK0atVK+Pr6ijvuuKPBh76jWLhwYaP/X/948NMZ998HH3wgYmJihKenpxg4cKDYtWuX9bFhw4aJBx98sMH2y5cvF506dRKenp6ie/fuYv369S2c+Opdan8tXLjQus2f3+PMmTOtX4+IiAhx6623in379rV8+Ktw7733isjISOHp6Slat24t7r33XnHq1Cnr486+/4SwHAEHII4fP37RY8647+o/s/58q38fZrNZvPTSSyIiIkJ4eXmJ4cOHX/Te27ZtK15++eUG913u+9gWFEIIYbsTRkRERETXjvOgEBERkcNhQSEiIiKHw4JCREREDocFhYiIiBwOCwoRERE5HBYUIiIicjgsKERERORwWFCIiIjI4bCgEBERkcNhQSEiIiKHw4JCREREDocFhYiIiBzO/wNPHREQV/s4swAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def f(x):\n", " return x**2\n", "\n", "plot_function(f)" ] }, { "cell_type": "markdown", "id": "084f1dcc-aa75-4bc9-b1d6-9ce88bcfca06", "metadata": {}, "source": [ "Alternatively,\n", "we can use the `lambda`-shortcut Python syntax to define the function inline,\n", "when calling `plot_function`." ] }, { "cell_type": "code", "execution_count": 68, "id": "05462c86-3e6b-4da0-a9c7-722ece7c9c9a", "metadata": {}, "outputs": [ { "data": { "image/png": "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Gwtvb28kJCRg9+7dl91+xYoV6NKlC7y9vdGzZ09s2LChhZI23dy5czFgwAAEBAQgPDwc48aNw/Hjxy/7nEWLFl20v7y9vVsocdP84x//uChrly5dLvscZ9p/jf08USgUmD59eqPbO8O+2759O8aMGYOoqCgoFAqsWrWqweNCCMyZMweRkZHw8fFBUlISTp48ecXXber3cVO5XUGpqanB+PHj8fjjjzf6uMlkwujRo1FTU4OdO3di8eLFWLRoEebMmXPZ1500aRIOHz6MTZs2Yd26ddi+fTumTZtmj7fQJIMHD0Z+fn6D28MPP4y4uDj079//ss995JFHGjxv3rx5LZS66V599dUGWZ988snLbv/MM89g7dq1WLFiBbZt24a8vDzceeedLZT26h07dgxmsxmffPIJDh8+jPfeew8LFizAX//61ys+11H337fffotZs2bh5Zdfxr59+9C7d2+MHDkSRUVFjW6/c+dOTJw4EVOnTkVaWhrGjRuHcePG4dChQy2c/Ops27YN06dPx65du7Bp0ybU1tZixIgRqKysvOzzAgMDG+yvs2fPtlDipuvevXuDrDt27Ljkts62//bs2dPgvW3atAkAMH78+Es+x9H3XWVlJXr37o2PPvqo0cfnzZuH+fPnY8GCBUhJSYGfnx9GjhyJ6urqS75mU7+Pm0W4qYULFwqNRnPR/Rs2bBBKpVIUFBRY7/v4449FYGCgMBgMjb7WkSNHBACxZ88e630//vijUCgUIjc31+bZr0VNTY0ICwsTr7766mW3GzZsmHj66adbJtQ1atu2rXjvvfeuevuysjKhVqvFihUrrPcdPXpUABDJycl2SGhb8+bNE3FxcZfdxpH338CBA8X06dOtfzeZTCIqKkrMnTu30e3vueceMXr06Ab3JSQkiEcffdSuOW2lqKhIABDbtm275DaX+nnkiF5++WXRu3fvq97e2fff008/Ldq3by/MZnOjjzvTvhNCCABi5cqV1r+bzWah1WrF22+/bb2vrKxMeHl5iW+++eaSr9PU7+PmcLsjKFeSnJyMnj17IiIiwnrfyJEjodfrcfjw4Us+JygoqMERiaSkJCiVSqSkpNg9c1OsWbMG58+fx5QpU6647ddff43Q0FD06NEDs2fPRlVVVQskbJ4333wTISEhiI+Px9tvv33ZU3Kpqamora1FUlKS9b4uXbogJiYGycnJLRH3muh0OgQHB19xO0fcfzU1NUhNTW3wtVcqlUhKSrrk1z45ObnB9oDle9IZ9hVg2V8ArrjPKioq0LZtW0RHR2Ps2LGX/HnjCE6ePImoqCi0a9cOkyZNQlZW1iW3deb9V1NTgyVLluChhx667MK0zrTv/iwjIwMFBQUN9pFGo0FCQsIl91Fzvo+bwykXC7SngoKCBuUEgPXvBQUFl3xOeHh4g/s8PDwQHBx8yefI8vnnn2PkyJFXXGzxvvvuQ9u2bREVFYUDBw7ghRdewPHjx/HDDz+0UNKr99RTT6Fv374IDg7Gzp07MXv2bOTn5+Pdd99tdPuCggJ4enpeNAYpIiLC4fbXn506dQoffPAB3nnnnctu56j779y5czCZTI1+jx07dqzR51zqe9LR9xVgWXl95syZGDJkCHr06HHJ7Tp37owvvvgCvXr1gk6nwzvvvIPBgwfj8OHDdl8YtakSEhKwaNEidO7cGfn5+XjllVdw/fXX49ChQwgICLhoe2fef6tWrUJZWRn+8pe/XHIbZ9p3janfD03ZR835Pm4OlygoL774It56663LbnP06NErDuRyJs15zzk5Ofjpp5+wfPnyK77+H8fP9OzZE5GRkRg+fDhOnz6N9u3bNz/4VWrK+5s1a5b1vl69esHT0xOPPvoo5s6d67BTUTdn/+Xm5uKWW27B+PHj8cgjj1z2ubL3H1lMnz4dhw4duuwYDQBITExEYmKi9e+DBw9G165d8cknn+C1116zd8wmGTVqlPXPvXr1QkJCAtq2bYvly5dj6tSpEpPZ3ueff45Ro0YhKirqkts4075zNi5RUJ599tnLNlwAaNeu3VW9llarvWgkcv3VHVqt9pLP+fPAIKPRiJKSkks+51o15z0vXLgQISEhuP3225v87yUkJACw/AbfEh9w17JPExISYDQakZmZic6dO1/0uFarRU1NDcrKyhocRSksLLTb/vqzpr6/vLw83HjjjRg8eDA+/fTTJv97Lb3/LiU0NBQqleqiK6Yu97XXarVN2t5RzJgxwzpgvqm/SavVasTHx+PUqVN2Smc7QUFB6NSp0yWzOuv+O3v2LH755ZcmH3V0pn0H/O9zrbCwEJGRkdb7CwsL0adPn0af05zv42ax2WgWJ3OlQbKFhYXW+z755BMRGBgoqqurG32t+kGye/futd73008/OdQgWbPZLOLi4sSzzz7brOfv2LFDABD79++3cTLbW7JkiVAqlaKkpKTRx+sHyX733XfW+44dO+awg2RzcnJEx44dxYQJE4TRaGzWazjS/hs4cKCYMWOG9e8mk0m0bt36soNkb7vttgb3JSYmOuwgS7PZLKZPny6ioqLEiRMnmvUaRqNRdO7cWTzzzDM2Tmd75eXlolWrVuLf//53o4872/6r9/LLLwutVitqa2ub9DxH33e4xCDZd955x3qfTqe7qkGyTfk+blZWm72Skzh79qxIS0sTr7zyivD39xdpaWkiLS1NlJeXCyEs/7l69OghRowYIdLT08XGjRtFWFiYmD17tvU1UlJSROfOnUVOTo71vltuuUXEx8eLlJQUsWPHDtGxY0cxceLEFn9/l/LLL78IAOLo0aMXPZaTkyM6d+4sUlJShBBCnDp1Srz66qti7969IiMjQ6xevVq0a9dODB06tKVjX9HOnTvFe++9J9LT08Xp06fFkiVLRFhYmJg8ebJ1mz+/PyGEeOyxx0RMTIz49ddfxd69e0ViYqJITEyU8RYuKycnR3To0EEMHz5c5OTkiPz8fOvtj9s40/5btmyZ8PLyEosWLRJHjhwR06ZNE0FBQdYr5x544AHx4osvWrf//fffhYeHh3jnnXfE0aNHxcsvvyzUarU4ePCgrLdwWY8//rjQaDRi69atDfZXVVWVdZs/v8dXXnlF/PTTT+L06dMiNTVVTJgwQXh7e4vDhw/LeAuX9eyzz4qtW7eKjIwM8fvvv4ukpCQRGhoqioqKhBDOv/+EsHzYxsTEiBdeeOGix5xx35WXl1s/6wCId999V6SlpYmzZ88KIYR48803RVBQkFi9erU4cOCAGDt2rIiLixMXLlywvsZNN90kPvjgA+vfr/R9bAtuV1AefPBBAeCi25YtW6zbZGZmilGjRgkfHx8RGhoqnn322QYtesuWLQKAyMjIsN53/vx5MXHiROHv7y8CAwPFlClTrKXHEUycOFEMHjy40ccyMjIafA2ysrLE0KFDRXBwsPDy8hIdOnQQzz33nNDpdC2Y+OqkpqaKhIQEodFohLe3t+jatat44403Ghzt+vP7E0KICxcuiCeeeEK0atVK+Pr6ijvuuKPBh76jWLhwYaP/X/948NMZ998HH3wgYmJihKenpxg4cKDYtWuX9bFhw4aJBx98sMH2y5cvF506dRKenp6ie/fuYv369S2c+Opdan8tXLjQus2f3+PMmTOtX4+IiAhx6623in379rV8+Ktw7733isjISOHp6Slat24t7r33XnHq1Cnr486+/4SwHAEHII4fP37RY8647+o/s/58q38fZrNZvPTSSyIiIkJ4eXmJ4cOHX/Te27ZtK15++eUG913u+9gWFEIIYbsTRkRERETXjvOgEBERkcNhQSEiIiKHw4JCREREDocFhYiIiBwOCwoRERE5HBYUIiIicjgsKERERORwWFCIiIjI4bCgEBERkcNhQSEiIiKHw4JCREREDocFhYiIiBzO/wNPHREQV/s4swAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plot_function(lambda x: x**2)" ] }, { "cell_type": "markdown", "id": "d6b0c4a3-6254-4fb4-99a8-6de99db9fd5a", "metadata": {}, "source": [ "The `lambda`-expression `lambda x: x**2` is equivalent to the Python function `f` we defined using the two-line `def`-statement.\n", "\n", "Both ways of defining `f` are the same `type` of object:" ] }, { "cell_type": "code", "execution_count": 69, "id": "d41cdac7-7bb0-4c9d-baf1-34bdc62e7b59", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "function" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(f)" ] }, { "cell_type": "code", "execution_count": 70, "id": "a8d6045c-712b-41b4-b040-8c3d7b4e3a3e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "function" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(lambda x: x**2)" ] }, { "cell_type": "code", "execution_count": null, "id": "ce38cc5a-4f64-43f1-86be-25688120a9d9", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "ed1918c3-6c72-4a5f-90ca-dcb918442852", "metadata": {}, "source": [ "Since `f` and `lambda x: x**2` are both expressions of the type `function`,\n", "we can call both of them the same way (by passing in the argument in parentheses).\n", "\n", "For example, if we want to evaluate the function $f(x)$ at the input $x=3$,\n", "we can call `f(3)` ..." ] }, { "cell_type": "code", "execution_count": 71, "id": "893317fb-6272-475f-8048-b61f82b22e57", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(3)" ] }, { "cell_type": "markdown", "id": "282d9afc-9500-4417-a580-b7311262f1f1", "metadata": {}, "source": [ "or we could define the function $f(x)=x^2$ using an inline `lambda` expression,\n", "then call the result of the lambda expression by passing in the argument in parentheses." ] }, { "cell_type": "code", "execution_count": 72, "id": "a117b214-6aef-45df-9fdf-d5d984174b20", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(lambda x: x**2)(3)" ] }, { "cell_type": "markdown", "id": "86e1f0f3-bd7e-402c-98e6-509cf9e884de", "metadata": {}, "source": [ "The `lambda`-shortcut for defining functions is not used often,\n", "but sometimes it is very convenient to be able to use inline function definition,\n", "so I want you to be familiar with this syntax." ] }, { "cell_type": "markdown", "id": "cc3ea1c6-b4b4-4f05-80f2-02d8c45fada1", "metadata": {}, "source": [ "### Applying functions to lists (optional)\n", "\n", "Consider the math function $f(x)=x^2$.\n", "We'll identify the output of the function as the variable $y$.\n", "\n", "In Python, the function $f(x)=x^2$ is" ] }, { "cell_type": "code", "execution_count": 73, "id": "9a0e9b2e-3b3f-4b50-b8a6-cc7eee511226", "metadata": {}, "outputs": [], "source": [ "def f(x):\n", " return x**2" ] }, { "cell_type": "markdown", "id": "be62bd97-d479-410a-9e12-fee3cf22f146", "metadata": {}, "source": [ "Suppose we want to compute the output values $y=f(x)$\n", "for each $x$ in the list of values $[1,2,3,4]$,\n", "which we'll call `xs` in the code." ] }, { "cell_type": "code", "execution_count": 74, "id": "1c98bbc6-a1c7-4450-bf9f-beee5a9dddda", "metadata": {}, "outputs": [], "source": [ "xs = [1,2,3,4]" ] }, { "cell_type": "markdown", "id": "e621d113-3fe4-46bf-af72-e4e07e550fb9", "metadata": {}, "source": [ "**Option A** You can use a `for` loop to compute the function output $y=f(x)$ for every $x$ in the list of values. First we create an empty list `ys` to store the outputs, then we `.append` to it the values one-by-one as we go though the for loop." ] }, { "cell_type": "code", "execution_count": 75, "id": "ef74a6bc-9480-4b3c-bff8-19ca565ea8c2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 4, 9, 16]" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ys = []\n", "for x in xs:\n", " y = f(x)\n", " ys.append(y)\n", "\n", "ys" ] }, { "cell_type": "markdown", "id": "f0cd1d5d-df89-4e37-9d3d-c97a8051f372", "metadata": {}, "source": [ "**Option B** \n", "We can shorten the code using the list comprehension syntax:" ] }, { "cell_type": "code", "execution_count": 76, "id": "2bd5fd9b-128c-48b0-ab4b-9d3d47e97f76", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 4, 9, 16]" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ys = [f(x) for x in xs]\n", "\n", "ys" ] }, { "cell_type": "markdown", "id": "85a7071a-ad35-4f99-9abc-930bc69ba469", "metadata": {}, "source": [ "**Option C** \n", "A third alternative would be to use the function `map(f,xs)`\n", "which returns a list of the outputs `f(x)` for all `x` in the list `xs`." ] }, { "cell_type": "code", "execution_count": 77, "id": "eb693e81-43d2-4595-a26d-99317308cf46", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 4, 9, 16]" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ys = map(f, xs)\n", "\n", "list(ys)" ] }, { "cell_type": "code", "execution_count": 78, "id": "c5c211a0-d0a3-4c36-b684-c1fd78bfeb3e", "metadata": {}, "outputs": [], "source": [ "# ALT. we can specify the function argument to map as a lambda expression\n", "# list(map(lambda x: x**2, xs))" ] }, { "cell_type": "markdown", "id": "9c420024-42f5-4a43-b353-ad86a2acd63e", "metadata": {}, "source": [ "This notion of obtaining `ys` from `xs` for entire lists of values,\n", "instead of individual values like `x` and `y` is super useful.\n", "We'll see this idea come up again later on in this tutorial\n", "when we discuss the Python module NumPy,\n", "which allows you to do math operations with \"universal functions\"\n", "that do the right thing whether you input a number `x`,\n", "a list of numbers `xs`, or even more complicated data structures (e.g. two-dimensional matrices, or higher-dimensional tensors).\n", "\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "bfce20d7-82da-435a-a713-1401f3875917", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "d478470f-add0-4b38-9a5d-71b52f563372", "metadata": {}, "outputs": [], "source": [] }, { "attachments": { "d41cd497-3947-46de-8aee-5bfee616a406.png": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlIAAAEaCAYAAADaPLnvAAAMZ2lDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnluSkJDQAhGQEnoTpFcpIbQIAlIFGyEJJJQYEoKKHV1UcO0iihVdBVF0dQVkLYgF2yLY+2JBRVkXdVEUlTchAV33le+dfHPnzz9nTstM7gwAmn1ciSQH1QIgV5wvjQsPZk5ISWWSngIUftRh8+PyZBJWbGwUgDLU/13e3QCIor/qqLD1z/H/Kjp8gYwHADIJ4nS+jJcLcRMA+CaeRJoPAFHBW0zPlyjwfIh1pTBAiNcqcKYSVylwuhIfHdRJiGND3AaAGpXLlWYCoHEP8swCXia0o/EJYmcxXyQGQHMUxAE8IZcPsSL2Ubm50xS4HGJbqC+BGMYDvNO/sZn5N/vpw/a53MxhrMxrUNRCRDJJDnfm/1ma/y25OfIhH9awUYXSiDhF/rCGt7KnRSowFeJucXp0jKLWEPeJ+Mq6A4BShPKIRKU+asSTsWH9AANiZz43JBJiI4jDxDnRUSo+PUMUxoEYrhZ0hiifkwCxPsRLBLLQeJXONum0OJUvtC5Dymap+HNc6aBfha8H8uxElsr+G6GAo7KPaRQKE5IhpkBsWSBKioZYA2InWXZ8pEpnTKGQHT2kI5XHKeK3hDhOIA4PVtrHCjKkYXEq/ZJc2VC+2DahiBOtwgfzhQkRyvpgp3ncwfhhLlibQMxKHLIjkE2IGsqFLwgJVeaOPReIE+NVdvok+cFxyrk4RZITq9LHzQU54QreHGJ3WUG8ai6elA8Xp9I+niHJj01QxokXZnHHxirjwVeCKMAGIYAJ5LClg2kgC4hau+u74TflSBjgAinIBALgqGKGZiQPjojhMx4Ugj8gEgDZ8LzgwVEBKID852FW+XQEGYOjBYMzssFTiHNBJMiB3+WDs8TD3pLAE8iI/uGdCxsPxpsDm2L83/ND7FeGBZkoFSMf8sjUHNIkhhJDiBHEMKIdbogH4H54FHwGweaKe+M+Q3l81Sc8JbQTHhGuEzoIt6eKiqTfRTkOdED7YapapH9bC9wa2vTAg3F/aB1axhm4IXDE3aEfFh4IPXtAlq2KW1EV5ne2/5bBN7+GSo/sTEbJI8hBZNvvZ2rYa3gMW1HU+tv6KGNNH643e3jke//sb6rPh33k95rYEuwQ1oKdxM5jR7F6wMROYA3YJeyYAg+vrieDq2vIW9xgPNnQjugf/rgqn4pKypxrnLucPynH8gUz8hUbjz1NMlMqyhTmM1nw7SBgcsQ8p1FMV2dXVwAU7xrl39dbxuA7BGFc+MrlNQHgUwLJzK8c1wKAI08BoL/7ylm8gdtmJQDH2nhyaYGSwxUPAvyX0IQ7zQCYAAtgC/NxBZ7ADwSBUDAWxIAEkAKmwCoL4TqXgulgNlgAikEpWAnWgY1gK9gBqsA+cBDUg6PgJDgLLoI2cB3chaunE7wEPeAd6EcQhITQEDpigJgiVogD4op4IwFIKBKFxCEpSBqSiYgROTIbWYiUIquRjch2pBr5GTmCnETOI+3IbeQh0oW8QT6iGEpFdVFj1BodjXqjLDQSTUAno5loHlqILkKXo+VoJboXrUNPohfR62gH+hLtxQCmjjEwM8wR88bYWAyWimVgUmwuVoKVYZVYLdYIf+erWAfWjX3AiTgdZ+KOcAVH4Ik4D8/D5+LL8I14FV6Hn8av4g/xHvwLgUYwIjgQfAkcwgRCJmE6oZhQRthFOEw4A/dSJ+EdkUhkEG2IXnAvphCziLOIy4ibifuJTcR24mNiL4lEMiA5kPxJMSQuKZ9UTNpA2ks6QbpC6iT1qamrmaq5qoWppaqJ1YrUytT2qB1Xu6L2TK2frEW2IvuSY8h88kzyCvJOciP5MrmT3E/RpthQ/CkJlCzKAko5pZZyhnKP8lZdXd1c3Ud9vLpIfb56ufoB9XPqD9U/UHWo9lQ2dRJVTl1O3U1tot6mvqXRaNa0IFoqLZ+2nFZNO0V7QOvToGs4aXA0+BrzNCo06jSuaLzSJGtaabI0p2gWapZpHtK8rNmtRday1mJrcbXmalVoHdG6qdWrTdd20Y7RztVepr1H+7z2cx2SjrVOqA5fZ5HODp1TOo/pGN2Czqbz6AvpO+ln6J26RF0bXY5ulm6p7j7dVt0ePR09d70kvRl6FXrH9DoYGMOawWHkMFYwDjJuMD6OMB7BGiEYsXRE7YgrI97rj9QP0hfol+jv17+u/9GAaRBqkG2wyqDe4L4hbmhvON5wuuEWwzOG3SN1R/qN5I0sGXlw5B0j1MjeKM5oltEOo0tGvcYmxuHGEuMNxqeMu00YJkEmWSZrTY6bdJnSTQNMRaZrTU+YvmDqMVnMHGY58zSzx8zILMJMbrbdrNWs39zGPNG8yHy/+X0LioW3RYbFWotmix5LU8txlrMtayzvWJGtvK2EVuutWqzeW9tYJ1svtq63fm6jb8OxKbSpsblnS7MNtM2zrbS9Zke087bLttts12aP2nvYC+0r7C87oA6eDiKHzQ7towijfEaJR1WOuulIdWQ5FjjWOD50YjhFORU51Tu9Gm05OnX0qtEto784ezjnOO90vuui4zLWpcil0eWNq70rz7XC9ZobzS3MbZ5bg9trdwd3gfsW91sedI9xHos9mj0+e3p5Sj1rPbu8LL3SvDZ53fTW9Y71XuZ9zofgE+wzz+eozwdfT99834O+f/o5+mX77fF7PsZmjGDMzjGP/c39uf7b/TsCmAFpAdsCOgLNArmBlYGPgiyC+EG7gp6x7FhZrL2sV8HOwdLgw8Hv2b7sOeymECwkPKQkpDVUJzQxdGPogzDzsMywmrCecI/wWeFNEYSIyIhVETc5xhwep5rTM9Zr7JyxpyOpkfGRGyMfRdlHSaMax6Hjxo5bM+5etFW0OLo+BsRwYtbE3I+1ic2L/XU8cXzs+IrxT+Nc4mbHtcTT46fG74l/lxCcsCLhbqJtojyxOUkzaVJSddL75JDk1ckdE0ZPmDPhYophiiilIZWUmpS6K7V3YujEdRM7J3lMKp50Y7LN5BmTz08xnJIz5dhUzancqYfSCGnJaXvSPnFjuJXc3nRO+qb0Hh6bt573kh/EX8vvEvgLVgueZfhnrM54numfuSazSxgoLBN2i9iijaLXWRFZW7PeZ8dk784eyEnO2Z+rlpuWe0SsI84Wn55mMm3GtHaJg6RY0pHnm7cur0caKd0lQ2STZQ35uvBQf0luK/9B/rAgoKCioG960vRDM7RniGdcmmk/c+nMZ4VhhT/NwmfxZjXPNpu9YPbDOaw52+cic9PnNs+zmLdoXuf88PlVCygLshf8VuRctLror4XJCxsXGS+av+jxD+E/1BRrFEuLby72W7x1Cb5EtKR1qdvSDUu/lPBLLpQ6l5aVflrGW3bhR5cfy38cWJ6xvHWF54otK4krxStvrApcVbVae3Xh6sdrxq2pW8tcW7L2r3VT150vcy/bup6yXr6+ozyqvGGD5YaVGz5tFG68XhFcsX+T0aalm95v5m++siVoS+1W462lWz9uE227tT18e12ldWXZDuKOgh1PdybtbPnJ+6fqXYa7Snd93i3e3VEVV3W62qu6eo/RnhU1aI28pmvvpL1t+0L2NdQ61m7fz9hfegAckB948XPazzcORh5sPuR9qPYXq182HaYfLqlD6mbW9dQL6zsaUhraj4w90tzo13j4V6dfdx81O1pxTO/YiuOU44uOD5woPNHbJGnqPpl58nHz1Oa7pyacunZ6/OnWM5Fnzp0NO3uqhdVy4pz/uaPnfc8fueB9of6i58W6Sx6XDv/m8dvhVs/WustelxvafNoa28e0H78SeOXk1ZCrZ69xrl28Hn29/UbijVs3J93suMW/9fx2zu3Xdwru9N+df49wr+S+1v2yB0YPKn+3+31/h2fHsYchDy89in909zHv8csnsiefOhc9pT0te2b6rPq56/OjXWFdbS8mvuh8KXnZ3138h/Yfm17Zvvrlz6A/L/VM6Ol8LX098GbZW4O3u/9y/6u5N7b3wbvcd/3vS/oM+qo+eH9o+Zj88Vn/9E+kT+Wf7T43fon8cm8gd2BAwpVyB48CGGxoRgYAb3YDQEuBZwd4b6NMVN4FBwVR3l8HEfhPWHlfHBRPAHYHAZA4H4AoeEbZApsVxFTYK47wCUEAdXMbbiqRZbi5Km1R4U2I0Dcw8NYYAFIjAJ+lAwP9mwcGPu+Ewd4GoClPeQdVCBHeGbY5KVBb5yvwvSjvp9/k+H0PFBG4g+/7fwGvRo9EhfhygwAAAJZlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAACQAAAAAQAAAJAAAAABAAOShgAHAAAAEgAAAISgAgAEAAAAAQAAAlKgAwAEAAAAAQAAARoAAAAAQVNDSUkAAABTY3JlZW5zaG90GJ6mygAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAtdpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjU5NDwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlVzZXJDb21tZW50PlNjcmVlbnNob3Q8L2V4aWY6VXNlckNvbW1lbnQ+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4zNDQ8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8dGlmZjpSZXNvbHV0aW9uVW5pdD4yPC90aWZmOlJlc29sdXRpb25Vbml0PgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj4xNDQ8L3RpZmY6WVJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjE0NDwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+ClW4uZkAACdMSURBVHgB7d19kFX1fcfx77LL0yJaWQwP4dksoOADKogLGi2ijg+IGqtYZ1IDGac2Jql0SiXTtElTa038w+rUpgqxcZSJRusDGhOG1hIgUZRVgQALhoeNIshzhGVhl+39Hv1df3u49+69557He97HuZyn3znn93v9dsbP/M6551Y1NTV1SGaqr6/XGRMCCCCAAAIIIIBAkQLdiixHMQQQQAABBBBAAAGXAEHKBcIqAggggAACCCBQrABBqlgpyiGAAAIIIIAAAi4BgpQLhFUEEEAAAQQQQKBYAYJUsVKUQwABBBBAAAEEXAIEKRcIqwgggAACCCCAQLECBKlipSiHAAIIIIAAAgi4BAhSLhBWEUAAAQQQQACBYgUIUsVKUQ4BBBBAAAEEEHAJEKRcIKwigAACCCCAAALFChCkipWiHAIIIIAAAggg4BIgSLlAWEUAAQQQQAABBIoVqCm2YFzKHTlyJC5VoR4IIIAAAgggkHIBRqRS/gdA8xFAAAEEEEDAuwBByrsdRyKAAAIIIIBAygUIUin/A6D5CCCAAAIIIOBdgCDl3Y4jEUAAAQQQQCDlAgSplP8B0HwEEEAAAQQQ8C5AkPJux5EIIIAAAgggkHIBglTK/wBoPgIIIIAAAgh4FyBIebfjSAQQQAABBBBIuQBBKuV/ADQfAQQQQAABBLwLEKS823EkAggggAACCKRcgCCV8j8Amo8AAggggAAC3gUIUt7tOBIBBBBAAAEEUi5AkEr5HwDNRwABBBBAAAHvAgQp73YciQACCCCAAAIpFyBIpfwPgOYjgAACCCCAgHcBgpR3O45EAAEEEEAAgZQLEKRS/gdA8xFAAAEEEEDAuwBByrsdRyKAAAIIIIBAygUIUin/A6D5CCCAAAIIIOBdgCDl3Y4jEUAAAQQQQCDlAgSplP8B0HwEEEAAAQQQ8C5AkPJux5EIIIAAAgggkHIBglTK/wBoPgIIIIAAAgh4FyBIebfjSAQQQAABBBBIuQBBKuV/ADQfAQQQQAABBLwLRB6kfndomxxsO+y9BRyJAAIIIIAAAghEJBBpkNIQdcvvvu98CFMR/QVwWQQQQAABBBDwLBBZkDIhSgNU85GP5Q+tH3tuRFwO7OjoiEtVqAcCCCCAAAIIhCBQE8I1TriEHaL6VtfKM+O+K2f2GX5CuSRseOedd+TZZ5+Vt956S5qbm6VPnz4yfvx4mTVrllxxxRVJaEJZdeyQDqnK/Bf1FJd6RO3A9RFAAAEEwhWoampqcoZR6uvrQ7lyuSHqyJEjvtZz48aNsnTpUrFHkwYPHiw33HBDl9e5//775ac//Wnectdcc4088MADUlXVddB49dVXZcuWLdlz6TGXXnqpnHnmmdltcVjYf+SQPPLmK/LGHzZK094PpbXtmAzu20++PHy83HvxV+TknrWhVHPz3h2yYPUS+dXvG2XP4T8619R6XDt6ovz1RddL75oeodSDiyCAAAIIpFsg1CBVbojSrvI7SM2ZM0dWrlx5wl/B22+/Lb179z5hu9mwefNmmTFjhrOqo1BXX321NDQ0yL59++TBBx+UQ4cOOfu+973vyc0332wOyzlvb2+Xs84664R955xzjixatOiE7VFteG79Spm/9EknPOWqQ5/uPeWZm+fJuC8My7U75zbtz8OHD0u/fv1y7s+18ek1/+fUI9c+3XZqr5Nk6Vd/IP16n5SvCNsRQAABBBDwRSC0W3t+hChfWuw6SWtra3bL/PnzneWhQ4cWDFFaaNiwYTJ79mwZNGiQ3HjjjdKrV6/seS688ELR0SidXnnllS6DVHV1tTz22GPZEamHHnrICWJ+h8ZsBT0s6AjQ3F8uzB456Yv1MnPsRZkRqN6yaM0yWdG8Xg4da5U7XnxIfn3H/dKzpnu2bL4FHQWcNGmSbNq0Sd59910ZPXp0vqKdtn/3f5/Krp87cFRmFOoC6dOjl/zbb1+WHZ/sk31HPpG7X/2xPHXT3Gw5FhBAAAEEEAhCIJQgFdcQZYMOGDBAbr/9dntTweUePXrI3Lm5/0c9cuRImTp1qixfvlzWrVtX8Dxm55QpU0Q/Oj3zzDOiI15xmg62fv6Kim9deJ1z+8zUT2+n/cULD8nrW9fIrkMH5KWNb8rN4z5tiymTa97S0uKEKN2ntzWLDVL3XDRTPvjjXvnGpGtk0EmnZk99/ZgLZcqCeU6Q0mDX0naUW3xZHRYQQAABBIIQ8PytPf223S3r/kk0JBWakhCiCtXfyz4dadm27VMXvT1XCdOY/kNER3/uOHdapxBl2qbhykyNH/3eLAYyv2vi1fLPf3p7pxClF6rN3Fq8ZfzU7DXfz4yiMSGAAAIIIBCkgOcRqa9v/JH89uB65x1QPzsz97fu0hqiFi9e7HyDTzvukksuCbL/Qju3Pv/0wq2f3vrMddG+mVt8ZtrT8unD32Y9zPmW/buylxt16sDsMgsIIIAAAggEIeB5ROofRnxV9NUFzshU5qWa7pGptIWo7du3yxNPPCG33HKLzJs3z+kr/cadeSA9iM6L0zlf2fRWtjoTB38puxzmwns7t8ovN692LnnOgBHOCFWY1+daCCCAAALpE/A8IqXvfdL3P/3Zuu9nw5QZmUpbiNI/m3vvvVcaGxuzf0H6zNWTTz7Z5UPr2QMSvPBR5gHvh9942WlBTbducuMZF4XWmr0tn8jP1v5aXt+21nklg15Y63DvxYW/KRlaBbkQAggggEBFC3gekVIVE6bskamff7ws+5MvSX/ZZik9f9ddd8mECROcF3LqcTt37pSbbrrJ+TZaKedJWtmj7W3y588/KG3HjztV/9bkGZnXDvQ9oRn6IL++TsL+1NXVZcvNnDmz0z4td/bZZ8sHH3yQLZNr4Ucr/1v+dcVz2RClZRbf9l2ZPGRMruJsQwABBBBAwFeBsoKU1sQdpuZuftQZoUpTiFIH/cbdU0895bzcU99NpdPWrVtFlz/55BNnvdL+OZ55qP4vF/+7vL/3I6dp5w06Xf5q4qevfbDbqq9xeO655+xNRS3raxH0hamFphvOmCxnfWF4p9ctXPv09+WJd5YWOox9CCCAAAII+CLg+daefXUTpvQ23x/bDzvPTiX5Z1/stpW6fPLJJ8s999wj+tV+DVb6Ys5ly5Y5L+ws9VxxLq8/yfLNX/ynLN3ynlPNutq+svD6b0q3HG9x13ds6QtO165d26lJGrDuvPNOZ9vdd98tF1xwQaf9/fv3l0svvbTTNvfKxMH18vJtf58ZEWuXnzQuzYxO/dwZHfvH1xfJ6LovSsPQse5DWEcAAQQQQMA3AV+ClNbGhKk5mW/zPT7mbxL723l+yU6fPt0JUno+fRC9kiYdidIQtbhpldMsfZP4K5nbaX/Sq0/eZuqD9+6fu9E3mpsgNW3aNLnyyivzHt/Vjppu1fL186+QU3rVyt8uecIp/l/v/g9Bqis49iOAAAIIlCVQ9q09++oaplae93DqQ5Sa6As7zVRT41teNaeMbK7PQn39pYezIUpfe7A4MyI00HoxZmSVy1z4mvrPR7U2Z34LkAkBBBBAAIEgBSrn//BBKuU495o1a0R/I09fuJnrR4ntHzM+99xzc5wheZvaO47LnEyI0jeY66S38/TBbvvt4lG3qkf153/S3bt9vhx1vbg+AggggEBlCvB/Gg/9umvXLud9UXromDFjnOefJk6cKPX19c63zPR381577TXnzPq7fbl+kNjDZSM9RJ+J+sYrP86GKA1P+mxS/9qTs/XaduBjue/Xz8qt4y+Wy0ac+CPM2YJlLGzZt1N+t7tZLh95TqcHzM0pH1v9K7OYua13RnaZBQQQQAABBIIQIEh5UNWv7WtAam5udr5VVuibZfoDxD179vRwlXgd8h+rXpNfbH47W6nLRp4lP3F9M275tnXybualmB8e3FNUkOre/fMfNtbXHRQz3fizf3F+S09/FHnGmEny5eHjneegDra2ON/Us7+td1OI77Mqpu6UQQABBBCoPAGClIc+ra6udn5Y+JFHHnG+kaeByj1ddtllzhvOhw0b5t6VyPVH3lzcqd5Pr1nWad1eqe3Ry17Nu6xBSn+gecOGDTJ58uS85ewdU4ad4Tyf1dp2TJ5dt8L52PvN8t9N/YqM+0Jl2Js2MUcAAQQQiJ8AQcpjn5xyyinyne98x/ns27fP+Wq/voRzyJAhMnz4cBk0aJDHM8fzsKu+dL48t35lUZUr5bbeddddJ/opdnrwiq/J4L795OWNb8qOzBvV3ZM+t/XA9Dtk2siz3btYRwABBBBAwHcBgpQPpKeeeqpcfPHFPpwpvqd48MqviX6invSW3vzMz7/o59DRI7J6x/uyfvcfnG8Njq4bLF/qN9j5iZio68n1EUAAAQTSIUCQSkc/V2Qr+2RuIV48fJzzqcgG0igEEEAAgdgLEKQ+6yK9LaffvNNp9OjRoq8v0Gehwpg6Mi+4vOOOO2TdunXO5fRt6EwIIIAAAgggEH+BbuVW8dixY85vyWkYSOJkv5pAA4x+tm3bJmG3Z8eOHc617RA1fvz4JJJSZwQQQAABBFIjUNXU1OQkIH0HUinTwYMH5Z133pG2trbsYf369ZOzzz5bunUrO59lz+le0N9n83vSHxW2g1NtbW1oo1GmLfpyT/3JFHvq27evvcoyAggggAACCMRMwNOtPQ1P+iO0Gj40PGnw0Ftje/fulffee0+S9ibvk046KfJu0duIBKfIu4EKIIAAAgggUJKAp6Ejc+vrtNNOc0KTPlPU0NDgjERpmDp69GhJlaAwAggggAACCCCQRAFPI1IalnSyXzapIyr6GoA9e/bIgQMHREOWTnorTt/8rdt0BEvf8j1y5EgZMGCAs59/EEAAAQQQQACBpAp4ClJmxElv6dmT+ZmPlpYWZ7MGp1WrVok+kK7PTelHnwPSb6fpOfRnVpgQQAABBBBAAIGkCngKUuYBc/u30hTArLe2tjoe+tMpGqL0GaRJkyZlt23atEm2bt1KkHJE+AcBBBBAAAEEkirgKUgV21jz7T0NUzoC1aNHDyc8aeAK6x1NxdaVcggggAACCCCAQKkCgQSpqqoqpx4DBw50Rp50hGr58uWit/702Sj9PToNVUwIIIAAAggggECSBTx9a6+m5tP8ZZ6VMgA68qSTPlCuk5bTb/ONGjXKCVH67JTe0luxYoV8/PHHThn+QQABBBBAAAEEkirgaURKg5KOMulbuO2RJfNCyV69ejke+o09fdHk8OHDZcSIEc7zUu+//758+OGHsn79+uw3+5KKR70RQAABBBBAIN0Cnkak9CWcOm3fvj2rpw+g79u3T/S2nr4GQSf9dt4bb7zh/OSKruuzUaeffroudnojurOBfxBAAAEEEEAAgYQJeBqR0hEmfSmnvjNq9erVzrfy9M3m+rqDuro655aeOuizUPr+qC1btjghS5+R2r17t0Ok5ZgQQAABBBBAAIEkC3j+rT39fbrGxkbndp0B0HCkv7VnHjbX7R999JHzQk69xaeTfltPR7TOOOOMbOBydhT5TxC/tVfkpSmGAAIIIIAAAgh0EvAcpMxZ9Jaehps+ffp0ClBmv5nrg+ha1ry002wvdU6QKlWM8ggggAACCCAQlICnW3t2ZfSbecX86K8+H2Ve2GkfzzICCCCAAAIIIJBUAU8Pmye1sdQbAQQQQAABBBDwU4Ag5acm50IAAQQQQACBVAkQpFLV3TQWAQQQQAABBPwUIEj5qcm5EEAAAQQQQCBVAgSpVHU3jUUAAQQQQAABPwUIUn5qci4EEEAAAQQQSJUAQSpV3U1jEUAAAQQQQMBPAYKUn5qcCwEEEEAAAQRSJUCQSlV301gEEEAAAQQQ8FOAIOWnJudCAAEEEEAAgVQJEKRS1d00FgEEEEAAAQT8FCj7t/b8rEwx5+rVq1cxxSiDAAIIIIAAAggELsCIVODEXAABBBBAAAEEKlWAIFWpPUu7EEAAAQQQQCBwAYJU4MRcAAEEEEAAAQQqVYAgVak9S7sQQAABBBBAIHABglTgxFwAAQQQQAABBCpVgCBVqT1LuxBAAAEEEEAgcAGCVODEXAABBBBAAAEEKlWAIFWpPUu7EEAAAQQQQCBwAYJU4MRcAAEEEEAAAQQqVYAgVak9S7sQQAABBBBAIHABglTgxFwAAQQQQAABBCpVgCBVqT1LuxBAAAEEEEAgcAGCVODEXAABBBBAAAEEKlWAIFWpPUu7EEAAAQQQQCBwAYJU4MRcAAEEEEAAAQQqVYAgVak9S7sQQAABBBBAIHABglTgxFwAAQQQQAABBCpVgCBVqT1LuxBAAAEEEEAgcAGCVODEXAABBBBAAAEEKlWAIFWpPUu7EEAAAQQQQCBwAYJU4MRcAAEEEEAAAQQqVYAgVak9S7sQQAABBBBAIHABglTgxFwAAQQQQAABBCpVoKZSG0a7/BP4zW9+I8uXL5f29vacJ62qqpKpU6fKlClTcu5nIwIIIIAAApUqUNXU1NShjauvr6/UNtKuMgVmzJgha9euLXiWPn36yJo1awqWYScCCCCAAAKVJsCIVKX1aIDt0bBUV1d3whWqq6tFwxYTAggggAACaRMgSKWtx8to77e//W2ZPXt2GWfgUAQQQAABBCpLgIfNK6s/aQ0CCCCAAAIIhChAkAoRm0shgAACCCCAQGUJcGuvsvoz0Nbs2LFDnn/+edm0aZMcOHBARo4cKePGjZPJkydLt25k8kDxOTkCCCCAQCwFCFKx7JZ4VmrhwoU5K3bJJZfI/fffLwMHDsy5n40IIIAAAghUqgDDCJXasz62q3v37tmz6Tf3pk+fLldddZXosk7Lli2TW2+9VVpaWrLlWEAAAQQQQCANAoxIpaGXy2zjzJkzZdCgQXL77bfLxIkTRV93oNO+fftk7ty58vrrr8v27dvl0UcflXvuuafMq3E4AggggAACyRHghZzJ6atY1lSflbr88stlz549zjumVq1aFct6UikEEEAAAQSCEODWXhCqKTrnKaecItdee63TYg1TGqyYEEAAAQQQSIsAQSotPR1gO0877bTs2ffv359dZgEBBBBAAIFKFyBIVXoPh9C+zO81Zq8yZMiQ7DILCCCAAAIIVLoAQarSezjg9umPGb/00kvOVSZMmJB9ED3gy3J6BBBAAAEEYiFAkIpFN8S3Eo899phMmzZNfvCDHzjfztu5c6dTWX3VwQsvvCCzZs3KVl6/wceEAAIIIIBAmgR4/UGaettDW3XEacuWLc4n3ws59bR33nmnNDQ0eLgChyCAAAIIIJBcAYJUcvsulJrPnz9fqqqqsrfv3Betq6uT++67z3lJp3sf6wgggAACCFS6AO+RqvQe9ql97e3tsm3bNtmwYYPzIs7+/fvL6aefLiNGjJCaGvK4T8ycBgEEEEAgYQL8HzBhHRZVdfVt5qNGjXI+UdWB6yKAAAIIIBA3AR42j1uPUB8EEEAAAQQQSIwAQSoxXUVFEUAAAQQQQCBuAgSpuPUI9UEAAQQQQACBxAgQpBLTVVQUAQQQQAABBOImQJCKW49QHwQQQAABBBBIjABBKjFdRUURQAABBBBAIG4CBKm49Qj1QQABBBBAAIHECBCkEtNVVBQBBBBAAAEE4iZAkIpbj1AfBBBAAAEEEEiMAEEqMV1FRRFAAAEEEEAgbgIEqbj1CPVBAAEEEEAAgcQIEKQS01VUFAEEEEAAAQTiJkCQiluPUB8EEEAAAQQQSIwAQSoxXUVFEUAAAQQQQCBuAgSpuPUI9UEAAQQQQACBxAgQpBLTVVQUAQQQQAABBOImQJCKW49QHwQQQAABBBBIjABBKjFdRUURQAABBBBAIG4CBKm49Qj1QQABBBBAAIHECBCkEtNVVBQBBBBAAAEE4iZAkIpbj1AfBBBAAAEEEEiMAEEqMV1FRRFAAAEEEEAgbgIEqbj1CPVBAAEEEEAAgcQIEKQS01VUFAEEEEAAAQTiJkCQiluPUB8EEEAAAQQQSIwAQSoxXUVFEUAAAQQQQCBuAgSpuPUI9UEAAQQQQACBxAgQpBLTVVQUAQQQQAABBOImQJCKW49QHwQQQAABBBBIjABBKjFdRUURQAABBBBAIG4CBKm49Qj1QQABBBBAAIHECNQkpqYlVLSjo6OE0hRFAAEEEEAAAQS8CSQ2SBGWvHU4RyGAAAIIIICAfwKJC1IEKP86nzMhgAACCCCAQHkCiQlSBKjyOpqjEUAAAQQQQMB/gdgHKQKU/53OGRFAAAEEEEDAH4HYBimvAcrrcf5wchYEEEAAAQQQSJNA7IJUqUGo1PJp6lzaigACCCCAAALBCsQqSBUbiootZ9N5OcY+nmUEEEAAAQQQQMAtEJsgVUzQ6apMV/vdjWcdAQQQQAABBBAoRyAWQaqrAFRof6F9BqaYMqYscwQQQAABBBBAoFiByINUVyEn1/5c27TB+bYXi2HK+XUecz7mCCCAAAIIIFCZApEGqUKBJde+YrdpV+UqW5ldSKsQQAABBBBAICqByIJUoaCTa597W1frNqi7rL2PZQQQQAABBBBAwKtAJEGqULBx7yu07t6nCLm2FdruFY7jEEAAAQQQQACBSIJUPnZ3CLLX7WU93l63l9373Ndyl3XvZx0BBBBAAAEEEChWIPQglS/IuLfb6/mWjx8/nm2nXUY3utdNwXzbzX7mCCCAAAIIIIBAsQKhB6liKmaHHfeyrru36TlNqDL7zNx9vXzb3eVYRwABBBBAAAEEuhIINUjlCzH29lzLus1sN4HJzLWBZtmUMY12r+v2XNtMeeYIIIAAAggggEApAqEGqVwVyxdszHadF/vR85uyZtl9TXNe93bWEUAAAQQQQACBUgVCC1LFBBhTxsy1MWa0ycx37dpVahspbwkMGDDAWmMRAQQQQAABBMoRCC1I5aqkHZjsZVO2vb3dWdQQpfvNutnPHAEEEEAAAQQQiFKgWxgXzxWS8l3XlDWhyQ5RZlQq37FsRwABBBBAAAEEwhQIJUjlapAJTLrPXrbXdbt+NFSZea5zsQ0BBBBAAAEEEIhCIPBbe+6QVKiRJjiZkSedm4+GqWPHjhU6nH0IIIAAAggggECoApGNSOVqpQlSus8EMDtImdt9uY5lGwIIIIAAAgggELZAJEHKhCRtrFk2cwNgApRu1+W2tjbnY/YzRwABBBBAAAEEohaIJEgVarQJTlpGl3UUSkOUmRc6ln0IIIAAAggggECYArEJUhqa9GMmHYUy67pMkDIyzBFAAAEEEEAgLgKRBikTlMzcRtFt9u09DVL6YUIAAQQQQAABBOIiEHqQyhWabAwNT2YyYUoDlG7XW3xMCCCAAAIIIIBAXAQCDVJdhaZ8CBqa9Fj7Y0an8h3DdgQQQAABBBBAIGyBQINUKY2xQ5cJUHq8WSZIlaJJWQQQQAABBBAIQyAWQcoOUXajzXYTpsy6XYZlBBBAAAEEEEAgKoFYBKl8jXcHKB2VYkIAAQQQQAABBOIiEHmQskeZ7GUDZLaZudnOHAEEEEAAAQQQiFogsiCVKxjpNvd2s43RqKj/VLg+AggggAACCLgFIgtS7oq4192BSvfn2uY+jnUEEEAAAQQQQCAsgVgGqXyBKd/2sLC4DgIIIIAAAgggYAvEMkhpBTU0EZzsrmIZAQQQQAABBOImUBO3CiWlPtu3b5fGxkbR+Z49e5y5Xfdhw4ZJXV2d6HzChAnO3N6flOXevXt3qurevXs7rbOCAAIIIIBAmgViH6TiNDK1e/duWbJkiROgdLnQpAHLhK0XX3xR+vfv7wSq6dOnO8uFjmUfAggggAACCCRDIPZBKg6Mhw8flkWLFsmKFSs8V8eEMA1iU6ZMkVmzZkltba3n83EgAggggAACCEQvQJDqog/09t2CBQtEw5RfkwYyPe/s2bOdUSq/zst5EEAAAQQQQCBcAYJUAW8NUOWMQhU4tRPMHn74YWd0SgNVUib3M1NJqTf1RAABBBBAIAgBglQOVR190hClo0ZBTxrU9HoaprjVF7Q250cAAQQQQMBfgdi+/sDdzDBfhRBWiDJtNLcPzTpzBBBAAAEEEEiGQCyCVJghqatuCTtEmfpomNIH2pkQQAABBBBAIDkCsQhSceHSMBPUM1HFtNG8WqGYspRBAAEEEEAAgegFCFKf9YF5LirqLtERMT+/IRh1e7g+AggggAAClSxAkPqsd59++ulYBBgNUVoXJgQQQAABBBCIvwBBKtNH+rLMlStXeuot/bad368E0Lp09eZ0T5XlIAQQQAABBBDwVYAgleHUZ5O8TvqW8nnz5snQoUO9niLnceXUKecJ2YgAAggggAACvgsQpDKk5b4vSn+YWMNUQ0ODbx1Ubp18qwgnQgABBBBAAIG8AqkPUvrDwn7cRtOXac6ZM8d5saYft/q0Tlo3JgQQQAABBBCIr0Dqg5TfIz9+3urbuHFjfP9yqBkCCCCAAAIISOqDVBCjPn7d6tuwYQN/oggggAACCCAQY4HUB6k9e/YE0j1+3OoLqm6BNJiTIoAAAgggkEKB1AepIEak7L+jcm71BV03u54sI4AAAggggEDpAqkPUqWTlX6EX7f6Sr8yRyCAAAIIIIBAkAIEqSB1XeeuqqpybWEVAQQQQAABBJIsUJPkyiel7nqLbuHChbzOICkdRj0RQAABBBAoUiD1QUrfSN7c3FwkV+nFVqxYIYsWLfL0O35+vy299NpzBAIIIIAAAggUEkh9kOrfv38gQUp/fFgDlAYpr5PWjQkBBBBAAAEE4iuQ+mek9EFwvye9lffAAw+UFaK0TmPHjvW7apwPAQQQQAABBHwUSH2QmjBhgo+c4oQnDVF+vLpgzJgxvtaNkyGAAAIIIICAvwKpv7WnI1J1dXVS7ssv/biVZ3et1imI0TL7GiwjgAACCCCAQHkCqR+RUr7zzjuvLEW/buXZlSi3Tva5WEYAAQQQQACBYAQIUhnX6dOne9bVh8n9upVnV6KcOtnnYRkBBBBAAAEEghMgSGVs9dtxDQ0NnpQXLFjg6dUGhS6mIYpv7BUSYh8CCCCAAALxECBIfdYPt912m/Tu3TvyXtE6XH/99ZHXgwoggAACCCCAQNcCBKnPjGpra2XOnDldiwVcQuugdWFCAAEEEEAAgfgLEKSsPtJXIXi9xWedxvOi3tLz+3UMnivDgQgggAACCCDQpQBBykWkI0JRhBkNcLNmzXLVhlUEEEAAAQQQiLNA6t8jlatzZs+eLfoQeWNjY67dvm/T4KbPaCVhamlpSUI1qSMCCCCAAAKhCMRiRKqqqiqUxhZ7EX1G6e677w7lNp/eztNr8VxUsb1DOQQQQAABBOIjkJgRqSjClt7mO//88+Xxxx8Xv0di9Nt5Ud1GjM+fHzVBAAEEEEAg2QKxGJGKM6HedvvhD3/o6+iUjkLpOaN4FivO1tQNAQQQQACBpAlUNTU1dWil6+vrfa97R4dz6k7nNdvsuS7r5/jx486nvb1d2tranE9ra6voR0eE9PfsBgwY0Ol8Ya7s3r1blixZIqtXry75t/n0t/P0Z1+iftlmlH5h9hXXQgABBBBAIAwBgpRHZf19vY0bN8qGDRtEA1Zzc3OnMw0dOtR5O/nYsWNlzJgxsfkBYoJUp25iBQEEEEAAgbIEEvOMVFmtDODgYcOGOeFIR5iYEEAAAQQQQCCdArF/RkofMo/iQfN0/jnQagQQQAABBBAoRSD2QaqUxlAWAQQQQAABBBAIUyC2QYqRqDD/DLgWAggggAACCHgRiGWQyncrL992Lw3nGAQQQAABBBBAoFyBWAapchvF8QgggAACCCCAQBgCkQWpfKNLpW4PA4lrIIAAAggggAACuQQiC1KmMnZwspfNfuYIIIAAAggggEBcBSIPUl3BaLgiYHWlxH4EEEAAAQQQiEIg1kHKHaDc61GAcU0EEEAAAQQQQMAIxCZIuUOSe71bt9hU1dgxRwABBBBAAIGUCwSaTtxhqFhr+zhdtteLPQflEEAAAQQQQACBoAUCDVK5Kt9VKHLvt9cZlcolyjYEEEAAAQQQiEog9CBlN9SEJDO39+myvd1edpdjHQEEEEAAAQQQiEIg0iDlbrAJSzo3y1pGR6Lc29zHso4AAggggAACCIQtEKsgZRrvDlG6Xbdxa88IMUcAAQQQQACBOAhEEqTsoGSW3XPFMcHJhCizHgc46oAAAggggAACCEQSpIphN6HJDlHV1dXFHEoZBBBAAAEEEEAgFIGaoK+iQaijo6Ooy5iyOnd/NFhpkNq/f78cPnxYWltbO33a2tpEP+3t7XL8+PHsNfXaha5faF9RlaYQAggggAACCKRWIPAglU/WhCbdb5ZNeDLhRtdNgDJzDVM9e/Z0wpEpp/uOHj0q3bt3d0KUhindZ/brNexlXc83FVsu3/FsRwABBBBAAIH0CIQSpExQysdq79dlnTQc6ciSzvVTU1PjrPfo0SM713JaXsOV7jcByoxIucOUlicoqQITAggggAACCPghEEqQyldRd4AyIcdsd4cpDUxmRErPqeW0jN7S0/Bk39bTdZ3MOZ2VHP90tT/HIWxCAAEEEEAAAQQcgdCClAlHhdxNGZ3rpHMNThqKdMRJQ48dfEyw0gBlhygtY4KU+3r28e59rCOAAAIIIIAAAqUIhBak8lXKhCd7v27TkSYNRzppYNIAZMKU2a9ldJ8JURqe3CHKBCczt6/DMgIIIIAAAgggUI5AqEEqV2jSytvbzbIJS7pfQ5AdpnSf2W+HKC1rwpQu61RsgCq23Kdn5V8EEEAAAQQQQEAk1CBVDLgGJJ002NiBSbfpiJS9TUekdJsJT+Z2nglFZl2PzTeZsvn2sx0BBBBAAAEEEMgnEHqQ0iCUK7xoKLKDj1nXuU4mQOmybtORKB2l0mP0o+e0z2ufS49xT3ZZ9z7WEUAAAQQQQACBYgRCD1KFKmVClj3X8u5QpSHIlDFBypy3UIAiPBkl5ggggAACCCDgh0AkQcqEoFwNMPt0biazbIKQmet+M2JlApTZZ+Zaxl7WdSYEEEAAAQQQQMAPgUiClFbcBCa7EWabmdvl3KNSuq4ByQQoE7bM+QhPRoI5AggggAACCAQlEFmQ0gbZgck00GzTuX40KJltJjyZkKTbzTY93mw358q3zd6faznXeXKVYxsCCCCAAAIIpFsg0iCl9CYk2d1gb7ODkimj+3XSwKMfe92UsecEI1uDZQQQQAABBBDwSyDyIKUNsYOTaZi9TZf1Y0anTBlzrFknMBkJ5ggggAACCCAQhkAsgpQ21A5OpuHubTo6pVO+56K0fL6JkJVPhu0IIIAAAggg4FUgNkFKG+AOTvm2mUCl++2AZC/rPnsqFLLsciwjgAACCCCAAALFCsQqSGmlTeCxQ5HZpvvt7XZ5s+zer9uZEEAAAQQQQACBIARiF6RMI014cgcjs92U07ldJtd+uyzLCCCAAAIIIICAXwL/D5zOVcA4hxl+AAAAAElFTkSuQmCC" }, "f082c596-74ed-47c2-9081-8faf2984ccb2.png": { "image/png": "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" } }, "cell_type": "markdown", "id": "7a2a51fe-6bb2-448c-a6e7-761ae97f1707", "metadata": {}, "source": [ "## Running Python code interactively\n", "\n", "Notebooks are an example of \"interactive\" use of the Python interpreter.\n", "You enter some commands `2+3` in a code cell,\n", "press SHIFT+ENTER to run the code,\n", "and you see the result.\n", "\n", "There are several different ways you can access the Python interpreter.\n", "\n", "- `python` shell.\n", " This is what you get in you install Python on your computer.\n", " You can open a command prompt (terminal or cmd.exe) and type in the\n", " command `python` to start the interactive Python shell.\n", "\n", " ```\n", " > python\n", " Python 3.6.9 (default, Oct 6 2019, 21:40:49)\n", " [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin\n", " Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n", " >>> 2+3\n", " 5\n", " >>> \n", " ```\n", "\n", "- `ipython` shell.\n", " This is a fancier shell with line numbering and\n", " many helpful commands.\n", " ```\n", " > ipython\n", " Python 3.6.9 (default, Oct 6 2019, 21:40:49)\n", " Type 'copyright', 'credits' or 'license' for more information\n", " IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help.\n", "\n", " In [1]: 2+3\n", " Out[1]: 5\n", "\n", " In [2]: \n", " ```\n", "\n", "- Jupyter notebooks are web-based coding environments that allow you\n", " to mix code cells and Markdown cells to create \"code documents.\"\n", " Notebook files have an extension `.ipynb` and can be created using JupyterLab.\n", " Several other systems like nbviewer, GitHub, VSCode, Google Colab,\n", " can also be used \"open\" notebooks for viewing and \"run\" the notebooks interactively. \n", " \"jupter-code-cell\"\n", "\n", "- Colab notebooks.\n", " Google operates a service called \"Google Colaboratory\" (Colab for short)\n", " that allows you to run Python code as Colab notebooks.\n", " \"colab\n", "\n", "Note the \"Python calculator\" functionality works the same way in each case.\n", "The basic Python shell, the fancy `ipython` shell, and the notebook interface\n", "all offer a place to input your commands,\n", "they READ your command input,\n", "EVALUATE them (i.e. run them),\n", "PRINT the output of the commands execution.\n", "At the end of the READ-EVAL-PRINT steps,\n", "the Python in interpreter goes back into \"listening mode\" \n", "waiting for your next command input.\n", "\n", "The overall behaviour of the Python interpreter is an example of the\n", "READ-EVAL-PRINT Loop (REPL) that appears in professional human-computer interfaces.\n", "The command line prompt (terminal on UNIX or `cmd.exe` on Windows),\n", "database prompts,\n", "the JavaScript console in your browser,\n", "the Ruby interactive console `irb`,\n", "and any other interface which accepts commands.\n", "\n", "Given this multitude of choices,\n", "we've opted to use a Jypyter notebook to present this tutorial.\n", "Keep in mind you could run all the code examples in python shell,\n", "or ipython shell, or as a Colab notebook.\n", "\n", "While we're on the topic of running Python code,\n", "let's briefly mention the other ways Python applications can operate.\n", "This is completely out of scope for the remainder of the discussion in this tutorial,\n", "since we're just using Python as a fancy calculator,\n", "but I though I'd mention some of the other uses of Python codes." ] }, { "cell_type": "code", "execution_count": 79, "id": "bdbe2f8d-86ec-49aa-ad6f-cfa95f598886", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
student_IDbackgroundcurriculumeffortscore
01artsNaN10.9675
12sciencelecture8.6975
\n", "
" ], "text/plain": [ " student_ID background curriculum effort score\n", "0 1 arts NaN 10.96 75\n", "1 2 science lecture 8.69 75" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import io\n", "import pandas as pd\n", "data2 = io.StringIO(\"\"\"\n", "student_ID,background,curriculum,effort,score\n", "1,arts,,10.96,75\n", "2,science,lecture,8.69,75\n", "\"\"\")\n", "df2 = pd.read_csv(data2)\n", "df2" ] }, { "cell_type": "code", "execution_count": null, "id": "0452679d-5635-4bd5-83f1-167eb1656e7d", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "7afc119c-9b62-4179-9f12-7421f7fe087f", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "1fce2a08-27ed-4841-ba6a-a9dfd6907c40", "metadata": {}, "source": [ "# Bonus topics\n", "\n", "- writing standalone scripts (`argparse`)\n", "- Reading and writing files https://python-textbok.readthedocs.io/en/1.0/Python_Basics.html#files\n", "\n", "\n", "\n", " \n", "\n" ] }, { "cell_type": "markdown", "id": "08428872-c78d-4ca8-a6f5-7e19af2082c0", "metadata": {}, "source": [ "# Bonus topics" ] }, { "cell_type": "markdown", "id": "0204704d-5e42-4374-8a28-bd5c33953e11", "metadata": {}, "source": [ "## Writing standalone scripts" ] }, { "cell_type": "markdown", "id": "9748c381-f8fa-4dd3-b716-61b475516464", "metadata": {}, "source": [ "## For loop tricks\n", "\n", "Tricks:\n", "- `enumerate`: provides an index when iterating through a list.\n", "- `zip`: allows you to iterate over multiple lists in parallel." ] }, { "cell_type": "markdown", "id": "7f0619a0-c968-482d-838e-a6d29f18e910", "metadata": {}, "source": [ "### Using `enumerate` to get `for`-loop with index\n", "\n", "Use `enumerate(somelist)` to iterate over tuples `(index, value)`,\n", "from a list of values from the list `somelist`.\n", "In each iteration, the `index` tells you the index of the `value`\n", "in the current iteration." ] }, { "cell_type": "code", "execution_count": 80, "id": "7e3ebd68-cfb6-414b-acde-b7037fd024c1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(0, 61), (1, 79), (2, 98), (3, 72)]" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "scores = [61, 79, 98, 72]\n", "list(enumerate(scores))" ] }, { "cell_type": "code", "execution_count": 81, "id": "a7b75752-b8fa-4af4-8014-54098b2d1fda", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processing score 61 which is at index 0 in the list\n", "Processing score 79 which is at index 1 in the list\n", "Processing score 98 which is at index 2 in the list\n", "Processing score 72 which is at index 3 in the list\n" ] } ], "source": [ "# example usage\n", "for idx, score in enumerate(scores):\n", " # this for loop has two variables index and score\n", " print(\"Processing score\", score, \"which is at index\", idx, \"in the list\")" ] }, { "cell_type": "code", "execution_count": null, "id": "758c00c7-4f28-4fd6-ad6b-2d5129f9533b", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "5ac76928-72fe-4b31-9c80-ad1909015758", "metadata": {}, "source": [ "### Using `zip`\n", "\n", "Use `zip(list1,list2)` to get an iterator over tuples `(value1, value2)`,\n", "where `value1` and `value2` are elements taken from `list1` and `list2`,\n", "in parallel, one at a time.\n", "\n", "The name \"zip\" is reference to the way a zipper joins together the teeth of the two sides of the zipper when it is closing." ] }, { "cell_type": "code", "execution_count": 82, "id": "9125138e-11d9-4eeb-b2de-e497631c5248", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(1, 'a'), (2, 'b'), (3, 'c')]" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# example 1\n", "list( zip([1,2,3], [\"a\",\"b\",\"c\"]) )" ] }, { "cell_type": "code", "execution_count": 83, "id": "41b17ebb-0293-4729-83ce-eb1e2081b210", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(1, 4), (2, 5), (3, 6)]" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# example 2\n", "list1 = [1, 2, 3]\n", "list2 = [4, 5, 6]\n", "\n", "list(zip(list1, list2))" ] }, { "cell_type": "code", "execution_count": 84, "id": "577cd7d4-9b76-43dd-a009-6bcbb4724333", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The sum of 1 and 4 is 5\n", "The sum of 2 and 5 is 7\n", "The sum of 3 and 6 is 9\n" ] } ], "source": [ "# compute the sum of the matching values in two lists\n", "for value1, value2 in zip(list1, list2):\n", " print(\"The sum of\", value1, \"and\", value2, \"is\", value1+value2)" ] }, { "cell_type": "code", "execution_count": null, "id": "592e71ca-cf23-481c-a088-314ae1b19019", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "8f5eacb3-d1f5-467c-ba1c-72cb36bde34c", "metadata": {}, "source": [ "## Functional programming helpers\n", "\n", "`functools.partial` for currying functions (e.g sample-generator callables)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "d1d6cf33-8cbf-495b-beb0-026a847c5926", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "36d2207f-096b-46bb-a23b-7e0d13b56638", "metadata": { "tags": [] }, "source": [ "## List-like objects = iterables\n", "\n", "The term \"iterable\" is used in Python to refer to any list-like object that can be used in a `for`-loop.\n", "\n", "Examples of iterables:\n", "- strings\n", "- dictionary keys, dictionary values, or dictionary (key,value) items\n", "- sets\n", "- `range` (lazy generator for lists of integers)\n", "\n", "" ] }, { "cell_type": "code", "execution_count": 85, "id": "7be7f905-7a52-4b5a-938c-0495f5239cc9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "range(0, 4)" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "range(0, 4)" ] }, { "cell_type": "code", "execution_count": 86, "id": "0479c0c2-25ae-4558-b485-e1bd795cf221", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3]" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(0, 4))" ] }, { "cell_type": "code", "execution_count": null, "id": "d50e1ef2-1de8-4d58-a2ae-584c44f4504f", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "15cc35e6-7dde-4ba6-b2f6-98f2ae3b2661", "metadata": {}, "source": [ "### Iterating over dictionaries\n", "\n" ] }, { "cell_type": "code", "execution_count": 87, "id": "dff8f341-4f31-49bd-b71d-40ee7bedded3", "metadata": {}, "outputs": [], "source": [ "profile = {\"first_name\":\"Julie\", \"last_name\":\"Tremblay\", \"score\":98}" ] }, { "cell_type": "code", "execution_count": 88, "id": "f80ef621-43f1-49fd-ba91-f5b47c9110fb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['first_name', 'last_name', 'score']" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(profile.keys())" ] }, { "cell_type": "code", "execution_count": 89, "id": "8d106630-f11e-4d59-a54e-c54124b2dc05", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['first_name', 'last_name', 'score']" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ALT.\n", "list(profile)" ] }, { "cell_type": "code", "execution_count": 90, "id": "1cdf1f32-75bb-43ad-97fb-fdfd8414f5a4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Julie', 'Tremblay', 98]" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(profile.values())" ] }, { "cell_type": "code", "execution_count": 91, "id": "cd683981-bf71-456a-8c26-96c46e33e088", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('first_name', 'Julie'), ('last_name', 'Tremblay'), ('score', 98)]" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(profile.items())" ] }, { "cell_type": "markdown", "id": "b205bc22-cdeb-4b5b-bea6-c7396f0197f0", "metadata": {}, "source": [ "We'll talk more about dictionaries [later on](#Dictionaries-and-other-data-structures)." ] }, { "cell_type": "code", "execution_count": null, "id": "09deaee6-7c3a-4ce7-bbf2-685a97948fd3", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "47f51643-1a02-4640-b883-821b6e49757b", "metadata": { "tags": [] }, "source": [ "### Converting iterables to lists\n", "\n", "Under the hood, Python uses all kinds of list-like data structures called iterables\".\n", "We don't need to talk about these or understand how they work—all you need to know is they are behave like lists.\n", "\n", "In the code examples above,\n", "we converted several fancy list-like data structures into ordinary lists,\n", "by wrapping them in a call to the function `list`,\n", "in order to display the results.\n", "\n", "Let's look at why need to use `list(iterable)` when printing,\n", "instead of just `iterable`." ] }, { "cell_type": "markdown", "id": "425cd4fd-2e22-4683-bebb-d5b01aeb1e13", "metadata": {}, "source": [ "For examples,\n", "the set of keys for a dictionary is a `dict_keys` iterable object:" ] }, { "cell_type": "code", "execution_count": 92, "id": "6fb2839d-ed3e-4506-8aa0-1ee9b16d3a9e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_keys(['first_name', 'last_name', 'score'])" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "profile.keys()" ] }, { "cell_type": "code", "execution_count": 93, "id": "d4441d9e-9017-4bd6-8d84-d574cea3bc1f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_keys" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(profile.keys())" ] }, { "cell_type": "markdown", "id": "b356d4db-eb27-441d-88df-c6e50dd3e3ab", "metadata": {}, "source": [ "I know, right? What the hell is `dict_keys`?\n", "I certainly don't want to have to explain that...\n", "\n", "\n", "... so instead, you'll see this in the code:" ] }, { "cell_type": "code", "execution_count": 94, "id": "0be25aa0-1e37-42e0-93bf-b5cd2211d27d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['first_name', 'last_name', 'score']" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(profile.keys())" ] }, { "cell_type": "code", "execution_count": 95, "id": "5e94f5c6-bb30-4155-8b2a-24ad36b3358f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(list(profile.keys()))" ] }, { "cell_type": "code", "execution_count": null, "id": "4baaab91-24ec-404d-932c-b5d114d30dc1", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "a563bc60-a41f-4812-b660-0c7fc3ea8f28", "metadata": {}, "source": [ "## Generic function arguments\n", "\n", "functions with `*args` and `**kwargs` arguments" ] }, { "cell_type": "code", "execution_count": null, "id": "979fa47e-d96a-4492-9527-bd4bebd8ca42", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "81543308-5dce-4dbf-b24f-3b7a085077d9", "metadata": {}, "source": [ "## Python programming\n", "\n", "Coding a.k.a. programming, software engineering, or software development is a broad topic,\n", "which is out of scope for this short tutorial.\n", "If you're interested to learn more about coding,\n", "see the article [What is code?](https://www.bloomberg.com/graphics/2015-paul-ford-what-is-code/) by Paul Ford.\n", "Think mobile apps, web apps, APIs, algorithms, CPUs, GPUs, SysOps, etc.\n", "There is a lot to learn about applications enabled by learning basic coding skills,\n", "it's almost like reading and writing skills.\n", "\n", "Learning programming usually takes several years,\n", "but you don't need to become a professional coder to start using Python for simple tasks,\n", "the same way you don't need to become a professional author to use writing for everyday tasks.\n", "If you reached this far in the tutorial,\n", "you know enough about basic Python to continue your journey.\n", "\n", "In particular, you can read the other two tutorials that appear in the **No Bullshit Guide to Statistics**:\n", "- Pandas (see [pandas_tutorial.ipynb](./pandas_tutorial.ipynb))\n", "- Seaborn (see [seaborn_tutorial.ipynb](./seaborn_tutorial.ipynb)) " ] }, { "cell_type": "code", "execution_count": null, "id": "5229d202-2b30-4e07-b04a-05288acd30d3", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "dc354d22-7cb2-40ae-882d-d00c584684cd", "metadata": { "tags": [] }, "source": [] }, { "cell_type": "code", "execution_count": null, "id": "aad5abc1-a911-4dcc-a947-99fb471a642e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "b453874d-f9d0-4bb3-9e59-6f9f159eb7ec", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "4ec99799-8905-4dda-8aae-ce7935af7859", "metadata": {}, "source": [ "**TODO** functions are verbs\n", "\n", "The In Python,\n", "we generally prefer to use more descriptive names (whole words)\n", "for function names and their inputs,\n", "as illustrated in the next example." ] }, { "cell_type": "code", "execution_count": null, "id": "5ffd1d05-5c37-48e5-80d0-df3cef7130c7", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "cbf0964e-eaf3-4fcd-b9dc-37ca824e8581", "metadata": {}, "source": [ "**Exercise 13**: Replace the `...`s in the following code cell\n", "with comments that explain the calculation\n", "\"adding 10\\% tax to a purchase that costs \\$57\"\n", "that is being computed." ] }, { "cell_type": "code", "execution_count": 96, "id": "afbd1a91-c20e-4cc7-bae2-649e6031f24a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "62.7" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cost = 57.00 # ...\n", "taxes = 0.10 * cost # ...\n", "total = cost + taxes # ...\n", "total # ..." ] }, { "cell_type": "code", "execution_count": 97, "id": "e8cfce23-07d8-4f0a-9e3f-d855d9c1d9c8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "62.7" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#@titlesolution Exercise 13 cost-plus-taxes-total\n", "cost = 57.00 # price before taxes\n", "taxes = 0.10 * cost # 10% taxes = 0.1 times the cost\n", "total = cost + taxes # add taxes to cost and store the result in total\n", "total # print the total" ] }, { "cell_type": "markdown", "id": "0f7d848a-fcb4-47d2-a9bf-e4c57060ceab", "metadata": {}, "source": [ "## Objects and classes\n", "\n", "All the Python variables we've been using until now are different kinds of \"objects.\"\n", "An object is a the most general purpose \"container\" for data,\n", "that also provides functions for manipulating this data in the object.\n", "\n", "In particular:\n", "- **attributes**: data properties of the object\n", "- **methods**: functions attached to the object" ] }, { "cell_type": "markdown", "id": "8d00428e-54c3-41f2-8ae7-abcee866808b", "metadata": {}, "source": [ "### Examples" ] }, { "cell_type": "markdown", "id": "938e362c-c364-4475-9020-083f0927f0e0", "metadata": {}, "source": [ "#### Example 1: string objects" ] }, { "cell_type": "code", "execution_count": 98, "id": "d2cdd96d-9295-4924-8f33-585b3d26cfb4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "msg = \"Hello world!\"\n", "\n", "type(msg)" ] }, { "cell_type": "code", "execution_count": 99, "id": "a0a52ab6-8600-4ccc-bc4d-5503050e90ff", "metadata": {}, "outputs": [], "source": [ "# Uncomment the next line and press TAB after the dot\n", "# msg." ] }, { "cell_type": "code", "execution_count": 100, "id": "ce3e6bab-9849-490a-a1f2-2022062107a4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Methods:\n", "msg.upper()\n", "msg.lower()\n", "msg.__len__()\n", "msg.isascii()\n", "msg.startswith(\"He\")\n", "msg.endswith(\"!\")" ] }, { "cell_type": "markdown", "id": "5e52d40f-8a54-4028-8063-82284927afa4", "metadata": {}, "source": [ "#### Example 2: file objects" ] }, { "cell_type": "code", "execution_count": 101, "id": "4aff500b-eee2-4bcc-8a6e-4181ef31a5ae", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "_io.TextIOWrapper" ] }, "execution_count": 101, "metadata": {}, "output_type": "execute_result" } ], "source": [ "filename = \"message.txt\"\n", "file = open(filename, \"w\")\n", "\n", "type(file)" ] }, { "cell_type": "code", "execution_count": 102, "id": "e9f5b9bc-04e5-4942-9fa9-f4c3d13bf33a", "metadata": {}, "outputs": [], "source": [ "# Uncomment the next line and press TAB after the dot\n", "# file." ] }, { "cell_type": "code", "execution_count": 103, "id": "f7d9d7d5-bae5-4d16-bb30-80685f07d188", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'UTF-8'" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Attributes:\n", "file.name\n", "file.mode\n", "file.encoding" ] }, { "cell_type": "code", "execution_count": 104, "id": "9efad2e1-9504-4f43-8c13-7c3c02458367", "metadata": {}, "outputs": [], "source": [ "# Methods:\n", "file.write(\"Hello world\\n\")\n", "file.writelines([\"line2\", \"and line3.\"])\n", "file.flush()\n", "file.close()" ] }, { "cell_type": "markdown", "id": "c0cb4cfa-6f2a-4b2b-8872-4b995952ed59", "metadata": {}, "source": [ "## DIscussion\n", "Let's go over some of the things we skipped in the tutorial,\n", "because they were not essential for getting started.\n", "Now that you know a little bit about Python,\n", "it's worth mentioning some of these details,\n", "since it's useful context to see how this \"Python calculator\" business works." ] }, { "cell_type": "code", "execution_count": null, "id": "3d3be415-16c6-4085-a6dc-11697c99402a", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "f68df993-9ede-48b1-ba80-569c8c581d39", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "f744c1e4-db13-4811-bf2b-7a9af5281c40", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "e9b197cd-369e-494b-94c0-c2b4188367fe", "metadata": {}, "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.4" } }, "nbformat": 4, "nbformat_minor": 5 }