diff --git a/sum23/labs/lab3/README.md b/sum23/labs/lab3/README.md new file mode 100644 index 0000000000000000000000000000000000000000..633d090c19baa5550fb14d51ead26011fb938e86 --- /dev/null +++ b/sum23/labs/lab3/README.md @@ -0,0 +1,203 @@ +# lab3: Learning an API and some functions + +### Corrections/Clarifications + +- None yet. + +**Find any issues?** Talk to your TA or peer mentor in lab, or create a Piazza post. + +------------------------------ +## Learning Objectives + +In this lab, you will practice... +* Writing functions with return statements +* Importing a module and using its functions +* Using parameters' default values when calling functions +* Avoiding hardcoding by using a `get_id` function +* Working with the index of a row of data + +------------------------------ +## Note on Academic Misconduct + +You may do these lab exercises only with your project partner; you are not allowed to start working on lab3 with one person, then do the project with a different partner. Now may be a good time to review [our course policies](https://canvas.wisc.edu/courses/355767/pages/syllabus?module_item_id=6048035). + +------------------------------ + +## Project partner + +We strongly recommend students find a project partner. Pair programming is a great way to learn from a fellow student. Project difficulty increases exponentially in this course. Finding a project partner early on during the semester is a good idea. + +If you are still looking for a project partner, take a moment now to ask around the room if anyone would like to partner with you on this project. Then you can work with them on this lab as well as the project. + +------------------------------ +## Description + +For many projects this semester, we'll provide you with a *module* (a collection of functions) named `project`, in a file named `project.py`. This module will provide functions that will help you complete the project. In the lab, we will introduce the module `project.py` which you will need to use in `p3`. + +When using an unfamiliar module, the first thing you should do is study the module's *API*. API stands for "Application Programming Interface". +The API descibes everything a programmer needs to know about a piece of the module in order to use it. Understanding the API will involve learning about each function and the arguments it takes, and what functions might need to be called before you can use other functions. + +There are two ways you can learn about an API. First, the person who created the API may have provided written directions, called *documentation*. Second, there are ways you can write code to learn about a collection of functions; this approach is called *inspection*. + +------------------------------ +## Segment 1: Setup + +Create a `lab3` directory and download the following files into the `lab3` directory: + +* `lab.csv` +* `project.py` +* `practice.ipynb` +* `practice_test.py` + +Once you have downloaded the files, open a terminal and navigate to your `lab3` directory. Run `ls` to make sure the above files are available. + +**Note:** If you accidentally downloaded the file as a `.txt` instead of `.csv` (say `lab.txt`), you can execute `mv lab.txt lab.csv` on a Terminal/PowerShell window. Recall that the `mv` (move) command lets you rename a source file (first argument, example: `lab.txt`) to the destination file (second argument, example: `lab.csv`). + +------------------------------ + +## Segment 2: Learning the `project.py` API + +The file `project.py` contains certain *functions* that will be useful for you when you are solving `p3`. It is not necessary to understand *how* these functions work (although you will learn how they work within a few weeks), but to use this module, you need to know *what* these functions do. +When dealing with an unfamiliar module, the best way to learn what its functions are, and how to use them, is to study the module's API. In this segment, we will be learning how to do exactly that. + +First, open a new Terminal/PowerShell window, and navigate to the `lab3` folder which contains `project.py`. From here, type `python` (or `python3` if that is what worked for you in [lab2](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab2)) to enter the Interactive Mode. It is also recommended that you review [lab2](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab2#task-16-exit-interactive-mode) on how to exit Interactive mode. + +### Task 2.1: Using `dir` + +From the Interactive mode, type the following command: + +```python +>>> import project +``` +This line *imports* the `project` module, so you can use the functions inside it. If you want to use any of the functions inside any module, you will have to import it first. But before we can use the functions inside this module, we need to find out *what* functions are inside this module. To do that, type the following command in Interactive mode: + +```python +>>> dir(project) +``` + +You should see the following output: + +``` +['__builtins__', '__cached__', '__csv__', '__doc__', '__file__', '__id_to_data__', '__loader__', '__name__', '__name_to_id__', '__package__', '__spec__', '__years__', 'dump', 'get_id', 'get_sales', 'init'] +``` + +The functions inside this module that will be relevant to us are the ones that do **not** begin and end with two underscores. + +### Task 2.2: Inspecting `project.py` + +Now that we know the functions inside the module that we can call, we need to figure out *what* these functions do. One way to do that is to just try and call them. Try the following on Interactive mode: + +```python +>>> project.dump() +``` + +You will likely see the following error message: + +``` +Traceback (most recent call last): + File "<stdin>", line 1, in <module> + File "C:\Users\myname\Documents\cs220\lab3", line 49, in dump + raise Exception("you did not call init first") +Exception: you did not call init first +``` + +This tells us that before we can call `project.dump`, we will need to call the `project.init` function. + +### Task 2.3: Using `help` + +We can continue to try and inspect the other functions in the `project` module to figure out what they do. However, most modules come with *documentation* explaining what each of the functions does, and it can save us time if we read this documentation. Try the following on Interactive mode: + +```python +>>> help(project.init) +``` + +You should see the following output: + +``` +Help on function init in module project: + +init(path) + init(path) must be called to load data before other calls will work. You should call it like this: init("car_sales_data.csv") or init("lab.csv") +``` + +**Note:** If you are using Mac OS, you **may** enter **Python help mode** when you type `help(project.init)`. You can recognize that you are in help mode if you no longer see the prompt `>>>` appearing on your screen. You will not be able to execute other Python commands from this mode. In order to *exit* the help mode, you need to type `q` and hit the `RETURN` key. If you do not enter Python help mode, this is unnecessary. + +The documentation here tells us that the function `init` takes in a `path` such as `lab.csv`, or `car_sales_data.csv` (which you will work with in p3) as its argument, and loads the data from the file into the Python program. Can you now understand what the Traceback was telling us when we called `project.dump` earlier? + +Let us now load the data from `lab.csv`. Execute the following command on Interactive mode. + +```python +>>> project.init('lab.csv') +``` + +**Note:** If you load the file `lab.csv` correctly, you will see the following warning message: +``` +WARNING! Opening a path other than car_sales_data.csv. That's fine for testing your code yourself, but car_sales_data.csv will be the only file around when we test your code for grading. +``` +That is to be expected. It is warning you that for the project `p3`, you will not be working with the data in `lab.csv`, but instead, the data in `car_sales_data.csv`, and that you should be careful not to load in the wrong file when working on `p3`. + +Now that we have loaded in our data, let us now see what `project.dump` does. Execute the following command on Interactive mode. + +```python +>>> help(project.dump) +``` + +You should see the following output: + +``` +Help on function dump in module project: + +dump() + prints all the data to the screen +``` + +Can you figure out what this function does, and how to call it? Call the function yourself. You should see the following output: + +``` +Chevy Bolt [ID: 21] + 2019: 16313 cars sold + 2020: 20754 cars sold + 2021: 24828 cars sold + +Chrysler Pacifica Plug-in Hybrid [ID: 3664] + 2019: 5811 cars sold + 2020: 9165 cars sold + 2021: 28747 cars sold + +Honda Clarity Plug-in [ID: 426] + 2019: 10728 cars sold + 2020: 4157 cars sold + 2021: 2366 cars sold + +Porsche Cayenne S E-Hybrid [ID: 6273] + 2019: 1140 cars sold + 2020: 1758 cars sold + 2021: 1783 cars sold + +Tesla Model 3 [ID: 850] + 2019: 154840 cars sold + 2020: 122700 cars sold + 2021: 121877 cars sold +``` + +This is data on the number of a few select models of electric cars sold between 2019 and 2021. If you manually open `lab.csv` using Microsoft Excel or some other Spreadsheet software, you will find this data stored there. + +We now need to figure out how to use the other functions in the module. Read the *documentation* using `help` to figure out what the following functions do: + +- `project.get_id` +- `project.get_sales` + +------------------------------ + +## Segment 3: Solving `practice.ipynb` + +You will be finishing the rest of your lab on `practice.ipynb`. Exit Python Interactive mode on your Terminal/PowerShell (using the `exit` function, as in [lab2](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab2#task-16-exit-interactive-mode)), and run the command `jupyter notebook`. Remember not to close this terminal window while Jupyter is running, and open a new Terminal window if necessary. + +**Note:** For `p3`, you will be working on `p3.ipynb` which is very similar to `practice.ipynb`. It is strongly recommended that you finish working on this notebook during the lab, so you can ask your TA/PM any questions about the notebook that may arise. + +**Note:** Unlike `p3.ipynb`, you do **not** have to submit `practice.ipynb`. This notebook is solely for your practice. + +------------------------------ +## Project 3 + +Great, now you're ready to start [P3](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/projects/p3)! Remember to only work with your partner from this lab on p3 from this point on. Have fun! diff --git a/sum23/labs/lab3/lab.csv b/sum23/labs/lab3/lab.csv new file mode 100644 index 0000000000000000000000000000000000000000..55dda4380766e13a52dbb9c67390d20694bad311 --- /dev/null +++ b/sum23/labs/lab3/lab.csv @@ -0,0 +1,6 @@ +id,vehicle,2019,2020,2021 +21,Chevy Bolt,16313,20754,24828 +3664,Chrysler Pacifica Plug-in Hybrid,5811,9165,28747 +850,Tesla Model 3,154840,122700,121877 +426,Honda Clarity Plug-in,10728,4157,2366 +6273,Porsche Cayenne S E-Hybrid,1140,1758,1783 \ No newline at end of file diff --git a/sum23/labs/lab3/practice.ipynb b/sum23/labs/lab3/practice.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..2d927b73a0b5dd523ebd895c973e6d2f4c0fdbdb --- /dev/null +++ b/sum23/labs/lab3/practice.ipynb @@ -0,0 +1,1428 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "1adf08f7", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "# Initialize Otter\n", + "import otter\n", + "grader = otter.Notebook(\"practice.ipynb\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d842427", + "metadata": {}, + "outputs": [], + "source": [ + "import practice_test" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a57e298e", + "metadata": {}, + "source": [ + "# Lab-P3: Learning an API and some functions\n", + "\n", + "**WARNING:** Please go through Segments 1 and 2 of [lab3](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab3) **before** you start to solve this notebook." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "2d751b35", + "metadata": {}, + "source": [ + "## Task 3.1: Calling functions in the `project` module\n", + "\n", + "You have already learned how to learn the *API* of the `project.py` module. You will now demonstrate your ability to call the functions in this module." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6bf657fc", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# include the relevant import statements in this cell\n", + "\n", + "import project # we have imported the project module for you here; you will have to add the import statement in p3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df773967", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "project.init(\"lab.csv\") # we have also loaded in 'lab.csv' for you here; you will have to load the data yourself in p3\n", + "\n", + "# you may call the dump function here to test if you have loaded the dataset correctly." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "384287a4", + "metadata": {}, + "source": [ + "**Question 1:** What is the `id` of the *Tesla Model 3*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e380d2d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we have done this one for you\n", + "model_3_id = project.get_id(\"Tesla Model 3\")\n", + "\n", + "model_3_id" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bbe449ea", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q1\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "72b2756f", + "metadata": {}, + "source": [ + "**Question 2:** What is the `id` of the *Honda Clarity Plug-in*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44b00d8a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# you will have to do this yourself; replace the ... with your code\n", + "# NOTE: assigning `clarity_id = 426` => is considered hardcoding\n", + "# if you do this in p3, you will lose points during manual code review\n", + "clarity_id = ...\n", + "\n", + "clarity_id" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6df63810", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q2\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "da1548b2", + "metadata": {}, + "source": [ + "**Question 3:** What is the `id` of the *Chrysler Pacifica Plug-in Hybrid*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b16fe080", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'pacifica_id'\n", + "\n", + "# display the variable 'pacifica_id' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "297a3d9b", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q3\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f6431a58", + "metadata": {}, + "source": [ + "### Task 3.1.1: Avoiding index hardcoding\n", + "\n", + "You should now have a good sense of how the `project.get_id` function works. You will now move on to the `project.get_sales` function. Read the documentation of this function, if you haven't already. Let us now call this function and see how it operates:\n", + "\n", + "**Note:** Recall that you can use `help(function_name)` to read the documentation of a function. Try reading the documentation for `get_id` function using `help(project.get_id)`" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c94ffb91", + "metadata": {}, + "source": [ + "**Question 4:** How many *Tesla Model 3* cars were sold in *2019*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "310952a5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# run this cell for now\n", + "model_3_sales_2019 = project.get_sales(850, 2019) # 850 is the `car_id` of Tesla Model 3\n", + "\n", + "model_3_sales_2019" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24cdd139", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q4\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "713c6a76", + "metadata": {}, + "source": [ + "## NOTE: Even though you passed the above test, this is considered hardcoding!\n", + "\n", + "You were asked how many *Tesla Model 3* cars were sold in *2019*. The `id` *850* was not provided to you as part of the question. You have no reason to expect that the dataset might not change in the future and that the ids will not be updated. Furthermore, by hardcoding the `id` into your answer, you are limiting its ability to be used for other datasets, where *Tesla Model 3* might have a different `id`.\n", + "\n", + "**Warning:** Since you used some information that was **not** explicitly provided to you as part of the question, this is considered **hardcoding**, and even if you pass the autograder, you will lose points for this, during manual code review.\n", + "\n", + "Let us now see the **correct** way to answer the previous question." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d5a62abf", + "metadata": {}, + "source": [ + "**Question 5:** How many *Tesla Model 3* cars were sold in *2019*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7cbf181d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# this is the *correct* way to solve this question without hardcoding any indices\n", + "model_3_id = project.get_id('Tesla Model 3')\n", + "model_3_sales_2019 = project.get_sales(model_3_id, 2019)\n", + "\n", + "model_3_sales_2019" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6527181", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q5\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "42af5648", + "metadata": {}, + "source": [ + "**Question 6:** How many *Porsche Cayenne S E-Hybrid* cars were sold in *2020*?\n", + "\n", + "You **must not** hardcode the `id` of the car" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5496e8af", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# replace the ... with your code\n", + "\n", + "cayenne_id = ...\n", + "cayenne_sales_2020 = ...\n", + "\n", + "cayenne_sales_2020" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "002f053d", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q6\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "46eeb2a9", + "metadata": {}, + "source": [ + "**Question 7:** How many *Chevy Bolt* cars were sold in *2021*?\n", + "\n", + "You **must not** hardcode the `id` of the car" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0745eb77", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'bolt_sales_2021'\n", + "\n", + "# display the variable 'bolt_sales_2021' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9cf584c", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q7\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d432cb49", + "metadata": {}, + "source": [ + "## Task 3.2: Calling and defining functions\n", + "\n", + "You will first demonstrate how to call some *built-in* functions (`max` and `min`) that will be useful for you in p3." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7fcb16fd", + "metadata": {}, + "source": [ + "**Question 8:** What is the *minimum* of the three numbers: *220*, *319*, and *320*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b16ec745", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we have done this one for you\n", + "min_three_numbers = min(220, 319, 320)\n", + "\n", + "min_three_numbers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b873de0", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q8\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b27754f4", + "metadata": {}, + "source": [ + "**Question 9:** What is the *minimum* of the two numbers: *220* and *200*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc2f98b0", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'min_two_numbers'.\n", + "\n", + "# display the variable 'min_two_numbers' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1b01ef9", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q9\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ecb87b5d", + "metadata": {}, + "source": [ + "**Question 10:** What is the *maximum* of the three numbers: *200*, *300*, and *400*?\n", + "\n", + "**Hint:** Just like the `min` function, there is a `max` function. You can either inspect or read its documentation to figure out how to use it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2765e62", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'max_three_numbers'.\n", + "\n", + "# display the variable 'max_three_numbers' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1a4e90b", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q10\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9a4044e9", + "metadata": {}, + "source": [ + "### Task 3.2.1: Defining your own functions\n", + "\n", + "You will now demonstrate how to define your own functions and how to call them." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "48857563", + "metadata": {}, + "source": [ + "### Function 1: `get_avg_drop_lowest(score1, score2, score3)`\n", + "\n", + "- This function will have three parameters, `score1`, `score2`, and `score3`.\n", + "- It should add up the 3 scores, subtract out the smallest of these scores, and then determine the average of the remaining two.\n", + "\n", + "For example, given the three scores `2, 4, 7`, your function should sum all the scores together `2 + 4 + 7` and then subtract `2`. Finally, it should return the average of the two remaining scores i.e it should be `(2 + 4 + 7 - 2)/2 = 5.5`.\n", + "\n", + "You will be provided with some code snippets to start with, but you will have to fill out the rest of the function. If you are not sure how to write this function, ask your TA/PM for help." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0b77f5b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def get_avg_drop_lowest(score1, score2, score3):\n", + " # replace the ... with your code\n", + " smallest = ...\n", + " sum_of_larger_two = ...\n", + " \n", + " avg = ...\n", + " return avg" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "29b14a9e", + "metadata": {}, + "source": [ + "**Question 11:** What is the output of `get_avg_drop_lowest(18, 20, 17)`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0db643e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we have done this one for you\n", + "avg_drop_lowest_18_20_17 = get_avg_drop_lowest(18, 20, 17)\n", + "\n", + "avg_drop_lowest_18_20_17" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fad5fb97", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q11\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "45ddc5f6", + "metadata": {}, + "source": [ + "**Question 12:** What is the output of `get_avg_drop_lowest(40, 45, 35)`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4e72726", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'avg_drop_lowest_40_45_35'\n", + "\n", + "# display the variable 'avg_drop_lowest_40_45_35' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4dc87926", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q12\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d65535a8", + "metadata": {}, + "source": [ + "### Function 2: `get_range(num1, num2, num3, num4)`\n", + "\n", + "- This function will have four parameters, `num1`, `num2`, `num3`, and `num4`.\n", + "- It should find the maximum of the four numbers, and the minimum of the four numbers, and subtract the minimum from the maximum.\n", + "\n", + "For example, given the four numbers `1, 2, 3, 4`, your function should subtract the minimum `1` from the maximum `4`, and return `4 - 1 = 3`.\n", + "\n", + "You will be provided with some code snippets to start with, but you will have to fill out the rest of the function. If you are not sure how to write this function, ask your TA/PM for help." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32ec2373", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def get_range(num1, num2, num3, num4):\n", + " # replace the ... with your code\n", + " maximum = ...\n", + " # define a variable called `minimum` and store the minimum of the four numbers as its value\n", + " \n", + " range_four_nums = ...\n", + " return range_four_nums" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e31827ec", + "metadata": {}, + "source": [ + "**Question 13:** What is the output of `get_range(10, 20, 40, 60)`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ffb303c3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'range_10_20_40_60'\n", + "\n", + "# display the variable 'range_10_20_40_60' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4bf58cbd", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q13\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "29cfab0d", + "metadata": {}, + "source": [ + "**Question 14:** What is the output of `get_range(40, 20, 10, 30)`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29a51926", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'range_40_20_10_30'\n", + "\n", + "# display the variable 'range_40_20_10_30' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8436d72", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q14\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "5275213c", + "metadata": {}, + "source": [ + "### Function 3: `change_in_value_per_year(year1, value1, year2, value2)`\n", + "\n", + "- This function will have four parameters, `year1`, `value1`, `year2`, and `value2`.\n", + "- `year1` and `year2` will be two different years represented as `int` and `value1` and `value2` will be the *value* of `year1` and `year2` respectively.\n", + "- The default value of `year2` is set to 2022 and the default value of `value2` is set to 6 (Refer the function in below cell)\n", + "- This function should find the average yearly change in *value* between `year1` and `year2`. It's not mandatory that `year2` > `year1`.\n", + "\n", + "**Hint:** This function basically computes the slope of the line that passes through the points (`year1`, `value1`) and (`year2`, `value2`).\n", + "\n", + "For example, if we are given the inputs `year1 = 2017`, `value1 = 5`, `year2 = 2022`, and `value2 = 0`, then the output of the function should be `(0 - 5)/(2022 - 2017) = -1.0`.\n", + "\n", + "You will be provided with some code snippets to start with, but you will have to fill out the rest of the function. Note that you will have to define a very similar function in p3, so this will be good practice for you. If you are not sure how to write this function, ask your TA/PM for help." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a4089a6", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def change_in_value_per_year(year1, value1, year2=2022, value2=6): # DO NOT EDIT THIS LINE\n", + " pass # this statement tells Python to do nothing.\n", + " # since this function has no code inside, we have added the pass statement inside so the code does not crash.\n", + " # once you have added code to this function, you can (and should) remove the pass statement as it does nothing.\n", + "\n", + " # TODO: find the change in *value* between `year1` and `year2` and store it in a variable `change_in_value`\n", + " # TODO: find the number of years between `year1` and `year2` and store it in a variable `num_years`\n", + " # TODO: compute the average change in value between `year1` and `year2` and store it in a variable `change_per_year`\n", + " # TODO: you *should* use the variables `change_in_value` and `num_years` to define this variable `change_per_year`\n", + " # TODO: return the variable `change_per_year` " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "832a8a49", + "metadata": {}, + "source": [ + "**Question 15:** What is the output of `change_in_value_per_year(2019, 12, 2020, 4)`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e00c8a2", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'change_per_year_2019_12_2020_4'\n", + "\n", + "# display the variable 'change_per_year_2019_12_2020_4' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9b11456", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q15\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a53a4b25", + "metadata": {}, + "source": [ + "**Question 16:** What is the output of `change_in_value_per_year(2015, 8, 2018, 11)`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bbf256b", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'change_per_year_2015_8_2018_11'\n", + "\n", + "# display the variable 'change_per_year_2015_8_2018_11' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2751ccfd", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q16\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7b4bd459", + "metadata": {}, + "source": [ + "### Task 3.2.2: Using default arguments\n", + "\n", + "You will now demonstrate how to use default arguments in functions.\n", + "\n", + "If you look back at the definition of `change_in_value_per_year`, you notice that the parameters `year2` and `value2` were given the default arguments `2022` and `6` respectively. We will now use these default arguments in our function calls." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "2fda6e37", + "metadata": {}, + "source": [ + "**Question 17:** Find the change in value per year when `year1` is *2020*, `value1` is *4*, `year2` is *2013*, and `value2` is *6*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8562d4b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we have done this one for you\n", + "change_per_year_2020_4_2013_6 = change_in_value_per_year(2020, 4, 2013) # note that the default argument for `value2` is used\n", + "\n", + "change_per_year_2020_4_2013_6" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "199435b8", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q17\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "fc1705b3", + "metadata": {}, + "source": [ + "**Question 18:** Find the change in value per year when `year1` is *2018*, `value1` is *11*, `year2` is *2022*, and `value2` is *6*\n", + "\n", + "You **must** use the default arguments (your call to `change_in_value_per_year` should **not** pass any more arguments than is absolutely necessary). Ask a TA/PM to review your code if you are unsure of your answer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85531f73", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'change_per_year_2018_11_2022_6'\n", + "\n", + "# display the variable 'change_per_year_2018_11_2022_6' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "730faa33", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q18\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d11d6a39", + "metadata": {}, + "source": [ + "**Question 19:** Find the change in value per year when `year1` is *2013*, `value1` is *3*, `year2` is *2022*, and `value2` is *2*\n", + "\n", + "**Note:** Pass the arguments only if they are not set as default in the function definition. This will be important when working with P3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0d4c988", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we have done this one for you\n", + "change_per_year_2013_3_2022_2 = change_in_value_per_year(2013, 3, value2=2) # note the use of positional arguments here\n", + "\n", + "change_per_year_2013_3_2022_2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9a327b6", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q19\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d01cd2c8", + "metadata": {}, + "source": [ + "**Question 20:** Find the change in value per year when `year1` is *2016*, `value1` is *4*, `year2` is *2022*, and `value2` is *0*\n", + "\n", + "**Note:** Pass the arguments only if they are not set as default in the function definition. This will be important when working with P3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54137a2c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'change_per_year_2016_4_2022_0'\n", + "\n", + "# display the variable 'change_per_year_2016_4_2022_0' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "150a1ca1", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q20\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8ba11cb3", + "metadata": {}, + "source": [ + "## That's it! You are done with lab3 and may start p3. You do not have to submit this practice notebook to Gradescope. Good luck!\n", + "\n", + "## It's a good practice to save notebook once in a while when working on projects as notebooks might lose network connection. So, try saving the notebook often!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9bef7039", + "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.8.0" + }, + "otter": { + "OK_FORMAT": true, + "tests": { + "q1": { + "name": "q1", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q1\", model_3_id)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q10": { + "name": "q10", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q10\", max_three_numbers)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q11": { + "name": "q11", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q11\", avg_drop_lowest_18_20_17)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q12": { + "name": "q12", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q12\", avg_drop_lowest_40_45_35)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q13": { + "name": "q13", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q13\", range_10_20_40_60)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q14": { + "name": "q14", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q14\", range_40_20_10_30)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q15": { + "name": "q15", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q15\", change_per_year_2019_12_2020_4)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q16": { + "name": "q16", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q16\", change_per_year_2015_8_2018_11)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q17": { + "name": "q17", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q17\", change_per_year_2020_4_2013_6)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q18": { + "name": "q18", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q18\", change_per_year_2018_11_2022_6)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q19": { + "name": "q19", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q19\", change_per_year_2013_3_2022_2)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q2": { + "name": "q2", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q2\", clarity_id)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q20": { + "name": "q20", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q20\", change_per_year_2016_4_2022_0)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q3": { + "name": "q3", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q3\", pacifica_id)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q4": { + "name": "q4", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q4\", model_3_sales_2019)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q5": { + "name": "q5", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q5\", model_3_sales_2019)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q6": { + "name": "q6", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q6\", cayenne_sales_2020)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q7": { + "name": "q7", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q7\", bolt_sales_2021)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q8": { + "name": "q8", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q8\", min_three_numbers)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q9": { + "name": "q9", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> practice_test.check(\"q9\", min_two_numbers)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + } + } + }, + "vscode": { + "interpreter": { + "hash": "f08154012ddadd8e950e6e9e035c7a7b32c136e7647e9b7c77e02eb723a8bedb" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sum23/labs/lab3/practice_test.py b/sum23/labs/lab3/practice_test.py new file mode 100644 index 0000000000000000000000000000000000000000..fb414d38962eca0ee096e6e931a68e06521f8b8e --- /dev/null +++ b/sum23/labs/lab3/practice_test.py @@ -0,0 +1,74 @@ +#!/usr/bin/python + +import os, json, math + + +REL_TOL = 6e-04 # relative tolerance for floats +ABS_TOL = 15e-03 # absolute tolerance for floats + +PASS = "PASS" + +TEXT_FORMAT = "text" # question type when expected answer is a str, int, float, or bool + +expected_json = {"1": (TEXT_FORMAT, 850), + "2": (TEXT_FORMAT, 426), + "3": (TEXT_FORMAT, 3664), + "4": (TEXT_FORMAT, 154840), + "5": (TEXT_FORMAT, 154840), + "6": (TEXT_FORMAT, 1758), + "7": (TEXT_FORMAT, 24828), + "8": (TEXT_FORMAT, 220), + "9": (TEXT_FORMAT, 200), + "10": (TEXT_FORMAT, 400), + "11": (TEXT_FORMAT, 19.0), + "12": (TEXT_FORMAT, 42.5), + "13": (TEXT_FORMAT, 50), + "14": (TEXT_FORMAT, 30), + "15": (TEXT_FORMAT, -8.0), + "16": (TEXT_FORMAT, 1.0), + "17": (TEXT_FORMAT, -0.2857142857142857), + "18": (TEXT_FORMAT, -1.25), + "19": (TEXT_FORMAT, -0.1111111111111111), + "20": (TEXT_FORMAT, -0.6666666666666666)} + +def check_cell(qnum, actual): + format, expected = expected_json[qnum[1:]] + try: + if format == TEXT_FORMAT: + return simple_compare(expected, actual) + else: + if expected != actual: + return "expected %s but found %s " % (repr(expected), repr(actual)) + except: + if expected != actual: + return "expected %s" % (repr(expected)) + return PASS + + +def simple_compare(expected, actual, complete_msg=True): + msg = PASS + if type(expected) == type: + if expected != actual: + if type(actual) == type: + msg = "expected %s but found %s" % (expected.__name__, actual.__name__) + else: + msg = "expected %s but found %s" % (expected.__name__, repr(actual)) + elif type(expected) != type(actual) and not (type(expected) in [float, int] and type(actual) in [float, int]): + msg = "expected to find type %s but found type %s" % (type(expected).__name__, type(actual).__name__) + elif type(expected) == float: + if not math.isclose(actual, expected, rel_tol=REL_TOL, abs_tol=ABS_TOL): + msg = "expected %s" % (repr(expected)) + if complete_msg: + msg = msg + " but found %s" % (repr(actual)) + else: + if expected != actual: + msg = "expected %s" % (repr(expected)) + if complete_msg: + msg = msg + " but found %s" % (repr(actual)) + return msg + +def check(qnum, actual): + msg = check_cell(qnum, actual) + if msg == PASS: + return True + print("<b style='color: red;'>ERROR:</b> " + msg) diff --git a/sum23/labs/lab3/project.py b/sum23/labs/lab3/project.py new file mode 100644 index 0000000000000000000000000000000000000000..50eaea9dc7f9f45820cf6c45f76fdd7bdf7e8a02 --- /dev/null +++ b/sum23/labs/lab3/project.py @@ -0,0 +1,76 @@ +import csv as __csv__ + +__id_to_data__ = None +__name_to_id__ = None +__years__ = None + + +def init(path): + """init(path) must be called to load data before other calls will work. You should call it like this: init("car_sales_data.csv") or init("lab.csv")""" + + global __id_to_data__ + global __name_to_id__ + global __years__ + + if path != 'car_sales_data.csv': + print("WARNING! Opening a path other than car_sales_data.csv. " + + "That's fine for testing your code yourself, but car_sales_data.csv " + + "will be the only file around when we test your code " + + "for grading.") + + __id_to_data__ = {} + __name_to_id__ = {} + __years__ = [] + + f = open(path, encoding='utf-8') + raw_data = list(__csv__.reader(f)) + f.close() + + id_i = raw_data[0].index('id') + vehicle_i = raw_data[0].index('vehicle') + for head in raw_data[0]: + if head not in ('id', 'vehicle'): + __years__.append(int(head)) + for car in raw_data[1:]: + __name_to_id__[car[vehicle_i]] = car[id_i] + __id_to_data__[car[id_i]] = {} + for i in range(len(car)): + if i == id_i: + continue + elif i == vehicle_i: + __id_to_data__[car[id_i]][raw_data[0][i]] = car[i] + else: + __id_to_data__[car[id_i]][raw_data[0][i]] = int(car[i]) + + +def dump(): + """prints all the data to the screen""" + if __id_to_data__ == None: + raise Exception("you did not call init first") + + for car in sorted(__name_to_id__.keys()): + car_id = __name_to_id__[car] + print("%s [ID: %s]" % (car, car_id)) + for year in __years__: + print(" %s: %d cars sold" % (year, __id_to_data__[car_id][str(year)])) + print() + +def get_id(car): + """get_id(car) returns the id of the specified car model.""" + if __name_to_id__ == None: + raise Exception("you did not call init first") + if not car in __name_to_id__: + raise Exception("No car '%s', only these: %s" % + (str(car), ', '.join(list(__name_to_id__.keys())))) + return int(__name_to_id__[car]) + +def get_sales(car_id, year=2019): + """get_sales(car_id, year) returns the number of cars of the specified model sold in the specified year.""" + if __id_to_data__ == None: + raise Exception("you did not call init first") + if str(car_id) not in list(__id_to_data__.keys()): + raise Exception("%s is not an id of any car in the dataset. Did you call get_id?" % (str(car_id))) + if not str(car_id) in __id_to_data__ or str(year) not in __id_to_data__[str(car_id)]: + raise Exception("No data for car %s, in year %s" % + (str(car_id), str(year))) + return __id_to_data__[str(car_id)][str(year)] diff --git a/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec-04-worksheet-solution-previous_sem.pdf b/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec-04-worksheet-solution-previous_sem.pdf new file mode 100644 index 0000000000000000000000000000000000000000..29a883754dd82916d9102d0fef14bbe5b2809698 Binary files /dev/null and b/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec-04-worksheet-solution-previous_sem.pdf differ diff --git a/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec-04-worksheet-solution.pdf b/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec-04-worksheet-solution.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ba423b23f06f8cc20dd16107c2f0964f25c95d40 Binary files /dev/null and b/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec-04-worksheet-solution.pdf differ diff --git a/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec_04_Creating_functions_solution.ipynb b/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec_04_Creating_functions_solution.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..62a4675a505f23dad3035517d7516479b3dc8715 --- /dev/null +++ b/sum23/lecture_materials/04_Functions_Creation_and_Scope/lec_04_Creating_functions_solution.ipynb @@ -0,0 +1,1116 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Creating Functions\n", + "\n", + "## Readings\n", + "\n", + "- Parts of Chapter 3 of Think Python,\n", + "- Chapter 5.5 to 5.8 of Python for Everybody\n", + "- Creating Fruitful Functions\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Review - modules\n", + "\n", + "### Two ways of importing functions from a module\n", + "1. import \\<module\\>\n", + " - requires you to use attribute operator: `.`\n", + " - \\<module\\>.\\<function\\>\n", + "2. from \\<module\\> import \\<function\\>\n", + " - function can be called just with its name\n", + " \n", + "Let's learn about time module" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# Add all your import statements to this cell\n", + "\n", + "# TODO: import time module using import style of import\n", + "import time\n", + "\n", + "\n", + "\n", + "# TODO: use from style of import to import log10 function from math module\n", + "from math import log10\n", + "\n", + "# Bad style to import everything from a module\n", + "# Not recommended to do\n", + "# from math import *\n", + "\n", + "# If you want to import everything, you need to \n", + "# follow import style of import\n", + "# import math" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# if I do \"from math import *\" (bad!), I'd call functions like\n", + "# sqrt(x) \n", + "\n", + "# if I do \"import math\", I call fucntions like\n", + "# math.sqrt(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "time module time function shows the current time in seconds since epoch.\n", + "\n", + "What is epoch? epoch is January 1, 1970. **FUN FACT:** epoch is considered beginning of time for computers." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1687791326.7691379\n", + "1687791331.6798909\n", + "4.910753011703491\n" + ] + } + ], + "source": [ + "start_time = time.time()\n", + "x = 2 ** 1000000000 # some large computation\n", + "end_time = time.time()\n", + "\n", + "# TODO: change the line below to compute difference\n", + "difference = end_time - start_time\n", + "\n", + "# TODO: add a separator of '\\n'\n", + "print(start_time, end_time, difference, sep=\"\\n\") \n", + "\n", + "# TODO: discuss - how can you use time() function to time your project code?" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "float" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(start_time)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.0\n" + ] + } + ], + "source": [ + "# TODO: call log10 function to determine log base 10 of 1000\n", + "print(log10(1000))\n", + "\n", + "# Recall that you cannot use math. when you use from style of import\n", + "# print(math.log10(1000)) #doesn't work" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'pi' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[4], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Can you access pi variable inside math module?\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43mpi\u001b[49m \u001b[38;5;66;03m# TODO: discuss why this didn't work\u001b[39;00m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# TODO: go back to the import cell and import math \u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# TODO: fix line 2, so that you are now able to access pi inside math module\u001b[39;00m\n", + "\u001b[0;31mNameError\u001b[0m: name 'pi' is not defined" + ] + } + ], + "source": [ + "# Can you access pi variable inside math module?\n", + "pi # TODO: discuss why this didn't work\n", + "\n", + "# TODO: go back to the import cell and import math \n", + "# TODO: fix line 2, so that you are now able to access pi inside math module\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "<div>\n", + "<img src=\"attachment:Modules.png\" width=\"800\"/>\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Learning Objectives\n", + "\n", + "- Explain the syntax of a function header:\n", + " - def, ( ), :, tabbing, return\n", + "- Write a function with:\n", + " - correct header and indentation\n", + " - a return value (fruitful function) or without (void function)\n", + " - parameters that have default values\n", + "- Write a function knowing the difference in outcomes of print and return statements\n", + "- Explain how positional, keyword, and default arguments are copied into parameters\n", + "- Make function calls using positional, keyword, and default arguments and determine the result.\n", + "- Trace function invocations to determine control flow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Function syntax\n", + "\n", + "- Let's compare math function definition to Python function definition\n", + " 1. Square of a number:\n", + " - Math: $f(x) = x^{2}$\n", + " - Python: \n", + " ```\n", + " def f(x):\n", + " return x ** 2\n", + " ```\n", + " \n", + "- Python function defintion syntax:\n", + " - start a function definition with `def` (short for definition), always followed by a pair of parenthesis `( )`\n", + " - inside the parenthesis specify **parameters** separated by `,`\n", + " - use a colon (`:`) instead of an equal sign (“=”)\n", + " - type the `return` keyword before the expression associated with the function\n", + " - indent (tab space) before the statement(s)\n", + " - it is common to have longer names for functions and arguments\n", + " - it is also common to have more than one line of code (all indented)\n", + " \n", + " \n", + " \n", + "- Let's compare math function definition to Python function definition\n", + " 2. Radius of a circle\n", + " - Math: $g(r) = \\pi r^{2}$\n", + " - Python (literal equivalent): \n", + " ```\n", + " def g(r):\n", + " return 3.14 * r ** 2\n", + " ```\n", + " - Python (better version 1):\n", + " ```\n", + " def get_area(radius):\n", + " return 3.14 * radius ** 2\n", + " ```\n", + " - Python (better version 2):\n", + " ```\n", + " def get_area(diameter):\n", + " radius = diameter / 2\n", + " return 3.14 * radius ** 2\n", + " ```\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 1: Cube of a number\n", + "- Input: number (to be cubed)\n", + "- Output: cubed number" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Let's define the cube function\n", + "def cube(x):\n", + " return x ** 3" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "125\n", + "512\n" + ] + } + ], + "source": [ + "# Let's call cube function to compute cube of 5\n", + "print(cube(5))\n", + "# TODO: discuss what is different about the below line of code\n", + "print(cube(cube(2)))\n", + "# the above line is equivalent to writing\n", + "# cube_2 = cube(2)\n", + "# print(cube(cube_2))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "37\n", + "37\n" + ] + } + ], + "source": [ + "# TODO: compute cube of 4 + cube of -3\n", + "# version 1\n", + "print(cube(4) + cube(-3))\n", + "\n", + "# version 2\n", + "cube_4 = cube(4)\n", + "cube_neg3 = cube(-3)\n", + "print(cube_4 + cube_neg3)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-1728\n" + ] + } + ], + "source": [ + "# TODO: compute cube of 4 * cube of -3\n", + "# Now which one of the above two versions is better?\n", + "\n", + "# This works fine\n", + "# print(cube(4) * cube(-3))\n", + "\n", + "# This is better, because we don't repeat computation that we already did\n", + "print(cube_4 * cube_neg3)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Whenever you think you are going to reuse a function call's output, save it in a variable\n", + "\n", + "Rookie programmer mistake: calling the same function with the same arguments will always give the same return value. Why is this a problem? Running the same function call twice takes twice the time" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`return` vs `print`\n", + "- `return` enables us to send output from a function to the calling place\n", + " - default `return` value is `None`\n", + " - that means, when you don't have a `return` statement, `None` will be returned\n", + "- `print` function simply displays / prints something\n", + " - it cannot enable you to produce output from a function" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Change the return to a print function call and run this cell\n", + "def cube_no_return(side):\n", + " print ( side ** 3 )" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4913\n" + ] + } + ], + "source": [ + "# if we are NOT saving function return in a variable, or using it as input \n", + "# to a function, then it is okay to have a function with no return statement.\n", + "cube_no_return(17)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "125\n", + "None\n" + ] + } + ], + "source": [ + "print(cube_no_return(5))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n" + ] + }, + { + "ename": "TypeError", + "evalue": "unsupported operand type(s) for ** or pow(): 'NoneType' and 'int'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[16], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mcube_no_return\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcube_no_return\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m) \n\u001b[1;32m 2\u001b[0m \u001b[38;5;66;03m# TODO: discuss the root cause of this TypeError\u001b[39;00m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# TypeError: \u001b[39;00m\n", + "Cell \u001b[0;32mIn[14], line 3\u001b[0m, in \u001b[0;36mcube_no_return\u001b[0;34m(side)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcube_no_return\u001b[39m(side):\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28mprint\u001b[39m ( \u001b[43mside\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m )\n", + "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for ** or pow(): 'NoneType' and 'int'" + ] + } + ], + "source": [ + "print(cube_no_return(cube_no_return(2))) \n", + "# TODO: discuss the root cause of this TypeError\n", + "# TypeError: \n", + "# print ( cube_no_return ( None ))\n", + "# Python can't raise None to the power of 3" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "64\n", + "-27\n" + ] + }, + { + "ename": "TypeError", + "evalue": "unsupported operand type(s) for +: 'NoneType' and 'NoneType'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mcube_no_return\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mcube_no_return\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m)\u001b[49m) \n\u001b[1;32m 2\u001b[0m \u001b[38;5;66;03m# TODO: discuss the root cause of this TypeError\u001b[39;00m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# TypeError: \u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'NoneType' and 'NoneType'" + ] + } + ], + "source": [ + "print(cube_no_return(4) + cube_no_return(-3)) \n", + "# TODO: discuss the root cause of this TypeError\n", + "# TypeError: " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## fruitful function versus void function\n", + "- fruitful function: returns something\n", + " - ex: cube\n", + "- void function: doesn't return anything\n", + " - ex: cube_no_return\n", + " - may produce output with `print` function calls\n", + " - may change values of certain variables\n", + " \n", + "<div>\n", + "<img src=\"attachment:return_print.png\" width=\"800\"/>\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tracing function invocations\n", + "- PythonTutor is a great tool to learn control flow\n", + "- Let's use PythonTutor to trace cube function invocation\n", + "- TODO: Copy-paste cube function defintion into PythonTutor (course website > tools > PythonTutor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 2: is_between(lower, num, upper)\n", + "- Purpose: check whether number is within the range of lower and upper (inclusive)\n", + "- Input: lower bound, number, upper bound\n", + "- Output: boolean value (`True` or `False`)\n", + "- Keyword: `pass`:\n", + " - placeholder statement\n", + " - you cannot run a cell with an empty function definition" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n", + "True\n" + ] + } + ], + "source": [ + "def is_between(lower, num, upper):\n", + " # pass # TODO: remove this and try to run this cell\n", + " return lower <= num <= upper\n", + "\n", + " \n", + "# you can call a function in the same cell that you defined it\n", + "print(is_between(3, 7, 21))\n", + "print(is_between(2, 14, 5))\n", + "print(is_between(100, cube(5), 200))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Types of arguments\n", + "<div>\n", + "<img src=\"attachment:argument_types.png\" width=\"800\"/>\n", + "</div>\n", + "\n", + "- positional: order of arguments must match exactly with order of parameters\n", + "- keyword: order of arguments doesn't matter\n", + "- default: included as part of the function definition line\n", + "\n", + "Python fills arguments in this order: positional, keyword, default" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Worksheet practice using an example similar to the next example\n", + "\n", + "Python Tutor links\n", + "* [Questions 1-9](https://pythontutor.com/visualize.html#code=def%20add3%28x,%20y%20%3D%20100,%20z%20%3D%20100%29%3A%20%0A%20%20%20%20%22%22%22adds%20three%20numbers%22%22%22%20%20%20%20%20%20%20%23documentation%20string%0A%20%20%20%20print%20%28%22x%20%3D%20%22%20%2B%20str%28x%29%29%0A%20%20%20%20print%20%28%22y%20%3D%20%22%20%2B%20str%28y%29%29%0A%20%20%20%20print%20%28%22z%20%3D%20%22%20%2B%20str%28z%29%29%0A%20%20%20%20return%20x%20%2B%20y%20%2B%20z%0A%0A%23%20TODO%20write%20a%20function%20call%20here%0Aadd3%28...%29&cumulative=false&heapPrimitives=nevernest&mode=edit&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)\n", + "* [Questions 10-18](https://pythontutor.com/visualize.html#code=def%20say%28word,%20t%3D1,%20end%3D%22%22%29%3A%0A%20%20%20%20%23%20add%20prints%20here%20to%20debug%20%0A%20%20%20%20print%28word%20*%20t%20%2B%20end%29%0A%20%20%20%20%0A%23%20TODO%20create%20a%20function%20call%20here%0Asay%28...%29&cumulative=false&heapPrimitives=nevernest&mode=edit&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)\n", + "* [Questions 19-20](https://pythontutor.com/visualize.html#code=print%28%22A%22%29%0A%0Adef%20foo%28%29%3A%0A%20%20%20print%28%22B%22%29%0A%20%20%20%0Aprint%28%22C%22%29%0Afoo%28%29%0Aprint%28%22D%22%29%0Afoo%28%29%0A&cumulative=false&heapPrimitives=nevernest&mode=edit&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)\n", + "* [Question 21](https://pythontutor.com/visualize.html#code=def%20func_c%28%29%3A%0A%20%20%20print%28%22C%22%29%0A%20%20%20%0Adef%20func_b%28%29%3A%0A%20%20%20print%28%22B1%22%29%0A%20%20%20func_c%28%29%0A%20%20%20print%28%22B2%22%29%0A%20%20%20%0Adef%20func_a%28%29%3A%0A%20%20%20print%28%22A1%22%29%0A%20%20%20func_b%28%29%0A%20%20%20print%28%22A2%22%29%0A%20%20%20%0Afunc_a%28%29&cumulative=false&heapPrimitives=nevernest&mode=edit&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)\n", + "* [Question 22](https://pythontutor.com/visualize.html#code=def%20f%28%29%3A%0A%20%20%20print%28%22A%22%29%0A%20%20%20%0Areturn%28%22B%22%29%0A%20%20%20print%28%22C%22%29%0A%20%20%20%0Aprint%28%22D%22%29%0Ax%20%3D%20f%28%29%0Aprint%28%22E%22%29%0Aprint%28x%29&cumulative=false&heapPrimitives=nevernest&mode=edit&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "def add(x, y):\n", + " print(\"x is\", x)\n", + " print(\"y is\", y)\n", + " return x + y" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x is 11\n", + "y is 10\n" + ] + }, + { + "data": { + "text/plain": [ + "21" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "add(y=10 , x=11)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# can you return multiple things from a function?\n", + "# technically yes (separate them with commas)\n", + "# but usually we don't want to do this\n", + "def test():\n", + " return 2, 3" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x = 100\n", + "y = 10\n", + "z = 5\n" + ] + } + ], + "source": [ + "def add3(x, y = 100, z = 100): \n", + " \"\"\"adds three numbers\"\"\" #documentation string\n", + " print (\"x = \" + str(x))\n", + " print (\"y = \" + str(y))\n", + " print (\"z = \" + str(z))\n", + " return x + y + z\n", + "\n", + "sum = add3(100, 10, 5) \n", + "# TODO: 1. sum is a bad variable, discuss: why. What would be a better variable name?\n", + "# option 1: sum_100_10_5\n", + "# option 2: my_sum better, but not great because it's not descriptive\n", + "# option 3: something descriptive to how you want to use sum\n", + "\n", + "\n", + "# TODO: 2. what type of arguments are 100, 10, and 5? \n", + "# all positional\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x = 1\n", + "y = 5\n", + "z = 2\n", + "8\n" + ] + } + ], + "source": [ + "print(add3(x = 1, z = 2, y = 5)) #TODO: what type of arguments are these? \n", + "\n", + "# keyword arguments" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x = 5\n", + "y = 6\n", + "z = 100\n" + ] + }, + { + "data": { + "text/plain": [ + "111" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "add3(5, 6) # TODO: what type of argument gets filled for the parameter z? \n", + "\n", + "# parameter z was given the default value, 100" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Positional arguments need to be specified before keyword arguments." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "positional argument follows keyword argument (77830574.py, line 3)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn[41], line 3\u001b[0;36m\u001b[0m\n\u001b[0;31m add3(z = 5, 2, 7)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m positional argument follows keyword argument\n" + ] + } + ], + "source": [ + "# Incorrect function call\n", + "print(\"HI\")\n", + "add3(z = 5, 2, 7) \n", + "# TODO: what category of error is this?\n", + "# syntax\n", + "\n", + "# you can fix this error with:\n", + "add3(z = 5, x = 2, y =7) \n", + "# or\n", + "add3( 2, 7, z = 5)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly, parameters with default values should be defined after parameters without default values." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "non-default argument follows default argument (424418737.py, line 2)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn[42], line 2\u001b[0;36m\u001b[0m\n\u001b[0;31m def bad_add3_v1(x = 10, y, z):\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m non-default argument follows default argument\n" + ] + } + ], + "source": [ + "# Incorrect function definition\n", + "# better: bad_add3_v1(y, z, x=10) # this works\n", + "\n", + "def bad_add3_v1(x = 10, y, z): \n", + " \"\"\"adds three numbers\"\"\" #documentation string\n", + " return x + y + z" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python expects exactly same number of arguments as parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "add3() got multiple values for argument 'x'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[43], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Incorrect function call\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43madd3\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m5\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# TODO: what category of error is this?\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: add3() got multiple values for argument 'x'" + ] + } + ], + "source": [ + "# Incorrect function call\n", + "add3(5, 3, 10, x = 4)\n", + "# TODO: what category of error is this?" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "add3() missing 1 required positional argument: 'x'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[44], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# TODO: will this function call work?\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43madd3\u001b[49m\u001b[43m(\u001b[49m\u001b[43my\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m5\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mz\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mTypeError\u001b[0m: add3() missing 1 required positional argument: 'x'" + ] + } + ], + "source": [ + "# TODO: will this function call work?\n", + "add3(y = 5, z = 10)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "add3() missing 1 required positional argument: 'x'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[45], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# TODO: will this function call work?\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43madd3\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mTypeError\u001b[0m: add3() missing 1 required positional argument: 'x'" + ] + } + ], + "source": [ + "# TODO: will this function call work?\n", + "add3()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 3: Generate a height x width grid\n", + "- Input: width, height, grid symbol, title of the grid\n", + "- Output: string containing title, a newline, and the grid\n", + "- Pseudocode steps:\n", + " 1. Generate a single row of symb (width dimension). What string operator do you need?\n", + " 2. Capture single row into a variable\n", + " 3. Add newline to single row variable.\n", + " 4. Generate multiple rows (height dimension). What string operator do you need?\n", + " 5. Generate the output string to be returned by adding title with a newline with the output from step 4." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: how many parameters have default values in the below function?\n", + "def get_grid(width, height, symb = '#', title = 'My Grid:'):\n", + " row = symb * width\n", + " grid = (row + '\\n') * height\n", + " return title + '\\n' + grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: generate various sized grids, by exploring\n", + "# three types of arguments\n", + "# Here is one example\n", + "print(get_grid(10, 8))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: use PythonTutor to trace get_grid function call" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: make your 2nd grid\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: make your 3rd grid\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When you use keyword arguments, the order of the arguments need not match with the parameters.\n", + "This is because we tie the arguments to the parameters, by explicitly saying parameter = argument" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Try using all keyword arguments and use different order than the order of the parameters.\n", + "print(get_grid(symb = \"^\", title = \"Some other grid:\", width = 4, height = 7))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Revisiting `print` function\n", + "- Let's look at `help(print)` to learn about print's parameters\n", + " - Default value for `sep` is space, that is: \" \"\n", + " - Default value for `end` is newline, that is: \"\\n\"" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function add3 in module __main__:\n", + "\n", + "add3(x, y=100, z=100)\n", + " adds three numbers\n", + "\n" + ] + } + ], + "source": [ + "help(add3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# sep doesn't work if you have a single argument\n", + "print(\"hello\" + \" world\", sep = \"---\") # `+` concatenates and produces a single string as argument." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: predict output, then run to validate your prediction\n", + "print(3 + 4, 3 < 4, \"3\" + \"4\", end = \"....\\n\" ) # sep default is \" \"\n", + "print(3 + 4, 3 < 4, \"3\" + \"4\", sep = \"\\t\" ) # end default is \"\\n\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## void function (one more example)\n", + "- fruitful function: returns something\n", + " - ex: add3\n", + "- void function: doesn't return anything\n", + " - ex: bad_add3_v2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example of void function\n", + "def bad_add3_v2(x, y, z):\n", + " \"\"\"prints x + y + z, instead of returning\"\"\"\n", + " pass\n", + "\n", + "print(bad_add3_v2(4, 2, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(bad_add3_v2(4, 2, 1) ** 2) # Cannot apply mathematical operator to None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `return` statement is final\n", + "- exactly *one* `return` statement gets executed for a function call\n", + "- immediately after encountering `return`, function execution terminates" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "50" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def bad_add3_v3(x, y, z): \n", + " return x\n", + " # python will never reach this line! \n", + " return x + y + z # will never execute\n", + "\n", + "bad_add3_v3(50, 60, 70)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Default return type from a function is None. \n", + "None is a special type in Python (similar to null in Java)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Trace this example\n", + "- manually\n", + "- then use PythonTutor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def func_c():\n", + " print(\"C\")\n", + "\n", + "def func_b():\n", + " print(\"B1\")\n", + " func_c()\n", + " print(\"B2\")\n", + "\n", + "def func_a():\n", + " print(\"A1\")\n", + " func_b()\n", + " print(\"A2\")\n", + "\n", + "func_a()" + ] + } + ], + "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.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/sum23/projects/p3/README.md b/sum23/projects/p3/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ff1dc485da1530a23eb44391e177b32334012063 --- /dev/null +++ b/sum23/projects/p3/README.md @@ -0,0 +1,40 @@ +# Project 3 (P3): Electric Vehicle Sales + +## Clarifications/Corrections: + +* None yet. + +**Find any issues?** Talk to Jane or Adi in lab, or make a post on Piazza. + +## Note on Academic Misconduct: +You are **allowed** to work with a partner on your projects. While it is not required that you work with a partner, it is **recommended** that you find a project partner as soon as possible as the projects will get progressively harder. Be careful **not** to work with more than one partner. If you worked with a partner on lab3, you are **not** allowed to finish your project with a different partner. You may either continue to work with the same partner, or work on P3 alone. Now may be a good time to review our [course policies](https://canvas.wisc.edu/courses/355767/pages/syllabus?module_item_id=6048035). + +## Instructions: + +In this project, we will focus on function calls, function definitions, default arguments, and simple arithmetic operations. To start, create a `p3` directory, and download `p3.ipynb`, `project.py`, `p3_test.py`, and `car_sales_data.csv`. + +**Note:** Please go through [lab3](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab3) before you start the project. The lab contains some very important information that will be necessary for you to finish the project. + +You will work on `p3.ipynb` and hand it in. You should follow the provided directions for each question. Questions have **specific** directions on what **to do** and what **not to do**. + +After you've downloaded the file to your `p3` directory, open a terminal window and use `cd` to navigate to that directory. To make sure you're in the correct directory in the terminal, type `pwd`. To make sure you've downloaded the notebook file, type `ls` to ensure that `p3.ipynb`, `project.py`, `p3_test.py`, and `car_sales_data.csv` are listed. Then run the command `jupyter notebook` to start Jupyter, and get started on the project! Make sure to run the initial cells in the notebook before proceeding. + +**IMPORTANT**: You should **NOT** terminate/close the session where you run the `jupyter notebook` command. If you need to use any other Terminal/PowerShell commands, open a new window instead. Keep constantly saving your notebook file, by either clicking the "Save and Checkpoint" button (floppy disk) or using the appropriate keyboard shortcut. + +------------------------------ + +## IMPORTANT Submission instructions: +- Review the [Grading Rubric](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/blob/main/sum23/projects/p3/rubric.md), to ensure that you don't lose points during code review. +- Login to [Gradescope](https://www.gradescope.com/) and upload the zip file into the P3 assignment. +- If you completed the project with a **partner**, make sure to **add their name** by clicking "Add Group Member" +in Gradescope when uploading the P3 zip file. + + <img src="images/add_group_member.png" width="400"> + + **Warning:** You will have to add your partner on Gradescope even if you have filled out this information in your `p3.ipynb` notebook. + +- It is **your responsibility** to make sure that your project clears auto-grader tests on the Gradescope test system. Otter test results should be available in a few minutes after your submission. You should be able to see both PASS / FAIL results for the 20 test cases and your total score, which is accessible via Gradescope Dashboard (as in the image below): + + <img src="images/gradescope.png" width="400"> + + Note that you can only see your score as `-/100.0` since it has not yet been reviewed by a TA. However, you should confirm that your tests have all passed the autograder. diff --git a/sum23/projects/p3/car_sales_data.csv b/sum23/projects/p3/car_sales_data.csv new file mode 100644 index 0000000000000000000000000000000000000000..7b211929c5c237a7c9b0ab3c05c314bf49c5d917 --- /dev/null +++ b/sum23/projects/p3/car_sales_data.csv @@ -0,0 +1,7 @@ +id,vehicle,2017,2018,2019,2020,2021 +958,Tesla Model S,26500,25745,15090,10125,17653 +10,Chevy Volt,20349,18306,4915,67,16 +64,Nissan Leaf,11230,14715,12365,9564,14239 +977,Toyota Prius PHEV,20936,27595,23630,43525,59010 +332,Ford Fusion Energi,9632,8074,7476,19402,3342 +951,Tesla Model X,208,26100,19425,7375,22546 diff --git a/sum23/projects/p3/images/README.md b/sum23/projects/p3/images/README.md new file mode 100644 index 0000000000000000000000000000000000000000..58de295751482954ef960c6197de0cafc3fe20fb --- /dev/null +++ b/sum23/projects/p3/images/README.md @@ -0,0 +1,3 @@ +# Images + +Images from p3 are stored here. diff --git a/sum23/projects/p3/images/add_group_member.png b/sum23/projects/p3/images/add_group_member.png new file mode 100644 index 0000000000000000000000000000000000000000..402e5962e3e54ce8349f60ccfe4ce2b60840dd3b Binary files /dev/null and b/sum23/projects/p3/images/add_group_member.png differ diff --git a/sum23/projects/p3/images/gradescope.png b/sum23/projects/p3/images/gradescope.png new file mode 100644 index 0000000000000000000000000000000000000000..a46c44d2a9b9b8d4b76a9721809d2e81754e946a Binary files /dev/null and b/sum23/projects/p3/images/gradescope.png differ diff --git a/sum23/projects/p3/p3.ipynb b/sum23/projects/p3/p3.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..e217d0f5ce977dbbb34483cb5eb7b5ef68bb49f5 --- /dev/null +++ b/sum23/projects/p3/p3.ipynb @@ -0,0 +1,1803 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "03ebcde3", + "metadata": { + "cell_type": "code", + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "# import and initialize otter\n", + "import otter\n", + "grader = otter.Notebook(\"p3.ipynb\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb437ef8", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "import p3_test" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0f32621", + "metadata": {}, + "outputs": [], + "source": [ + "# PLEASE FILL IN THE DETAILS\n", + "# enter none if you don't have a project partner\n", + "\n", + "# project: p3\n", + "# submitter: NETID1\n", + "# partner: NETID2\n", + "# hours: ????" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0afa6bb0", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "# Project 3: Electric Vehicle Sales" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e98c5f26", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "## Learning Objectives:\n", + "\n", + "In this project you will demonstrate your ability to:\n", + "- import a module and use its functions,\n", + "- write functions,\n", + "- use default arguments when calling functions,\n", + "- use positional and keyword arguments when calling functions,\n", + "- avoid hardcoding, and\n", + "- work with the index of a row of data." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ed6d6e6a", + "metadata": {}, + "source": [ + "## Testing your code:\n", + "\n", + "Along with this notebook, you must have downloaded the file `p3_test.py`. If you are curious about how we test your code, you can explore this file, and specifically the value of the variable `expected_json`, to understand the expected answers to the questions. You can have a look at [p2](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/projects/p2) if you have forgotten how to read the outputs of the `grader.check(...)` function calls." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7513e29b", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Please go through [lab3](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab3) before starting this project.** The lab introduces some useful techniques necessary for this project." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9d214da8", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "## Project Description:\n", + "\n", + "In this project, you'll analyze data on six different electric vehicle models sold in the United States between 2017 and 2021. The dataset we will analyze is truncated and modified from [the Alternative Fuels Data Center](https://afdc.energy.gov/data/) published by the U.S. Department of Energy, and from the [Kelley Blue Book](https://www.coxautoinc.com/brands/kelley-blue-book/) Electric Car Sales Reports published by Cox Automative Inc.\n", + "\n", + "You'll get practice calling functions from the `project` module, which we've provided, and practice writing your own functions.\n", + "\n", + "If you haven't already downloaded `project.py`, `p3_test.py`, and `car_sales_data.csv` (you can verify by running `ls` in a new terminal tab from your `p3` project directory). , please terminate the current `jupyter notebook` session, download all the required files, launch a `jupyter notebook` session again and click on *Kernel* > *Restart and Clear Output*. Start by executing all the cells (including the ones containing `import` statements).\n", + "\n", + "We won't explain how to use the `project` module here (i.e., the code in the `project.py` file). Refer to [lab3](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab3) to understand how the inspection process works and use the `help` function to learn about the various functions inside `project.py`. Feel free to take a look at the `project.py` code, if you are curious about how it works.\n", + "\n", + "This project consists of writing code to answer 20 questions." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f8a4f285", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "## Dataset:\n", + "\n", + "The dataset you will be working with for this project is reproduced here:\n", + "\n", + "|id|vehicle|2017|2018|2019|2020|2021|\n", + "|--|-------|----|----|----|----|----|\n", + "|958|Tesla Model S|26500|25745|15090|10125|17653|\n", + "|10|Chevy Volt|20349|18306|4915|67|16|\n", + "|64|Nissan Leaf|11230|14715|12365|9564|14239|\n", + "|977|Toyota Prius PHEV|20936|27595|23630|43525|59010|\n", + "|332|Ford Fusion Energi|9632|8074|7476|19402|3342|\n", + "|951|Tesla Model X|208|26100|19425|7375|22546|\n", + "\n", + "\n", + "This table lists 6 different electric vehicle models, and how many cars of each model were sold each year between 2017 and 2021 (inclusive of both years).\n", + "\n", + "The dataset is in the `car_sales_data.csv` file which you downloaded. Alternatively, you can open the `car_sales_data.csv` file, to look at the same data and verify answers to simple questions." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7910407a", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "## Project Requirements:\n", + "\n", + "You **may not** hardcode indices in your code. For example, if we ask how many Nissan Leaf cars were sold in 2019, you **must** obtain the answer with this code: `get_sales(get_id(\"Nissan Leaf\"), 2019)`. If you **do not** use `get_id` and instead use `get_sales(64, 2019)`, we'll **manually deduct** points from your autograder score on Gradescope during code review.\n", + "\n", + "For some of the questions, we'll ask you to write (then use) a function to compute the answer. If you compute the answer **without** creating the function we ask you to write, we'll **manually deduct** points from your autograder score on Gradescope, even if the way you did it produced the correct answer.\n", + "\n", + "Students are only allowed to use Python commands and concepts that have been taught in the course before the release of p3. In particular, you are **NOT** allowed to use Conditionals or Iteration on this project. We will **manually deduct** points from your autograder score on Gradescope otherwise.\n", + "\n", + "For more details on what will cause you to lose points during code review, please take a look at the [Grading rubric](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/blob/main/sum23/projects/p3/rubric.md)." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "04d5883c", + "metadata": {}, + "source": [ + "## Incremental Coding and Testing:\n", + "\n", + "You should always strive to do incremental coding. Incremental coding enables you to avoid challenging bugs. Always write a few lines of code and then test those lines of code, before proceeding to write further code. You can call the `print` function to test intermediate step outputs. **Store your final answer for each question in the variable recommended for each question.** This step is important because Otter grades your work by comparing the value of this variable against the correct answer. So, if you store your answer in a different variable, you will not get points for it.\n", + "\n", + "We also recommend you do incremental testing: make sure to run the local tests as soon as you are done with a question. This will ensure that you haven't made a big mistake that might potentially impact the rest of your project solution. Please refrain from making multiple submissions on Gradescope for testing individual questions' answers. Instead use the local tests, to test your solution on your laptop. \n", + "\n", + "That said, it is very **important** that you check the *Gradescope* test results as soon as you submit your project on Gradescope. Test results on *Gradescope* are typically available somewhere between 2 to 10 minutes after the submission." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0734c875", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "## Project Questions and Functions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7116a071", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# include the relevant import statements in this cell\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9001348c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# call the init function to load the dataset\n", + "\n", + "# you may call the dump function here to test if you have loaded the dataset correctly." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b0855d70", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 1:** What is the `id` of the *Toyota Prius PHEV*?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "471e2bf1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# replace the ... with your code\n", + "# INCORRECT METHOD prius_id = 977 => this is considered hardcoding\n", + "prius_id = ...\n", + "\n", + "prius_id" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bc08132", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q1\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7fd504f4", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "Instead of repeatedly calling `project.get_id` function for each question, make these calls once at the beginning of your notebook and save the results in variables. Recall that calling the same function multiple times with the same argument(s) is a waste of computation. Complete the code in the below cell and make sure to use the relevant ID variables for the rest of the project questions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "534224e1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "model_s_id = project.get_id('Tesla Model S') # we have done this for you\n", + "# replace the ... in the line below with code to get the id of 'Chevy Volt'\n", + "volt_id = ...\n", + "# invoke get_id for the other car models and store the result into similar variable names\n", + "\n", + "# considering that you already invokved get_id for Toyota Prius PHEV, you need to \n", + "# make 3 more function calls to store the ID for the rest of the vehicles\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "48566641", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 2:** How many *Nissan Leaf* cars were sold in *2017*?\n", + "\n", + "Your answer should just be a number (without any units at the end). You **should not** hardcode the ID of the car. You **must** use the variable that you used to store the ID of Nissan Leaf (assuming you already invoked `get_id` for all the car models in the cell right below Question 1)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f83b9e3f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# replace the ... with your code\n", + "num_leaf = ...\n", + "\n", + "num_leaf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02c76483", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q2\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4353acb3", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "### Function 1: `year_max(year)`\n", + "\n", + "This function will compute the highest number of sales for any model in the given `year`.\n", + "\n", + "It has already been written for you, so you do not have to modify it. You can directly call this function to answer the following questions. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68ceec70", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def year_max(year):\n", + " \"\"\"\n", + " year_max(year) computes the highest number of sales \n", + " for any model in the given year\n", + " \"\"\"\n", + " # get the sales of each model in the given year\n", + " model_s_sales = project.get_sales(project.get_id('Tesla Model S'), year)\n", + " volt_sales = project.get_sales(project.get_id('Chevy Volt'), year)\n", + " leaf_sales = project.get_sales(project.get_id('Nissan Leaf'), year)\n", + " prius_sales = project.get_sales(project.get_id('Toyota Prius PHEV'), year)\n", + " fusion_sales = project.get_sales(project.get_id('Ford Fusion Energi'), year)\n", + " model_x_sales = project.get_sales(project.get_id('Tesla Model X'), year)\n", + "\n", + " # use the built-in max function to get the maximum of the six values\n", + " return max(model_s_sales, volt_sales, leaf_sales, prius_sales, fusion_sales, model_x_sales)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f33786b6", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 3:** What was the highest number of sales for *any* model in the year *2017*?\n", + "\n", + "You **must** call the `year_max` function to answer this question." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7492b42", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# replace the ... with your code\n", + "max_sales_2017 = ...\n", + "\n", + "max_sales_2017" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68bac2c4", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q3\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "98e63c77", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 4:** What was the highest number of sales for *any* model in a single year in the period *2018-2020*?\n", + "\n", + "Recall that we can use the `max` function to compute the maximum of some values. Look at the lab examples where you used the `max` function or the `year_max` function definition. To be clear, the answer to this question is a single integer whose value is the highest sales number achieved by any model in a single year during these three years. You **must** invoke the `year_max` function in your answer to this question." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2c09476", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# replace the ... with your code\n", + "max_sales_2018_to_2020 = ...\n", + "\n", + "max_sales_2018_to_2020" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f9448b0", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q4\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "3f2ace5a", + "metadata": {}, + "source": [ + "### Function 2: `sales_min(model)`\n", + "\n", + "This function should compute the lowest number of sales in a year for the given `model` considering every year in the dataset (2017-2021).\n", + "\n", + "We'll help you get started with this function, but you need to fill in the rest of the function yourself." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18f18574", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def sales_min(model):\n", + " \"\"\"\n", + " sales_min(model) computes the lowest number of sales \n", + " in a year for the given model\n", + " \"\"\"\n", + " model_id = project.get_id(model) \n", + " sales_2017 = project.get_sales(model_id, 2017)\n", + " sales_2018 = project.get_sales(model_id, 2018)\n", + " # get the sales from other years\n", + " \n", + " # use the built-in min function (similar to the max function) to get the minimum across the \n", + " # five years and return that value\n", + " \n", + " min_sales_2017_to_2021 = ...\n", + " return min_sales_2017_to_2021" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "71fc6d6b", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 5:** What was the lowest number of sales for the *Tesla Model S* in a *single* year?\n", + "\n", + "You **must** call the `sales_min` function to answer this question." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f25caa1b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# replace the ... with your code\n", + "min_sales_model_s = ...\n", + "\n", + "min_sales_model_s" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c27ea52", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q5\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e4230b1d", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 6:** What was the lowest sales number in a *single* year between the *Chevy Volt*, *Ford Fusion Energi*, and the *Nissan Leaf*?\n", + "\n", + "Recall that we can use the `min` function to compute the minimum of some values. To be clear, the answer to this question is a single integer whose value is the lowest sales number achieved in a single year during this entire period between 2017-2021 by any of the 3 models mentioned. You **must** invoke the `sales_min` function in your answer to this question." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1ef390e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'min_sales_CV_FFE_NL'\n", + "\n", + "# display the variable 'min_sales_CV_FFE_NL' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5888492f", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q6\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "46a31062", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "### Function 3: `sales_avg(model) `\n", + "\n", + "This function should compute the average yearly sales number for the given `model` across the five years in the dataset (i.e. *2017 - 2021*).\n", + "\n", + "**Hint:** start by copy/pasting the `sales_min` function definition, and renaming your copy to `sales_avg` (this is not necessary, but it will save you time). \n", + "Instead of returning the minimum of `sales_2017`, `sales_2018`, etc., return the average of these by adding them together, then dividing by five. \n", + "**You may hardcode the number 5 for this computation**.\n", + "\n", + "The type of the *return value* should be `float`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfa38855", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# define the function 'sales_avg' here\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e923324a", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 7:** What was the average number of *Toyota Prius PHEV* cars sold per year between *2017* and *2021*?\n", + "\n", + "You **must** call the `sales_avg` function to answer this question." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb19bfa9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'sales_avg_prius_2017_to_2021'\n", + "\n", + "# display the variable 'sales_avg_prius_2017_to_2021' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd037ea5", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q7\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ff0c296a", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 8:** What was the average number of *Chevy Volt* cars sold per year between *2017* and *2021*?\n", + "\n", + "You **must** call the `sales_avg` function to answer this question." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0df4f0f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'sales_avg_volt_2017_to_2021'\n", + "\n", + "# display the variable 'sales_avg_volt_2017_to_2021' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f37a868", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q8\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "57fadb6d", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 9:** Relative to its 5-year average, how many more or fewer *Nissan Leaf* cars were sold in *2018*?\n", + "\n", + "**Hint:** Call the `sales_avg` function, to compare the *Nissan Leaf* average sales to the *Nissan Leaf* sales in *2018*. \n", + "Your answer will be a positive number if more Nissan Leafs were sold in 2018 than on average. Your answer will be a negative number if fewer Nissan Leafs were sold in 2018 than on average." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "283027ea", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'diff_leaf_2018_to_average'.\n", + "# it is recommended that you create more intermediary variables to make your code easier to write and read.\n", + "# some useful intermediary variables you could create are: 'leaf_id', 'num_sales_leaf_2018'.\n", + "\n", + "\n", + "# display the variable 'diff_leaf_2018_to_average' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e2d1c985", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q9\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c042f57e", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "### Function 4: `year_sum(year)`\n", + "\n", + "This function should compute the total number of sales across every model for the given `year`.\n", + "\n", + "You can start from the following code snippet:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb8d2a45", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def year_sum(year=2021): # DO NOT EDIT THIS LINE\n", + " \"\"\"\n", + " year_sum(year) computes the total number of sales \n", + " across every model for the given year\n", + " \"\"\"\n", + " pass # this statement tells Python to do nothing.\n", + " # since this function has no code inside, we have added the pass statement \n", + " # inside so the code does not crash.\n", + " # once you have added code to this function, you can (and should) \n", + " # remove the pass statement as it does nothing.\n", + " \n", + " # finish this function definition and return the total number of sales \n", + " # across every model for the given 'year'\n", + " " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c95936d8", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 10:** What was the *total* number of vehicles sold in *2021*?\n", + "\n", + "You **must** call the `year_sum` function to answer this question. Use the default argument (your call to `year_sum` function **should not** pass any arguments)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee16b185", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'sales_sum_2021'\n", + "\n", + "# display the variable 'sales_sum_2021' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9695b29a", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q10\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "04b95e64", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 11:** What was the *total* number of vehicles sold between *2019* and *2021*?\n", + "\n", + "You **must** invoke the `year_sum` function in your answer to this question. To be clear, the answer to this question is a single integer whose value is the total sales number achieved by all six models during these three years.\n", + "\n", + "You will **lose points** on this question if you use more arguments than necessary." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92f034d0", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'sales_sum_2019_to_2021'\n", + "\n", + "# display the variable 'sales_sum_2019_to_2021' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "455e53c5", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q11\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f6626e6b", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "### Function 5: `change_per_year(model, start_year, end_year)`\n", + "\n", + "This function should return the average increase/decrease in sales (could be positive if there's an increase, negative if there’s a decrease) over the period from `start_year` to `end_year` for the given `model`.\n", + "\n", + "The type of the *return value* should be `float`.\n", + "\n", + "We're not asking you to do anything complicated here; you just need to compute the difference in sales between the last year and the first year, then divide by the number of elapsed years. Recall that you created a similar function in the lab. You can start with the following code snippet (with the default arguments):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a378f98", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def change_per_year(model, start_year=2017, end_year=2021): # DO NOT EDIT THIS LINE\n", + " \"\"\"\n", + " change_per_year(model, start_year, end_year) computes the average increase/decrease in sales \n", + " (could be positive if there's an increase, negative if there’s a decrease) \n", + " over the period from start_year to end_year for the given model\n", + " \"\"\"\n", + " pass # as before, you should delete this statement after finishing your function.\n", + " \n", + " # TODO: compute and return the change per year in sales of the model between start_year and end_year\n", + " # TODO: it is recommended that you create intermediary variables to make your code easier to write and read.\n", + " # TODO: some useful intermediary variables you could create are: \n", + " # 'sales_start_year', 'sales_end_year', 'sales_difference'.\n", + " " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7272fc2d", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 12:** How much have the sales of the *Ford Fusion Energi* changed per year (on average) from *2017* to *2021*?\n", + "\n", + "You **must** call the `change_per_year` function to answer this question. Use the default arguments (your call to `change_per_year` function **must not** pass any more arguments than is absolutely necessary)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39df41b1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'fusion_average_change'\n", + "\n", + "# display the variable 'fusion_average_change' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "529049d8", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q12\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6120fc92", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 13:** How much have the sales of the *Chevy Volt* changed per year (on average) from *2018* to *2021*?\n", + "\n", + "You **must** call the `change_per_year` function to answer this question. Use the default arguments (your call to `change_per_year` function **should not** pass any more arguments than is absolutely necessary)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b0ebb4f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'volt_average_change'\n", + "\n", + "# display the variable 'volt_average_change' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "610596ce", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q13\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4adf4b13", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 14:** How much have the sales of the *Tesla Model X* changed per year (on average) from *2017* to *2020*?\n", + "\n", + "You **must** call the `change_per_year` function to answer this question. Use the default arguments (your call to `change_per_year` function **should not** pass any more arguments than is absolutely necessary)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4dddce3e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'model_x_average_change'\n", + "\n", + "# display the variable 'model_x_average_change' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8f81fd9", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q14\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0a72e53e", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "### Function 6: `estimate_sales(model, target_year, start_year, end_year)`\n", + "\n", + "This function should estimate what the sales would be for the given `model` in the given `target_year` assuming that there is a constant rate of change in the sales after `end_year` that is equal to the average change per year in the period between `start_year` and `end_year`.\n", + "\n", + "The type of the *return value* should be `float`.\n", + "\n", + "You **must** define `estimate_sales` so that the parameter `start_year` has the default argument `2017` and `end_year` has the default argument `2021`.\n", + "\n", + "You **must** call the `change_per_year` function in the definition of `estimate_sales`. **Do not** manually compute the average change in sales." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94b56287", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# define the function estimate_sales(model, target_year, start_year, end_year) here.\n", + "# it should return the estimated sales of the model in target_year based on the change in \n", + "# sales between start_year and end_year.\n", + "# it is recommended that you create intermediary variables to make your code easier to write and read.\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ed7d14af", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 15:** What are the estimated sales for the *Nissan Leaf* in *2025* based on the average change in sales per year for it between *2017* and *2021*?\n", + "\n", + "You **must** call the `estimate_sales` function to answer this question. Use the default arguments if possible (your call to `estimate_sales` function **should not** pass any more arguments than is absolutely necessary)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dede0030", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'leaf_sales_in_2025'\n", + "\n", + "# display the variable 'leaf_sales_in_2025' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa7204fd", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q15\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6e912cc8", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 16:** What are the estimated sales for the *Toyota Prius PHEV* in *2026* based on the average change in sales per year for it between *2018* and *2020*?\n", + "\n", + "You **must** call the `estimate_sales` function to answer this question. Use the default arguments if possible (your call to `estimate_sales` function **should not** pass any more arguments than is absolutely necessary)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3cc23ed4", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'prius_sales_in_2026'\n", + "\n", + "# display the variable 'prius_sales_in_2026' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb206e30", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q16\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9d8cf368", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 17:** What is the difference between estimated sales for the *Tesla Model X* in *2030* based on the average change per year between *2017* and *2020* and between *2017* and *2021*?\n", + "\n", + "You **must** invoke the `estimate_sales` function in your answer to this question. Use the default arguments if possible (your call to `estimate_sales` function **should not** pass any more arguments than is absolutely necessary). A positive answer implies that the estimate based on the sales between *2017* and *2020* is higher, while a negative answer implies that it is lower." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b131642", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'diff_sales_model_x_2030'\n", + "\n", + "# display the variable 'diff_sales_model_x_2030' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "152cb2d5", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q17\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7d11494c", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 18:** What is the difference between estimated sales for the *Nissan Leaf* in *2030* based on the average change per year between *2017* and *2019* and between *2018* and *2019*?\n", + "\n", + "You **must** invoke the `estimate_sales` function in your answer to this question. Use the default arguments if possible (your call to `estimate_sales` function **should not** pass any more arguments than is absolutely necessary). A positive answer implies that the estimate based on the sales between *2017* and *2019* is higher, while a negative answer implies that it is lower." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a34556e2", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'diff_sales_leaf_2030'\n", + "\n", + "# display the variable 'diff_sales_leaf_2030' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b9a6b3f", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q18\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "54d9c934", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "The wild answers we get to **Question 17** and **Question 18** suggest that our function `estimated_sales` is not very good at estimating the sales of any model in the future. This is not surprising since it is clearly not reasonable to assume that the rate of change in sales will remain constant over a period of time. We will now try to see how much the change per year in the sales of the models varies over time." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d7be4fe7", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 19:** What is the difference in change per year of *Chevy Volt* sales between the time periods of *2019* to *2021* and *2017* to *2018*?\n", + "\n", + "You **must** invoke the `change_per_year` function in your answer to this question. Use the default arguments if possible (your call to `change_per_year` function **should not** pass any more arguments than is absolutely necessary). A positive answer would imply that more cars were sold each year on average during the period *2019-2021* than during the period *2017-2018*, while a negative answer would imply that fewer cars were sold during the period *2019-2021*." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60aefae5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'volt_diff_change_per_year'\n", + "\n", + "# display the variable 'volt_diff_change_per_year' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb52dec9", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q19\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "eec9b3f5", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "**Question 20:** What is, for the *Toyota Prius PHEV* sales, the ratio of the change per year between *2019* and *2020* to the change per year between *2017* and *2021*?\n", + "\n", + "You **must** invoke the `change_per_year` function in your answer to this question. Use the default arguments if possible (your call to `change_per_year` function **should not** pass any more arguments than is absolutely necessary). A value *greater than 1* here would imply that on average, more cars were sold each year during the period *2019-2020* than normal, while a value *less than 1* would imply that on average, fewer cars were sold each year during the period *2019-2020* than normal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fdc8782", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# compute and store the answer in the variable 'prius_change_per_year_ratio'\n", + "\n", + "# display the variable 'prius_change_per_year_ratio' here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "053c7edf", + "metadata": { + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "grader.check(\"q20\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f2f3db9f", + "metadata": { + "deletable": false, + "editable": false + }, + "source": [ + "## Submission\n", + "It is recommended that at this stage, you Restart and Run all Cells in your notebook.\n", + "That will automatically save your work and generate a zip file for you to submit.\n", + "\n", + "**SUBMISSION INSTRUCTIONS**:\n", + "1. **Upload** the zipfile to Gradescope.\n", + "2. Check **Gradescope otter** results as soon as the auto-grader execution gets completed. Don't worry about the score showing up as -/100.0. You only need to check that the test cases passed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01da6654", + "metadata": { + "cell_type": "code", + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "# running this cell will create a new save checkpoint for your notebook\n", + "from IPython.display import display, Javascript\n", + "display(Javascript('IPython.notebook.save_checkpoint();'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bd03170", + "metadata": { + "cell_type": "code", + "deletable": false, + "editable": false + }, + "outputs": [], + "source": [ + "p3_test.check_file_size(\"p3.ipynb\")\n", + "grader.export(pdf=False, run_tests=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "cdfa26fa", + "metadata": { + "deletable": false, + "editable": false + }, + "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.10.6" + }, + "otter": { + "OK_FORMAT": true, + "tests": { + "q1": { + "name": "q1", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q1\", prius_id)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q10": { + "name": "q10", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q10\", sales_sum_2021)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q11": { + "name": "q11", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q11\", sales_sum_2019_to_2021)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q12": { + "name": "q12", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q12\", fusion_average_change)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q13": { + "name": "q13", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q13\", volt_average_change)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q14": { + "name": "q14", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q14\", model_x_average_change)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q15": { + "name": "q15", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q15\", leaf_sales_in_2025)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q16": { + "name": "q16", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q16\", prius_sales_in_2026)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q17": { + "name": "q17", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q17\", diff_sales_model_x_2030)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q18": { + "name": "q18", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q18\", diff_sales_leaf_2030)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q19": { + "name": "q19", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q19\", volt_diff_change_per_year)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q2": { + "name": "q2", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q2\", num_leaf)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q20": { + "name": "q20", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q20\", prius_change_per_year_ratio)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q3": { + "name": "q3", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q3\", max_sales_2017)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q4": { + "name": "q4", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q4\", max_sales_2018_to_2020)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q5": { + "name": "q5", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q5\", min_sales_model_s)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q6": { + "name": "q6", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q6\", min_sales_CV_FFE_NL)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q7": { + "name": "q7", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q7\", sales_avg_prius_2017_to_2021)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q8": { + "name": "q8", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q8\", sales_avg_volt_2017_to_2021)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + }, + "q9": { + "name": "q9", + "points": 5, + "suites": [ + { + "cases": [ + { + "code": ">>> p3_test.check(\"q9\", diff_leaf_2018_to_average)\nTrue", + "hidden": false, + "locked": false + } + ], + "scored": true, + "setup": "", + "teardown": "", + "type": "doctest" + } + ] + } + } + }, + "vscode": { + "interpreter": { + "hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sum23/projects/p3/p3_test.py b/sum23/projects/p3/p3_test.py new file mode 100644 index 0000000000000000000000000000000000000000..ec2b1092bce4fa03f5c89e6d3449317bb0bb35d6 --- /dev/null +++ b/sum23/projects/p3/p3_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +import os, json, math + +MAX_FILE_SIZE = 500 # units - KB +REL_TOL = 6e-04 # relative tolerance for floats +ABS_TOL = 15e-03 # absolute tolerance for floats + +PASS = "PASS" + +TEXT_FORMAT = "text" # question type when expected answer is a str, int, float, or bool + +expected_json = {"1": (TEXT_FORMAT, 977), + "2": (TEXT_FORMAT, 11230), + "3": (TEXT_FORMAT, 26500), + "4": (TEXT_FORMAT, 43525), + "5": (TEXT_FORMAT, 10125), + "6": (TEXT_FORMAT, 16), + "7": (TEXT_FORMAT, 34939.2), + "8": (TEXT_FORMAT, 8730.6), + "9": (TEXT_FORMAT, 2292.3999999999996), + "10": (TEXT_FORMAT, 116806), + "11": (TEXT_FORMAT, 289765), + "12": (TEXT_FORMAT, -1572.5), + "13": (TEXT_FORMAT, -6096.666666666667), + "14": (TEXT_FORMAT, 2389.0), + "15": (TEXT_FORMAT, 17248.0), + "16": (TEXT_FORMAT, 91315.0), + "17": (TEXT_FORMAT, -41541.5), + "18": (TEXT_FORMAT, 32092.5), + "19": (TEXT_FORMAT, -406.5), + "20": (TEXT_FORMAT, 2.090140253191154)} + +def check_cell(qnum, actual): + format, expected = expected_json[qnum[1:]] + try: + if format == TEXT_FORMAT: + return simple_compare(expected, actual) + else: + if expected != actual: + return "expected %s but found %s " % (repr(expected), repr(actual)) + except: + if expected != actual: + return "expected %s" % (repr(expected)) + return PASS + + +def simple_compare(expected, actual, complete_msg=True): + msg = PASS + if type(expected) == type: + if expected != actual: + if type(actual) == type: + msg = "expected %s but found %s" % (expected.__name__, actual.__name__) + else: + msg = "expected %s but found %s" % (expected.__name__, repr(actual)) + elif type(expected) != type(actual) and not (type(expected) in [float, int] and type(actual) in [float, int]): + msg = "expected to find type %s but found type %s" % (type(expected).__name__, type(actual).__name__) + elif type(expected) == float: + if not math.isclose(actual, expected, rel_tol=REL_TOL, abs_tol=ABS_TOL): + msg = "expected %s" % (repr(expected)) + if complete_msg: + msg = msg + " but found %s" % (repr(actual)) + else: + if expected != actual: + msg = "expected %s" % (repr(expected)) + if complete_msg: + msg = msg + " but found %s" % (repr(actual)) + return msg + +def check(qnum, actual): + msg = check_cell(qnum, actual) + if msg == PASS: + return True + print("<b style='color: red;'>ERROR:</b> " + msg) + +def check_file_size(path): + size = os.path.getsize(path) + assert size < MAX_FILE_SIZE * 10**3, "Your file is too big to be processed by Gradescope; please delete unnecessary output cells so your file size is < %s KB" % MAX_FILE_SIZE diff --git a/sum23/projects/p3/project.py b/sum23/projects/p3/project.py new file mode 100644 index 0000000000000000000000000000000000000000..50eaea9dc7f9f45820cf6c45f76fdd7bdf7e8a02 --- /dev/null +++ b/sum23/projects/p3/project.py @@ -0,0 +1,76 @@ +import csv as __csv__ + +__id_to_data__ = None +__name_to_id__ = None +__years__ = None + + +def init(path): + """init(path) must be called to load data before other calls will work. You should call it like this: init("car_sales_data.csv") or init("lab.csv")""" + + global __id_to_data__ + global __name_to_id__ + global __years__ + + if path != 'car_sales_data.csv': + print("WARNING! Opening a path other than car_sales_data.csv. " + + "That's fine for testing your code yourself, but car_sales_data.csv " + + "will be the only file around when we test your code " + + "for grading.") + + __id_to_data__ = {} + __name_to_id__ = {} + __years__ = [] + + f = open(path, encoding='utf-8') + raw_data = list(__csv__.reader(f)) + f.close() + + id_i = raw_data[0].index('id') + vehicle_i = raw_data[0].index('vehicle') + for head in raw_data[0]: + if head not in ('id', 'vehicle'): + __years__.append(int(head)) + for car in raw_data[1:]: + __name_to_id__[car[vehicle_i]] = car[id_i] + __id_to_data__[car[id_i]] = {} + for i in range(len(car)): + if i == id_i: + continue + elif i == vehicle_i: + __id_to_data__[car[id_i]][raw_data[0][i]] = car[i] + else: + __id_to_data__[car[id_i]][raw_data[0][i]] = int(car[i]) + + +def dump(): + """prints all the data to the screen""" + if __id_to_data__ == None: + raise Exception("you did not call init first") + + for car in sorted(__name_to_id__.keys()): + car_id = __name_to_id__[car] + print("%s [ID: %s]" % (car, car_id)) + for year in __years__: + print(" %s: %d cars sold" % (year, __id_to_data__[car_id][str(year)])) + print() + +def get_id(car): + """get_id(car) returns the id of the specified car model.""" + if __name_to_id__ == None: + raise Exception("you did not call init first") + if not car in __name_to_id__: + raise Exception("No car '%s', only these: %s" % + (str(car), ', '.join(list(__name_to_id__.keys())))) + return int(__name_to_id__[car]) + +def get_sales(car_id, year=2019): + """get_sales(car_id, year) returns the number of cars of the specified model sold in the specified year.""" + if __id_to_data__ == None: + raise Exception("you did not call init first") + if str(car_id) not in list(__id_to_data__.keys()): + raise Exception("%s is not an id of any car in the dataset. Did you call get_id?" % (str(car_id))) + if not str(car_id) in __id_to_data__ or str(year) not in __id_to_data__[str(car_id)]: + raise Exception("No data for car %s, in year %s" % + (str(car_id), str(year))) + return __id_to_data__[str(car_id)][str(year)] diff --git a/sum23/projects/p3/rubric.md b/sum23/projects/p3/rubric.md new file mode 100644 index 0000000000000000000000000000000000000000..367f3fb84ca7e3f4769c0fbba01855db804be9e4 --- /dev/null +++ b/sum23/projects/p3/rubric.md @@ -0,0 +1,137 @@ +# Project 3 (P3) grading rubric + +## Code reviews + +- A TA / grader will be reviewing your code after the deadline. +- They will make deductions based on the Rubric provided below. +- To ensure that you don't lose any points in code review, you must review the rubric and make sure that you have followed the instructions provided in the project correctly. + +## Rubric + +### General guidelines: + +- Did not save the notebook file prior to running the cell containing "export". We cannot see your output if you do not save before generating the zip file. This deduction will become stricter for future projects. (-1) + +### Question specific guidelines: + +- Q1 deductions + + - `prius_id` variable is hard coded as 977 (-5) + +- Q2 deductions + + - `num_leaf` variable is hard coded as 11230 (-5) + - output of `get_id` function is not used as input to `get_sales` function (-3) + +- Q3 deductions + + - `max_sales_2017` variable is hard coded as 26500 (-5) + - `year_max` function is not used (-3) + - conditionals/iterations are used to get output (-2) + +- Q4 deductions + + - `max_sales_2016_to_2018` variable is hard coded as 43525 (-5) + - `year_max` function is not used (-3) + - max function is not used or conditionals/iterations are used to get output (-2) + +- Q5 deductions + + - `min_sales_model_s` variable is hard coded as 10125 (-5) + - `sales_min` function is not used (-3) + - min function is not used in `sales_min` function or conditionals/iterations are used to get output (-2) + +- Q6 deductions + + - `min_sales_CV_FFE_NL` variable is hard coded as 16 (-5) + - `sales_min` function is not used (-3) + - min function is not used or conditionals/iterations are used to get output (-2) + +- Q7 deductions + + - `sales_avg_prius_2017_to_2021` variable is hard coded as 34939.2 (-5) + - `sales_avg` function is not used or conditionals/iterations are used to get output (-3) + - `get_id` function is not used in `sales_avg` function (-1) + - `get_sales` function is not used in `sales_avg` function (-1) + +- Q8 deductions + + - `sales_avg_volt_2017_to_2021` variable is hard coded as 8730.6 (-5) + - `sales_avg` function is not used or conditionals/iterations are used to get output (-3) + +- Q9 deductions + + - `diff_leaf_2018_to_average` variable is hard coded as 2292.3999999999996 (-5) + - `sales_avg` function is not used or conditionals/iterations are used to get output (-3) + - `get_sales` function is not used for getting Nissan Leaf car sales (-1) + +- Q10 deductions + + - `sales_sum_2021` variable is hard coded as 116806 (-5) + - `year_sum` function is not used (-3) + - Passed more arguments than necessary to `year_sum` function (-1) + - Default value for year=2021 is changed in `year_sum` function (-1) + +- Q11 deductions + + - `sales_sum_2019_to_2021` variable is hard coded as 289765 (-5) + - `year_sum` function is not used (-3) + - Passed more arguments than necessary to `year_sum` function (-1) + +- Q12 deductions + + - `fusion_average_change` variable is hard coded as -1572.5 (-5) + - `change_per_year` function is not used (-3) + - Passed more arguments than necessary to `change_per_year` function (-1) + - Default values for `start_year`=2017, `end_year`=2021 are changed in `change_per_year` function (-1) + - `get_id` function is not used in `change_per_year` function (-1) + - `get_sales` function is not used in `change_per_year` function (-1) + +- Q13 deductions + + - `volt_average_change` variable is hard coded as -6096.666666666667 (-5) + - `change_per_year` function is not used (-3) + - Passed more arguments than necessary to `change_per_year` function (-1) + +- Q14 deductions + + - `model_x_average_change` variable is hard coded as 2389.0 (-5) + - `change_per_year` function is not used (-3) + - Passed more arguments than necessary to `change_per_year` function (-1) + +- Q15 deductions + + - `leaf_sales_in_2025` variable is hard coded as 17248.0 (-5) + - `estimate_sales` function is not used (-3) + - `change_per_year` function is not used in `estimate_sales` function (-3) + - Passed more arguments than necessary to `estimate_sales` function (-1) + - Default values for `start_year`=2017 and `end_year`=2021 are not specified in `estimate_sales` function (-1) + +- Q16 deductions + + - `prius_sales_in_2026` variable is hard coded as 91315.0 (-5) + - `estimate_sales` function is not used (-3) + - Required arguments are not passed to `estimate_sales` function (-1) + +- Q17 deductions + + - `diff_sales_model_x_2030` variable is hard coded as -41541.5 (-5) + - `estimate_sales` function is not used (-3) + - Passed more arguments than necessary to `estimate_sales` function (-1) + +- Q18 deductions + + - `diff_sales_leaf_2030` variable is hard coded as 32092.5 (-5) + - `estimate_sales` function is not used (-3) + - Passed more arguments than necessary to `estimate_sales` function (-1) + +- Q19 deductions + + - `volt_diff_change_per_year` variable is hard coded as -406.5 (-5) + - `change_per_year` function is not used (-3) + - Passed more arguments than necessary to `change_per_year` function (-1) + +- Q20 deductions + - `prius_change_per_year_ratio` variable is hard coded as 2.090140253191154 (-5) + - `change_per_year` function is not used (-3) + - Passed more arguments than necessary to `change_per_year` function (-1)