diff --git a/Exercises/01-python/intro_to_python_Sol.ipynb b/Exercises/01-python/intro_to_python_Sol.ipynb new file mode 100644 index 0000000..eba5588 --- /dev/null +++ b/Exercises/01-python/intro_to_python_Sol.ipynb @@ -0,0 +1,1565 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction to Python - Solutions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "This notebook was developed for the CS-233 Introduction to Machine Learning course at EPFL, adapted for the CIVIL-226 Introduction to Machine Learning for Engineers course, and re-adapted for the ME-390. We thank contributers in CS-233 ([CVLab](https://www.epfl.ch/labs/cvlab)) and CIVIL-226 ([VITA](https://www.epfl.ch/labs/vita/)).\n", + " \n", + "**Author(s):** [Sena Kiciroglu](mailto:sena.kiciroglu@epfl.ch), minor changes by [Tom Winandy](mailto:tom.winandy@epfl.ch) and [David Mizrahi](mailto:david.mizrahi@epfl.ch)\n", + "
\n", + "\n", + "Welcome to the first exercise of Introduction to Machine Learning. Today we will get familiar with Python, the language we will use for all the exercises of this course. \n", + "\n", + "This week we will introduce some important concepts in the basics of Python. Next week, you will learn how to work with NumPy, a popular Python library used for scientific computing. \n", + "\n", + "Python is a popular language to use for machine learning tasks. This is especially true because of the selection of **libraries and frameworks**, developed specifically for machine learning and scientific computing. To name a few, you have Keras, TensorFlow and PyTorch for developing neural networks, SciPy and NumPy used for scientific computing, Pandas for data analysis, etc. (You might also get to dabble in PyTorch in the upcoming weeks.)\n", + "\n", + "Python also allows you to write quick, readable, high-level code. It's great for fast prototyping. \n", + "\n", + "You can find a useful Python cheatsheet at: https://www.pythoncheatsheet.org/\n", + "\n", + "Let's get into it!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Anaconda and Jupyter Notebook\n", + "\n", + "If you're reading this Jupyter notebook as it is intended, chances are you already installed Anaconda, a Python distribution that comes with its own package management system, `conda`. Using `conda`, you can install and upgrade software packages and libraries. It will make managing the versions of the libraries you use very convenient.\n", + "\n", + "In these exercises we will use Jupyter Notebooks, which contain Python code, text explanations and visuals. \n", + "\n", + "The Jupyter Notebook document (such as the one you are looking at right now) consists of cells containing Python code, text or other content. You can run each cell by clicking on the button `Run` in the top toolbar, or you can use a keyboard shortcut `Ctrl` + `Enter` (run current cell) or `Shift` + `Enter` (run current cell and move to the cell below)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Indentation and Control Flow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally we get to start doing some coding!\n", + "\n", + "First thing to know: Python does not separate different lines of code with a semicolon `;`. So just RUN the following cell with no worries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This is a Python comment. Start the line with `#` for a comment\n", + "print(\"First line of code. I will declare some variables\")\n", + "a = 1 # second line!!\n", + "b = 2\n", + "c = \"Fish\"\n", + "print(f\"My variables are: a = {a}, b = {b}, c = {c}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Easy! However, in Python you have to be careful and have perfect indentation (a reason why Python code is so readable). The reason is, Python uses indentation to keep track of what is part of the if statement, the loops and the functions. This is different from Java (this is assuming you know Java) where you would have curly brackets `{ }` for this purpose. \n", + "\n", + "Let's start with the if statement.\n", + "\n", + "### 2.1. If Statement\n", + "\n", + "The rule is, all indented parts after the `if condition :` belong to that branch of the if statement. \n", + "\n", + "```python\n", + "if condition :\n", + " inside the statement\n", + " still inside the statement\n", + "elif condition:\n", + " inside the else-if part of the statement\n", + "else:\n", + " inside the else part of the statement\n", + "outside the statement\n", + " ```\n", + " \n", + "Let's see it in action:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if a + b == 3:\n", + " print(\"It's me again! We are inside the first if statement\")\n", + " print(\"It's optional to use parentheses for the condition a + b ==3\")\n", + " print(\"Don't forget to put a `:` at the end of the condition!!\")\n", + " if (c == \"Fish\"):\n", + " print(\"This is a second if statement inside the first one\")\n", + " print(\"I'm out of the second if statement, but still inside the first one\")\n", + "else:\n", + " print(\"This is the else part of the first if statement.\")\n", + " print(\"These lines will never be printed!\")\n", + "print(\"I'm not inside any of the if statements\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise\n", + "\n", + "Let's see another if statement example. Try to figure out what the output will be **BEFORE** running the cell below.\n", + "\n", + "Reminder, we declared\n", + "\n", + "```python\n", + "a = 1\n", + "b = 2\n", + "c = \"Fish\"\n", + " ```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Don't run me until you find the output first!\n", + "if a == 5:\n", + " print (\"1\")\n", + " if b == 1:\n", + " print(\"2\")\n", + "# here comes an else-if \n", + "elif a == 2 or c == \"Fish\":\n", + " print(\"3\")\n", + " \n", + " if b == 1:\n", + " print(\"4\")\n", + " if b == 2:\n", + " print(\"5\")\n", + " if b == 2:\n", + " print(\"6\")\n", + " if c == \"Fish\":\n", + " if a == 1:\n", + " if b == 100:\n", + " print(\"7\")\n", + " else:\n", + " print(\"8\")\n", + " elif a == 1:\n", + " print(\"9\")\n", + "print (\"10\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.3. Loops\n", + "\n", + "Let's talk about loops. The syntax for a while-loop is:\n", + "\n", + "```python\n", + "while condition:\n", + " inside the loop\n", + " inside the loop\n", + " inside the loop\n", + "outside the loop\n", + " ```\n", + " \n", + " A small example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "count = 0\n", + "while count < 3:\n", + " count += 1 # this is the same as count = count +1\n", + " print(f\"Count is {count}\")\n", + "print(\"Left the loop!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For-loops iterate through sequences, in this way:\n", + "\n", + "```python\n", + "for x in sequence:\n", + " inside the loop\n", + " inside the loop\n", + " inside the loop\n", + "outside the loop\n", + "```\n", + " \n", + " An example is shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Here is a basic list of strings\n", + "fish_list = [\"salmon\", \"trout\", \"parrot\", \"clown\", \"dory\"]\n", + "\n", + "#The for-loop:\n", + "for fish in fish_list:\n", + " print(fish)\n", + " print(\"*\")\n", + "print(\"fish list over!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An incredibly useful built-in function to use in for-loops is `range()`. Range allows you to create a sequence of integers from the start (default is 0), to the stop, with a given step size (default is 1). We can use `range()` in for-loops as shown in the example below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# \"default start is 0, default step size is 1\"\n", + "for number in range(7):\n", + " print (number)\n", + "print(\"**\")\n", + "\n", + "# now we also provide the start as 2.\n", + "# Default step size 1 is still used.\n", + "for number in range(2,7):\n", + " print(number)\n", + "print(\"**\")\n", + "\n", + "# now we also provide the step size as 2.\n", + "for number in range(2,7,2):\n", + " print(number)\n", + "print(\"**\") \n", + "\n", + "# what happens if step size is -1?\n", + "for number in range(6,-1,-1):\n", + " print(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One more useful built-in function will be `enumerate()`. Let's go back to the fish list.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for fish in fish_list:\n", + " print(fish)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What if I also want to keep track of the index of the list element? You can use `enumerate()` which creates a sequence of 2-tuples, where each tuple contains an integer index and an actual element of the original list. Here is how it looks like:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for item_index, fish in enumerate(fish_list):\n", + " print(f\"{item_index}: {fish}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Data Types and Basic Operations\n", + "\n", + "Python is a **dynamically typed** language. This means that the data type is inferred at run-time and can be changed during run-time. To check the type of a variable you can use the function `type()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# var_1 is first defined as an integer\n", + "var_1 = 1\n", + "print(f\"{var_1} is {type(var_1)}\")\n", + "\n", + "# var_1's type is changed to string\n", + "var_1 = \"hi!\"\n", + "print(f\"{var_1} is {type(var_1)}\")\n", + "\n", + "# more types\n", + "var_1 = 0.312\n", + "print(f\"{var_1} is {type(var_1)}\")\n", + "var_1 = 3.\n", + "print(f\"{var_1} is {type(var_1)}\")\n", + "var_1 = 3+2j\n", + "print(f\"{var_1} is {type(var_1)}\")\n", + "var_1 = True\n", + "print(f\"{var_1} is {type(var_1)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.1. Type Casting\n", + "\n", + "Some examples of type casting in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# From int to float\n", + "var_1 = 42\n", + "print(f\"{var_1} is {type(var_1)}\")\n", + "var_1 = float(var_1)\n", + "print(f\"{var_1} is {type(var_1)}\")\n", + "print (\"**\")\n", + "\n", + "# From float to int\n", + "var_2 = 3.14\n", + "print(f\"{var_2} is {type(var_2)}\")\n", + "var_2 = int(var_2)\n", + "# This operations does FLOOR, not round!\n", + "print(f\"{var_2} is {type(var_2)}\")\n", + "print (\"**\")\n", + "\n", + "# From string to int\n", + "var_3 = \"100\"\n", + "print(f\"{var_3} is {type(var_3)}\")\n", + "var_3 = int(var_3)\n", + "print(f\"{var_3} is {type(var_3)}\")\n", + "print(\"**\")\n", + "\n", + "# From float to string\n", + "var_4 = 1.23\n", + "print(f\"{var_4} is {type(var_4)}\")\n", + "var_4 = str(var_4)\n", + "print(f\"{var_4} is {type(var_4)}\")\n", + "print(\"**\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2. Basic Operations\n", + "\n", + "Arithmetic operations are fairly standard. There are some examples below. \n", + "* Look out for the difference between `/` division and `//` integer division.\n", + "* `**` is used for power.\n", + "* `%` is modulo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 50\n", + "b = 7\n", + "\n", + "print(f\"a + b = {a + b}\")\n", + "print(f\"a - b = {a - b}\")\n", + "print(f\"a * b = {a * b}\")\n", + "print(f\"a / b = {a / b}\")\n", + "print(f\"a // b = {a // b}\") # integer divison\n", + "print(f\"a ** b = {a ** b}\") # power\n", + "print(f\"a % b = {a % b}\") # modulo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Boolean operations are also fairly standard:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"(True and False) = {True and False}\")\n", + "print(f\"(True or False) = {True or False}\")\n", + "print(f\"((True and False) or True) = {(True and False) or True}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can declare strings with a single quote `'`, a double quote `\"` or a three double quotes `\"\"\"`. The string declared with `\"\"\"` is known as a *docstring*, it can span multiple lines and is usually used to comment functions and classes.\n", + "\n", + "**Note:** Throughout the exercises, we will be using f-strings to format our strings nicely. You can learn more about them [here](https://realpython.com/python-f-strings/)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 'Life\\'s but a walking shadow, a poor player,' \n", + "print(a)\n", + "a = \"That struts and frets his hour upon the stage,\"\n", + "print(a)\n", + "a = \"\"\"And then is heard no more. It is a tale\n", + "Told by an idiot, full of sound and fury,\n", + "Signifying nothing.\"\"\"\n", + "print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The types of quotes do not change anything!\n", + "a = \"fish\" # double quote\n", + "b = 'fish' # single quote\n", + "print(a == b) # the string is the same!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Lists\n", + "\n", + "Lists are data types containing a sequence of values. The size of the list can change during run-time, as you add and remove elements from the list. \n", + "\n", + "Here is how you can create lists:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_a = [] # empty\n", + "print(f\"list_a {list_a}\")\n", + "\n", + "list_b = [1, 2, 3, 4] # 4 elements\n", + "print(f\"list_b {list_b}\")\n", + "\n", + "list_c = [1, 'cat', 0.23] # mixed types\n", + "print(f\"list_c {list_c}\")\n", + "\n", + "list_d = [1, ['cat', 'dog'], 2, 3] # list in list\n", + "print(f\"list_d {list_d}\")\n", + "\n", + "list_e = [1] * 10 # a list of 1s of length 10\n", + "print(f\"list_e {list_e}\")\n", + "\n", + "list_f = list(range(5)) # turns range object into a list\n", + "print(f\"list_f {list_f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below we introduce some common operations with lists.\n", + "* Use `len(list1)` to find the length of the list.\n", + "* `list1.append(element)` to add an element to the end of the list.\n", + "* `list1.insert(index, element)` to add an element to an index in the list\n", + "* `list1.extend(list2)` to extend the elements of list1 with the elements of list2\n", + "* `list1.pop()` removes last element from the list\n", + "* `list1.pop(index)` removes the element at the given index\n", + "* `list1.remove(element)` removes the first instance of the given element" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Some common operations\n", + "b = [\"great\", \"minds\", \"think\", \"alike\"]\n", + "print(f\"b: {b}\")\n", + "\n", + "# finding the length\n", + "print(f\"length of b is {len(b)}\")\n", + "\n", + "# append element to list\n", + "b.append(\"sometimes\")\n", + "print(f\"b.append(\\\"sometimes\\\")= {b}\")\n", + "\n", + "# extend list\n", + "c = [\"-\", \"Abraham\", \"Lincoln\"]\n", + "b.extend(c)\n", + "print(f\"c: {c}\")\n", + "print(f\"b.extend(c) = {b}\")\n", + "\n", + "# removes element and specific index\n", + "b.pop(6) \n", + "print(f\"b.pop(6) = {b}\")\n", + "\n", + "# remove specific element\n", + "b.remove(\"Lincoln\") \n", + "b.remove(\"-\")\n", + "print(f\"b.remove(\\\"Lincoln\\\"); b.remove(\\\"-\\\") = {b}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also check whether an element is in a list in the following way:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_1 = [\"a\", \"b\", \"c\"]\n", + "if \"b\" in list_1:\n", + " print(\"\\\"b\\\" is in list\")\n", + "else:\n", + " print(\"\\\"b\\\" is not in list\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.1. List Indexing and Slicing:\n", + "\n", + "You can extract a single element from a list in the following way:\n", + "`list1[index]`\n", + "\n", + "In lists, the indices start from 0. You can also index elements from the end of the list to the beginning by $-1, -2, -3...$. Check out the image below for the example list:\n", + "\n", + "`list_1 = [\"a\", \"b\", \"c\", \"d\", \"e\"]`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* You can extract multiple elements by slicing. This will give you elements from the start up to **(but not including)** the end index.\n", + "\n", + " `list1[start_index:end_index]`\n", + "\n", + "\n", + "* If you do not specify the `start_index`, you will retrieve the elements from index $0$ up to the `end_index`.\n", + "\n", + " `list1[:end_index]` is the same as `list1[0:end_index]`\n", + "\n", + "\n", + "* If you do not specify the `end_index`, you will retrieve the elements from the `start_index` up to (and **including**) the end of the list.\n", + "\n", + " `list1[start_index:]`\n", + "\n", + "\n", + "* You can provide a step size.\n", + " `list1[start_index:end_index:step_size]`\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise\n", + "\n", + "Try to write the output of the following code **BEFORE** running the cell." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Don't run BEFORE you solve it!\n", + "list_1 = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", + "\n", + "print(f\"list_1[-3] = {list_1[-3]}\")\n", + "print(f\"list_1[0:2] = {list_1[0:2]}\")\n", + "print(f\"list_1[:4:2] = {list_1[:4:2]}\")\n", + "print(f\"list_1[::-1] = {list_1[::-1]}\")\n", + "print(f\"list_1[-4:-1] = {list_1[-4:-1]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also assign new values to indices using slicing. Here is an example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_1 = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", + "\n", + "list_1[-1]= \"<3\"\n", + "print(list_1)\n", + "\n", + "list_1[0:2] = [\"x\", \"y\"]\n", + "print(list_1)\n", + "\n", + "list_1[::2] = [\":)\",\":(\", \":O\"]\n", + "print(list_1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2. Copying\n", + "\n", + "We have one last thing to say about lists. Observe the behaviour of the following code:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Case 1:\n", + "\n", + "list_1 = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", + "print(f\"list_1 before {list_1}\")\n", + "\n", + "list_2 = list_1\n", + "list_2.append(\"Z\")\n", + "\n", + "print(f\"list_1 after {list_1}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Case 2:\n", + "\n", + "list_1 = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", + "print(f\"list_1 before function {list_1}\")\n", + "\n", + "def function_that_changes_list(input_list):\n", + " input_list.append(\"Z\")\n", + "\n", + "function_that_changes_list(list_1)\n", + "\n", + "print(f\"list_1 after function {list_1}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We never changed list_1 explicitly, but the values changed anyway. What's going on?\n", + "\n", + "Well, in Python, when you say `list_2 = list_1`, you are not actually creating a new list, you are only copying the **reference** to the same list. This means that they are actually two variables pointing to the same list! So when you change the values of `list_2`, the values of `list_1` also change (since they are referring to the same list). Something similar is at play when you pass this list to a function. So be careful!\n", + "\n", + "If you do not want this to happen, you can use the function `.copy()` to create a new object with the same values. \n", + "\n", + "#### Exercise\n", + "\n", + "Change the code below and fix the two cases given above using the `.copy()` function. Make sure the contents of `list_1` do not change." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Case 1\n", + "list_1 = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", + "print(f\"list_1 before {list_1}\")\n", + "\n", + "list_2 = list_1.copy()\n", + "list_2.append(\"Z\")\n", + "\n", + "print(f\"list_1 after {list_1}\")\n", + "print(\"**\")\n", + "\n", + "# Case 2\n", + "list_1 = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", + "print(f\"list_1 before function {list_1}\")\n", + "\n", + "def function_that_changes_list(input_list):\n", + " input_list.append(\"Z\")\n", + "\n", + "list_2 = list_1.copy()\n", + "function_that_changes_list(list_2)\n", + "\n", + "print(f\"list_1 after function {list_1}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise\n", + "\n", + "Now that we know how lists work, here is a quick exercise for you. Fill in the function below that takes a list and returns True if it is a palindrome, False if it is not. Palindromes are defined as sequences that read the same forwards and backwards.\n", + "Examples of palindrome lists:\n", + "* [\"cat\", \"dog\", \"fish\", \"dog\", \"cat\"]\n", + "* [0, 1, 2, 3, 3, 2, 1, 0]\n", + "* [1]\n", + "* []\n", + "\n", + "You may use a for-loop in this exercise. However, if you're feeling ambitious try to do it in 1 line, without using a for-loop (hint: use slicing)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# with for-loop\n", + "def function_is_palindrome(input_list):\n", + " is_palindrome = True\n", + " \n", + " # Your code here\n", + " len_of_list = len(input_list) // 2\n", + " for element in range(len_of_list):\n", + " if input_list[element] != input_list[-element-1]:\n", + " is_palindrome = False\n", + " return is_palindrome" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# without for-loop\n", + "def function_is_palindrome(input_list):\n", + " return input_list == input_list[::-1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "test_list_1 = [\"cat\", \"dog\", \"fish\", \"dog\", \"cat\"]\n", + "res_1 = function_is_palindrome(test_list_1)\n", + "\n", + "test_list_2 = [\"cat\", \"dog\", \"fish\", \"bird\", \"dog\", \"cat\"]\n", + "res_2 = function_is_palindrome(test_list_2)\n", + "\n", + "test_list_3 = [\"cat\"]\n", + "res_3 = function_is_palindrome(test_list_3)\n", + "\n", + "test_list_4 = [\"cat\", \"cat\"]\n", + "res_4 = function_is_palindrome(test_list_4)\n", + "\n", + "if not (res_1 and not res_2 and res_3 and res_4):\n", + " print(\"Test failed\")\n", + "else:\n", + " print(\"Correct! :)\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Tuples\n", + "\n", + "Tuples are similar to lists but they are fixed in size and **immutable**, which means that change is not allowed.\n", + "We declare tuples in the following way using parentheses`()`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tuple_1 = (\"wash\", \"your\", \"hands\", \"with\", \"soap\")\n", + "\n", + "print(f\"tuple_1 = {tuple_1}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since change is not allowed, observe the result of the following piece of code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tuple_1[2] = (\"face\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can typecast from list to tuple and vice versa! " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sequence_1 = [\"here\", \"comes\", \"the\", \"sun\"]\n", + "print(f\"{sequence_1} is {type(sequence_1)}\")\n", + "\n", + "\n", + "# from list to tuple\n", + "sequence_1 = tuple(sequence_1)\n", + "print(f\"{sequence_1} is {type(sequence_1)}\")\n", + "\n", + "#from tuple to list\n", + "sequence_1 = list(sequence_1)\n", + "print(f\"{sequence_1} is {type(sequence_1)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Dictionaries\n", + "\n", + "An incredibly useful data type to know, you might also know dictionaries as \"hash maps\". Dictionaries are collections of \"key: value\" pairs. You can access the values using the keys in $O(1)$ time.\n", + "\n", + "The keys of a dictionary must be **immutable** and **unique**. Below we show how to define a dictionary.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "shopping_list = {\"apples\": 3, \"pears\":2, \"eggs\":6, \"bread\":1, \"yogurt\":1}\n", + "print(f\"shopping_list = {shopping_list}\")\n", + "print(\"**\")\n", + "\n", + "\n", + "book_dict = {}\n", + "print(f\"book_dict = {book_dict}\")\n", + "#add key value pairs\n", + "book_dict[\"vonnegut\"] = \"cat\\'s cradle\"\n", + "book_dict[\"ishiguro\"] = \"never let me go\"\n", + "print(f\"book_dict = {book_dict}\")\n", + "print(\"**\")\n", + "\n", + "# we can retrieve the dict keys:\n", + "print(book_dict.keys())\n", + "# and the dict values:\n", + "print(book_dict.values())\n", + "print(\"**\")\n", + "\n", + "#we can also iterate through the dict keys and values with a for-loop\n", + "for key, value in book_dict.items():\n", + " print(f\"{key} : {value}\")\n", + "\n", + "print(\"**\")\n", + "#we can modify the value of a key\n", + "book_dict[\"ishiguro\"] = \"a pale view of hills\"\n", + "print(f\"modified book_dict = {book_dict}\")\n", + "print(\"**\")\n", + "\n", + "#and we can remove a key completely\n", + "removed_value = book_dict.pop(\"ishiguro\")\n", + "print(f\"book_dict with removed value = {book_dict}\")\n", + "print(f\"removed_value = {removed_value}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Functions\n", + "\n", + "You can define a function in Python in the following way:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def multiply(a, b):\n", + " return a * b\n", + "\n", + "print(f\"multiply(100, 2) = {multiply(100, 2)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can have default arguments by specifying their default value in the parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add(a, b, c=0, d=1):\n", + " return a + b + c + d\n", + "\n", + "# use no default arguments\n", + "print(f\"add(1, 2, 100, 1000) = {add(1, 2, 100, 1000)}\")\n", + "\n", + "# use the default value of d\n", + "print(f\"add(1, 2, 100) = {add(1, 2, 100)}\")\n", + "\n", + "# use the default value of c and d\n", + "print(f\"add(1, 2) = {add(1, 2)}\")\n", + "\n", + "# use the default value of c\n", + "print(f\"add(1, 2, d=1000) = {add(1, 2, d=1000)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A function can return multiple values in a tuple. You can assign the values of the tuple to separate variables. This is called **tuple unpacking**." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def min_max(input_list):\n", + " return min(input_list), max(input_list)\n", + "\n", + "\n", + "test_list = [1,2,3,4]\n", + "min_val, max_val = min_max(test_list)\n", + "print(f\"min_val: {min_val}, max_val: {max_val}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: You have seen tuple unpacking when using function `enumerate` in for-loop." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.1. Common Built-in Functions\n", + "\n", + "Here we introduce some nifty commonly used built-in functions. \n", + "\n", + "* You already learned `range()`, `enumerate()`!\n", + "* We have also seen `type()` to return the type of the object. We use `str()`, `int()`, `float()`, `list()`, `tuple()` for typecasting.\n", + "* The functions `len()`, `sum()`, `min()`, `max()`, `any()`, `all()`, `sorted()`, `zip()` are useful for lists and tuples.\n", + "\n", + "Let's see them in action below" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_1 = list(range(5))\n", + "print(f\"list_1 = {list_1}\")\n", + "\n", + "print(f\"len(list_1) = {len(list_1)}\")\n", + "print(f\"sum(list_1) = {sum(list_1)}\")\n", + "print(f\"min(list_1) = {min(list_1)}\")\n", + "print(f\"max(list_1) = {max(list_1)}\")\n", + "print(\"**\")\n", + "\n", + "\n", + "list_2 = [5,3,1,2,0,6]\n", + "print(f\"list_2 = {list_2}\")\n", + "print(f\"sorted(list_2) = {sorted(list_2)}\")\n", + "print(\"**\")\n", + "\n", + "\n", + "# any checks whether there are any 1s in the list (OR)\n", + "# all checks whether all elements are 1s. (AND)\n", + "# in Python: 1 = True, 0 = False\n", + "list_3 = [1, 1, 1]\n", + "print(f\"list_3 = {list_3}\")\n", + "print(f\"any(list_3) = {any(list_3)}\")\n", + "print(f\"all(list_3) = {all(list_3)}\")\n", + "\n", + "list_4 = [0, 1, 1]\n", + "print(f\"list_4 = {list_4}\")\n", + "print(f\"any(list_4) = {any(list_4)}\")\n", + "print(f\"all(list_4) = {all(list_4)}\")\n", + "\n", + "list_5 = [0, 0, 0]\n", + "print(f\"list_5 = {list_5}\")\n", + "print(f\"any(list_5) = {any(list_5)}\")\n", + "print(f\"all(list_5) = {all(list_5)}\")\n", + "print(\"**\")\n", + "\n", + "# zip function:\n", + "x = [1,2,3]\n", + "y = [4,5,6]\n", + "zipped = zip(x,y)\n", + "print(f\"x {x}\")\n", + "print(f\"y {y}\")\n", + "print(f\"zipped {list(zipped)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.2. List Comprehensions\n", + "\n", + "One of the most practical things about Python is that you can do many things on just a single line. One popular example is so called *list comprehensions*, a specific syntax to create and initalize lists of objects. Here are some examples.\n", + "\n", + "A syntax for list comprehension is shown below:\n", + "`[thing for thing in list]`\n", + "\n", + "Let's make it more concrete with an example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_of_numbers = [1, 2, 3, 101, 102, 103]\n", + "print(f\"list_of_numbers = {list_of_numbers}\")\n", + "\n", + "#I want to create a new list with all these items doubled.\n", + "doubled_list = [2 * elem for elem in list_of_numbers]\n", + "print(f\"doubled_list = {doubled_list}\")\n", + "\n", + "#A new list with all these items as floats\n", + "float_list = [float(elem) for elem in list_of_numbers]\n", + "print(f\"float_list = {float_list}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's make it more interesting by adding an if in there:\n", + "\n", + "`[thing for thing in list if condition]`\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#I want to create a new list with all these items doubled\n", + "#IF the element is above 100\n", + "conditional_doubled_list = [2 * elem for elem in list_of_numbers if elem > 100]\n", + "print(f\"conditional_doubled_list = {conditional_doubled_list}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise\n", + "\n", + "You will be given a list of vocabulary words. Your task is to use list comprehensions to iterate through a document and create a new list including the words that are included in the vocabulary. You don't need to worry about duplicates.\n", + "\n", + "Example: \n", + "```python\n", + "vocabulary = [\"a\" \"c\", \"e\"]\n", + "document = [\"a\", \"b\", \"c\", \"d\"]\n", + "new_list = [\"a\", \"c\"]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vocabulary = ['epfl', 'europe', 'swiss', 'switzerland', 'best', 'education', 'high', 'higher', 'research', 'school', 'science', 'students', 'technology', 'top-tier', 'university']\n", + "\n", + "document = \"\"\"The École polytechnique fédérale de Lausanne (EPFL) is a research institute\n", + "and university in Lausanne, Switzerland, that specializes in natural sciences and engineering.\n", + "It is one of the two Swiss Federal Institutes of Technology, and it has three main missions: \n", + "education, research and technology transfer at the highest international level. EPFL is widely regarded \n", + "as a world leading university. The QS World University Rankings ranks EPFL 12th in the world \n", + "across all fields in their 2017/2018 ranking, whilst Times Higher Education World \n", + "University Rankings ranks EPFL as the world's 11th best school for Engineering and Technology.\"\"\"\n", + "document_parsed = document.split()\n", + "document_parsed = [word.lower() for word in document_parsed]\n", + "new_list = []\n", + "\n", + "# Your code here\n", + "new_list = [word for word in document_parsed if (word in vocabulary)]\n", + "\n", + "# We convert the list to a set and then back to a list. We do this because converting it to a set automatically\n", + "# removes duplicates (since sets are sequences that do not contain duplicates). afterwards we sort it.\n", + "new_list = sorted(list(set(new_list)))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "correct_result = ['best', 'education', 'epfl', 'higher', 'research', 'school', 'swiss', 'technology', 'university']\n", + "\n", + "if new_list == correct_result:\n", + " print (\"Correct! :)\")\n", + "else:\n", + " print (\"Incorrect :(\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. (optional now - useful later on) Object-Oriented Programming" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Object-oriented programming is a programming paradigm that provides a means of structuring programs so that properties and behaviors are bundled into individual objects.\n", + "\n", + "For this end, we use classes. Classes are used to create user-defined data structures. Classes define functions called methods, which identify the behaviors and actions that an object created from the class can perform with its data." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All class definitions start with the class keyword, which is followed by the name of the class and a colon. Any code that is indented below the class definition is considered part of the class’s body. To start, let's declare an `EPFL_faculty` class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class EPFL_faculty:\n", + "\n", + " def __init__(self, name, number_of_students):\n", + " self.name = name\n", + " self.number_of_students = number_of_students\n", + "\n", + " # Instance method\n", + " def description(self):\n", + " return f\"The faculty {self.name} has {self.number_of_students} students\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While the class is the blueprint, an instance is an object that is built from a class and contains real data. `.__init__()` sets the initial state of the object by assigning the values of the object’s properties. That is, `.__init__()` initializes each new instance of the class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sti = EPFL_faculty(\"STI\", 1000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the instance `sti` has been created, we can call the method description." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# sti.description()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Inheritance is the process by which one class takes on the attributes and methods of another. Newly formed classes are called child classes, and the classes that child classes are derived from are called parent classes. Child classes inherit from the parent's attributs and methods but it can overwrite methods. Let's define a class `EPFL_section` that inherits from `EPFL_faculty` and that overwrites the method `description(self)`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class EPFL_section(EPFL_faculty):\n", + " \n", + " def description(self):\n", + " return f\"The section {self.name} has {self.number_of_students} students\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "genie_mecanique = EPFL_section(\"GM\", 200)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "genie_mecanique.description()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Disclaimer__: This part of the tutorial and its text was inspired by and taken from \"Object-Oriented Programming (OOP) in Python 3\" by David Amos. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Additional OOP resources" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For further information on object-oriented programming and classes in Python, here are two useful resources:\n", + "* Object-Oriented Programming (OOP) in Python 3: https://realpython.com/python3-object-oriented-programming/\n", + "* Classes from the official Python Tutorial: https://docs.python.org/3/tutorial/classes.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. (optional now, useful later on) Matplotlib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perhaps the most widely used plotting library in Python is Matplotlib. If you've ever used MATLAB, you'll find that the functions look pretty similar. \n", + "\n", + "In the following exercise sessions, we won't ask you to do any plotting. So this part is optional for those who are interested in having a short introduction.\n", + "\n", + "First, we will import Matplotlib." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Importing in Python\n", + "\n", + "* A short note on importing: to be able to use modules in our code, we import them. \n", + " \n", + " example: `import numpy`\n", + " \n", + "\n", + "* We can also select a name for the imported module.\n", + " \n", + " example: `import numpy as np`. Now when we call numpy functions, we will always use `np.` as a prefix, i.e. `np.zeros()`\n", + " \n", + "\n", + "* You can also choose to only import selected functions/variables/classes from the module. \n", + " \n", + " example: `from numpy import arange`. Now you can use this function as `arange(5)`. You cannot use any other functions from the numpy module as you did not import them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# To import Matplotlib we do:\n", + "\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's do some plotting! \n", + "\n", + "Let's start with the simplest of plots, the good old line-plot. The function we will use is `plot()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Let's create some data first to plot\n", + "x = list(range(10))\n", + "y = [2,3,5,1,0,2,3,0,0,1]\n", + "\n", + "#first create a figure\n", + "fig = plt.figure()\n", + "\n", + "#now do the plotting\n", + "#specifying a color and marker are optional.\n", + "#check out the documentation to see what else you can do with the plot function\n", + "plt.plot(x, y, marker=\"*\", color=\"r\")\n", + "\n", + "#axis labels and title\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "plt.title(\"just a random plot\")\n", + "\n", + "#so that we see the plot\n", + "plt.show()\n", + "\n", + "#close the plot\n", + "plt.close(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise\n", + "\n", + "You can plot two lines on top of one another by calling the `plt.plot()` function consecutively. Try to implement this! Also, specify the parameter `label` of the `plt.plot()` function and call the function `plt.legend()` to create a legend for your graph. It should look like the figure shown below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![result](images/two_lines_plot.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Let's create some data first to plot\n", + "x = list(range(10))\n", + "y1 = [2,3,5,1,0,2,3,0,0,1]\n", + "y2 = [1,2,3,5,1,0,2,3,0,0]\n", + "\n", + "#your code here\n", + "#first create a figure\n", + "fig = plt.figure()\n", + "\n", + "#now do the plotting\n", + "#let's add labels for the legend\n", + "p1 = plt.plot(x, y1, marker=\"*\", color=\"r\", label=\"red line\")\n", + "p2 = plt.plot(x, y2, marker=\"^\", color=\"b\", label=\"green line\")\n", + "plt.legend()\n", + "\n", + "#axis labels and title\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "plt.title(\"just a random plot\")\n", + "\n", + "#so that we see the plot\n", + "plt.show()\n", + "#close the plot\n", + "plt.close(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can create scatter plots (line plots without lines) with `scatter()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Let's create some data first to plot\n", + "x = list(range(10))\n", + "y1 = [2,3,5,1,0,2,3,0,0,1]\n", + "\n", + "#first create a figure\n", + "fig = plt.figure()\n", + "\n", + "#now do the plotting\n", + "p1 = plt.scatter(x, y1, marker=\"*\", color=\"r\")\n", + "\n", + "#axis labels and title\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "plt.title(\"just a random scatter plot\")\n", + "\n", + "#so that we see the plot\n", + "plt.show()\n", + "\n", + "#close the plot\n", + "plt.close(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And you can read and display images with `imread()` and `imshow()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#first create a figure\n", + "fig = plt.figure()\n", + "\n", + "#now do the plotting\n", + "im = plt.imread(\"images/krabby_patty.jpg\")\n", + "plt.imshow(im)\n", + "\n", + "#axis labels and title\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "plt.title(\"krabby patty\")\n", + "\n", + "#so that we see the plot\n", + "plt.show()\n", + "\n", + "#close the plot\n", + "plt.close(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And that's all for this tutorial! If you have any problems, just ask (or even Google) them. You can check out the official Python tutorials for further learning.\n", + "\n", + "https://docs.python.org/3/tutorial/" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python", + "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.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}