diff --git a/.gitignore b/.gitignore index 667f0ec..1b03ad5 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,3 @@ Session_9/.ipynb_checkpoints/exercises_9_solutions-checkpoint.ipynb Session_2/.ipynb_checkpoints/exercises_2-checkpoint.ipynb Session_3/.ipynb_checkpoints/exercises_3-checkpoint.ipynb Session_3/.ipynb_checkpoints/Readme-checkpoint.md -.* -~* \ No newline at end of file diff --git a/README.md b/README.md index c1cf2d4..4177656 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ # Class Schedule This repository contains the folders with the content of each class. Please check them for the references of each meeting. -The schedule goes as follows (**always 10-12AM in room R42.3.103**). +The schedule goes as follows (**always 10-12AM in room R42.3.103**) | Session | Date | Discussant | Topic | References | | ------------- | -------------|-------------|-------------| ----------------------------------------------------------------------------------------------------------------------------------- | | [Session 1](https://github.com/Python-do-ECARES/Classes/tree/master/Session_1) | 11/02/2020 | Glenn | Reproducible research, automation and introduction to the course | Slides / [Gentzkow and Shapiro](https://web.stanford.edu/~gentzkow/research/CodeAndData.pdf)| | [Session 2](https://github.com/Python-do-ECARES/Classes/tree/master/Session_2) | 18/02/2020 | Fabrizio | Jupyter (Anaconda), Git, GitHub, GitHub Desktop | Slides / [QuantEcon](https://python.quantecon.org/getting_started.html) | | [Session 3](https://github.com/Python-do-ECARES/Classes/tree/master/Session_3) | 25/02/2020 | Federico | Variables, numbers, strings, lists, functions, tuples, sets, dictionaries, lists comprehension, for and while loops, if statements, other logical operators | [Udemy - Section 1:"Intro to Python" and Section 2:"Python fundamentals"](https://www.udemy.com/course/the-complete-python-course/learn/lecture/9412506#overview), [QuantEcon - An Introductory Example](https://python.quantecon.org/python_by_example.html) and [Python Essentials](https://python.quantecon.org/python_essentials.html) | -| [Session 4](https://github.com/Python-do-ECARES/Classes/tree/master/Session_4) | 03/03/2020 | Alberto, Marco & Giampaolo | Loops and Functions (Part 2) | | -| [Session 5](https://github.com/Python-do-ECARES/Classes/tree/master/Session_5) | 10/03/2020 | Angela, Moritz & Thomas |APIs| [Udemy - Section 16:"Interacting with APIs with Python"](https://www.udemy.com/course/the-complete-python-course/learn/lecture/9412506#overview) | +| [Session 4](https://github.com/Python-do-ECARES/Classes/tree/master/Session_4) | 03/03/2020 | | Classes, handling errors (including try and except), files | [Udemy - Section 4:"Object-Oriented Programming with Python", Section 5:"Errors in Python", Section 6:"Files in Python"](https://www.udemy.com/course/the-complete-python-course/learn/lecture/9412506#overview), [QuantEcon - OOP I](https://python.quantecon.org/oop_intro.html), [Building Classes](https://python.quantecon.org/python_oop.html) and [Debugging](https://python.quantecon.org/debugging.html) | +| [Session 5](https://github.com/Python-do-ECARES/Classes/tree/master/Session_5) | 10/03/2020 | Moritz |APIs| [Udemy - Section 16:"Interacting with APIs with Python"](https://www.udemy.com/course/the-complete-python-course/learn/lecture/9412506#overview) | | [Session 6](https://github.com/Python-do-ECARES/Classes/tree/master/Session_6) | 17/03/2020 | Charles | Web Scraping, regular expressions, Selenium| [Udemy - Section 10:"Advanced Python Development", Section 11:"Web Scraping with Python", Section 12:"Browser Automation with Selenium"](https://www.udemy.com/course/the-complete-python-course/learn/lecture/9412506#overview) | | [Session 7](https://github.com/Python-do-ECARES/Classes/tree/master/Session_7) | 24/03/2020 | Cristina & Remi | Pandas | [QuantEcon - Pandas](https://python.quantecon.org/pandas.html) and [QuantEcon- DataScience](https://datascience.quantecon.org/pandas/) | | Homework | *Easter Break*| | | | -| [Session 8](https://github.com/Python-do-ECARES/Classes/tree/master/Session_8) | 21/04/2020 | Charles and Fabrizio | Discussion Easter projects | | -| [Session 9](https://github.com/Python-do-ECARES/Classes/tree/master/Session_9) | 28/04/2020 | Domenico | Numpy and Numba | [QuantEcon - Numpy](https://python.quantecon.org/numpy.html) and [QuantEcon - Numba](https://python.quantecon.org/numba.html) | | +| [Session 8](https://github.com/Python-do-ECARES/Classes/tree/master/Session_8) | 21/04/2020 | | Discussion Easter homework | | +| [Session 9](https://github.com/Python-do-ECARES/Classes/tree/master/Session_9) | 28/04/2020 | | Numpy and Numba | [QuantEcon - Numpy](https://python.quantecon.org/numpy.html) and [QuantEcon - Numba](https://python.quantecon.org/numba.html) | | | [Session 10](https://github.com/Python-do-ECARES/Classes/tree/master/Session_10) | 12/05/2020 | | Scipy | [QuantEcon - Scipy](https://python.quantecon.org/scipy.html) and [Scipy.optimize](https://docs.scipy.org/doc/scipy/reference/optimize.html) | | -| [Session 11](https://github.com/Python-do-ECARES/Classes/tree/master/Session_11) | 19/05/2020 | Yasmine | Visualisation (matplotlib) | [QuantEcon- Matplotlib](https://python.quantecon.org/matplotlib.html) | -| [Session 12](https://github.com/Python-do-ECARES/Classes/tree/master/Session_12) | 26/05/2020 | Glenn & Fabrizio | Intro to Machine Learning | [QuantEcon DataScience](https://datascience.quantecon.org/applications/ml_in_economics.html) and TBD | +| [Session 11](https://github.com/Python-do-ECARES/Classes/tree/master/Session_11) | 19/05/2020 | | Visualisation (matplotlib) | [QuantEcon- Matplotlib](https://python.quantecon.org/matplotlib.html) | +| [Session 12](https://github.com/Python-do-ECARES/Classes/tree/master/Session_12) | 26/05/2020 | | Intro to Machine Learning | [QuantEcon DataScience](https://datascience.quantecon.org/applications/ml_in_economics.html) and TBD | diff --git a/Session_11/Readme.md b/Session_11/Readme.md.txt similarity index 100% rename from Session_11/Readme.md rename to Session_11/Readme.md.txt diff --git a/Session_12/Readme.md b/Session_12/Readme.md.txt similarity index 100% rename from Session_12/Readme.md rename to Session_12/Readme.md.txt diff --git a/Session_3/Slides_3_solutions.ipynb b/Session_3/Slides_3_solutions.ipynb deleted file mode 100644 index 01b6ccd..0000000 --- a/Session_3/Slides_3_solutions.ipynb +++ /dev/null @@ -1,1609 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Session 3: introduction to Python\n", - "We will cover (more details about the topics below are available in the [Python Bible](https://docs.python.org/3.7/library/stdtypes.html)):\n", - "* Numeric types, *int* and *float*, *booleans* operators and *strings* \n", - "* Containers: *dictionaries*, *lists*, *sets*, *tuples*\n", - " * We will not cover other containers, you can find them [here](https://docs.python.org/3.7/library/collections.html)\n", - "* Introduction to functions, which we will cover more in-depth next week\n", - "* Loops\n", - "\n", - "First, let's see the solutions to the exercises" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "# RISE: slideshow using jupyter notebook\n", - "* Step 1: Follow the installation procedure in the [RISE webpage: Installation](https://rise.readthedocs.io/en/stable/installation.html)\n", - " * If you don't use conda, consider using virtual environments ([pipenv](https://pipenv-fork.readthedocs.io/en/latest/)) instead of pip\n", - "* Step 2: Write your code on jupyter lab or jupyter notebook (you can also use other editors, but you will have to organise the code after)\n", - "* Step 3: Open jupyter notebook\n", - "* Step 2: From the \"View\" tab select \"Cell Toolbar -> Slideshow\"\n", - "* Step 5: Organise the slide type for each block of content (details for this on the [RISE webpage: Usage](https://rise.readthedocs.io/en/stable/usage.html))\n", - "* Step 6: Use shortcuts or the \"Enter/Exit RISE slideshow\" button in your jupyter notebook to start the presentation" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Exercise 1: Variables, Numbers and Strings\n", - "\n", - "You have a variable of type *int* and another one of type *float*.\n", - "* They are both numeric types\n", - "* *float* is used for floating-point numbers\n", - " * We insert decimal floating-point numbers, and the computer approximates them to base 2 fractions\n", - "* *int* is for integer numbers\n", - "* You can also write complex numbers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "a = 40\n", - "b = 4.0\n", - "print(type(a))\n", - "print(type(b))\n", - "# Otherwise, you can write print(type(40)) and print(type(4.0)) instead of assigning values to variables" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Convert the integer *a* to a *float*, and viceversa." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "a = float(a)\n", - "print(type(a))\n", - "b = int(b)\n", - "print(type(b))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "The function *int()* truncates *float* numbers, and truncating a number is different from rounding it" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "print(b)\n", - "# Remember that b as float is 4.0\n", - "temp = 4.6\n", - "print(temp)\n", - "temp = int(temp)\n", - "print(temp)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Sum, subtract, multiply and divide the two variables above by one another. Print the output of each operation. Notice the type of the output." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "c = a + b\n", - "print(c)\n", - "d = a - b\n", - "print(d)\n", - "e = a * b\n", - "print(e)\n", - "f = a / b\n", - "print(f)\n", - "# You can take an exponent using two asterisks\n", - "print(a ** b)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "Now, *a* is a *float* and *b* is an *integer*. Divide them by one another to get an *integer*. (Hint: a / b won't work. and \"/\" is different from \"//\" )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "a = int(a)\n", - "g = a // b\n", - "print(g)\n", - "print(type(g))\n", - "# The operation \"//\" is a floored quotient, meaning that it rounds the result to the greates integer below the floating result.\n", - "# For example, you can try to change the numerator to (a + 11) and check the output " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "Let's now move onto **strings**. Create two strings, one with the text *Hello* and the other with *World*. Print them." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "string_1 = \"Hello\"\n", - "string_2 = \"World\"\n", - "print(string_1)\n", - "print(string_2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "# There are a lot of things that you can do using strings, just to mention a few of them:\n", - "# Concatenate strings\n", - "print(string_1 + string_2)\n", - "# The output does not include a space, you can write print(string_1 + \" \" + string_2) to include it, or\n", - "print(\" \".join([string_1, string_2]))\n", - "# Add a string multiple times to itself\n", - "print(string_1 * 4)\n", - "# Slice the string\n", - "print(string_1[0:2])\n", - "# Get the number of elements in the string\n", - "print(len(string_1))\n", - "temp_2=\"Hello!\"\n", - "print(len(temp_2))\n", - "# Check if a string is part of another string!\n", - "print(\"He\" in string_1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Below a brief introduction to formatted string literals:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "temp_name = \"Fede\"\n", - "temp_age = 24\n", - "print(f\"Name: {temp_name}; age: {temp_age}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "This might look useless for now, but wait for it!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Exercise 2: Lists\n", - "\n", - "Create a list including *a*, *b*, and *\"Hello, World!\"*. Print the entire list and its third element separately. (Hint = the index of the first element in Python is 0)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "list_1 = [a, b, string_1 + \", \" + string_2 +\"!\"]\n", - "print(list_1)\n", - "print(type(list_1))\n", - "print(list_1[2])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "Remove the element that is not a number, and replace it with an *int*." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "list_1.remove(list_1[2])\n", - "list_1.append(8)\n", - "print(list_1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "Print the length of the list defined above." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "print(len(list_1))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true, - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "# Add a list to itself multiple times\n", - "print(f\"{list_1 * 3} \\nThe length of this list is: {len(list_1 * 3)}\")\n", - "# Check if an element is in a list or not\n", - "print(8.0 in list_1)\n", - "print(8 not in list_1)\n", - "# List slicing\n", - "print(list_1[0])\n", - "print(list_1[0:2])\n", - "# Append an item. Remember that if you try to append an item using temp_list[3].append(40) you get an error\n", - "# You can use temp_list = list_1[:] instead of the copy method\n", - "temp_list = list_1.copy()\n", - "temp_list.append(4)\n", - "# Check the occurrences of an element in a list\n", - "print(temp_list.count(4))\n", - "# Check the min in the list (can use max(temp_list) for the max)\n", - "print(min(temp_list))\n", - "# The remove method removes the first item in the list with the specified value\n", - "print(temp_list)\n", - "temp_list.remove(4)\n", - "print(temp_list)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "temp_list = list_1.copy()\n", - "temp_list.append(4)\n", - "# You can also use \".pop\" and del to remove items in a different way\n", - "print(temp_list.pop(1))\n", - "print(temp_list)\n", - "del temp_list[1]\n", - "print(temp_list)\n", - "# For delete you can also use list slicing with steps\n", - "temp_list2 = list(range(10))\n", - "print(temp_list2)\n", - "del temp_list2[0:10:2]\n", - "print(temp_list2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "# You can also create a list of lists (a matrix)\n", - "temp_list3 = [list_1] * 3\n", - "print(temp_list3)\n", - "# The first element of this list is a list. You can slice the first element of the first list\n", - "print(temp_list3[0])\n", - "print(temp_list3[0][0])\n", - "temp_list3.remove([40, 4, 8])\n", - "print(temp_list3)\n", - "temp_list3.append([20, 2, 4])\n", - "print(temp_list3)\n", - "print(temp_list3.pop(2))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "#### List comprehension" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "temp_list4 = [x for x in list_1]\n", - "print(temp_list4)\n", - "# This gives an outcome similar to the method .copy mentioned above\n", - "temp_list5 = [x for x in range(10)]\n", - "print(temp_list5)\n", - "temp_list6 = [x for x in temp_list5 if temp_list5[x] % 2 is 0]\n", - "print(temp_list6)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "# We can use the list index in a f string\n", - "temp_list_name = [\"Fede\", \"Ale\"]\n", - "temp_list_age = [24, 27]\n", - "print(f\"Name: {temp_list_name[0]}; Age: {temp_list_age[0]} \\nName: {temp_list_name[1]}; Age: {temp_list_age[1]}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Exercise 3: Tuples, sets and dictionaries\n", - "\n", - "Create a tuple and a dictionary including a, b, and \"Hello, World!\"." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tuple_1 = (a, b, string_1 + \", \" + string_2 +\"!\")\n", - "print(tuple_1)\n", - "dict_1 = {'int_1': a, 'int_2': b, 'string_1': string_1 + \", \" + string_2 +\"!\"}\n", - "print(dict_1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The dictionary includes *key: value* pairs, and the keys within a dictionary must be unique. You can use strings or numbers as keys, but also tuples that contain strings, numbers, or other tuples." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "The tuples are immutable objects, meaning that: \"Such an object cannot be altered. A new object has to be created if a different value has to be stored.\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(tuple_1[0])\n", - "tuple_1[0] = 20" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "\n", - "Add another *int* to the tuple." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tuple_1 += (8,)\n", - "print(tuple_1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "You can include lists inside a tuple" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "temp_tuple1 = ([\"Fede\", \"Ale\"], [24, 27])\n", - "print(type(temp_tuple1))\n", - "temp_tuple1[1][0] = 42\n", - "print(temp_tuple1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "temp_tuple1[1] = [54, 57]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Print the value associated to the first key of the dictionary defined above." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(dict_1['int_1'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "temp_dict1 = dict_1.copy()\n", - "print(temp_dict1)\n", - "temp_dict1[\"goodbye_1\"] = \"Goodbye, World!\" \n", - "print(temp_dict1)\n", - "# To get the keys in different orders\n", - "print(f\"Not sorted:{list(temp_dict1)} \\nSorted:{sorted(temp_dict1)}\")\n", - "# You can check if a key is in the dictionary\n", - "print(\"goodbye_1\" in temp_dict1)\n", - "print(\"Goodbye, World!\" in temp_dict1[\"goodbye_1\"])\n", - "# You can delete keys and their associated values using del\n", - "del temp_dict1[\"goodbye_1\"]\n", - "print(\"goodbye_1\" in temp_dict1)\n", - "print(\"goodbye_1\" not in temp_dict1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "You can create a dictionary in different ways:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# From a list of tuples\n", - "temp_dict2 = dict([(\"int_1\", 40), (\"int_2\", 4), (\"string_1\", \"Hello, World!\")])\n", - "print(temp_dict2)\n", - "# From a list of lists\n", - "temp_dict3 = dict([[\"int_1\", 40], [\"int_2\", 4], [\"string_1\", \"Hello, World!\"]])\n", - "print(temp_dict3)\n", - "temp_dict3[\"int_1\"] = 41\n", - "print(temp_dict3)\n", - "# Using a dict comprehension\n", - "temp_dict4 = {x: [y, y**2] for x, y in [[\"int_1\", 1], [\"int_2\", 2], [\"int_3\", 3]]}\n", - "print(temp_dict4)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "# With dict you need 2 arguments per element, but the second one containing values can include multiple elements\n", - "temp_dict5 = dict([(\"int_1\", (40, 41, 42)), (\"int_2\", (4, 5, 6)), (\"string_1\", \"Hello, World!\")])\n", - "print(temp_dict5)\n", - "# If the values for a key are in a tuple, you will not be able to change them, but you can change the tuple assigned to that key\n", - "temp_dict5[\"int_1\"] = (41, 42, 43)\n", - "print(temp_dict5)\n", - "# While you can do that using lists\n", - "temp_dict6 = dict([[\"int_1\", [40, 41, 42]], [\"int_2\", [4, 5, 6]], [\"string_1\", \"Hello, World!\"]])\n", - "print(temp_dict6)\n", - "temp_dict6[\"int_1\"][0] = 41\n", - "print(temp_dict6)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Sets\n", - "A set is an unordered collection with no duplicate elements" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "set_1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3}\n", - "set_2 = {0, 2, 4, 6, 10, 11, 12}\n", - "print(set_1)\n", - "print(type(set_1))\n", - "# You can print the element in set_1 that are not in set_2, you can alse use \"set_1 - set_2\" to do that)\n", - "print(set_1.difference(set_2))\n", - "# You can print the union of two sets (use \"set_1 | set_2\")\n", - "print(set_1.union(set_2))\n", - "# The intesection (use \"set_1 & set_2\" or set_1.intersection(set_2))\n", - "print(set_1 & set_2)\n", - "# The symmetric difference for elements in set_1 or set_2 but not in both (you can use \"set_1 ^ set_2\")\n", - "print(set_1.symmetric_difference(set_2))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "# Check if an element is in a set\n", - "print(f\"Is 9 an element of set 1? {9 in set_1} \\nIs 9 an element of set 2? {9 in set_2}\")\n", - "# You can use set comprehension to create a set\n", - "set_3 = {x for x in range(10)}\n", - "print(set_1.symmetric_difference(set_3))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Exercise 4: Functions and logical statements\n", - "\n", - "Create a function that takes an *int*, a *float* and a *string* as inputs and returns a list containing the three of them." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "# The typing package is not necessary, but it helps in keeping track of the inputs' types and the type of the function output\n", - "\n", - "def func_1(int_1: int, float_1: float, str_1: str) -> list:\n", - " return [str(int_1), str(float_1), str_1]\n", - "\n", - "# Below the function using positional arguments, you can also use keyword arguments: func_1(int_1 = 4, float_1 = 3.0, str_1 = \"hello\")\n", - "# You can use keyword arguments after positional arguments (as long as they do not assign values to the same argument), but not the opposite\n", - "func_1(4, 3.0, 'hello')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "The functions start with a \"def\", then you have the name of the function and the inputs inside round brackets.\n", - "\n", - "After the semicolons you can write the function, remember that you need one indentation level for each function (or loop). You can use 4 spaces or a tab to do the indent.\n", - "\n", - "The return at the end of the function gives the output from that function. If return is not assigned, Python will give by default an output \"None\" (same happens if return is included but it does not have an expression argument defined)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### More fun with FUNctions\n", - "Remember to define the functions before they are called in the code. You can set default values for the parameters, and you have to order the parameters starting from the one that do not have default values" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def temp_func1(float_1: float, str_1: str, int_1: int = 4) -> list:\n", - " temp = temp_func2()\n", - " return [[str(int_1), str(float_1), str_1], temp]\n", - "\n", - "print(temp_func1(3.0, \"hello\"))\n", - "\n", - "def temp_func2(int_2: int = 8, float_2: float = 6.0, str_2: str = \"Hello\") -> list:\n", - " return [str(int_2), str(float_2), str_2]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "You can use unpacking argument for lists and tuples (using \"*\"), while double asterisks for dictionaries, to get the values used in a function" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def temp_func3(float_1: float, str_1: str, int_1: int = 4) -> list:\n", - " return [str(int_1), str(float_1), str_1]\n", - "\n", - "temp_tuple2 = (6.0, \"Hello\", 8)\n", - "print(temp_func3(*temp_tuple2))\n", - "\n", - "temp_dict7 = {\"int_1\": 8, \"float_1\": 6.0, \"str_1\": \"Hello\"}\n", - "print(temp_func3(**temp_dict7))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "# You can (and should) include a documentation inside your function\n", - "def temp_doc():\n", - " \"\"\" Usually the summary in the first line.\n", - " \n", - " Leave one black space between the summary and the rest of the text\n", - " \"\"\"\n", - " pass\n", - "\n", - "print(temp_doc.__doc__)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Use a lambda function to achieve the same result. It is a short function (in one line) that take parameters and an expression; the latter after the semicolons." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "lambda_1 = lambda a, b, c : [str(a), str(b), c]\n", - "print(lambda_1(4, 3.0, 'hello'))\n", - "print(type(lambda_1(4, 3.0, 'hello')))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Let's move into something slightly more involving. This function checks the type of the input. \n", - "* The part of code in the \"if\" statement environment is evaluated if the initial condition is *True*.\n", - "* If the \"if\" condition evaluates to *False*, we jump to the elseif (or else) statement that follows the initial \"if\" statement. Elseif is short for else if.\n", - "* You can include else or elseif statements, they are not necessary in the code. In that case, when the if statement is true, the code will continue as if there is an else statement containing *pass*, meaning that it does nothing when the if statement evaluates to *False* " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def func_2(x):\n", - " if type(x) == int:\n", - " print(f\"{x} is an integer\")\n", - " elif type(x) == float:\n", - " print(f\"{x} is a float\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Notice that the function only checks if the input is an *int* or a *float*. Add an extra condition to check if the input is a *string*" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def func_2(x):\n", - " if type(x) == int:\n", - " print(f\"{x} is an integer\")\n", - " elif type(x) == float:\n", - " print(f\"{x} is a float\")\n", - " elif type(x) == str:\n", - " print(f\"{x} is a string\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "func_2(\"hello\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Comparisons\n", - "The comparisons yield boolean values (*True* or *False*). We will discuss:\n", - "* Value comparisons, which compare the values of two objects\n", - " * In this group you can find equality comparison \"==\" and \"!=\"\n", - " * Order comparison, \"<\", \">\", \"<=\", \">=\"\n", - "* Membership test, we have seen them previously as \"x in y\" and \"z not in f\"\n", - "* Identity comparisons \"x is y\"and \"z is not f\"" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Value comparisons" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "# Comparison of numbers\n", - "print(5 == 5)\n", - "print(5 != 5)\n", - "print(7 < 10)\n", - "print(7 < 10 < 20)\n", - "# This is pretty much the same as \"7 < 20 and 20 < 10\".\n", - "# The first comparison evaluates \"True\", but the second is \"False\", so the presence of \"and\" gives a \"False\"\n", - "print(7 < 20 < 10)\n", - "# For strings the comparison is realised looking at the unicode of each character\n", - "print(\"hello\" < \"Hello\")\n", - "print(\"h unicode is\", ord('h'), \", H unicode is\", ord('H'))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "# You can compare collections if they have the same type (a list with a list, set with another set, etc.)\n", - "# Lexicographic comparison\n", - "print([1, 2, 3] < [1, 2, 4])\n", - "print([1, 2] < [1, 2, 4])\n", - "print([1, 3] < [1, 2, 4])\n", - "# For dictionaries you can only use equality comparison, it evaluates the equality between (key, value) pairs\n", - "temp_dict8 = {\"temp_1\": 1, \"temp_2\": 2}\n", - "temp_dict9 = {\"temp_1\": 1, \"temp_2\": 2}\n", - "print(temp_dict8 == temp_dict9)\n", - "# For sets we have order comparison operators to realise subset and superset tests\n", - "temp_set1 = {1, 2}\n", - "temp_set2 = {1, 2, 3}\n", - "print(temp_set1 == temp_set2)\n", - "print(temp_set1 < temp_set2)\n", - "print(temp_set1 > temp_set2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Identity comparison\n", - "It is not the same as equality comparisons as you can see below" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "temp_var = [1, 2]\n", - "temp_var2 = [1, 2]\n", - "print(id(temp_var2))\n", - "print(id(temp_var))\n", - "print(temp_var is temp_var2)\n", - "print(temp_var == temp_var2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Boolean operations\n", - "The boolean values are *True* and *False*. But what exactly evaluate to these two values?\n", - "* Values for *False*: False, None, numeric zero of all types, empy strings and containers.\n", - "* Values for *True*: All the values that do not evaluate to *False*.\n", - "\n", - "We can use the following operator and expressions:\n", - "* The opeartor \"not\" yields *True* if its argument is false, *False* otherwise. In other words, it reverses the result.\n", - "* The expression *x and y* first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.\n", - "* The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "x = 42\n", - "y = 20\n", - "z = 22\n", - "print(not(x == 42 and y + z == x))\n", - "print(not(x == 42 and y + z != x))\n", - "print(x != 42 or y == 20)\n", - "print(bool([]))\n", - "print(bool([1]))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Exercise 5: For and While Loops\n", - "\n", - "Python allows you to loop over several type of objects. A simple loop looks like" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "for x in range(10):\n", - " print(x, end=\" \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "The for statement iterates over the items of a sequence. In this case, the sequence of numbers generated by the *range(10)* function.\n", - "\n", - "You can notice that the for statement follows the order in which the items appear in the sequence." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Modify the script above to loop over a list containing both numbers (*int* and/or *float*) and *string*. Print the type of the input at each iteration." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "for x in [1, 3.0, \"hello\"]:\n", - " print(\"The input supplied is a \" + str(type(x)))\n", - " \n", - "# If you want a better look for your print output use the \"__name__\" dunder method, more regarding dunder below\n", - "for x in [1, 3.0, \"hello\"]:\n", - " print(\"The input supplied is a \" + str(type(x).__name__))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "The next chunk of code fills in an empty list with a sequence of integers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "list_1 = []\n", - "\n", - "for i in range(10):\n", - " list_1.append(i)\n", - " \n", - "print(list_1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "Produce the same result using a while loop instead (Hint: create a new list, call it *list_2*. Make sure to update the counter at each iteration of the loop)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "i = 0\n", - "list_2 = []\n", - "while i < 10:\n", - " list_2.append(i)\n", - " i += 1\n", - "\n", - "print(list_2)\n", - "print(list_1 == list_2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "The *while* loop executes the code inside its environment as long as the initial condition (in this case \"i < 10\") evaluates to *True*" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "Sum the strings above to obtain *Hello, World!*. Print the result." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "string_3 = string_1 + \", \" + string_2 +\"!\"\n", - "print(string_3)\n", - "# Otherwise, use:\n", - "# print(string_1 + \", \" + string_2 +\"!\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "# You can add more arguments in the for loop to unpack items\n", - "temp_list7 = [[\"Fede\", 24, \"ULB\"], [\"Ale\", 27, \"Sapienza\"]]\n", - "for x, y, z in temp_list7:\n", - " print(f\"Item in the list {x}, {y}, {z}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Break statement\n", - "The *break* statement exits the loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "for i in range(10):\n", - " if i <= 7:\n", - " print(i, end=\" \")\n", - " else:\n", - " break" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "i = 0\n", - "while i < 10:\n", - " print(i, end=\" \")\n", - " i += 1\n", - " if i == 9:\n", - " break " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Continue statement\n", - "The *continue* statement restart the loop moving to the next iteration" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "temp_list8 = list(range(10))\n", - "temp_list8[5] = \"five\"\n", - "print(temp_list8)\n", - "for i in temp_list8:\n", - " try:\n", - " print(i + 1, end=\" \")\n", - " except TypeError:\n", - " continue" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "temp_list8 = list(range(10))\n", - "temp_list8[5] = \"five\"\n", - "i = 0\n", - "while i < 10:\n", - " if type(temp_list8[i]) == int:\n", - " i += 1\n", - " continue\n", - " temp = temp_list8[i]\n", - " i += 1\n", - " print(temp, type(temp))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Else clause\n", - "The else clause is executed only if the for loop has been completed without breaks" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def example_1(container: list):\n", - " for i in container:\n", - " if type(i) == float:\n", - " print(\"This list contains at least one float\")\n", - " break\n", - " else:\n", - " print(\"This list does not contain a float\")\n", - " \n", - "temp_list9 = [1, 2, 3, 4]\n", - "temp_list10 = [1, 2, 3.0, 4]\n", - "example_1(temp_list9)\n", - "example_1(temp_list10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "def example_2(i: int, n: int, c: int):\n", - " initial_value = i\n", - " while i <= n:\n", - " i += 1\n", - " if i == (2/3)*c:\n", - " print(f\"The value {i} is 2/3 of {c}. Stop the loop.\")\n", - " break\n", - " else:\n", - " print(f\"2/3 of {c} is {(2/3)*c}; it is not part of the interval [{initial_value}, {n}]\")\n", - "\n", - "example_2(0, 10, 12)\n", - "example_2(0, 10, 30)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Classes in Python" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "class Savings:\n", - " \n", - " def __init__(self, w):\n", - " self.wealth = w\n", - " self.new_wealth = w\n", - " \n", - " def salary(self, x):\n", - " self.new_wealth += x\n", - " \n", - " def expenditures(self, **kwargs):\n", - " total_expenditures = 0\n", - " for key, value in kwargs.items():\n", - " total_expenditures += value\n", - " print(f\"You plan to spend {value} euro on {key}\")\n", - " new_wealth = self.new_wealth - total_expenditures\n", - " if new_wealth < 0:\n", - " print(\"Insufficient savings, try decreasing your expenditures\")\n", - " else:\n", - " self.new_wealth = new_wealth\n", - " print(f\"Your new wealth after the expenditures will be: {self.new_wealth} euro\")\n", - " if self.new_wealth < self.wealth:\n", - " print(f\"You will be below your initial wealth by {self.wealth - self.new_wealth} euro\")\n", - " elif self.new_wealth == self.wealth:\n", - " print(f\"Your new wealth will be the same as the initial one: {self.new_wealth} euro\")\n", - " else:\n", - " print(f\"You will be above your initial wealth by {self.new_wealth - self.wealth} euro\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "person = Savings(1000)\n", - "print(person.wealth)\n", - "person.salary(200)\n", - "print(person.new_wealth)\n", - "person.expenditures(chocolate = 50, beer = 75)\n", - "print(person.new_wealth)\n", - "person.expenditures(chocolate = 400, beer = 600)\n", - "print(person.new_wealth)\n", - "person. expenditures(chocolate = 100)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Debugger using jupyter notebook\n", - "In jupyter notebook you can use the *%debug* magic to launch the debugger. In jupyter lab you can have a better graphical interface for the debugger using the debugger extension." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def example3(s1: set, s2: set):\n", - " s3 = s1 & s2\n", - " %debug\n", - " print(s3[1])\n", - " return s3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "temp_set1 = set(range(0 , 20, 2))\n", - "temp_set2 = set(range(0, 20, 4))\n", - "print(temp_set1)\n", - "print(temp_set2)\n", - "example3(temp_set1, temp_set2)" - ] - } - ], - "metadata": { - "celltoolbar": "Slideshow", - "file_extension": ".py", - "kernelspec": { - "display_name": "Python 3", - "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.7.4" - }, - "mimetype": "text/x-python", - "name": "python", - "npconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": 3 - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/Session_4/README.md b/Session_4/README.md deleted file mode 100644 index 0ba1317..0000000 --- a/Session_4/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Session 4: More on Python's basic - -In this session, we will work more specifically on loops and functions. We have two files, both to be open with Jupyter. - -The first one, the regular one (named `exercise_4.ipynb`), shows how to play around with lists of values to simulate a small investment strategy and perform non-parametric Monte-Carlo simulations. The second one, that is optional (and called `ad_fundum_the_programming_case.ipynb`), digs further in the topics of exception handling, recursive functions and Belgian student drinking culture. - -The solutions to both of them will be posted. diff --git a/Session_8/Readme.md b/Session_4/Readme.md.txt similarity index 100% rename from Session_8/Readme.md rename to Session_4/Readme.md.txt diff --git a/Session_4/ad_fundum_the_programming_case.ipynb b/Session_4/ad_fundum_the_programming_case.ipynb deleted file mode 100644 index 8d710b5..0000000 --- a/Session_4/ad_fundum_the_programming_case.ipynb +++ /dev/null @@ -1,276 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Ad fundum!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "This notebook has three purposes: \n", - "1. Learning to use exceptions as part of a normal program workflow\n", - "2. Getting acquainted with recursive function\n", - "3. Introducing those of you who are not from Belgium with the tradition of Ad Fundum (I'm sure it exists in every country but the Belgian way is probably slightly different)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## The ULB way" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "In this notebook, we are going to build a small system that enables you to hone your ad fundum skills from the comfort of your own house. For that, we will use a set of functions that call one another and time the whole process.\n", - "\n", - "The ad fundum is a student... let's call it ritual that goes more or less like this:\n", - "\n", - "* One person challenges another at ad fundum, the other usually agrees. They go and pick up a beer or a beverage each. A referee is appointed (in our case, the referee is the program we write and the only adversary in our case is ourself).\n", - "* The referee asks the two contestants whether they are ready. Once it is the case, she pronounces the following formula: \"À main, à bouche, à cul, nom de dieu!\" (loosely translated, it means \"To the hand, to the mouth, to the bottom, for god's sake\"). Of course, I assume that in catholic universities, they drop the last part so our program should let the player decides if she wants to see this. Also, the word \"cul\" is somewhat vulgar in French and our program should be family friendly (with the difference that, if children want to play, they should drink a non-alcoholic beverage but the program cannot control that, now, can it?). The player should be able to decide if she wants to see the full word or the cleaner \"c\\*\\*\".\n", - "* Once the referee has pronouced the formula, both contestants have to chug their beer (or their beverage) as fast as possible. For some reason, bystanders usually shout \"et glou\" (which in English would sounds something like \"hay glue\" and which is supposed to mimick the sound of somebody drinking) regularly, so we'll emulate that as well.\n", - "* Once the first of the player is done with her glass (or whatever container she's drinking from), she's declared the winner and go on to enjoy the rest of the evening (or directly to do another ad fundum).\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## The program" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "So basically, our program is a glorified timer: it writes the ritual formula, starts a timer and then repeatedly writes \"et glou\" on the screen until the player kill it by hand (meaning by clicking on the little \"stop\" sign on the top of the notebook. This is not something normal for the program: it is an exception and it can be captured in the logic of the code to treat it accordingly (by default, it kills the whole program but in our case, we just want to use it to stop the never-ending stream of \"et glou\").\n", - "\n", - "Before getting down to business, there are two functions that we could see:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on built-in function sleep in module time:\n", - "\n", - "sleep(...)\n", - " sleep(seconds)\n", - " \n", - " Delay execution for a given number of seconds. The argument may be\n", - " a floating point number for subsecond precision.\n", - "\n" - ] - } - ], - "source": [ - "import time # Yes, in Python, you can import time itself! God-feeling, much?\n", - "\n", - "help(time.sleep)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on built-in function time in module time:\n", - "\n", - "time(...)\n", - " time() -> floating point number\n", - " \n", - " Return the current time in seconds since the Epoch.\n", - " Fractions of a second may be present if the system clock provides them.\n", - "\n" - ] - } - ], - "source": [ - "help(time.time)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This took 2.002575159072876 seconds\n" - ] - } - ], - "source": [ - "start = time.time()\n", - "time.sleep(2)\n", - "finish = time.time()\n", - "print(\"This took \", finish - start, \" seconds\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## The formula" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The first step of this exercise is to create a function that put the initial formula. It should be a function that takes 2 arguments and returns nothing. The two arguments should be two Boolean: the first one, called *parental_version* will be True if we must print \"c\\*\\*\" instead of \"cul\" and the other parameter, called *gods_sake* will also be a Boolean and will be True if we have to take out the mention to God's sake.\n", - "\n", - "Write this function here below:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Et glou" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We are now going to write a function that takes 1 argument (an integer), lets call it *x*, but do three things sequentially:\n", - "1. Print the infamous \"Et glou\" to the screen.\n", - "2. Sleep for *x* number of seconds\n", - "3. Call the function itself" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "![boum](https://i.ytimg.com/vi/LLpIMRowndg/maxresdefault.jpg)\n", - "\n", - "Whaaaat? A function that calls itself? Well, yes. It is called a [recursive function](http://algosaur.us/recursion/). Recursive functions are a fascinating topic that allow you to do many stuff. For example, certain languages do not have loop as using recursive functions can substitute any type of loop. A classical example of use of recursive function is to compute Fibonacci numbers.\n", - "\n", - "> \"To iterate is human, to recurse is divine\"\n", - "> *L Peter Deutsch*\n", - "\n", - "OK, enough about recursion (although if you're into it, there is plenty to do and be said on the topic!). We actually need to modify slightly our function: if we let it as is, it will recurse until the end of time (or when the memory of your computer runs out). We need to implement a way to kill this list manually. As told before, we will implement the end of this loop as an Exception Handling problem: if the user tries to kill the program (by clicking on the square above), the exception will be capture and the function will return None, which will break the cycle. To do so, do wrap the whole body of your function in a *try* block and then in the *except* part, only capture the *KeyboardInterrupt* exception. If such an exception happen, just return *None*.\n", - "\n", - "Write the modified function below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now it's time to tie everything together. Create a final function, that takes three arguments (the *parental_control*, the *gods_sake* and the *time_sleeping*) and that does the following:\n", - "\n", - "1. Call the function that will print the ritual formula\n", - "2. Create a *start* variable that contains the time at which the challenge starts\n", - "3. Call the function that writes \"et glou\" recursively\n", - "4. Create an *end* variable containing the time after your recursiv function ends\n", - "5. Print the value of *end* - *start*" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "That's it, you can now train your ad fundum skills from home. Drink responsibly. Prosit!" - ] - } - ], - "metadata": { - "kernelspec": { - "argv": [ - "python", - "-m", - "ipykernel_launcher", - "-f", - "{connection_file}" - ], - "display_name": "Python 3", - "env": null, - "interrupt_mode": "signal", - "language": "python", - "metadata": null, - "name": "python3" - }, - "name": "exercises_4_bis_using_exceptions.ipynb" - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Session_4/exercises_4.ipynb b/Session_4/exercises_4.ipynb deleted file mode 100644 index b8d7d50..0000000 --- a/Session_4/exercises_4.ipynb +++ /dev/null @@ -1,419 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# It gets loopy" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "In this notebook, we will work with stock prices. I'll get you started by writing some code that go and fetch the last quotes of a few American stocks. We will then write loops and functions to do two things:\n", - "\n", - "1. Evaluate the performance of an investing strategy on past data\n", - "2. Infer the possible performance of the same strategy on short-run future data" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We start by importing the quotes. It is not crucial to understand the code here below as we will see what a call to an API is during a future session. It works broadly like this: we call a server that sends us back a kind of nested dictionaries and lists that contain the quotes and date of those quotes for the 5 largest tech firms (that are sometimes referred to as GAFAM)." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "from requests import get\n", - "stock_quotes = {}\n", - "tickers = {\"GOOG\" : \"Google\", \"AAPL\" : \"Apple\", \"FB\": \"Facebook\", \"AMZN\" : \"Amazon\", \"MSFT\": \"Microsoft\"}\n", - "for ticker in tickers:\n", - " prices_and_dates = {}\n", - " query = \"https://financialmodelingprep.com/api/v3/historical-price-full/\"+ticker+\"?serietype=line\"\n", - " histoire_des_prix = get(query).json()[\"historical\"]\n", - " prices_and_dates[\"quotes\"] = [cours[\"close\"] for cours in histoire_des_prix[-31:]]\n", - " prices_and_dates[\"dates\"] = [cours[\"date\"] for cours in histoire_des_prix[-31:]]\n", - " stock_quotes[ticker] = prices_and_dates" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Run the cell above: it will run for some time and then ends without showing anything. In fact, it loads a peculiar data structure in the memory of your computer. The structure consists in prices and dates contained inside a dictionary which is itself contained in a dictionary. It is kind of a lousy structure so far but we will see in next sessions (the pandas one) how to make it easier. For now, we have to rely on this awkward structure. Here are some example of how to use it." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1404.32, 1419.83, 1429.73, 1439.23, 1430.88, 1439.2, 1451.7, 1480.39, 1484.4, 1485.95, 1486.65, 1466.71, 1433.9, 1452.56, 1458.63, 1455.84, 1434.23, 1485.94, 1447.07, 1448.23, 1476.23, 1479.23, 1508.68, 1508.79, 1518.27, 1514.66, 1520.74, 1519.67, 1526.69, 1518.15, 1485.11]\n" - ] - } - ], - "source": [ - "# Show all prices for Google\n", - "print(stock_quotes[\"GOOG\"][\"quotes\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "313.05\n" - ] - } - ], - "source": [ - "# Show the price of the Apple closing quote yesterday\n", - "print(stock_quotes[\"AAPL\"][\"quotes\"][-1])" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2020-01-10\n" - ] - } - ], - "source": [ - "# What is the date of the third quote for the Microsoft data?\n", - "print(stock_quotes[\"MSFT\"][\"dates\"][2])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Let's work" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "OK, enough playing around! Now is your turn: Let's start by stretching our programming muscles. I'll write a line that will create a new variable called *quotes_amazon* and that is a list that contains the quotes of Amazon (in dollars) for all the data we have.\n", - "\n", - "Your job is to create a new list, called *quotes_amazon_euro* in which you will store the quotes but in Euros (for this exercise, it is enough to consider that converting to Euros just means multiplying by *0.9* - please applied trade economists, don't crucify me for this approximation)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "quotes_amazon = stock_quotes[\"AMZN\"][\"quotes\"]\n", - "\n", - "# Your code comes below this line\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Done? Good! Now for a harder problem: We will create a function that will compute the mean of any list that is passed (provided it contains integers or floats, of course). The function will work broadly like this: You initialize a counter at 0, you loop over the list and, at each iteration, you add the value at that position to the counter. Once the loop is over, you divide this by the length of the list to obtain the average.\n", - "\n", - "Oddly enough, Python doesn't ship with a built-in mean function (it was not initially a scientific computing language). Implementing it is therefore needed to perform the next steps (in future session, we will see some libraries, the most important being Numpy, that provide implementation of means functions.\n", - "\n", - "Implement your function, call it my_mean and then see if it works on the list containing the prices of the Facebook stock (that will be stored in the variable *facebook_quotes*.\n", - "\n", - "*Don't forget that you must produce a **function**, it will be important because we will use it in the next part!*" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Your function should produce the following result (plus ou minus numerical error):\t 215.19645161290322\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "facebook_quotes = stock_quotes[\"FB\"][\"quotes\"]\n", - "print(\"Your function should produce the following result (plus ou minus numerical error):\\t\"\n", - " , np.mean(facebook_quotes))\n", - "\n", - "# Your code comes here below\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Let's now build on top of what we did previously to build a function that computes the mobile average. Let's start by using a fix number of lags to be considered (you can always extend it later): We want to have a function that takes a list and produces a new list containing the average value of the three past value (you can either align the two list by setting the three first value of your result to *None* or not, this will impact the way you will have to solve the next exercises, but both ways will be equally practical). Test it on the Google quotes that are in the variable *google_quotes*." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "google_quotes = stock_quotes[\"GOOG\"][\"quotes\"]\n", - "\n", - "# Your code comes here below\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now that we have done it for a fix number of lags, do it again but now allow for a second parameter to your function: the number of lags you want to consider for your moving average." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We are now going to compute the mean squared error. Write a function that sums over the squared differences between the actual value and your moving-average-based forecast. This will help us determining the optimal number of lags for our secret investment strategy at the next step." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Our masterplan to get rich is getting together nicely...\n", - "\n", - "![coming_together](https://i1.wp.com/media1.tenor.com/images/a71c94c3aa7ad66a5051f81f48d14dd2/tenor.gif?w=688&ssl=1)\n", - "\n", - "The last step before creating the actual investement strategy: we are going to evaluate which lag produces the smallest mean square error. For that, create a function that loops over the range between 2 and 6 and return the optimal lag (the one with the smallest MSE)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We are now going to devise an incredibly dumb investment strategy: if your moving-average prediction (with the optimal lag - see, we are already [double-dipping](https://en.wikipedia.org/wiki/Circular_analysis) in the data...) is higher than the current price on a day, we invest all our accrued fortune (if we currently had no stock) or hold (if we had already some value invested), if the prediction is below, we sell our whole position (or do nothing if we had no money invested at the time).\n", - "\n", - "How much would we have today if we had started using this strategy on February 3rd and started out with 100 Euros?\n", - "\n", - "This is a significantly more complex problem than the ones above and you might want to split it into subproblems (for example, a good idea could be to devise a function that takes two values and returns the variation between those). There are many ways to solve it, find the one that makes more sense to you. The result should be the same for everyone, though." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Get rich (fast) or code tryin'" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The last step for today is to assess how much we will make in the near future. For this, we will use a small, non-parametric Monte-Carlo simulation.\n", - "\n", - "![monte_carlo](http://www.azquotes.com/picture-quotes/quote-in-mathematics-as-in-physics-so-much-depends-on-chance-on-a-propitious-moment-stanislaw-ulam-111-21-35.jpg)\n", - "\n", - "Here's how it will go: we are going to reuse the function that simulates the performance of our stupid investment strategy but on simulated data that will be produced in the following way: we are going to simulate 20 periods of data by resampling at random the past prices. This can be done using the function [random.choices(population, weights=None, \\*, cum_weights=None, k=1)](https://docs.python.org/3/library/random.html#random.choices): We are going to produce a list containing all the price variations of the quote. We then are going to produce a list of 20 values between 0 and the length of the list we just create and use those as variations over the next 20 days. We test our investment strategy again this \"future reality\" as if we started today with 100 Euros and the result is the final value we would have after 20 days. We have one potential result that we store in a list, called *results*. We repeat the process 5000 times (you can do it less time if your computer is rather slow). In the end, we will end up with 5000 potential results of our investment strategy over the 20 next days. I'll write the function that plots the distribution so that we can see visually what we can expect.\n", - "\n", - "Again, this whole procedure will probably require several functions. Try to break down the problem in a sequence of intermediate steps." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "import random\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The next cell will represent the distribution of your profits, only execute it once you have your 5000 results in the variable *results*." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "import seaborn as sns\n", - "\n", - "sns.distplot(results)" - ] - } - ], - "metadata": { - "kernelspec": { - "argv": [ - "python", - "-m", - "ipykernel_launcher", - "-f", - "{connection_file}" - ], - "display_name": "Python 3", - "env": null, - "interrupt_mode": "signal", - "language": "python", - "metadata": null, - "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.7.6" - }, - "name": "exercises_4.ipynb" - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Session_4/exercises_4_solutions.ipynb b/Session_4/exercises_4_solutions.ipynb deleted file mode 100644 index 5e6de28..0000000 --- a/Session_4/exercises_4_solutions.ipynb +++ /dev/null @@ -1,429 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# It gets loopy" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this notebook, we will work with stock prices. I'll get you started by writing some code that go and fetch the last quotes of a few American stocks. We will then write loops and functions to do two things:\n", - "\n", - "1. Evaluate the performance of an investing strategy on past data\n", - "2. Infer the possible performance of the same strategy on short-run future data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We start by importing the quotes. It is not crucial to understand the code here below as we will see what a call to an API is during a future session. It works broadly like this: we call a server that sends us back a kind of nested dictionaries and lists that contain the quotes and date of those quotes for the 5 largest tech firms (that are sometimes referred to as GAFAM)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "from requests import get\n", - "stock_quotes = {}\n", - "tickers = {\"GOOG\" : \"Google\", \"AAPL\" : \"Apple\", \"FB\": \"Facebook\", \"AMZN\" : \"Amazon\", \"MSFT\": \"Microsoft\"}\n", - "for ticker in tickers:\n", - " prices_and_dates = {}\n", - " query = \"https://financialmodelingprep.com/api/v3/historical-price-full/\"+ticker+\"?serietype=line\"\n", - " histoire_des_prix = get(query).json()[\"historical\"]\n", - " prices_and_dates[\"quotes\"] = [cours[\"close\"] for cours in histoire_des_prix[-31:]]\n", - " prices_and_dates[\"dates\"] = [cours[\"date\"] for cours in histoire_des_prix[-31:]]\n", - " stock_quotes[ticker] = prices_and_dates" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Run the cell above: it will run for some time and then ends without showing anything. In fact, it loads a peculiar data structure in the memory of your computer. The structure consists in prices and dates contained inside a dictionary which is itself contained in a dictionary. It is kind of a lousy structure so far but we will see in next sessions (the pandas one) how to make it easier. For now, we have to rely on this awkward structure. Here are some example of how to use it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# Show all prices for Google\n", - "print(stock_quotes[\"GOOG\"][\"quotes\"])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# Show the price of the Apple closing quote yesterday\n", - "print(stock_quotes[\"AAPL\"][\"quotes\"][-1])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# What is the date of the third quote for the Microsoft data?\n", - "print(stock_quotes[\"MSFT\"][\"dates\"][2])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Let's work" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OK, enough playing around! Now is your turn: Let's start by stretching our programming muscles. I'll write a line that will create a new variable called *quotes_amazon* and that is a list that contains the quotes of Amazon (in dollars) for all the data we have.\n", - "\n", - "Your job is to create a new list, called *quotes_amazon_euro* in which you will store the quotes but in Euros (for this exercise, it is enough to consider that converting to Euros just means multiplying by *0.9* - please applied trade economists, don't crucify me for this approximation)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "quotes_amazon = stock_quotes[\"AMZN\"][\"quotes\"]\n", - "\n", - "# Your code comes below this line\n", - "print([quote * 0.9 for quote in quotes_amazon])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Done? Good! Now for a harder problem: We will create a function that will compute the mean of any list that is passed (provided it contains integers or floats, of course). The function will work broadly like this: You initialize a counter at 0, you loop over the list and, at each iteration, you add the value at that position to the counter. Once the loop is over, you divide this by the length of the list to obtain the average.\n", - "\n", - "Oddly enough, Python doesn't ship with a built-in mean function (it was not initially a scientific computing language). Implementing it is therefore needed to perform the next steps (in future session, we will see some libraries, the most important being Numpy, that provide implementation of means functions.\n", - "\n", - "Implement your function, call it my_mean and then see if it works on the list containing the prices of the Facebook stock (that will be stored in the variable *facebook_quotes*.\n", - "\n", - "*Don't forget that you must produce a **function**, it will be important because we will use it in the next part!*" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "facebook_quotes = stock_quotes[\"FB\"][\"quotes\"]\n", - "print(\"Your function should produce the following result (plus ou minus numerical error):\\t\"\n", - " , np.mean(facebook_quotes))\n", - "\n", - "# Your code comes here below\n", - "def mean(numbers_to_average):\n", - " return sum(numbers_to_average)/len(numbers_to_average)\n", - "\n", - "print(mean(facebook_quotes))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's now build on top of what we did previously to build a function that computes the mobile average. Let's start by using a fix number of lags to be considered (you can always extend it later): We want to have a function that takes a list and produces a new list containing the average value of the three past value (you can either align the two list by setting the three first value of your result to *None* or not, this will impact the way you will have to solve the next exercises, but both ways will be equally practical). Test it on the Google quotes that are in the variable *google_quotes*." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "google_quotes = stock_quotes[\"GOOG\"][\"quotes\"]\n", - "\n", - "# Your code comes here below\n", - "def moving_average_3(list_to_treat):\n", - " result = [None, None, None]\n", - " for i in range(3,len(list_to_treat)):\n", - " result.append(round(mean(list_to_treat[i-3:i]),2))\n", - " return result\n", - " \n", - "print(moving_average_3(google_quotes))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we have done it for a fix number of lags, do it again but now allow for a second parameter to your function: the number of lags you want to consider for your moving average." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def moving_average(list_to_treat, order):\n", - " results = [None for i in range(order)]\n", - " for i in range(order, len(list_to_treat)):\n", - " results.append(round(mean(list_to_treat[i-order:i]),2))\n", - " return results\n", - "\n", - "print(moving_average(google_quotes, 4))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are now going to compute the mean squared error. Write a function that sums over the squared differences between the actual value and your moving-average-based forecast. This will help us determining the optimal number of lags for our secret investment strategy at the next step." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def mse(list_1, list_2):\n", - " if len(list_1) != len(list_2):\n", - " print(\"Both list must be of the same size\")\n", - " return None\n", - " accumulator = 0\n", - " count = 0\n", - " for i in range(len(list_1)):\n", - " if list_1[i] != None and list_2[i] != None:\n", - " accumulator += (list_1[i] - list_2[i])**2\n", - " count += 1\n", - " return accumulator/count\n", - "\n", - "print(mse([1, 2, 2, 5], [None, None, 4, 3]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our masterplan to get rich is getting together nicely...\n", - "\n", - "![coming_together](https://i1.wp.com/media1.tenor.com/images/a71c94c3aa7ad66a5051f81f48d14dd2/tenor.gif?w=688&ssl=1)\n", - "\n", - "The last step before creating the actual investement strategy: we are going to evaluate which lag produces the smallest mean square error. For that, create a function that loops over the range between 2 and 6 and return the optimal lag (the one with the smallest RMSE)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def optimal_order(a_list):\n", - " optimum = 0\n", - " minimum_mse = 1_000_000_000_000 # that's a comically large value\n", - " for i in range(2, 7):\n", - " MA = moving_average(a_list, i)\n", - " mse_for_this_lag = mse(a_list, MA)\n", - " if mse_for_this_lag < minimum_mse:\n", - " minimum_mse = mse_for_this_lag\n", - " optimum = i\n", - " return optimum\n", - "\n", - "print(optimal_order(google_quotes))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are now going to devise an incredibly dumb investment strategy: if your moving-average prediction (with the optimal lag - see, we are already [double-dipping](https://en.wikipedia.org/wiki/Circular_analysis) in the data...) is higher than the current price on a day, we invest all our accrued fortune (if we currently had no stock) or hold (if we had already some value invested), if the prediction is below, we sell our whole position (or do nothing if we had no money invested at the time).\n", - "\n", - "How much would we have today if we had started using this strategy on February 3rd and started out with 100 Euros?\n", - "\n", - "This is a significantly more complex problem than the ones above and you might want to split it into subproblems (for example, a good idea could be to devise a function that takes two values and returns the variation between those). There are many ways to solve it, find the one that makes more sense to you. The result should be the same for everyone, though." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "compute_variation = lambda day_before, current_day : round((current_day - day_before)/day_before, 4)\n", - "\n", - "update_value = lambda current_value, variation : current_value * (1 + variation)\n", - "\n", - "def choose_investment_decision(value_today, forecast_tomorrow, amount_invested_today, amount_in_cash_today):\n", - " new_amount_in_cash, new_amount_in_stocks = amount_in_cash_today, amount_invested_today # the baseline is that we keep the situation as is\n", - " if value_today >= forecast_tomorrow: # the stock is predicted to loose money\n", - " if amount_in_cash_today == 0: # We had money on the stock\n", - " new_amount_in_cash = amount_invested_today\n", - " new_amount_in_stocks = amount_in_cash_today\n", - " elif value_today < forecast_tomorrow: # The stock is predicted to make money\n", - " if amount_in_cash_today != 0: # Our money was in cash\n", - " new_amount_in_cash = amount_invested_today\n", - " new_amount_in_stocks = amount_in_cash_today\n", - " # Note: we can convert this large if by removing the elif and using boolean algebra (because the body is the same)\n", - " return new_amount_in_cash, new_amount_in_stocks\n", - "\n", - "def index_date(date_list, date):\n", - " for i in range(len(date_list)): \n", - " if date_list[i] == date:\n", - " return i\n", - " return -1\n", - "\n", - "def simulate_investment(stock, start_simulation, start_cash, end_simulation = -1):\n", - " if end_simulation == -1: end_simulation = len(stock)-1\n", - " cash_stocks = (start_cash, 0)\n", - " optimal_lag = optimal_order(stock)\n", - " forecast = moving_average(stock, optimal_lag)\n", - " for ii in range(start_simulation, end_simulation):\n", - " variation = compute_variation(stock[ii], stock[ii-1])\n", - " cash_stocks = (cash_stocks[0], update_value(cash_stocks[1], variation)) # The value of the stocks are updated\n", - " cash_stocks = choose_investment_decision(stock[ii], forecast[ii+1], cash_stocks[1], cash_stocks[0])\n", - " return sum(cash_stocks)\n", - "\n", - "stock_to_analyse = stock_quotes[\"AAPL\"]\n", - "index_start = index_date(stock_to_analyse[\"dates\"], '2020-02-03')\n", - "simulate_investment(stock_to_analyse[\"quotes\"], index_start, 100)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Get rich (fast) or code tryin'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The last step for today is to assess how much we will make in the near future. For this, we will use a small, non-parametric Monte-Carlo simulation.\n", - "\n", - "![monte_carlo](http://www.azquotes.com/picture-quotes/quote-in-mathematics-as-in-physics-so-much-depends-on-chance-on-a-propitious-moment-stanislaw-ulam-111-21-35.jpg)\n", - "\n", - "Here's how it will go: we are going to reuse the function that simulates the performance of our stupid investment strategy but on simulated data that will be produced in the following way: we are going to simulate 20 periods of data by resampling at random the past prices. This can be done using the function [random.choices(population, weights=None, \\*, cum_weights=None, k=1)](https://docs.python.org/3/library/random.html#random.choices): We are going to produce a list containing all the price variations of the quote. We then are going to produce a list of 20 values between 0 and the length of the list we just create and use those as variations over the next 20 days. We test our investment strategy again this \"future reality\" as if we started today with 100 Euros and the result is the final value we would have after 20 days. We have one potential result that we store in a list, called *results*. We repeat the process 5000 times (you can do it less time if your computer is rather slow). In the end, we will end up with 5000 potential results of our investment strategy over the 20 next days. I'll write the function that plots the distribution so that we can see visually what we can expect.\n", - "\n", - "Again, this whole procedure will probably require several functions. Try to break down the problem in a sequence of intermediate steps." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "import random\n", - "\n", - "def produce_variations_lists(stock_prices):\n", - " variations = []\n", - " for ii in range(1,len(stock_prices)):\n", - " variations.append(compute_variation(stock_prices[ii - 1], stock_prices[ii]))\n", - " return variations\n", - "\n", - "def produce_simulation(list_prices, n_future_periods):\n", - " return random.choices(produce_variations_lists(list_prices), k=n_future_periods)\n", - "\n", - "def simulate_profit(stock_prices, n_future_steps, n_monte_carlo):\n", - " results = []\n", - " for i in range(n_monte_carlo):\n", - " variations = produce_simulation(stock_prices, n_future_steps)\n", - " length_original_list = len(stock_prices)\n", - " simulated_list = stock_prices[:]\n", - " for variation_that_day in variations:\n", - " simulated_list.append(simulated_list[-1]*(1 + variation_that_day))\n", - " results.append(simulate_investment(simulated_list, length_original_list, 100))\n", - " return results\n", - "\n", - "stock_to_analyse = stock_quotes[\"AAPL\"][\"quotes\"][:]\n", - "results = simulate_profit(stock_to_analyse, 20, 5000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next cell will represent the distribution of your profits, only execute it once you have your 5000 results in the variable *results*." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "import seaborn as sns\n", - "\n", - "sns.distplot(results)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - }, - "name": "exercises_4.ipynb" - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Session_5/Ex 1 - UN Comtrade.ipynb b/Session_5/Ex 1 - UN Comtrade.ipynb deleted file mode 100644 index 01fb2e8..0000000 --- a/Session_5/Ex 1 - UN Comtrade.ipynb +++ /dev/null @@ -1,1036 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Dowloading Trade Data with the Comtrade API\n", - "\n", - "Many institutions including the World Bank, the Fed, or the ECB now provide access to their data bases through APIs (Automated Programming Interfaces). In this exercise we will use the United Nations Comtrade API to download trade flows. \n", - "\n", - "The trade data accessible through the API can also be downloaded manually through drop-down menus on the [comtrade website](https://comtrade.un.org/data/). But if one is interested in making multiple downloads the API will come in pretty handy. \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Working directory\n", - "First, let us set up the working directory since we will download files from the UN comtrade. If you are running this notebook from the session 5 folder of your fork, you should have it as current directory." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/home/moritz/Documents/GitHub/Classes/Session_5\n" - ] - } - ], - "source": [ - "import os\n", - "\n", - "# The os.getcwd() returns a string, you can assign it to a variable if you need using var = os.getcwd(). \n", - "# Then, var will be assigned to that string.\n", - "print(os.getcwd())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, create a folder to store the data, call it `/Data` inside your working directory. " - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "os.makedirs(\"Data\", exist_ok = True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## API Documentation\n", - "\n", - "Every API comes with a documentation. To understand how to use the Comtrade API you **need** to look at the [UN Comtrade documentation here](https://comtrade.un.org/data/doc/api/) to get an idea of the parameters required to make a request. \n", - "\n", - "Let's start with a simple request using the `requests` package, we want: \n", - "- Commodities\n", - "- Annual frequency\n", - "- Year 2013\n", - "- HS Sector Classification\n", - "- UK to World\n", - "- Imports and exports \n", - "\n", - "Check out the url including these parameters!\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Your request was successful\n" - ] - } - ], - "source": [ - "import requests\n", - "\n", - "url = \"http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=HS&ps=2013&r=826&p=0&rg=all&cc=ALL&fmt=csv&head=M\"\n", - "\n", - "data_1 = requests.get(url)\n", - "\n", - "if data_1.status_code == 200:\n", - " print(\"Your request was successful\")\n", - "else:\n", - " print(f\"Error {data_1.status_code} on your request \")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Some initial remarks: Above you might receive the \"ChunkedEncodingError\" which stops your code. If you receive this before the function \"bilateral_requests\" is defined, just run again the block of code returning the error. Instead, if you get it in the bilateral_requests call, or in the blocks of code after that, just ignore it and read the rest of the code without running it. We have not used exception handling to solve this problem on purpose, since we want to show some of the problems you might have using the UN Comtrade API. At the end of this notebook we mention this (and other problems) and possible ways to solve them, but we leave it is an exercise to include those solutions in your code.\n", - "\n", - "You don't need to always print the status code when you download data. The HTTP code 200 means that the request was succesful and the object required has been returned. You can learn more about HTTP codes [here](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). The use of HTTP codes helps when you want to use exception handling to deal with possible problems in retrieving data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that you have obtained an object as result from your query (in this case the csv file), you might want to store the file somewhere. In this case, we will use the *Data* folder of the previous step." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/\n" - ] - } - ], - "source": [ - "# Use one of the variables below depending on your OS.\n", - "\n", - "# For Windows\n", - "#data_path = os.getcwd() + \"\\\\Data\\\\UK_world\"\n", - "\n", - "# For MacOS or Linux\n", - "data_path = os.getcwd() + \"/Data/\"\n", - "\n", - "# Function to write csv for reporter and partner data\n", - "def write(req, path, reporter = \"\", partner = \"\"):\n", - " \n", - " print(f\"Writing .csv file in {path}\")\n", - "\n", - " # The function open below just opens the file defined as path in write mode. \n", - " # Then, while this file is open, the following line will write the text content of the request \n", - " # to this file (after some manipulation using join and replace)\n", - " with open(path + reporter + \"_\" + partner + \".csv\", 'w', newline = \"\") as f:\n", - " # This will access the content of our request, and we already know that it is a csv file. \n", - " # It will write that file in the directory that we specify as path.\n", - " f.write(\"\".join(req.text.replace(\";\",\"\")))\n", - " print(f\"File .csv saved in {path}\")\n", - "\n", - " \n", - "# Execute the Function \n", - "write(data_1, data_path, \"UK\", \"World\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Good job! Now you should have the csv file inside the data folder. To start all over again, let's remove it:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "os.remove(data_path + \"_.csv\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Country IDs\n", - "\n", - "The API uses numeric ISO codes for specific countries. In order to retrieve a list of country codes, the API allows the following call (see Documentation!): " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "[{'id': '4', 'text': 'Afghanistan'}, {'id': '8', 'text': 'Albania'}, {'id': '12', 'text': 'Algeria'}, {'id': '20', 'text': 'Andorra'}, {'id': '24', 'text': 'Angola'}, {'id': '660', 'text': 'Anguilla'}, {'id': '28', 'text': 'Antigua and Barbuda'}, {'id': '32', 'text': 'Argentina'}, {'id': '51', 'text': 'Armenia'}]\n" - ] - } - ], - "source": [ - "# This is the url to the json file with the id-country pairs\n", - "url_country_values= \"https://comtrade.un.org/Data/cache/reporterAreas.json\"\n", - "\n", - "country_values = requests.get(url_country_values).json()[\"results\"]\n", - "\n", - "# Let's print the first 10 codes\n", - "print(country_values[1:10])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's get the format into a more convienent shape:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n" - ] - } - ], - "source": [ - "# Object is of type\n", - "print(type(country_values))\n", - "# First item inside object is of type\n", - "print(type(country_values[1]))" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "[('4', 'Afghanistan'), ('8', 'Albania'), ('12', 'Algeria'), ('20', 'Andorra'), ('24', 'Angola'), ('660', 'Anguilla'), ('28', 'Antigua and Barbuda'), ('32', 'Argentina'), ('51', 'Armenia'), ('533', 'Aruba'), ('36', 'Australia'), ('40', 'Austria'), ('31', 'Azerbaijan'), ('44', 'Bahamas'), ('48', 'Bahrain'), ('50', 'Bangladesh'), ('52', 'Barbados'), ('112', 'Belarus'), ('56', 'Belgium'), ('58', 'Belgium-Luxembourg'), ('84', 'Belize'), ('204', 'Benin'), ('60', 'Bermuda'), ('64', 'Bhutan')]\n" - ] - } - ], - "source": [ - "# Below you can find two different ways to achieve the same result\n", - "\"\"\"\n", - "unpacked_id = []\n", - "unpacked_countries = []\n", - "for x in range(len(country_values)):\n", - " unpacked_id.append(country_values[x][\"id\"])\n", - " unpacked_countries.append(country_values[x][\"text\"])\n", - " \n", - "unpacked_values = list(zip(unpacked_id, unpacked_countries))\n", - "print(unpacked_values)\n", - "\"\"\"\n", - "unpacked_values = [(x, y) for entry in range(len(country_values)) for x, y in [(country_values[entry].get(\"id\"), country_values[entry].get(\"text\"))]]\n", - "\n", - "print(type(unpacked_values))\n", - "print(type(unpacked_values[1]))\n", - "print(unpacked_values[1:25])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since we know the name of a country but not the id, which is what we need for the API request, we can construct a function that takes the name of the country as argument and return the associated id." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The country Belgium is in the list with id 56\n", - "56\n" - ] - } - ], - "source": [ - "def obtain_id(country_name):\n", - " for x in range(len(unpacked_values)):\n", - " if country_name in unpacked_values[x]:\n", - " print(f\"The country {country_name} is in the list with id {unpacked_values[x][0]}\")\n", - " i = unpacked_values[x][0]\n", - " return i\n", - " else:\n", - " print(f\"The country {country_name} is not on the list, check the exact name used by the UN comtrade for that country\")\n", - " \n", - "# Let's try it:\n", - "print(obtain_id(\"Belgium\"))\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## API Call\n", - "\n", - "Let's build another helper function. It creates new folders to store our data with the arguments:\n", - "- Frequency\n", - "- Sector classificiation\n", - "- Year\n", - "- Reporter\n", - "\n", - "Since we work on different OS, we will also add an argument that takes the string \"Windows\" or \"MacOS\"" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [], - "source": [ - "def folder(frequency, classification, year, reporter, OS, month = \"\"):\n", - " if OS == \"Windows\":\n", - " path = os.getcwd() + \"\\\\Data\\\\\" + frequency + \"\\\\\" + classification + \"\\\\\" + year + month + \"\\\\\" + reporter\n", - " os.makedirs(path, exist_ok = True)\n", - " print(f\"The folder at {path} has been created.\")\n", - " return path + \"\\\\\"\n", - " elif OS == \"MacOS\":\n", - " path = os.getcwd() + \"/Data/\" + frequency + \"/\" + classification + \"/\" + year + month + \"/\" + reporter + \"/\"\n", - " os.makedirs(path, exist_ok = True)\n", - " print(f\"The folder at {path} has been created.\")\n", - " return path\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's creates the function with the actual call to the API. It should take as arguments the parameters required by the API. Use the name of a country instead of the id, which we can recover from the previous function. As arguments use:\n", - "\n", - "* \"frequency\" to which we will assign the value \"A\" or \"M\" to get the data frequency\n", - "* \"classification\" that takes the values \"HS\", \"H4\", etc. depending on the calssification that we want to use\n", - "* \"year\" for the data reference year\n", - "* \"reporter\" the reporter country, we will recover the id using the previous function\n", - "* \"partner\" same as reporter but for the trading partner\n", - "\n", - "For the other parameters in the URL fix the following values:\n", - "* Commodities (type=C)\n", - "* Obtaind data on imports and exports (rg=1,2)\n", - "* For all the classification codes within a classification (cc=all)\n", - "* The format returned is a csv file (fmt=csv)\n", - "\n", - "This function should return the object of the query (like we did with \"data_1 = requests.get(url)\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are including a frequency argument in the function but we will always use the annual frequency data for this exercise. If you want to get monthly data you should adjust the function in the following way:\n", - "* If you did read the documentation of the API, you should have noticed that the format of the parameter at annual frequency is 2017, 2016, etc.\n", - "* Instead, for the monthly frequency you have 201701, 201702, etc. the second part is the month\n", - "* To obtain this parameter, you should add another argument (called \"month\") to the function. You will use the values 01, 02, 03, etc. for this parameter\n", - "* In the url_year part you should concatenate the year and month arguments to get the required values, i.e. 201701.\n", - "* The only classification available for the monthly data is \"HS\"" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [], - "source": [ - "def query_constructor_C(frequency, classification, year, reporter, partner, month = \"\"):\n", - " url_frequency = \"&freq=\" + frequency\n", - " url_classification = \"&px=\" + classification\n", - " url_year = \"&ps=\" + year + month\n", - " url_reporter = \"&r=\" + obtain_id(reporter)\n", - " url_partner = \"&p=\" + obtain_id(partner)\n", - " url_final = \"&rg=1,2&cc=ALL&fmt=csv&head=M\"\n", - " url = \"http://comtrade.un.org/api/get?max=100000&type=C\" + url_frequency + url_classification + url_year + url_reporter + url_partner + url_final\n", - " print(f\"The url for {classification} and trade flows between {reporter} and {partner} in {year + month} has been created. Processing request...\")\n", - " req = requests.get(url) \n", - " print(f\"The request for {classification}, {reporter}, {partner}, {year + month} has been completed. The HTTP code is: {req.status_code}\")\n", - " print(url)\n", - " return req" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, let us try if the function is working properly. For now we will include it in a temporary function together with the folder function just to store the file. Then, we will check how to improve things." - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [], - "source": [ - "def bilateral_requests(frequency, classification, year, reporter, partner, OS, month = \"\"):\n", - " path = folder(frequency, classification, year, reporter, OS, month = month)\n", - " print(path)\n", - " req = query_constructor_C(frequency, classification, year, reporter, partner, month = month)\n", - " write(req, path, reporter, partner)\n", - " return req" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The country France is in the list with id 251\n", - "The country Germany is in the list with id 276\n", - "The url for H4 and trade flows between France and Germany in 2017 has been created. Processing request...\n", - "The request for H4, France, Germany, 2017 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2017&r=251&p=276&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 82, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check your folder now, this should have created the csv file\n", - "bilateral_requests(\"A\", \"H4\", \"2017\", \"France\", \"Germany\", \"MacOS\")\n", - "# Let us try with monthly data\n", - "#bilateral_requests(\"M\", \"HS\", \"2017\", \"France\", \"Germany\", \"MacOs\", month = \"01\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Everything should be fine for now. Instead of bilateral data, try to get trade values between France and all its trading partners." - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The country France is in the list with id 251\n", - "The country All is in the list with id all\n", - "The url for H4 and trade flows between France and All in 2017 has been created. Processing request...\n", - "The request for H4, France, All, 2017 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2017&r=251&p=all&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bilateral_requests(\"A\", \"H4\", \"2017\", \"France\", \"All\", \"MacOS\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you check the last file, you will notice that the request was successful but we did not get the data since the number of observations is above the limit. Usually, it is better to receive an error when you make the request that exceed the limit instead of a successful request code. However, this is how the UN Comtrade deisgned its API. Anyway, we can take a step back to avoid this problem. If you did check the API documentation, the UN Comtrade has a separate file to check the data availability (it returns a json with multiple informations). Let us define a couple of functions to use this data availability request." - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [], - "source": [ - "def query_availability_C(frequency, classification, year, reporter, partner = \"\", month = \"\"):\n", - " url_frequency = \"http://comtrade.un.org/api/refs/da/view?type=C&freq=\" + frequency\n", - " url_classification = \"&px=\" + classification\n", - " url_year = \"&ps=\" + year + month\n", - " url_reporter = \"&r=\" + obtain_id(reporter)\n", - " if partner == \"\":\n", - " url_partner = \"&p=\"\n", - " elif partner != \"\":\n", - " url_partner = \"&p=\" + obtain_id(partner)\n", - " url_final = \"&rg=1,2&cc=ALL\"\n", - " url = url_frequency + url_classification + url_year + url_reporter + url_partner + url_final\n", - " print(f\"The url for {classification} and trade flows between {reporter} and {partner} in {year + month} has been created. Processing data availability file...\")\n", - " req = requests.get(url).json()\n", - " print(f\"The json for {classification}, {reporter}, {partner}, {year + month} is now available. Now it is time to unpack it.\")\n", - " unpacked = [(x) for entry in range(len(req)) for x in req[entry].items()]\n", - " print(unpacked)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, start from our previous query on annual data between France and Germany." - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The country France is in the list with id 251\n", - "The country Germany is in the list with id 276\n", - "The url for H4 and trade flows between France and Germany in 2017 has been created. Processing data availability file...\n", - "The json for H4, France, Germany, 2017 is now available. Now it is time to unpack it.\n", - "[('type', 'COMMODITIES'), ('freq', 'ANNUAL'), ('px', 'H4'), ('r', '251'), ('rDesc', 'France'), ('ps', '2017'), ('TotalRecords', 684593), ('isOriginal', 0), ('publicationDate', '2018-08-24T00:00:00'), ('isPartnerDetail', 1)]\n" - ] - } - ], - "source": [ - "query_availability_C(\"A\", \"H4\", \"2017\", \"France\", partner = \"Germany\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you can see, the data availabilty json is good if you have problems for observations between a reporter country and all its trade partners, while it is useless to solve the observation problem should it arise for bilateral flows (it should not since UN Comtrade increase the max size of the request). We did include a partner paramater but the request ignored it since it is not a paramenter of the data availability query. The request sent us the number of observations for all trade flows (including re-exports and re-imports) between the reporter country and all trade partners." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us check the availability for the monthly data just for fun" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The country France is in the list with id 251\n", - "The country All is in the list with id all\n", - "The url for HS and trade flows between France and All in 201701 has been created. Processing data availability file...\n", - "The json for HS, France, All, 201701 is now available. Now it is time to unpack it.\n", - "[('type', 'COMMODITIES'), ('freq', 'MONTHLY'), ('px', 'HS'), ('r', '251'), ('rDesc', 'France'), ('ps', '201701'), ('TotalRecords', 373901), ('isOriginal', 1), ('publicationDate', '2018-08-22T00:00:00'), ('isPartnerDetail', 1)]\n" - ] - } - ], - "source": [ - "query_availability_C(\"M\", \"HS\", \"2017\", \"France\", partner = \"All\", month = \"01\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Same problem as before, we only get aggregate observations for France." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Clean the Data folder by deleting the csv files. We could also write down a function to do that. You can do that as an exercise, you will need to look at some of the functions in the os library." - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": {}, - "outputs": [], - "source": [ - "# For Windows\n", - "#os.remove(os.getcwd() + \"\\\\Data\\\\A\\\\H4\\\\2017\\\\France\\\\France_Germany.csv\")\n", - "#os.remove(os.getcwd() + \"\\\\Data\\\\A\\\\H4\\\\2017\\\\France\\\\France_All.csv\")\n", - "#os.remove(os.getcwd() + \"\\\\Data\\\\M\\\\HS\\\\201701\\\\France\\\\France_Germany.csv\")\n", - "\n", - "# For MacOS\n", - "os.remove(os.getcwd() + \"/Data/A/H4/2017/France/France_Germany.csv\")\n", - "os.remove(os.getcwd() + \"/Data/A/H4/2017/France/France_All.csv\")\n", - "#os.remove(os.getcwd() + \"/Data/M/HS/201701/France/France_Germany.csv\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will look at some of the problems that you might have using the UN Comtrade API without a license below. First, we will create a for loop to make requests for bilateral data." - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [], - "source": [ - "# We might include an elif to avoid the request for the \"All\" partner, but we do not know if, at least for some reporter country (maybe small countries) it works because there are less observations\n", - "def reporter_requests(frequency, classification, year, reporter, OS, month = \"\"):\n", - " index = 0\n", - " for x in range(len(unpacked_values)):\n", - " if reporter == unpacked_values[x][1]:\n", - " continue\n", - " else:\n", - " req = bilateral_requests(frequency, classification, year, reporter, unpacked_values[x][1], OS, month = month)\n", - " index += 1\n", - " if req.status_code != 200:\n", - " print(f\"The request was not successful for {frequency}, {classification}, {year + month}, {reporter}, {unpacked_values[x][1]}\")\n", - " break\n", - " elif index == 4:\n", - " print(f\"Since this is only an example, we stop at the index {index} since you might not want to download all the bilateral data for {reporter} in {year + month}\")\n", - " break" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The country France is in the list with id 251\n", - "The country All is in the list with id all\n", - "The url for H4 and trade flows between France and All in 2017 has been created. Processing request...\n", - "The request for H4, France, All, 2017 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2017&r=251&p=all&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The country France is in the list with id 251\n", - "The country Afghanistan is in the list with id 4\n", - "The url for H4 and trade flows between France and Afghanistan in 2017 has been created. Processing request...\n", - "The request for H4, France, Afghanistan, 2017 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2017&r=251&p=4&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The country France is in the list with id 251\n", - "The country Albania is in the list with id 8\n", - "The url for H4 and trade flows between France and Albania in 2017 has been created. Processing request...\n", - "The request for H4, France, Albania, 2017 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2017&r=251&p=8&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "The country France is in the list with id 251\n", - "The country Algeria is in the list with id 12\n", - "The url for H4 and trade flows between France and Algeria in 2017 has been created. Processing request...\n", - "The request for H4, France, Algeria, 2017 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2017&r=251&p=12&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2017/France/\n", - "Since this is only an example, we stop at the index 4 since you might not want to download all the bilateral data for France in 2017\n" - ] - } - ], - "source": [ - "reporter_requests(\"A\", \"H4\", \"2017\", \"France\", \"MacOS\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let us mention a couple of problems that you might find using the UN Comtrade API:\n", - "1. If you got an error at some point the loop will break. There are a couple of possible explanation for this:\n", - " * We know that the request for the parameters above is well defined (meaning that the data are available, believe me on this). However, as we have seen before, they might exceed the number of observations available to free users. We have seen that this still return an HTTP code equal to 200, so it does not break the loop (more on this below). More on how to deal with large number of observations below.\n", - " * Most likely, the problem is that free users can send 1 request per second. Since the files for the bilateral data are quite small, the loop might cycle requests really fast. In that case, you should get an HTTP code different from 200, breaking the loop. To avoid this, we can just import the time library and include a time.sleep(1) inside the loop.\n", - " * You exceed the number of requests (100) that free users can make to the API in a 60 minutes window. To keep track of this, we can add an index = 0 at the beginning of the function, and increase it by 1 with each iteration of the for loop. Then, just add an if statement that, when the index is close to 100, uses time.sleep() for a sufficient number of minutes to reset the counter. Inside the function, after the time.sleep(), you can reset the index and go back to the iterations of the loop. Otherwise, instead of the counter, you can use exception handling to tell the code to sleep once the API returns the error (using an HTTP code) associated to the user request limit. When you hit the limit you receive a 409 HTTP code, which would stop the code, and the first row of the last file donwloaded will tell you why you received the error and, if the error was cause by the requests limit per hour, the time in which you can get back to sending requests. You could import in Python the first row from that file to extract, using regular expressions, the time to resume the requests, and use it to restart the loop creating the requests. We will not provide the code to do that here since we already cover a lot of topics in this session. \n", - "2. The loop stops after you have already completed a certain amount of iterations. This might happen for multiple reasons such as a loss of internet connection which leads to an error when you try to make the request or you simply interrupt the code by hand to close the notebook. In that case, you do not want to download again files that you have already stored in your folder, since it will burn your number of available requests per hour. Below we address this problem using a function that tells you whether a file is already stored in your folder and, in that case, does not submit a request since you already have the file. Below we do not provide the code to deal handle the exception from the loss of internet connection during a request. Try to write it without our help!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Below the function to check the existing files in your folder." - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [], - "source": [ - "def check_existence(frequency, classification, year, reporter, partner, OS, month = \"\"):\n", - " if OS == \"Windows\":\n", - " try:\n", - " if reporter + \"_\" + partner + \".csv\" in os.listdir(os.getcwd() + \"\\\\Data\\\\\" + frequency + \"\\\\\" + classification + \"\\\\\" + year + month + \"\\\\\" + reporter):\n", - " print (f\"File {reporter}_{partner}.csv already exists, skip to next iteration.\")\n", - " return True\n", - " except FileNotFoundError:\n", - " print (f\"The folder does not exist, implying that the file {reporter}_{partner}.csv does not exist, continue with this iteration.\")\n", - " elif OS == \"MacOS\":\n", - " try:\n", - " if reporter + \"_\" + partner + \".csv\" in os.listdir(os.getcwd() + \"/Data/\" + frequency + \"/\" + classification + \"/\" + year + month + \"/\" + reporter):\n", - " print (f\"File {reporter}_{partner}.csv already exists, skip to next iteration.\")\n", - " return True\n", - " except FileNotFoundError:\n", - " print (f\"The folder does not exist, implying that the file {reporter}_{partner}.csv does not exist, continue with this iteration.\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Slightly modify the reporter_requests function defined above to include this" - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": {}, - "outputs": [], - "source": [ - "def reporter_requests_v2(frequency, classification, year, reporter, OS, month = \"\"):\n", - " index = 0\n", - " for x in range(len(unpacked_values)):\n", - " if reporter == unpacked_values[x][1]:\n", - " continue\n", - " else:\n", - " existence = check_existence(frequency, classification, year, reporter, unpacked_values[x][1], OS, month = month)\n", - " if existence:\n", - " continue\n", - " else:\n", - " req = bilateral_requests(frequency, classification, year, reporter, unpacked_values[x][1], OS, month = month)\n", - " index += 1\n", - " if req.status_code != 200:\n", - " print(f\"The request was not successful for {frequency}, {classification}, {year + month}, {reporter}, {unpacked_values[x][1]}\")\n", - " break\n", - " elif index == 4:\n", - " print(f\"Since this is only an example, we stop at the index {index} since you might not want to download all the bilateral data for {reporter} in {year + month}\")\n", - " break" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The folder does not exist, implying that the file France_All.csv does not exist, continue with this iteration.\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "The country France is in the list with id 251\n", - "The country All is in the list with id all\n", - "The url for H4 and trade flows between France and All in 2016 has been created. Processing request...\n", - "The request for H4, France, All, 2016 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2016&r=251&p=all&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "The country France is in the list with id 251\n", - "The country Afghanistan is in the list with id 4\n", - "The url for H4 and trade flows between France and Afghanistan in 2016 has been created. Processing request...\n", - "The request for H4, France, Afghanistan, 2016 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2016&r=251&p=4&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "The country France is in the list with id 251\n", - "The country Albania is in the list with id 8\n", - "The url for H4 and trade flows between France and Albania in 2016 has been created. Processing request...\n", - "The request for H4, France, Albania, 2016 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2016&r=251&p=8&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "The country France is in the list with id 251\n", - "The country Algeria is in the list with id 12\n", - "The url for H4 and trade flows between France and Algeria in 2016 has been created. Processing request...\n", - "The request for H4, France, Algeria, 2016 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=2016&r=251&p=12&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/2016/France/\n", - "Since this is only an example, we stop at the index 4 since you might not want to download all the bilateral data for France in 2016\n" - ] - } - ], - "source": [ - "reporter_requests_v2(\"A\", \"H4\", \"2016\", \"France\", \"MacOS\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To see another problem with the API, let us make a request for data that are not in the database (the H4 classification is from 2012, so there are no data using this classification in 1992)." - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The folder does not exist, implying that the file France_All.csv does not exist, continue with this iteration.\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "The country France is in the list with id 251\n", - "The country All is in the list with id all\n", - "The url for H4 and trade flows between France and All in 1992 has been created. Processing request...\n", - "The request for H4, France, All, 1992 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=1992&r=251&p=all&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "The country France is in the list with id 251\n", - "The country Afghanistan is in the list with id 4\n", - "The url for H4 and trade flows between France and Afghanistan in 1992 has been created. Processing request...\n", - "The request for H4, France, Afghanistan, 1992 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=1992&r=251&p=4&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "The country France is in the list with id 251\n", - "The country Albania is in the list with id 8\n", - "The url for H4 and trade flows between France and Albania in 1992 has been created. Processing request...\n", - "The request for H4, France, Albania, 1992 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=1992&r=251&p=8&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "The folder at /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/ has been created.\n", - "/home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "The country France is in the list with id 251\n", - "The country Algeria is in the list with id 12\n", - "The url for H4 and trade flows between France and Algeria in 1992 has been created. Processing request...\n", - "The request for H4, France, Algeria, 1992 has been completed. The HTTP code is: 200\n", - "http://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=H4&ps=1992&r=251&p=12&rg=1,2&cc=ALL&fmt=csv&head=M\n", - "Writing .csv file in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "File .csv saved in /home/moritz/Documents/GitHub/Classes/Session_5/Data/A/H4/1992/France/\n", - "Since this is only an example, we stop at the index 4 since you might not want to download all the bilateral data for France in 1992\n" - ] - } - ], - "source": [ - "reporter_requests_v2(\"A\", \"H4\", \"1992\", \"France\", \"MacOS\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you try to open one of the .csv file downloaded, you will notice that the request was successful but the first entry of the downloaded file tells you that the data are not available for that query." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Check what we get from the data availability request if we use this classification and year" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The country France is in the list with id 251\n", - "The url for H4 and trade flows between France and in 1992 has been created. Processing data availability file...\n", - "The json for H4, France, , 1992 is now available. Now it is time to unpack it.\n", - "[]\n" - ] - } - ], - "source": [ - "query_availability_C(\"A\", \"H4\", \"1992\", \"France\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It is empty, meaning that the data are not available for this combination of parameter. Let us discuss the problems of the current code and possible solutions. You can improve the code to include those solutions as an exercise." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Exceeding number of observations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We have seen that the query for the data availability does not really help to adrress this problem. We have also noticed that the request is successful but we get a file that in the first entry says \"Result too large: you do not have permissions to access such a large resultset.\".\n", - "1. Remember that our query asks for imports and exports at the same time. You can rewrite the functions to include trade_flows as argument (adjust also the functions to construct folders, etc. obvisouly). In this way, you reduce the number of observations per file, but increase the number of requests you have to make.\n", - "2. Include in our main function another function that opens each file that we download to read the first entry. If we get the string \"Results too large etc.\" we can then sae the parameters of this query to a list so that we know which query had the observations problem. Then, we will have to break down those query to find a request with fewer observations. For example, instead of downloading all the commodity codes at once, we split them up (look at the \"cc=\" parameters on the API documentation). Otherwise, split the trade flows as suggested in 1." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# More than 1 request per second" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The rate limit should return a 409 error (according to the documentation). This is the same code returned once you exceed 100 requests per hour (again, according to the documentation).\n", - "1. To avoid the more than 1 request per second problem you just need to include a time.sleep(1) between iterations of the requests. \n", - "2. Even if you have this problem, it is possible that the UN Comtrade will download a .csv file containing the error as first entry. As for the observations problem, you can just open the file and check the first entry to see if there is a problem. Then, just tell the loop to submit the query again if that was the problem listed in the file" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Usage limit, more than 100 requests per hour" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As mentioned above, this should get a 409 status code, so you can deal with it using exception handling and time.sleep(). As for the previous problems, you might get a file that in the first entry report the error, including the time at which you can start submitting requests again. You can extract that and tell Python to restart the requests at that time. Otherwise, just include an index to keep track of how many requests you have made, to stop before the limit, and to tell the code to sleep." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Data not available" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For this problem you can again use the first entry of the file downloaded, which will tell you that there is a problem of availability with the data. Otherwise, include at the start of the function the query for the avaialbility of the data. If the json from that query is an empty list you know that the data are not available, so you can avoid making that request for the data to the API. The latter approach is better since it should not burn your number of requests per hour (the request for the data availability probably is not included in the usage limit)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Folder management" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are things that you can do to improve folder management of the data downloaded while keeping track of the requests made. You should add a function that deletes the file reporting errors (without data) after you open them to get information about the error contained and the parameter used for that request. In this way you can keep track of the paramaters for which you do not have data due to errors. You should also store these information somewhere since they might be useful at some point.\n", - "\n", - "If you want to update your data files over time you can create a function that looks at the creation time of your .csv files and delete them if they are older than your desired threshold. Then, you can download them again. Whether this is useful or not depends on how often UN Comtrade revises old data. For example, they might never change the content of files for trade flows between countries in 1973. In that case, deleting the old file and downloading it again is useless since there are no changes to the data. Instead, they might update trade flows data for the last 2-3 years, so you might want to update the files associated to this time window." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/Session_5/Ex 2 - GOP Twitter.ipynb b/Session_5/Ex 2 - GOP Twitter.ipynb deleted file mode 100644 index 15bbaa6..0000000 --- a/Session_5/Ex 2 - GOP Twitter.ipynb +++ /dev/null @@ -1,696 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here we are finally at the final project. As you know, we are going to extract\n", - "information on the course of the cryptomonnages and see if the feeling of tweets expressed in relation to these cryptomonnages correlates with\n", - "the evolution of their price.\n", - "\n", - "Of course, we're not going to code everything from the beginning. We can reuse parts of the code that other people have made public to\n", - "be able to accelerate our development. These code parts are\n", - "usually called \"bookstores\" and identify which ones are useful\n", - "and how they work are often an important part of a project (especially for smaller projects).\n", - "\n", - "In this notebook, we'll see how the libraries you'll have\n", - "needed for the project is working. Of course, we will only show here\n", - "that certain functions you will probably have to use.\n", - "This list is not exhaustive and you will still need to look for\n", - "information on bookstores and functions on the internet. By\n", - "elsewhere, if you prefer to use other libraries for the project,\n", - "you're obviously free to do so.\n", - "\n", - "### Requests and APIs\n", - "\n", - "A good part of the project consists in finding information through\n", - "of API. In this section, we see what APIs are and how they work.\n", - "use them with the *requests* library.\n", - "\n", - "### What's an API?\n", - "\n", - "An API is the acronym for Application Programming Interface. It is actually\n", - "a set of instructions that the designers of an application (whether local or online) made available to other programmers who would like to use their application through code-based interactions (i.e. without going through the GUI).\n", - "\n", - "There are many APIs for a whole bunch of sites or applications. For the project, you will need to use the coinpaprika and twitter API. For\n", - "using the first API, we can use a very powerful library of\n", - "who just makes a call to the site and gets an answer. For the Twitter API, the fact that you have to identify yourself makes the process more\n", - "complex and, for this reason, we will use a library that manages\n", - "most of the authentication details for us.\n", - "\n", - "Here's a video that explains what a web API is (there are also\n", - "Local APIs, but we won't see them in this course). *The company that produced this video sells integration solutions, so the last part of the video is largely an ad but the video is\n", - "instructive if you've never used an API before.\n", - "\n", - "http://www.youtube.com/watch?feature=player_embedded&v=s7wmiS2mSXY\n", - "\n", - "#### The Game of Thrones API\n", - "\n", - "To use an API, you usually need to know what you want to\n", - "recover. During this session, and because it's in season, we're going to\n", - "use an API that allows us to access information about [Game of Thrones characters and their h](https://anapioficeandfire.com/)ouses. In this saga, characters from several families (called\n", - "houses) compete to become the Queen or King of the 7 Kingdoms, and\n", - "govern Westeros. Dragons are also part of the picture. *If you have a worse way of describing it, let me know *.\n", - "\n", - "This kind of API may seem a bit pointless as it is. However, it is\n", - "possible to couple this API with others and to program a little to get [this kind of result](https://got.show/) - a predictive model giving the likelihood that each character will die in the last season (a project from the Munich Technical University).\n", - "\n", - "The first step, after identifying the API you want to use is to read the documentation. Fortunately, in the case of the API for\n", - "GoT (we will use this abbreviation for Games of Thrones in the\n", - "rest of this notebook), it's pretty simple. The documentation can be\n", - "can be found [on this page](https://anapioficeandfire.com/Documentation).\n", - "\n", - "On this page you can find some important information:\n", - "\n", - "1. We will not be able to receive information from more than 50 characters or houses per API call.\n", - "2. There are two interesting \"features\" for us\n", - " - The one that lists the characters ([https://www.anapioficeandfire.com/api/characters](https://www.anapioficeandfire.com/api/characters) + options)\n", - " - The one that lists the houses ([https://www.anapioficeandfire.com/api/houses](https://www.anapioficeandfire.com/api/houses) + options)\n", - "\n", - "The Requests bookstore\n", - "\n", - "To use simple APIs like this one (and the one from Coinpaprika), you can use the *requests* library. This library manages the request forwading to the server, its reception and additionnally deals with formatting. Let's try to load the first outcome page consisting in all of the GoT characters. \n", - "\n", - "Let's start by importing the requests library.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import requests" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now write the string containing the address that the documentation gives as the one to get the character list. We store it in a variable and then pass it through the\n", - "string to the get() function from the requests library." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "request_string = \"https://www.anapioficeandfire.com/api/characters\"\n", - "response = requests.get(request_string)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By default, nothing is returned, but you can display the contents of the response." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'url': 'https://www.anapioficeandfire.com/api/characters/1',\n", - " 'name': '',\n", - " 'gender': 'Female',\n", - " 'culture': 'Braavosi',\n", - " 'born': '',\n", - " 'died': '',\n", - " 'titles': [''],\n", - " 'aliases': ['The Daughter of the Dusk'],\n", - " 'father': '',\n", - " 'mother': '',\n", - " 'spouse': '',\n", - " 'allegiances': [],\n", - " 'books': ['https://www.anapioficeandfire.com/api/books/5'],\n", - " 'povBooks': [],\n", - " 'tvSeries': [''],\n", - " 'playedBy': ['']},\n", - " {'url': 'https://www.anapioficeandfire.com/api/characters/2',\n", - " 'name': 'Walder',\n", - " 'gender': 'Male',\n", - " 'culture': '',\n", - " 'born': '',\n", - " 'died': '',\n", - " 'titles': [''],\n", - " 'aliases': ['Hodor'],\n", - " 'father': '',\n", - " 'mother': '',\n", - " 'spouse': '',\n", - " 'allegiances': ['https://www.anapioficeandfire.com/api/houses/362'],\n", - " 'books': ['https://www.anapioficeandfire.com/api/books/1',\n", - " 'https://www.anapioficeandfire.com/api/books/2',\n", - " 'https://www.anapioficeandfire.com/api/books/3',\n", - " 'https://www.anapioficeandfire.com/api/books/5',\n", - " 'https://www.anapioficeandfire.com/api/books/8'],\n", - " 'povBooks': [],\n", - " 'tvSeries': ['Season 1', 'Season 2', 'Season 3', 'Season 4', 'Season 6'],\n", - " 'playedBy': ['Kristian Nairn']},\n", - " {'url': 'https://www.anapioficeandfire.com/api/characters/3',\n", - " 'name': '',\n", - " 'gender': 'Male',\n", - " 'culture': '',\n", - " 'born': '',\n", - " 'died': '',\n", - " 'titles': [''],\n", - " 'aliases': ['Lamprey'],\n", - " 'father': '',\n", - " 'mother': '',\n", - " 'spouse': '',\n", - " 'allegiances': ['https://www.anapioficeandfire.com/api/houses/15'],\n", - " 'books': ['https://www.anapioficeandfire.com/api/books/3'],\n", - " 'povBooks': [],\n", - " 'tvSeries': [''],\n", - " 'playedBy': ['']}]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "response.json()[0:3]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here, we must use the .json() method because response type objects are complex and contain several elements.\n", - "\n", - "*[{'url': 'https://www.anapioficeandfire.com/api/characters/1', 'name': '', 'gender': 'Female', 'culture': 'Braavosi', 'born': '', 'died': '', 'titles': [''], 'aliases': ['The Daughter of the Dusk'], 'father': '', 'mother': '', 'spouse': '', 'allegiances': [], 'books': ['https://www.anapioficeandfire.com/api/books/5'], 'povBooks': [], 'tvSeries': [''], 'playedBy': ['']}, {'url': 'https://www.anapioficeandfire.com/api/characters/2', 'name': 'Walder', 'gender': 'Male', 'culture': '', 'born': '', 'died': '', 'titles': [''], 'aliases': ['Hodor'], 'father': '', 'mother': '', 'spouse': '', 'allegiances': ['https://www.anapioficeandfire.com/api/houses/362'], 'books': ['https://www.anapioficeandfire.com/api/books/1', 'https://www.anapioficeandfire.com/api/books/2', 'https://www.anapioficeandfire.com/api/books/3', 'https://www.anapioficeandfire.com/api/books/5', 'https://www.anapioficeandfire.com/api/books/8'], 'povBooks': [], 'tvSeries': ['Season 1', 'Season 2', 'Season 3', 'Season 4', 'Season 6'], 'playedBy': ['Kristian Nairn']}, {'url': 'https://www.anapioficeandfire.com/api/characters/3', 'name': '', 'gender': 'Male', 'culture': '', 'born': '', 'died': '', 'titles': [''], 'aliases': ['Lamprey'], 'father': '', 'mother': '', 'spouse': '', 'allegiances': ['https://www.anapioficeandfire.com/api/houses/15'], 'books': ['https://www.anapioficeandfire.com/api/books/3'], 'povBooks': [], 'tvSeries': [''], 'playedBy': ['']}]*\n", - "\n", - "As we can see, the function returned a list of 10 characters (which do not have names, this is due to the fact that, the characters being\n", - "ranked by alphabetical order, the characters whose names are\n", - "empty appear first. We'll exclude these characters a little\n", - "later).\n", - "\n", - "One problem with this result is that it only returns 10 characters. We want them all. So we'll have to create a loop that\n", - "continues to request additional pages until the answer is the\n", - "last. Since the logic is the same for the characters and the\n", - "houses, we're going to put that part of the code into a function." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'first_response' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;31m# If you don't understand the next line, it's not too bad. They are specific to the GoT API and are not really relevant to the course.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;31m# If you want to understand why this is necessary, feel free to ask the assistant or send us a mail\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0mlast_page\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfirst_response\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"Link\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mend\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mii\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mlast_page\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'first_response' is not defined" - ] - } - ], - "source": [ - "def get_GoT_info(root, start, end): # The argument is the root of the address which indicates whether we deal with the characters or the houses. \n", - " final_list = [] # Create an empty list \n", - " page_size = 50 # We take the maximum number of objects per call to avoid too many API calls. \n", - " options = {\"page\": \"1\", \"pageSize\": str(page_size)} # The options for the first page, we need them to know how many pages we should extract. \n", - " first_response = requests.get(root, params= options) # This line retrieves the first response. In this response, one of the fields in the \"headers\" contains the number of the last info page. \n", - "\n", - "# If you don't understand the next line, it's not too bad. They are specific to the GoT API and are not really relevant to the course. \n", - "# If you want to understand why this is necessary, feel free to ask the assistant or send us a mail \n", - "last_page = int(first_response.headers[\"Link\"] [-start:-end]) \n", - "\n", - "for ii in range(1,last_page+1): \n", - "\toptions = {\"page\": str(ii), \"pageSize\": str(page_size)} \n", - "\tresponse = requests.get(root, params=options) \n", - "\tfinal_list = final_list + response.json() \n", - "\treturn final_list" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The function is a bit weird but it first checks the number of content pages available on the site (you never know they add, they might add characters or houses during the last episodes). Next, for each page, we ask the site to send us the list of the 50\n", - "characters or houses on this page. The characters or houses are\n", - "stored in a list (named *response*) and finally this list is added to the resulting list of all previous iterations.\n", - "\n", - "We can now create two lists. One containing all the dictionaries representing the characters and the other one containing the dictionaries\n", - "containing the houses." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "characters = get_GoT_info(\"https://www.anapioficeandfire.com/api/characters\", 27, 25) \n", - "# Numbers 27, 26 and 25 were determined by inspecting the chains manually\n", - "houses = get_GoT_info(\"https://www.anapioficeandfire.com/api/houses\", 26, 25) \n", - "# A good exercise (but one that requires a lot of additional study) would be to automatically determine the number to be extracted. This requires the use of regular expressions (which we will not see in this course)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So much for the Game of Thrones API. Now let's see a short example of how to use the Twitter API.\n", - "\n", - "The Twitter API\n", - "\n", - "Some APIs are freely available, such as the GoT API. You can easily query them with *requests*. For Twitter, it's a bit more complicated. You need credentials.\n", - "\n", - "You can create usernames quite simply: start by creating an\n", - "Twitter account (if no member of your group has one). Make an appointment\n", - "then on the [Twitter for developers] site ([https://developer.twitter.com/](https://developer.twitter.com/)). Then create a new application. This should give you access to 4 codes identifying your account and application. These codes are\n", - "Meaningless sequences of letters and numbers.\n", - "\n", - "To use the Twitter API, we will use the [Python-Twitter] library ([https://python-twitter.readthedocs.io/en/latest/](https://python-twitter.readthedocs.io/en/latest/)). Using this library, you just have to give the credentials you received from Twitter and make requests." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "api_key = \"5oxVSi0q8FWGKSZ68D2iwnFLZ\"\n", - "api_secret_key = \"51esJc1fCtAWpgBPd6TVr4Lun5QbtjI6afOJ00uPBD1x74L8eL\"\n", - "access_token = \"4143588544-7mu5NDQ7x1xa1hoIsZn2sT93GI01zbBDVue634c\"\n", - "access_secret_token = \"qQqrfGwuEduRZ5uAqekq72IoqkdDbdfsZVjB4NiV17wSJ\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now create an *API* object from the library. This object (we haven't seen the objects during this class, this would probably be the next topic you could study if you want to go further in the concepts) allows us to make queries to Twitter which can send us a copy of the tweets according to certain criteria.\n", - "\n", - "A detailed understanding of the library requires reading in detail\n", - "documentation but, for simple queries, you can use\n", - "the following workflow: create an API object $\\rightarrow$ define a string representing the search $\\rightarrow$ send it to the *getSearch()* method of the API object $\\rightarrow$ process the resulting list." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "#import sys\n", - "#!{sys.executable} -m pip install twitter\n", - "\n", - "from twitter import *\n", - "\n", - "api = Twitter(\n", - " auth=OAuth(token=access_token, token_secret=access_secret_token, \n", - " consumer_key=api_key, consumer_secret=api_secret_key))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The above code creates the API object. We can now create the request. In that case, we'll just search all the tweets regarding the houses of Stark, Lannister and Targaryen." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "main_houses = [\"Stark\", \"Lannister\", \"Targaryen\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we need to format a search string. To do this, you can use the search page in the following way: use the advanced search tool,\n", - "specifying the parameters you want. Then copy the parameter part of the URL." - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['HouseStark', 'HouseLannister', 'HouseTargaryen']\n" - ] - } - ], - "source": [ - "query_chain = [\"House\"+name for name in main_houses]\n", - "print(query_chain)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'statuses': [{'created_at': 'Mon Mar 09 06:29:26 +0000 2020', 'id': 1236901891394670594, 'id_str': '1236901891394670594', 'text': \"@bIuerosez Seconded. People lack the ability to see the nuanced characters. Some people are not all good. And they'… https://t.co/vWNVRRa1nU\", 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [{'screen_name': 'bIuerosez', 'name': 'chi', 'id': 1159864331066052608, 'id_str': '1159864331066052608', 'indices': [0, 10]}], 'urls': [{'url': 'https://t.co/vWNVRRa1nU', 'expanded_url': 'https://twitter.com/i/web/status/1236901891394670594', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': 1236818877109149704, 'in_reply_to_status_id_str': '1236818877109149704', 'in_reply_to_user_id': 1159864331066052608, 'in_reply_to_user_id_str': '1159864331066052608', 'in_reply_to_screen_name': 'bIuerosez', 'user': {'id': 1051029304103096320, 'id_str': '1051029304103096320', 'name': 'Rhᥲᥱᥒყs Tᥲrgᥲrყᥱᥒ', 'screen_name': 'Rhaenys_IX', 'location': 'Ikeja, Nigeria', 'description': '🇧\\u200b🇺\\u200b🇷\\u200b🇳\\u200b🇪\\u200b🇩\\u200b 🇦\\u200b🇳\\u200b🇩\\u200b 🇺\\u200b🇳\\u200b🇧\\u200b🇴\\u200b🇼\\u200b🇪\\u200b🇩\\u200b', 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 396, 'friends_count': 343, 'listed_count': 0, 'created_at': 'Sat Oct 13 08:38:08 +0000 2018', 'favourites_count': 4633, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 3256, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'F5F8FA', 'profile_background_image_url': None, 'profile_background_image_url_https': None, 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1229689925001531393/MeUUKGMU_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1229689925001531393/MeUUKGMU_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1051029304103096320/1582054223', 'profile_link_color': '1DA1F2', 'profile_sidebar_border_color': 'C0DEED', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': True, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 20:54:56 +0000 2020', 'id': 1236757315497459718, 'id_str': '1236757315497459718', 'text': 'günde sadece 4 saat uyku\\ndört bir yanı hain dolu \\nyoruldun biliyoruz ama \\nbu dava sensiz olmaz daenerys… https://t.co/SzmYA4A4YD', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/SzmYA4A4YD', 'expanded_url': 'https://twitter.com/i/web/status/1236757315497459718', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [105, 128]}]}, 'metadata': {'result_type': 'recent', 'iso_language_code': 'tr'}, 'source': 'Twitter for iPhone', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 314407493, 'id_str': '314407493', 'name': 'zeynep ünsal', 'screen_name': 'znsal', 'location': 'Ankara, Türkiye', 'description': 'passionate artist & potential architect in the cyber world', 'url': 'https://t.co/jv9NEU3fWY', 'entities': {'url': {'urls': [{'url': 'https://t.co/jv9NEU3fWY', 'expanded_url': 'http://instagram.com/unsalz/', 'display_url': 'instagram.com/unsalz/', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 475, 'friends_count': 134, 'listed_count': 3, 'created_at': 'Fri Jun 10 06:20:39 +0000 2011', 'favourites_count': 1887, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 1756, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '131516', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme17/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme17/bg.gif', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1236755439922094081/NDnh7zIC_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1236755439922094081/NDnh7zIC_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/314407493/1581453720', 'profile_link_color': '981CEB', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': 'C8CF02', 'profile_text_color': 'E6781E', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'regular'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 12, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'tr'}, {'created_at': 'Sun Mar 08 19:24:02 +0000 2020', 'id': 1236734438140252160, 'id_str': '1236734438140252160', 'text': 'RT @AilikHeda_: Siccome mi sentivo abbastanza in vena ho scritto un nuovo capitolo che ha 3 pov!\\nhttps://t.co/Z79finLEmY\\n#GameOfThrones #Go…', 'truncated': False, 'entities': {'hashtags': [{'text': 'GameOfThrones', 'indices': [121, 135]}], 'symbols': [], 'user_mentions': [{'screen_name': 'AilikHeda_', 'name': 'ثریا', 'id': 1003252529403219968, 'id_str': '1003252529403219968', 'indices': [3, 14]}], 'urls': [{'url': 'https://t.co/Z79finLEmY', 'expanded_url': 'https://efpfanfic.net/viewstory.php?sid=3890200', 'display_url': 'efpfanfic.net/viewstory.php?…', 'indices': [97, 120]}]}, 'metadata': {'iso_language_code': 'it', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 1003252529403219968, 'id_str': '1003252529403219968', 'name': 'ثریا', 'screen_name': 'AilikHeda_', 'location': 'lost in Westeros ~', 'description': \"|So che è orgogliosa. Perché no? Che altro le rimaneva, se non l'orgoglio? So che è forte. Come poteva essere altrimenti?| \\n|Jus drein jus daun| \\n~FAN ACCOUNT~\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 450, 'friends_count': 538, 'listed_count': 6, 'created_at': 'Sun Jun 03 12:30:17 +0000 2018', 'favourites_count': 10964, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 11959, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '000000', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1236719448217866241/oyvFPnyo_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1236719448217866241/oyvFPnyo_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1003252529403219968/1583240442', 'profile_link_color': '1B95E0', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': '000000', 'profile_text_color': '000000', 'profile_use_background_image': False, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'retweeted_status': {'created_at': 'Sat Mar 07 20:05:28 +0000 2020', 'id': 1236382480418197504, 'id_str': '1236382480418197504', 'text': 'Siccome mi sentivo abbastanza in vena ho scritto un nuovo capitolo che ha 3 pov!\\nhttps://t.co/Z79finLEmY… https://t.co/D1efcXoFp3', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/Z79finLEmY', 'expanded_url': 'https://efpfanfic.net/viewstory.php?sid=3890200', 'display_url': 'efpfanfic.net/viewstory.php?…', 'indices': [81, 104]}, {'url': 'https://t.co/D1efcXoFp3', 'expanded_url': 'https://twitter.com/i/web/status/1236382480418197504', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [106, 129]}]}, 'metadata': {'iso_language_code': 'it', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 1003252529403219968, 'id_str': '1003252529403219968', 'name': 'ثریا', 'screen_name': 'AilikHeda_', 'location': 'lost in Westeros ~', 'description': \"|So che è orgogliosa. Perché no? Che altro le rimaneva, se non l'orgoglio? So che è forte. Come poteva essere altrimenti?| \\n|Jus drein jus daun| \\n~FAN ACCOUNT~\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 450, 'friends_count': 538, 'listed_count': 6, 'created_at': 'Sun Jun 03 12:30:17 +0000 2018', 'favourites_count': 10964, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 11959, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '000000', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1236719448217866241/oyvFPnyo_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1236719448217866241/oyvFPnyo_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1003252529403219968/1583240442', 'profile_link_color': '1B95E0', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': '000000', 'profile_text_color': '000000', 'profile_use_background_image': False, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'it'}, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'it'}, {'created_at': 'Sun Mar 08 13:52:08 +0000 2020', 'id': 1236650913659379713, 'id_str': '1236650913659379713', 'text': 'LOVE YOUUUUU ALL TARGARYEN!!! \\nu made ur momma proud, as always\\n- your cute house head -\\n[ day 2 ]\\n@PlmAces… https://t.co/ruWCh6OR8X', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [{'screen_name': 'PlmAces', 'name': 'PLM-ACES', 'id': 1167436768255172608, 'id_str': '1167436768255172608', 'indices': [99, 107]}], 'urls': [{'url': 'https://t.co/ruWCh6OR8X', 'expanded_url': 'https://twitter.com/i/web/status/1236650913659379713', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [109, 132]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 1008623532, 'id_str': '1008623532', 'name': 'biancake 🌻', 'screen_name': 'iambiancafaye', 'location': 'Philippines', 'description': 'take the moment and make it perfect.', 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 653, 'friends_count': 431, 'listed_count': 2, 'created_at': 'Thu Dec 13 11:48:23 +0000 2012', 'favourites_count': 13886, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 15606, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'ACDED6', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme18/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme18/bg.gif', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1191938071585009664/OQN3d_t__normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1191938071585009664/OQN3d_t__normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1008623532/1576898320', 'profile_link_color': '91D2FA', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'F6F6F6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 5, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 01:09:27 +0000 2020', 'id': 1236458980362326022, 'id_str': '1236458980362326022', 'text': 'ArtOfWarXWarOfArt \\n\\n#representltd #rephard #newera #neweracap #got #housetargaryen #dragons https://t.co/xFbUqfSdot', 'truncated': False, 'entities': {'hashtags': [{'text': 'representltd', 'indices': [20, 33]}, {'text': 'rephard', 'indices': [34, 42]}, {'text': 'newera', 'indices': [43, 50]}, {'text': 'neweracap', 'indices': [51, 61]}, {'text': 'got', 'indices': [62, 66]}, {'text': 'housetargaryen', 'indices': [67, 82]}, {'text': 'dragons', 'indices': [83, 91]}], 'symbols': [], 'user_mentions': [], 'urls': [], 'media': [{'id': 1236458967905316865, 'id_str': '1236458967905316865', 'indices': [92, 115], 'media_url': 'http://pbs.twimg.com/media/ESjI4VlXsAEgEq7.jpg', 'media_url_https': 'https://pbs.twimg.com/media/ESjI4VlXsAEgEq7.jpg', 'url': 'https://t.co/xFbUqfSdot', 'display_url': 'pic.twitter.com/xFbUqfSdot', 'expanded_url': 'https://twitter.com/unable08/status/1236458980362326022/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'large': {'w': 2048, 'h': 2048, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 1200, 'resize': 'fit'}, 'small': {'w': 680, 'h': 680, 'resize': 'fit'}}}]}, 'extended_entities': {'media': [{'id': 1236458967905316865, 'id_str': '1236458967905316865', 'indices': [92, 115], 'media_url': 'http://pbs.twimg.com/media/ESjI4VlXsAEgEq7.jpg', 'media_url_https': 'https://pbs.twimg.com/media/ESjI4VlXsAEgEq7.jpg', 'url': 'https://t.co/xFbUqfSdot', 'display_url': 'pic.twitter.com/xFbUqfSdot', 'expanded_url': 'https://twitter.com/unable08/status/1236458980362326022/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'large': {'w': 2048, 'h': 2048, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 1200, 'resize': 'fit'}, 'small': {'w': 680, 'h': 680, 'resize': 'fit'}}}]}, 'metadata': {'iso_language_code': 'und', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 46298804, 'id_str': '46298804', 'name': 'abe', 'screen_name': 'unable08', 'location': '', 'description': 'my crappy audio covers', 'url': 'https://t.co/rQLeFB0up9', 'entities': {'url': {'urls': [{'url': 'https://t.co/rQLeFB0up9', 'expanded_url': 'http://www.youtube.com/pacadoy08', 'display_url': 'youtube.com/pacadoy08', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 75, 'friends_count': 544, 'listed_count': 0, 'created_at': 'Thu Jun 11 03:02:45 +0000 2009', 'favourites_count': 17347, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 794, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '1A1B1F', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme9/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme9/bg.gif', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/929414153403371521/n49-iwxj_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/929414153403371521/n49-iwxj_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/46298804/1390739435', 'profile_link_color': '2FC2EF', 'profile_sidebar_border_color': '181A1E', 'profile_sidebar_fill_color': '252429', 'profile_text_color': '666666', 'profile_use_background_image': True, 'has_extended_profile': False, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'und'}, {'created_at': 'Sat Mar 07 20:05:28 +0000 2020', 'id': 1236382480418197504, 'id_str': '1236382480418197504', 'text': 'Siccome mi sentivo abbastanza in vena ho scritto un nuovo capitolo che ha 3 pov!\\nhttps://t.co/Z79finLEmY… https://t.co/D1efcXoFp3', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/Z79finLEmY', 'expanded_url': 'https://efpfanfic.net/viewstory.php?sid=3890200', 'display_url': 'efpfanfic.net/viewstory.php?…', 'indices': [81, 104]}, {'url': 'https://t.co/D1efcXoFp3', 'expanded_url': 'https://twitter.com/i/web/status/1236382480418197504', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [106, 129]}]}, 'metadata': {'iso_language_code': 'it', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 1003252529403219968, 'id_str': '1003252529403219968', 'name': 'ثریا', 'screen_name': 'AilikHeda_', 'location': 'lost in Westeros ~', 'description': \"|So che è orgogliosa. Perché no? Che altro le rimaneva, se non l'orgoglio? So che è forte. Come poteva essere altrimenti?| \\n|Jus drein jus daun| \\n~FAN ACCOUNT~\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 450, 'friends_count': 538, 'listed_count': 6, 'created_at': 'Sun Jun 03 12:30:17 +0000 2018', 'favourites_count': 10964, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 11959, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '000000', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1236719448217866241/oyvFPnyo_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1236719448217866241/oyvFPnyo_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1003252529403219968/1583240442', 'profile_link_color': '1B95E0', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': '000000', 'profile_text_color': '000000', 'profile_use_background_image': False, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'it'}, {'created_at': 'Sat Mar 07 03:37:48 +0000 2020', 'id': 1236133926441078784, 'id_str': '1236133926441078784', 'text': 'What to name blackened fossil of flying beasts? Easy. \\n#HouseTargaryen represent! \\n\\n#ASOIAF #GameofThrones \\nhttps://t.co/EUh2ZIEtyQ', 'truncated': False, 'entities': {'hashtags': [{'text': 'HouseTargaryen', 'indices': [55, 70]}, {'text': 'ASOIAF', 'indices': [84, 91]}, {'text': 'GameofThrones', 'indices': [92, 106]}], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/EUh2ZIEtyQ', 'expanded_url': 'http://bit.ly/2TvICGA', 'display_url': 'bit.ly/2TvICGA', 'indices': [108, 131]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 1103695946, 'id_str': '1103695946', 'name': 'Westeros Philippines', 'screen_name': 'WesterosPH', 'location': 'Manila City, National Capital', 'description': \"This is a fanbase for all Filipinos devoted to GRRM's A Song Of Ice and Fire as well as HBO's Game Of Thrones.\\nFollowed by @GameOfThrones\", 'url': 'https://t.co/5azIXSfS1F', 'entities': {'url': {'urls': [{'url': 'https://t.co/5azIXSfS1F', 'expanded_url': 'https://www.facebook.com/groups/WesterosPhilippines/', 'display_url': 'facebook.com/groups/Westero…', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 1490, 'friends_count': 366, 'listed_count': 37, 'created_at': 'Sat Jan 19 13:27:36 +0000 2013', 'favourites_count': 13821, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 8430, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'E1E6CF', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme9/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme9/bg.gif', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1113243610823020544/71nfiHa7_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1113243610823020544/71nfiHa7_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1103695946/1505445413', 'profile_link_color': '2FC2EF', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': '252429', 'profile_text_color': '666666', 'profile_use_background_image': True, 'has_extended_profile': False, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, {'created_at': 'Fri Mar 06 21:44:21 +0000 2020', 'id': 1236044976468955136, 'id_str': '1236044976468955136', 'text': 'At least we have the prequel to look forward to. #remember #got #housetargaryen #backtowork https://t.co/JE4Zvrr6yN https://t.co/HSmB8vmtax', 'truncated': False, 'entities': {'hashtags': [{'text': 'remember', 'indices': [50, 59]}, {'text': 'got', 'indices': [60, 64]}, {'text': 'housetargaryen', 'indices': [65, 80]}, {'text': 'backtowork', 'indices': [81, 92]}], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/JE4Zvrr6yN', 'expanded_url': 'https://ift.tt/2xa7k6m', 'display_url': 'ift.tt/2xa7k6m', 'indices': [93, 116]}], 'media': [{'id': 1236044975051362306, 'id_str': '1236044975051362306', 'indices': [117, 140], 'media_url': 'http://pbs.twimg.com/media/ESdQWyBX0AIZraT.jpg', 'media_url_https': 'https://pbs.twimg.com/media/ESdQWyBX0AIZraT.jpg', 'url': 'https://t.co/HSmB8vmtax', 'display_url': 'pic.twitter.com/HSmB8vmtax', 'expanded_url': 'https://twitter.com/BruniWeb/status/1236044976468955136/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 640, 'h': 640, 'resize': 'fit'}, 'medium': {'w': 640, 'h': 640, 'resize': 'fit'}, 'large': {'w': 640, 'h': 640, 'resize': 'fit'}}}]}, 'extended_entities': {'media': [{'id': 1236044975051362306, 'id_str': '1236044975051362306', 'indices': [117, 140], 'media_url': 'http://pbs.twimg.com/media/ESdQWyBX0AIZraT.jpg', 'media_url_https': 'https://pbs.twimg.com/media/ESdQWyBX0AIZraT.jpg', 'url': 'https://t.co/HSmB8vmtax', 'display_url': 'pic.twitter.com/HSmB8vmtax', 'expanded_url': 'https://twitter.com/BruniWeb/status/1236044976468955136/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 640, 'h': 640, 'resize': 'fit'}, 'medium': {'w': 640, 'h': 640, 'resize': 'fit'}, 'large': {'w': 640, 'h': 640, 'resize': 'fit'}}}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'IFTTT', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 755811438, 'id_str': '755811438', 'name': 'Fred M. Bruni II', 'screen_name': 'BruniWeb', 'location': 'USA & INTERNATIONAL ', 'description': 'I deeply enjoy uncomfortable biblical truths... and the rest of the Bible of course.', 'url': 'https://t.co/P6kdWNtNUO', 'entities': {'url': {'urls': [{'url': 'https://t.co/P6kdWNtNUO', 'expanded_url': 'http://digitalcreative.studio', 'display_url': 'digitalcreative.studio', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 594, 'friends_count': 1312, 'listed_count': 38, 'created_at': 'Mon Aug 13 20:52:23 +0000 2012', 'favourites_count': 113, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 1011, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '000000', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1206775918959550465/xBhnyoZx_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1206775918959550465/xBhnyoZx_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/755811438/1576552775', 'profile_link_color': '16AAE0', 'profile_sidebar_border_color': 'C0DEED', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, {'created_at': 'Fri Mar 06 18:06:43 +0000 2020', 'id': 1235990206488158208, 'id_str': '1235990206488158208', 'text': 'Thereby the two rival branches of House Targaryen were united and two years of treachery and carnage were ended.… https://t.co/zBEctqv0fm', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/zBEctqv0fm', 'expanded_url': 'https://twitter.com/i/web/status/1235990206488158208', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [114, 137]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1235989932822405121, 'in_reply_to_status_id_str': '1235989932822405121', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 5, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Fri Mar 06 18:01:34 +0000 2020', 'id': 1235988908850151430, 'id_str': '1235988908850151430', 'text': 'They raised in its place the red dragon of the first Aegon, the banner that all the Targaryen kings had flow until… https://t.co/zxwuepXudV', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/zxwuepXudV', 'expanded_url': 'https://twitter.com/i/web/status/1235988908850151430', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [116, 139]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1235988680113827845, 'in_reply_to_status_id_str': '1235988680113827845', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 2, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Fri Mar 06 16:19:55 +0000 2020', 'id': 1235963327924391936, 'id_str': '1235963327924391936', 'text': 'Uma coisa importante que aprendemos muito com a Dany é: sempre vai ter um macho querendo de comer e te subestimando… https://t.co/2pO7JEQdDR', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/2pO7JEQdDR', 'expanded_url': 'https://twitter.com/i/web/status/1235963327924391936', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'pt', 'result_type': 'recent'}, 'source': 'Twitter for iPhone', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 214275534, 'id_str': '214275534', 'name': 'Jo Pais', 'screen_name': 'jopais_', 'location': 'Recife, Pernambuco', 'description': 'Senhora das Tempestades. Escritora de ranhuras. Fotógrafa de relatos estranhos. Um saco de longas histórias. House of DC.', 'url': 'https://t.co/HjAQUr5L9z', 'entities': {'url': {'urls': [{'url': 'https://t.co/HjAQUr5L9z', 'expanded_url': 'http://www.instagram.com/jopais_', 'display_url': 'instagram.com/jopais_', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 339, 'friends_count': 465, 'listed_count': 10, 'created_at': 'Thu Nov 11 00:41:29 +0000 2010', 'favourites_count': 4404, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 53564, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'FCFCFC', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme19/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme19/bg.gif', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1225456949686349828/q4AtpftN_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1225456949686349828/q4AtpftN_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/214275534/1578790927', 'profile_link_color': '000000', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': 'FAFAFA', 'profile_text_color': '333333', 'profile_use_background_image': False, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': True, 'lang': 'pt'}, {'created_at': 'Fri Mar 06 16:00:03 +0000 2020', 'id': 1235958329467420672, 'id_str': '1235958329467420672', 'text': '#DaenerysTargaryen #HouseTargaryen #GameOfThrones \\n\\nDaenerys Targaryen the queen of the seven kingdoms! THE QUEEN O… https://t.co/wYeimtE5jX', 'truncated': True, 'entities': {'hashtags': [{'text': 'DaenerysTargaryen', 'indices': [0, 18]}, {'text': 'HouseTargaryen', 'indices': [19, 34]}, {'text': 'GameOfThrones', 'indices': [35, 49]}], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/wYeimtE5jX', 'expanded_url': 'https://twitter.com/i/web/status/1235958329467420672', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 1004037379437551617, 'id_str': '1004037379437551617', 'name': '🔥🐉 𝓦𝓸𝓵𝓯 𝓒𝓵𝓪𝓻𝓴𝓮 𝓣𝓪𝓻𝓰𝓪𝓻𝔂𝓮𝓷 🐉🔥', 'screen_name': 'WolfTargaryen_', 'location': '𝓓𝓻𝓪𝓰𝓸𝓷𝓼𝓽𝓸𝓷𝓮', 'description': '🔥𝓕𝓲𝓻𝓮 𝓪𝓷𝓭 𝓑𝓵𝓸𝓸𝓭!🔥\\n\\n🐉 𝓗𝓸𝓾𝓼𝓮 𝓣𝓪𝓻𝓰𝓪𝓻𝔂𝓮𝓷 🐉\\n\\n🏎 𝓕𝓸𝓻𝓶𝓾𝓵𝓪 1 𝓕𝓪𝓷 🏎\\n \\n(𝓕𝓪𝓷 𝓐𝓬𝓬𝓸𝓾𝓷𝓽)', 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 448, 'friends_count': 397, 'listed_count': 4, 'created_at': 'Tue Jun 05 16:29:00 +0000 2018', 'favourites_count': 11171, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 12693, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '000000', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1236493272035590145/K93mQHs7_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1236493272035590145/K93mQHs7_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1004037379437551617/1582270501', 'profile_link_color': '7FFF00', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': '000000', 'profile_text_color': '000000', 'profile_use_background_image': False, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, {'created_at': 'Fri Mar 06 04:45:58 +0000 2020', 'id': 1235788693014745089, 'id_str': '1235788693014745089', 'text': 'I LOVE GAME OF JONES AND I MISS GAME OF THRONES!! Haha #HouseSharks #HouseTargaryen 😜❤️👊🏻👊🏻👊🏻🔥 https://t.co/uFuiId0WBI', 'truncated': False, 'entities': {'hashtags': [{'text': 'HouseSharks', 'indices': [55, 67]}, {'text': 'HouseTargaryen', 'indices': [68, 83]}], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/uFuiId0WBI', 'expanded_url': 'https://twitter.com/sanjosesharks/status/1235787798562521091', 'display_url': 'twitter.com/sanjosesharks/…', 'indices': [95, 118]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for iPhone', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 1148248129, 'id_str': '1148248129', 'name': 'Brennan', 'screen_name': 'Bonespinpin', 'location': '', 'description': \"22 years old! 😜🤘🏻A big fan of hockey! San Jose Sharks! 🏒☺️ A big fan of BONES!! ❤️❤️ And I'm in love with IRON MAN! I love you 3000!! 😍❤️ RDJ\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 236, 'friends_count': 1273, 'listed_count': 5, 'created_at': 'Mon Feb 04 15:04:00 +0000 2013', 'favourites_count': 30967, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 15140, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'FFF04D', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1097887591481921537/SxchYtt5_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1097887591481921537/SxchYtt5_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/1148248129/1501029361', 'profile_link_color': '0099CC', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': True, 'quoted_status_id': 1235787798562521091, 'quoted_status_id_str': '1235787798562521091', 'quoted_status': {'created_at': 'Fri Mar 06 04:42:25 +0000 2020', 'id': 1235787798562521091, 'id_str': '1235787798562521091', 'text': 'Martin Jones save appreciation tweet. \\n\\n#SJSharks https://t.co/oUzQxnMehe', 'truncated': False, 'entities': {'hashtags': [{'text': 'SJSharks', 'indices': [40, 49]}], 'symbols': [], 'user_mentions': [], 'urls': [], 'media': [{'id': 1235787378004045824, 'id_str': '1235787378004045824', 'indices': [50, 73], 'media_url': 'http://pbs.twimg.com/media/ESZmNZLU4AAyei-.jpg', 'media_url_https': 'https://pbs.twimg.com/media/ESZmNZLU4AAyei-.jpg', 'url': 'https://t.co/oUzQxnMehe', 'display_url': 'pic.twitter.com/oUzQxnMehe', 'expanded_url': 'https://twitter.com/SanJoseSharks/status/1235787798562521091/video/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}, 'large': {'w': 1280, 'h': 720, 'resize': 'fit'}}}]}, 'extended_entities': {'media': [{'id': 1235787378004045824, 'id_str': '1235787378004045824', 'indices': [50, 73], 'media_url': 'http://pbs.twimg.com/media/ESZmNZLU4AAyei-.jpg', 'media_url_https': 'https://pbs.twimg.com/media/ESZmNZLU4AAyei-.jpg', 'url': 'https://t.co/oUzQxnMehe', 'display_url': 'pic.twitter.com/oUzQxnMehe', 'expanded_url': 'https://twitter.com/SanJoseSharks/status/1235787798562521091/video/1', 'type': 'video', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'medium': {'w': 1200, 'h': 675, 'resize': 'fit'}, 'small': {'w': 680, 'h': 383, 'resize': 'fit'}, 'large': {'w': 1280, 'h': 720, 'resize': 'fit'}}, 'video_info': {'aspect_ratio': [16, 9], 'duration_millis': 12646, 'variants': [{'content_type': 'application/x-mpegURL', 'url': 'https://video.twimg.com/amplify_video/1235787378004045824/pl/8_ItPNlvO_GvPR65.m3u8?tag=13'}, {'bitrate': 832000, 'content_type': 'video/mp4', 'url': 'https://video.twimg.com/amplify_video/1235787378004045824/vid/640x360/Qrn_34ylf0dHhA1H.mp4?tag=13'}, {'bitrate': 288000, 'content_type': 'video/mp4', 'url': 'https://video.twimg.com/amplify_video/1235787378004045824/vid/480x270/P3jTWzH-wJztuJ7F.mp4?tag=13'}, {'bitrate': 2176000, 'content_type': 'video/mp4', 'url': 'https://video.twimg.com/amplify_video/1235787378004045824/vid/1280x720/bnCYx8ZcidTs8l7_.mp4?tag=13'}]}, 'additional_media_info': {'title': '', 'description': '', 'embeddable': True, 'monetizable': False}}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Media Studio', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 27961547, 'id_str': '27961547', 'name': 'San Jose Sharks', 'screen_name': 'SanJoseSharks', 'location': '#SharksTerritory', 'description': '\"\\'I just want to keep smiling and keep a positive mind\\' - Tomas Hertl\" - San Jose Sharks', 'url': 'https://t.co/wS3IYB9Wsq', 'entities': {'url': {'urls': [{'url': 'https://t.co/wS3IYB9Wsq', 'expanded_url': 'http://sjsharks.com', 'display_url': 'sjsharks.com', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 823133, 'friends_count': 482, 'listed_count': 5387, 'created_at': 'Tue Mar 31 20:57:57 +0000 2009', 'favourites_count': 6431, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': True, 'statuses_count': 57609, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'FFFFFF', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1236799341244739584/mS5KTBgb_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1236799341244739584/mS5KTBgb_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/27961547/1583551737', 'profile_link_color': '00788A', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': '000000', 'profile_text_color': '00788B', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 36, 'favorite_count': 285, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, {'created_at': 'Fri Mar 06 03:28:37 +0000 2020', 'id': 1235769225299529728, 'id_str': '1235769225299529728', 'text': 'RT @WatchersOTWall: Doing Justice to Helaena Targaryen and the Women of Westeros – a House of the Dragon video essay by @PLHalbur https://t…', 'truncated': False, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [{'screen_name': 'WatchersOTWall', 'name': 'Watchers on the Wall', 'id': 2679863268, 'id_str': '2679863268', 'indices': [3, 18]}, {'screen_name': 'PLHalbur', 'name': 'Petra Halbur', 'id': 324909635, 'id_str': '324909635', 'indices': [120, 129]}], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for iPhone', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 612018761, 'id_str': '612018761', 'name': 'Michelle Carter', 'screen_name': 'CarterMlc2139', 'location': '', 'description': '', 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 57, 'friends_count': 390, 'listed_count': 0, 'created_at': 'Mon Jun 18 21:36:48 +0000 2012', 'favourites_count': 18218, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 8385, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'C0DEED', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/2320597819/image_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/2320597819/image_normal.jpg', 'profile_link_color': '1DA1F2', 'profile_sidebar_border_color': 'C0DEED', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': False, 'default_profile': True, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'retweeted_status': {'created_at': 'Tue Mar 03 15:27:52 +0000 2020', 'id': 1234863066656989184, 'id_str': '1234863066656989184', 'text': 'Doing Justice to Helaena Targaryen and the Women of Westeros – a House of the Dragon video essay by @PLHalbur… https://t.co/1kvVZAXQBo', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [{'screen_name': 'PLHalbur', 'name': 'Petra Halbur', 'id': 324909635, 'id_str': '324909635', 'indices': [100, 109]}], 'urls': [{'url': 'https://t.co/1kvVZAXQBo', 'expanded_url': 'https://twitter.com/i/web/status/1234863066656989184', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [111, 134]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 2679863268, 'id_str': '2679863268', 'name': 'Watchers on the Wall', 'screen_name': 'WatchersOTWall', 'location': 'USA', 'description': 'A Game of Thrones Community for Breaking News, Casting, and Commentary.', 'url': 'https://t.co/8ViHtiyPql', 'entities': {'url': {'urls': [{'url': 'https://t.co/8ViHtiyPql', 'expanded_url': 'http://watchersonthewall.com/', 'display_url': 'watchersonthewall.com', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 67801, 'friends_count': 794, 'listed_count': 606, 'created_at': 'Fri Jul 25 15:45:36 +0000 2014', 'favourites_count': 10954, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 15472, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '000000', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme14/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme14/bg.gif', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1213853941777219584/dEMFRDFY_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1213853941777219584/dEMFRDFY_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2679863268/1583716584', 'profile_link_color': '000000', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': 'EFEFEF', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': False, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 5, 'favorite_count': 36, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, 'is_quote_status': False, 'retweet_count': 5, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Fri Mar 06 02:22:42 +0000 2020', 'id': 1235752637217284096, 'id_str': '1235752637217284096', 'text': 'ACABEI DE DESCOBRIR: GIZELLY É UMA TARGARYEN.\\nFOGO, AANGUE E LABAREDA-SE É O NOVO DRACARYS #BBB20 #GoT… https://t.co/R8ngVNVywL', 'truncated': True, 'entities': {'hashtags': [{'text': 'BBB20', 'indices': [91, 97]}, {'text': 'GoT', 'indices': [98, 102]}], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/R8ngVNVywL', 'expanded_url': 'https://twitter.com/i/web/status/1235752637217284096', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [104, 127]}]}, 'metadata': {'iso_language_code': 'pt', 'result_type': 'recent'}, 'source': 'Twitter for iPhone', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 214275534, 'id_str': '214275534', 'name': 'Jo Pais', 'screen_name': 'jopais_', 'location': 'Recife, Pernambuco', 'description': 'Senhora das Tempestades. Escritora de ranhuras. Fotógrafa de relatos estranhos. Um saco de longas histórias. House of DC.', 'url': 'https://t.co/HjAQUr5L9z', 'entities': {'url': {'urls': [{'url': 'https://t.co/HjAQUr5L9z', 'expanded_url': 'http://www.instagram.com/jopais_', 'display_url': 'instagram.com/jopais_', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 339, 'friends_count': 465, 'listed_count': 10, 'created_at': 'Thu Nov 11 00:41:29 +0000 2010', 'favourites_count': 4404, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 53564, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'FCFCFC', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme19/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme19/bg.gif', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1225456949686349828/q4AtpftN_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1225456949686349828/q4AtpftN_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/214275534/1578790927', 'profile_link_color': '000000', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': 'FAFAFA', 'profile_text_color': '333333', 'profile_use_background_image': False, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'possibly_sensitive': True, 'lang': 'pt'}], 'search_metadata': {'completed_in': 0.046, 'max_id': 1236901891394670594, 'max_id_str': '1236901891394670594', 'next_results': '?max_id=1235752637217284095&q=HouseTargaryen&include_entities=1', 'query': 'HouseTargaryen', 'refresh_url': '?since_id=1236901891394670594&q=HouseTargaryen&include_entities=1', 'count': 15, 'since_id': 0, 'since_id_str': '0'}}\n" - ] - } - ], - "source": [ - "number_tweets = 99 # This is the maximum number of tweets that can be requested with the free version of API\n", - "tweets_on_houses = {} # We create an empty dictionary \n", - "\n", - "for ii in query_chain: \n", - " tweets = api.search.tweets(q=ii)\n", - " #tweets = api.GetSearch(raw_query=\"l=en&q=%23\"+ii+\"&count=\"+str(number_tweets)) \n", - " tweets_on_houses[ii] = tweets\n", - " \n", - "print(tweets) " - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'statuses': [{'created_at': 'Sun Mar 08 18:29:33 +0000 2020', 'id': 1236720730563399681, 'id_str': '1236720730563399681', 'text': 'RT @ASOIAFReadThru: Rule in the west had therefore passed to his widow, Lady Johanna, and her father, Roland Westerling, Lord of the Crag.…', 'truncated': False, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [{'screen_name': 'ASOIAFReadThru', 'name': 'ASOIAF Tweet-Through', 'id': 2396358626, 'id_str': '2396358626', 'indices': [3, 18]}], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 875434881668526081, 'id_str': '875434881668526081', 'name': 'Miguel C. Martínez', 'screen_name': 'Micaerys', 'location': 'Marín, España', 'description': 'Escritor, youtuber, Padre de Dragones, Guardián de Wikis :v', 'url': 'https://t.co/2TOanfsHqn', 'entities': {'url': {'urls': [{'url': 'https://t.co/2TOanfsHqn', 'expanded_url': 'https://m.youtube.com/channel/UCoC3UzXi_Sv5wXEAIgOVqHw', 'display_url': 'm.youtube.com/channel/UCoC3U…', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 260, 'friends_count': 635, 'listed_count': 3, 'created_at': 'Thu Jun 15 19:28:35 +0000 2017', 'favourites_count': 23429, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 8027, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '000000', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1120069602589933568/I71c45Cw_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1120069602589933568/I71c45Cw_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/875434881668526081/1533726511', 'profile_link_color': '77FFDD', 'profile_sidebar_border_color': '000000', 'profile_sidebar_fill_color': '000000', 'profile_text_color': '000000', 'profile_use_background_image': False, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'retweeted_status': {'created_at': 'Sun Mar 08 18:24:44 +0000 2020', 'id': 1236719515733557248, 'id_str': '1236719515733557248', 'text': 'Rule in the west had therefore passed to his widow, Lady Johanna, and her father, Roland Westerling, Lord of the Cr… https://t.co/cy0IOBGMwH', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/cy0IOBGMwH', 'expanded_url': 'https://twitter.com/i/web/status/1236719515733557248', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236719265069387781, 'in_reply_to_status_id_str': '1236719265069387781', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'lang': 'en'}, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 18:29:09 +0000 2020', 'id': 1236720626733285378, 'id_str': '1236720626733285378', 'text': 'She agreed as well to restore that portion of the royal treasury that Tyland Lannister had sent west for safekeepin… https://t.co/bHqPNK1DfD', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/bHqPNK1DfD', 'expanded_url': 'https://twitter.com/i/web/status/1236720626733285378', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236720301087559680, 'in_reply_to_status_id_str': '1236720301087559680', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 18:27:51 +0000 2020', 'id': 1236720301087559680, 'id_str': '1236720301087559680', 'text': 'She would deliver two daughters to the Red Keep, to serve as companions to the new queen (and as hostages to ensure… https://t.co/RWAR0pt8Fi', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/RWAR0pt8Fi', 'expanded_url': 'https://twitter.com/i/web/status/1236720301087559680', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236720151602528257, 'in_reply_to_status_id_str': '1236720151602528257', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 18:26:03 +0000 2020', 'id': 1236719847876288513, 'id_str': '1236719847876288513', 'text': 'With the Red Kraken’s longships still menacing their coasts, the Lannisters were more concerned with defending Kayc… https://t.co/1bAZ7YjWE9', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/1bAZ7YjWE9', 'expanded_url': 'https://twitter.com/i/web/status/1236719847876288513', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236719515733557248, 'in_reply_to_status_id_str': '1236719515733557248', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 18:24:44 +0000 2020', 'id': 1236719515733557248, 'id_str': '1236719515733557248', 'text': 'Rule in the west had therefore passed to his widow, Lady Johanna, and her father, Roland Westerling, Lord of the Cr… https://t.co/cy0IOBGMwH', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/cy0IOBGMwH', 'expanded_url': 'https://twitter.com/i/web/status/1236719515733557248', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236719265069387781, 'in_reply_to_status_id_str': '1236719265069387781', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 18:23:44 +0000 2020', 'id': 1236719265069387781, 'id_str': '1236719265069387781', 'text': 'Lord Jason Lannister had left six children when he died in battle: five daughters and one son, Loreon, a boy of four.\\n#HouseLannister', 'truncated': False, 'entities': {'hashtags': [{'text': 'HouseLannister', 'indices': [118, 133]}], 'symbols': [], 'user_mentions': [], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236719073670705155, 'in_reply_to_status_id_str': '1236719073670705155', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 18:22:58 +0000 2020', 'id': 1236719073670705155, 'id_str': '1236719073670705155', 'text': 'Casterly Rock was the first to respond.\\n#HouseLannister', 'truncated': False, 'entities': {'hashtags': [{'text': 'HouseLannister', 'indices': [40, 55]}], 'symbols': [], 'user_mentions': [], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sun Mar 08 17:58:21 +0000 2020', 'id': 1236712875458207750, 'id_str': '1236712875458207750', 'text': 'Others rumors claimed the Lannisters and the Hightowers were on the march, without truth. \\n#HouseLannister #HouseHightower', 'truncated': False, 'entities': {'hashtags': [{'text': 'HouseLannister', 'indices': [91, 106]}, {'text': 'HouseHightower', 'indices': [108, 123]}], 'symbols': [], 'user_mentions': [], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236712633019097090, 'in_reply_to_status_id_str': '1236712633019097090', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sat Mar 07 22:46:16 +0000 2020', 'id': 1236422944471035905, 'id_str': '1236422944471035905', 'text': 'RT @ASOIAFReadThru: \"You speak of taking Storm’s End, Oldtown, and Casterly Rock, my lord, but the men who held those seats were slain in b…', 'truncated': False, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [{'screen_name': 'ASOIAFReadThru', 'name': 'ASOIAF Tweet-Through', 'id': 2396358626, 'id_str': '2396358626', 'indices': [3, 18]}], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter for Android', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 910528259049365505, 'id_str': '910528259049365505', 'name': 'Carlos_Martins_2017', 'screen_name': 'Joao_Pelixo', 'location': '', 'description': \"Politics, history and philosophy.\\nI love to buy new books even when I have some that I haven't read yet.\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 199, 'friends_count': 224, 'listed_count': 3, 'created_at': 'Wed Sep 20 15:37:08 +0000 2017', 'favourites_count': 27600, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 41127, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'F5F8FA', 'profile_background_image_url': None, 'profile_background_image_url_https': None, 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1075098095568982016/PSxLm2xV_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1075098095568982016/PSxLm2xV_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/910528259049365505/1537982366', 'profile_link_color': '1DA1F2', 'profile_sidebar_border_color': 'C0DEED', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': True, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'retweeted_status': {'created_at': 'Sat Mar 07 18:44:38 +0000 2020', 'id': 1236362138555494402, 'id_str': '1236362138555494402', 'text': '\"You speak of taking Storm’s End, Oldtown, and Casterly Rock, my lord, but the men who held those seats were slain… https://t.co/qnEwnTIH2S', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/qnEwnTIH2S', 'expanded_url': 'https://twitter.com/i/web/status/1236362138555494402', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [116, 139]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 12, 'favorited': False, 'retweeted': False, 'lang': 'en'}, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sat Mar 07 19:32:21 +0000 2020', 'id': 1236374144347971586, 'id_str': '1236374144347971586', 'text': 'Paisas with beards #beardbros #PaisaPals #BestFriendsGang #HouseLannister #lannisterlions 🦁 @ Oakland, California https://t.co/hSUqrE0ea9', 'truncated': False, 'entities': {'hashtags': [{'text': 'beardbros', 'indices': [19, 29]}, {'text': 'PaisaPals', 'indices': [30, 40]}, {'text': 'BestFriendsGang', 'indices': [41, 57]}, {'text': 'HouseLannister', 'indices': [58, 73]}, {'text': 'lannisterlions', 'indices': [74, 89]}], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/hSUqrE0ea9', 'expanded_url': 'https://www.instagram.com/p/B9cbudHB7K8/?igshid=13ozaspleskma', 'display_url': 'instagram.com/p/B9cbudHB7K8/…', 'indices': [114, 137]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Instagram', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 30808871, 'id_str': '30808871', 'name': 'A-Lo', 'screen_name': 'Thunderlips187', 'location': 'Murda Meda, CA', 'description': 'Bulletproof Tiger. Cats. Tacos. Yoga. Tattoos. Trees. Bikes. Serenity. Nonsense. I never update my website', 'url': 'https://t.co/reoGmSJENh', 'entities': {'url': {'urls': [{'url': 'https://t.co/reoGmSJENh', 'expanded_url': 'http://angelobenedetto.com', 'display_url': 'angelobenedetto.com', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 379, 'friends_count': 561, 'listed_count': 12, 'created_at': 'Mon Apr 13 04:42:26 +0000 2009', 'favourites_count': 1167, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 15229, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '709397', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/661438836484902912/WwXkKoZy_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/661438836484902912/WwXkKoZy_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/30808871/1543411811', 'profile_link_color': '1B1E1A', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'A0C5C7', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': False, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': {'type': 'Point', 'coordinates': [37.8029, -122.2721]}, 'coordinates': {'type': 'Point', 'coordinates': [-122.2721, 37.8029]}, 'place': {'id': 'ab2f2fac83aa388d', 'url': 'https://api.twitter.com/1.1/geo/id/ab2f2fac83aa388d.json', 'place_type': 'city', 'name': 'Oakland', 'full_name': 'Oakland, CA', 'country_code': 'US', 'country': 'United States', 'contained_within': [], 'bounding_box': {'type': 'Polygon', 'coordinates': [[[-122.34266, 37.699279], [-122.114711, 37.699279], [-122.114711, 37.8847092], [-122.34266, 37.8847092]]]}, 'attributes': {}}, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 0, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'en'}, {'created_at': 'Sat Mar 07 19:03:01 +0000 2020', 'id': 1236366761823477760, 'id_str': '1236366761823477760', 'text': '\"Has Oldtown yielded? Has Casterly Rock returned the Crown’s gold?\"\\n#HouseHightower #HouseLannister', 'truncated': False, 'entities': {'hashtags': [{'text': 'HouseHightower', 'indices': [68, 83]}, {'text': 'HouseLannister', 'indices': [85, 100]}], 'symbols': [], 'user_mentions': [], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236366588447727618, 'in_reply_to_status_id_str': '1236366588447727618', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sat Mar 07 18:44:59 +0000 2020', 'id': 1236362225633419271, 'id_str': '1236362225633419271', 'text': '\"Grant them honorable terms, and they will bend the knee.\"\\n#HouseBaratheon #HouseHightower \\n#HouseLannister', 'truncated': False, 'entities': {'hashtags': [{'text': 'HouseBaratheon', 'indices': [59, 74]}, {'text': 'HouseHightower', 'indices': [76, 91]}, {'text': 'HouseLannister', 'indices': [93, 108]}], 'symbols': [], 'user_mentions': [], 'urls': []}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236362138555494402, 'in_reply_to_status_id_str': '1236362138555494402', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 7, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sat Mar 07 18:44:38 +0000 2020', 'id': 1236362138555494402, 'id_str': '1236362138555494402', 'text': '\"You speak of taking Storm’s End, Oldtown, and Casterly Rock, my lord, but the men who held those seats were slain… https://t.co/qnEwnTIH2S', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/qnEwnTIH2S', 'expanded_url': 'https://twitter.com/i/web/status/1236362138555494402', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [116, 139]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 1, 'favorite_count': 12, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sat Mar 07 18:33:04 +0000 2020', 'id': 1236359224592130051, 'id_str': '1236359224592130051', 'text': 'Kermit Tully pointed out that Storm’s End, Oldtown, and Casterly Rock were as strong as Stark’s own Winterfell (f n… https://t.co/WyYDtZanCj', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/WyYDtZanCj', 'expanded_url': 'https://twitter.com/i/web/status/1236359224592130051', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236358915308302336, 'in_reply_to_status_id_str': '1236358915308302336', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 4, 'favorited': False, 'retweeted': False, 'lang': 'en'}, {'created_at': 'Sat Mar 07 18:30:45 +0000 2020', 'id': 1236358644398202881, 'id_str': '1236358644398202881', 'text': 'He would reduce Storm’s End first, then cross the Reach to take Oldtown. Once the Hightower had fallen, he would ta… https://t.co/hPxRnnXbEa', 'truncated': True, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [], 'urls': [{'url': 'https://t.co/hPxRnnXbEa', 'expanded_url': 'https://twitter.com/i/web/status/1236358644398202881', 'display_url': 'twitter.com/i/web/status/1…', 'indices': [117, 140]}]}, 'metadata': {'iso_language_code': 'en', 'result_type': 'recent'}, 'source': 'Twitter Web App', 'in_reply_to_status_id': 1236358411463393280, 'in_reply_to_status_id_str': '1236358411463393280', 'in_reply_to_user_id': 2396358626, 'in_reply_to_user_id_str': '2396358626', 'in_reply_to_screen_name': 'ASOIAFReadThru', 'user': {'id': 2396358626, 'id_str': '2396358626', 'name': 'ASOIAF Tweet-Through', 'screen_name': 'ASOIAFReadThru', 'location': 'Fire and Blood', 'description': \"Live-tweeting quotes from George R. R. Martin's A Song of Ice and Fire series as I re-read it. It in no way belongs to me. SPOILERS\", 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 6098, 'friends_count': 1247, 'listed_count': 75, 'created_at': 'Tue Mar 18 15:05:40 +0000 2014', 'favourites_count': 80122, 'utc_offset': None, 'time_zone': None, 'geo_enabled': False, 'verified': False, 'statuses_count': 141308, 'lang': None, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '3B94D9', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_image_url': 'http://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/560626739559153664/SbqurU-g_normal.jpeg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/2396358626/1422498865', 'profile_link_color': '0084B4', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 4, 'favorited': False, 'retweeted': False, 'lang': 'en'}], 'search_metadata': {'completed_in': 0.049, 'max_id': 1236720730563399681, 'max_id_str': '1236720730563399681', 'next_results': '?max_id=1236358644398202880&q=HouseLannister&include_entities=1', 'query': 'HouseLannister', 'refresh_url': '?since_id=1236720730563399681&q=HouseLannister&include_entities=1', 'count': 15, 'since_id': 0, 'since_id_str': '0'}}\n" - ] - } - ], - "source": [ - "print(tweets_on_houses[\"HouseLannister\"]) # Frankly, Lannister's deserve the Iron throne. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "*[Status(ID=1121038719195275265, ScreenName=YSoSeriousBoo, Created=Wed Apr 24 13:10:33 +0000 2019, Text='@Oreo @oreo #ForTheThrone #GOT \\n #GameOfCookies \\n\\n#WhiteWalker 7 Oreos \\n\\n#HouseLannister 6 Oreos\\n\\n#HouseDargaryen… https://t.co/zgva8sb28N'), Status(ID=1121012886875385859, ScreenName=DohertyCiaran, Created=Wed Apr 24 11:27:54 +0000 2019, Text='Second of Six #GlassOfThrones stained glass installations unveiled at #Belfast Waterfront Hall. Depicting… https://t.co/eVttTzPSQD'), Status(ID=1120944289301843968, ScreenName=TourismIreland, Created=Wed Apr 24 06:55:19 +0000 2019, Text='RT @VirginMediaNews: PICTURED: Another #GameOfThrones-themed stained glass window has been unveiled in #Belfast as part of @TourismIreland’…'), Status(ID=1120944181906690049, ScreenName=SineadGrace1, Created=Wed Apr 24 06:54:53 +0000 2019, Text='RT @VirginMediaNews: PICTURED: Another #GameOfThrones-themed stained glass window has been unveiled in #Belfast as part of @TourismIreland’…'), Status(ID=1120908255193071617, ScreenName=opeadigs, Created=Wed Apr 24 04:32:08 +0000 2019, Text='RT @PiggyBankNG: What house do you belong to, based on the feature you use the most?\\n\\n#HouseTargaryen #HouseGreyJoy #HouseStark #HouseLanni…')]*\n", - "\n", - "Nice!\n", - "\n", - "## Interact with the database\n", - "\n", - "In the first part of the project, you created a database.\n", - "This will be used to store all the information you will need for your analyses.\n", - "\n", - "In the case of our GoT analysis, we need to create the database\n", - "specifically to receive the information we extracted. However, the creation procedure of a database and inserting values into it is more or less the same from a Python point of view.\n", - "\n", - "Everything happens with *sqlite3* library. This library allows you to interact with a sqlite database by forwarding it strings containing the SQL statements we want to execute.\n", - "\n", - "Let's start by importing the library..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sqlite3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create the tables\n", - "\n", - "The simplest way is to create a database (which can start as an empty file with a name ending in *.db* or *.sqlite*) in the folder where your Python code is located (whether it's a code in pure\" Python - a \".py\" - or a Jupyter notebook - a \".ipynb\").\n", - "\n", - "Once the file is created, you can use the sqlite3 library to handle it . The library documentation is available [here](https://docs.python.org/3/library/sqlite3.html).\n", - "\n", - "The first step is to link to the data. This is created by passing the database name as a string to the *connect()* method of the library. In our case, we created a database called \"GoT.db\" in the folder containing this notebook. So we create a connection." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "conn = sqlite3.connect(\"GoT.db\") # If the file doesn't exist, it is automatically created" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we have a connection, we can use the *execute()*, passing as argument a string of characters containing the instruction you wish to execute. In our case, we want to create two tables: one table containing the houses and a table containing the characters.\n", - "\n", - "Some characters can have several allegiances, it is necessary therefore to create a join table (a house can have several members and a character may have pledged allegiance to more than one member. houses)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "create_houses = '''CREATE TABLE IF NOT EXISTS houses( url TEXT PRIMARY KEY UNIQUE NOT NULL, name TEXT NON NULL, symbol TEXT)'''\n", - "create_characters = '''CREATE TABLE IF NOT EXISTS characters( url TEXT PRIMARY KEY UNIQUE NOT NULL, name TEXT NON NULL, dead INT NON NULL DEFAULT 0)'''\n", - "create_allegeances = '''CREATE TABLE IF NOT EXISTS allegeances( url_character TEXT NOT NULL, url_house TEXT NOT NULL, PRIMARY KEY (url_character, url_house), FOREIGN KEY (url_character) REFERENCES characters(url), FOREIGN KEY (url_house) REFERENCES houses(url))'''" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we create the table containing the houses\n", - "\n", - "conn.execute(create_homes)\n", - "\n", - "Then the characters\n", - "\n", - "conn.execute(create_characters)\n", - "\n", - "And finally, the joining table\n", - "\n", - "conn.execute(create_allegeances)\n", - "\n", - "\n", - "\n", - "Fill in the tables\n", - "\n", - "Now, it's time to build tuples representing the data that we wish to insert into our tables. We do this through loops and comprehensions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "inputs_houses = [(house[\"url\"], house[\"name\"], house[\"coatOfArms\"]) for house in houses]\n", - "inputs_personnages = [(perso[\"url\"], perso[\"name\"], perso[\"died\"] == \"\") for perso in personnages if perso[\"name\"] != \"\"] # If the character has a date of death, the third element of the tuple equals Falseinputs_allegeances = [] \n", - "# Exercise: try to transform this loop into comprehensions for perso in characters: if perso[\"name\"] != \"\": for house in perso[\"allegiances\"]: inputs_allegeances = inputs_allegeances +[(perso[\"url\"], maison)]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "After these few manipulations, we are now ready to fill our database! By reading the documentation for the sqlite3 module, we can realize that, if we have a tuple list containing\n", - "the values that we want to insert in the database, we can use the executemany() statement on the connection to insert them as one statement in the table." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "conn.executemany('''INSERT INTO maisons VALUES (?, ?, ?)''', inputs_houses)\n", - "conn.executemany('''INSERT INTO personnages VALUES (?, ?, ?)''', inputs_characters)\n", - "conn.executemany('''INSERT INTO allegeances VALUES (?, ?)''', inputs_allegeances)\n", - "conn.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There you go. We now have the information in the database. Notice that the boolean value indicating whether the person is still has been automatically converted to 0 (for False) and 1 (for true).\n", - "\n", - "Querying the database\n", - "\n", - "The peculiarity of the *sqlite3* library is that; the response of an *execute()* statement is always a pointer (i.e. kind of a link to the responses returned). This means that to obtain a table with\n", - "responses to a SELECT instruction, the function method *.fetchall()* must be applied on the pointer to convert all the rows of the results in a table of tuples. Let's illustrate this\n", - "with an example: we will use the SELECT instruction to find the url (which is the primary key) of the Stark (of Winterfell) houses, Lannister (of Casterly Rock) and Targaryen (of King's Landing). This will be useful to record the tweets we have extracted." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "main_houses_query = '''SELECT name, url FROM houses WHERE name LIKE \"%Stark of Winterfell\" OR name LIKE \"%Lannister of Casterly Rock\" OR name LIKE \"%Targaryen of King's Landing\"'''" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "res = conn.execute(main_houses_query)urls_main_houses = res.fetchall()main_houses = {main_house[0]: main_house[1] for main_house in urls_main_houses}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next (and last step for today) is to pass the Tweets we retrieved from the Sentiment Analysis Library and to insert them in a new database table.\n", - "\n", - "## Sentiment analysis\n", - "\n", - "We can now pass on the tweets we've collected in a\n", - "Sentiment analysis bookstore. Sentiment analysis is a task\n", - "extremely complex and still evolving. Indeed, many\n", - "of clues to discover the meaning of a sentence (this includes by\n", - "example, the use of punctuation, certain key words, certain\n", - "emoji and sometimes complex probabilistic models - think by\n", - "example to tweets containing sarcastic remarks, the most\n", - "complex to interpret).\n", - "\n", - "Fortunately, there are, once again, libraries that allow to interpret the strings passed to them and to extract from them\n", - "sentiment indicators.\n", - "\n", - "One such bookstore is [Vader (Valencia Aware Dictionary and sEntiment Reasoner)](https://github.com/cjhutto/vaderSentiment). This library can be installed by the usual means (using PiPy for example, or conda).\n", - "\n", - "The library is provided with some datasets so that you can\n", - "can convince you of the strength of the concepts behind it. Once convinced, it's time to apply the library to the Tweets that\n", - "we extracted." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzeranalyser = SentimentIntensityAnalyzer() \n", - "# We create an object that will analyze tweetstweets_texts = [(house, tweet.text) for house, tweets in tweets_on_houses.items() for tweet in tweets]tweets_texts = list(set(tweets_texts)) # This is a little trick to remove duplicate lines (there may be retweets that we are not interested in here)abrevs = {\"HouseLannister\": \"House Lannister of Casterly Rock\", \"HouseStark\": \"House Stark of Winterfell\", \"HouseTargaryen\": \"House Targaryen of King's Landing\"}tweets_with_primary_key = [(houses_importantes[abrevs[tweet[0]]], tweet[1]) for tweet in tweets_texts]load_for_database = []for tweet in tweets_with_primary_key: # Here, we use a loop because the algorithm that determines the sentiment can take a long time to run: we may prefer to run it only once per tweet sentiment = analyze.polarity_scores(tweet[1]) # We pass the text to the library, it returns a dictionary containing 3 keys: \"pos\", \"neg\", \"neu\" and \"compound\" res = (tweet[0], tweet[1], sentiment[\"compound\"], sentiment[\"pos\"], sentiment[\"neu\"], sentiment[\"neg\"]) load_for_database = load_for_database + [res]load_for_database[0:5]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "*[('https://www.anapioficeandfire.com/api/houses/229', 'Exclusive #GameofThrones Silver #IronThrone Tankard\\n\\nOrder Now {https://t.co/xWIe02Nfnd}\\n\\n#affiliate… https://t.co/R0c2OvGKf4', 0.128, 0.143, 0.857, 0.0), ('https://www.anapioficeandfire.com/api/houses/229', '#HouseLannister 🦁 https://t.co/2NIYvQ5PUx', 0.0, 0.0, 1.0, 0.0), ('https://www.anapioficeandfire.com/api/houses/378', 'Esqueci a poha da #Gameofthrones #GOT #JonSnow #DaenerysTargaryen #ForTheThrone #HouseTargaryen', 0.0, 0.0, 1.0, 0.0), ('https://www.anapioficeandfire.com/api/houses/362', '@Maisie_Williams Best scene ever. Of all the series. I’ve been waiting since Arya met Gendry. It was all I ever hop… https://t.co/ISQ37QN5sb', 0.6369, 0.174, 0.826, 0.0), ('https://www.anapioficeandfire.com/api/houses/378', 'Will the real John Snow ❄️ please stand up @GameOfThrones #GamefThrones #HouseStark #HouseTargaryen https://t.co/EZZbxokFvF', 0.3182, 0.15, 0.85, 0.0)]*\n", - "\n", - "Sentiment analysis returns 3 values: \"proportions of beliefs\" that the message is positive, negative or neutral. The sum of these three\n", - "In addition to these three values, there is a fourth, the composite index. This \"summarizes\" the other three into a value that is unconstrained (i.e. it can be\n", - "positive or negative). A value of the composite indicator close to 0\n", - "indicates a rather neutral tweet, a positive value indicates a tweet\n", - "generally positive and a negative value a tweet generally\n", - "negative. It is this value that will be mainly useful in the case of\n", - "analysis of the results (taking, for example, the average of all tweets on a house before and after an episode).\n", - "\n", - "OK, as you can probably see (it depends on when you run this code), the algorithm is not flawless (especially since, in the\n", - "of the show, talking about death, destruction, etc. is not\n", - "necessarily negative, whereas in general, a tweet talking about these\n", - "topics is of some concern). However, for this example, as we\n", - "are not too concerned about the analysis, it will not pose too much of a problem.\n", - "problem (the graphs for the previous course will be just enough for the\n", - "sad).\n", - "\n", - "Note that, if we wanted to track the interest of the twittosphere for each house per day, we could run some cells of this notebook but there are some others that should be avoided. A large part of the work consists in taking and adapting the contents of this notebook for\n", - "extract the interesting parts for your project.\n", - "\n", - "Well, now, it's a matter of creating a table in our database where we'll store the tweets and their analysis. We'll just go in enter the tuples we created earlier. We'll add a column to represent the day (in fact, the exact time) we added the tweets. This will allow us to analyze the average feeling about each of the houses this week and after.\n", - "next week's episode to see if there's any developments." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "table_tweets_creation = '''CREATE TABLE IF NOT EXISTS tweets( house TEXT NOT NULL, content TEXT NOT NULL, composite_index NUMERIC, positive_index NUMERIC, neutral_index NUMERIC, negative_index NUMERIC, insert_when TEXT DEFAULT (date('now', 'localtime')), PRIMARY KEY (house, content), FOREIGN KEY (house) REFERENCES houses(url))'''conn.execute(creation_table_tweets)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note the line *\"insert_when TEXT DEFAULT (date('now', 'localtime')), \"*.\n", - "It indicates that, if we don't specify a date for the insertion, we will just add the string corresponding to the date of the system on which the script is being run (this implies that, if we run this script at 2:00 a.m. Belgian time. simultaneously on two computers, one in Brussels and one in Buenos Aires, we will not have the same line in the databases).\n", - "\n", - "That's it, we can finally insert our tweets and their information in the database. This will conclude the presentation of libraries needed to complete the second part of the work." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "insert_into_tweets = '''INSERT INTO tweets(house, content, composite_index, positive_index, neutral_index, negative_index) VALUES (?,?,?,?,?,?)'''conn.executemany(insert_into_tweets, load_for_database)conn.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this case, since we do not provide a tuple of the table size (the table has 7 columns but we only provide 6 values because we want to make the database add today's date), it is\n", - "It is necessary to name the columns in which the 6 values should be inserted.\n", - "\n", - "The *conn.commit()* writes the changes to the database. It's worth to ensure that any changes contained in the notebook have been well written. Do not hesitate to look in the database of\n", - "given to see what the code in this book has produced." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Session_5/Readme.md b/Session_5/Readme.md deleted file mode 100644 index 6326abb..0000000 --- a/Session_5/Readme.md +++ /dev/null @@ -1,12 +0,0 @@ -**APIs with Python** - - -In Slides -1. Introduction to APIs -2. JSON -3. Hardcoding access with `requests` -4. Popular pre-written modules for geocoding and mapping - -External scripts -1. Trade data with Comtrade API (kudos Federico) -2. The Twitter API (kudos Charles) diff --git a/Session_5/Readme.md.txt b/Session_5/Readme.md.txt new file mode 100644 index 0000000..304360c --- /dev/null +++ b/Session_5/Readme.md.txt @@ -0,0 +1 @@ +Readme diff --git a/Session_5/Session 5 - APIs Intro.ipynb b/Session_5/Session 5 - APIs Intro.ipynb deleted file mode 100644 index ded1522..0000000 --- a/Session_5/Session 5 - APIs Intro.ipynb +++ /dev/null @@ -1,644 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Python and APIs\n", - "Angela, Moritz & Thomas" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Outline of Session 5\n", - "\n", - "In these slides\n", - "* Introduction \n", - "* JSON\n", - "* Hardcoding access with `requests`\n", - "* Popular pre-written modules for geocoding and mapping\n", - "\n", - "External scripts\n", - "* Trade data with Comtrade API (kudos Federico)\n", - "* The Twitter API (kudos Charles)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# What is an API?\n", - "\n", - "## API: Application programming interface\n", - "\n", - "_\"a set of clearly defined methods of communication between various software components.\"_\n", - "\n", - "\n", - "- Pre-internet days: Extension of software beyond its usual capabilities\n", - "- Nowadays: Interface by web service providers for you to connect/retrieve with your own application (i.e. without going through GUI)\n", - "- You send data <-> You get data back\n", - "- Most APIs have a similar structure: the REST architecture (REpresentational State Transfer)\n", - "- Inititatives like the Linux Foundation's [OpenAPI](https://www.openapis.org/) develop these types of standards\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Illustration: General Set-up\n", - "\n", - "\n", - "\n", - "Source: [MuleSoft Videos](https://www.youtube.com/embed/s7wmiS2mSXY)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Illustration: Making a request\n", - "\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Illustration: Returning Content\n", - "\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Elements of an API\n", - "\n", - "* A protocol (eg: https)\n", - "* A server (eg: httpbin.org)\n", - "* A method name / location (eg: /get)\n", - "* A set of arguments (eg: hello=world and foo=bar)\n", - "\n", - "➥ https://httpbin.org/get?hello=world&foo=bar\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# The Request\n", - "\n", - "* You need to read the documentation (e.g. [Eurostat API documentation](https://ec.europa.eu/eurostat/web/json-and-unicode-web-services/getting-started/rest-request))\n", - "* You need to specify the URL (if it is a remote API)\n", - "* You need to import the `requests` module in Python" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# The returning object\n", - "\n", - "* Usually it is encoded in JSON \n", - "* The other popular formats for data structure are XML (mainly old stuff) and CSV (spreadsheet compatible)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# What is a JSON?\n", - "* JSON = [(JavaScript Object Notation)](https://www.json.org/)\n", - "* It is one of the most popular format for data in the world\n", - "* It looks like a Python dictionary, except for the fact that:\n", - " - JSON is a string (it is inside a text file)\n", - " - JSON must use double quotation mark\n", - " - in JavaScript it is defined as Object\n", - "* In Python there is a built-in module called `json` module \n", - "* It follows this strcture {\"key\" : \"value\"}; see example below:\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'friends': [{'name': 'Jose', 'degree': 'Applied Computing'},\n", - " {'name': 'Rolf', 'degree': 'Computer Science'},\n", - " {'name': 'Anna', 'degree': 'Physics'}]}" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "{\n", - " \"friends\": [\n", - " {\n", - " \"name\": \"Jose\",\n", - " \"degree\": \"Applied Computing\"\n", - " },\n", - " {\n", - " \"name\": \"Rolf\",\n", - " \"degree\": \"Computer Science\"\n", - " },\n", - " {\n", - " \"name\": \"Anna\",\n", - " \"degree\": \"Physics\"\n", - " }\n", - " ]\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# What can I do with APIs? \n", - "\n", - "- Retrieve [World Bank Dev Indicators](https://datahelpdesk.worldbank.org/knowledgebase/articles/898581-api-basic-call-structures)\n", - "- Track stock prices with [OpenFIGI](https://www.openfigi.com/api)\n", - "- Geocode an address with [Here Maps](https://developer.here.com/)\n", - "- Convert fiat currency with [opencurrency](https://openexchangerates.org/) or crypto with [alternative.me](https://alternative.me/crypto/api/)\n", - "- Send tweets with [Twitter](https://developer.twitter.com/)\n", - "- Download images from Mars or the Moon from [NASA](https://api.nasa.gov/)\n", - "- ..." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# The Starwars Character API\n", - "\n", - "- Let's get data on Starwars characters! \n", - "- We find [the documentation](https://swapi.co/documentation) \n", - "- We import the `requests` module \n", - "- We set the base URL of the API: `https://swapi.co/api/`\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "import requests\n", - "\n", - "url = \"https://swapi.co/api/\"\n", - "\n", - "# Launch request\n", - "base_req = requests.get(url)\n", - "print(base_req)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "scrolled": true, - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'people': 'https://swapi.co/api/people/', 'planets': 'https://swapi.co/api/planets/', 'films': 'https://swapi.co/api/films/', 'species': 'https://swapi.co/api/species/', 'vehicles': 'https://swapi.co/api/vehicles/', 'starships': 'https://swapi.co/api/starships/'}\n" - ] - } - ], - "source": [ - "# Explore json content of object\n", - "print(base_req.json())\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Making sense of the answer\n", - "\n", - "- The call to the basic URL returns various subfields\n", - "`\n", - "{\n", - " 'people': 'https://swapi.co/api/people/', \n", - " 'planets': 'https://swapi.co/api/planets/', \n", - " 'films': 'https://swapi.co/api/films/', \n", - " 'species': 'https://swapi.co/api/species/', \n", - " 'vehicles': 'https://swapi.co/api/vehicles/', \n", - " 'starships': 'https://swapi.co/api/starships/'\n", - " }\n", - "`\n", - "- The documentation adds: `/people/:id/ -- get a specific people resource`\n", - "- Let's request info on the first id of the subfield `people`\n", - "- We can request further info on a sub-subfield (e.g. `starships`)\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'name': 'Luke Skywalker', 'height': '172', 'mass': '77', 'hair_color': 'blond', 'skin_color': 'fair', 'eye_color': 'blue', 'birth_year': '19BBY', 'gender': 'male', 'homeworld': 'https://swapi.co/api/planets/1/', 'films': ['https://swapi.co/api/films/2/', 'https://swapi.co/api/films/6/', 'https://swapi.co/api/films/3/', 'https://swapi.co/api/films/1/', 'https://swapi.co/api/films/7/'], 'species': ['https://swapi.co/api/species/1/'], 'vehicles': ['https://swapi.co/api/vehicles/14/', 'https://swapi.co/api/vehicles/30/'], 'starships': ['https://swapi.co/api/starships/12/', 'https://swapi.co/api/starships/22/'], 'created': '2014-12-09T13:50:51.644000Z', 'edited': '2014-12-20T21:17:56.891000Z', 'url': 'https://swapi.co/api/people/1/'}\n" - ] - } - ], - "source": [ - "# Let's try\n", - "url = \"https://swapi.co/api/people/1\"\n", - "\n", - "# Launch request\n", - "req_1 = requests.get(url)\n", - "\n", - "# Extract json\n", - "req_1_js = req_1.json()\n", - "print(req_1_js)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['https://swapi.co/api/starships/12/', 'https://swapi.co/api/starships/22/']\n", - "{'name': 'X-wing', 'model': 'T-65 X-wing', 'manufacturer': 'Incom Corporation', 'cost_in_credits': '149999', 'length': '12.5', 'max_atmosphering_speed': '1050', 'crew': '1', 'passengers': '0', 'cargo_capacity': '110', 'consumables': '1 week', 'hyperdrive_rating': '1.0', 'MGLT': '100', 'starship_class': 'Starfighter', 'pilots': ['https://swapi.co/api/people/1/', 'https://swapi.co/api/people/9/', 'https://swapi.co/api/people/18/', 'https://swapi.co/api/people/19/'], 'films': ['https://swapi.co/api/films/2/', 'https://swapi.co/api/films/3/', 'https://swapi.co/api/films/1/'], 'created': '2014-12-12T11:19:05.340000Z', 'edited': '2014-12-22T17:35:44.491233Z', 'url': 'https://swapi.co/api/starships/12/'}\n" - ] - } - ], - "source": [ - "# Let's extract Luke's starships\n", - "ships = req_1_js.get(\"starships\")\n", - "print(ships)\n", - "\n", - "# And get entry of first starship\n", - "ship = requests.get(ships[0]).json()\n", - "print(ship)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Geocoding\n", - "\n", - "- Most map services like Google Maps, Open Street Maps, Bing, etc. have APIs\n", - "- Let's check out Open Street Maps' (OSM) API called [Nominatim](https://developer.mapquest.com/)\n", - "- We will use the API through the Python module `geopy`\n", - "- To install new modules check out this [tutorial](https://jakevdp.github.io/blog/2017/12/05/installing-python-packages-from-jupyter/)\n", - "- But we still need to sign up with our email to obtain a key for Nominatim\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Retriving a location\n", - "\n", - "* We install `geopy`\n", - "* We sign up and obtain the key (in this example we use Moritz's key)\n", - "* We search the location of two popular places among ULB students: the ULB and the bar Tavernier\n", - "* We store and print out their coordinates" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Université Libre de Bruxelles (Campus du Solbosch), Square Albert Devèze - Albert Devèzesquare, Ixelles - Elsene, Région de Bruxelles-Capitale - Brussels Hoofdstedelijk Gewest, 1050, België - Belgique - Belgien\n", - "Tavernier, 445, Chaussée de Boondael - Boondaalse Steenweg, Ixelles - Elsene, Région de Bruxelles-Capitale - Brussels Hoofdstedelijk Gewest, 1050, België - Belgique - Belgien\n", - "[50.8134537, 4.381308819663028]\n", - "[50.816496, 4.388727177209292]\n" - ] - } - ], - "source": [ - "#import sys \n", - "#!{sys.executable} -m pip install geopy\n", - "\n", - "from geopy.geocoders import Nominatim\n", - "\n", - "# Replace the user agent key with your own key\n", - "geolocator = Nominatim(user_agent=\"jjG4qnPniTAGpG7O0q8XcMhARm0Pxcln\")\n", - "location_ULB = geolocator.geocode(\"Universite libre de Bruxelles\")\n", - "\n", - "location_tav = geolocator.geocode(\"Bar Tavernier Ixelles\")\n", - "\n", - "\n", - "# Did it work?\n", - "print(location_ULB)\n", - "print(location_tav)\n", - "# Like a charm...\n", - "\n", - "# Store coordinates in tuple\n", - "ulb_coords = [location_ULB.latitude, location_ULB.longitude]\n", - "print(ulb_coords)\n", - "\n", - "tav_coords = [location_tav.latitude, location_tav.longitude]\n", - "print(tav_coords)\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Mapping\n", - "\n", - "- Sadly, not everybody can associate a place to its coordinates in their mind :-P \n", - "- With the free [Leaflet API](https://leafletjs.com/reference-1.6.0.html) we can pin point them on a map\n", - "- Unfortunately written in Java Script\n", - "- But no need to learn, use \"wrapper\" Python Module `Folium`\n", - "- Example: Map of environmental violations of shale gas drilling in Pennsyilvania ([website](http://stateimpact.npr.org/pennsylvania/drilling/violations/))\n", - "\n", - " \"Map\"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Producing a map\n", - "\n", - "* We install `Folium`\n", - "* We create a map for the ULB, specifying the location and a zoom level\n", - "* We display the map" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [], - "source": [ - "# Install Python module Folium, a wrapper of the Leaflet API\n", - "#import sys\n", - "#!{sys.executable} -m pip install folium\n", - "\n", - "import folium\n", - "from folium.plugins import MarkerCluster\n", - "import pandas as pd\n", - "\n", - "#Create the map\n", - "my_map = folium.Map(location = ulb_coords, zoom_start = 14)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Display map\n", - "my_map\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Adding markers to the map\n", - "\n", - "* It is still not clear where the ULB and Tavernier are located: we need some markers!\n", - "* We pin point them on the map by adding some representative icons ;-) " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Let's add markers\n", - "\n", - "\n", - "folium.Marker(ulb_coords, popup = 'ULB', icon = folium.Icon(icon='book')).add_to(my_map)\n", - "folium.Marker(tav_coords, popup = 'STATA User Meeting', icon = folium.Icon(icon='glass', color='red')).add_to(my_map)\n", - "\n", - "my_map\n" - ] - } - ], - "metadata": { - "celltoolbar": "Slideshow", - "kernelspec": { - "display_name": "Python 3", - "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.7.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Session_5/Slide1.png b/Session_5/Slide1.png deleted file mode 100644 index 44150db..0000000 Binary files a/Session_5/Slide1.png and /dev/null differ diff --git a/Session_5/Slide2.png b/Session_5/Slide2.png deleted file mode 100644 index e130366..0000000 Binary files a/Session_5/Slide2.png and /dev/null differ diff --git a/Session_5/Slide3.png b/Session_5/Slide3.png deleted file mode 100644 index 8b56235..0000000 Binary files a/Session_5/Slide3.png and /dev/null differ diff --git a/Session_5/map.png b/Session_5/map.png deleted file mode 100644 index fe73330..0000000 Binary files a/Session_5/map.png and /dev/null differ diff --git a/Session_6/README.md b/Session_6/README.md deleted file mode 100644 index 87a4f10..0000000 --- a/Session_6/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Session 6: Webscraping -This week exercises are about retrieving data from HTML pages. It is a discipline that requires perseverance and ingenuity as you will often resort to dirty tricks and need a bit of luck to do what you want. - -The session will be divided into two parts: - -1. The regular exercises during which we'll scrape Wikipedia and Wikiquote pages to retrieve info on the laureates of the Nobel Memorial Prize in Economic Science. For this, you can use the library `requests`, together with `BeautifulSoup` or any library you are comfortable with. -2. A case that I'll present in class (or at least the start of it, as I'm still working on it) solving a real research problem. I'll showcase `selenium` in this context. - -Regarding the solution, I will make no attempt at all at presenting the best way to do it. I'll just show one way to retrieve the data we want, given the environment we operate in. You will see that the final results are not complete nor entirely correct. If you find a solution that is *good enough*, this will already be plenty. - -See you in class! diff --git a/Session_6/Readme.md.txt b/Session_6/Readme.md.txt new file mode 100644 index 0000000..304360c --- /dev/null +++ b/Session_6/Readme.md.txt @@ -0,0 +1 @@ +Readme diff --git a/Session_6/exercises_6.ipynb b/Session_6/exercises_6.ipynb deleted file mode 100644 index b49ca17..0000000 --- a/Session_6/exercises_6.ipynb +++ /dev/null @@ -1,239 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Webscraping" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "In this session, we will do some exercises about webscraping. Webscraping is the evil twin of API calls, seen last week. At the core of webscraping, there is a game: Usually, the website operators wants to prevent you from scraping her site as she would lose the ad revenues. It is therefore usually a fairly complex work where you have to outsmart somebody who makes part of her livelihood out of the data provided on the site.\n", - "\n", - "Moreover, scrapers are tipically much faster than humans and put therefore much more strain on the servers than the normal human user and require therefore more computing power on the part of the data provider. This long and boring introduction to say: please scrape responsibly." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Nobel purpose" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We know that the Nobel Prize in economics does not exist. The closest thing we have is the Nobel Memorial Prize in Economic Science. The first one was awarded in 1969, so it's fairly recent. This means that many of the work by the laureates are easily available online. In this week's exercises we will do two things:\n", - "\n", - "1. Scrape Wikipedia to retrieve informations about the location of the Alma Mater(s) of each Nobel Memorial Prize in Economic Sciences laureate. We want to know specifically how many Nobel Memorial Prize winner have never worked in an university in the United States.\n", - "2. Retrieve quotes from those people in an automated fashion so that we can pick one at random in a \"quote of the day\" spirit.\n", - "\n", - "Wikipedia is a great source for this endeavour as the website curators are notably favorable towards scrapers and make little effort to try to deter them. It is therefore a great use case for a first foray into the topic." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Retrieving the name and wikipedia page of all the laureate" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "There is a list of all the laureates available [here](https://en.wikipedia.org/wiki/List_of_Nobel_Memorial_Prize_laureates_in_Economics). The URL is \"https://en.wikipedia.org/wiki/List_of_Nobel_Memorial_Prize_laureates_in_Economics\". Let's just use requests and Beautiful Soup to retrieve all the names and wikipedia page of the laureates." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now that we have a list with the names and wikipedia pages of all laureates, we need to get inside each of those in order to get the name of their alma mater. The issue is that several of the laureates have several alma mater. Spend a little time looking at several of the pages of winners to see how this is reflected in the HTML.\n", - "\n", - "In this case, extracting the information might be wrapped inside a function that will be applied on the value of the dictionary created at the step before. Please use regular expression to identify the words \"Alma Mater\" (with and without capital letters for each word)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "And now, repeat the same to identify in which country this university is located. No need to use regular expressions here." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We are now ready to put everything together. Put everything together to modify the structure in which you store the name of the laureates to contain also the countries of their alma mater." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We are now ready to perform our analysis. Note however that what we have done could have been done in an more structured fashion had we used *pandas*, the library that enables working with dataframes.\n", - "\n", - "Moreover, you will see that some of the results are not correct and/or available (for example, Esther Duflo has no \"Alma Mater\" listed on her page (because in her case, it is called \"Education\") and some universities, such as the University of Leningrad, have no location). This is fine for now but a more comprehensive solution should determine something to work with that." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Voices from the past" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We are now going to collect all the quotes avaiable on Wikiquotes from the Nobel Memorial Prize for Economic Science laureates. In order to do so, we will pass through the list of laureates pages. If there is a link to a quotes page, we will scrape all the quotes there. If not, we will simply ignore it.\n", - "\n", - "When doing so, it usually makes sense to start by writing the code (in a function) that will scrape the quotes and then write the loop that pass on each laureate and identify if it is relevant to scrape it. Write the function that collects all the quotes from a wikiquote page. \n", - "\n", - "You will see that, for some authors, there are also quotes about the person (rather than quotes from the person). In this simple example, it is OK to collect them as well although in a real setting, we probably will want to avoid keeping those.\n", - "\n", - "If you need a page to serve as example, here is [Ragnar Frisch's wikiquotes page](https://en.wikiquote.org/wiki/Ragnar_Frisch)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We are now going to write the part that goes through the pages of all laureates, checks whether they have a Wikiquote page (the link is in the left sidebar) and then retrieve the quotes. We can, as we did previously, put the quotes in a dictionary of lists. Try avoiding having lists of size 0." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now that all the quotes are collected, we just use a standard random number generator to select one at random. You can either select a quote from a big \"bag\" containing all quotes but I would rather first choose a laureate and then a quote in order to avoid favouring the laureates who were more prolix (or who have a larger fan-base)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "argv": [ - "python", - "-m", - "ipykernel_launcher", - "-f", - "{connection_file}" - ], - "display_name": "Python 3", - "env": null, - "interrupt_mode": "signal", - "language": "python", - "metadata": null, - "name": "python3" - }, - "name": "Exercises.ipynb" - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Session_7/1_intro.ipynb b/Session_7/1_intro.ipynb new file mode 100644 index 0000000..43fe219 --- /dev/null +++ b/Session_7/1_intro.ipynb @@ -0,0 +1,2385 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [Python Fundamentals](https://datascience.quantecon.org/../python_fundamentals/index.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Understand the core pandas objects (`Series` and `DataFrame`) \n", + "- Index into particular elements of a Series and DataFrame \n", + "- Understand what `.dtype`/`.dtypes` do \n", + "- Make basic visualizations \n", + "\n", + "\n", + "**Data**\n", + "\n", + "- US regional unemployment data from Bureau of Labor Statistics " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [Introduction](#Introduction) \n", + " - [pandas](#pandas) \n", + " - [Series](#Series) \n", + " - [DataFrame](#DataFrame) \n", + " - [Data Types](#Data-Types) \n", + " - [Changing DataFrames](#Changing-DataFrames) \n", + " - [Exercises](#Exercises) " + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (1.12.0)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: python-dateutil in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (2.8.0)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n" + ] + } + ], + "source": [ + "# Uncomment following line to install on colab\n", + "! pip install qeds \n", + "#qeds = quantecon data science" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## pandas\n", + "\n", + "This lecture begins the material on `pandas`.\n", + "\n", + "To start, we will import the pandas package and give it the alias\n", + "`pd`, which is conventional practice." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Don't worry about this line for now!\n", + "%matplotlib inline\n", + "# activate plot theme\n", + "import qeds\n", + "qeds.themes.mpl_style();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sometimes, knowing which pandas version we are\n", + "using is helpful.\n", + "\n", + "We can check this by running the code below." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'0.25.1'" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.__version__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Series\n", + "\n", + "The first main pandas type we will introduce is called Series.\n", + "\n", + "A Series is a single column of data, with row labels for each\n", + "observation.\n", + "\n", + "pandas refers to the row labels as the *index* of the Series.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/intro_files/PandasSeries.png](https://datascience.quantecon.org/assets/_static/intro_files/PandasSeries.png) \n", + "Below, we create a Series which contains the US unemployment rate every\n", + "other year starting in 1995." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "values = [5.6, 5.3, 4.3, 4.2, 5.8, 5.3, 4.6, 7.8, 9.1, 8., 5.7]\n", + "years = list(range(1995, 2017, 2))\n", + "\n", + "unemp = pd.Series(data=values, index=years, name=\"Unemployment\")" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 5.6\n", + "1997 5.3\n", + "1999 4.3\n", + "2001 4.2\n", + "2003 5.8\n", + "2005 5.3\n", + "2007 4.6\n", + "2009 7.8\n", + "2011 9.1\n", + "2013 8.0\n", + "2015 5.7\n", + "Name: Unemployment, dtype: float64" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can look at the index and values in our Series." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Int64Index([1995, 1997, 1999, 2001, 2003, 2005, 2007, 2009, 2011, 2013, 2015], dtype='int64')" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.index" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([5.6, 5.3, 4.3, 4.2, 5.8, 5.3, 4.6, 7.8, 9.1, 8. , 5.7])" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What Can We Do with a Series object?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### `.head` and `.tail`\n", + "\n", + "Often, our data will have many rows, and we won’t want to display it all\n", + "at once.\n", + "\n", + "The methods `.head` and `.tail` show rows at the beginning and end\n", + "of our Series, respectively." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 5.6\n", + "1997 5.3\n", + "1999 4.3\n", + "2001 4.2\n", + "2003 5.8\n", + "Name: Unemployment, dtype: float64" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.head() #default 5, but we can put in brackets other number" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2007 4.6\n", + "2009 7.8\n", + "2011 9.1\n", + "2013 8.0\n", + "2015 5.7\n", + "Name: Unemployment, dtype: float64" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.tail() #default 5, but we can put in brackets other number" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Basic Plotting\n", + "\n", + "We can also plot data using the `.plot` method." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "unemp.plot() #check if there's a way to do the graph for a period of time, etc." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ">**Note**\n", + ">\n", + ">This is why we needed the `%matplotlib inline` — it tells the notebook\n", + "to display figures inside the notebook itself. Also, pandas has much greater visualization functionality than this, but we will study that later on." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Unique Values\n", + "\n", + "Though it doesn’t make sense in this data set, we may want to find the\n", + "unique values in a Series – which can be done with the `.unique` method." + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([5.6, 5.3, 4.3, 4.2, 5.8, 4.6, 7.8, 9.1, 8. , 5.7])" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.unique()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Indexing\n", + "\n", + "Sometimes, we will want to select particular elements from a Series.\n", + "\n", + "We can do this using `.loc[index_items]`; where `index_items` is\n", + "an item from the index, or a list of items in the index.\n", + "\n", + "We will see this more in-depth in a coming lecture, but for now, we\n", + "demonstrate how to select one or multiple elements of the Series." + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5.6" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.loc[1995]" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 5.6\n", + "2005 5.3\n", + "2015 5.7\n", + "Name: Unemployment, dtype: float64" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.loc[[1995, 2005, 2015]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## DataFrame\n", + "\n", + "A DataFrame is how pandas stores one or more columns of data.\n", + "\n", + "We can think a DataFrames a multiple Series stacked side by side as\n", + "columns.\n", + "\n", + "This is similar to a sheet in an Excel workbook or a table in a SQL\n", + "database.\n", + "\n", + "In addition to row labels (an index), DataFrames also have column labels.\n", + "\n", + "We refer to these column labels as the columns or column names.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/intro_files/PandasDataFrame.png](https://datascience.quantecon.org/assets/_static/intro_files/PandasDataFrame.png) \n", + "Below, we create a DataFrame that contains the unemployment rate every\n", + "other year by region of the US starting in 1995." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNational
19955.94.55.36.65.6
19975.64.35.26.05.3
19994.43.64.25.24.3
20013.84.04.04.64.2
20035.85.75.76.55.8
20054.95.75.25.55.3
20074.34.94.34.54.6
20097.18.17.68.67.8
20118.38.79.110.79.1
20137.97.47.48.58.0
20155.75.15.56.15.7
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National\n", + "1995 5.9 4.5 5.3 6.6 5.6\n", + "1997 5.6 4.3 5.2 6.0 5.3\n", + "1999 4.4 3.6 4.2 5.2 4.3\n", + "2001 3.8 4.0 4.0 4.6 4.2\n", + "2003 5.8 5.7 5.7 6.5 5.8\n", + "2005 4.9 5.7 5.2 5.5 5.3\n", + "2007 4.3 4.9 4.3 4.5 4.6\n", + "2009 7.1 8.1 7.6 8.6 7.8\n", + "2011 8.3 8.7 9.1 10.7 9.1\n", + "2013 7.9 7.4 7.4 8.5 8.0\n", + "2015 5.7 5.1 5.5 6.1 5.7" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = {\n", + " \"NorthEast\": [5.9, 5.6, 4.4, 3.8, 5.8, 4.9, 4.3, 7.1, 8.3, 7.9, 5.7],\n", + " \"MidWest\": [4.5, 4.3, 3.6, 4. , 5.7, 5.7, 4.9, 8.1, 8.7, 7.4, 5.1],\n", + " \"South\": [5.3, 5.2, 4.2, 4. , 5.7, 5.2, 4.3, 7.6, 9.1, 7.4, 5.5],\n", + " \"West\": [6.6, 6., 5.2, 4.6, 6.5, 5.5, 4.5, 8.6, 10.7, 8.5, 6.1],\n", + " \"National\": [5.6, 5.3, 4.3, 4.2, 5.8, 5.3, 4.6, 7.8, 9.1, 8., 5.7]\n", + "}\n", + "\n", + "unemp_region = pd.DataFrame(data, index=years)\n", + "unemp_region" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can retrieve the index and the DataFrame values as we\n", + "did with a Series." + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Int64Index([1995, 1997, 1999, 2001, 2003, 2005, 2007, 2009, 2011, 2013, 2015], dtype='int64')" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.index" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 5.9, 4.5, 5.3, 6.6, 5.6],\n", + " [ 5.6, 4.3, 5.2, 6. , 5.3],\n", + " [ 4.4, 3.6, 4.2, 5.2, 4.3],\n", + " [ 3.8, 4. , 4. , 4.6, 4.2],\n", + " [ 5.8, 5.7, 5.7, 6.5, 5.8],\n", + " [ 4.9, 5.7, 5.2, 5.5, 5.3],\n", + " [ 4.3, 4.9, 4.3, 4.5, 4.6],\n", + " [ 7.1, 8.1, 7.6, 8.6, 7.8],\n", + " [ 8.3, 8.7, 9.1, 10.7, 9.1],\n", + " [ 7.9, 7.4, 7.4, 8.5, 8. ],\n", + " [ 5.7, 5.1, 5.5, 6.1, 5.7]])" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What Can We Do with a DataFrame?\n", + "\n", + "Pretty much everything we can do with a Series." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### `.head` and `.tail`\n", + "\n", + "As with Series, we can use `.head` and `.tail` to show only the\n", + "first or last `n` rows." + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNational
19955.94.55.36.65.6
19975.64.35.26.05.3
19994.43.64.25.24.3
20013.84.04.04.64.2
20035.85.75.76.55.8
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National\n", + "1995 5.9 4.5 5.3 6.6 5.6\n", + "1997 5.6 4.3 5.2 6.0 5.3\n", + "1999 4.4 3.6 4.2 5.2 4.3\n", + "2001 3.8 4.0 4.0 4.6 4.2\n", + "2003 5.8 5.7 5.7 6.5 5.8" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNational
20118.38.79.110.79.1
20137.97.47.48.58.0
20155.75.15.56.15.7
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National\n", + "2011 8.3 8.7 9.1 10.7 9.1\n", + "2013 7.9 7.4 7.4 8.5 8.0\n", + "2015 5.7 5.1 5.5 6.1 5.7" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.tail(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Plotting\n", + "\n", + "We can generate plots with the `.plot` method.\n", + "\n", + "Notice we now have a separate line for each column of data." + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "unemp_region.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Indexing\n", + "\n", + "We can also do indexing using `.loc`.\n", + "\n", + "This is slightly more advanced than before because we can choose\n", + "subsets of both row and columns." + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5.9" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.loc[1995, \"NorthEast\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 5.3\n", + "2005 5.2\n", + "Name: South, dtype: float64" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.loc[[1995, 2005], \"South\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "NorthEast 5.9\n", + "National 5.6\n", + "Name: 1995, dtype: float64" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.loc[1995, [\"NorthEast\", \"National\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 5.9\n", + "1997 5.6\n", + "1999 4.4\n", + "2001 3.8\n", + "2003 5.8\n", + "2005 4.9\n", + "2007 4.3\n", + "2009 7.1\n", + "2011 8.3\n", + "2013 7.9\n", + "2015 5.7\n", + "Name: NorthEast, dtype: float64" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.loc[:, \"NorthEast\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 4.5\n", + "1997 4.3\n", + "1999 3.6\n", + "2001 4.0\n", + "2003 5.7\n", + "2005 5.7\n", + "2007 4.9\n", + "2009 8.1\n", + "2011 8.7\n", + "2013 7.4\n", + "2015 5.1\n", + "Name: MidWest, dtype: float64" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# `[string]` with no `.loc` extracts a whole column\n", + "unemp_region[\"MidWest\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Computations with Columns\n", + "\n", + "pandas can do various computations and mathematical operations on\n", + "columns.\n", + "\n", + "Let’s take a look at a few of them." + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 0.066\n", + "1997 0.060\n", + "1999 0.052\n", + "2001 0.046\n", + "2003 0.065\n", + "2005 0.055\n", + "2007 0.045\n", + "2009 0.086\n", + "2011 0.107\n", + "2013 0.085\n", + "2015 0.061\n", + "Name: West, dtype: float64" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Divide by 100 to move from percent units to a rate\n", + "unemp_region[\"West\"] / 100" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10.7" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Find maximum\n", + "unemp_region[\"West\"].max()" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 2.1\n", + "1997 1.7\n", + "1999 1.6\n", + "2001 0.6\n", + "2003 0.8\n", + "2005 -0.2\n", + "2007 -0.4\n", + "2009 0.5\n", + "2011 2.0\n", + "2013 1.1\n", + "2015 1.0\n", + "dtype: float64" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Find the difference between two columns\n", + "# Notice that pandas applies `-` to _all rows_ at once\n", + "# We'll see more of this throughout these materials\n", + "unemp_region[\"West\"] - unemp_region[\"MidWest\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9006381255384481" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Find correlation between two columns\n", + "unemp_region.West.corr(unemp_region[\"MidWest\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNational
NorthEast1.0000000.8756540.9644150.9678750.976016
MidWest0.8756541.0000000.9513790.9006380.952389
South0.9644150.9513791.0000000.9872590.995030
West0.9678750.9006380.9872591.0000000.981308
National0.9760160.9523890.9950300.9813081.000000
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National\n", + "NorthEast 1.000000 0.875654 0.964415 0.967875 0.976016\n", + "MidWest 0.875654 1.000000 0.951379 0.900638 0.952389\n", + "South 0.964415 0.951379 1.000000 0.987259 0.995030\n", + "West 0.967875 0.900638 0.987259 1.000000 0.981308\n", + "National 0.976016 0.952389 0.995030 0.981308 1.000000" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# find correlation between all column pairs\n", + "unemp_region.corr()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data Types\n", + "\n", + "We asked you to run the commands `unemp.dtype` and\n", + "`unemp_region.dtypes` and think about the outputs.\n", + "\n", + "You might have guessed that they return the type of the values inside\n", + "each column.\n", + "\n", + "Occasionally, you might need to investigate what types you have in your\n", + "DataFrame when an operation isn’t behaving as expected." + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dtype('float64')" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.dtype" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "NorthEast float64\n", + "MidWest float64\n", + "South float64\n", + "West float64\n", + "National float64\n", + "dtype: object" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.dtypes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "DataFrames will only distinguish between a few types.\n", + "\n", + "- Booleans (`bool`) \n", + "- Floating point numbers (`float64`) \n", + "- Integers (`int64`) \n", + "- Dates (`datetime`) — we will learn this soon \n", + "- Categorical data (`categorical`) \n", + "- Everything else, including strings (`object`) \n", + "\n", + "\n", + "In the future, we will often refer to the type of data stored in a\n", + "column as its `dtype`.\n", + "\n", + "Let’s look at an example for when having an incorrect `dtype` can\n", + "cause problems.\n", + "\n", + "Suppose that when we imported the data the `South` column was\n", + "interpreted as a string." + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "NorthEast float64\n", + "MidWest float64\n", + "South object\n", + "West float64\n", + "National float64\n", + "dtype: object" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str_unemp = unemp_region.copy()\n", + "str_unemp[\"South\"] = str_unemp[\"South\"].astype(str)\n", + "str_unemp.dtypes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Everything *looks* ok…" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNational
19955.94.55.36.65.6
19975.64.35.26.05.3
19994.43.64.25.24.3
20013.84.04.04.64.2
20035.85.75.76.55.8
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National\n", + "1995 5.9 4.5 5.3 6.6 5.6\n", + "1997 5.6 4.3 5.2 6.0 5.3\n", + "1999 4.4 3.6 4.2 5.2 4.3\n", + "2001 3.8 4.0 4.0 4.6 4.2\n", + "2003 5.8 5.7 5.7 6.5 5.8" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str_unemp.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But if we try to do something like compute the sum of all the columns,\n", + "we get unexpected results…" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "NorthEast 63.7\n", + "MidWest 62\n", + "South 5.35.24.24.05.75.24.37.69.17.45.5\n", + "West 72.8\n", + "National 65.7\n", + "dtype: object" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str_unemp.sum()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This happened because `.sum` effectively calls `+` on all rows in\n", + "each column.\n", + "\n", + "Recall that when we apply `+` to two strings, the result is the two\n", + "strings concatenated.\n", + "\n", + "So, in this case, we saw that the entries in all rows of the South\n", + "column were stitched together into one long string." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Changing DataFrames\n", + "\n", + "We can change the data inside of a DataFrame in various ways:\n", + "\n", + "- Adding new columns \n", + "- Changing index labels or column names \n", + "- Altering existing data (e.g. doing some arithmetic or making a column\n", + " of strings lowercase) \n", + "\n", + "\n", + "Some of these “mutations” will be topics of future lectures, so we will\n", + "only briefly discuss a few of the things we can do below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating New Columns\n", + "\n", + "We can create new data by assigning values to a column similar to how\n", + "we assign values to a variable.\n", + "\n", + "In pandas, we create a new column of a DataFrame by writing:" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + "df[\"New Column Name\"] = new_values\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below, we create an unweighted mean of the unemployment rate across the\n", + "four regions of the US — notice that this differs from the national\n", + "unemployment rate." + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "unemp_region[\"UnweightedMean\"] = (unemp_region[\"NorthEast\"] +\n", + " unemp_region[\"MidWest\"] +\n", + " unemp_region[\"South\"] +\n", + " unemp_region[\"West\"])/4" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNationalUnweightedMean
19955.94.55.36.65.65.575
19975.64.35.26.05.35.275
19994.43.64.25.24.34.350
20013.84.04.04.64.24.100
20035.85.75.76.55.85.925
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National UnweightedMean\n", + "1995 5.9 4.5 5.3 6.6 5.6 5.575\n", + "1997 5.6 4.3 5.2 6.0 5.3 5.275\n", + "1999 4.4 3.6 4.2 5.2 4.3 4.350\n", + "2001 3.8 4.0 4.0 4.6 4.2 4.100\n", + "2003 5.8 5.7 5.7 6.5 5.8 5.925" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Changing Values\n", + "\n", + "Changing the values inside of a DataFrame should be done sparingly.\n", + "\n", + "However, it can be done by assigning a value to a location in the\n", + "DataFrame.\n", + "\n", + "`df.loc[index, column] = value`" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "unemp_region.loc[1995, \"UnweightedMean\"] = 0.0" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNationalUnweightedMean
19955.94.55.36.65.60.000
19975.64.35.26.05.35.275
19994.43.64.25.24.34.350
20013.84.04.04.64.24.100
20035.85.75.76.55.85.925
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National UnweightedMean\n", + "1995 5.9 4.5 5.3 6.6 5.6 0.000\n", + "1997 5.6 4.3 5.2 6.0 5.3 5.275\n", + "1999 4.4 3.6 4.2 5.2 4.3 4.350\n", + "2001 3.8 4.0 4.0 4.6 4.2 4.100\n", + "2003 5.8 5.7 5.7 6.5 5.8 5.925" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Renaming Columns\n", + "\n", + "We can also rename the columns of a DataFrame, which is helpful because the names that sometimes come with datasets are\n", + "unbearable…\n", + "\n", + "For example, the original name for the North East unemployment rate\n", + "given by the Bureau of Labor Statistics was `LASRD910000000000003`…\n", + "\n", + "They have their reasons for using these names, but it can make our job\n", + "difficult since we often need to type it repeatedly.\n", + "\n", + "We can rename columns by passing a dictionary to the `rename` method.\n", + "\n", + "This dictionary contains the old names as the keys and new names as the\n", + "values.\n", + "\n", + "See the example below." + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NEMWSWNationalUnweightedMean
19955.94.55.36.65.60.000
19975.64.35.26.05.35.275
19994.43.64.25.24.34.350
20013.84.04.04.64.24.100
20035.85.75.76.55.85.925
20054.95.75.25.55.35.325
20074.34.94.34.54.64.500
20097.18.17.68.67.87.850
20118.38.79.110.79.19.200
20137.97.47.48.58.07.800
20155.75.15.56.15.75.600
\n", + "
" + ], + "text/plain": [ + " NE MW S W National UnweightedMean\n", + "1995 5.9 4.5 5.3 6.6 5.6 0.000\n", + "1997 5.6 4.3 5.2 6.0 5.3 5.275\n", + "1999 4.4 3.6 4.2 5.2 4.3 4.350\n", + "2001 3.8 4.0 4.0 4.6 4.2 4.100\n", + "2003 5.8 5.7 5.7 6.5 5.8 5.925\n", + "2005 4.9 5.7 5.2 5.5 5.3 5.325\n", + "2007 4.3 4.9 4.3 4.5 4.6 4.500\n", + "2009 7.1 8.1 7.6 8.6 7.8 7.850\n", + "2011 8.3 8.7 9.1 10.7 9.1 9.200\n", + "2013 7.9 7.4 7.4 8.5 8.0 7.800\n", + "2015 5.7 5.1 5.5 6.1 5.7 5.600" + ] + }, + "execution_count": 82, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names = {\"NorthEast\": \"NE\",\n", + " \"MidWest\": \"MW\",\n", + " \"South\": \"S\",\n", + " \"West\": \"W\"}\n", + "unemp_region.rename(columns=names)" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNationalUnweightedMean
19955.94.55.36.65.60.000
19975.64.35.26.05.35.275
19994.43.64.25.24.34.350
20013.84.04.04.64.24.100
20035.85.75.76.55.85.925
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National UnweightedMean\n", + "1995 5.9 4.5 5.3 6.6 5.6 0.000\n", + "1997 5.6 4.3 5.2 6.0 5.3 5.275\n", + "1999 4.4 3.6 4.2 5.2 4.3 4.350\n", + "2001 3.8 4.0 4.0 4.6 4.2 4.100\n", + "2003 5.8 5.7 5.7 6.5 5.8 5.925" + ] + }, + "execution_count": 83, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We renamed our columns… Why does the DataFrame still show the old\n", + "column names?\n", + "\n", + "Many pandas operations create a copy of your data by\n", + "default to protect your data and prevent you from overwriting\n", + "information you meant to keep.\n", + "\n", + "We can make these operations permanent by either:\n", + "\n", + "1. Assigning the output back to the variable name\n", + " `df = df.rename(columns=rename_dict)` \n", + "1. Looking into whether the method has an `inplace` option. For\n", + " example, `df.rename(columns=rename_dict, inplace=True)` \n", + "\n", + "\n", + "Setting `inplace=True` will sometimes make your code faster\n", + "(e.g. if you have a very large DataFrame and you don’t want to copy all\n", + "the data), but that doesn’t always happen.\n", + "\n", + "We recommend using the first option until you get comfortable with\n", + "pandas because operations that don’t alter your data are (usually)\n", + "safer." + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NEMWSWNationalUnweightedMean
19955.94.55.36.65.60.000
19975.64.35.26.05.35.275
19994.43.64.25.24.34.350
20013.84.04.04.64.24.100
20035.85.75.76.55.85.925
\n", + "
" + ], + "text/plain": [ + " NE MW S W National UnweightedMean\n", + "1995 5.9 4.5 5.3 6.6 5.6 0.000\n", + "1997 5.6 4.3 5.2 6.0 5.3 5.275\n", + "1999 4.4 3.6 4.2 5.2 4.3 4.350\n", + "2001 3.8 4.0 4.0 4.6 4.2 4.100\n", + "2003 5.8 5.7 5.7 6.5 5.8 5.925" + ] + }, + "execution_count": 84, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names = {\"NorthEast\": \"NE\",\n", + " \"MidWest\": \"MW\",\n", + " \"South\": \"S\",\n", + " \"West\": \"W\"}\n", + "\n", + "unemp_shortname = unemp_region.rename(columns=names)\n", + "unemp_shortname.head()" + ] + } + ], + "metadata": { + "date": 1584040761.4786024, + "filename": "intro.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "Introduction" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/1_intro_exercises.ipynb b/Session_7/1_intro_exercises.ipynb new file mode 100644 index 0000000..d4137da --- /dev/null +++ b/Session_7/1_intro_exercises.ipynb @@ -0,0 +1,682 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: six>=1.0.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pyarrow->qeds) (1.12.0)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: python-dateutil>=2.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.8.0)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import pandas as pd\n", + "%matplotlib inline\n", + "import qeds\n", + "qeds.themes.mpl_style();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "\n", + "\n", + "**For the purpose of these exercises, we create:**\n", + "\n", + "- **a Series which contains the US unemployment rate every other year starting in 1995**\n", + "\n", + "- **a DataFrame that contains the unemployment rate every other year by region of the US starting in 1995**" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 5.6\n", + "1997 5.3\n", + "1999 4.3\n", + "2001 4.2\n", + "2003 5.8\n", + "2005 5.3\n", + "2007 4.6\n", + "2009 7.8\n", + "2011 9.1\n", + "2013 8.0\n", + "2015 5.7\n", + "Name: Unemployment, dtype: float64" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Series which contains the US unemployment rate every other year starting in 1995\n", + "values = [5.6, 5.3, 4.3, 4.2, 5.8, 5.3, 4.6, 7.8, 9.1, 8., 5.7]\n", + "years = list(range(1995, 2017, 2))\n", + "\n", + "unemp = pd.Series(data=values, index=years, name=\"Unemployment\")\n", + "unemp" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastMidWestSouthWestNational
19955.94.55.36.65.6
19975.64.35.26.05.3
19994.43.64.25.24.3
20013.84.04.04.64.2
20035.85.75.76.55.8
20054.95.75.25.55.3
20074.34.94.34.54.6
20097.18.17.68.67.8
20118.38.79.110.79.1
20137.97.47.48.58.0
20155.75.15.56.15.7
\n", + "
" + ], + "text/plain": [ + " NorthEast MidWest South West National\n", + "1995 5.9 4.5 5.3 6.6 5.6\n", + "1997 5.6 4.3 5.2 6.0 5.3\n", + "1999 4.4 3.6 4.2 5.2 4.3\n", + "2001 3.8 4.0 4.0 4.6 4.2\n", + "2003 5.8 5.7 5.7 6.5 5.8\n", + "2005 4.9 5.7 5.2 5.5 5.3\n", + "2007 4.3 4.9 4.3 4.5 4.6\n", + "2009 7.1 8.1 7.6 8.6 7.8\n", + "2011 8.3 8.7 9.1 10.7 9.1\n", + "2013 7.9 7.4 7.4 8.5 8.0\n", + "2015 5.7 5.1 5.5 6.1 5.7" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#DataFrame that contains the unemployment rate every other year by region of the US starting in 1995\n", + "data = {\n", + " \"NorthEast\": [5.9, 5.6, 4.4, 3.8, 5.8, 4.9, 4.3, 7.1, 8.3, 7.9, 5.7],\n", + " \"MidWest\": [4.5, 4.3, 3.6, 4. , 5.7, 5.7, 4.9, 8.1, 8.7, 7.4, 5.1],\n", + " \"South\": [5.3, 5.2, 4.2, 4. , 5.7, 5.2, 4.3, 7.6, 9.1, 7.4, 5.5],\n", + " \"West\": [6.6, 6., 5.2, 4.6, 6.5, 5.5, 4.5, 8.6, 10.7, 8.5, 6.1],\n", + " \"National\": [5.6, 5.3, 4.3, 4.2, 5.8, 5.3, 4.6, 7.8, 9.1, 8., 5.7]\n", + "}\n", + "\n", + "unemp_region = pd.DataFrame(data, index=years)\n", + "unemp_region" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "1. **Display only the first 2 elements of the Series using the `.head` method.**" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1995 5.6\n", + "1997 5.3\n", + "Name: Unemployment, dtype: float64" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# To display only the two first lines, we use the .head function with \"2\" as an argument.\n", + "unemp.head(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Using the `plot` method, make a bar plot.** " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# The following makes a bar for each state and for each year.\n", + "unemp.plot.bar()\n", + "# Note that, by default, the index is taken as the x variable here." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Use `.loc` to select the lowest/highest unemployment rate shown in the Series.** " + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4.2" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#lowest temperature\n", + "unemp.loc[unemp.idxmin()]" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9.1" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#highest temperature\n", + "unemp.loc[unemp.idxmax()]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. **Run the code `unemp.dtype` below. What does it give you? Where do you think it comes from?**" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dtype('float64')" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.dtype\n", + "#we get that the dtype is float64\n", + "#this tells us the type of data stored in the series " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Now we create we create a DataFrame that contains the unemployment rate every other year by region of the US starting in 1995.**\n", + "\n", + "1. **Use introspection (or google-fu) to find a way to obtain a list with all of the column names in `unemp_region`.**" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['NorthEast', 'MidWest', 'South', 'West', 'National']" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(unemp_region)\n", + "\n", + "#to get the index, we can do:\n", + "#list(unemp_region.index)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Using the `plot` method, make a bar plot. What does it look like now?** " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXMAAAEYCAYAAACuiRYLAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3da1xU1cIG8GeQgUFAbiGIKGYg3j0qF01NyxLKRC010RNkJ7Q0T8FJk7TULoplomURZKl0MS+Q5FEh85RxtNJOZipgomQpIsYdHa4z7wd+zisBMwPMnj0unv+nmDXDsxbYM3s2a/Yo1Gq1FkREdEuzknsCRETUfixzIiIBsMyJiATAMiciEoAsZV5YWIjCwkI5oomIhGQtZ3hVVVWbHldRUQFHR0cTz8Zyc+XM5prFz5Uzm2tuHZVK1eIYT7MQEQmAZU5EJACWORGRAFjmREQCYJkTEQmAZU5EJABZtya2RKvV4s8//0R1dXWz4xqNBmVlZWaelXy5cmYbyu3UqROcnJzQuXNnM86KiP7KIsu8vLwcCoUC3bt3h0KhaDJeX1+PTp06mX1ecuXKma0vV6vVoqamBkVFRQDAQieSkUWeZrl27RqcnZ2bLXKyHAqFAra2tnBzc5PtFQsRNbDIMtdoNLIdAVPr2djYoL6+Xu5pEHVoFnmaBQCPym8h/F2RPv4L0lsc2xcbgIAlh1scP/NOqBRTEpJFHpkTEVHrsMyJiARgsadZ/krfSzUpWOLLu+nTpyMmJgYjR47sELlEZDwemZvQxo0bMX36dKSkpDS6/fTp05g+fTrKy8uN/j6rV69ucntSUhICAgJMMlciEgvL3MSUSiXS0tIk2arn4uICpVJp8u9LRLe+W+Y0y61i4MCBKCoqQkpKCh5//PEm4/X19UhMTMSpU6dQWloKNzc33HvvvZg0aRKsrKywY8cOHDp0CEDD6Q0AWLFiBfr27dvkdMeFCxewdetW5OTkwMbGBgEBAZgzZw7s7e0BNBzhV1RUYPDgwUhLS0NNTQ0CAwPxxBNPwNbWFgBw/PhxpKam4o8//gAA+Pr64rHHHoO3t7fkPysiMh2WuYkpFArMnj0br7/+Oh544AF4eno2GtdqtXB1dUVMTAy6dOmC3NxcJCYmwsHBAePHj8ekSZNw8eJFVFZWYuHChQAABweHJjnV1dV47bXX4Ovri9WrV6OyshKJiYlISEjAc889p7tfdnY2XFxc8NJLL6GoqAjr1q2Dl5cXpk6dqvs+EydOhI+PD2pqapCSkoK4uDjEx8fzVQDRLYSnWSQwbNgw9O3bF9u2bWsyZm1tjZkzZ8LX1xddu3bFnXfeifvuuw+HDzfstbWzs4ONjQ2USiVcXFxaPLWSmZmJqqoqLFy4ED4+PhgwYADmzZuHH374AZcvX9bdr3PnzoiKioK3tzeGDBmCkSNH4uTJk7rxESNGYMSIEejWrRt8fHwwf/58FBYWIjc3V4KfDBFJhUfmEvn73/+OF154AWFhYU3GvvzySxw8eBBXr15FTU0N6uvr4e7u3qrvf/HiRfj4+MDOzk53W58+faBQKHDx4kV069YNAODt7d3o3bQuLi44e/as7uuCggJ89tlnyM3NRXl5OTQaje5CZ0R062CZS8TX1xcjRozAxx9/jGnTpuluP3z4MLZs2YJHH30U/v7+sLOzQ0ZGBo4ePdrqjJbeeXnz7X+9LIJCoYBWq9V9HRcXB1dXV8ydOxeurq7o1KkToqOjUVdX1+r5EJF8eJpFQuHh4cjOzsbx48d1t+Xk5MDX1xf3338/evfujW7duqGgoKDR46ytraHRaPR+b29vb/z2229Qq9W623799VdotVp0797dqPlVVFTg0qVLeOihhzB48GB4e3tDrVbzOitEtyCWuYS6deuGe++9F/v27dPd5uXlhby8PBw/fhyXL1/Grl27kJWV1ehxXbt2xR9//IFLly6hvLy82aPkMWPGQKVS4e2338aFCxeQlZWFxMREBAcH606xGGJvbw9HR0d89dVXuHz5Mk6fPo2kpCRe5IzoFnTLnGa5+R2Zcl5XvLWmT5+OQ4cOoba2FgBw7733Ii8vDxs2bIBWq0VwcDAmTZqEr7/+WveY8ePH4/Tp01iyZAmqqqp0WxNvZmtri6VLl2LLli2IjY1ttDXRWFZWVoiOjsbmzZvxr3/9C56enoiIiMDatWtNs3giMhuFWq3WGr6baRUWFgIAunTp0uz4xYsX9e5ztsQPahA129hcQ7+ztqioqICjo6NJvydzzZ9t6KqJD6z+scVxKS+rcSv+nlUqVYtjPM1CRCQAljkRkQBY5kREAmCZExEJwGLL/OY3tpBl4++KSH4WWeZKpRIVFRUsCQun1WpRV1eHoqIi3VUYiUgeBveZ19fXY9u2bfj6669RUlICFxcXjBs3DrNmzZJsq5ybmxuKiopa/DAHjUYDKyvzPw/JlStntqFcKysr2Nvbt7jNlIjMw2CZp6SkYO/evYiOjoaPjw9+++033eVRZ86cKc2krK3h4eHR4vituD/0Vs2Wc81EZDyDZZ6dnY2goCAEBQUBADw8PBAcHIwzZ85IPjkiIjKOwdft/fv3xy+//KL7JJrff/8dv/zyCz+LkojIghh8O79Wq8VHH32EXbt2wcrKCvX19ZgxYwYeffTRZu+fnp6OjIwMvaGxsbEN4S1cwtUQrVbb5se2h1y5cmZzzeLnSp1dWFbd4pirgxLFlbUtjnd1avsf1vXlGspuT64h7flZ6/vcA4Nl/u2332Lz5s2YM2cOevbsifPnz+P999/HnDlzMGHChDZNyNC1WQzpiOePuWbm3qrZcl2bRV+uoWxLvSaMvmuzGDxnvnnzZkydOhV33XUXAKBXr164evUqdu3a1eYyJyIi0zJ4zry6urrJ1jQrKyuDH55ARETmY/DIPDAwELt27YKHh4fuNMvu3btxzz33mGN+RGQCxpxyCFhyuNkxKU85kOkYLPN58+bhk08+QUJCAsrKyuDi4oKQkBDJ9pgTEVHrGSzzzp07IyoqClFRUeaYDxERtYFFXpuFiIhah2VORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQBY5kREAmCZExEJgGVORCQAljkRkQCsjblTcXExtm7dih9//BFqtRqenp546qmnMGjQIKnnR0RERjBY5pWVlVi8eDH69++P5cuXo0uXLrhy5QqcnZ3NMT8iIjKCwTJPTU2Fq6srYmJidLd5enpKOikiImodhVqt1uq7w/z58zFs2DAUFRXh5MmTcHV1xYQJEzBx4kQoFIom909PT0dGRobe0NjY2IbwZh5vDK1W2+bHtodcuXJmc81i5BaWVesdd3VQoriyttmxrk62kmXry21vtpxr1qc9v2d3d/cWxwyW+UMPPQQAmDx5MkaPHo28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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Note that, by default, the index is taken as the x variable here.\n", + "unemp_region.plot.bar()\n", + "\n", + "#We create a column entitled UnweightedMean to play around with other plotting characteristics\n", + "unemp_region[\"UnweightedMean\"] = (unemp_region[\"NorthEast\"] +\n", + " unemp_region[\"MidWest\"] +\n", + " unemp_region[\"South\"] +\n", + " unemp_region[\"West\"])/4\n", + "\n", + "# The following makes a bar for each year, and this bar is the unweighted mean\n", + "unemp_region.plot.bar(y='UnweightedMean')\n", + "# The following makes a bar for each year, but plots the value \"Nation\"\n", + "unemp_region.plot.bar(y='National')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Use `.loc` to select the the unemployment data for the `NorthEast` and `West` for the years 1995, 2005, 2011, and 2015.** " + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NorthEastWest
19955.96.6
20054.95.5
20118.310.7
20155.76.1
\n", + "
" + ], + "text/plain": [ + " NorthEast West\n", + "1995 5.9 6.6\n", + "2005 4.9 5.5\n", + "2011 8.3 10.7\n", + "2015 5.7 6.1" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# .loc \"accesses a group of rows and columns by label(s)...\" Arguments are labels\n", + "unemp_region.loc[[1995, 2005, 2011, 2015], [\"NorthEast\", \"West\"]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. **Run the code `unemp_region.dtypes` below. What does it give you? How does this compare with `unemp.dtype`?**" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "NorthEast float64\n", + "MidWest float64\n", + "South float64\n", + "West float64\n", + "National float64\n", + "UnweightedMean float64\n", + "dtype: object" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_region.dtypes" + ] + } + ], + "metadata": { + "date": 1584040761.4786024, + "filename": "intro.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "Introduction" + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Session_7/2_basics.ipynb b/Session_7/2_basics.ipynb new file mode 100644 index 0000000..3c305c7 --- /dev/null +++ b/Session_7/2_basics.ipynb @@ -0,0 +1,3308 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Functionality\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [pandas Intro](https://datascience.quantecon.org/intro.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Be familiar with `datetime` \n", + "- Use built-in aggregation functions and be able to create your own and\n", + " apply them using `agg` \n", + "- Use built-in Series transformation functions and be able to create your\n", + " own and apply them using `apply` \n", + "- Use built-in scalar transformation functions and be able to create your\n", + " own and apply them using `applymap` \n", + "- Be able to select subsets of the DataFrame using boolean selection \n", + "- Know what the “want operator” is and how to apply it \n", + "\n", + "\n", + "**Data**\n", + "\n", + "- US state unemployment data from Bureau of Labor Statistics " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [Basic Functionality](#Basic-Functionality) \n", + " - [State Unemployment Data](#State-Unemployment-Data) \n", + " - [Dates in pandas](#Dates-in-pandas) \n", + " - [DataFrame Aggregations](#DataFrame-Aggregations) \n", + " - [Transforms](#Transforms) \n", + " - [Boolean Selection](#Boolean-Selection) \n", + " - [Exercises](#Exercises) " + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: python-dateutil in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (2.8.0)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (1.12.0)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n" + ] + } + ], + "source": [ + "# Uncomment following line to install on colab\n", + "! pip install qeds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## State Unemployment Data\n", + "\n", + "In this lecture, we will use unemployment data by state at a monthly\n", + "frequency." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'0.25.1'" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "%matplotlib inline\n", + "# activate plot theme\n", + "import qeds\n", + "qeds.themes.mpl_style();\n", + "\n", + "pd.__version__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we will download the data directly from a url and read it into a pandas DataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "## Load up the data -- this will take a couple seconds\n", + "url = \"https://datascience.quantecon.org/assets/data/state_unemployment.csv\"\n", + "unemp_raw = pd.read_csv(url, parse_dates=[\"Date\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The pandas `read_csv` will determine most datatypes of the underlying columns. The\n", + "exception here is that we need to give pandas a hint so it can load up the `Date` column as a Python datetime type: the `parse_dates=[\"Date\"]`.\n", + "\n", + "We can see the basic structure of the downloaded data by getting the first 5 rows, which directly matches\n", + "the underlying CSV file." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
DatestateLaborForceUnemploymentRate
02000-01-01Alabama2142945.04.7
12000-01-01Alaska319059.06.3
22000-01-01Arizona2499980.04.1
32000-01-01Arkansas1264619.04.4
42000-01-01California16680246.05.0
\n", + "
" + ], + "text/plain": [ + " Date state LaborForce UnemploymentRate\n", + "0 2000-01-01 Alabama 2142945.0 4.7\n", + "1 2000-01-01 Alaska 319059.0 6.3\n", + "2 2000-01-01 Arizona 2499980.0 4.1\n", + "3 2000-01-01 Arkansas 1264619.0 4.4\n", + "4 2000-01-01 California 16680246.0 5.0" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_raw.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that a row has a date, state, labor force size, and unemployment rate.\n", + "\n", + "For our analysis, we want to look at the unemployment rate across different states over time, which\n", + "requires a transformation of the data similar to an Excel pivot-table." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateAlabamaAlaskaArizonaArkansasCaliforniaColoradoConnecticutDelawareFloridaGeorgia...South DakotaTennesseeTexasUtahVermontVirginiaWashingtonWest VirginiaWisconsinWyoming
Date
2000-01-014.76.34.14.45.02.82.83.53.73.7...2.43.74.63.12.72.64.95.83.24.1
2000-02-014.76.34.14.35.02.82.73.63.73.6...2.43.74.63.12.62.54.95.63.23.9
2000-03-014.66.34.04.35.02.72.63.63.73.6...2.43.84.53.12.62.45.05.53.33.9
2000-04-014.66.34.04.35.12.72.53.73.73.7...2.43.84.43.12.72.45.05.43.43.8
2000-05-014.56.34.04.25.12.72.43.73.73.7...2.43.94.33.22.72.35.15.43.53.8
\n", + "

5 rows × 50 columns

\n", + "
" + ], + "text/plain": [ + "state Alabama Alaska Arizona Arkansas California Colorado \\\n", + "Date \n", + "2000-01-01 4.7 6.3 4.1 4.4 5.0 2.8 \n", + "2000-02-01 4.7 6.3 4.1 4.3 5.0 2.8 \n", + "2000-03-01 4.6 6.3 4.0 4.3 5.0 2.7 \n", + "2000-04-01 4.6 6.3 4.0 4.3 5.1 2.7 \n", + "2000-05-01 4.5 6.3 4.0 4.2 5.1 2.7 \n", + "\n", + "state Connecticut Delaware Florida Georgia ... South Dakota \\\n", + "Date ... \n", + "2000-01-01 2.8 3.5 3.7 3.7 ... 2.4 \n", + "2000-02-01 2.7 3.6 3.7 3.6 ... 2.4 \n", + "2000-03-01 2.6 3.6 3.7 3.6 ... 2.4 \n", + "2000-04-01 2.5 3.7 3.7 3.7 ... 2.4 \n", + "2000-05-01 2.4 3.7 3.7 3.7 ... 2.4 \n", + "\n", + "state Tennessee Texas Utah Vermont Virginia Washington \\\n", + "Date \n", + "2000-01-01 3.7 4.6 3.1 2.7 2.6 4.9 \n", + "2000-02-01 3.7 4.6 3.1 2.6 2.5 4.9 \n", + "2000-03-01 3.8 4.5 3.1 2.6 2.4 5.0 \n", + "2000-04-01 3.8 4.4 3.1 2.7 2.4 5.0 \n", + "2000-05-01 3.9 4.3 3.2 2.7 2.3 5.1 \n", + "\n", + "state West Virginia Wisconsin Wyoming \n", + "Date \n", + "2000-01-01 5.8 3.2 4.1 \n", + "2000-02-01 5.6 3.2 3.9 \n", + "2000-03-01 5.5 3.3 3.9 \n", + "2000-04-01 5.4 3.4 3.8 \n", + "2000-05-01 5.4 3.5 3.8 \n", + "\n", + "[5 rows x 50 columns]" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Don't worry about the details here quite yet\n", + "unemp_all = (\n", + " unemp_raw\n", + " .reset_index()\n", + " .pivot_table(index=\"Date\", columns=\"state\", values=\"UnemploymentRate\")\n", + ")\n", + "unemp_all.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we can filter it to look at a subset of the columns (i.e. “state” in this case)." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "states = [\n", + " \"Arizona\", \"California\", \"Florida\", \"Illinois\",\n", + " \"Michigan\", \"New York\", \"Texas\"\n", + "]\n", + "unemp = unemp_all[states]\n", + "unemp.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When plotting, a DataFrame knows the column and index names." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "unemp.plot(figsize=(8, 6))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dates in pandas\n", + "\n", + "You might have noticed that our index now has a nice format for the\n", + "dates (`YYYY-MM-DD`) rather than just a year.\n", + "\n", + "This is because the `dtype` of the index is a variant of `datetime`." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "DatetimeIndex(['2000-01-01', '2000-02-01', '2000-03-01', '2000-04-01',\n", + " '2000-05-01', '2000-06-01', '2000-07-01', '2000-08-01',\n", + " '2000-09-01', '2000-10-01',\n", + " ...\n", + " '2017-03-01', '2017-04-01', '2017-05-01', '2017-06-01',\n", + " '2017-07-01', '2017-08-01', '2017-09-01', '2017-10-01',\n", + " '2017-11-01', '2017-12-01'],\n", + " dtype='datetime64[ns]', name='Date', length=216, freq=None)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.index" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can index into a DataFrame with a `DatetimeIndex` using string\n", + "representations of dates.\n", + "\n", + "For example" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Arizona 4.1\n", + "California 5.0\n", + "Florida 3.7\n", + "Illinois 4.2\n", + "Michigan 3.3\n", + "New York 4.7\n", + "Texas 4.6\n", + "Name: 2000-01-01 00:00:00, dtype: float64" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Data corresponding to a single date\n", + "unemp.loc[\"01/01/2000\", :]" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
2000-06-014.05.13.84.33.74.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3\n", + "2000-06-01 4.0 5.1 3.8 4.3 3.7 4.6 4.3" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Data for all days between New Years Day and June first in the year 2000\n", + "unemp.loc[\"01/01/2000\":\"06/01/2000\", :]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will learn more about what pandas can do with dates and times in an\n", + "upcoming lecture on time series data." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## DataFrame Aggregations\n", + "\n", + "Let’s talk about *aggregations*.\n", + "\n", + "Loosely speaking, an aggregation is an operation that combines multiple\n", + "values into a single value.\n", + "\n", + "For example, computing the mean of three numbers (for example\n", + "`[0, 1, 2]`) returns a single number (1).\n", + "\n", + "We will use aggregations extensively as we analyze and manipulate our data.\n", + "\n", + "Thankfully, pandas makes this easy!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Built-in Aggregations\n", + "\n", + "pandas already has some of the most frequently used aggregations.\n", + "\n", + "For example:\n", + "\n", + "- Mean (`mean`) \n", + "- Variance (`var`) \n", + "- Standard deviation (`std`) \n", + "- Minimum (`min`) \n", + "- Median (`median`) \n", + "- Maximum (`max`) \n", + "- etc… \n", + "\n", + "\n", + ">**Note**\n", + ">\n", + ">When looking for common operations, using “tab completion” goes a long way." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Arizona 6.301389\n", + "California 7.299074\n", + "Florida 6.048611\n", + "Illinois 6.822685\n", + "Michigan 7.492593\n", + "New York 6.102315\n", + "Texas 5.695370\n", + "dtype: float64" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As seen above, the aggregation’s default is to aggregate each column.\n", + "\n", + "However, by using the `axis` keyword argument, you can do aggregations by\n", + "row as well." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 0.352381\n", + "2000-02-01 0.384762\n", + "2000-03-01 0.364762\n", + "2000-04-01 0.353333\n", + "2000-05-01 0.294762\n", + "dtype: float64" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.var(axis=1).head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Writing Your Own Aggregation\n", + "\n", + "The built-in aggregations will get us pretty far in our analysis, but\n", + "sometimes we need more flexibility.\n", + "\n", + "We can have pandas perform custom aggregations by following these two\n", + "steps:\n", + "\n", + "1. Write a Python function that takes a `Series` as an input and\n", + " outputs a single value. \n", + "1. Call the `agg` method with our new function as an argument. \n", + "\n", + "\n", + "For example, below, we will classify states as “low unemployment” or\n", + "“high unemployment” based on whether their mean unemployment level is\n", + "above or below 6.5." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "#\n", + "# Step 1: We write the (aggregation) function that we'd like to use\n", + "#\n", + "def high_or_low(s):\n", + " \"\"\"\n", + " This function takes a pandas Series object and returns high\n", + " if the mean is above 6.5 and low if the mean is below 6.5\n", + " \"\"\"\n", + " if s.mean() < 6.5:\n", + " out = \"Low\"\n", + " else:\n", + " out = \"High\"\n", + "\n", + " return out" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Arizona Low\n", + "California High\n", + "Florida Low\n", + "Illinois High\n", + "Michigan High\n", + "New York Low\n", + "Texas Low\n", + "dtype: object" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#\n", + "# Step 2: Apply it via the agg method.\n", + "#\n", + "unemp.agg(high_or_low)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 Low\n", + "2000-02-01 Low\n", + "2000-03-01 Low\n", + "2000-04-01 Low\n", + "2000-05-01 Low\n", + "dtype: object" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# How does this differ from unemp.agg(high_or_low)?\n", + "unemp.agg(high_or_low, axis=1).head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that `agg` can also accept multiple functions at once." + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
min3.64.53.14.23.24.23.9
max10.912.311.311.314.68.98.3
high_or_lowLowHighLowHighHighLowLow
\n", + "
" + ], + "text/plain": [ + " Arizona California Florida Illinois Michigan New York Texas\n", + "min 3.6 4.5 3.1 4.2 3.2 4.2 3.9\n", + "max 10.9 12.3 11.3 11.3 14.6 8.9 8.3\n", + "high_or_low Low High Low High High Low Low" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.agg([min, max, high_or_low])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Transforms\n", + "\n", + "Many analytical operations do not necessarily involve an aggregation.\n", + "\n", + "The output of a function applied to a Series might need to be a new\n", + "Series.\n", + "\n", + "Some examples:\n", + "\n", + "- Compute the percentage change in unemployment from month to month. \n", + "- Calculate the cumulative sum of elements in each column. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Built-in Transforms\n", + "\n", + "pandas comes with many transform functions including:\n", + "\n", + "- Cumulative sum/max/min/product (`cum(sum|min|max|prod)`) \n", + "- Difference (`diff`) \n", + "- Elementwise addition/subtraction/multiplication/division (`+`, `-`, `*`, `/`) \n", + "- Percent change (`pct_change`) \n", + "- Number of occurrences of each distinct value (`value_counts`) \n", + "- Absolute value (`abs`) \n", + "\n", + "\n", + "Again, tab completion is helpful when trying to find these functions." + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-01NaNNaNNaNNaNNaNNaNNaN
2000-02-010.000000.000.00.00000-0.0303030.0000000.000000
2000-03-01-0.024390.000.00.023810.000000-0.021277-0.021739
2000-04-010.000000.020.00.000000.0312500.000000-0.022222
2000-05-010.000000.000.00.000000.0606060.000000-0.022727
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York \\\n", + "Date \n", + "2000-01-01 NaN NaN NaN NaN NaN NaN \n", + "2000-02-01 0.00000 0.00 0.0 0.00000 -0.030303 0.000000 \n", + "2000-03-01 -0.02439 0.00 0.0 0.02381 0.000000 -0.021277 \n", + "2000-04-01 0.00000 0.02 0.0 0.00000 0.031250 0.000000 \n", + "2000-05-01 0.00000 0.00 0.0 0.00000 0.060606 0.000000 \n", + "\n", + "state Texas \n", + "Date \n", + "2000-01-01 NaN \n", + "2000-02-01 0.000000 \n", + "2000-03-01 -0.021739 \n", + "2000-04-01 -0.022222 \n", + "2000-05-01 -0.022727 " + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.pct_change().head()" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-01NaNNaNNaNNaNNaNNaNNaN
2000-02-010.00.00.00.0-0.10.00.0
2000-03-01-0.10.00.00.10.0-0.1-0.1
2000-04-010.00.10.00.00.10.0-0.1
2000-05-010.00.00.00.00.20.0-0.1
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 NaN NaN NaN NaN NaN NaN NaN\n", + "2000-02-01 0.0 0.0 0.0 0.0 -0.1 0.0 0.0\n", + "2000-03-01 -0.1 0.0 0.0 0.1 0.0 -0.1 -0.1\n", + "2000-04-01 0.0 0.1 0.0 0.0 0.1 0.0 -0.1\n", + "2000-05-01 0.0 0.0 0.0 0.0 0.2 0.0 -0.1" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.diff().head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Transforms can be split into to several main categories:\n", + "\n", + "1. *Series transforms*: functions that take in one Series and produce another Series. The index of the input and output does not need to be the same. \n", + "1. *Scalar transforms*: functions that take a single value and produce a single value. An example is the `abs` method, or adding a constant to each value of a Series. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom Series Transforms\n", + "\n", + "pandas also simplifies applying custom Series transforms to a Series or the\n", + "columns of a DataFrame. The steps are:\n", + "\n", + "1. Write a Python function that takes a Series and outputs a new Series. \n", + "1. Pass our new function as an argument to the `apply` method (alternatively, the `transform` method). \n", + "\n", + "\n", + "As an example, we will standardize our unemployment data to have mean 0\n", + "and standard deviation 1.\n", + "\n", + "After doing this, we can use an aggregation to determine at which date the\n", + "unemployment rate is most different from “normal times” for each state." + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "#\n", + "# Step 1: We write the Series transform function that we'd like to use\n", + "#\n", + "def standardize_data(x):\n", + " \"\"\"\n", + " Changes the data in a Series to become mean 0 with standard deviation 1\n", + " \"\"\"\n", + " mu = x.mean()\n", + " std = x.std()\n", + "\n", + " return (x - mu)/std" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-01-1.076861-0.935545-0.976846-1.337203-1.605740-0.925962-0.849345
2000-02-01-1.076861-0.935545-0.976846-1.337203-1.644039-0.925962-0.849345
2000-03-01-1.125778-0.935545-0.976846-1.286217-1.644039-0.991993-0.926885
2000-04-01-1.125778-0.894853-0.976846-1.286217-1.605740-0.991993-1.004424
2000-05-01-1.125778-0.894853-0.976846-1.286217-1.529141-0.991993-1.081964
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York \\\n", + "Date \n", + "2000-01-01 -1.076861 -0.935545 -0.976846 -1.337203 -1.605740 -0.925962 \n", + "2000-02-01 -1.076861 -0.935545 -0.976846 -1.337203 -1.644039 -0.925962 \n", + "2000-03-01 -1.125778 -0.935545 -0.976846 -1.286217 -1.644039 -0.991993 \n", + "2000-04-01 -1.125778 -0.894853 -0.976846 -1.286217 -1.605740 -0.991993 \n", + "2000-05-01 -1.125778 -0.894853 -0.976846 -1.286217 -1.529141 -0.991993 \n", + "\n", + "state Texas \n", + "Date \n", + "2000-01-01 -0.849345 \n", + "2000-02-01 -0.849345 \n", + "2000-03-01 -0.926885 \n", + "2000-04-01 -1.004424 \n", + "2000-05-01 -1.081964 " + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#\n", + "# Step 2: Apply our function via the apply method.\n", + "#\n", + "std_unemp = unemp.apply(standardize_data)\n", + "std_unemp.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-011.0768610.9355450.9768461.3372031.6057400.9259620.849345
2000-02-011.0768610.9355450.9768461.3372031.6440390.9259620.849345
2000-03-011.1257780.9355450.9768461.2862171.6440390.9919930.926885
2000-04-011.1257780.8948530.9768461.2862171.6057400.9919931.004424
2000-05-011.1257780.8948530.9768461.2862171.5291410.9919931.081964
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York \\\n", + "Date \n", + "2000-01-01 1.076861 0.935545 0.976846 1.337203 1.605740 0.925962 \n", + "2000-02-01 1.076861 0.935545 0.976846 1.337203 1.644039 0.925962 \n", + "2000-03-01 1.125778 0.935545 0.976846 1.286217 1.644039 0.991993 \n", + "2000-04-01 1.125778 0.894853 0.976846 1.286217 1.605740 0.991993 \n", + "2000-05-01 1.125778 0.894853 0.976846 1.286217 1.529141 0.991993 \n", + "\n", + "state Texas \n", + "Date \n", + "2000-01-01 0.849345 \n", + "2000-02-01 0.849345 \n", + "2000-03-01 0.926885 \n", + "2000-04-01 1.004424 \n", + "2000-05-01 1.081964 " + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Takes the absolute value of all elements of a function\n", + "abs_std_unemp = std_unemp.abs()\n", + "\n", + "abs_std_unemp.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Arizona 2009-11-01\n", + "California 2010-03-01\n", + "Florida 2010-01-01\n", + "Illinois 2009-12-01\n", + "Michigan 2009-06-01\n", + "New York 2009-11-01\n", + "Texas 2009-08-01\n", + "dtype: datetime64[ns]" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# find the date when unemployment was \"most different from normal\" for each State\n", + "def idxmax(x):\n", + " # idxmax of Series will return index of maximal value\n", + " return x.idxmax()\n", + "\n", + "abs_std_unemp.agg(idxmax)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom Scalar Transforms\n", + "\n", + "As you may have predicted, we can also apply custom scalar transforms to our\n", + "pandas data.\n", + "\n", + "To do this, we use the following pattern:\n", + "\n", + "1. Define a Python function that takes in a scalar and produces a scalar. \n", + "1. Pass this function as an argument to the `applymap` Series or DataFrame method. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Boolean Selection\n", + "\n", + "We have seen how we can select subsets of data by referring to the index\n", + "or column names.\n", + "\n", + "However, we often want to select based on conditions met by\n", + "the data itself.\n", + "\n", + "Some examples are:\n", + "\n", + "- Restrict analysis to all individuals older than 18. \n", + "- Look at data that corresponds to particular time periods. \n", + "- Analyze only data that corresponds to a recession. \n", + "- Obtain data for a specific product or customer ID. \n", + "\n", + "\n", + "We will be able to do this by using a Series or list of boolean values\n", + "to index into a Series or DataFrame.\n", + "\n", + "Let’s look at some examples." + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_small = unemp.head() # Create smaller data so we can see what's happening\n", + "unemp_small" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list of booleans selects rows\n", + "unemp_small.loc[[True, True, True, False, False]]" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-03-014.05.03.74.33.24.64.5
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# second argument selects columns, the ``:`` means \"all\".\n", + "# here we use it to select all columns\n", + "unemp_small.loc[[True, False, True, False, True], :]" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaNew YorkTexas
Date
2000-01-014.14.74.6
2000-02-014.14.74.6
2000-03-014.04.64.5
\n", + "
" + ], + "text/plain": [ + "state Arizona New York Texas\n", + "Date \n", + "2000-01-01 4.1 4.7 4.6\n", + "2000-02-01 4.1 4.7 4.6\n", + "2000-03-01 4.0 4.6 4.5" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# can use booleans to select both rows and columns\n", + "unemp_small.loc[[True, True, True, False, False], [True, False, False, False, False, True, True]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating Boolean DataFrames/Series\n", + "\n", + "We can use [conditional statements](https://datascience.quantecon.org/../python_fundamentals/control_flow.html) to\n", + "construct Series of booleans from our data." + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 False\n", + "2000-02-01 False\n", + "2000-03-01 False\n", + "2000-04-01 True\n", + "2000-05-01 True\n", + "Name: Texas, dtype: bool" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_small[\"Texas\"] < 4.5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once we have our Series of bools, we can use it to extract subsets of\n", + "rows from our DataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_small.loc[unemp_small[\"Texas\"] < 4.5]" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 True\n", + "2000-02-01 True\n", + "2000-03-01 True\n", + "2000-04-01 True\n", + "2000-05-01 True\n", + "dtype: bool" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_small[\"New York\"] > unemp_small[\"Texas\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "big_NY = unemp_small[\"New York\"] > unemp_small[\"Texas\"]\n", + "unemp_small.loc[big_NY]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Multiple Conditions\n", + "\n", + "In the boolean section of the [basics lecture](https://datascience.quantecon.org/../python_fundamentals/basics.html), we saw\n", + "that we can use the words `and` and `or` to combine multiple booleans into\n", + "a single bool.\n", + "\n", + "Recall:\n", + "\n", + "- `True and False -> False` \n", + "- `True and True -> True` \n", + "- `False and False -> False` \n", + "- `True or False -> True` \n", + "- `True or True -> True` \n", + "- `False or False -> False` \n", + "\n", + "\n", + "We can do something similar in pandas, but instead of\n", + "`bool1 and bool2` we write:" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + "(bool_series1) & (bool_series2)\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Likewise, instead of `bool1 or bool2` we write:" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + "(bool_series1) | (bool_series2)\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 False\n", + "2000-02-01 False\n", + "2000-03-01 True\n", + "2000-04-01 True\n", + "2000-05-01 True\n", + "dtype: bool" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "small_NYTX = (unemp_small[\"Texas\"] < 4.7) & (unemp_small[\"New York\"] < 4.7)\n", + "small_NYTX" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_small[small_NYTX]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### `isin`\n", + "\n", + "Sometimes, we will want to check whether a data point takes on one of a\n", + "several fixed values.\n", + "\n", + "We could do this by writing `(df[\"x\"] == val_1) | (df[\"x\"] == val_2)`\n", + "(like we did above), but there is a better way: the `.isin` method" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 True\n", + "2000-02-01 True\n", + "2000-03-01 True\n", + "2000-04-01 True\n", + "2000-05-01 False\n", + "Name: Michigan, dtype: bool" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp_small[\"Michigan\"].isin([3.3, 3.2])" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# now select full rows where this Series is True\n", + "unemp_small.loc[unemp_small[\"Michigan\"].isin([3.3, 3.2])]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### `.any` and `.all`\n", + "\n", + "Recall from the boolean section of the [basics lecture](https://datascience.quantecon.org/../python_fundamentals/basics.html)\n", + "that the Python functions `any` and `all` are aggregation functions that\n", + "take a collection of booleans and return a single boolean.\n", + "\n", + "`any` returns True whenever at least one of the inputs are True while\n", + "`all` is True only when all the inputs are `True`.\n", + "\n", + "Series and DataFrames with `dtype` bool have `.any` and `.all`\n", + "methods that apply this logic to pandas objects.\n", + "\n", + "Let’s use these methods to count how many months all the states in our\n", + "sample had high unemployment.\n", + "\n", + "As we work through this example, consider the [“want\n", + "operator”](http://albertjmenkveld.com/2014/07/07/endogeneous-price-dispersion/), a helpful\n", + "concept from Nobel Laureate [Tom\n", + "Sargent](http://www.tomsargent.com) for clearly stating the goal of our analysis and\n", + "determining the steps necessary to reach the goal.\n", + "\n", + "We always begin by writing `Want:` followed by what we want to\n", + "accomplish.\n", + "\n", + "In this case, we would write:\n", + "\n", + "> Want: Count the number of months in which all states in our sample\n", + "had unemployment above 6.5%\n", + "\n", + "\n", + "After identifying the **want**, we work *backwards* to identify the\n", + "steps necessary to accomplish our goal.\n", + "\n", + "So, starting from the result, we have:\n", + "\n", + "1. Sum the number of `True` values in a Series indicating dates for\n", + " which all states had high unemployment. \n", + "1. Build the Series used in the last step by using the `.all` method\n", + " on a DataFrame containing booleans indicating whether each state had\n", + " high unemployment at each date. \n", + "1. Build the DataFrame used in the previous step using a `>`\n", + " comparison. \n", + "\n", + "\n", + "Now that we have a clear plan, let’s follow through and *apply* the want\n", + "operator:" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-01FalseFalseFalseFalseFalseFalseFalse
2000-02-01FalseFalseFalseFalseFalseFalseFalse
2000-03-01FalseFalseFalseFalseFalseFalseFalse
2000-04-01FalseFalseFalseFalseFalseFalseFalse
2000-05-01FalseFalseFalseFalseFalseFalseFalse
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 False False False False False False False\n", + "2000-02-01 False False False False False False False\n", + "2000-03-01 False False False False False False False\n", + "2000-04-01 False False False False False False False\n", + "2000-05-01 False False False False False False False" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Step 3: construct the DataFrame of bools\n", + "high = unemp > 6.5\n", + "high.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 False\n", + "2000-02-01 False\n", + "2000-03-01 False\n", + "2000-04-01 False\n", + "2000-05-01 False\n", + "dtype: bool" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Step 2: use the .all method on axis=1 to get the dates where all states have a True\n", + "all_high = high.all(axis=1)\n", + "all_high.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Out of 216 months, 41 had high unemployment across all states\n" + ] + } + ], + "source": [ + "# Step 1: Call .sum to add up the number of True values in `all_high`\n", + "# (note that True == 1 and False == 0 in Python, so .sum will count Trues)\n", + "msg = \"Out of {} months, {} had high unemployment across all states\"\n", + "print(msg.format(len(all_high), all_high.sum()))" + ] + } + ], + "metadata": { + "date": 1584040758.8912327, + "filename": "basics.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "Basic Functionality" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/2_basics_exercises.ipynb b/Session_7/2_basics_exercises.ipynb new file mode 100644 index 0000000..62eae16 --- /dev/null +++ b/Session_7/2_basics_exercises.ipynb @@ -0,0 +1,1452 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 90, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: python-dateutil>=2.6.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2.8.0)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.12.0)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import pandas as pd\n", + "%matplotlib inline\n", + "import qeds\n", + "qeds.themes.mpl_style();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Functionality - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "**For these exercises we use unemployment data by state at a monthly frequency.**\n", + "\n", + "- **We download the data directly from a url and read it into a pandas DataFrame.**\n", + "\n", + "- **Since we want to look at the unemployment rate across different states over time, we proceed to a transformation of the data similar to an Excel pivot-table.**" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "#Download the data directly from a url and read it into a pandas DataFrame.\n", + "url = \"https://datascience.quantecon.org/assets/data/state_unemployment.csv\"\n", + "unemp_raw = pd.read_csv(url, parse_dates=[\"Date\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateAlabamaAlaskaArizonaArkansasCaliforniaColoradoConnecticutDelawareFloridaGeorgia...South DakotaTennesseeTexasUtahVermontVirginiaWashingtonWest VirginiaWisconsinWyoming
Date
2000-01-014.76.34.14.45.02.82.83.53.73.7...2.43.74.63.12.72.64.95.83.24.1
2000-02-014.76.34.14.35.02.82.73.63.73.6...2.43.74.63.12.62.54.95.63.23.9
2000-03-014.66.34.04.35.02.72.63.63.73.6...2.43.84.53.12.62.45.05.53.33.9
2000-04-014.66.34.04.35.12.72.53.73.73.7...2.43.84.43.12.72.45.05.43.43.8
2000-05-014.56.34.04.25.12.72.43.73.73.7...2.43.94.33.22.72.35.15.43.53.8
\n", + "

5 rows × 50 columns

\n", + "
" + ], + "text/plain": [ + "state Alabama Alaska Arizona Arkansas California Colorado \\\n", + "Date \n", + "2000-01-01 4.7 6.3 4.1 4.4 5.0 2.8 \n", + "2000-02-01 4.7 6.3 4.1 4.3 5.0 2.8 \n", + "2000-03-01 4.6 6.3 4.0 4.3 5.0 2.7 \n", + "2000-04-01 4.6 6.3 4.0 4.3 5.1 2.7 \n", + "2000-05-01 4.5 6.3 4.0 4.2 5.1 2.7 \n", + "\n", + "state Connecticut Delaware Florida Georgia ... South Dakota \\\n", + "Date ... \n", + "2000-01-01 2.8 3.5 3.7 3.7 ... 2.4 \n", + "2000-02-01 2.7 3.6 3.7 3.6 ... 2.4 \n", + "2000-03-01 2.6 3.6 3.7 3.6 ... 2.4 \n", + "2000-04-01 2.5 3.7 3.7 3.7 ... 2.4 \n", + "2000-05-01 2.4 3.7 3.7 3.7 ... 2.4 \n", + "\n", + "state Tennessee Texas Utah Vermont Virginia Washington \\\n", + "Date \n", + "2000-01-01 3.7 4.6 3.1 2.7 2.6 4.9 \n", + "2000-02-01 3.7 4.6 3.1 2.6 2.5 4.9 \n", + "2000-03-01 3.8 4.5 3.1 2.6 2.4 5.0 \n", + "2000-04-01 3.8 4.4 3.1 2.7 2.4 5.0 \n", + "2000-05-01 3.9 4.3 3.2 2.7 2.3 5.1 \n", + "\n", + "state West Virginia Wisconsin Wyoming \n", + "Date \n", + "2000-01-01 5.8 3.2 4.1 \n", + "2000-02-01 5.6 3.2 3.9 \n", + "2000-03-01 5.5 3.3 3.9 \n", + "2000-04-01 5.4 3.4 3.8 \n", + "2000-05-01 5.4 3.5 3.8 \n", + "\n", + "[5 rows x 50 columns]" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Transformation of the data similar to an Excel pivot-table\n", + "unemp_all = (\n", + " unemp_raw\n", + " .reset_index()\n", + " .pivot_table(index=\"Date\", columns=\"state\", values=\"UnemploymentRate\")\n", + ")\n", + "unemp_all.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-014.15.03.74.23.34.74.6
2000-02-014.15.03.74.23.24.74.6
2000-03-014.05.03.74.33.24.64.5
2000-04-014.05.13.74.33.34.64.4
2000-05-014.05.13.74.33.54.64.3
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 4.1 5.0 3.7 4.2 3.3 4.7 4.6\n", + "2000-02-01 4.1 5.0 3.7 4.2 3.2 4.7 4.6\n", + "2000-03-01 4.0 5.0 3.7 4.3 3.2 4.6 4.5\n", + "2000-04-01 4.0 5.1 3.7 4.3 3.3 4.6 4.4\n", + "2000-05-01 4.0 5.1 3.7 4.3 3.5 4.6 4.3" + ] + }, + "execution_count": 93, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#subset of the columns \n", + "states = [\n", + " \"Arizona\", \"California\", \"Florida\", \"Illinois\",\n", + " \"Michigan\", \"New York\", \"Texas\"\n", + "]\n", + "unemp = unemp_all[states]\n", + "unemp.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Looking at the unemp DataFrame above, can you identify the index? The columns? You can use the cell below to verify your visual intuition.**" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DatetimeIndex(['2000-01-01', '2000-02-01', '2000-03-01', '2000-04-01',\n", + " '2000-05-01', '2000-06-01', '2000-07-01', '2000-08-01',\n", + " '2000-09-01', '2000-10-01',\n", + " ...\n", + " '2017-03-01', '2017-04-01', '2017-05-01', '2017-06-01',\n", + " '2017-07-01', '2017-08-01', '2017-09-01', '2017-10-01',\n", + " '2017-11-01', '2017-12-01'],\n", + " dtype='datetime64[ns]', name='Date', length=216, freq=None)" + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#index\n", + "unemp.index" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Arizona', 'California', 'Florida', 'Illinois', 'Michigan', 'New York',\n", + " 'Texas'],\n", + " dtype='object', name='state')" + ] + }, + "execution_count": 95, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#columns\n", + "unemp.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2\n", + "\n", + "**Do the following exercises in separate code cells below:**\n", + "\n", + "1. **At each date, what is the minimum unemployment rate across all states in our sample?**" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Arizona 3.6\n", + "California 4.5\n", + "Florida 3.1\n", + "Illinois 4.2\n", + "Michigan 3.2\n", + "New York 4.2\n", + "Texas 3.9\n", + "dtype: float64" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# min unemployment rate by state\n", + "unemp.min()\n", + "\n", + "#alternatively, we can use unemp.agg(min)" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Date\n", + "2000-01-01 3.3\n", + "2000-02-01 3.2\n", + "2000-03-01 3.2\n", + "2000-04-01 3.3\n", + "2000-05-01 3.5\n", + " ... \n", + "2017-08-01 4.0\n", + "2017-09-01 3.9\n", + "2017-10-01 3.9\n", + "2017-11-01 3.9\n", + "2017-12-01 3.9\n", + "Length: 216, dtype: float64" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The argument axis=1 allows to search within rows. This gives the min overall for a given date\n", + "unemp.min(axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **What was the median unemployment rate in each state?**" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Arizona 5.80\n", + "California 6.50\n", + "Florida 5.35\n", + "Illinois 6.15\n", + "Michigan 7.00\n", + "New York 5.70\n", + "Texas 5.40\n", + "dtype: float64" + ] + }, + "execution_count": 98, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# median unemployment rate by state\n", + "unemp.median()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **What was the maximum unemployment rate across the states in our sample? What state did it happen in? In what month/year was this achieved?**\n", + " Hint 1: What Python type (not dtype) is returned by the aggregation?\n", + " Hint 2: Read documentation for the method idxmax" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "14.6" + ] + }, + "execution_count": 99, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# max unemployment rate across all states and Year\n", + "unemp.max().max()" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Michigan'" + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#type(unemp)\n", + "unemp.max().idxmax()\n", + "\n", + "#if we use unemp.max() we get the max value across all states\n", + "#but we want to know more: \n", + " #we want the state that had the max of all max unemployment rates and the month/year in which it has been achieved" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Timestamp('2009-06-01 00:00:00')" + ] + }, + "execution_count": 101, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unemp.max(axis=1).idxmax() \n", + "\n", + "#we can check whether for this date Michigan registered indeed the highest value by doing unemp.loc[\"06/01/2009\",:]\n", + "#we will get True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. **Classify each state as high or low volatility based on whether the variance of their unemployment is above or below 4.**\n" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Arizona High\n", + "California High\n", + "Florida High\n", + "Illinois Low\n", + "Michigan High\n", + "New York Low\n", + "Texas Low\n", + "dtype: object" + ] + }, + "execution_count": 102, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# high or low volatility\n", + "\n", + "# 1. we create our aggregation function\n", + "\n", + "def high_or_low_vol(v):\n", + " if v.var() > 4:\n", + " out = \"High\"\n", + " else:\n", + " out = \"Low\"\n", + " \n", + " return out\n", + "\n", + "# 2. we apply the function via the agg method\n", + "\n", + "unemp.agg(high_or_low_vol)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Imagine that we want to determine whether unemployment was high (> 6.5),medium (4.5 < x <= 6.5), or low (<= 4.5) for each state and each month.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Write a Python function that takes a single number as an input and outputs a single string noting if that number is high, medium, or low.** " + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [], + "source": [ + "# Part 1: Write a Python function to classify unemployment levels.\n", + "\n", + "def unemployment_levels(ul):\n", + " if ul > 6.5:\n", + " return \"high\"\n", + " elif 4.5 < ul <= 6.5:\n", + " #elif ul < 6.5: #equivalent to the line above\n", + " return \"medium\"\n", + " else:\n", + " return \"low\"\n", + " \n", + " return ul" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Pass your function to `applymap` (quiz: why `applymap` and not `agg` or `apply`?) and save the result in a new DataFrame called `unemp_bins`.** " + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
Date
2000-01-01lowmediumlowlowlowmediummedium
2000-02-01lowmediumlowlowlowmediummedium
2000-03-01lowmediumlowlowlowmediumlow
2000-04-01lowmediumlowlowlowmediumlow
2000-05-01lowmediumlowlowlowmediumlow
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "Date \n", + "2000-01-01 low medium low low low medium medium\n", + "2000-02-01 low medium low low low medium medium\n", + "2000-03-01 low medium low low low medium low\n", + "2000-04-01 low medium low low low medium low\n", + "2000-05-01 low medium low low low medium low" + ] + }, + "execution_count": 104, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Part 2: Pass your function from part 1 to applymap\n", + "#Apply map allows to apply a function that takes a scalar and returns a scalar to a dataframe\n", + "\n", + "unemp_bins = unemp.applymap(unemployment_levels) #replace this comment with your code!!\n", + "unemp_bins.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " 3. **(Challenging) Use another transform on `unemp_bins` to count how many times each state had each of the three classifications.**\n", + " - Hint 1: Will this value counting function be a Series or scalar transform? \n", + " - Hint 2: Try googling \"pandas count unique value\" or something similar to find the right transform. \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stateArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
high7510668911426551
low4446919172258
medium971067910657129107
\n", + "
" + ], + "text/plain": [ + "state Arizona California Florida Illinois Michigan New York Texas\n", + "high 75 106 68 91 142 65 51\n", + "low 44 4 69 19 17 22 58\n", + "medium 97 106 79 106 57 129 107" + ] + }, + "execution_count": 105, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Part 3: Count the number of times each state had each classification.\n", + "\n", + "# we count the number of times each state had each classification. \n", + "def count_bins(cb):\n", + " var = cb.value_counts() \n", + " return var\n", + "\n", + "unemp_count = unemp_bins.apply(count_bins)\n", + "unemp_count" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ArizonaCaliforniaFloridaIllinoisMichiganNew YorkTexas
low44.04.069.019.017.022.058.0
medium97.0106.079.0106.057.0129.0107.0
high75.0106.068.091.0142.065.051.0
\n", + "
" + ], + "text/plain": [ + " Arizona California Florida Illinois Michigan New York Texas\n", + "low 44.0 4.0 69.0 19.0 17.0 22.0 58.0\n", + "medium 97.0 106.0 79.0 106.0 57.0 129.0 107.0\n", + "high 75.0 106.0 68.0 91.0 142.0 65.0 51.0" + ] + }, + "execution_count": 106, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# alternative solution: value_counts is a series function (columns) so I loop over columns to have the frequencies for each states, then append each series\n", + "unemp_freq_cat = pd.DataFrame()\n", + "for iter in unemp_bins.columns:\n", + " series=unemp_bins[iter].value_counts()\n", + " unemp_freq_cat=unemp_freq_cat.append(series)\n", + "unemp_freq_cat=unemp_freq_cat[['low', 'medium', 'high']]\n", + "# We can transpose the table to make it more readable, matter of preferences\n", + "unemp_freq_catT=unemp_freq_cat.T\n", + "unemp_freq_catT" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. **Construct a horizontal bar chart of the number of occurrences of each level with one bar per state and classification (21 total bars).** " + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 107, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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y/f8/dW1bZ6enqpTp47279+v/fv3q2HDhgoNDdWff/6phIQEHT16lDADAABsIzAwUC4uLjp48KBlW25urg4fPmxZZV76v3kz167CuLm5KSQkRMuWLbP7+TKSAz3NBACA0Xh4eKh9+/b6/PPP5e3trSpVqujbb79VcnKyOnToYBnXsGFDrVq1Su7u7qpTp45l29dff62GDRva9XwZiTADAHBAJV2Rt7jK4osme/fuLUmaOXOmLl26pDp16ujNN9+Un5+fZUxYWJhMJpPq169vOX+jRo20dOlSu7/FJBFmAAAod1544QXLz66urhowYIAGDBhw3fGenp768ssv821r2LChlixZUmY1lieEGQNzpBVa09LS6BcAUCgmAAMAAEMjzAAAAEMjzAAAAEMjzAAAAEMjzAAAAEMjzAAAAEMjzAAAAEMjzAAAAENj0TwAgMPxjWtr1fOl1N9s1fMV18qVK7V27VrNnDlTkvTf//5XO3fu1NSpU21cWckQZgAAgCQpMjJSjzzyiK3LKDHCDAAAkHT1O56MiDADAEA5M3r0aFWvXl3u7u7avHmznJyc1K1bN7Vv317z58/Xtm3b5OnpqV69eunBBx+UJF24cEELFizQnj17JEmhoaEaMGCAqlWrZjnuihUrtGrVKmVlZemee+5R1apV853377eZZsyYobS0NEVFRd1wTP369fXtt9/q8uXLat++vZ566iktXbpU69atk8lkUufOndW1a9cy+byYAAwAQDn0ww8/yNPTUxMmTNBjjz2mefPmafLkyapWrZomTpyoNm3a6D//+Y8uXryo7OxsjR07Vq6urho7dqzeffdd+fn5ady4ccrOzpYk7dixQ1988YV69uypyZMnKygoSN9++22p1BoXF6fExESNHTtWQ4YM0cqVK/Xee+/pypUrGj9+vHr06KHPP/9cx44dK5Xz/R1hBgCAcqhGjRrq0aOHqlWrps6dO8vb21vOzs7q1KmTqlWrpieeeEJms1mHDh3S9u3bZTabNWzYMNWqVUvVq1fXkCFDlJWVpd27d0uSYmJi1KZNG/3jH/9QUFCQunXrppCQkFKp1cvLS4MGDVL16tV13333qU6dOkpKStLTTz+toKAgtW/fXrfddpv2799fKuf7O24zAQBQDtWqVcvys8lkkq+vr2rWrGnZ5uLioooVKyo1NVXx8fFKTExUnz59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Pfzww5Kkn3/+Wa6urmrUqJFSU1MlFX6baePGjfrmm290+vRpVaxYUXfddZdGjBhh2Z+WlqaJEydq165dqlSpkp5++mm1bft/3zz999tMhw4d0syZMxUfH6/g4GD16dNHY8eO1XvvvafGjRsrNzdX0dHR2rNnj5KTkxUQEKAOHTrosccek5PT1Zw4bdo0paamqlmzZlq2bJmys7PVsmVLPfvss/Lw8CjzzxMAAHtX7sKMJLVv317fffedJcxs2LBBDz/8sM6ePXvd96xZs0Zz5sxR3759FR4erqysLO3duzffmC+//FL9+vVT37599d133+nf//63GjZsqCpVqhQ4XmZmpsaNG6emTZtq5MiRunjxoubMmZNvjNlslr+/v15//XX5+vrq8OHDio6Olre3t9q3b28Zd+DAAfn7++udd97R+fPnNXnyZFWvXl3du3e/lY8JAAConIaZBx98UJ9++qnOnDkjT09P7d69W0OGDNHnn39+3fd89dVXevTRR9W1a1fLtpCQkHxj2rZta7kS07t3b61cuVL79+8vNMxs2bJFeXl5Gj58uNzd3VWrVi316NFDU6ZMsYxxcXFR7969La+rVq2qY8eO6fvvv88XZry8vPT888/L2dlZwcHBat26tfbs2VNomFm7dq3WrVtX5OcTFRUlSQqY+HqR44wiLS3thmPMZnOxxtkLR+rXkXqV6Nfe0W/ZKepuRrkMMxUrVlTLli313XffqUKFCmrcuHGhgeOa5ORkXbhwQU2aNCnyuLVr17b87OzsLF9fX6WkpBQ69tSpU6pVq5bc3d0t2+64444C49asWaP169crMTFRly9fVk5OToFag4OD5ezsbHnt7++vw4cPF3reiIgIRUREFNlHYmKiJOnCqElFjjOK4jzNlJaWJm9vbytUUz44Ur+O1KtEv/aOfm2jXIYZSfrHP/6hadOmydPTU08//XSRY81mc7GO6eKSv12TyaS8vLybrnHbtm2aM2eOBg4cqLCwMHl5eSkmJkY7d+7MN+6vQaY0zgsAAP5PuXua6ZomTZrIxcVFqampatmyZZFj/fz8FBAQoD179pTa+WvUqKE//vhD2dnZlm1/v5py4MABhYaGqnPnzgoJCVFQUFCR83oAAEDpK7dhxmQyafr06Zo7d26xHpfu0aOHVq5cqeXLl+v06dM6fvy4vvnmm5s+f5s2beTk5KQZM2bo5MmT+u2337RkyZJ8Y4KCgnT8+HHt2rVLZ86c0Zdffql9+/bd9DkBAEDJldvbTNLVibPF1bFjR7m4uGj58uWaP3++KlasqPDw8Js+t6enp/71r3/p448/1ksvvaSaNWuqV69emjhxotzc3CRdnd9y4sQJffDBB5Kke++9V127dtWGDRtu+rwl0cmvk1XOU+aGrb3hkNVR4Qoftd0KxZQPjtSvI/Uq0a+9o9+rDkUXPfeztJkyMzOLN+EE2rlzp9577z0tXLhQvr6+Nqvj2gTg5lE7bFaDta2OClfHCbtsXYbVOFK/jtSrRL/2jn6vKoswY7inmcqLjRs3KjAwUJUrV9Yff/yhOXPmqEWLFjYNMgAAID/CTBGSk5O1ePFiXbx4UX5+fgoPD1f//v1tXRYAAPgLwkwRunXrpm7dutm6DAAAUIRy+zQTAABAcRBmAACAoRFmAACAoRFmAACAoRFmAACAobFongFdWzTPx8fHxpVYT3n5ZlZrcaR+HalXiX7tHf2WnaIWzePKDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDTCDAAAMDSXkr4hNzdX27Zt0969e5WcnKw+ffqoTp06Sk9P16+//qqGDRvK39+/LGoFAAAooERh5tKlS3r77bd15MgReXh4KDs7W126dJEkeXp66pNPPtFDDz2kvn37lkmxAAAAf1eiMDN//nydPHlSo0ePVkhIiPr06WPZ5+zsrHvvvVe7d+8mzFiJb1xbW5dgNemBn8k37lFbl2E1jtSvI/Uq0e/NSqm/uRSqgb0q0ZyZnTt3qnPnzrr77rtlMpkK7A8KClJiYmKpFQcAAHAjJQoz6enpCgwMvO5+s9msK1eu3HJRAAAAxVWiMFOlShWdPHnyuvv37dun6tWr33JRAAAAxVWiMNOmTRutW7dO+/bts2y7drtp1apV2rlzp9q1a1e6FQIAABShRBOAn3jiCR06dEhvvvmmqlevLpPJpNmzZystLU1JSUlq2bKlIiMjy6pWAACAAkoUZlxcXDR69Ght2bJF27dvl3R13Zm6devqgQceUJs2bQqdGAwAAFBWSrxonnT1dlObNm1KuRQAAICSK9GcmcGDB+t///vfdff/9NNPGjx48C0XBQAAUFwlCjOJiYnKzMy87v6srCydP3/+losCAAAorhJ/0WRRc2JOnz4tT0/PWyoIAACgJG44Z2bjxo3atGmT5fVXX32l9evXFxiXnp6u33//Xc2bNy/dCm/R4sWLtX37dkVHRxfrdWk4d+6cBg8erKlTp+r2228vteP+3e7xjcrs2OVByOLplp/NaWkOtZy5I/XrSL1K9P7rgkIAACAASURBVAuUhRuGmaysLF28eNHy+tKlSzKbzfnGmEwmubu7q0OHDurVq1fpV1lC06ZNU2pqqkaPHn3DsY899pg6d+5cquevXLmyFixYIB8fn1I9LgAAKOiGYaZTp07q1KmTJGnQoEEaMmSI7rnnnjIvzFo8PT1L/daYs7Oz/Pz8SvWYAACgcCV6NPuTTz4pqzps5u+3ma5d1WnWrJmWLVum7OxstWzZUs8++6w8PDwkSVeuXNG8efP0/fff69KlS6pbt64GDBighg0bSip4myknJ0effPKJduzYodTUVFWqVEkPPvig+vfvb6u2AQCwGze1zowkZWRkKCMjQ3l5eQX2ValS5ZaKsrUDBw7I399f77zzjs6fP6/JkyerevXq6t69uyTps88+0w8//KDhw4crMDBQy5cv15gxYzRr1iz5+/sXON61r3p49dVXVaVKFV24cEGnT5+2dlsAANilEoeZdevW6ZtvvlFCQsJ1x6xYseKWirI1Ly8vPf/883J2dlZwcLBat26tPXv2qHv37srKytKaNWv04osvWiY7P//889q7d69iYmLUp0+fAsdLTExUUFCQGjZsKJPJpCpVqqh+/fqFnnvt2rVat25dkfVFRUVJkgImvn6LnZZvaWlplp/NZnO+1/bOkfp1pF4l+rV39Ft2rt0dKUyJwsx3332n6OhoNWnSRO3atdPChQvVpUsXubq6auPGjfLz8yv1ybS2EBwcLGdnZ8trf39/HT58WJKUkJCgnJycfGHE2dlZYWFhio+PL/R47dq109tvv62hQ4eqWbNmCg8P19133y0np4JPxkdERCgiIqLI+hITEyVJF0ZNKnFvRvLXp5nS0tLk7e1tw2qsy5H6daReJfq1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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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kqSWLVvqqaeeksVi0aJFi/Tdd98pIyND4eHhuv/++9WiRQun9O1IBAoAgEszm81655131Lp1az399NMym83at2+fqlatqkcffVSzZ8/WpEmTJEne3t6SpIKCAnXt2lURERE6efKkvvjiC7333nsaNWqUQkJC9Pzzz+s///mPJkyYID8/P+vjs7Nnz9amTZvUv39/ValSRbt27dLUqVNVvnx5NW7c2Gk/A0cgUAAAXNqZM2d0+vRpNW7cWOHh4ZKkiIgISdL+/fslSUFBQTbbtG7d2vp1WFiYBgwYoGeffVYnTpxQSEiI/Pz8JEmBgYEKCAiQJOXl5WnJkiX6v//7P8XGxlq33bNnj1auXEmgAACgNPP391erVq00evRo1atXT/Xr11fTpk1VsWLFy26zb98+ffPNNzpw4IBOnToli8UiSTp+/LhCQkIuuU1KSorOnTun0aNH2yw3m82qVKmS/RoqoQgUAACXN2TIEHXs2FFbtmzR77//rtmzZ+vFF1+85Ni8vDy9+eabatCggYYOHarAwECdPHlSr776qgoKCi57jAuh46WXXioSVjw8XP/t1vU7BABAUvXq1VW9enXdf//9Gj16tNauXavGjRursLDQZlxqaqpycnLUo0cPhYWFSTp/9uFiFwLCxdtGRkbK09NTx48fV/369W9wNyUPgQIA4NLS0tL03Xff6bbbblNwcLDS0tL03//+V+3atVNoaKjOnTunv/76SzfddJO8vLxUsWJFeXp6asWKFWrfvr1SUlL01Vdf2eyzYsWKMplM2rx5sxo3bqxy5crJx8dHnTt31meffSaLxaLY2Fjl5eVp9+7dMplMuvvuu530E3AM95EjRyY4u4jS5vTp05IkLy8vJ1fiOPn5+fTrwujXtd2ofk+ePGm9IbEksVgscnP73zRLBQUFWrdunZYsWaJvv/1WW7du1Z133qmHH35YoaGhysrK0rx58/TNN9/I3d3devPmypUrtXDhQqWmpqpXr15av369WrVqpdDQUPn6+spkMmnhwoX65ptvlJGRoSZNmqhevXry8vLSsmXLNH/+fP388886deqUzQ2hN7pfo670ul7p0o0pNzfXYrcqyoj09HRJKpH/I90oOTk58vf3d3YZDkO/ro1+7SMlJUWRkZF2369RZrNZ7u7uzi7DYezd75Ve1wuP1V4KM2UCAADDCBQAAMAwAgUAADCMQAEAAAwjUAAAAMMIFAAAwDACBQAAMIxAAQAADCNQAAAAwwgUAABcg6SkJHXp0kUnT550diklEh8OBgCwq9pDVjj0eH9Pbl+s7fbv36+XXnpJMTExevPNN686PiYmRtOmTStT07ZfD85QAADKpO+//17t2rXTwYMHi3w8+T8VFBTI09NTQUFBMplMDqqwdOEMBQCgzDl79qx++uknjRo1SmfPntUPP/ygPn36SDr/AZBDhgzRM888o++//167du1S7969Va1aNSUkJGjGjBkKCAjQk08+qWPHjhXZ9+TJkxUaGqpjx47pk08+0bZt2yRJDRo00GOPPaaQkBBJ0pw5c7Rp0yY99NBDmj17trKzs1W/fn098cQT1g+f3LNnj2bPnq39+/eroKBA1apVU+/evVW7dm0H/aSuHWcoAABlzqZNm1SpUiVFRUWpZcuWWrdunQoKCmzGfPnll2rXrp0mTpyoJk2aFNnHmDFjNG3aNOt/jRs3VkREhAIDA2WxWDRu3DhlZ2frtddeU0JCgjIzM/XOO+/IYvnfh3ynp6drw4YNeuGFFzRy5Ejt379fs2fPtq7Pzc1VixYtNGrUKI0ZM0bVq1fXmDFjSuR9HAQKAECZs3r1arVo0UKSVLduXXl5een333+3GRMfH6+mTZsqLCzMelbhYoGBgQoKClJQUJDWrVunXbt26eWXX5aXl5e2bt2qAwcO6JlnnlF0dLRq1qypZ555Rvv377eesZCkwsJCDRkyRFFRUapdu7batm1rs75+/fpq2bKlIiMjFRERof79+8vT01Nbtmy5QT+Z4uOSBwCgTDly5Ij+/vtvPfvss5Ikk8mkO++8U6tXr9Ydd9xhHVejRo1r2t/vv/+uOXPmaMSIEQoPD5ckpaamKjg4WKGhodZxYWFhCgoKUkpKiho0aCBJqlixosqXL28dExwcbHP2ITs7W1999ZWSkpKUlZWlwsJC5efn6/jx48X/AdwgBAoAQJmyevVqFRYWavDgwdZlFy5DXPxG7e3tfdV9HTx4UO+//7769++vuLi4Ivu7lItv6vTwKPo2XFhYaP06MTFR2dnZ6tu3r0JDQ+Xh4aFRo0YVuTxTEhAoAABlhtls1rp169SzZ081btzYZt2kSZO0Zs0atWzZ8pr2dfLkSb399ttq06aN2rRpY7MuMjJSGRkZSk9Pt56lSEtLU2ZmpiIjI6+53uTkZD322GPWWrOyspSZmXnN2zsSgQIAUGZs3rxZOTk5atu2bZH5JJo1a6ZVq1ZZ7624mv/85z8KCgpS586dbd7kAwIC1KBBA1WvXl3vv/+++vXrJ0maMWOGbrrpJtWrV++a661cubJ+/PFHRUdH6+zZs5o1a9Ylz2qUBCWzKgBAqVXciaYcYfXq1YqLi7vk5FRNmzbVF198oa1bt17Tvnbu3ClJGjRokM3yC4+NvvDCC/rkk0+UkJAg6fwNlv3797+ueSyefPJJTZ06VS+99JKCg4NL9Eydptzc3Mtf6MElpaenS5L1OeGyICcnp0zNDke/ro1+7SMlJeW6Tt87itlslru7u7PLcBh793ul1/VK95Xw2CgAADCMQAEAAAwjUAAAAMMIFAAAwDACBQAAMIxAAQAADCNQAAAAwwgUAADAMAIFAAAwjEABAEAxJCUl2UyF/c/vJem3337T0KFD1a1bNyUmJt7QetLT09WlSxft3bv3hh7ncvgsDwCAXe3pOdShx4v+clKxtsvKytL8+fO1efNmnThxQv7+/oqKilJ8fLwaNWp03fuLiYnRtGnTbKY5/+CDD9S6dWvFx8df08ehGxESEqJp06Y57WMhCBQGBN3yurNLcJhf5w1QtRYTnF2Gw7hqv5l/vubsEoASIT09XSNHjpSPj4969uypqKgoWSwWbdu2TdOmTdOHH3543fv09PRUUFCQ9fvTp08rJydHN998s0JCQopd67lz5+Tp6XnVce7u7jbHdzQCBQCgzPnoo48kSWPHjpWPj491eWRkpJo3by5JWrx4sdauXau0tDT5+vrqlltuUZ8+fVS+fPlL7jMpKUkJCQmaMWOGDh06ZP2U0ddfP//LZ0JCguLi4vTLL7/o66+/1pEjRxQYGKi7775bDz74oPVTSJ988km1atVKx48f1y+//KIGDRqod+/eGjJkiJ577jmtWrVKf//9typVqqR+/fpZPw49PT1dQ4YM0dixY1WzZk2ZzWZNnTpV27dvV1ZWlkJCQtS2bVt17txZbm72v+OBQAEAKFNycnK0ZcsWde/e3SZMXODn5ydJcnNz06OPPqqwsDAdO3ZMH3/8sWbMmKGnn376qseIiYnRhAkTNGzYMD3//POKiYmRn5+f9u7dq/Hjx+uhhx5S8+bNtXfvXk2dOlW+vr6Kj4+3br9kyRI99NBDGjt2rM1+Z8+erd69e2vAgAGaN2+e3n33XSUmJl4y5FgsFgUHB2vYsGEKCAjQnj17NHXqVPn5+alNmzbX+2O7Km7KBACUKUePHpXFYlFERMQVx3Xs2FH169dXaGio4uLi1KtXL23cuFGFhYVXPYanp6cCAwMlnQ8oQUFB8vT01JIlS1S3bl1169ZNVapUUfPmzXXvvfdq4cKFNtvXrVtX9913nypXrqzKlStbl3fq1Em33nqrKleurB49eujUqVM6cODAJWvw8PBQ9+7dFR0drdDQUP3rX//S3XffrQ0bNly1/uLgDAUAAJewbds2LViwQKmpqTpz5owKCwtVUFCgrKwsBQcHF2ufqampRW74rFOnjr755hudOXNGvr6+kqSaNWtecvtq1apZv75Qw8VPlfzTqlWrtHr1ah07dkz5+fkym82qVKlSsWq/GgIFAKBMCQ8Pl8lkUmpq6mXHHDt2TGPGjFHbtm3VrVs3+fv7a//+/Xr33XdVUFBQ7GNbLJbLrrtwD4UkeXl5XXKMh8f/3rYvjL/cGZMNGzZo5syZ6t27t2rXri0fHx+tXLlSv/76a3FKvyoCBQCgTPH391fDhg21YsUKxcfHF7mP4vTp09q7d68KCgrUt29fubu7S5L++OMPw8eOjIxUcnKyzbLk5GSFhIRc8n4OI5KTkxUdHW1zb8bRo0fteoyLcQ8FAKDMefzxx2WxWPTyyy9r48aNSk1NVWpqqlauXKnnnntOlStXlsVi0bJly5SWlqaffvpJS5cuNXzczp07a8eOHZozZ44OHz6s9evXa/Hixbrvvvvs0JWtKlWqaP/+/frzzz915MgRzZ07Vzt27LD7cS7gDAUAwK6KO9GUI4WFhemdd97R/PnzNWvWLGVkZFgntho0aJCioqLUr18/LVy4ULNnz1bt2rXVp08fTZw40dBxa9Sooeeee05ff/215s+frwoVKuj+++9X+/bt7dTZ/7Rt21b79+/Xe++9J4vFottvv12dO3fWmjVr7H4sSTLl5uZe/oIOLik9PV2SFNXS2F+s0uTXeQPU5KHpzi7DYVy138tNbJWTk2Mzu5+ro1/7SElJUWRkpN33a5TZbLZepigL7N3vlV7XK832yRkKA8qNS3F2CY4TYL5kv2ltXe9NVzr/DzCzSgLAteMeCgAAYBiBAgAAGEagAAAAhhEoAACAYQQKAABgGIECAAAYRqAAAACGESgAAIBhBAoAAC6SmJioMWPGGN7PmjVr1KtXryuOWbRokZ588knDxyoJmCnTgIzN65xdgl2ce3HXVcfk5OS47KyYAOwrcOddDj1eduz1fzZFYmKi1q0r+m/4O++8Y4+SJEn/+te/1KhRI7vtr6QjUAAAyqT69etr6NChNssCAgLssu+CggJ5eXnJy8vLLvsrDQgUAIAyydPTU0FBQVcdd+7cOc2aNUsbNmzQmTNnVL16dfXu3VuxsbGSpKSkJCUkJGj48OGaM2eODhw4oBdeeEEnT57UjBkzNGvWLOu+vv32Wy1evFh5eXm6/fbbFRYWZnOsPXv2aPbs2dq/f78KCgpUrVo19e7dW7Vr17Zv8zcAgQIAgCv4/PPPtXHjRg0ePFhhYWFasmSJRo8erUmTJtkEklmzZqlv374KDw+Xt7e3Nm/ebLOfn3/+WbNnz1b//v0VFxenjRs36ttvv5Wfn591TG5urlq0aKF+/frJZDJp+fLlGjNmjN5//327nT25UQgUAIAyacuWLTY3TcbGxmrEiBE2Y/Ly8rRq1SoNHjxYjRs3liQNGDBA27dv14oVK9SjRw/r2K5du6phw4aXPd7SpUvVqlUr3X333ZKkhx56SElJSTp69Kh1TP369W226d+/v3755Rdt2bJFLVq0KH6zDkCgAACUSbGxsRo0aJD1+3LlyhUZk5aWJrPZbHPJwd3dXTExMUpJSbEZW7NmzSseLzU1VW3atLFZFhMTYxMosrOz9dVXXykpKUlZWVkqLCxUfn6+jh8/fl29OQOBAgBQJnl5ealy5cpXHGOxWCRJJpOpyLp/LrPHDZiJiYnKzs5W3759FRoaKg8PD40aNUoFBQWG932jMQ8FAACXER4eLg8PDyUnJ1uXmc1m7dq1S5GRkde1r4iICO3aZfuY/j+/T05OVnx8vBo3bqyqVavKx8dHmZmZxW/AgThDAQDAZXh7e+uee+7RF198IX9/f4WGhmrJkiXKyspSu3btrmtfHTp0UGJioqKjoxUXF6dNmzZpz549NjdlVq5cWT/++KOio6N19uxZzZo1Sx4epeOtunRUCQAoNYoz0VRJduHGzSlTpuj06dO66aabNGLEiGt65PRizZo1U3p6umbPnq2zZ8/q1ltvVadOnbR27VrrmCeffFJTp07VSy+9pODgYHXp0kUnT560Zzs3jCk3N9fi7CJKm/T0dElSyIe3OrkS+7jWmTL9/f0dUE3JQL+ujX7tIyUl5bpP+zuC2WyWu7u7s8twGHv3e6XX1dvb+7LblZozFBMnTtTJkyf12muvObsUq41H1jq7BPv49+FLLr51YhUHFwIAKK24KRMAABhGoAAAAIaVykBx7tw5TZ8+Xb1799aDDz6o559/XklJSdb1zz33nObOnWv9/j//+Y86d+5sffQmLy9PDzzwgHbs2OHw2gEAcEWlMlB88sknWr9+vZ5++mm99957ioqKUkJCgjIyMiSdn7p027Zt1vHbt29XQECAddnOnTutM50BAADjSs1NmRfk5eVp+fLlGjp0qG677TZJ5x+z2bp1q5YuXarevXurXr16Wrp0qcxms9LS0nTmzBl16tRJW7duVYsWLbRt2zbFxsZe8tneFStWaOXKlVesYfjw4ZKkGs/52r/BEiQnJ8f6tcVisfne1dGva6Nf+ygsLJTZbLb7fu2hpNZ1o9iz38LCwsv+fXGJpzwuOHLkiAoKCqwfGyudn1e9Tp06OnTokCQpLi5O586d0+7du/Xf//5XdevW1c0336wpU6ZIOn/G4sKHvPxT+/bt1b59+yvWcOGx0X3jz9ijpRLr4qc8eMzOtdGva7tR/WZnZ5fIxzN5bNQYNze3Yv19KZWXPKRLz6t+gY+Pj2rWrKmtW7dq27ZtatCggerUqaP09HQdPnxYu3fvLvKJbgAAoPhKXaCoXLmyPDw8bG6oNJvNSk5OVrVq1azLLtxHsX37dtWrV0/lypVTTEyMvv76a+6fAADAzkpdoPD29laHDh306aef6vfff9ehQ4f0wQcfKCsrSx06dLCOq1evnrZu3arc3FzrR8rWr19fa9euvez9EwCAsmfOnDkaNmzYNX9vD+np6erSpYv27t1r1/06U6l8V3300UclSe+9955OnTqlmjVrKiEhQcHBwdYxcXFxMplMqlu3rvXaUoMGDfTVV1+pXr16dqmjzcBH7LKfEmvn/748Ff6JAnfe67xaHIx+bxxX+5wHFPX7ZWbfvVGKM6tvYmKicnJyrDfZX0nnzp0VHx9fnNIuKyQkRNOmTVNAQIBd9+tMpSZQ/Pvf/7Z+7enpqQEDBmjAgAGXHe/j46OFCxfaLKtfv74WL158w2oEALgeHx8fu+/T3d39uj9crKQrNYECAABnmDNnjjZt2qQJEyZI+t/ZjQYNGujbb79Vfn6+brvtNj3++OPy8vKSdH4CxlmzZmnDhg06c+aMqlevrt69e1ufUExPT9eQIUM0duxY1axZUwUFBfrss8+0adMm5eTkKDAwUHfeeaf1k05LAwIFAADXaefOnQoKCtKrr76qEydOaMKECapSpYoeeOABSdLnn3+ujRs3avDgwQoLC9OSJUs0evRoTZo06ZJnJpYvX65ff/1Vzz77rCpVqqSMjAwdPuzYS0dGlbqbMgEAcDZfX18NGDBAkZGRatiwoZo2bWqdjTkvL0+rVq1Sr1691LhxY3WW8ncAACAASURBVEVGRmrAgAGqUKGCVqxYccn9HTt2TJUrV1ZsbKwqVaqk2rVr66677nJkS4YRKAAAuE6RkZE2k0kFBQUpOztbkpSWliaz2azatWtb11+YriAlJeWS+2vVqpUOHDigp59+Wh999JH++OMPFRYW3tgm7IxAAQDAdfrnzJQmk0kWi0WSrH9eagLGy03KWKNGDU2ZMkU9e/ZUYWGhJk+erDfeeKNUhQoCBQAAdhQeHi4PDw8lJydbl5nNZu3atUuRkZGX3c7Hx0dNmzbVwIEDNXz4cG3fvl1Hjx51RMl2wU2ZAADYkbe3t+655x598cUX8vf3V2hoqJYsWaKsrCy1a9fuktssXrxYQUFBql69utzd3bV+/Xr5+PgoJCTEwdUXH4ECAGBXxZloytVceNxzypQpOn36tG666SaNGDHisnNP+Pj4aNGiRTpy5IhMJpOqV6+uESNGWB9DLQ1Mubm5FmcXUdpc+LTR9CdGXPM20V9OulHlOASfzuja6Ne13ah+U1JSrngK31n4tFFjrvS6Xunjy7mHAgAAGEagAAAAhhEoAACAYQQKAABgGIECAAAYRqAAAACGESgAAIBhBAoAAGAYgQIAABhGoAAA4ArmzJmjYcOGXfP4Ll26aOPGjYbHlDZ8locBHYM6XvvgIStuXCEOsGz4rbr15Q3OLsNhrrffvye3v4HVAKWL5zsxDj3euRd3Xfc2iYmJWrdunVq3bq3BgwfbrPv888+1aNEiNWrUSMOHD1fnzp0VHx9vr3IlSdOmTZOfn59d9+lsnKEAAJRJISEh+vnnn5WXl2ddZjab9eOPP6pixYrWZT4+Pnb/LJSgoCB5enradZ/OxhkKAECZFBUVpczMTG3cuFF33XWXJGnz5s3y9PRU3bp1lZOTI+n8JY9NmzZpwoQJ1m3Xrl1r/XTQ8uXL6+abb9ZTTz1lXX/q1CmNHz9ef/75pwIDA9WtWze1aNHCur5Lly4aNmyYmjZtKknavXu3pk+frpSUFEVERKhHjx4aM2aMEhISFBcXJ7PZrKlTp2r79u3KyspSSEiI2rZtq86dO1v3mZiYqJycHDVo0EDffvut8vPzddttt+nxxx93yKeWEigAAGVW69at9cMPP1gDxYWv09LSLrvNd999p08++UQ9evRQo0aNlJeXp+3bt9uMmTt3rh555BH17NlTP/zwg6ZMmaLY2FhVqlSpyP5yc3M1ZswYNWjQQEOHDlVGRoZmzpxpM8ZisSg4OFjDhg1TQECA9uzZo6lTp8rPz0+tWrWyjtu5c6eCgoL06quv6sSJE5owYYKqVKmiBx54oPg/pGvEJQ8AQJl15513au/evTpy5IgyMzO1ZcsWmzfoS5k7d646dOigzp07KyIiQjVr1tR9991nM6ZFixZq0aKFKleurO7du8vd3V07d+685P5++uknFRYWavDgwapataoaNmyoBx980GaMh4eHunfvrujoaIWGhupf//qX7r77bm3YYHuvl6+vrwYMGKDIyEg1bNhQTZs21bZt267/B1MMnKEAAJRZfn5+atKkiX744QeVL19ecXFxlzyLcEF2drYyMjJUv379K+43KirK+rW7u7sCAgKUnZ19ybGpqamqVq2azWWJWrVqFRm3atUqrV69WseOHVN+fr7MZnORWiMjI+Xu7m79PigoSLt3775irfZCoAAAlGmtW7dWYmKivL291a1btyuOtVgs17TPi9/UJclkMl1222vZ54YNGzRz5kz17t1btWvXlo+Pj1auXKlff/212Me1Ny55AADKtPr168vDw0M5OTlq0qTJFcdWqFBBwcHBdr2MEBkZqYMHD+rs2bPWZXv27LEZk5ycrOjoaMXHx6tGjRqqXLmyjh49arca7IFAAQAo00wmk8aPH6/Jkydf06OcDz74oJYtW6YlS5bo8OHD2r9/vxYvXlzs4995551yc3PT1KlTdejQIW3dulXz58+3GVOlShXt379ff/75p44cOaK5c+dqx44dxT7mjcAlDwCAXRVnoiln8/Hxueax7dq1k4eHhxYvXqxZs2bJz89PjRo1MnTsl19+WdOnT9eLL76o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f79mzpypffv2SZLCw8P12GOPKTY29kb/GG4IAgUAABfJzc3Va6+9pgYNGmjUqFFyd3fXggUL9MYbb2jixIny9PTU0KFD9cILL2j58uWKj4/X9OnT5evrqx49ekg6/wmgoaGhat++vfz8/LR7925NnTpVgYGBat68uSRpwoQJqlOnjgYOHCg3Nzf997//laenpzNbN4RAAQDARX788Ud5e3vriSeesC4bPHiw+vXrpy1btui2225TpUqVNGDAAE2ePFmZmZn67bffNHbsWGsg8Pb2trlfIywsTLt379ZPP/2k5s2by2Kx6MSJE7r55psVEREhSapcubJjG7UzAgUAABfZu3evUlNT1atXL5vl+fn5SktLs37frFkz/fbbb1qwYIEee+wxVa1a1Wb88uXLtWbNGh0/flz5+fkym82qUqWKJMlkMqljx46aNGmSVq9erfr16+uOO+4o1aGCQAEAwEUsFotq1aqlIUOGFFkXEBBg/TovL0/79u2Tm5ubjhw5YjNu7dq1mjVrlvr27atatWrJ29tbS5cu1bZt26xjHnnkEbVq1Up//vmn/vrrL3399dcaMmSI9ZJIaUOgAADgIjVq1NAff/yhChUqyMfH57LjZs6cKTc3N40YMUJvvfWWGjVqpJtvvlmSlJycrNjYWN1zzz3W8f8MHZIUERGhiIgIderUSZMnT9bq1atLbaBgYisAAC7SsmVL+fj46J133tHOnTuVlpampKQkffzxxzp27Jgk6ddff9W6dev0zDPPqEGDBrr//vs1efJknTx5UtL5+yF2796tv/76S4cPH9ZXX32l3bt3W49x+vRpffzxx0pKStKxY8f0999/a9euXYqMjHRKz/bAGQoAgF1dz0RTJZGvr6/eeOMNzZo1S+PGjVNeXp6CgoJUv359+fr6KjMzUx9++KG6d++um266SdL5CbO2bt2qDz/8UC+++KLi4+N16NAhTZgwQSaTSU2bNlV8fLw2bdokSfLw8FB2drYmTZqk7Oxs+fv769Zbby1y30ZpYsrNzbU4u4jSJj09XZLttTRXl5OTI39/f2eX4TD069ro1z5SUlJK5G/UZrNZ7u7uzi7DYezd75VeV29v78tuxyUPAABgGIECAAAYRqAAAACGESgAAIBhBAoAQLFZLNzX70qMvJ4ECgBAsbi7uys/P9/ZZcCO8vPzi/3ECIECAFAs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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "## then make a horizontal bar chart here\n", + "unemp_count.T.plot.barh(figsize=(8,8))\n", + "unemp_count.plot.barh(figsize=(8,8))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "5. **(Challenging) Repeat the previous step, but count how many states had each classification in each month. Which month had the most states with high unemployment? What about medium and low?** " + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The month with high unemployment is 2009-04-01 00:00:00.\n", + "The month with medium unemployment is 2001-09-01 00:00:00.\n", + "The month with low unemployment is 2000-08-01 00:00:00.\n" + ] + } + ], + "source": [ + "# Part 4: Apply the same transform from part 4, but to each date instead of to each state.\n", + "\n", + "#a solution based on this lecture has not been found :p\n", + "#alternative solution: we transpose the previous table in order to be able to apply the same function as before \n", + " #for more informtion on reshaping the DataFrames, check Lecture 6\n", + "unemp_binsT = unemp_bins.T\n", + "unemp_binsT\n", + "\n", + "#we call the function previously created for the transposed DataFrame\n", + "unemp_countT = unemp_binsT.apply(count_bins)\n", + "unemp_countT.T.head()\n", + "\n", + "#we create a for loop to answer the question\n", + "times = [\"high\", \"medium\", \"low\"]\n", + "\n", + "for x in times:\n", + " m=unemp_countT.T[x].idxmax()\n", + " \n", + " print(f\"The month with {x} unemployment is {m}.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **For a single state of your choice, determine what the mean unemployment is during \"Low\", \"Medium\", and \"High\" unemployment times (recall your `unemp_bins` DataFrame from the exercise above).**\n", + " - Think about how you would do this for all the states in our sample and write your thoughts... We will soon learn tools that will *greatly* simplify operations like this that operate on distinct *groups* of data at a time. " + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "During high unemployment times, the mean unemployment in Arizona is 8.73333333333333.\n", + "During medium unemployment times, the mean unemployment in Arizona is 5.436082474226807.\n", + "During low unemployment times, the mean unemployment in Arizona is 4.0636363636363635.\n" + ] + } + ], + "source": [ + "#The analysis is performed on Arizona\n", + "\n", + "times = [\"high\", \"medium\", \"low\"]\n", + "\n", + "for x in times:\n", + " Arizona_x = unemp[\"Arizona\"].loc[unemp_bins[\"Arizona\"]==x].mean()\n", + "\n", + " print(f\"During {x} unemployment times, the mean unemployment in Arizona is {Arizona_x}.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Arizona_Bins\n", + "high 8.733333\n", + "low 4.063636\n", + "medium 5.436082\n", + "Name: Arizona_Values, dtype: float64" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Alternative solution:\n", + "\n", + "# I chose Arizona. I extract both values and bin series, rename them and concatenate it into an new data frame.\n", + "Arizona_bins=pd.Series(unemp_bins['Arizona'], name='Arizona_Bins')\n", + "Arizona_val=pd.Series(unemp['Arizona'], name='Arizona_Values')\n", + "Arizona_valbins = pd.concat([Arizona_bins, Arizona_val], axis=1)\n", + "Arizona_valbins.head()\n", + "Arizona_valbins.groupby('Arizona_Bins')['Arizona_Values'].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Arizona - high: 8.73333333333333.\n", + "Arizona - medium: 5.436082474226807.\n", + "Arizona - low: 4.0636363636363635.\n", + "California - high: 9.249056603773582.\n", + "California - medium: 5.454716981132074.\n", + "California - low: 4.5.\n", + "Florida - high: 9.155882352941177.\n", + "Florida - medium: 5.331645569620254.\n", + "Florida - low: 3.807246376811594.\n", + "Illinois - high: 8.740659340659343.\n", + "Illinois - medium: 5.618867924528302.\n", + "Illinois - low: 4.35263157894737.\n", + "Michigan - high: 8.76267605633803.\n", + "Michigan - medium: 5.4070175438596495.\n", + "Michigan - low: 3.8764705882352946.\n", + "New York - high: 8.16923076923077.\n", + "New York - medium: 5.3612403100775206.\n", + "New York - low: 4.340909090909091.\n", + "Texas - high: 7.552941176470585.\n", + "Texas - medium: 5.567289719626171.\n", + "Texas - low: 4.298275862068967.\n" + ] + } + ], + "source": [ + "#Now, we perform the same analysis on all countries\n", + "\n", + "states = [\"Arizona\", \"California\", \"Florida\", \"Illinois\",\n", + " \"Michigan\", \"New York\", \"Texas\"]\n", + "\n", + "for y in states:\n", + " for x in times:\n", + " y_x = unemp[y].loc[unemp_bins[y]==x].mean()\n", + "\n", + " print(f\"{y} - {x}: {y_x}.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Which states in our sample performs the best during \"bad times?\" To determine this, compute the mean unemployment for each state only for months in which the mean unemployment rate in our sample is greater than 7.** " + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "state\n", + "Texas 7.972727\n", + "dtype: float64" + ] + }, + "execution_count": 112, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Between bracket, the condition that the value is greater than 7\n", + "df=unemp[unemp>7].mean()\n", + "df=df.loc[df==min(df)]\n", + "df\n", + "# There must be a way to be more concise" + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Arizona: 9.038461538461535\n", + "California: 10.234210526315788\n", + "Florida: 9.568965517241377\n", + "Illinois: 9.423529411764704\n", + "Michigan: 9.465384615384618\n", + "New York: 8.286666666666667\n", + "Texas: 7.972727272727272\n" + ] + } + ], + "source": [ + "#Alternative solution\n", + "def unemployment_levels2(ul2):\n", + " if ul2 > 7:\n", + " return \"High\"\n", + " else:\n", + " return \"Low\"\n", + " \n", + " return ul2\n", + "\n", + "unemp_bins2 = unemp.applymap(unemployment_levels2)\n", + "\n", + "for s in states:\n", + " s_high = unemp[s].loc[unemp_bins2[s]==\"High\"].mean()\n", + " \n", + " print(f\"{s}: {s_high}\")\n", + " \n", + "#The 3 states that perform the best during high unemployment times (>7) are, in ascending order, Texas, New York, Arizona" + ] + } + ], + "metadata": { + "date": 1584040758.8912327, + "filename": "basics.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "Basic Functionality" + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Session_7/3_the_index.ipynb b/Session_7/3_the_index.ipynb new file mode 100644 index 0000000..ebcf492 --- /dev/null +++ b/Session_7/3_the_index.ipynb @@ -0,0 +1,3919 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The Index\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [Introduction to pandas](https://datascience.quantecon.org/intro.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Understand how the index is used to align data \n", + "- Know how to set and reset the index \n", + "- Understand how to select subsets of data by slicing on index and columns \n", + "- Understand that for DataFrames, the column names also align data " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [The Index](#The-Index) \n", + " - [So What is this Index?](#So-What-is-this-Index?) \n", + " - [Setting the Index](#Setting-the-Index) \n", + " - [Re-setting the Index](#Re-setting-the-Index) \n", + " - [Choose the Index Carefully](#Choose-the-Index-Carefully) \n", + " - [Exercises](#Exercises) " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (1.12.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: python-dateutil in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (2.8.0)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n" + ] + } + ], + "source": [ + "# Uncomment following line to install on colab\n", + "! pip install qeds" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## So What is this Index?\n", + "\n", + "Every Series or DataFrame has an index.\n", + "\n", + "We told you that the index was the “row labels” for the data.\n", + "\n", + "This is true, but an index in pandas does much more than label the rows.\n", + "\n", + "The purpose of this lecture is to understand the importance of the index.\n", + "\n", + "The [pandas\n", + "documentation](https://pandas.pydata.org/pandas-docs/stable/dsintro.html)\n", + "says\n", + "\n", + "> Data alignment is intrinsic. The link between labels and data will\n", + "not be broken unless done so explicitly by you.\n", + "\n", + "\n", + "In practice, the index and column names are used to make sure the data is\n", + "properly aligned when operating on multiple DataFrames.\n", + "\n", + "This is a somewhat abstract concept that is best understood by\n", + "example…\n", + "\n", + "Let’s begin by loading some data on GDP components that we collected from\n", + "the World Bank’s World Development Indicators Dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 72 entries, 0 to 71\n", + "Data columns (total 7 columns):\n", + "country 72 non-null object\n", + "year 72 non-null int64\n", + "GovExpend 72 non-null float64\n", + "Consumption 72 non-null float64\n", + "Exports 72 non-null float64\n", + "Imports 72 non-null float64\n", + "GDP 72 non-null float64\n", + "dtypes: float64(5), int64(1), object(1)\n", + "memory usage: 4.1+ KB\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryyearGovExpendConsumptionExportsImportsGDP
0Canada20170.3726651.0954750.5828310.6000311.868164
1Canada20160.3648991.0584260.5763940.5757751.814016
2Canada20150.3583031.0352080.5688590.5757931.794270
3Canada20140.3534851.0119880.5503230.5723441.782252
4Canada20130.3515410.9864000.5180400.5586361.732714
\n", + "
" + ], + "text/plain": [ + " country year GovExpend Consumption Exports Imports GDP\n", + "0 Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "1 Canada 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "2 Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "3 Canada 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "4 Canada 2013 0.351541 0.986400 0.518040 0.558636 1.732714" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = \"https://datascience.quantecon.org/assets/data/wdi_data.csv\"\n", + "df = pd.read_csv(url)\n", + "df.info()\n", + "\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We’ll also extract a couple smaller DataFrames we can use in examples." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryyearGovExpendConsumptionExportsImportsGDP
0Canada20170.3726651.0954750.5828310.6000311.868164
1Canada20160.3648991.0584260.5763940.5757751.814016
2Canada20150.3583031.0352080.5688590.5757931.794270
3Canada20140.3534851.0119880.5503230.5723441.782252
4Canada20130.3515410.9864000.5180400.5586361.732714
\n", + "
" + ], + "text/plain": [ + " country year GovExpend Consumption Exports Imports GDP\n", + "0 Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "1 Canada 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "2 Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "3 Canada 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "4 Canada 2013 0.351541 0.986400 0.518040 0.558636 1.732714" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_small = df.head(5)\n", + "df_small" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryyearGovExpendConsumptionExportsImportsGDP
0Canada20170.3726651.0954750.5828310.6000311.868164
3Canada20140.3534851.0119880.5503230.5723441.782252
2Canada20150.3583031.0352080.5688590.5757931.794270
4Canada20130.3515410.9864000.5180400.5586361.732714
\n", + "
" + ], + "text/plain": [ + " country year GovExpend Consumption Exports Imports GDP\n", + "0 Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "3 Canada 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "2 Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "4 Canada 2013 0.351541 0.986400 0.518040 0.558636 1.732714" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_tiny = df.iloc[[0, 3, 2, 4], :]\n", + "df_tiny" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ImportsExports
00.6000310.582831
10.5757750.576394
20.5757930.568859
30.5723440.550323
40.5586360.518040
\n", + "
" + ], + "text/plain": [ + " Imports Exports\n", + "0 0.600031 0.582831\n", + "1 0.575775 0.576394\n", + "2 0.575793 0.568859\n", + "3 0.572344 0.550323\n", + "4 0.558636 0.518040" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "im_ex = df_small[[\"Imports\", \"Exports\"]]\n", + "im_ex_copy = im_ex.copy()\n", + "im_ex_copy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Observe what happens when we evaluate `im_ex + im_ex_copy`." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ImportsExports
01.2000631.165661
11.1515501.152787
21.1515851.137718
31.1446881.100646
41.1172721.036081
\n", + "
" + ], + "text/plain": [ + " Imports Exports\n", + "0 1.200063 1.165661\n", + "1 1.151550 1.152787\n", + "2 1.151585 1.137718\n", + "3 1.144688 1.100646\n", + "4 1.117272 1.036081" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "im_ex + im_ex_copy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that this operated *elementwise*, meaning that the `+`\n", + "operation was applied to each element of `im_ex` and the corresponding\n", + "element of `im_ex_copy`.\n", + "\n", + "Let’s take a closer look at `df_tiny`:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryyearGovExpendConsumptionExportsImportsGDP
0Canada20170.3726651.0954750.5828310.6000311.868164
3Canada20140.3534851.0119880.5503230.5723441.782252
2Canada20150.3583031.0352080.5688590.5757931.794270
4Canada20130.3515410.9864000.5180400.5586361.732714
\n", + "
" + ], + "text/plain": [ + " country year GovExpend Consumption Exports Imports GDP\n", + "0 Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "3 Canada 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "2 Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "4 Canada 2013 0.351541 0.986400 0.518040 0.558636 1.732714" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_tiny" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Relative to `im_ex` notice a few things:\n", + "\n", + "- The row labeled `1` appears in `im_ex` but not `df_tiny`. \n", + "- For row labels that appear in both, they are not in the same position\n", + " within each DataFrame. \n", + "- Certain columns appear only in `df_tiny`. \n", + "- The `Imports` and `Exports` columns are the 6th and 5th columns of\n", + " `df_tiny` and the 1st and 2nd of `im_ex`, respectively. \n", + "\n", + "\n", + "Now, let’s see what happens when we try `df_tiny + im_ex`." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ConsumptionExportsGDPGovExpendImportscountryyear
0NaN1.165661NaNNaN1.200063NaNNaN
1NaNNaNNaNNaNNaNNaNNaN
2NaN1.137718NaNNaN1.151585NaNNaN
3NaN1.100646NaNNaN1.144688NaNNaN
4NaN1.036081NaNNaN1.117272NaNNaN
\n", + "
" + ], + "text/plain": [ + " Consumption Exports GDP GovExpend Imports country year\n", + "0 NaN 1.165661 NaN NaN 1.200063 NaN NaN\n", + "1 NaN NaN NaN NaN NaN NaN NaN\n", + "2 NaN 1.137718 NaN NaN 1.151585 NaN NaN\n", + "3 NaN 1.100646 NaN NaN 1.144688 NaN NaN\n", + "4 NaN 1.036081 NaN NaN 1.117272 NaN NaN" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "im_ex_tiny = df_tiny + im_ex\n", + "im_ex_tiny" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Whoa, a lot happened! Let’s break it down." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Automatic Alignment\n", + "\n", + "For all (row, column) combinations that appear in both DataFrames (e.g.\n", + "rows `[1, 3]` and columns `[Imports, Exports]`), the value of `im_ex_tiny`\n", + "is equal to `df_tiny.loc[row, col] + im_ex.loc[row, col]`.\n", + "\n", + "This happened even though the rows and columns were not in the same\n", + "order.\n", + "\n", + "We refer to this as pandas *aligning* the data for us.\n", + "\n", + "To see how awesome this is, think about how to do something similar in\n", + "Excel:\n", + "\n", + "- `df_tiny` and `im_ex` would be in different sheets. \n", + "- The index and column names would be the first column and row in each\n", + " sheet. \n", + "- We would have a third sheet to hold the sum. \n", + "- For each label in the first row and column of *either* the `df_tiny`\n", + " sheet or the `im_ex` sheet we would have to do a `IFELSE` to check\n", + " if the label exists in the other sheet and then a `VLOOKUP` to\n", + " extract the value. \n", + "\n", + "\n", + "In pandas, this happens automatically, behind the scenes, and *very\n", + "quickly*." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Handling Missing Data\n", + "\n", + "For all elements in row `1` or columns\n", + "`[\"country\", \"year\", \"GovExpend\", \"Consumption\", \"GDP\"]`,\n", + "the value in `im_ex_tiny` is `NaN`.\n", + "\n", + "This is how pandas represents *missing data*.\n", + "\n", + "So, when pandas was trying to look up the values in `df_tiny` and `im_ex`, it could\n", + "only find a value in one DataFrame: the other value was missing.\n", + "\n", + "When pandas tries to add a number to something that is missing, it says\n", + "that the result is missing (spelled `NaN`)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting the Index\n", + "\n", + "For a DataFrame `df`, the `df.set_index` method allows us to use one\n", + "(or more) of the DataFrame’s columns as the index.\n", + "\n", + "Here’s an example." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryGovExpendConsumptionExportsImportsGDP
year
2017Canada0.3726651.0954750.5828310.6000311.868164
2016Canada0.3648991.0584260.5763940.5757751.814016
2015Canada0.3583031.0352080.5688590.5757931.794270
2014Canada0.3534851.0119880.5503230.5723441.782252
2013Canada0.3515410.9864000.5180400.5586361.732714
\n", + "
" + ], + "text/plain": [ + " country GovExpend Consumption Exports Imports GDP\n", + "year \n", + "2017 Canada 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "2016 Canada 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "2015 Canada 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "2014 Canada 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "2013 Canada 0.351541 0.986400 0.518040 0.558636 1.732714" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# first, create the DataFrame\n", + "df_year = df.set_index([\"year\"])\n", + "df_year.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the year is on the index, we can use `.loc` to extract all the\n", + "data for a specific year." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryGovExpendConsumptionExportsImportsGDP
year
2010Canada0.3473320.9219520.4699490.5003411.613543
2010Germany0.6533861.9154811.4437351.2661263.417095
2010United Kingdom0.5211461.5985630.6908240.7450652.452900
2010United States2.51014310.1858361.8462802.36018314.992053
\n", + "
" + ], + "text/plain": [ + " country GovExpend Consumption Exports Imports GDP\n", + "year \n", + "2010 Canada 0.347332 0.921952 0.469949 0.500341 1.613543\n", + "2010 Germany 0.653386 1.915481 1.443735 1.266126 3.417095\n", + "2010 United Kingdom 0.521146 1.598563 0.690824 0.745065 2.452900\n", + "2010 United States 2.510143 10.185836 1.846280 2.360183 14.992053" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_year.loc[2010]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This would be helpful, for example, if we wanted to compute the difference\n", + "in the average of all our variables from one year to the next." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "GovExpend 0.033317\n", + "Consumption -0.042998\n", + "Exports -0.121425\n", + "Imports -0.140042\n", + "GDP -0.182610\n", + "dtype: float64" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_year.loc[2009].mean() - df_year.loc[2008].mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that pandas did a few things for us.\n", + "\n", + "- After computing `.mean()`, the row labels (index) were the former column names. \n", + "- These column names were used to align data when we wanted asked pandas to\n", + " compute the difference. \n", + "\n", + "\n", + "Suppose that someone asked you, “What was the GDP in the US in 2010?”\n", + "\n", + "To compute that using `df_year` you might do something like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "14.992052727" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_year.loc[df_year[\"country\"] == \"United States\", \"GDP\"].loc[2010]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That was a lot of work!\n", + "\n", + "Now, suppose that after seeing you extract that data, your friend asks you\n", + "“What about GDP in Germany and the UK in 2010?”\n", + "\n", + "To answer that question, you might write." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "year\n", + "2010 3.417095\n", + "2010 2.452900\n", + "Name: GDP, dtype: float64" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_year.loc[df_year[\"country\"].isin([\"United Kingdom\", \"Germany\"]), \"GDP\"].loc[2010]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that this code is similar to the code above, but now provides a result\n", + "that is ambiguous.\n", + "\n", + "The two elements in the series both have with label 2010.\n", + "\n", + "How do we know which is which?\n", + "\n", + "We might think that the first value corresponds to the United Kingdom because\n", + "that is what we listed first in the call to `isin`, but we would be wrong!\n", + "\n", + "Let’s check." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryGovExpendConsumptionExportsImportsGDP
year
2010Canada0.3473320.9219520.4699490.5003411.613543
2010Germany0.6533861.9154811.4437351.2661263.417095
2010United Kingdom0.5211461.5985630.6908240.7450652.452900
2010United States2.51014310.1858361.8462802.36018314.992053
\n", + "
" + ], + "text/plain": [ + " country GovExpend Consumption Exports Imports GDP\n", + "year \n", + "2010 Canada 0.347332 0.921952 0.469949 0.500341 1.613543\n", + "2010 Germany 0.653386 1.915481 1.443735 1.266126 3.417095\n", + "2010 United Kingdom 0.521146 1.598563 0.690824 0.745065 2.452900\n", + "2010 United States 2.510143 10.185836 1.846280 2.360183 14.992053" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_year.loc[2010]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting just the year as index has one more potential issue: we will\n", + "get data alignment only on the year, which may not be sufficient.\n", + "\n", + "To demonstrate this point, suppose now you are asked to use our WDI dataset\n", + "to compute an approximation for net exports and investment in in 2009.\n", + "\n", + "As a seasoned economist, you would remember the expenditure formula for GDP is\n", + "written\n", + "\n", + "$$\n", + "GDP = Consumption + Investment + GovExpend + Net Exports\n", + "$$\n", + "\n", + "which we can rearrange to compute investment as a function of the variables in\n", + "our DataFrame…\n", + "\n", + "$$\n", + "Investment = GDP - Consumption - GovExpend - Net Exports\n", + "$$\n", + "\n", + "Note that we can compute NetExports as `Exports - Imports`." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "year\n", + "2017 -0.017201\n", + "2016 0.000619\n", + "2015 -0.006934\n", + "2014 -0.022021\n", + "2013 -0.040596\n", + "2012 -0.041787\n", + "2011 -0.035878\n", + "2010 -0.030393\n", + "2009 0.000896\n", + "2008 0.004068\n", + "2007 0.032451\n", + "2006 0.053530\n", + "2005 0.072729\n", + "2004 0.091902\n", + "2003 0.097794\n", + "2002 0.121850\n", + "2001 0.122673\n", + "2000 0.118702\n", + "2017 0.264214\n", + "dtype: float64" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nx = df_year[\"Exports\"] - df_year[\"Imports\"]\n", + "nx.head(19)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, suppose that we accidentally had a bug in our code that swapped\n", + "the data for Canada and Germany’s net exports in 2017.\n", + "\n", + ">**Note**\n", + ">\n", + ">This example is contrived, but if you were getting unclean data from\n", + "some resource or doing more complicated operations, this type of mistake\n", + "becomes increasingly likely." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "year\n", + "2017 0.264214\n", + "2016 0.000619\n", + "2015 -0.006934\n", + "2014 -0.022021\n", + "2013 -0.040596\n", + "2012 -0.041787\n", + "2011 -0.035878\n", + "2010 -0.030393\n", + "2009 0.000896\n", + "2008 0.004068\n", + "2007 0.032451\n", + "2006 0.053530\n", + "2005 0.072729\n", + "2004 0.091902\n", + "2003 0.097794\n", + "2002 0.121850\n", + "2001 0.122673\n", + "2000 0.118702\n", + "2017 -0.017201\n", + "dtype: float64" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ca17 = nx.iloc[[0]]\n", + "g17 = nx.iloc[[18]]\n", + "nx.iloc[[0]] = g17\n", + "nx.iloc[[18]] = ca17\n", + "\n", + "nx.head(19)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that if we now add `nx` to the DataFrame and compute investment\n", + "pandas doesn’t complain." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryGovExpendConsumptionExportsImportsGDPNetExportsInvestment
year
2017Canada0.3726651.0954750.5828310.6000311.8681640.2642140.135811
2016Canada0.3648991.0584260.5763940.5757751.8140160.0006190.390072
2015Canada0.3583031.0352080.5688590.5757931.794270-0.0069340.407692
2014Canada0.3534851.0119880.5503230.5723441.782252-0.0220210.438800
2013Canada0.3515410.9864000.5180400.5586361.732714-0.0405960.435369
2012Canada0.3543420.9612260.5059690.5477561.693428-0.0417870.419647
2011Canada0.3518870.9431450.4923490.5282271.664240-0.0358780.405086
2010Canada0.3473320.9219520.4699490.5003411.613543-0.0303930.374652
2009Canada0.3396860.8900780.4406920.4397961.5652910.0008960.334631
2008Canada0.3307660.8896020.5063500.5022811.6128620.0040680.388425
2007Canada0.3187770.8640120.5304530.4980021.5968760.0324510.381636
2006Canada0.3113820.8276430.5244610.4709311.5646080.0535300.372053
2005Canada0.3030430.7943900.5199500.4472221.5246080.0727290.354447
2004Canada0.2998540.7643570.5086570.4167541.4773170.0919020.321203
2003Canada0.2943350.7417960.4819930.3841991.4330890.0977940.299164
2002Canada0.2860940.7219740.4904650.3686151.4077250.1218500.277806
2001Canada0.2797670.6942300.4846960.3620231.3665900.1226730.269921
2000Canada0.2705530.6777130.4995260.3808231.3428050.1187020.275837
2017Germany0.7455792.1120091.9305631.6663483.883870-0.0172011.043482
\n", + "
" + ], + "text/plain": [ + " country GovExpend Consumption Exports Imports GDP \\\n", + "year \n", + "2017 Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "2016 Canada 0.364899 1.058426 0.576394 0.575775 1.814016 \n", + "2015 Canada 0.358303 1.035208 0.568859 0.575793 1.794270 \n", + "2014 Canada 0.353485 1.011988 0.550323 0.572344 1.782252 \n", + "2013 Canada 0.351541 0.986400 0.518040 0.558636 1.732714 \n", + "2012 Canada 0.354342 0.961226 0.505969 0.547756 1.693428 \n", + "2011 Canada 0.351887 0.943145 0.492349 0.528227 1.664240 \n", + "2010 Canada 0.347332 0.921952 0.469949 0.500341 1.613543 \n", + "2009 Canada 0.339686 0.890078 0.440692 0.439796 1.565291 \n", + "2008 Canada 0.330766 0.889602 0.506350 0.502281 1.612862 \n", + "2007 Canada 0.318777 0.864012 0.530453 0.498002 1.596876 \n", + "2006 Canada 0.311382 0.827643 0.524461 0.470931 1.564608 \n", + "2005 Canada 0.303043 0.794390 0.519950 0.447222 1.524608 \n", + "2004 Canada 0.299854 0.764357 0.508657 0.416754 1.477317 \n", + "2003 Canada 0.294335 0.741796 0.481993 0.384199 1.433089 \n", + "2002 Canada 0.286094 0.721974 0.490465 0.368615 1.407725 \n", + "2001 Canada 0.279767 0.694230 0.484696 0.362023 1.366590 \n", + "2000 Canada 0.270553 0.677713 0.499526 0.380823 1.342805 \n", + "2017 Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "\n", + " NetExports Investment \n", + "year \n", + "2017 0.264214 0.135811 \n", + "2016 0.000619 0.390072 \n", + "2015 -0.006934 0.407692 \n", + "2014 -0.022021 0.438800 \n", + "2013 -0.040596 0.435369 \n", + "2012 -0.041787 0.419647 \n", + "2011 -0.035878 0.405086 \n", + "2010 -0.030393 0.374652 \n", + "2009 0.000896 0.334631 \n", + "2008 0.004068 0.388425 \n", + "2007 0.032451 0.381636 \n", + "2006 0.053530 0.372053 \n", + "2005 0.072729 0.354447 \n", + "2004 0.091902 0.321203 \n", + "2003 0.097794 0.299164 \n", + "2002 0.121850 0.277806 \n", + "2001 0.122673 0.269921 \n", + "2000 0.118702 0.275837 \n", + "2017 -0.017201 1.043482 " + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_year[\"NetExports\"] = nx\n", + "df_year[\"Investment\"] = df_year.eval(\"GDP - Consumption - GovExpend - NetExports\")\n", + "df_year.head(19)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Because we didn’t also have data alignment on the country, we would have overstated Canada’s investment by 281 billion USD and understated Germany’s by the\n", + "same amount.\n", + "\n", + "To make these types operation easier, we need to include both the year\n", + "and country in the index…" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Setting a Hierarchical Index\n", + "\n", + "Include multiple columns in the index is advantageous in some situations.\n", + "\n", + "These situations might include:\n", + "\n", + "- When we need more than one piece of information (column) to identify an\n", + " observation (as in the Germany and UK GDP example above) \n", + "- When we need data-alignment by more than one column \n", + "\n", + "\n", + "To achieve multiple columns in the index, we pass a list of multiple column\n", + "names to `set_index`." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20170.3726651.0954750.5828310.6000311.868164
20160.3648991.0584260.5763940.5757751.814016
20150.3583031.0352080.5688590.5757931.794270
20140.3534851.0119880.5503230.5723441.782252
20130.3515410.9864000.5180400.5586361.732714
20120.3543420.9612260.5059690.5477561.693428
20110.3518870.9431450.4923490.5282271.664240
20100.3473320.9219520.4699490.5003411.613543
20090.3396860.8900780.4406920.4397961.565291
20080.3307660.8896020.5063500.5022811.612862
20070.3187770.8640120.5304530.4980021.596876
20060.3113820.8276430.5244610.4709311.564608
20050.3030430.7943900.5199500.4472221.524608
20040.2998540.7643570.5086570.4167541.477317
20030.2943350.7417960.4819930.3841991.433089
20020.2860940.7219740.4904650.3686151.407725
20010.2797670.6942300.4846960.3620231.366590
20000.2705530.6777130.4995260.3808231.342805
Germany20170.7455792.1120091.9305631.6663483.883870
20160.7340142.0756151.8449491.5894953.801859
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + " 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + " 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + " 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + " 2013 0.351541 0.986400 0.518040 0.558636 1.732714\n", + " 2012 0.354342 0.961226 0.505969 0.547756 1.693428\n", + " 2011 0.351887 0.943145 0.492349 0.528227 1.664240\n", + " 2010 0.347332 0.921952 0.469949 0.500341 1.613543\n", + " 2009 0.339686 0.890078 0.440692 0.439796 1.565291\n", + " 2008 0.330766 0.889602 0.506350 0.502281 1.612862\n", + " 2007 0.318777 0.864012 0.530453 0.498002 1.596876\n", + " 2006 0.311382 0.827643 0.524461 0.470931 1.564608\n", + " 2005 0.303043 0.794390 0.519950 0.447222 1.524608\n", + " 2004 0.299854 0.764357 0.508657 0.416754 1.477317\n", + " 2003 0.294335 0.741796 0.481993 0.384199 1.433089\n", + " 2002 0.286094 0.721974 0.490465 0.368615 1.407725\n", + " 2001 0.279767 0.694230 0.484696 0.362023 1.366590\n", + " 2000 0.270553 0.677713 0.499526 0.380823 1.342805\n", + "Germany 2017 0.745579 2.112009 1.930563 1.666348 3.883870\n", + " 2016 0.734014 2.075615 1.844949 1.589495 3.801859" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi = df.set_index([\"country\", \"year\"])\n", + "wdi.head(20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that in the display above, the row labels seem to have two\n", + "*levels* now.\n", + "\n", + "The *outer* (or left-most) level is named `country` and the *inner* (or\n", + "right-most) level is named `year`.\n", + "\n", + "When a DataFrame’s index has multiple levels, we (and the pandas documentation)\n", + "refer to the DataFrame as having a hierarchical index." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Slicing a Hierarchical Index\n", + "\n", + "Now, we can answer our friend’s questions in a much more straightforward way." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "14.992052727" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[(\"United States\", 2010), \"GDP\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "country year\n", + "Germany 2010 3.417095\n", + "United Kingdom 2010 2.452900\n", + "Name: GDP, dtype: float64" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[([\"United Kingdom\", \"Germany\"], 2010), \"GDP\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As shown above, we can use `wdi.loc` to extract different slices of our\n", + "national accounts data.\n", + "\n", + "The rules for using `.loc` with a hierarchically-indexed DataFrame are\n", + "similar to the ones we’ve learned for standard DataFrames, but they are a bit\n", + "more elaborate as we now have more structure to our data.\n", + "\n", + "**Slicing rules**\n", + "\n", + "pandas slicing reacts differently to `list`s and `tuple`s.\n", + "\n", + "It does this to provide more flexibility to select the\n", + "data you want.\n", + "\n", + "`list` in row slicing will be an “or” operation, where it chooses rows\n", + "based on whether the index value corresponds to any element of the list.\n", + "\n", + "`tuple` in row slicing will be used to denote a single hierarchical\n", + "index and must include a value for each level.\n", + "\n", + "**Row slicing examples**\n", + "\n", + "1. `wdi.loc[\"United States\"]`: all rows where the *outer* most index value is\n", + " equal to `United States` \n", + "1. `wdi.loc[(\"United States\", 2010)]`: all rows where the *outer-most* index value\n", + " is equal to `\"United States` and the second level is equal to `2010` \n", + "1. `wdi.loc[[\"United States\", \"Canada\"]]`: all rows where the *outer-most* index is\n", + " either `\"United States\"` or `\"Canada\"` \n", + "1. `wdi.loc[([\"United States\", \"Canada\"], [2010, 2011]), :]`: all rows where the\n", + " *outer-most* index is either `\"United States` or `\"Canada\"` AND where the\n", + " second level index is either `2010` or `2011` \n", + "1. `wdi.loc[[(\"United States\", 2010), (\"Canada\", 2011)], :]`: all rows where the the\n", + " two hierarchical indices are either `(\"United States\", 2010)` or\n", + " `(\"Canada\", 2011)` \n", + "\n", + "\n", + "We can also restrict `.loc` to extract certain columns by doing:\n", + "\n", + "1. `wdi.loc[rows, GDP]`: return the rows specified by rows (see rules\n", + " above) and only column named `GDP` (returned object will be a\n", + " Series) \n", + "1. `df.loc[rows, [\"GDP\", \"Consumption\"]]`: return the rows specified by rows\n", + " (see rules above) and only columns `GDP` and `Consumption` " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Alignment with `MultiIndex`\n", + "\n", + "The data alignment features we talked about above also apply to a\n", + "`MultiIndex` DataFrame." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `pd.IndexSlice`\n", + "\n", + "When we want to extract rows for a few values of the outer index and all\n", + "values for an inner index level, we can use the convenient\n", + "`df.loc[[id11, id22]]` shorthand.\n", + "\n", + "We can use this notation to extract all the data for the United States and\n", + "Canada." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20170.3726651.0954750.5828310.6000311.868164
20160.3648991.0584260.5763940.5757751.814016
20150.3583031.0352080.5688590.5757931.794270
20140.3534851.0119880.5503230.5723441.782252
20130.3515410.9864000.5180400.5586361.732714
20120.3543420.9612260.5059690.5477561.693428
20110.3518870.9431450.4923490.5282271.664240
20100.3473320.9219520.4699490.5003411.613543
20090.3396860.8900780.4406920.4397961.565291
20080.3307660.8896020.5063500.5022811.612862
20070.3187770.8640120.5304530.4980021.596876
20060.3113820.8276430.5244610.4709311.564608
20050.3030430.7943900.5199500.4472221.524608
20040.2998540.7643570.5086570.4167541.477317
20030.2943350.7417960.4819930.3841991.433089
20020.2860940.7219740.4904650.3686151.407725
20010.2797670.6942300.4846960.3620231.366590
20000.2705530.6777130.4995260.3808231.342805
United States20172.40574312.0192662.2870713.06995417.348627
20162.40798111.7221332.2199372.93600416.972348
20152.37313011.4098002.2222282.88133716.710459
20142.33407111.0006192.2095552.73222816.242526
20132.35338110.6872142.1186392.60019815.853796
20122.39887310.5340422.0455092.56067715.567038
20112.43437810.3780601.9780832.49319415.224555
20102.51014310.1858361.8462802.36018314.992053
20092.50739010.0106871.6464322.08629914.617299
20082.40777110.1378471.7973472.40034914.997756
20072.35198710.1593871.7010962.45501615.018268
20062.3149579.9385031.5649202.39518914.741688
20052.2870229.6430981.4312052.24624614.332500
20042.2679999.3114311.3359782.10858513.846058
20032.2335198.9747081.2181991.89282513.339312
20022.1931888.6983061.1921801.80410512.968263
20012.1120388.4804611.2132531.74079712.746262
20002.0405008.2720971.2877391.79099512.620268
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + " 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + " 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + " 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + " 2013 0.351541 0.986400 0.518040 0.558636 1.732714\n", + " 2012 0.354342 0.961226 0.505969 0.547756 1.693428\n", + " 2011 0.351887 0.943145 0.492349 0.528227 1.664240\n", + " 2010 0.347332 0.921952 0.469949 0.500341 1.613543\n", + " 2009 0.339686 0.890078 0.440692 0.439796 1.565291\n", + " 2008 0.330766 0.889602 0.506350 0.502281 1.612862\n", + " 2007 0.318777 0.864012 0.530453 0.498002 1.596876\n", + " 2006 0.311382 0.827643 0.524461 0.470931 1.564608\n", + " 2005 0.303043 0.794390 0.519950 0.447222 1.524608\n", + " 2004 0.299854 0.764357 0.508657 0.416754 1.477317\n", + " 2003 0.294335 0.741796 0.481993 0.384199 1.433089\n", + " 2002 0.286094 0.721974 0.490465 0.368615 1.407725\n", + " 2001 0.279767 0.694230 0.484696 0.362023 1.366590\n", + " 2000 0.270553 0.677713 0.499526 0.380823 1.342805\n", + "United States 2017 2.405743 12.019266 2.287071 3.069954 17.348627\n", + " 2016 2.407981 11.722133 2.219937 2.936004 16.972348\n", + " 2015 2.373130 11.409800 2.222228 2.881337 16.710459\n", + " 2014 2.334071 11.000619 2.209555 2.732228 16.242526\n", + " 2013 2.353381 10.687214 2.118639 2.600198 15.853796\n", + " 2012 2.398873 10.534042 2.045509 2.560677 15.567038\n", + " 2011 2.434378 10.378060 1.978083 2.493194 15.224555\n", + " 2010 2.510143 10.185836 1.846280 2.360183 14.992053\n", + " 2009 2.507390 10.010687 1.646432 2.086299 14.617299\n", + " 2008 2.407771 10.137847 1.797347 2.400349 14.997756\n", + " 2007 2.351987 10.159387 1.701096 2.455016 15.018268\n", + " 2006 2.314957 9.938503 1.564920 2.395189 14.741688\n", + " 2005 2.287022 9.643098 1.431205 2.246246 14.332500\n", + " 2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + " 2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + " 2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + " 2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + " 2000 2.040500 8.272097 1.287739 1.790995 12.620268" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[[\"United States\", \"Canada\"]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, suppose we wanted to extract the data for all countries, but only the\n", + "years 2005, 2007, and 2009.\n", + "\n", + "We cannot do this using `wdi.loc` because the year is on the second level,\n", + "not outer-most level of our index.\n", + "\n", + "To get around this limitation, we can use the `pd.IndexSlice` helper.\n", + "\n", + "Here’s an example." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20090.3396860.8900780.4406920.4397961.565291
20070.3187770.8640120.5304530.4980021.596876
20050.3030430.7943900.5199500.4472221.524608
Germany20090.6450231.9083931.2605251.1219143.283144
20070.6056241.8942191.4424361.2138353.441356
20050.5911841.8662531.1752001.0280943.213777
United Kingdom20090.5197161.5871520.6538300.6890112.411632
20070.5045491.6447890.7102000.7676992.527327
20050.4908061.5789140.6400880.7159512.403352
United States20092.50739010.0106871.6464322.08629914.617299
20072.35198710.1593871.7010962.45501615.018268
20052.2870229.6430981.4312052.24624614.332500
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2009 0.339686 0.890078 0.440692 0.439796 1.565291\n", + " 2007 0.318777 0.864012 0.530453 0.498002 1.596876\n", + " 2005 0.303043 0.794390 0.519950 0.447222 1.524608\n", + "Germany 2009 0.645023 1.908393 1.260525 1.121914 3.283144\n", + " 2007 0.605624 1.894219 1.442436 1.213835 3.441356\n", + " 2005 0.591184 1.866253 1.175200 1.028094 3.213777\n", + "United Kingdom 2009 0.519716 1.587152 0.653830 0.689011 2.411632\n", + " 2007 0.504549 1.644789 0.710200 0.767699 2.527327\n", + " 2005 0.490806 1.578914 0.640088 0.715951 2.403352\n", + "United States 2009 2.507390 10.010687 1.646432 2.086299 14.617299\n", + " 2007 2.351987 10.159387 1.701096 2.455016 15.018268\n", + " 2005 2.287022 9.643098 1.431205 2.246246 14.332500" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[pd.IndexSlice[:, [2005, 2007, 2009]], :]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that the `:` in the first part of `[:, [\"A\", \"D\"]]`\n", + "instructed pandas to give us rows for all values of the outer most index\n", + "level and that the `:` just before `]` said grab all the columns." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Multi-index Columns\n", + "\n", + "The functionality of `MultiIndex` also applies to the column names.\n", + "\n", + "Let’s see how it works." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryCanada...United States
year2017201620152014201320122011201020092008...2009200820072006200520042003200220012000
GovExpend0.3726650.3648990.3583030.3534850.3515410.3543420.3518870.3473320.3396860.330766...2.5073902.4077712.3519872.3149572.2870222.2679992.2335192.1931882.1120382.040500
Consumption1.0954751.0584261.0352081.0119880.9864000.9612260.9431450.9219520.8900780.889602...10.01068710.13784710.1593879.9385039.6430989.3114318.9747088.6983068.4804618.272097
Exports0.5828310.5763940.5688590.5503230.5180400.5059690.4923490.4699490.4406920.506350...1.6464321.7973471.7010961.5649201.4312051.3359781.2181991.1921801.2132531.287739
Imports0.6000310.5757750.5757930.5723440.5586360.5477560.5282270.5003410.4397960.502281...2.0862992.4003492.4550162.3951892.2462462.1085851.8928251.8041051.7407971.790995
GDP1.8681641.8140161.7942701.7822521.7327141.6934281.6642401.6135431.5652911.612862...14.61729914.99775615.01826814.74168814.33250013.84605813.33931212.96826312.74626212.620268
\n", + "

5 rows × 72 columns

\n", + "
" + ], + "text/plain": [ + "country Canada \\\n", + "year 2017 2016 2015 2014 2013 2012 \n", + "GovExpend 0.372665 0.364899 0.358303 0.353485 0.351541 0.354342 \n", + "Consumption 1.095475 1.058426 1.035208 1.011988 0.986400 0.961226 \n", + "Exports 0.582831 0.576394 0.568859 0.550323 0.518040 0.505969 \n", + "Imports 0.600031 0.575775 0.575793 0.572344 0.558636 0.547756 \n", + "GDP 1.868164 1.814016 1.794270 1.782252 1.732714 1.693428 \n", + "\n", + "country ... United States \\\n", + "year 2011 2010 2009 2008 ... 2009 \n", + "GovExpend 0.351887 0.347332 0.339686 0.330766 ... 2.507390 \n", + "Consumption 0.943145 0.921952 0.890078 0.889602 ... 10.010687 \n", + "Exports 0.492349 0.469949 0.440692 0.506350 ... 1.646432 \n", + "Imports 0.528227 0.500341 0.439796 0.502281 ... 2.086299 \n", + "GDP 1.664240 1.613543 1.565291 1.612862 ... 14.617299 \n", + "\n", + "country \\\n", + "year 2008 2007 2006 2005 2004 2003 \n", + "GovExpend 2.407771 2.351987 2.314957 2.287022 2.267999 2.233519 \n", + "Consumption 10.137847 10.159387 9.938503 9.643098 9.311431 8.974708 \n", + "Exports 1.797347 1.701096 1.564920 1.431205 1.335978 1.218199 \n", + "Imports 2.400349 2.455016 2.395189 2.246246 2.108585 1.892825 \n", + "GDP 14.997756 15.018268 14.741688 14.332500 13.846058 13.339312 \n", + "\n", + "country \n", + "year 2002 2001 2000 \n", + "GovExpend 2.193188 2.112038 2.040500 \n", + "Consumption 8.698306 8.480461 8.272097 \n", + "Exports 1.192180 1.213253 1.287739 \n", + "Imports 1.804105 1.740797 1.790995 \n", + "GDP 12.968263 12.746262 12.620268 \n", + "\n", + "[5 rows x 72 columns]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdiT = wdi.T # .T means \"transpose\" or \"swap rows and columns\"\n", + "wdiT" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that `wdiT` seems to have two levels of names for the columns.\n", + "\n", + "The same logic laid out in the above row slicing rules applies when we\n", + "have a hierarchical index for column names." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
year201720162015201420132012201120102009200820072006200520042003200220012000
GovExpend2.4057432.4079812.3731302.3340712.3533812.3988732.4343782.5101432.5073902.4077712.3519872.3149572.2870222.2679992.2335192.1931882.1120382.040500
Consumption12.01926611.72213311.40980011.00061910.68721410.53404210.37806010.18583610.01068710.13784710.1593879.9385039.6430989.3114318.9747088.6983068.4804618.272097
Exports2.2870712.2199372.2222282.2095552.1186392.0455091.9780831.8462801.6464321.7973471.7010961.5649201.4312051.3359781.2181991.1921801.2132531.287739
Imports3.0699542.9360042.8813372.7322282.6001982.5606772.4931942.3601832.0862992.4003492.4550162.3951892.2462462.1085851.8928251.8041051.7407971.790995
GDP17.34862716.97234816.71045916.24252615.85379615.56703815.22455514.99205314.61729914.99775615.01826814.74168814.33250013.84605813.33931212.96826312.74626212.620268
\n", + "
" + ], + "text/plain": [ + "year 2017 2016 2015 2014 2013 2012 \\\n", + "GovExpend 2.405743 2.407981 2.373130 2.334071 2.353381 2.398873 \n", + "Consumption 12.019266 11.722133 11.409800 11.000619 10.687214 10.534042 \n", + "Exports 2.287071 2.219937 2.222228 2.209555 2.118639 2.045509 \n", + "Imports 3.069954 2.936004 2.881337 2.732228 2.600198 2.560677 \n", + "GDP 17.348627 16.972348 16.710459 16.242526 15.853796 15.567038 \n", + "\n", + "year 2011 2010 2009 2008 2007 2006 \\\n", + "GovExpend 2.434378 2.510143 2.507390 2.407771 2.351987 2.314957 \n", + "Consumption 10.378060 10.185836 10.010687 10.137847 10.159387 9.938503 \n", + "Exports 1.978083 1.846280 1.646432 1.797347 1.701096 1.564920 \n", + "Imports 2.493194 2.360183 2.086299 2.400349 2.455016 2.395189 \n", + "GDP 15.224555 14.992053 14.617299 14.997756 15.018268 14.741688 \n", + "\n", + "year 2005 2004 2003 2002 2001 2000 \n", + "GovExpend 2.287022 2.267999 2.233519 2.193188 2.112038 2.040500 \n", + "Consumption 9.643098 9.311431 8.974708 8.698306 8.480461 8.272097 \n", + "Exports 1.431205 1.335978 1.218199 1.192180 1.213253 1.287739 \n", + "Imports 2.246246 2.108585 1.892825 1.804105 1.740797 1.790995 \n", + "GDP 14.332500 13.846058 13.339312 12.968263 12.746262 12.620268 " + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdiT.loc[:, \"United States\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryCanada...United States
year2017201620152014201320122011201020092008...2009200820072006200520042003200220012000
GovExpend0.3726650.3648990.3583030.3534850.3515410.3543420.3518870.3473320.3396860.330766...2.5073902.4077712.3519872.3149572.2870222.2679992.2335192.1931882.1120382.040500
Consumption1.0954751.0584261.0352081.0119880.9864000.9612260.9431450.9219520.8900780.889602...10.01068710.13784710.1593879.9385039.6430989.3114318.9747088.6983068.4804618.272097
Exports0.5828310.5763940.5688590.5503230.5180400.5059690.4923490.4699490.4406920.506350...1.6464321.7973471.7010961.5649201.4312051.3359781.2181991.1921801.2132531.287739
Imports0.6000310.5757750.5757930.5723440.5586360.5477560.5282270.5003410.4397960.502281...2.0862992.4003492.4550162.3951892.2462462.1085851.8928251.8041051.7407971.790995
GDP1.8681641.8140161.7942701.7822521.7327141.6934281.6642401.6135431.5652911.612862...14.61729914.99775615.01826814.74168814.33250013.84605813.33931212.96826312.74626212.620268
\n", + "

5 rows × 36 columns

\n", + "
" + ], + "text/plain": [ + "country Canada \\\n", + "year 2017 2016 2015 2014 2013 2012 \n", + "GovExpend 0.372665 0.364899 0.358303 0.353485 0.351541 0.354342 \n", + "Consumption 1.095475 1.058426 1.035208 1.011988 0.986400 0.961226 \n", + "Exports 0.582831 0.576394 0.568859 0.550323 0.518040 0.505969 \n", + "Imports 0.600031 0.575775 0.575793 0.572344 0.558636 0.547756 \n", + "GDP 1.868164 1.814016 1.794270 1.782252 1.732714 1.693428 \n", + "\n", + "country ... United States \\\n", + "year 2011 2010 2009 2008 ... 2009 \n", + "GovExpend 0.351887 0.347332 0.339686 0.330766 ... 2.507390 \n", + "Consumption 0.943145 0.921952 0.890078 0.889602 ... 10.010687 \n", + "Exports 0.492349 0.469949 0.440692 0.506350 ... 1.646432 \n", + "Imports 0.528227 0.500341 0.439796 0.502281 ... 2.086299 \n", + "GDP 1.664240 1.613543 1.565291 1.612862 ... 14.617299 \n", + "\n", + "country \\\n", + "year 2008 2007 2006 2005 2004 2003 \n", + "GovExpend 2.407771 2.351987 2.314957 2.287022 2.267999 2.233519 \n", + "Consumption 10.137847 10.159387 9.938503 9.643098 9.311431 8.974708 \n", + "Exports 1.797347 1.701096 1.564920 1.431205 1.335978 1.218199 \n", + "Imports 2.400349 2.455016 2.395189 2.246246 2.108585 1.892825 \n", + "GDP 14.997756 15.018268 14.741688 14.332500 13.846058 13.339312 \n", + "\n", + "country \n", + "year 2002 2001 2000 \n", + "GovExpend 2.193188 2.112038 2.040500 \n", + "Consumption 8.698306 8.480461 8.272097 \n", + "Exports 1.192180 1.213253 1.287739 \n", + "Imports 1.804105 1.740797 1.790995 \n", + "GDP 12.968263 12.746262 12.620268 \n", + "\n", + "[5 rows x 36 columns]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdiT.loc[:, [\"United States\", \"Canada\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryCanadaUnited States
year20102010
GovExpend0.3473322.510143
Consumption0.92195210.185836
Exports0.4699491.846280
Imports0.5003412.360183
GDP1.61354314.992053
\n", + "
" + ], + "text/plain": [ + "country Canada United States\n", + "year 2010 2010\n", + "GovExpend 0.347332 2.510143\n", + "Consumption 0.921952 10.185836\n", + "Exports 0.469949 1.846280\n", + "Imports 0.500341 2.360183\n", + "GDP 1.613543 14.992053" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdiT.loc[:, ([\"United States\", \"Canada\"], 2010)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Re-setting the Index\n", + "\n", + "The `df.reset_index` method will move one or more level of the index\n", + "back into the DataFrame as a normal column.\n", + "\n", + "With no additional arguments, it moves all levels out of the index and\n", + "sets the index of the returned DataFrame to the default of\n", + "`range(df.shape[0])`." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryyearGovExpendConsumptionExportsImportsGDP
0Canada20170.3726651.0954750.5828310.6000311.868164
1Canada20160.3648991.0584260.5763940.5757751.814016
2Canada20150.3583031.0352080.5688590.5757931.794270
3Canada20140.3534851.0119880.5503230.5723441.782252
4Canada20130.3515410.9864000.5180400.5586361.732714
........................
67United States20042.2679999.3114311.3359782.10858513.846058
68United States20032.2335198.9747081.2181991.89282513.339312
69United States20022.1931888.6983061.1921801.80410512.968263
70United States20012.1120388.4804611.2132531.74079712.746262
71United States20002.0405008.2720971.2877391.79099512.620268
\n", + "

72 rows × 7 columns

\n", + "
" + ], + "text/plain": [ + " country year GovExpend Consumption Exports Imports GDP\n", + "0 Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "1 Canada 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "2 Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "3 Canada 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "4 Canada 2013 0.351541 0.986400 0.518040 0.558636 1.732714\n", + ".. ... ... ... ... ... ... ...\n", + "67 United States 2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + "68 United States 2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + "69 United States 2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + "70 United States 2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + "71 United States 2000 2.040500 8.272097 1.287739 1.790995 12.620268\n", + "\n", + "[72 rows x 7 columns]" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.reset_index()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choose the Index Carefully\n", + "\n", + "So, now that we know that we use index and column names for\n", + "aligning data, “how should we pick the index?” is a natural question to ask.\n", + "\n", + "To guide us to the right answer, we will list the first two components\n", + "to [Hadley Wickham’s](http://hadley.nz/) description of [tidy\n", + "data](http://vita.had.co.nz/papers/tidy-data.html):\n", + "\n", + "1. Each column should each have one variable. \n", + "1. Each row should each have one observation. \n", + "\n", + "\n", + "If we strive to have our data in a tidy form (we should), then when\n", + "choosing the index, we should set:\n", + "\n", + "- the row labels (index) to be a unique identifier for an observation\n", + " of data \n", + "- the column names to identify one variable \n", + "\n", + "\n", + "For example, suppose we are looking data on interest rates.\n", + "\n", + "Each column might represent one bond or asset and each row might\n", + "represent the date.\n", + "\n", + "Using hierarchical row and column indices allows us to store higher\n", + "dimensional data in our (inherently) two dimensional DataFrame." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Know Your Goal\n", + "\n", + "The correct column(s) to choose for the index often depends on the context of\n", + "your analysis.\n", + "\n", + "For example, if I were studying how GDP and consumption evolved over time for\n", + "various countries, I would want time (year) and country name on the index\n", + "\n", + "On the other hand, if I were trying to look at the differences across countries\n", + "and variables within a particular year, I may opt to put the country and\n", + "variable on the index and have years be columns.\n", + "\n", + "Following the tidy data rules above and thinking about how you intend to *use*\n", + "the data – and a little practice – will enable you to consistently select the\n", + "correct index." + ] + } + ], + "metadata": { + "date": 1584040764.873878, + "filename": "the_index.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "The Index" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/3_the_index_exercises.ipynb b/Session_7/3_the_index_exercises.ipynb new file mode 100644 index 0000000..e631853 --- /dev/null +++ b/Session_7/3_the_index_exercises.ipynb @@ -0,0 +1,3443 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: python-dateutil>=2.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.8.0)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: six>=1.0.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pyarrow->qeds) (1.12.0)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import pandas as pd\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The Index - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For these exercises we load data on GDP components collected from the World Bank’s World Development Indicators Dataset.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For the purpose of this exercise we extract smaller DataFrames.**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "url = \"https://datascience.quantecon.org/assets/data/wdi_data.csv\"\n", + "df = pd.read_csv(url)\n", + "#df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "df_small = df.head(5)\n", + "#df_small" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "df_tiny = df.iloc[[0, 3, 2, 4], :]\n", + "#df_tiny" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "im_ex = df_small[[\"Imports\", \"Exports\"]]\n", + "im_ex_copy = im_ex.copy()\n", + "#im_ex_copy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Create a new DataFrame as follows: im_ex_tiny = df_tiny + im_ex. Analyze the outcome.**" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ConsumptionExportsGDPGovExpendImportscountryyear
0NaN1.165661NaNNaN1.200063NaNNaN
1NaNNaNNaNNaNNaNNaNNaN
2NaN1.137718NaNNaN1.151585NaNNaN
3NaN1.100646NaNNaN1.144688NaNNaN
4NaN1.036081NaNNaN1.117272NaNNaN
\n", + "
" + ], + "text/plain": [ + " Consumption Exports GDP GovExpend Imports country year\n", + "0 NaN 1.165661 NaN NaN 1.200063 NaN NaN\n", + "1 NaN NaN NaN NaN NaN NaN NaN\n", + "2 NaN 1.137718 NaN NaN 1.151585 NaN NaN\n", + "3 NaN 1.100646 NaN NaN 1.144688 NaN NaN\n", + "4 NaN 1.036081 NaN NaN 1.117272 NaN NaN" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "im_ex_tiny = df_tiny + im_ex\n", + "im_ex_tiny" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **What happens when you apply the mean method to im_ex_tiny? In particular, what happens to columns that have missing data?**\n", + "\n", + " - HINT: also looking at the output of the sum method might help" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Consumption NaN\n", + "Exports 1.110027\n", + "GDP NaN\n", + "GovExpend NaN\n", + "Imports 1.153402\n", + "country NaN\n", + "year NaN\n", + "dtype: float64" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "im_ex_tiny.mean()\n", + "\n", + "#we get missing values for the columns where all values are missing (NaN)\n", + "#the mean is computed for the other columns even though there are missing values" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Consumption 0.000000\n", + "Exports 4.440106\n", + "GDP 0.000000\n", + "GovExpend 0.000000\n", + "Imports 4.613608\n", + "country 0.000000\n", + "year 0.000000\n", + "dtype: float64" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "im_ex_tiny.sum() \n", + "\n", + "#we get 0s for the columns where all values are missing (NaN)\n", + "#the sum is computed for the other columns (even though there are missing values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercises 2-6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**We create a new DataFrame to use throughout the exercises 2-6. Now we set \"country\" and \"year\" as indices.**" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20170.3726651.0954750.5828310.6000311.868164
20160.3648991.0584260.5763940.5757751.814016
20150.3583031.0352080.5688590.5757931.794270
20140.3534851.0119880.5503230.5723441.782252
20130.3515410.9864000.5180400.5586361.732714
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + " 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + " 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + " 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + " 2013 0.351541 0.986400 0.518040 0.558636 1.732714" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi = df.set_index([\"country\", \"year\"])\n", + "wdi.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For each of the examples below do the following and write your answers:**\n", + "\n", + " - Determine which of the rules above applies.\n", + " - Identify the type of the returned value.\n", + " - Explain why the slicing operation returned the data it did." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20170.3726651.0954750.5828310.6000311.868164
20160.3648991.0584260.5763940.5757751.814016
20150.3583031.0352080.5688590.5757931.794270
20140.3534851.0119880.5503230.5723441.782252
20130.3515410.9864000.5180400.5586361.732714
20120.3543420.9612260.5059690.5477561.693428
20110.3518870.9431450.4923490.5282271.664240
20100.3473320.9219520.4699490.5003411.613543
20090.3396860.8900780.4406920.4397961.565291
20080.3307660.8896020.5063500.5022811.612862
20070.3187770.8640120.5304530.4980021.596876
20060.3113820.8276430.5244610.4709311.564608
20050.3030430.7943900.5199500.4472221.524608
20040.2998540.7643570.5086570.4167541.477317
20030.2943350.7417960.4819930.3841991.433089
20020.2860940.7219740.4904650.3686151.407725
20010.2797670.6942300.4846960.3620231.366590
20000.2705530.6777130.4995260.3808231.342805
United States20172.40574312.0192662.2870713.06995417.348627
20162.40798111.7221332.2199372.93600416.972348
20152.37313011.4098002.2222282.88133716.710459
20142.33407111.0006192.2095552.73222816.242526
20132.35338110.6872142.1186392.60019815.853796
20122.39887310.5340422.0455092.56067715.567038
20112.43437810.3780601.9780832.49319415.224555
20102.51014310.1858361.8462802.36018314.992053
20092.50739010.0106871.6464322.08629914.617299
20082.40777110.1378471.7973472.40034914.997756
20072.35198710.1593871.7010962.45501615.018268
20062.3149579.9385031.5649202.39518914.741688
20052.2870229.6430981.4312052.24624614.332500
20042.2679999.3114311.3359782.10858513.846058
20032.2335198.9747081.2181991.89282513.339312
20022.1931888.6983061.1921801.80410512.968263
20012.1120388.4804611.2132531.74079712.746262
20002.0405008.2720971.2877391.79099512.620268
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + " 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + " 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + " 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + " 2013 0.351541 0.986400 0.518040 0.558636 1.732714\n", + " 2012 0.354342 0.961226 0.505969 0.547756 1.693428\n", + " 2011 0.351887 0.943145 0.492349 0.528227 1.664240\n", + " 2010 0.347332 0.921952 0.469949 0.500341 1.613543\n", + " 2009 0.339686 0.890078 0.440692 0.439796 1.565291\n", + " 2008 0.330766 0.889602 0.506350 0.502281 1.612862\n", + " 2007 0.318777 0.864012 0.530453 0.498002 1.596876\n", + " 2006 0.311382 0.827643 0.524461 0.470931 1.564608\n", + " 2005 0.303043 0.794390 0.519950 0.447222 1.524608\n", + " 2004 0.299854 0.764357 0.508657 0.416754 1.477317\n", + " 2003 0.294335 0.741796 0.481993 0.384199 1.433089\n", + " 2002 0.286094 0.721974 0.490465 0.368615 1.407725\n", + " 2001 0.279767 0.694230 0.484696 0.362023 1.366590\n", + " 2000 0.270553 0.677713 0.499526 0.380823 1.342805\n", + "United States 2017 2.405743 12.019266 2.287071 3.069954 17.348627\n", + " 2016 2.407981 11.722133 2.219937 2.936004 16.972348\n", + " 2015 2.373130 11.409800 2.222228 2.881337 16.710459\n", + " 2014 2.334071 11.000619 2.209555 2.732228 16.242526\n", + " 2013 2.353381 10.687214 2.118639 2.600198 15.853796\n", + " 2012 2.398873 10.534042 2.045509 2.560677 15.567038\n", + " 2011 2.434378 10.378060 1.978083 2.493194 15.224555\n", + " 2010 2.510143 10.185836 1.846280 2.360183 14.992053\n", + " 2009 2.507390 10.010687 1.646432 2.086299 14.617299\n", + " 2008 2.407771 10.137847 1.797347 2.400349 14.997756\n", + " 2007 2.351987 10.159387 1.701096 2.455016 15.018268\n", + " 2006 2.314957 9.938503 1.564920 2.395189 14.741688\n", + " 2005 2.287022 9.643098 1.431205 2.246246 14.332500\n", + " 2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + " 2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + " 2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + " 2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + " 2000 2.040500 8.272097 1.287739 1.790995 12.620268" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[[\"United States\", \"Canada\"]]\n", + "\n", + "#row slicing\n", + "#all rows where the outer-most index is either \"United States\" or \"Canada\"" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20120.3543420.9612260.5059690.5477561.693428
20110.3518870.9431450.4923490.5282271.664240
20100.3473320.9219520.4699490.5003411.613543
United States20122.39887310.5340422.0455092.56067715.567038
20112.43437810.3780601.9780832.49319415.224555
20102.51014310.1858361.8462802.36018314.992053
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2012 0.354342 0.961226 0.505969 0.547756 1.693428\n", + " 2011 0.351887 0.943145 0.492349 0.528227 1.664240\n", + " 2010 0.347332 0.921952 0.469949 0.500341 1.613543\n", + "United States 2012 2.398873 10.534042 2.045509 2.560677 15.567038\n", + " 2011 2.434378 10.378060 1.978083 2.493194 15.224555\n", + " 2010 2.510143 10.185836 1.846280 2.360183 14.992053" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[([\"United States\", \"Canada\"], [2010, 2011, 2012]), :]\n", + "\n", + "#row slicing\n", + "#all rows where the outer-most index is either \"United States or \"Canada\" AND \n", + "#where the second level index is either 2010 or 2011 or 2012" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
year
20172.40574312.0192662.2870713.06995417.348627
20162.40798111.7221332.2199372.93600416.972348
20152.37313011.4098002.2222282.88133716.710459
20142.33407111.0006192.2095552.73222816.242526
20132.35338110.6872142.1186392.60019815.853796
20122.39887310.5340422.0455092.56067715.567038
20112.43437810.3780601.9780832.49319415.224555
20102.51014310.1858361.8462802.36018314.992053
20092.50739010.0106871.6464322.08629914.617299
20082.40777110.1378471.7973472.40034914.997756
20072.35198710.1593871.7010962.45501615.018268
20062.3149579.9385031.5649202.39518914.741688
20052.2870229.6430981.4312052.24624614.332500
20042.2679999.3114311.3359782.10858513.846058
20032.2335198.9747081.2181991.89282513.339312
20022.1931888.6983061.1921801.80410512.968263
20012.1120388.4804611.2132531.74079712.746262
20002.0405008.2720971.2877391.79099512.620268
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "year \n", + "2017 2.405743 12.019266 2.287071 3.069954 17.348627\n", + "2016 2.407981 11.722133 2.219937 2.936004 16.972348\n", + "2015 2.373130 11.409800 2.222228 2.881337 16.710459\n", + "2014 2.334071 11.000619 2.209555 2.732228 16.242526\n", + "2013 2.353381 10.687214 2.118639 2.600198 15.853796\n", + "2012 2.398873 10.534042 2.045509 2.560677 15.567038\n", + "2011 2.434378 10.378060 1.978083 2.493194 15.224555\n", + "2010 2.510143 10.185836 1.846280 2.360183 14.992053\n", + "2009 2.507390 10.010687 1.646432 2.086299 14.617299\n", + "2008 2.407771 10.137847 1.797347 2.400349 14.997756\n", + "2007 2.351987 10.159387 1.701096 2.455016 15.018268\n", + "2006 2.314957 9.938503 1.564920 2.395189 14.741688\n", + "2005 2.287022 9.643098 1.431205 2.246246 14.332500\n", + "2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + "2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + "2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + "2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + "2000 2.040500 8.272097 1.287739 1.790995 12.620268" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[\"United States\"]\n", + "\n", + "#row slicing\n", + "#all rows where the outer most index value is equal to United States" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "GDP 14.992053\n", + "Exports 1.846280\n", + "Name: (United States, 2010), dtype: float64" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[(\"United States\", 2010), [\"GDP\", \"Exports\"]] \n", + "\n", + "#row + column slicing\n", + "#we get the values for the GDP and Exports columns in the United States in 2010 \n", + "#however, this is not presented as expected (the column names appear as indices)\n", + "# Tuple used to select united states on year 2010. Then, only GDP and Exports columns are extracted" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "GovExpend 2.510143\n", + "Consumption 10.185836\n", + "Exports 1.846280\n", + "Imports 2.360183\n", + "GDP 14.992053\n", + "Name: (United States, 2010), dtype: float64" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[(\"United States\", 2010)]\n", + "\n", + "#row slicing\n", + "#we get the values for all columns in the United States in 2010 \n", + "#however, this is not presented as expected (the column names appear as indices)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
United States20102.51014310.1858361.8462802.36018314.992053
Canada20150.3583031.0352080.5688590.5757931.794270
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "United States 2010 2.510143 10.185836 1.846280 2.360183 14.992053\n", + "Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[[(\"United States\", 2010), (\"Canada\", 2015)]]\n", + "\n", + "#row slicing\n", + "#all rows where the the two hierarchical indices are either (\"United States\", 2010) or (\"Canada\", 2015)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "country year\n", + "Canada 2017 1.868164\n", + " 2016 1.814016\n", + " 2015 1.794270\n", + " 2014 1.782252\n", + " 2013 1.732714\n", + " 2012 1.693428\n", + " 2011 1.664240\n", + " 2010 1.613543\n", + " 2009 1.565291\n", + " 2008 1.612862\n", + " 2007 1.596876\n", + " 2006 1.564608\n", + " 2005 1.524608\n", + " 2004 1.477317\n", + " 2003 1.433089\n", + " 2002 1.407725\n", + " 2001 1.366590\n", + " 2000 1.342805\n", + "United States 2017 17.348627\n", + " 2016 16.972348\n", + " 2015 16.710459\n", + " 2014 16.242526\n", + " 2013 15.853796\n", + " 2012 15.567038\n", + " 2011 15.224555\n", + " 2010 14.992053\n", + " 2009 14.617299\n", + " 2008 14.997756\n", + " 2007 15.018268\n", + " 2006 14.741688\n", + " 2005 14.332500\n", + " 2004 13.846058\n", + " 2003 13.339312\n", + " 2002 12.968263\n", + " 2001 12.746262\n", + " 2000 12.620268\n", + "Name: GDP, dtype: float64" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[[\"United States\", \"Canada\"], \"GDP\"]\n", + "\n", + "#row + column slicing\n", + "#all rows for United States or Canada only for the column GDP" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "year\n", + "2017 17.348627\n", + "2016 16.972348\n", + "2015 16.710459\n", + "2014 16.242526\n", + "2013 15.853796\n", + "2012 15.567038\n", + "2011 15.224555\n", + "2010 14.992053\n", + "2009 14.617299\n", + "2008 14.997756\n", + "2007 15.018268\n", + "2006 14.741688\n", + "2005 14.332500\n", + "2004 13.846058\n", + "2003 13.339312\n", + "2002 12.968263\n", + "2001 12.746262\n", + "2000 12.620268\n", + "Name: GDP, dtype: float64" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi.loc[\"United States\", \"GDP\"]\n", + "\n", + "#row + column slicing\n", + "#all rows for the US for column GDP" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Try setting my_df to some subset of the rows in wdi (use one of the .loc variations above).**" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
United States20102.51014310.1858361.8462802.36018314.992053
Canada20150.3583031.0352080.5688590.5757931.794270
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "United States 2010 2.510143 10.185836 1.846280 2.360183 14.992053\n", + "Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#below we take a few examples (we comment the ones not used in the analysis below)\n", + "\n", + "my_df = wdi.loc[[(\"United States\", 2010), (\"Canada\", 2015)]]\n", + "#my_df = wdi.loc[\"United States\"]\n", + "#my_df = wdi.loc[(\"United States\", 2010)]\n", + "#my_df = wdi.loc[\"United States\", \"GDP\"]\n", + "#my_df = wdi.loc[[\"United States\", \"Canada\"]]\n", + "\n", + "my_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Then see what happens when you do wdi / my_df or my_df ** wdi.**" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada2000NaNNaNNaNNaNNaN
2001NaNNaNNaNNaNNaN
2002NaNNaNNaNNaNNaN
2003NaNNaNNaNNaNNaN
2004NaNNaNNaNNaNNaN
.....................
United States2013NaNNaNNaNNaNNaN
2014NaNNaNNaNNaNNaN
2015NaNNaNNaNNaNNaN
2016NaNNaNNaNNaNNaN
2017NaNNaNNaNNaNNaN
\n", + "

72 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2000 NaN NaN NaN NaN NaN\n", + " 2001 NaN NaN NaN NaN NaN\n", + " 2002 NaN NaN NaN NaN NaN\n", + " 2003 NaN NaN NaN NaN NaN\n", + " 2004 NaN NaN NaN NaN NaN\n", + "... ... ... ... ... ...\n", + "United States 2013 NaN NaN NaN NaN NaN\n", + " 2014 NaN NaN NaN NaN NaN\n", + " 2015 NaN NaN NaN NaN NaN\n", + " 2016 NaN NaN NaN NaN NaN\n", + " 2017 NaN NaN NaN NaN NaN\n", + "\n", + "[72 rows x 5 columns]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#we create a variable that does wdi/my_df and we analyze the outcome\n", + "x = wdi / my_df\n", + "x\n", + "\n", + "#since it is not clear at a first look, it's better if we extract the subsets used before to see what happens (uncomment to check):\n", + " #x_df = x.loc[[(\"United States\", 2010), (\"Canada\", 2015)]]\n", + " #x_df = x.loc[\"United States\"]\n", + " #x_df = x.loc[(\"United States\", 2010)]\n", + " #x_df = x.loc[\"United States\", \"GDP\"]\n", + " #x_df = x.loc[[\"United States\", \"Canada\"]]\n", + " #x_df" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada2000NaNNaNNaNNaNNaN
2001NaNNaNNaNNaNNaN
2002NaNNaNNaNNaNNaN
2003NaNNaNNaNNaNNaN
2004NaNNaNNaNNaNNaN
.....................
United States2013NaNNaNNaNNaNNaN
2014NaNNaNNaNNaNNaN
2015NaNNaNNaNNaNNaN
2016NaNNaNNaNNaNNaN
2017NaNNaNNaNNaNNaN
\n", + "

72 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2000 NaN NaN NaN NaN NaN\n", + " 2001 NaN NaN NaN NaN NaN\n", + " 2002 NaN NaN NaN NaN NaN\n", + " 2003 NaN NaN NaN NaN NaN\n", + " 2004 NaN NaN NaN NaN NaN\n", + "... ... ... ... ... ...\n", + "United States 2013 NaN NaN NaN NaN NaN\n", + " 2014 NaN NaN NaN NaN NaN\n", + " 2015 NaN NaN NaN NaN NaN\n", + " 2016 NaN NaN NaN NaN NaN\n", + " 2017 NaN NaN NaN NaN NaN\n", + "\n", + "[72 rows x 5 columns]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#we create a variable that does wdi**my_df and we analyze the outcome\n", + "y = wdi ** my_df\n", + "y\n", + "\n", + "#since it is not clear at a first look, it's better if we extract the subsets used before to see what happens (uncomment to check):\n", + " #y_df = y.loc[[(\"United States\", 2010), (\"Canada\", 2015)]]\n", + " #y_df = y.loc[\"United States\"]\n", + " #y_df = y.loc[(\"United States\", 2010)]\n", + " #y_df = y.loc[\"United States\", \"GDP\"]\n", + " #y_df = y.loc[[\"United States\", \"Canada\"]]\n", + " #y_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Try changing the subset of rows in my_df and repeat until you understand what is happening.**" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "#conclusion: the operation applies only to the subset my_df and not to the entire DataFrame wdi" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Below, we create wdi2, which is the same as df4 except that the levels of the index are swapped.**" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
yearcountry
2017Canada0.3726651.0954750.5828310.6000311.868164
2016Canada0.3648991.0584260.5763940.5757751.814016
2015Canada0.3583031.0352080.5688590.5757931.794270
2014Canada0.3534851.0119880.5503230.5723441.782252
2013Canada0.3515410.9864000.5180400.5586361.732714
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "year country \n", + "2017 Canada 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "2016 Canada 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "2015 Canada 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "2014 Canada 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "2013 Canada 0.351541 0.986400 0.518040 0.558636 1.732714" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi2 = df.set_index([\"year\", \"country\"])\n", + "wdi2.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **In the cells after df6 is defined, we have commented out a few of the slicing examples from the previous exercise. For each of these examples, use pd.IndexSlice to extract the same data from df6.**\n", + "\n", + " - HINT: You will need to swap the order of the row slicing arguments within the pd.IndexSlice." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
United States20172.40574312.0192662.2870713.06995417.348627
20162.40798111.7221332.2199372.93600416.972348
20152.37313011.4098002.2222282.88133716.710459
20142.33407111.0006192.2095552.73222816.242526
20132.35338110.6872142.1186392.60019815.853796
20122.39887310.5340422.0455092.56067715.567038
20112.43437810.3780601.9780832.49319415.224555
20102.51014310.1858361.8462802.36018314.992053
20092.50739010.0106871.6464322.08629914.617299
20082.40777110.1378471.7973472.40034914.997756
20072.35198710.1593871.7010962.45501615.018268
20062.3149579.9385031.5649202.39518914.741688
20052.2870229.6430981.4312052.24624614.332500
20042.2679999.3114311.3359782.10858513.846058
20032.2335198.9747081.2181991.89282513.339312
20022.1931888.6983061.1921801.80410512.968263
20012.1120388.4804611.2132531.74079712.746262
20002.0405008.2720971.2877391.79099512.620268
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "United States 2017 2.405743 12.019266 2.287071 3.069954 17.348627\n", + " 2016 2.407981 11.722133 2.219937 2.936004 16.972348\n", + " 2015 2.373130 11.409800 2.222228 2.881337 16.710459\n", + " 2014 2.334071 11.000619 2.209555 2.732228 16.242526\n", + " 2013 2.353381 10.687214 2.118639 2.600198 15.853796\n", + " 2012 2.398873 10.534042 2.045509 2.560677 15.567038\n", + " 2011 2.434378 10.378060 1.978083 2.493194 15.224555\n", + " 2010 2.510143 10.185836 1.846280 2.360183 14.992053\n", + " 2009 2.507390 10.010687 1.646432 2.086299 14.617299\n", + " 2008 2.407771 10.137847 1.797347 2.400349 14.997756\n", + " 2007 2.351987 10.159387 1.701096 2.455016 15.018268\n", + " 2006 2.314957 9.938503 1.564920 2.395189 14.741688\n", + " 2005 2.287022 9.643098 1.431205 2.246246 14.332500\n", + " 2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + " 2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + " 2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + " 2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + " 2000 2.040500 8.272097 1.287739 1.790995 12.620268" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#the equivalent of wdi.loc[\"United States\"] is below:\n", + "\n", + "#we create a shortcut for pd.IndexSlice to use in what follows\n", + "idx = pd.IndexSlice\n", + "\n", + "wdi.loc[idx[\"United States\",:],:]" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20120.3543420.9612260.5059690.5477561.693428
20110.3518870.9431450.4923490.5282271.664240
20100.3473320.9219520.4699490.5003411.613543
United States20122.39887310.5340422.0455092.56067715.567038
20112.43437810.3780601.9780832.49319415.224555
20102.51014310.1858361.8462802.36018314.992053
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2012 0.354342 0.961226 0.505969 0.547756 1.693428\n", + " 2011 0.351887 0.943145 0.492349 0.528227 1.664240\n", + " 2010 0.347332 0.921952 0.469949 0.500341 1.613543\n", + "United States 2012 2.398873 10.534042 2.045509 2.560677 15.567038\n", + " 2011 2.434378 10.378060 1.978083 2.493194 15.224555\n", + " 2010 2.510143 10.185836 1.846280 2.360183 14.992053" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#the equivalent of wdi.loc[([\"United States\", \"Canada\"], [2010, 2011, 2012]), :] is below:\n", + "\n", + "wdi.loc[idx[([\"United States\", \"Canada\"],[2010, 2011, 2012])], :]" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "country year\n", + "Canada 2017 1.868164\n", + " 2016 1.814016\n", + " 2015 1.794270\n", + " 2014 1.782252\n", + " 2013 1.732714\n", + " 2012 1.693428\n", + " 2011 1.664240\n", + " 2010 1.613543\n", + " 2009 1.565291\n", + " 2008 1.612862\n", + " 2007 1.596876\n", + " 2006 1.564608\n", + " 2005 1.524608\n", + " 2004 1.477317\n", + " 2003 1.433089\n", + " 2002 1.407725\n", + " 2001 1.366590\n", + " 2000 1.342805\n", + "United States 2017 17.348627\n", + " 2016 16.972348\n", + " 2015 16.710459\n", + " 2014 16.242526\n", + " 2013 15.853796\n", + " 2012 15.567038\n", + " 2011 15.224555\n", + " 2010 14.992053\n", + " 2009 14.617299\n", + " 2008 14.997756\n", + " 2007 15.018268\n", + " 2006 14.741688\n", + " 2005 14.332500\n", + " 2004 13.846058\n", + " 2003 13.339312\n", + " 2002 12.968263\n", + " 2001 12.746262\n", + " 2000 12.620268\n", + "Name: GDP, dtype: float64" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#the equivalent of wdi.loc[[\"United States\", \"Canada\"], \"GDP\"] is below:\n", + "\n", + "wdi.loc[idx[[\"United States\", \"Canada\"],:], \"GDP\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 5\n", + "\n", + "**For the purpose of this exercise, we create a new DataFrame that swaps the rows and columns of the wdi DataFrame.**" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryCanada...United States
year2017201620152014201320122011201020092008...2009200820072006200520042003200220012000
GovExpend0.3726650.3648990.3583030.3534850.3515410.3543420.3518870.3473320.3396860.330766...2.5073902.4077712.3519872.3149572.2870222.2679992.2335192.1931882.1120382.040500
Consumption1.0954751.0584261.0352081.0119880.9864000.9612260.9431450.9219520.8900780.889602...10.01068710.13784710.1593879.9385039.6430989.3114318.9747088.6983068.4804618.272097
Exports0.5828310.5763940.5688590.5503230.5180400.5059690.4923490.4699490.4406920.506350...1.6464321.7973471.7010961.5649201.4312051.3359781.2181991.1921801.2132531.287739
Imports0.6000310.5757750.5757930.5723440.5586360.5477560.5282270.5003410.4397960.502281...2.0862992.4003492.4550162.3951892.2462462.1085851.8928251.8041051.7407971.790995
GDP1.8681641.8140161.7942701.7822521.7327141.6934281.6642401.6135431.5652911.612862...14.61729914.99775615.01826814.74168814.33250013.84605813.33931212.96826312.74626212.620268
\n", + "

5 rows × 72 columns

\n", + "
" + ], + "text/plain": [ + "country Canada \\\n", + "year 2017 2016 2015 2014 2013 2012 \n", + "GovExpend 0.372665 0.364899 0.358303 0.353485 0.351541 0.354342 \n", + "Consumption 1.095475 1.058426 1.035208 1.011988 0.986400 0.961226 \n", + "Exports 0.582831 0.576394 0.568859 0.550323 0.518040 0.505969 \n", + "Imports 0.600031 0.575775 0.575793 0.572344 0.558636 0.547756 \n", + "GDP 1.868164 1.814016 1.794270 1.782252 1.732714 1.693428 \n", + "\n", + "country ... United States \\\n", + "year 2011 2010 2009 2008 ... 2009 \n", + "GovExpend 0.351887 0.347332 0.339686 0.330766 ... 2.507390 \n", + "Consumption 0.943145 0.921952 0.890078 0.889602 ... 10.010687 \n", + "Exports 0.492349 0.469949 0.440692 0.506350 ... 1.646432 \n", + "Imports 0.528227 0.500341 0.439796 0.502281 ... 2.086299 \n", + "GDP 1.664240 1.613543 1.565291 1.612862 ... 14.617299 \n", + "\n", + "country \\\n", + "year 2008 2007 2006 2005 2004 2003 \n", + "GovExpend 2.407771 2.351987 2.314957 2.287022 2.267999 2.233519 \n", + "Consumption 10.137847 10.159387 9.938503 9.643098 9.311431 8.974708 \n", + "Exports 1.797347 1.701096 1.564920 1.431205 1.335978 1.218199 \n", + "Imports 2.400349 2.455016 2.395189 2.246246 2.108585 1.892825 \n", + "GDP 14.997756 15.018268 14.741688 14.332500 13.846058 13.339312 \n", + "\n", + "country \n", + "year 2002 2001 2000 \n", + "GovExpend 2.193188 2.112038 2.040500 \n", + "Consumption 8.698306 8.480461 8.272097 \n", + "Exports 1.192180 1.213253 1.287739 \n", + "Imports 1.804105 1.740797 1.790995 \n", + "GDP 12.968263 12.746262 12.620268 \n", + "\n", + "[5 rows x 72 columns]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdiT = wdi.T # .T means \"transpose\" or \"swap rows and columns\"\n", + "wdiT" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Use pd.IndexSlice to extract all data from wdiT where the year level of the column names (the second level) is one of 2010, 2012, and 2014.**" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryCanadaGermanyUnited KingdomUnited States
year201420122010201420122010201420122010201420122010
GovExpend0.3534850.3543420.3473320.6859900.6664540.6533860.5388880.5281940.5211462.3340712.3988732.510143
Consumption1.0119880.9612260.9219521.9999531.9673901.9154811.6757161.6125501.59856311.00061910.53404210.185836
Exports0.5503230.5059690.4699491.7122701.6074551.4437350.7740220.7454840.6908242.2095552.0455091.846280
Imports0.5723440.5477560.5003411.4454091.3541221.2661260.8273110.7726920.7450652.7322282.5606772.360183
GDP1.7822521.6934281.6135433.6549243.5595873.4170952.6571592.5293232.45290016.24252615.56703814.992053
\n", + "
" + ], + "text/plain": [ + "country Canada Germany \\\n", + "year 2014 2012 2010 2014 2012 2010 \n", + "GovExpend 0.353485 0.354342 0.347332 0.685990 0.666454 0.653386 \n", + "Consumption 1.011988 0.961226 0.921952 1.999953 1.967390 1.915481 \n", + "Exports 0.550323 0.505969 0.469949 1.712270 1.607455 1.443735 \n", + "Imports 0.572344 0.547756 0.500341 1.445409 1.354122 1.266126 \n", + "GDP 1.782252 1.693428 1.613543 3.654924 3.559587 3.417095 \n", + "\n", + "country United Kingdom United States \\\n", + "year 2014 2012 2010 2014 2012 \n", + "GovExpend 0.538888 0.528194 0.521146 2.334071 2.398873 \n", + "Consumption 1.675716 1.612550 1.598563 11.000619 10.534042 \n", + "Exports 0.774022 0.745484 0.690824 2.209555 2.045509 \n", + "Imports 0.827311 0.772692 0.745065 2.732228 2.560677 \n", + "GDP 2.657159 2.529323 2.452900 16.242526 15.567038 \n", + "\n", + "country \n", + "year 2010 \n", + "GovExpend 2.510143 \n", + "Consumption 10.185836 \n", + "Exports 1.846280 \n", + "Imports 2.360183 \n", + "GDP 14.992053 " + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdiT.loc[:, idx[:,[2010, 2012, 2014]]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 6\n", + "\n", + "1. **Move just the `year` level of the index back as a column.**" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
yearGovExpendConsumptionExportsImportsGDP
country
Canada20170.3726651.0954750.5828310.6000311.868164
Canada20160.3648991.0584260.5763940.5757751.814016
Canada20150.3583031.0352080.5688590.5757931.794270
Canada20140.3534851.0119880.5503230.5723441.782252
Canada20130.3515410.9864000.5180400.5586361.732714
.....................
United States20042.2679999.3114311.3359782.10858513.846058
United States20032.2335198.9747081.2181991.89282513.339312
United States20022.1931888.6983061.1921801.80410512.968263
United States20012.1120388.4804611.2132531.74079712.746262
United States20002.0405008.2720971.2877391.79099512.620268
\n", + "

72 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " year GovExpend Consumption Exports Imports GDP\n", + "country \n", + "Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "Canada 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "Canada 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "Canada 2013 0.351541 0.986400 0.518040 0.558636 1.732714\n", + "... ... ... ... ... ... ...\n", + "United States 2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + "United States 2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + "United States 2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + "United States 2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + "United States 2000 2.040500 8.272097 1.287739 1.790995 12.620268\n", + "\n", + "[72 rows x 6 columns]" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# remove just year level and add as column\n", + "wdi_1 = df.set_index([\"country\", \"year\"])\n", + "wdi_1.reset_index([\"year\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Completely throw away all levels of the index.** " + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryyearGovExpendConsumptionExportsImportsGDP
0Canada20170.3726651.0954750.5828310.6000311.868164
1Canada20160.3648991.0584260.5763940.5757751.814016
2Canada20150.3583031.0352080.5688590.5757931.794270
3Canada20140.3534851.0119880.5503230.5723441.782252
4Canada20130.3515410.9864000.5180400.5586361.732714
........................
67United States20042.2679999.3114311.3359782.10858513.846058
68United States20032.2335198.9747081.2181991.89282513.339312
69United States20022.1931888.6983061.1921801.80410512.968263
70United States20012.1120388.4804611.2132531.74079712.746262
71United States20002.0405008.2720971.2877391.79099512.620268
\n", + "

72 rows × 7 columns

\n", + "
" + ], + "text/plain": [ + " country year GovExpend Consumption Exports Imports GDP\n", + "0 Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "1 Canada 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "2 Canada 2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "3 Canada 2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "4 Canada 2013 0.351541 0.986400 0.518040 0.558636 1.732714\n", + ".. ... ... ... ... ... ... ...\n", + "67 United States 2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + "68 United States 2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + "69 United States 2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + "70 United States 2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + "71 United States 2000 2.040500 8.272097 1.287739 1.790995 12.620268\n", + "\n", + "[72 rows x 7 columns]" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# throw away all levels of index\n", + "wdi_2 = df.set_index([\"country\", \"year\"])\n", + "wdi_2.reset_index()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Remove the `country` of the index and *do not* keep it as a column.**" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
year
20170.3726651.0954750.5828310.6000311.868164
20160.3648991.0584260.5763940.5757751.814016
20150.3583031.0352080.5688590.5757931.794270
20140.3534851.0119880.5503230.5723441.782252
20130.3515410.9864000.5180400.5586361.732714
..................
20042.2679999.3114311.3359782.10858513.846058
20032.2335198.9747081.2181991.89282513.339312
20022.1931888.6983061.1921801.80410512.968263
20012.1120388.4804611.2132531.74079712.746262
20002.0405008.2720971.2877391.79099512.620268
\n", + "

72 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "year \n", + "2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "2015 0.358303 1.035208 0.568859 0.575793 1.794270\n", + "2014 0.353485 1.011988 0.550323 0.572344 1.782252\n", + "2013 0.351541 0.986400 0.518040 0.558636 1.732714\n", + "... ... ... ... ... ...\n", + "2004 2.267999 9.311431 1.335978 2.108585 13.846058\n", + "2003 2.233519 8.974708 1.218199 1.892825 13.339312\n", + "2002 2.193188 8.698306 1.192180 1.804105 12.968263\n", + "2001 2.112038 8.480461 1.213253 1.740797 12.746262\n", + "2000 2.040500 8.272097 1.287739 1.790995 12.620268\n", + "\n", + "[72 rows x 5 columns]" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Remove country from the index -- don't keep it as a column\n", + "wdi_3 = df.set_index([\"country\", \"year\"])\n", + "wdi_3.reset_index([\"country\"], drop=True)" + ] + } + ], + "metadata": { + "date": 1584040764.873878, + "filename": "the_index.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "The Index" + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Session_7/4_storage_formats.ipynb b/Session_7/4_storage_formats.ipynb new file mode 100644 index 0000000..f00663c --- /dev/null +++ b/Session_7/4_storage_formats.ipynb @@ -0,0 +1,1080 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Storage Formats\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [Intro to DataFrames and Series](https://datascience.quantecon.org/intro.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Understand that data can be saved in various formats \n", + "- Know where to get help on file input and output \n", + "- Know when to use csv, xlsx, feather, and sql formats \n", + "\n", + "\n", + "**Data**\n", + "\n", + "- Results for all NFL games between September 1920 to February 2017 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [Storage Formats](#Storage-Formats) \n", + " - [File Formats](#File-Formats) \n", + " - [Writing DataFrames](#Writing-DataFrames) \n", + " - [Reading Files into DataFrames](#Reading-Files-into-DataFrames) \n", + " - [Practice](#Practice) " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "# Uncomment following line to install on colab\n", + "#! pip install qeds" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## File Formats\n", + "\n", + "Data can be saved in a variety of formats.\n", + "\n", + "pandas understands how to write and read DataFrames to and from many of\n", + "these formats.\n", + "\n", + "We defer to the [official\n", + "documentation](https://pandas.pydata.org/pandas-docs/stable/io.html)\n", + "for a full description of how to interact with all the file formats, but\n", + "will briefly discuss a few of them here." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### CSV\n", + "\n", + "**What is it?** CSVs store data as plain text (strings) where each row is a\n", + "line and columns are separated by `,`.\n", + "\n", + "**Pros**\n", + "\n", + "- Widely used (you should be familiar with it) \n", + "- Plain text file (can open on any computer, “future proof”) \n", + "- Can be read from and written to by most data software \n", + "\n", + "\n", + "**Cons**\n", + "\n", + "- Not the most efficient way to store or access \n", + "- No formal standard, so there is room for user interpretation on how to\n", + " handle edge cases (e.g. what to do about a data field that itself includes\n", + " a comma) \n", + "\n", + "\n", + "**When to use**:\n", + "\n", + "- A great default option for most use cases " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### xlsx\n", + "\n", + "**What is it?** xlsx is a binary file format used as Excel’s default.\n", + "\n", + "**Pros**:\n", + "\n", + "- Standard format in many industries \n", + "- Easy to share with colleagues that use Excel \n", + "\n", + "\n", + "**Cons**:\n", + "\n", + "- Quite slow to read/write large amounts of data \n", + "- Stores both data and *metadata* like styling and display information\n", + " and even plots. This metadata is not always portable to other file formats\n", + " or programs. \n", + "\n", + "\n", + "**When to use**:\n", + "\n", + "- When sharing data with Excel \n", + "- When you would like special formatting to be applied to the\n", + " spreadsheet when viewed in Excel " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Parquet\n", + "\n", + "**What is it?** Parquet is a custom binary format designed for efficient reading and\n", + "writing of data stored in columns.\n", + "\n", + "**Pros**:\n", + "\n", + "- *Very* fast \n", + "- Naturally understands all `dtypes` used by pandas, including\n", + " multi-index DataFrames \n", + "- Very common in “big data” systems like Hadoop or Spark \n", + "- Supports various compression algorithms \n", + "\n", + "\n", + "**Cons**:\n", + "\n", + "- Binary storage format that is not human-readable \n", + "\n", + "\n", + "**When to use**:\n", + "\n", + "- If you have “not small” amounts (> 100 MB) of unchanging data that\n", + " you want to read quickly \n", + "- If you want to store data in an size-and-time-efficient way that may\n", + " be accessed by external systems " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Feather\n", + "\n", + "**What is it?** Feather is a custom binary format designed for efficient reading and\n", + "writing of data stored in columns.\n", + "\n", + "**Pros**:\n", + "\n", + "- *Very* fast – even faster than parquet \n", + "- Naturally understands all `dtypes` used by pandas \n", + "\n", + "\n", + "**Cons**:\n", + "\n", + "- Can only read and write from Python and a handful of other\n", + " programming languages \n", + "- New file format (introduced in March ‘16), so most files don’t come\n", + " in this format \n", + "- Only supports standard pandas index, so you need to `reset_index`\n", + " before saving and then `set_index` after loading \n", + "\n", + "\n", + "**When to use**:\n", + "\n", + "- Use as an alternative to Parquet if you need the absolute best read and write\n", + " speeds for unchanging datasets \n", + "- Only use when you will not need to access the data in a programming language\n", + " or software outside of Python, R, and Julia " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### SQL\n", + "\n", + "**What is it?** SQL is a language used to interact with relational\n", + "databases… [more info](https://en.wikipedia.org/wiki/SQL)\n", + "\n", + "**Pros**:\n", + "\n", + "- Well established industry standard for handling data \n", + "- Much of the world’s data is in a SQL database somewhere \n", + "\n", + "\n", + "**Cons**:\n", + "\n", + "- Complicated: to have full control you need to learn another language\n", + " (SQL) \n", + "\n", + "\n", + "**When to use**:\n", + "\n", + "- When reading from or writing to existing SQL databases \n", + "\n", + "\n", + "**NOTE**: We can cover interacting with SQL databases in a dedicated\n", + "lecture – contact us for more information." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Writing DataFrames\n", + "\n", + "Let’s now talk about saving a DataFrame to a file.\n", + "\n", + "As a general rule of thumb, if we have a DataFrame `df` and we would\n", + "like to save to save it as a file of type `FOO`, then we would call\n", + "the method named `df.to_FOO(...)`.\n", + "\n", + "We will show you how this can be done and try to highlight some of the\n", + "items mentioned above.\n", + "\n", + "But, we will not cover all possible options and features — we feel\n", + "it is best to learn these as you need them by consulting the appropriate\n", + "documentation.\n", + "\n", + "First, we need some DataFrames to save. Let’s make them now.\n", + "\n", + "Note that by default `df2` will be approximately 10 MB.\n", + "\n", + "If you need to change this number, adjust the value of\n", + "the `wanted_mb` variable below." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "df2.shape = (100000, 13)\n", + "df2 is approximately 9.9183349609375 MB\n" + ] + } + ], + "source": [ + "np.random.seed(42) # makes sure we get the same random numbers each time\n", + "df1 = pd.DataFrame(\n", + " np.random.randint(0, 100, size=(10, 4)),\n", + " columns=[\"a\", \"b\", \"c\", \"d\"]\n", + ")\n", + "\n", + "wanted_mb = 10 # CHANGE THIS LINE\n", + "nrow = 100000\n", + "ncol = int(((wanted_mb * 1024**2) / 8) / nrow)\n", + "df2 = pd.DataFrame(\n", + " np.random.rand(nrow, ncol),\n", + " columns=[\"x{}\".format(i) for i in range(ncol)]\n", + ")\n", + "\n", + "print(\"df2.shape = \", df2.shape)\n", + "print(\"df2 is approximately {} MB\".format(df2.memory_usage().sum() / (1024**2)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [df.to_csv](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_csv.html)\n", + "\n", + "Let’s start with `df.to_csv`.\n", + "\n", + "Without any additional arguments, the `df.to_csv` function will return\n", + "a string containing the csv form of the DataFrame:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ",a,b,c,d\n", + "0,51,92,14,71\n", + "1,60,20,82,86\n", + "2,74,74,87,99\n", + "3,23,2,21,52\n", + "4,1,87,29,37\n", + "5,1,63,59,20\n", + "6,32,75,57,21\n", + "7,88,48,90,58\n", + "8,41,91,59,79\n", + "9,14,61,61,46\n", + "\n" + ] + } + ], + "source": [ + "# notice the plain text format -- one row per line, columns separated by `'`\n", + "print(df1.to_csv())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we do pass an argument, the first argument will be used as the file name." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "df1.to_csv(\"df1.csv\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run the cell below to verify that the file was created." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "os.path.isfile(\"df1.csv\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s see how long it takes to save `df2` to a file. (Because of the `%%time` at\n", + "the top, Jupyter will report the total time to run all code in\n", + "the cell)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wall time: 4.18 s\n" + ] + } + ], + "source": [ + "%%time\n", + "df2.to_csv(\"df2.csv\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we will see below, this isn’t as fastest file format we could choose." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [df.to_excel](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_excel.html)\n", + "\n", + "When saving a DataFrame to an Excel workbook, we can\n", + "choose both the name of the workbook (file) and the name of the sheet\n", + "within the file where the DataFrame should be written.\n", + "\n", + "We do this by passing the workbook name as the first argument and the\n", + "sheet name as the second argument as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "df1.to_excel(\"df1.xlsx\", \"df1\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "pandas also gives us the option to write more than one DataFrame to a\n", + "workbook.\n", + "\n", + "To do this, we need to first construct an instance of `pd.ExcelWriter`\n", + "and then pass that as the first argument to `df.to_excel`.\n", + "\n", + "Let’s see how this works." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "with pd.ExcelWriter(\"df1.xlsx\") as writer:\n", + " df1.to_excel(writer, \"df1\")\n", + " (df1 + 10).to_excel(writer, \"df1 plus 10\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + "with ... as ... :\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "syntax used above is an example of a *context manager*.\n", + "\n", + "We don’t need to understand all the details behind what this means\n", + "(google it if you are curious).\n", + "\n", + "For now, just recognize that particular syntax as the way to write\n", + "multiple sheets to an Excel workbook.\n", + "\n", + "

\n", + "\n", + "WARNING:\n", + "\n", + "

\n", + "\n", + "Saving `df2` to an excel file takes a very long time.\n", + "\n", + "For that reason, we will just show the code and hard-code the output\n", + "we saw when we ran the code." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + "%%time\n", + "df2.to_excel(\"df2.xlsx\")\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + " Wall time: 25.7 s\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [pyarrow.feather.write_feather](https://arrow.apache.org/docs/python/generated/pyarrow.feather.write_feather.html#pyarrow.feather.write_feather)\n", + "\n", + "As noted above, the feather file format was developed for very efficient\n", + "reading and writing between Python and your computer.\n", + "\n", + "Support for this format is provided by a separate Python package called `pyarrow`.\n", + "\n", + "This package is not installed by default. To install it, copy/paste the code\n", + "below into a code cell and execute." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```markdown\n", + "!pip install pyarrow\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The parameters for `pyarrow.feather.write_feather` are the DataFrame and file name.\n", + "\n", + "Let’s try it out." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import pyarrow.feather\n", + "pyarrow.feather.write_feather(df1, \"df1.feather\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wall time: 40.4 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "pyarrow.feather.write_feather(df2, \"df2.feather\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An example timing result:\n", + "\n", + "|format|time|\n", + "|:---------:|:----------------------:|\n", + "|csv|2.66 seconds|\n", + "|xlsx|25.7 seconds|\n", + "|feather|43 milliseconds|\n", + "As you can see, saving this DataFrame in the feather format was far\n", + "faster than either CSV or Excel." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reading Files into DataFrames\n", + "\n", + "As with the `df.to_FOO` family of methods, there are similar\n", + "`pd.read_FOO` functions. (Note: they are in defined pandas, not as\n", + "methods on a DataFrame.)\n", + "\n", + "These methods have many more options because data storage can be messy or wrong.\n", + "\n", + "We will explore these in more detail in a separate lecture.\n", + "\n", + "For now, we just want to highlight the differences in how to read data\n", + "from each of the file formats.\n", + "\n", + "Let’s start by reading the files we just created to verify that they\n", + "match the data we began with." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
abcd
051921471
160208286
274748799
32322152
41872937
\n", + "
" + ], + "text/plain": [ + " a b c d\n", + "0 51 92 14 71\n", + "1 60 20 82 86\n", + "2 74 74 87 99\n", + "3 23 2 21 52\n", + "4 1 87 29 37" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# notice that index was specified in the first (0th -- why?) column of the file\n", + "df1_csv = pd.read_csv(\"df1.csv\", index_col=0)\n", + "df1_csv.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
abcd
051921471
160208286
274748799
32322152
41872937
\n", + "
" + ], + "text/plain": [ + " a b c d\n", + "0 51 92 14 71\n", + "1 60 20 82 86\n", + "2 74 74 87 99\n", + "3 23 2 21 52\n", + "4 1 87 29 37" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1_xlsx = pd.read_excel(\"df1.xlsx\", \"df1\", index_col=0)\n", + "df1_xlsx.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
abcd
051921471
160208286
274748799
32322152
41872937
\n", + "
" + ], + "text/plain": [ + " a b c d\n", + "0 51 92 14 71\n", + "1 60 20 82 86\n", + "2 74 74 87 99\n", + "3 23 2 21 52\n", + "4 1 87 29 37" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# notice feather already knows what the index is\n", + "df1_feather = pyarrow.feather.read_feather(\"df1.feather\")\n", + "df1_feather.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the `pd.read_FOO` family of functions, we can also read files\n", + "from places on the internet.\n", + "\n", + "We saved our `df1` DataFrame to a file\n", + "and posted it online.\n", + "\n", + "Below, we show an example of using `pd.read_csv` to read this file." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
abcd
051921471
160208286
274748799
32322152
41872937
\n", + "
" + ], + "text/plain": [ + " a b c d\n", + "0 51 92 14 71\n", + "1 60 20 82 86\n", + "2 74 74 87 99\n", + "3 23 2 21 52\n", + "4 1 87 29 37" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1_url = \"https://storage.googleapis.com/workshop_materials/df1.csv\"\n", + "df1_web = pd.read_csv(df1_url, index_col=0)\n", + "df1_web.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Cleanup\n", + "\n", + "If you want to remove the files we just created, run the following cell." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "def try_remove(file):\n", + " if os.path.isfile(file):\n", + " os.remove(file)\n", + "\n", + "for df in [\"df1\", \"df2\"]:\n", + " for extension in [\"csv\", \"feather\", \"xlsx\"]:\n", + " filename = df + \".\" + extension\n", + " try_remove(filename)" + ] + } + ], + "metadata": { + "date": 1584040764.364358, + "filename": "storage_formats.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "Storage Formats" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/4_storage_formats_exercises.ipynb b/Session_7/4_storage_formats_exercises.ipynb new file mode 100644 index 0000000..7893f00 --- /dev/null +++ b/Session_7/4_storage_formats_exercises.ipynb @@ -0,0 +1,584 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: six>=1.0.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pyarrow->qeds) (1.12.0)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: python-dateutil in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (2.8.0)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.16.0)\n", + "Requirement already satisfied: six>=1.0.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pyarrow) (1.12.0)\n", + "Requirement already satisfied: numpy>=1.14 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pyarrow) (1.16.5)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import pandas as pd\n", + "import numpy as np\n", + "!pip install pyarrow\n", + "import pyarrow.feather" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Storage Formats - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**In the cell below, the variable `url` contains a web address to a csv file containing the result of all NFL games from September 1920 to February 2017.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Use `pd.read_csv` to read this file into a DataFrame named `nfl`.** " + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonneutralplayoffteam1team2elo1elo2elo_prob1score1score2result1
date
1920-09-26192000RIISTP1503.9470001300.0000000.8246514801.0
1920-10-03192000AKRWHE1503.4200001300.0000000.8242124301.0
1920-10-03192000RCHABU1503.4200001300.0000000.8242121001.0
1920-10-03192000DAYCOL1493.0020001504.9080000.5758191401.0
1920-10-03192000RIIMUN1516.1080001478.0040000.6441714501.0
....................................
2017-01-15201601DALGB1617.7946831635.4511720.56771431340.0
2017-01-15201601KCPIT1681.9264631647.7341790.63899316180.0
2017-01-22201601ATLGB1664.1272661651.5377310.60984044211.0
2017-01-22201601NEPIT1747.1603211662.4372150.70305236171.0
2017-02-05201611ATLNE1688.0814181763.8181680.39270028340.0
\n", + "

15740 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " season neutral playoff team1 team2 elo1 elo2 \\\n", + "date \n", + "1920-09-26 1920 0 0 RII STP 1503.947000 1300.000000 \n", + "1920-10-03 1920 0 0 AKR WHE 1503.420000 1300.000000 \n", + "1920-10-03 1920 0 0 RCH ABU 1503.420000 1300.000000 \n", + "1920-10-03 1920 0 0 DAY COL 1493.002000 1504.908000 \n", + "1920-10-03 1920 0 0 RII MUN 1516.108000 1478.004000 \n", + "... ... ... ... ... ... ... ... \n", + "2017-01-15 2016 0 1 DAL GB 1617.794683 1635.451172 \n", + "2017-01-15 2016 0 1 KC PIT 1681.926463 1647.734179 \n", + "2017-01-22 2016 0 1 ATL GB 1664.127266 1651.537731 \n", + "2017-01-22 2016 0 1 NE PIT 1747.160321 1662.437215 \n", + "2017-02-05 2016 1 1 ATL NE 1688.081418 1763.818168 \n", + "\n", + " elo_prob1 score1 score2 result1 \n", + "date \n", + "1920-09-26 0.824651 48 0 1.0 \n", + "1920-10-03 0.824212 43 0 1.0 \n", + "1920-10-03 0.824212 10 0 1.0 \n", + "1920-10-03 0.575819 14 0 1.0 \n", + "1920-10-03 0.644171 45 0 1.0 \n", + "... ... ... ... ... \n", + "2017-01-15 0.567714 31 34 0.0 \n", + "2017-01-15 0.638993 16 18 0.0 \n", + "2017-01-22 0.609840 44 21 1.0 \n", + "2017-01-22 0.703052 36 17 1.0 \n", + "2017-02-05 0.392700 28 34 0.0 \n", + "\n", + "[15740 rows x 11 columns]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = \"https://raw.githubusercontent.com/fivethirtyeight/nfl-elo-game/\"\n", + "url = url + \"3488b7d0b46c5f6583679bc40fb3a42d729abd39/data/nfl_games.csv\"\n", + "\n", + "nfl = pd.read_csv(url, index_col=0)\n", + "nfl" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Print the shape and column names of `nfl`.**" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "nfl.shape= (15740, 11)\n", + "Index(['season', 'neutral', 'playoff', 'team1', 'team2', 'elo1', 'elo2',\n", + " 'elo_prob1', 'score1', 'score2', 'result1'],\n", + " dtype='object')\n" + ] + } + ], + "source": [ + "print(\"nfl.shape=\",nfl.shape)\n", + "print(nfl.columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Save the DataFrame to a file named `nfl.xlsx`** " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "nfl.to_excel(\"nfl.xlsx\", \"nfl\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. **Open the spreadsheet using Excel on your computer.** " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Compute the average total points in each game (note, you will need to sum two of the columns to get total points).** " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "39.95368487928844" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#we compute the total points as score1 + score 2, then we take the average\n", + "nfl[\"total_points\"] = nfl[\"score1\"]+nfl[\"score2\"]\n", + "nfl[\"total_points\"].mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Repeat the above calculation, but only for playoff games.** " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "42.70404411764706" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#here we compute the average total points for the subset corresponding to playoff games\n", + "nfl[\"total_points\"][nfl[\"playoff\"]==1].mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Compute the average score for your favorite team (you’ll need to consider when they were team1 vs team2).** " + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "17.125" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#I don't have a smarter solution\n", + "\n", + "#in order to get the average for AKR:\n", + " #I sum the total points obtained by AKR either as team1 or team2\n", + " #I sum the total number of games of AKR either as team1 or team2\n", + " #then I divide the total points by the total number of games\n", + "\n", + "sum_teams12 = nfl[\"total_points\"][nfl[\"team1\"]==\"AKR\"].sum() + nfl[\"total_points\"][nfl[\"team2\"]==\"AKR\"].sum()\n", + "count_teams12 = nfl[\"total_points\"][nfl[\"team1\"]==\"AKR\"].count() + nfl[\"total_points\"][nfl[\"team2\"]==\"AKR\"].count()\n", + "average = sum_teams12/count_teams12\n", + "average" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. **Compute the ratio of “upsets” to total games played. An upset is defined as a team with a lower ELO winning the game.** " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.34358322744599745" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#for all the matches \n", + "nfl.loc[((nfl['elo1']>nfl['elo2']) & (nfl['result1']==0)) | ((nfl['elo2']>nfl['elo1']) & (nfl['result1']==1)) , 'Upset?' ] =1 \n", + "nfl.loc[(nfl['Upset?']!=1), 'Upset?']=0\n", + "nfl['Upset?'].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.21739130434782608" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#only for the matches of AKR (as team1)\n", + "nfl.loc[((nfl['elo1']>nfl['elo2']) & (nfl['result1']==0)) | ((nfl['elo2']>nfl['elo1']) & (nfl['result1']==1)) , 'Upset?' ] =1 \n", + "nfl.loc[(nfl['Upset?']!=1), 'Upset?']=0\n", + "nfl['Upset?'][nfl[\"team1\"] == \"AKR\"].mean()" + ] + } + ], + "metadata": { + "date": 1584040764.364358, + "filename": "storage_formats.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "Storage Formats" + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Session_7/5_data_clean.ipynb b/Session_7/5_data_clean.ipynb new file mode 100644 index 0000000..425d5fe --- /dev/null +++ b/Session_7/5_data_clean.ipynb @@ -0,0 +1,1947 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cleaning Data\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [Intro](https://datascience.quantecon.org/intro.html) \n", + "- [Boolean selection](https://datascience.quantecon.org/basics.html) \n", + "- [Indexing](https://datascience.quantecon.org/the_index.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Be able to use string methods to clean data that comes as a string \n", + "- Be able to drop missing data \n", + "- Use cleaning methods to prepare and analyze a real dataset \n", + "\n", + "\n", + "**Data**\n", + "\n", + "- Item information from about 3,000 Chipotle meals from about 1,800\n", + " Grubhub orders " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: python-dateutil>=2.6.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2.8.0)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.12.0)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n" + ] + } + ], + "source": [ + "# Uncomment following line to install on colab\n", + "! pip install qeds" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import qeds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [Cleaning Data](#Cleaning-Data) \n", + " - [Cleaning Data](#Cleaning-Data) \n", + " - [String Methods](#String-Methods) \n", + " - [Type Conversions](#Type-Conversions) \n", + " - [Missing Data](#Missing-Data) \n", + " - [Case Study](#Case-Study) \n", + " - [Appendix: Performance of `.str` Methods](#Appendix:-Performance-of-`.str`-Methods) \n", + " - [Exercises](#Exercises) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cleaning Data\n", + "\n", + "For many data projects, a [significant proportion of\n", + "time](https://www.forbes.com/sites/gilpress/2016/03/23/data-preparation-most-time-consuming-least-enjoyable-data-science-task-survey-says/#74d447456f63)\n", + "is spent collecting and cleaning the data — not performing the analysis.\n", + "\n", + "This non-analysis work is often called “data cleaning”.\n", + "\n", + "pandas provides very powerful data cleaning tools, which we\n", + "will demonstrate using the following dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_column
0#2323green0
1#2424red1
2#1818yellow0
3#1414orange2
4#12NaNpurple1
5#10XYZblue0
6#3535pink2
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column\n", + "0 #23 23 green 0\n", + "1 #24 24 red 1\n", + "2 #18 18 yellow 0\n", + "3 #14 14 orange 2\n", + "4 #12 NaN purple 1\n", + "5 #10 XYZ blue 0\n", + "6 #35 35 pink 2" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame({\"numbers\": [\"#23\", \"#24\", \"#18\", \"#14\", \"#12\", \"#10\", \"#35\"],\n", + " \"nums\": [\"23\", \"24\", \"18\", \"14\", np.nan, \"XYZ\", \"35\"],\n", + " \"colors\": [\"green\", \"red\", \"yellow\", \"orange\", \"purple\", \"blue\", \"pink\"],\n", + " \"other_column\": [0, 1, 0, 2, 1, 0, 2]})\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What would happen if we wanted to try and compute the mean of\n", + "`numbers`?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + "df[\"numbers\"].mean()\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It throws an error!\n", + "\n", + "Can you figure out why?\n", + "\n", + "Hint: When looking at error messages, start at the very\n", + "bottom.\n", + "\n", + "The final error says, `TypeError: Could not convert #23#24... to numeric`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## String Methods\n", + "\n", + "Our solution to the previous exercise was to remove the `#` by using\n", + "the `replace` string method: `int(c2n.replace(\"#\", \"\"))`.\n", + "\n", + "One way to make this change to every element of a column would be to\n", + "loop through all elements of the column and apply the desired string\n", + "methods…" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wall time: 6.51 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "\n", + "# Iterate over all rows\n", + "for row in df.iterrows():\n", + "\n", + " # `iterrows` method produces a tuple with two elements...\n", + " # The first element is an index and the second is a Series with the data from that row\n", + " index_value, column_values = row\n", + "\n", + " # Apply string method\n", + " clean_number = int(column_values[\"numbers\"].replace(\"#\", \"\"))\n", + "\n", + " # The `at` method is very similar to the `loc` method, but it is specialized\n", + " # for accessing single elements at a time... We wanted to use it here to give\n", + " # the loop the best chance to beat a faster method which we show you next.\n", + " df.at[index_value, \"numbers_loop\"] = clean_number" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While this is fast for a small dataset like this, this method slows for larger datasets.\n", + "\n", + "One *significantly* faster (and easier) method is to apply a string\n", + "method to an entire column of data.\n", + "\n", + "Most methods that are available to a Python string (we learned a\n", + "few of them in the [strings lecture](https://datascience.quantecon.org/../python_fundamentals/basics.html)) are\n", + "also available to a pandas Series that has `dtype` object.\n", + "\n", + "We access them by doing `s.str.method_name` where `method_name` is\n", + "the name of the method.\n", + "\n", + "When we apply the method to a Series, it is applied to all rows in the\n", + "Series in one shot!\n", + "\n", + "Let’s redo our previous example using a pandas `.str` method." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wall time: 0 ns\n" + ] + } + ], + "source": [ + "%%time\n", + "\n", + "# ~2x faster than loop... However, speed gain increases with size of DataFrame. The\n", + "# speedup can be in the ballpark of ~100-500x faster for big DataFrames.\n", + "# See appendix at the end of the lecture for an application on a larger DataFrame\n", + "df[\"numbers_str\"] = df[\"numbers\"].str.replace(\"#\", \"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use `.str` to access almost any string method that works on\n", + "normal strings. (See the [official\n", + "documentation](https://pandas.pydata.org/pandas-docs/stable/text.html)\n", + "for more information.)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0 False\n", + "1 False\n", + "2 False\n", + "3 False\n", + "4 True\n", + "5 False\n", + "6 True\n", + "Name: colors, dtype: bool" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"colors\"].str.contains(\"p\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0 Green\n", + "1 Red\n", + "2 Yellow\n", + "3 Orange\n", + "4 Purple\n", + "5 Blue\n", + "6 Pink\n", + "Name: colors, dtype: object" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"colors\"].str.capitalize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Type Conversions\n", + "\n", + "In our example above, the `dtype` of the `numbers_str` column shows that pandas still treats\n", + "it as a string even after we have removed the `\"#\"`.\n", + "\n", + "We need to convert this column to numbers.\n", + "\n", + "The best way to do this is using the `pd.to_numeric` function.\n", + "\n", + "This method attempts to convert whatever is stored in a Series into\n", + "numeric values\n", + "\n", + "For example, after the `\"#\"` removed, the numbers of column\n", + "`\"numbers\"` are ready to be converted to actual numbers." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "df[\"numbers_numeric\"] = pd.to_numeric(df[\"numbers_str\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "numbers object\n", + "nums object\n", + "colors object\n", + "other_column int64\n", + "numbers_loop float64\n", + "numbers_str object\n", + "numbers_numeric int64\n", + "dtype: object" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columnnumbers_loopnumbers_strnumbers_numeric
0#2323green023.02323
1#2424red124.02424
2#1818yellow018.01818
3#1414orange214.01414
4#12NaNpurple112.01212
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column numbers_loop numbers_str \\\n", + "0 #23 23 green 0 23.0 23 \n", + "1 #24 24 red 1 24.0 24 \n", + "2 #18 18 yellow 0 18.0 18 \n", + "3 #14 14 orange 2 14.0 14 \n", + "4 #12 NaN purple 1 12.0 12 \n", + "\n", + " numbers_numeric \n", + "0 23 \n", + "1 24 \n", + "2 18 \n", + "3 14 \n", + "4 12 " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can convert to other types well.\n", + "\n", + "Using the `astype` method, we can convert to any of the supported\n", + "pandas `dtypes` (recall the [intro lecture](https://datascience.quantecon.org/intro.html)).\n", + "\n", + "Below are some examples. (Pay attention to the reported `dtype`)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0 23\n", + "1 24\n", + "2 18\n", + "3 14\n", + "4 12\n", + "5 10\n", + "6 35\n", + "Name: numbers_numeric, dtype: object" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"numbers_numeric\"].astype(str)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0 23.0\n", + "1 24.0\n", + "2 18.0\n", + "3 14.0\n", + "4 12.0\n", + "5 10.0\n", + "6 35.0\n", + "Name: numbers_numeric, dtype: float64" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"numbers_numeric\"].astype(float)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Missing Data\n", + "\n", + "Many datasets have missing data.\n", + "\n", + "In our example, we are missing an element from the `\"nums\"` column." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columnnumbers_loopnumbers_strnumbers_numeric
0#2323green023.02323
1#2424red124.02424
2#1818yellow018.01818
3#1414orange214.01414
4#12NaNpurple112.01212
5#10XYZblue010.01010
6#3535pink235.03535
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column numbers_loop numbers_str \\\n", + "0 #23 23 green 0 23.0 23 \n", + "1 #24 24 red 1 24.0 24 \n", + "2 #18 18 yellow 0 18.0 18 \n", + "3 #14 14 orange 2 14.0 14 \n", + "4 #12 NaN purple 1 12.0 12 \n", + "5 #10 XYZ blue 0 10.0 10 \n", + "6 #35 35 pink 2 35.0 35 \n", + "\n", + " numbers_numeric \n", + "0 23 \n", + "1 24 \n", + "2 18 \n", + "3 14 \n", + "4 12 \n", + "5 10 \n", + "6 35 " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can find missing data by using the `isnull` method." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columnnumbers_loopnumbers_strnumbers_numeric
0FalseFalseFalseFalseFalseFalseFalse
1FalseFalseFalseFalseFalseFalseFalse
2FalseFalseFalseFalseFalseFalseFalse
3FalseFalseFalseFalseFalseFalseFalse
4FalseTrueFalseFalseFalseFalseFalse
5FalseFalseFalseFalseFalseFalseFalse
6FalseFalseFalseFalseFalseFalseFalse
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column numbers_loop numbers_str \\\n", + "0 False False False False False False \n", + "1 False False False False False False \n", + "2 False False False False False False \n", + "3 False False False False False False \n", + "4 False True False False False False \n", + "5 False False False False False False \n", + "6 False False False False False False \n", + "\n", + " numbers_numeric \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False \n", + "5 False \n", + "6 False " + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.isnull()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We might want to know whether particular rows or columns have any\n", + "missing data.\n", + "\n", + "To do this we can use the `.any` method on the boolean DataFrame\n", + "`df.isnull()`." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "numbers False\n", + "nums True\n", + "colors False\n", + "other_column False\n", + "numbers_loop False\n", + "numbers_str False\n", + "numbers_numeric False\n", + "dtype: bool" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.isnull().any(axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0 False\n", + "1 False\n", + "2 False\n", + "3 False\n", + "4 True\n", + "5 False\n", + "6 False\n", + "dtype: bool" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.isnull().any(axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Many approaches have been developed to deal with missing data, but the two most commonly used (and the corresponding DataFrame method) are:\n", + "\n", + "- Exclusion: Ignore any data that is missing (`.dropna`). \n", + "- Imputation: Compute “predicted” values for the data that is missing\n", + " (`.fillna`). \n", + "\n", + "\n", + "For the advantages and disadvantages of these (and other) approaches,\n", + "consider reading the [Wikipedia\n", + "article](https://en.wikipedia.org/wiki/Missing_data).\n", + "\n", + "For now, let’s see some examples." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columnnumbers_loopnumbers_strnumbers_numeric
0#2323green023.02323
1#2424red124.02424
2#1818yellow018.01818
3#1414orange214.01414
5#10XYZblue010.01010
6#3535pink235.03535
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column numbers_loop numbers_str \\\n", + "0 #23 23 green 0 23.0 23 \n", + "1 #24 24 red 1 24.0 24 \n", + "2 #18 18 yellow 0 18.0 18 \n", + "3 #14 14 orange 2 14.0 14 \n", + "5 #10 XYZ blue 0 10.0 10 \n", + "6 #35 35 pink 2 35.0 35 \n", + "\n", + " numbers_numeric \n", + "0 23 \n", + "1 24 \n", + "2 18 \n", + "3 14 \n", + "5 10 \n", + "6 35 " + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# drop all rows containing a missing observation\n", + "df.dropna()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columnnumbers_loopnumbers_strnumbers_numeric
0#2323green023.02323
1#2424red124.02424
2#1818yellow018.01818
3#1414orange214.01414
4#12100purple112.01212
5#10XYZblue010.01010
6#3535pink235.03535
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column numbers_loop numbers_str \\\n", + "0 #23 23 green 0 23.0 23 \n", + "1 #24 24 red 1 24.0 24 \n", + "2 #18 18 yellow 0 18.0 18 \n", + "3 #14 14 orange 2 14.0 14 \n", + "4 #12 100 purple 1 12.0 12 \n", + "5 #10 XYZ blue 0 10.0 10 \n", + "6 #35 35 pink 2 35.0 35 \n", + "\n", + " numbers_numeric \n", + "0 23 \n", + "1 24 \n", + "2 18 \n", + "3 14 \n", + "4 12 \n", + "5 10 \n", + "6 35 " + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# fill the missing values with a specific value\n", + "df.fillna(value=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columnnumbers_loopnumbers_strnumbers_numeric
0#2323green023.02323
1#2424red124.02424
2#1818yellow018.01818
3#1414orange214.01414
4#12XYZpurple112.01212
5#10XYZblue010.01010
6#3535pink235.03535
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column numbers_loop numbers_str \\\n", + "0 #23 23 green 0 23.0 23 \n", + "1 #24 24 red 1 24.0 24 \n", + "2 #18 18 yellow 0 18.0 18 \n", + "3 #14 14 orange 2 14.0 14 \n", + "4 #12 XYZ purple 1 12.0 12 \n", + "5 #10 XYZ blue 0 10.0 10 \n", + "6 #35 35 pink 2 35.0 35 \n", + "\n", + " numbers_numeric \n", + "0 23 \n", + "1 24 \n", + "2 18 \n", + "3 14 \n", + "4 12 \n", + "5 10 \n", + "6 35 " + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# use the _next_ valid observation to fill the missing data\n", + "df.fillna(method=\"bfill\")" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columnnumbers_loopnumbers_strnumbers_numeric
0#2323green023.02323
1#2424red124.02424
2#1818yellow018.01818
3#1414orange214.01414
4#1214purple112.01212
5#10XYZblue010.01010
6#3535pink235.03535
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column numbers_loop numbers_str \\\n", + "0 #23 23 green 0 23.0 23 \n", + "1 #24 24 red 1 24.0 24 \n", + "2 #18 18 yellow 0 18.0 18 \n", + "3 #14 14 orange 2 14.0 14 \n", + "4 #12 14 purple 1 12.0 12 \n", + "5 #10 XYZ blue 0 10.0 10 \n", + "6 #35 35 pink 2 35.0 35 \n", + "\n", + " numbers_numeric \n", + "0 23 \n", + "1 24 \n", + "2 18 \n", + "3 14 \n", + "4 12 \n", + "5 10 \n", + "6 35 " + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# use the _previous_ valid observation to fill missing data\n", + "df.fillna(method=\"ffill\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will see more examples of dealing with missing data in future\n", + "chapters." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case Study\n", + "\n", + "We will now use data from an\n", + "[article](https://www.nytimes.com/interactive/2015/02/17/upshot/what-do-people-actually-order-at-chipotle.html)\n", + "written by The Upshot at the NYTimes.\n", + "\n", + "This data has order information from almost 2,000 Chipotle orders and\n", + "includes information on what was ordered and how much it cost." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
order_idquantityitem_namechoice_descriptionitem_price
011Chips and Fresh Tomato SalsaNaN$2.39
111Izze[Clementine]$3.39
211Nantucket Nectar[Apple]$3.39
311Chips and Tomatillo-Green Chili SalsaNaN$2.39
422Chicken Bowl[Tomatillo-Red Chili Salsa (Hot), [Black Beans...$16.98
\n", + "
" + ], + "text/plain": [ + " order_id quantity item_name \\\n", + "0 1 1 Chips and Fresh Tomato Salsa \n", + "1 1 1 Izze \n", + "2 1 1 Nantucket Nectar \n", + "3 1 1 Chips and Tomatillo-Green Chili Salsa \n", + "4 2 2 Chicken Bowl \n", + "\n", + " choice_description item_price \n", + "0 NaN $2.39 \n", + "1 [Clementine] $3.39 \n", + "2 [Apple] $3.39 \n", + "3 NaN $2.39 \n", + "4 [Tomatillo-Red Chili Salsa (Hot), [Black Beans... $16.98 " + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chipotle = qeds.data.load(\"chipotle_raw\")\n", + "chipotle.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Appendix: Performance of `.str` Methods\n", + "\n", + "Let’s repeat the “remove the `#`” example from above, but this time on\n", + "a much larger dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
floatsstrings
015.5215.52%
197.9897.98%
277.8177.81%
372.9972.99%
428.4728.47%
\n", + "
" + ], + "text/plain": [ + " floats strings\n", + "0 15.52 15.52%\n", + "1 97.98 97.98%\n", + "2 77.81 77.81%\n", + "3 72.99 72.99%\n", + "4 28.47 28.47%" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "test = pd.DataFrame({\"floats\": np.round(100*np.random.rand(100000), 2)})\n", + "test[\"strings\"] = test[\"floats\"].astype(str) + \"%\"\n", + "test.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wall time: 19.6 s\n" + ] + } + ], + "source": [ + "%%time\n", + "\n", + "for row in test.iterrows():\n", + " index_value, column_values = row\n", + " clean_number = column_values[\"strings\"].replace(\"%\", \"\")\n", + " test.at[index_value, \"numbers_loop\"] = clean_number" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wall time: 62.3 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "test[\"numbers_str_method\"] = test[\"strings\"].str.replace(\"%\", \"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test[\"numbers_str_method\"].equals(test[\"numbers_loop\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We got the exact same result in a fraction of the time!" + ] + } + ], + "metadata": { + "date": 1584040759.478476, + "filename": "data_clean.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "Cleaning Data" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/5_data_clean_exercises.ipynb b/Session_7/5_data_clean_exercises.ipynb new file mode 100644 index 0000000..746e4e2 --- /dev/null +++ b/Session_7/5_data_clean_exercises.ipynb @@ -0,0 +1,915 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (1.12.0)\n", + "Requirement already satisfied: python-dateutil in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (2.8.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import pandas as pd\n", + "import numpy as np\n", + "import qeds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cleaning Data - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Convert the string below into a number.**" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "39.0\n" + ] + } + ], + "source": [ + "c2n = \"#39\"\n", + "\n", + "new_c2n = c2n.replace(\"#\", \"\")\n", + "\n", + "print(float(new_c2n))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercises 2-3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For these exercises, we create the following DataFrame:**" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_column
0#2323green0
1#2424red1
2#1818yellow0
3#1414orange2
4#12NaNpurple1
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column\n", + "0 #23 23 green 0\n", + "1 #24 24 red 1\n", + "2 #18 18 yellow 0\n", + "3 #14 14 orange 2\n", + "4 #12 NaN purple 1" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame({\"numbers\": [\"#23\", \"#24\", \"#18\", \"#14\", \"#12\", \"#10\", \"#35\"],\n", + " \"nums\": [\"23\", \"24\", \"18\", \"14\", np.nan, \"XYZ\", \"35\"],\n", + " \"colors\": [\"green\", \"red\", \"yellow\", \"orange\", \"purple\", \"blue\", \"pink\"],\n", + " \"other_column\": [0, 1, 0, 2, 1, 0, 2]})\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " **Make a new column called `colors_upper` that contains the elements of `colors` with all uppercase letters.**" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columncolors_upper
0#2323green0GREEN
1#2424red1RED
2#1818yellow0YELLOW
3#1414orange2ORANGE
4#12NaNpurple1PURPLE
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column colors_upper\n", + "0 #23 23 green 0 GREEN\n", + "1 #24 24 red 1 RED\n", + "2 #18 18 yellow 0 YELLOW\n", + "3 #14 14 orange 2 ORANGE\n", + "4 #12 NaN purple 1 PURPLE" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df['colors_upper']=df['colors'].str.upper()\n", + "df.head()\n", + "\n", + "#if we want only the first letter as capital letter \n", + "#df['colors_upper'] = df[\"colors\"].str.capitalize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Convert the column `\"nums\"` to a numeric type using `pd.to_numeric` and save it to the DataFrame as `\"nums_tonumeric\"`.**\n", + "\n", + " - Notice that there is a missing value, and a value that is not a number. Look at the documentation for `pd.to_numeric` and think about how to overcome this." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
numbersnumscolorsother_columncolors_uppernums_tonumeric
0#2323green0GREEN23.0
1#2424red1RED24.0
2#1818yellow0YELLOW18.0
3#1414orange2ORANGE14.0
4#12NaNpurple1PURPLENaN
5#10XYZblue0BLUENaN
6#3535pink2PINK35.0
\n", + "
" + ], + "text/plain": [ + " numbers nums colors other_column colors_upper nums_tonumeric\n", + "0 #23 23 green 0 GREEN 23.0\n", + "1 #24 24 red 1 RED 24.0\n", + "2 #18 18 yellow 0 YELLOW 18.0\n", + "3 #14 14 orange 2 ORANGE 14.0\n", + "4 #12 NaN purple 1 PURPLE NaN\n", + "5 #10 XYZ blue 0 BLUE NaN\n", + "6 #35 35 pink 2 PINK 35.0" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"nums_tonumeric\"] = pd.to_numeric(df[\"nums\"], errors='coerce')\n", + "df\n", + "# errors \"coerce\" means that we force the conversion of string to NaN" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Think about why this could be a bad idea of used without knowing what your data looks like. (Think about what happens when you apply it to the `\"numbers\"` column before replacing the `\"#\"`.)**" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "#that would set all values to NaN" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For this exercise, we use data from an article written by The Upshot at the NYTimes, which has order information from almost 2,000 Chipotle orders and includes information on what was ordered and how much it cost.**" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
order_idquantityitem_namechoice_descriptionitem_price
011Chips and Fresh Tomato SalsaNaN$2.39
111Izze[Clementine]$3.39
211Nantucket Nectar[Apple]$3.39
311Chips and Tomatillo-Green Chili SalsaNaN$2.39
422Chicken Bowl[Tomatillo-Red Chili Salsa (Hot), [Black Beans...$16.98
\n", + "
" + ], + "text/plain": [ + " order_id quantity item_name \\\n", + "0 1 1 Chips and Fresh Tomato Salsa \n", + "1 1 1 Izze \n", + "2 1 1 Nantucket Nectar \n", + "3 1 1 Chips and Tomatillo-Green Chili Salsa \n", + "4 2 2 Chicken Bowl \n", + "\n", + " choice_description item_price \n", + "0 NaN $2.39 \n", + "1 [Clementine] $3.39 \n", + "2 [Apple] $3.39 \n", + "3 NaN $2.39 \n", + "4 [Tomatillo-Red Chili Salsa (Hot), [Black Beans... $16.98 " + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chipotle = qeds.data.load(\"chipotle_raw\")\n", + "chipotle.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Make sure the `item_price` column has a numeric `dtype` (probably float).**" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
order_idquantityitem_namechoice_descriptionitem_priceitem_price_numeric
011Chips and Fresh Tomato SalsaNaN$2.392.39
111Izze[Clementine]$3.393.39
211Nantucket Nectar[Apple]$3.393.39
311Chips and Tomatillo-Green Chili SalsaNaN$2.392.39
422Chicken Bowl[Tomatillo-Red Chili Salsa (Hot), [Black Beans...$16.9816.98
\n", + "
" + ], + "text/plain": [ + " order_id quantity item_name \\\n", + "0 1 1 Chips and Fresh Tomato Salsa \n", + "1 1 1 Izze \n", + "2 1 1 Nantucket Nectar \n", + "3 1 1 Chips and Tomatillo-Green Chili Salsa \n", + "4 2 2 Chicken Bowl \n", + "\n", + " choice_description item_price \\\n", + "0 NaN $2.39 \n", + "1 [Clementine] $3.39 \n", + "2 [Apple] $3.39 \n", + "3 NaN $2.39 \n", + "4 [Tomatillo-Red Chili Salsa (Hot), [Black Beans... $16.98 \n", + "\n", + " item_price_numeric \n", + "0 2.39 \n", + "1 3.39 \n", + "2 3.39 \n", + "3 2.39 \n", + "4 16.98 " + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chipotle[\"item_price_numeric\"] = pd.to_numeric(chipotle[\"item_price\"].str.replace(\"$\", \"\"))\n", + "chipotle.dtypes\n", + "chipotle.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **What is the average price of an item with chicken?**" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10.133724358974309" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chipotle.loc[chipotle['item_name'].str.match('Chicken'),\"item_price_numeric\"].mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **What is the average price of an item with steak?** " + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10.518888888888851" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chipotle.loc[chipotle['item_name'].str.match('Steak'),\"item_price_numeric\"].mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. **Did chicken or steak produce more revenue (total)?** " + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chipotle.loc[chipotle['item_name'].str.match('Chicken'),\"item_price_numeric\"].sum()>chipotle.loc[chipotle['item_name'].str.match('Steak'),\"item_price_numeric\"].sum()\n", + "\n", + "#we create a boolean which confirms that chicken produces more total revenue compared to steak" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Product containing steak generated a revenue of 8072.619999999973 dollars\n", + "Product containing chicken generated a revenue of 17742.14999999992 dollars\n" + ] + } + ], + "source": [ + "#Alternative solution:\n", + "chipotle['revenue']=chipotle['item_price_numeric']*chipotle['quantity']\n", + "\n", + "steak= chipotle[chipotle['item_name'].str.contains(pat='Steak')].sum()\n", + "print('Product containing steak generated a revenue of', steak.loc['revenue'], 'dollars')\n", + "steak= chipotle[chipotle['item_name'].str.contains(pat='Chicken')].sum()\n", + "print('Product containing chicken generated a revenue of', steak.loc['revenue'], 'dollars')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "5. **How many missing items are there in this dataset? How many missing items in each column?**" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1246" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#in the dataset\n", + "chipotle.isnull().sum().sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "order_id 0\n", + "quantity 0\n", + "item_name 0\n", + "choice_description 1246\n", + "item_price 0\n", + "item_price_numeric 0\n", + "revenue 0\n", + "dtype: int64" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#in each column\n", + "chipotle.isnull().sum()" + ] + } + ], + "metadata": { + "date": 1584040759.478476, + "filename": "data_clean.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "Cleaning Data" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/6_reshape.ipynb b/Session_7/6_reshape.ipynb new file mode 100644 index 0000000..c7a6948 --- /dev/null +++ b/Session_7/6_reshape.ipynb @@ -0,0 +1,5296 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reshape\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [pandas intro](https://datascience.quantecon.org/intro.html) \n", + "- [pandas basics](https://datascience.quantecon.org/basics.html) \n", + "- [Importance of index](https://datascience.quantecon.org/the_index.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Understand and be able to apply the `melt`/`stack`/`unstack`/`pivot` methods \n", + "- Practice transformations of indices \n", + "- Understand tidy data " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.12.0)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: python-dateutil>=2.6.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2.8.0)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n" + ] + } + ], + "source": [ + "# Uncomment following line to install on colab\n", + "! pip install qeds" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "%matplotlib inline\n", + "# activate plot theme\n", + "import qeds\n", + "qeds.themes.mpl_style();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [Reshape](#Reshape) \n", + " - [Tidy Data](#Tidy-Data) \n", + " - [Reshaping your Data](#Reshaping-your-Data) \n", + " - [Long vs Wide](#Long-vs-Wide) \n", + " - [`set_index`, `reset_index`, and Transpose](#`set_index`,-`reset_index`,-and-Transpose) \n", + " - [`stack` and `unstack`](#`stack`-and-`unstack`) \n", + " - [`melt`](#`melt`) \n", + " - [`pivot` and `pivot_table`](#`pivot`-and-`pivot_table`) \n", + " - [Visualizing Reshaping](#Visualizing-Reshaping) \n", + " - [Exercises](#Exercises) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tidy Data\n", + "\n", + "While pushed more generally in the `R` language, the concept of “[tidy data](https://en.wikipedia.org/wiki/Tidy_data)” is helpful in understanding the\n", + "objectives for reshaping data, which in turn makes advanced features like\n", + "[GroupBy](https://datascience.quantecon.org/groupby.html) more seamless.\n", + "\n", + "Hadley Wickham gives a terminology slightly better-adapted for the experimental\n", + "sciences, but nevertheless useful for the social sciences.\n", + "\n", + "> A dataset is a collection of values, usually either numbers (if\n", + "quantitative) or strings (if qualitative). Values are organized in two\n", + "ways. Every value belongs to a variable and an observation. A variable\n", + "contains all values that measure the same underlying attribute (like\n", + "height, temperature, duration) across units. An observation contains all\n", + "values measured on the same unit (like a person, or a day, or a race)\n", + "across attributes. – [Tidy Data (Journal of Statistical Software 2013)](https://www.jstatsoft.org/index.php/jss/article/view/v059i10/v59i10.pdf)\n", + "\n", + "\n", + "With this framing,\n", + "\n", + "> A dataset is messy or tidy depending on how rows, columns and tables are\n", + "matched with observations, variables, and types. In tidy data:\n", + "1. Each variable forms a column.\n", + "2. Each observation forms a row.\n", + "3. Each type of observational unit forms a table.\n", + "\n", + "\n", + "The “column” and “row” terms map directly to pandas columns and rows, while the\n", + "“table” maps to a pandas DataFrame.\n", + "\n", + "With this thinking and interpretation, it becomes essential to think through\n", + "what uniquely identifies an “observation” in your data.\n", + "\n", + "Is it a country? A year? A combination of country and year?\n", + "\n", + "These will become the indices of your DataFrame.\n", + "\n", + "For those with more of a database background, the “tidy” format matches the\n", + "[3rd normal form](https://en.wikipedia.org/wiki/Third_normal_form) in\n", + "database theory, where the referential integrity of the database is maintained\n", + "by the uniqueness of the index.\n", + "\n", + "When considering how to map this to the social sciences, note that\n", + "reshaping data can change what we consider to be the variable and\n", + "observation in a way that doesn’t occur within the natural sciences.\n", + "\n", + "For example, if the “observation” uniquely identified by a country and year and\n", + "the “variable” is GDP, you may wish to reshape it so that the “observable” is a\n", + "country, and the variables are a GDP for each year.\n", + "\n", + "A word of caution: The tidy approach, where there is no redundancy and each\n", + "type of observational unit forms a table, is a good approach for storing data,\n", + "but you will frequently reshape/merge/etc. in order to make graphing or\n", + "analysis easier. This doesn’t break the tidy format since those examples are\n", + "ephemeral states used in analysis." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reshaping your Data\n", + "\n", + "The data you receive is not always in a “shape” that makes it easy to analyze.\n", + "\n", + "What do we mean by shape? The number of rows and columns in a\n", + "DataFrame and how information is stored in the index and column names.\n", + "\n", + "This lecture will teach you the basic concepts of reshaping data.\n", + "\n", + "As with other topics, we recommend reviewing the [pandas\n", + "documentation](https://pandas.pydata.org/pandas-docs/stable/reshaping.html)\n", + "on this subject for additional information.\n", + "\n", + "We will keep our discussion here as brief and simple as possible because\n", + "these tools will reappear in subsequent lectures." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 9 entries, 0 to 8\n", + "Data columns (total 8 columns):\n", + "Year 9 non-null int64\n", + "Player 9 non-null object\n", + "Team 9 non-null object\n", + "TeamName 9 non-null object\n", + "Games 9 non-null int64\n", + "Pts 9 non-null float64\n", + "Assist 9 non-null float64\n", + "Rebound 9 non-null float64\n", + "dtypes: float64(3), int64(2), object(3)\n", + "memory usage: 704.0+ bytes\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNameGamesPtsAssistRebound
02015CurryGSWWarriors7930.16.75.4
12016CurryGSWWarriors7925.36.64.5
22017CurryGSWWarriors5126.46.15.1
32015DurantOKCThunder7228.25.08.2
42016DurantGSWWarriors6225.14.88.3
52017DurantGSWWarriors6826.45.46.8
62015IbakaOKCThunder7812.60.86.8
72016IbakaORLMagic5615.11.16.8
82016IbakaTORRaptors2314.20.76.8
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName Games Pts Assist Rebound\n", + "0 2015 Curry GSW Warriors 79 30.1 6.7 5.4\n", + "1 2016 Curry GSW Warriors 79 25.3 6.6 4.5\n", + "2 2017 Curry GSW Warriors 51 26.4 6.1 5.1\n", + "3 2015 Durant OKC Thunder 72 28.2 5.0 8.2\n", + "4 2016 Durant GSW Warriors 62 25.1 4.8 8.3\n", + "5 2017 Durant GSW Warriors 68 26.4 5.4 6.8\n", + "6 2015 Ibaka OKC Thunder 78 12.6 0.8 6.8\n", + "7 2016 Ibaka ORL Magic 56 15.1 1.1 6.8\n", + "8 2016 Ibaka TOR Raptors 23 14.2 0.7 6.8" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = \"https://datascience.quantecon.org/assets/data/bball.csv\"\n", + "bball = pd.read_csv(url)\n", + "bball.info()\n", + "\n", + "bball" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Long vs Wide\n", + "\n", + "Many of these operations change between long and wide DataFrames.\n", + "\n", + "What does it mean for a DataFrame to be long or wide?\n", + "\n", + "Here is long possible long-form representation of our basketball data." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNamevariablevalue
02015CurryGSWWarriorsGames79.0
12016CurryGSWWarriorsGames79.0
22017CurryGSWWarriorsGames51.0
32015DurantOKCThunderGames72.0
42016DurantGSWWarriorsGames62.0
52017DurantGSWWarriorsGames68.0
62015IbakaOKCThunderGames78.0
72016IbakaORLMagicGames56.0
82016IbakaTORRaptorsGames23.0
92015CurryGSWWarriorsPts30.1
102016CurryGSWWarriorsPts25.3
112017CurryGSWWarriorsPts26.4
122015DurantOKCThunderPts28.2
132016DurantGSWWarriorsPts25.1
142017DurantGSWWarriorsPts26.4
152015IbakaOKCThunderPts12.6
162016IbakaORLMagicPts15.1
172016IbakaTORRaptorsPts14.2
182015CurryGSWWarriorsAssist6.7
192016CurryGSWWarriorsAssist6.6
202017CurryGSWWarriorsAssist6.1
212015DurantOKCThunderAssist5.0
222016DurantGSWWarriorsAssist4.8
232017DurantGSWWarriorsAssist5.4
242015IbakaOKCThunderAssist0.8
252016IbakaORLMagicAssist1.1
262016IbakaTORRaptorsAssist0.7
272015CurryGSWWarriorsRebound5.4
282016CurryGSWWarriorsRebound4.5
292017CurryGSWWarriorsRebound5.1
302015DurantOKCThunderRebound8.2
312016DurantGSWWarriorsRebound8.3
322017DurantGSWWarriorsRebound6.8
332015IbakaOKCThunderRebound6.8
342016IbakaORLMagicRebound6.8
352016IbakaTORRaptorsRebound6.8
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName variable value\n", + "0 2015 Curry GSW Warriors Games 79.0\n", + "1 2016 Curry GSW Warriors Games 79.0\n", + "2 2017 Curry GSW Warriors Games 51.0\n", + "3 2015 Durant OKC Thunder Games 72.0\n", + "4 2016 Durant GSW Warriors Games 62.0\n", + "5 2017 Durant GSW Warriors Games 68.0\n", + "6 2015 Ibaka OKC Thunder Games 78.0\n", + "7 2016 Ibaka ORL Magic Games 56.0\n", + "8 2016 Ibaka TOR Raptors Games 23.0\n", + "9 2015 Curry GSW Warriors Pts 30.1\n", + "10 2016 Curry GSW Warriors Pts 25.3\n", + "11 2017 Curry GSW Warriors Pts 26.4\n", + "12 2015 Durant OKC Thunder Pts 28.2\n", + "13 2016 Durant GSW Warriors Pts 25.1\n", + "14 2017 Durant GSW Warriors Pts 26.4\n", + "15 2015 Ibaka OKC Thunder Pts 12.6\n", + "16 2016 Ibaka ORL Magic Pts 15.1\n", + "17 2016 Ibaka TOR Raptors Pts 14.2\n", + "18 2015 Curry GSW Warriors Assist 6.7\n", + "19 2016 Curry GSW Warriors Assist 6.6\n", + "20 2017 Curry GSW Warriors Assist 6.1\n", + "21 2015 Durant OKC Thunder Assist 5.0\n", + "22 2016 Durant GSW Warriors Assist 4.8\n", + "23 2017 Durant GSW Warriors Assist 5.4\n", + "24 2015 Ibaka OKC Thunder Assist 0.8\n", + "25 2016 Ibaka ORL Magic Assist 1.1\n", + "26 2016 Ibaka TOR Raptors Assist 0.7\n", + "27 2015 Curry GSW Warriors Rebound 5.4\n", + "28 2016 Curry GSW Warriors Rebound 4.5\n", + "29 2017 Curry GSW Warriors Rebound 5.1\n", + "30 2015 Durant OKC Thunder Rebound 8.2\n", + "31 2016 Durant GSW Warriors Rebound 8.3\n", + "32 2017 Durant GSW Warriors Rebound 6.8\n", + "33 2015 Ibaka OKC Thunder Rebound 6.8\n", + "34 2016 Ibaka ORL Magic Rebound 6.8\n", + "35 2016 Ibaka TOR Raptors Rebound 6.8" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Don't worry about what this command does -- We'll see it soon\n", + "bball_long = bball.melt(id_vars=[\"Year\", \"Player\", \"Team\", \"TeamName\"])\n", + "\n", + "bball_long" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And here is a wide-form version." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant...Ibaka
variableAssistGamesPtsReboundAssistGamesPts...AssistGamesPtsRebound
TeamGSWGSWGSWGSWGSWOKCGSWOKCGSWOKC...TOROKCORLTOROKCORLTOROKCORLTOR
Year
20156.779.030.15.4NaN5.0NaN72.0NaN28.2...NaN78.0NaNNaN12.6NaNNaN6.8NaNNaN
20166.679.025.34.54.8NaN62.0NaN25.1NaN...0.7NaN56.023.0NaN15.114.2NaN6.86.8
20176.151.026.45.15.4NaN68.0NaN26.4NaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + "Player Curry Durant ... \\\n", + "variable Assist Games Pts Rebound Assist Games Pts ... \n", + "Team GSW GSW GSW GSW GSW OKC GSW OKC GSW OKC ... \n", + "Year ... \n", + "2015 6.7 79.0 30.1 5.4 NaN 5.0 NaN 72.0 NaN 28.2 ... \n", + "2016 6.6 79.0 25.3 4.5 4.8 NaN 62.0 NaN 25.1 NaN ... \n", + "2017 6.1 51.0 26.4 5.1 5.4 NaN 68.0 NaN 26.4 NaN ... \n", + "\n", + "Player Ibaka \n", + "variable Assist Games Pts Rebound \n", + "Team TOR OKC ORL TOR OKC ORL TOR OKC ORL TOR \n", + "Year \n", + "2015 NaN 78.0 NaN NaN 12.6 NaN NaN 6.8 NaN NaN \n", + "2016 0.7 NaN 56.0 23.0 NaN 15.1 14.2 NaN 6.8 6.8 \n", + "2017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Again, don't worry about this command... We'll see it soon too\n", + "bball_wide = bball_long.pivot_table(\n", + " index=\"Year\",\n", + " columns=[\"Player\", \"variable\", \"Team\"],\n", + " values=\"value\"\n", + ")\n", + "bball_wide" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `set_index`, `reset_index`, and Transpose\n", + "\n", + "We have already seen a few basic methods for reshaping a\n", + "DataFrame.\n", + "\n", + "- `set_index`: Move one or more columns into the index. \n", + "- `reset_index`: Move one or more index levels out of the index and make\n", + " them either columns or drop from DataFrame. \n", + "- `T`: Swap row and column labels. \n", + "\n", + "\n", + "Sometimes, the simplest approach is the right approach.\n", + "\n", + "Let’s review them briefly." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TeamTeamNameGamesPtsAssistRebound
PlayerYear
Curry2015GSWWarriors7930.16.75.4
2016GSWWarriors7925.36.64.5
2017GSWWarriors5126.46.15.1
Durant2015OKCThunder7228.25.08.2
2016GSWWarriors6225.14.88.3
\n", + "
" + ], + "text/plain": [ + " Team TeamName Games Pts Assist Rebound\n", + "Player Year \n", + "Curry 2015 GSW Warriors 79 30.1 6.7 5.4\n", + " 2016 GSW Warriors 79 25.3 6.6 4.5\n", + " 2017 GSW Warriors 51 26.4 6.1 5.1\n", + "Durant 2015 OKC Thunder 72 28.2 5.0 8.2\n", + " 2016 GSW Warriors 62 25.1 4.8 8.3" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball2 = bball.set_index([\"Player\", \"Year\"])\n", + "bball2.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
Year201520162017201520162017201520162016
TeamGSWGSWGSWOKCGSWGSWOKCORLTOR
TeamNameWarriorsWarriorsWarriorsThunderWarriorsWarriorsThunderMagicRaptors
Games797951726268785623
Pts30.125.326.428.225.126.412.615.114.2
Assist6.76.66.154.85.40.81.10.7
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka \\\n", + "Year 2015 2016 2017 2015 2016 2017 2015 \n", + "Team GSW GSW GSW OKC GSW GSW OKC \n", + "TeamName Warriors Warriors Warriors Thunder Warriors Warriors Thunder \n", + "Games 79 79 51 72 62 68 78 \n", + "Pts 30.1 25.3 26.4 28.2 25.1 26.4 12.6 \n", + "Assist 6.7 6.6 6.1 5 4.8 5.4 0.8 \n", + "\n", + "Player \n", + "Year 2016 2016 \n", + "Team ORL TOR \n", + "TeamName Magic Raptors \n", + "Games 56 23 \n", + "Pts 15.1 14.2 \n", + "Assist 1.1 0.7 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball3 = bball2.T\n", + "bball3.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `stack` and `unstack`\n", + "\n", + "The `stack` and `unstack` methods operate directly on the index\n", + "and/or column labels." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `stack`\n", + "\n", + "`stack` is used to move certain levels of the column labels into the\n", + "index (i.e. moving from wide to long)\n", + "\n", + "Let’s take `ball_wide` as an example." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant...Ibaka
variableAssistGamesPtsReboundAssistGamesPts...AssistGamesPtsRebound
TeamGSWGSWGSWGSWGSWOKCGSWOKCGSWOKC...TOROKCORLTOROKCORLTOROKCORLTOR
Year
20156.779.030.15.4NaN5.0NaN72.0NaN28.2...NaN78.0NaNNaN12.6NaNNaN6.8NaNNaN
20166.679.025.34.54.8NaN62.0NaN25.1NaN...0.7NaN56.023.0NaN15.114.2NaN6.86.8
20176.151.026.45.15.4NaN68.0NaN26.4NaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + "Player Curry Durant ... \\\n", + "variable Assist Games Pts Rebound Assist Games Pts ... \n", + "Team GSW GSW GSW GSW GSW OKC GSW OKC GSW OKC ... \n", + "Year ... \n", + "2015 6.7 79.0 30.1 5.4 NaN 5.0 NaN 72.0 NaN 28.2 ... \n", + "2016 6.6 79.0 25.3 4.5 4.8 NaN 62.0 NaN 25.1 NaN ... \n", + "2017 6.1 51.0 26.4 5.1 5.4 NaN 68.0 NaN 26.4 NaN ... \n", + "\n", + "Player Ibaka \n", + "variable Assist Games Pts Rebound \n", + "Team TOR OKC ORL TOR OKC ORL TOR OKC ORL TOR \n", + "Year \n", + "2015 NaN 78.0 NaN NaN 12.6 NaN NaN 6.8 NaN NaN \n", + "2016 0.7 NaN 56.0 23.0 NaN 15.1 14.2 NaN 6.8 6.8 \n", + "2017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball_wide" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Suppose that we want to be able to use the `mean` method to compute the\n", + "average value of each stat for each player, regardless of year or team.\n", + "\n", + "To do that, we need two column levels: one for the player and one for the variable.\n", + "\n", + "We can achieve this using the `stack` method." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "hide-output": false, + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
variableAssistGamesPtsReboundAssistGamesPtsReboundAssistGamesPtsRebound
YearTeam
2015GSW6.779.030.15.4NaNNaNNaNNaNNaNNaNNaNNaN
OKCNaNNaNNaNNaN5.072.028.28.20.878.012.66.8
2016GSW6.679.025.34.54.862.025.18.3NaNNaNNaNNaN
ORLNaNNaNNaNNaNNaNNaNNaNNaN1.156.015.16.8
TORNaNNaNNaNNaNNaNNaNNaNNaN0.723.014.26.8
2017GSW6.151.026.45.15.468.026.46.8NaNNaNNaNNaN
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka \\\n", + "variable Assist Games Pts Rebound Assist Games Pts Rebound Assist Games \n", + "Year Team \n", + "2015 GSW 6.7 79.0 30.1 5.4 NaN NaN NaN NaN NaN NaN \n", + " OKC NaN NaN NaN NaN 5.0 72.0 28.2 8.2 0.8 78.0 \n", + "2016 GSW 6.6 79.0 25.3 4.5 4.8 62.0 25.1 8.3 NaN NaN \n", + " ORL NaN NaN NaN NaN NaN NaN NaN NaN 1.1 56.0 \n", + " TOR NaN NaN NaN NaN NaN NaN NaN NaN 0.7 23.0 \n", + "2017 GSW 6.1 51.0 26.4 5.1 5.4 68.0 26.4 6.8 NaN NaN \n", + "\n", + "Player \n", + "variable Pts Rebound \n", + "Year Team \n", + "2015 GSW NaN NaN \n", + " OKC 12.6 6.8 \n", + "2016 GSW NaN NaN \n", + " ORL 15.1 6.8 \n", + " TOR 14.2 6.8 \n", + "2017 GSW NaN NaN " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball_wide.stack()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we can compute the statistic we are after." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Player variable\n", + "Curry Assist 6.466667\n", + " Games 69.666667\n", + " Pts 27.266667\n", + " Rebound 5.000000\n", + "Durant Assist 5.066667\n", + " Games 67.333333\n", + " Pts 26.566667\n", + " Rebound 7.766667\n", + "Ibaka Assist 0.866667\n", + " Games 52.333333\n", + " Pts 13.966667\n", + " Rebound 6.800000\n", + "dtype: float64" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player_stats = bball_wide.stack().mean()\n", + "player_stats" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now suppose instead of that we wanted to compute the average for each team and\n", + "stat, averaging over years and players.\n", + "\n", + "We’d need to move the `Player` level down into the index so we are\n", + "left with column levels for Team and variable.\n", + "\n", + "We can ask pandas do this using the `level` keyword argument." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variableAssistGamesPtsRebound
TeamGSWOKCORLTORGSWOKCORLTORGSWOKCORLTORGSWOKCORLTOR
YearPlayer
2015Curry6.7NaNNaNNaN79.0NaNNaNNaN30.1NaNNaNNaN5.4NaNNaNNaN
DurantNaN5.0NaNNaNNaN72.0NaNNaNNaN28.2NaNNaNNaN8.2NaNNaN
IbakaNaN0.8NaNNaNNaN78.0NaNNaNNaN12.6NaNNaNNaN6.8NaNNaN
2016Curry6.6NaNNaNNaN79.0NaNNaNNaN25.3NaNNaNNaN4.5NaNNaNNaN
Durant4.8NaNNaNNaN62.0NaNNaNNaN25.1NaNNaNNaN8.3NaNNaNNaN
IbakaNaNNaN1.10.7NaNNaN56.023.0NaNNaN15.114.2NaNNaN6.86.8
2017Curry6.1NaNNaNNaN51.0NaNNaNNaN26.4NaNNaNNaN5.1NaNNaNNaN
Durant5.4NaNNaNNaN68.0NaNNaNNaN26.4NaNNaNNaN6.8NaNNaNNaN
\n", + "
" + ], + "text/plain": [ + "variable Assist Games Pts \\\n", + "Team GSW OKC ORL TOR GSW OKC ORL TOR GSW OKC ORL \n", + "Year Player \n", + "2015 Curry 6.7 NaN NaN NaN 79.0 NaN NaN NaN 30.1 NaN NaN \n", + " Durant NaN 5.0 NaN NaN NaN 72.0 NaN NaN NaN 28.2 NaN \n", + " Ibaka NaN 0.8 NaN NaN NaN 78.0 NaN NaN NaN 12.6 NaN \n", + "2016 Curry 6.6 NaN NaN NaN 79.0 NaN NaN NaN 25.3 NaN NaN \n", + " Durant 4.8 NaN NaN NaN 62.0 NaN NaN NaN 25.1 NaN NaN \n", + " Ibaka NaN NaN 1.1 0.7 NaN NaN 56.0 23.0 NaN NaN 15.1 \n", + "2017 Curry 6.1 NaN NaN NaN 51.0 NaN NaN NaN 26.4 NaN NaN \n", + " Durant 5.4 NaN NaN NaN 68.0 NaN NaN NaN 26.4 NaN NaN \n", + "\n", + "variable Rebound \n", + "Team TOR GSW OKC ORL TOR \n", + "Year Player \n", + "2015 Curry NaN 5.4 NaN NaN NaN \n", + " Durant NaN NaN 8.2 NaN NaN \n", + " Ibaka NaN NaN 6.8 NaN NaN \n", + "2016 Curry NaN 4.5 NaN NaN NaN \n", + " Durant NaN 8.3 NaN NaN NaN \n", + " Ibaka 14.2 NaN NaN 6.8 6.8 \n", + "2017 Curry NaN 5.1 NaN NaN NaN \n", + " Durant NaN 6.8 NaN NaN NaN " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball_wide.stack(level=\"Player\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can compute the mean." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "variable Team\n", + "Assist GSW 5.92\n", + " OKC 2.90\n", + " ORL 1.10\n", + " TOR 0.70\n", + "Games GSW 67.80\n", + " OKC 75.00\n", + " ORL 56.00\n", + " TOR 23.00\n", + "Pts GSW 26.66\n", + " OKC 20.40\n", + " ORL 15.10\n", + " TOR 14.20\n", + "Rebound GSW 6.02\n", + " OKC 7.50\n", + " ORL 6.80\n", + " TOR 6.80\n", + "dtype: float64" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball_wide.stack(level=\"Player\").mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice a few features of the `stack` method:\n", + "\n", + "- Without any arguments, the `stack` arguments move the level of column\n", + " labels closest to the data (also called inner-most or bottom level of labels)\n", + " to become the index level closest to the data (also called the inner-most or\n", + " right-most level of the index). In our example, this moved `Team` down from\n", + " columns to the index. \n", + "- When we do pass a level, that level of column labels is moved down to the\n", + " right-most level of the index and all other column labels stay in their\n", + " relative position. \n", + "\n", + "\n", + "Note that we can also move multiple levels at a time in one call to `stack`." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variableAssistGamesPtsRebound
YearPlayerTeam
2015CurryGSW6.779.030.15.4
DurantOKC5.072.028.28.2
IbakaOKC0.878.012.66.8
2016CurryGSW6.679.025.34.5
DurantGSW4.862.025.18.3
IbakaORL1.156.015.16.8
TOR0.723.014.26.8
2017CurryGSW6.151.026.45.1
DurantGSW5.468.026.46.8
\n", + "
" + ], + "text/plain": [ + "variable Assist Games Pts Rebound\n", + "Year Player Team \n", + "2015 Curry GSW 6.7 79.0 30.1 5.4\n", + " Durant OKC 5.0 72.0 28.2 8.2\n", + " Ibaka OKC 0.8 78.0 12.6 6.8\n", + "2016 Curry GSW 6.6 79.0 25.3 4.5\n", + " Durant GSW 4.8 62.0 25.1 8.3\n", + " Ibaka ORL 1.1 56.0 15.1 6.8\n", + " TOR 0.7 23.0 14.2 6.8\n", + "2017 Curry GSW 6.1 51.0 26.4 5.1\n", + " Durant GSW 5.4 68.0 26.4 6.8" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball_wide.stack(level=[\"Player\", \"Team\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the example above, we started with one level on the index (just the year) and\n", + "stacked two levels to end up with a three-level index.\n", + "\n", + "Notice that the two new index levels went closer to the data than the existing\n", + "level and that their order matched the order we passed in our list argument to\n", + "`level`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `unstack`\n", + "\n", + "Now suppose that we wanted to see a bar chart of each player’s stats.\n", + "\n", + "This chart should have one “section” for each player and a different colored\n", + "bar for each variable.\n", + "\n", + "As we’ll learn in more detail in a later lecture, we will\n", + "need to have the player’s name on the index and the variables as columns to do this.\n", + "\n", + ">**Note**\n", + ">\n", + ">In general, for a DataFrame, calling the `plot` method will put the index\n", + "on the horizontal (x) axis and make a new line/bar/etc. for each column.\n", + "\n", + "Notice that we are close to that with the `player_stats` variable." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Player variable\n", + "Curry Assist 6.466667\n", + " Games 69.666667\n", + " Pts 27.266667\n", + " Rebound 5.000000\n", + "Durant Assist 5.066667\n", + " Games 67.333333\n", + " Pts 26.566667\n", + " Rebound 7.766667\n", + "Ibaka Assist 0.866667\n", + " Games 52.333333\n", + " Pts 13.966667\n", + " Rebound 6.800000\n", + "dtype: float64" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player_stats" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now need to rotate the variable level of the index up to be column layers.\n", + "\n", + "We use the `unstack` method for this." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variableAssistGamesPtsRebound
Player
Curry6.46666769.66666727.2666675.000000
Durant5.06666767.33333326.5666677.766667
Ibaka0.86666752.33333313.9666676.800000
\n", + "
" + ], + "text/plain": [ + "variable Assist Games Pts Rebound\n", + "Player \n", + "Curry 6.466667 69.666667 27.266667 5.000000\n", + "Durant 5.066667 67.333333 26.566667 7.766667\n", + "Ibaka 0.866667 52.333333 13.966667 6.800000" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player_stats.unstack()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can make our plot!" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "player_stats.unstack().plot.bar()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This particular visualization would be helpful if we wanted to see which stats\n", + "for which each player is strongest.\n", + "\n", + "For example, we can see that Steph Curry scores far more points than he does\n", + "rebound, but Serge Ibaka is a bit more balanced.\n", + "\n", + "What if we wanted to be able to compare all players for each statistic?\n", + "\n", + "This would be easier to do if the bars were grouped by variable, with a\n", + "different bar for each player.\n", + "\n", + "To plot this, we need to have the variables on the index and the player\n", + "name as column names.\n", + "\n", + "We can get this DataFrame by setting `level=\"Player\"` when calling `unstack`." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
variable
Assist6.4666675.0666670.866667
Games69.66666767.33333352.333333
Pts27.26666726.56666713.966667
Rebound5.0000007.7666676.800000
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka\n", + "variable \n", + "Assist 6.466667 5.066667 0.866667\n", + "Games 69.666667 67.333333 52.333333\n", + "Pts 27.266667 26.566667 13.966667\n", + "Rebound 5.000000 7.766667 6.800000" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player_stats.unstack(level=\"Player\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "player_stats.unstack(level=\"Player\").plot.bar()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can use the chart to make a number of statements about players:\n", + "\n", + "- Ibaka does not get many assists, compared to Curry and Durant. \n", + "- Steph and Kevin Durant are both high scorers. \n", + "\n", + "\n", + "Based on the examples above, notice a few things about `unstack`:\n", + "\n", + "- It is the *inverse* of `stack`; `stack` will move labels down\n", + " from columns to index, while `unstack` moves them up from index to columns. \n", + "- By default, `unstack` will move the level of the index closest to the data\n", + " and place it in the column labels closest to the data. \n", + "\n", + "\n", + ">**Note**\n", + ">\n", + ">Just as we can pass multiple levels to `stack`, we can also pass multiple\n", + "levels to `unstack`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Summary\n", + "\n", + "In some ways `set_index`, `reset_index`, `stack`, and `unstack`\n", + "are the “most fundamental” reshaping operations…\n", + "\n", + "The other operations we discuss can be formulated with these\n", + "four operations (and, in fact, some of them are exactly written as these\n", + "operations in `pandas`’s code base).\n", + "\n", + "*Pro tip*: We remember stack vs unstack with a mnemonic: **U**nstack moves index\n", + "levels **U**p" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `melt`\n", + "\n", + "The `melt` method is used to move from wide to long form.\n", + "\n", + "It can be used to move all of the “values” stored in your DataFrame to a\n", + "single column with all other columns being used to contain identifying\n", + "information.\n", + "\n", + "**Warning**: When you use `melt`, any index that you currently have\n", + "will be deleted.\n", + "\n", + "We saw used `melt` above when we constructed `bball_long`:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNameGamesPtsAssistRebound
02015CurryGSWWarriors7930.16.75.4
12016CurryGSWWarriors7925.36.64.5
22017CurryGSWWarriors5126.46.15.1
32015DurantOKCThunder7228.25.08.2
42016DurantGSWWarriors6225.14.88.3
52017DurantGSWWarriors6826.45.46.8
62015IbakaOKCThunder7812.60.86.8
72016IbakaORLMagic5615.11.16.8
82016IbakaTORRaptors2314.20.76.8
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName Games Pts Assist Rebound\n", + "0 2015 Curry GSW Warriors 79 30.1 6.7 5.4\n", + "1 2016 Curry GSW Warriors 79 25.3 6.6 4.5\n", + "2 2017 Curry GSW Warriors 51 26.4 6.1 5.1\n", + "3 2015 Durant OKC Thunder 72 28.2 5.0 8.2\n", + "4 2016 Durant GSW Warriors 62 25.1 4.8 8.3\n", + "5 2017 Durant GSW Warriors 68 26.4 5.4 6.8\n", + "6 2015 Ibaka OKC Thunder 78 12.6 0.8 6.8\n", + "7 2016 Ibaka ORL Magic 56 15.1 1.1 6.8\n", + "8 2016 Ibaka TOR Raptors 23 14.2 0.7 6.8" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNamevariablevalue
02015CurryGSWWarriorsGames79.0
12016CurryGSWWarriorsGames79.0
22017CurryGSWWarriorsGames51.0
32015DurantOKCThunderGames72.0
42016DurantGSWWarriorsGames62.0
52017DurantGSWWarriorsGames68.0
62015IbakaOKCThunderGames78.0
72016IbakaORLMagicGames56.0
82016IbakaTORRaptorsGames23.0
92015CurryGSWWarriorsPts30.1
102016CurryGSWWarriorsPts25.3
112017CurryGSWWarriorsPts26.4
122015DurantOKCThunderPts28.2
132016DurantGSWWarriorsPts25.1
142017DurantGSWWarriorsPts26.4
152015IbakaOKCThunderPts12.6
162016IbakaORLMagicPts15.1
172016IbakaTORRaptorsPts14.2
182015CurryGSWWarriorsAssist6.7
192016CurryGSWWarriorsAssist6.6
202017CurryGSWWarriorsAssist6.1
212015DurantOKCThunderAssist5.0
222016DurantGSWWarriorsAssist4.8
232017DurantGSWWarriorsAssist5.4
242015IbakaOKCThunderAssist0.8
252016IbakaORLMagicAssist1.1
262016IbakaTORRaptorsAssist0.7
272015CurryGSWWarriorsRebound5.4
282016CurryGSWWarriorsRebound4.5
292017CurryGSWWarriorsRebound5.1
302015DurantOKCThunderRebound8.2
312016DurantGSWWarriorsRebound8.3
322017DurantGSWWarriorsRebound6.8
332015IbakaOKCThunderRebound6.8
342016IbakaORLMagicRebound6.8
352016IbakaTORRaptorsRebound6.8
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName variable value\n", + "0 2015 Curry GSW Warriors Games 79.0\n", + "1 2016 Curry GSW Warriors Games 79.0\n", + "2 2017 Curry GSW Warriors Games 51.0\n", + "3 2015 Durant OKC Thunder Games 72.0\n", + "4 2016 Durant GSW Warriors Games 62.0\n", + "5 2017 Durant GSW Warriors Games 68.0\n", + "6 2015 Ibaka OKC Thunder Games 78.0\n", + "7 2016 Ibaka ORL Magic Games 56.0\n", + "8 2016 Ibaka TOR Raptors Games 23.0\n", + "9 2015 Curry GSW Warriors Pts 30.1\n", + "10 2016 Curry GSW Warriors Pts 25.3\n", + "11 2017 Curry GSW Warriors Pts 26.4\n", + "12 2015 Durant OKC Thunder Pts 28.2\n", + "13 2016 Durant GSW Warriors Pts 25.1\n", + "14 2017 Durant GSW Warriors Pts 26.4\n", + "15 2015 Ibaka OKC Thunder Pts 12.6\n", + "16 2016 Ibaka ORL Magic Pts 15.1\n", + "17 2016 Ibaka TOR Raptors Pts 14.2\n", + "18 2015 Curry GSW Warriors Assist 6.7\n", + "19 2016 Curry GSW Warriors Assist 6.6\n", + "20 2017 Curry GSW Warriors Assist 6.1\n", + "21 2015 Durant OKC Thunder Assist 5.0\n", + "22 2016 Durant GSW Warriors Assist 4.8\n", + "23 2017 Durant GSW Warriors Assist 5.4\n", + "24 2015 Ibaka OKC Thunder Assist 0.8\n", + "25 2016 Ibaka ORL Magic Assist 1.1\n", + "26 2016 Ibaka TOR Raptors Assist 0.7\n", + "27 2015 Curry GSW Warriors Rebound 5.4\n", + "28 2016 Curry GSW Warriors Rebound 4.5\n", + "29 2017 Curry GSW Warriors Rebound 5.1\n", + "30 2015 Durant OKC Thunder Rebound 8.2\n", + "31 2016 Durant GSW Warriors Rebound 8.3\n", + "32 2017 Durant GSW Warriors Rebound 6.8\n", + "33 2015 Ibaka OKC Thunder Rebound 6.8\n", + "34 2016 Ibaka ORL Magic Rebound 6.8\n", + "35 2016 Ibaka TOR Raptors Rebound 6.8" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# this is how we made ``bball_long``\n", + "bball.melt(id_vars=[\"Year\", \"Player\", \"Team\", \"TeamName\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that the columns we specified as `id_vars` remained columns, but all\n", + "other columns were put into two new columns:\n", + "\n", + "1. `variable`: This has dtype string and contains the former column names.\n", + " as values \n", + "1. `value`: This has the former values. \n", + "\n", + "\n", + "Using this method is an effective way to get our data in *tidy* form as noted\n", + "above." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `pivot` and `pivot_table`\n", + "\n", + "The next two reshaping methods that we will use are closely related.\n", + "\n", + "Some of you might even already be familiar with these ideas because you\n", + "have previously used *pivot tables* in Excel.\n", + "\n", + "- If so, good news. We think this is even more powerful than Excel\n", + " and easier to use! \n", + "- If not, good news. You are about to learn a very powerful and user-friendly tool. \n", + "\n", + "\n", + "We will begin with `pivot`.\n", + "\n", + "The `pivot` method:\n", + "\n", + "- Takes the unique values of one column and places them along the index. \n", + "- Takes the unique values of another column and places them along the\n", + " columns. \n", + "- Takes the values that correspond to a third column and fills in the\n", + " DataFrame values that correspond to that index/column pair. \n", + "\n", + "\n", + "We’ll illustrate with an example." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant
Year
201530.128.2
201625.325.1
201726.426.4
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant\n", + "Year \n", + "2015 30.1 28.2\n", + "2016 25.3 25.1\n", + "2017 26.4 26.4" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# .head 8 excludes Ibaka -- will discuss why later\n", + "bball.head(6).pivot(index=\"Year\", columns=\"Player\", values=\"Pts\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can replicate `pivot` using three of the fundamental operations\n", + "from above:\n", + "\n", + "1. Call `set_index` with the `index` and `columns` arguments \n", + "1. Extract the `values` column \n", + "1. `unstack` the columns level of the new index " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant
Year
201530.128.2
201625.325.1
201726.426.4
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant\n", + "Year \n", + "2015 30.1 28.2\n", + "2016 25.3 25.1\n", + "2017 26.4 26.4" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 1--------------------------------------- 2--- 3----------------------\n", + "bball.head(6).set_index([\"Year\", \"Player\"])[\"Pts\"].unstack(level=\"Player\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One important thing to be aware of is that in order for `pivot` to\n", + "work, the index/column pairs must be *unique*!\n", + "\n", + "Below, we demonstrate the error that occurs when they are not unique." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hide-output": false + }, + "source": [ + "```python\n", + "# Ibaka shows up twice in 2016 because he was traded mid-season from\n", + "# the Orlando Magic to the Toronto Raptors\n", + "bball.pivot(index=\"Year\", columns=\"Player\", values=\"Pts\")\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `pivot_table`\n", + "\n", + "The `pivot_table` method is a generalization of `pivot`.\n", + "\n", + "It overcomes two limitations of `pivot`:\n", + "\n", + "1. It allows you to choose multiple columns for the index/columns/values\n", + " arguments. \n", + "1. It allows you to deal with duplicate entries by\n", + " having you choose how to combine them. " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNameGamesPtsAssistRebound
02015CurryGSWWarriors7930.16.75.4
12016CurryGSWWarriors7925.36.64.5
22017CurryGSWWarriors5126.46.15.1
32015DurantOKCThunder7228.25.08.2
42016DurantGSWWarriors6225.14.88.3
52017DurantGSWWarriors6826.45.46.8
62015IbakaOKCThunder7812.60.86.8
72016IbakaORLMagic5615.11.16.8
82016IbakaTORRaptors2314.20.76.8
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName Games Pts Assist Rebound\n", + "0 2015 Curry GSW Warriors 79 30.1 6.7 5.4\n", + "1 2016 Curry GSW Warriors 79 25.3 6.6 4.5\n", + "2 2017 Curry GSW Warriors 51 26.4 6.1 5.1\n", + "3 2015 Durant OKC Thunder 72 28.2 5.0 8.2\n", + "4 2016 Durant GSW Warriors 62 25.1 4.8 8.3\n", + "5 2017 Durant GSW Warriors 68 26.4 5.4 6.8\n", + "6 2015 Ibaka OKC Thunder 78 12.6 0.8 6.8\n", + "7 2016 Ibaka ORL Magic 56 15.1 1.1 6.8\n", + "8 2016 Ibaka TOR Raptors 23 14.2 0.7 6.8" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that we can replicate the functionality of `pivot` if we pass\n", + "the same arguments." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant
Year
201530.128.2
201625.325.1
201726.426.4
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant\n", + "Year \n", + "2015 30.1 28.2\n", + "2016 25.3 25.1\n", + "2017 26.4 26.4" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.head(6).pivot(index=\"Year\", columns=\"Player\", values=\"Pts\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But we can also choose multiple columns to be used in\n", + "index/columns/values." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
YearTeam
2015GSW30.1NaNNaN
OKCNaN28.212.6
2016GSW25.325.1NaN
ORLNaNNaN15.1
TORNaNNaN14.2
2017GSW26.426.4NaN
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka\n", + "Year Team \n", + "2015 GSW 30.1 NaN NaN\n", + " OKC NaN 28.2 12.6\n", + "2016 GSW 25.3 25.1 NaN\n", + " ORL NaN NaN 15.1\n", + " TOR NaN NaN 14.2\n", + "2017 GSW 26.4 26.4 NaN" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.pivot_table(index=[\"Year\", \"Team\"], columns=\"Player\", values=\"Pts\")" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
TeamGSWGSWOKCOKCORLTOR
Year
201530.1NaN28.212.6NaNNaN
201625.325.1NaNNaN15.114.2
201726.426.4NaNNaNNaNNaN
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka \n", + "Team GSW GSW OKC OKC ORL TOR\n", + "Year \n", + "2015 30.1 NaN 28.2 12.6 NaN NaN\n", + "2016 25.3 25.1 NaN NaN 15.1 14.2\n", + "2017 26.4 26.4 NaN NaN NaN NaN" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.pivot_table(index=\"Year\", columns=[\"Player\", \"Team\"], values=\"Pts\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "AND we can deal with duplicated index/column pairs." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
Year
201530.128.212.60
201625.325.114.65
201726.426.4NaN
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka\n", + "Year \n", + "2015 30.1 28.2 12.60\n", + "2016 25.3 25.1 14.65\n", + "2017 26.4 26.4 NaN" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# This produced an error\n", + "# bball.pivot(index=\"Year\", columns=\"Player\", values=\"Pts\")\n", + "\n", + "# This doesn't!\n", + "bball_pivoted = bball.pivot_table(index=\"Year\", columns=\"Player\", values=\"Pts\")\n", + "bball_pivoted" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`pivot_table` handles duplicate index/column pairs using an aggregation.\n", + "\n", + "By default, the aggregation is the mean.\n", + "\n", + "For example, our duplicated index/column pair is `(\"x\", 1)` and had\n", + "associated values of 2 and 5.\n", + "\n", + "Notice that `bball_pivoted.loc[2016, \"Ibaka\"]` is `(15.1 + 14.2)/2 = 14.65`.\n", + "\n", + "We can choose how `pandas` aggregates all of the values.\n", + "\n", + "For example, here’s how we would keep the max." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
Year
201530.128.212.6
201625.325.115.1
201726.426.4NaN
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka\n", + "Year \n", + "2015 30.1 28.2 12.6\n", + "2016 25.3 25.1 15.1\n", + "2017 26.4 26.4 NaN" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.pivot_table(index=\"Year\", columns=\"Player\", values=\"Pts\", aggfunc=max)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Maybe we wanted to count how many values there were." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurantIbaka
Year
20151.01.01.0
20161.01.02.0
20171.01.0NaN
\n", + "
" + ], + "text/plain": [ + "Player Curry Durant Ibaka\n", + "Year \n", + "2015 1.0 1.0 1.0\n", + "2016 1.0 1.0 2.0\n", + "2017 1.0 1.0 NaN" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.pivot_table(index=\"Year\", columns=\"Player\", values=\"Pts\", aggfunc=len)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can even pass multiple aggregation functions!" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
maxlen
PlayerCurryDurantIbakaCurryDurantIbaka
Year
201530.128.212.61.01.01.0
201625.325.115.11.01.02.0
201726.426.4NaN1.01.0NaN
\n", + "
" + ], + "text/plain": [ + " max len \n", + "Player Curry Durant Ibaka Curry Durant Ibaka\n", + "Year \n", + "2015 30.1 28.2 12.6 1.0 1.0 1.0\n", + "2016 25.3 25.1 15.1 1.0 1.0 2.0\n", + "2017 26.4 26.4 NaN 1.0 1.0 NaN" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.pivot_table(index=\"Year\", columns=\"Player\", values=\"Pts\", aggfunc=[max, len])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing Reshaping\n", + "\n", + "Now that you have learned the basics and had a chance to experiment,\n", + "we will use some generic data to provide a visualization of what the above\n", + "reshape operations do.\n", + "\n", + "The data we will use is:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 4 entries, 0 to 3\n", + "Data columns (total 5 columns):\n", + "A 4 non-null int64\n", + "B 4 non-null object\n", + "C 4 non-null int64\n", + "D 4 non-null int64\n", + "E 4 non-null int64\n", + "dtypes: int64(4), object(1)\n", + "memory usage: 288.0+ bytes\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABCDE
00x1102
10y2201
21x1305
31z4204
\n", + "
" + ], + "text/plain": [ + " A B C D E\n", + "0 0 x 1 10 2\n", + "1 0 y 2 20 1\n", + "2 1 x 1 30 5\n", + "3 1 z 4 20 4" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# made up\n", + "# columns A and B are \"identifiers\" while C, D, and E are variables.\n", + "df = pd.DataFrame({\n", + " \"A\": [0, 0, 1, 1],\n", + " \"B\": \"x y x z\".split(),\n", + " \"C\": [1, 2, 1, 4],\n", + " \"D\": [10, 20, 30, 20,],\n", + " \"E\": [2, 1, 5, 4,]\n", + "})\n", + "\n", + "df.info()\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CDE
AB
0x1102
y2201
1x1305
z4204
\n", + "
" + ], + "text/plain": [ + " C D E\n", + "A B \n", + "0 x 1 10 2\n", + " y 2 20 1\n", + "1 x 1 30 5\n", + " z 4 20 4" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2 = df.set_index([\"A\", \"B\"])\n", + "df2.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A01
Bxyxz
C1214
D10203020
E2154
\n", + "
" + ], + "text/plain": [ + "A 0 1 \n", + "B x y x z\n", + "C 1 2 1 4\n", + "D 10 20 30 20\n", + "E 2 1 5 4" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df3 = df2.T\n", + "df3.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `stack` and `unstack`\n", + "\n", + "Below is an animation that shows how stacking works.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/reshape_files/stack.gif](https://datascience.quantecon.org/assets/_static/reshape_files/stack.gif) " + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CDE
AB
0x1102
y2201
1x1305
z4204
\n", + "
" + ], + "text/plain": [ + " C D E\n", + "A B \n", + "0 x 1 10 2\n", + " y 2 20 1\n", + "1 x 1 30 5\n", + " z 4 20 4" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "A B \n", + "0 x C 1\n", + " D 10\n", + " E 2\n", + " y C 2\n", + " D 20\n", + " E 1\n", + "1 x C 1\n", + " D 30\n", + " E 5\n", + " z C 4\n", + " D 20\n", + " E 4\n", + "dtype: int64" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2_stack = df2.stack()\n", + "df2_stack" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And here is an animation that shows how unstacking works.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/reshape_files/unstack_level0.gif](https://datascience.quantecon.org/assets/_static/reshape_files/unstack_level0.gif) " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CDE
AB
0x1102
y2201
1x1305
z4204
\n", + "
" + ], + "text/plain": [ + " C D E\n", + "A B \n", + "0 x 1 10 2\n", + " y 2 20 1\n", + "1 x 1 30 5\n", + " z 4 20 4" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CDE
Bxyzxyzxyz
A
01.02.0NaN10.020.0NaN2.01.0NaN
11.0NaN4.030.0NaN20.05.0NaN4.0
\n", + "
" + ], + "text/plain": [ + " C D E \n", + "B x y z x y z x y z\n", + "A \n", + "0 1.0 2.0 NaN 10.0 20.0 NaN 2.0 1.0 NaN\n", + "1 1.0 NaN 4.0 30.0 NaN 20.0 5.0 NaN 4.0" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2.unstack()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `melt`\n", + "\n", + "As noted above, the `melt` method transforms data from wide to long in form.\n", + "\n", + "Here’s a visualization of that operation.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/reshape_files/melt.gif](https://datascience.quantecon.org/assets/_static/reshape_files/melt.gif) " + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABCDE
00x1102
10y2201
21x1305
31z4204
\n", + "
" + ], + "text/plain": [ + " A B C D E\n", + "0 0 x 1 10 2\n", + "1 0 y 2 20 1\n", + "2 1 x 1 30 5\n", + "3 1 z 4 20 4" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABvariablevalue
00xC1
10yC2
21xC1
31zC4
40xD10
50yD20
61xD30
71zD20
80xE2
90yE1
101xE5
111zE4
\n", + "
" + ], + "text/plain": [ + " A B variable value\n", + "0 0 x C 1\n", + "1 0 y C 2\n", + "2 1 x C 1\n", + "3 1 z C 4\n", + "4 0 x D 10\n", + "5 0 y D 20\n", + "6 1 x D 30\n", + "7 1 z D 20\n", + "8 0 x E 2\n", + "9 0 y E 1\n", + "10 1 x E 5\n", + "11 1 z E 4" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_melted = df.melt(id_vars=[\"A\", \"B\"])\n", + "df_melted" + ] + } + ], + "metadata": { + "date": 1584040763.8179712, + "filename": "reshape.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "Reshape" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/6_reshape_exercises.ipynb b/Session_7/6_reshape_exercises.ipynb new file mode 100644 index 0000000..7ab7376 --- /dev/null +++ b/Session_7/6_reshape_exercises.ipynb @@ -0,0 +1,3882 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (1.12.0)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: python-dateutil in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (2.8.0)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import numpy as np\n", + "import pandas as pd\n", + "%matplotlib inline\n", + "import qeds\n", + "qeds.themes.mpl_style();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reshape - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For these exercises we use basketball data. After loading the data:**\n", + "- we create a long-form version\n", + "- we create a wide-form version " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNameGamesPtsAssistRebound
02015CurryGSWWarriors7930.16.75.4
12016CurryGSWWarriors7925.36.64.5
22017CurryGSWWarriors5126.46.15.1
32015DurantOKCThunder7228.25.08.2
42016DurantGSWWarriors6225.14.88.3
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName Games Pts Assist Rebound\n", + "0 2015 Curry GSW Warriors 79 30.1 6.7 5.4\n", + "1 2016 Curry GSW Warriors 79 25.3 6.6 4.5\n", + "2 2017 Curry GSW Warriors 51 26.4 6.1 5.1\n", + "3 2015 Durant OKC Thunder 72 28.2 5.0 8.2\n", + "4 2016 Durant GSW Warriors 62 25.1 4.8 8.3" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = \"https://datascience.quantecon.org/assets/data/bball.csv\"\n", + "bball = pd.read_csv(url)\n", + "bball.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNamevariablevalue
02015CurryGSWWarriorsGames79.0
12016CurryGSWWarriorsGames79.0
22017CurryGSWWarriorsGames51.0
32015DurantOKCThunderGames72.0
42016DurantGSWWarriorsGames62.0
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName variable value\n", + "0 2015 Curry GSW Warriors Games 79.0\n", + "1 2016 Curry GSW Warriors Games 79.0\n", + "2 2017 Curry GSW Warriors Games 51.0\n", + "3 2015 Durant OKC Thunder Games 72.0\n", + "4 2016 Durant GSW Warriors Games 62.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball_long = bball.melt(id_vars=[\"Year\", \"Player\", \"Team\", \"TeamName\"])\n", + "bball_long.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant...Ibaka
variableAssistGamesPtsReboundAssistGamesPts...AssistGamesPtsRebound
TeamGSWGSWGSWGSWGSWOKCGSWOKCGSWOKC...TOROKCORLTOROKCORLTOROKCORLTOR
Year
20156.779.030.15.4NaN5.0NaN72.0NaN28.2...NaN78.0NaNNaN12.6NaNNaN6.8NaNNaN
20166.679.025.34.54.8NaN62.0NaN25.1NaN...0.7NaN56.023.0NaN15.114.2NaN6.86.8
20176.151.026.45.15.4NaN68.0NaN26.4NaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + "Player Curry Durant ... \\\n", + "variable Assist Games Pts Rebound Assist Games Pts ... \n", + "Team GSW GSW GSW GSW GSW OKC GSW OKC GSW OKC ... \n", + "Year ... \n", + "2015 6.7 79.0 30.1 5.4 NaN 5.0 NaN 72.0 NaN 28.2 ... \n", + "2016 6.6 79.0 25.3 4.5 4.8 NaN 62.0 NaN 25.1 NaN ... \n", + "2017 6.1 51.0 26.4 5.1 5.4 NaN 68.0 NaN 26.4 NaN ... \n", + "\n", + "Player Ibaka \n", + "variable Assist Games Pts Rebound \n", + "Team TOR OKC ORL TOR OKC ORL TOR OKC ORL TOR \n", + "Year \n", + "2015 NaN 78.0 NaN NaN 12.6 NaN NaN 6.8 NaN NaN \n", + "2016 0.7 NaN 56.0 23.0 NaN 15.1 14.2 NaN 6.8 6.8 \n", + "2017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball_wide = bball_long.pivot_table(\n", + " index=\"Year\",\n", + " columns=[\"Player\", \"variable\", \"Team\"],\n", + " values=\"value\"\n", + ")\n", + "bball_wide.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**(*Warning*: This one is challenging):**\n", + "\n", + "**Recall the `bball_wide` DataFrame from above (repeated below to jog your memory).**\n", + "\n", + "**In this task, you will start from `ball` and re-recreate `bball_wide` by combining the operations we just learned about. There are many ways to do this, so be creative.**\n", + "\n", + "**The solution presented in the lecture used `set_index`, `T`, `stack`, and `unstack` in that order.**\n", + "\n", + "**Here are a few hints:**\n", + "\n", + "- Think about what columns you will need to call `set_index` on so that their data ends up as labels (either in index or columns). \n", + "- Leave other columns (e.g. the actual game stats) as actual columns so their data can stay data during your reshaping. \n", + "\n", + "**Hint**: You might need to add `.sort_index(axis=1)` after you are finished to get the columns in the same order.\n", + "\n", + "**Hint**: You may not end up with a `variable` header on the second level of column labels. This is ok." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant...Ibaka
variableAssistGamesPtsReboundAssistGamesPts...AssistGamesPtsRebound
TeamGSWGSWGSWGSWGSWOKCGSWOKCGSWOKC...TOROKCORLTOROKCORLTOROKCORLTOR
Year
20156.779.030.15.4NaN5.0NaN72.0NaN28.2...NaN78.0NaNNaN12.6NaNNaN6.8NaNNaN
20166.679.025.34.54.8NaN62.0NaN25.1NaN...0.7NaN56.023.0NaN15.114.2NaN6.86.8
20176.151.026.45.15.4NaN68.0NaN26.4NaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + "Player Curry Durant ... \\\n", + "variable Assist Games Pts Rebound Assist Games Pts ... \n", + "Team GSW GSW GSW GSW GSW OKC GSW OKC GSW OKC ... \n", + "Year ... \n", + "2015 6.7 79.0 30.1 5.4 NaN 5.0 NaN 72.0 NaN 28.2 ... \n", + "2016 6.6 79.0 25.3 4.5 4.8 NaN 62.0 NaN 25.1 NaN ... \n", + "2017 6.1 51.0 26.4 5.1 5.4 NaN 68.0 NaN 26.4 NaN ... \n", + "\n", + "Player Ibaka \n", + "variable Assist Games Pts Rebound \n", + "Team TOR OKC ORL TOR OKC ORL TOR OKC ORL TOR \n", + "Year \n", + "2015 NaN 78.0 NaN NaN 12.6 NaN NaN 6.8 NaN NaN \n", + "2016 0.7 NaN 56.0 23.0 NaN 15.1 14.2 NaN 6.8 6.8 \n", + "2017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#we have to recreate this DataFrame in a different way\n", + "bball_wide" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant...Ibaka
AssistGamesPtsReboundAssistGamesPts...AssistGamesPtsRebound
TeamGSWGSWGSWGSWGSWOKCGSWOKCGSWOKC...TOROKCORLTOROKCORLTOROKCORLTOR
Year
20156.779.030.15.4NaN5.0NaN72.0NaN28.2...NaN78.0NaNNaN12.6NaNNaN6.8NaNNaN
20166.679.025.34.54.8NaN62.0NaN25.1NaN...0.7NaN56.023.0NaN15.114.2NaN6.86.8
20176.151.026.45.15.4NaN68.0NaN26.4NaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + "Player Curry Durant ... \\\n", + " Assist Games Pts Rebound Assist Games Pts ... \n", + "Team GSW GSW GSW GSW GSW OKC GSW OKC GSW OKC ... \n", + "Year ... \n", + "2015 6.7 79.0 30.1 5.4 NaN 5.0 NaN 72.0 NaN 28.2 ... \n", + "2016 6.6 79.0 25.3 4.5 4.8 NaN 62.0 NaN 25.1 NaN ... \n", + "2017 6.1 51.0 26.4 5.1 5.4 NaN 68.0 NaN 26.4 NaN ... \n", + "\n", + "Player Ibaka \n", + " Assist Games Pts Rebound \n", + "Team TOR OKC ORL TOR OKC ORL TOR OKC ORL TOR \n", + "Year \n", + "2015 NaN 78.0 NaN NaN 12.6 NaN NaN 6.8 NaN NaN \n", + "2016 0.7 NaN 56.0 23.0 NaN 15.1 14.2 NaN 6.8 6.8 \n", + "2017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.drop(\"TeamName\", axis=1).set_index([\"Year\", \"Player\", \"Team\"]).stack().unstack(level=[1, 3, 2]).sort_index(axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**(Tentative) explanation of the code:**" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamGamesPtsAssistRebound
02015CurryGSW7930.16.75.4
12016CurryGSW7925.36.64.5
22017CurryGSW5126.46.15.1
32015DurantOKC7228.25.08.2
42016DurantGSW6225.14.88.3
52017DurantGSW6826.45.46.8
62015IbakaOKC7812.60.86.8
72016IbakaORL5615.11.16.8
82016IbakaTOR2314.20.76.8
\n", + "
" + ], + "text/plain": [ + " Year Player Team Games Pts Assist Rebound\n", + "0 2015 Curry GSW 79 30.1 6.7 5.4\n", + "1 2016 Curry GSW 79 25.3 6.6 4.5\n", + "2 2017 Curry GSW 51 26.4 6.1 5.1\n", + "3 2015 Durant OKC 72 28.2 5.0 8.2\n", + "4 2016 Durant GSW 62 25.1 4.8 8.3\n", + "5 2017 Durant GSW 68 26.4 5.4 6.8\n", + "6 2015 Ibaka OKC 78 12.6 0.8 6.8\n", + "7 2016 Ibaka ORL 56 15.1 1.1 6.8\n", + "8 2016 Ibaka TOR 23 14.2 0.7 6.8" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# '.drop(\"TeamName\", axis=1)' drops the columns (axis=1) TeamName, Avoid to have a useless (maybe akward ?) variable in the final dataset\n", + "bball.drop(\"TeamName\", axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GamesPtsAssistRebound
YearPlayerTeam
2015CurryGSW7930.16.75.4
2016CurryGSW7925.36.64.5
2017CurryGSW5126.46.15.1
2015DurantOKC7228.25.08.2
2016DurantGSW6225.14.88.3
2017DurantGSW6826.45.46.8
2015IbakaOKC7812.60.86.8
2016IbakaORL5615.11.16.8
TOR2314.20.76.8
\n", + "
" + ], + "text/plain": [ + " Games Pts Assist Rebound\n", + "Year Player Team \n", + "2015 Curry GSW 79 30.1 6.7 5.4\n", + "2016 Curry GSW 79 25.3 6.6 4.5\n", + "2017 Curry GSW 51 26.4 6.1 5.1\n", + "2015 Durant OKC 72 28.2 5.0 8.2\n", + "2016 Durant GSW 62 25.1 4.8 8.3\n", + "2017 Durant GSW 68 26.4 5.4 6.8\n", + "2015 Ibaka OKC 78 12.6 0.8 6.8\n", + "2016 Ibaka ORL 56 15.1 1.1 6.8\n", + " TOR 23 14.2 0.7 6.8" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# set_index([\"Year\", \"Player\", \"Team\"]) sets multindex, the hierarchy is Year > Player > Team. This is necessary if we want to stack the data (ie group and 'stack'), with each component of the stack corresponding to the values in a given year of a player in a given team\n", + "bball.drop(\"TeamName\", axis=1).set_index([\"Year\", \"Player\", \"Team\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Year Player Team \n", + "2015 Curry GSW Games 79.0\n", + " Pts 30.1\n", + " Assist 6.7\n", + " Rebound 5.4\n", + "2016 Curry GSW Games 79.0\n", + " Pts 25.3\n", + " Assist 6.6\n", + " Rebound 4.5\n", + "2017 Curry GSW Games 51.0\n", + " Pts 26.4\n", + " Assist 6.1\n", + " Rebound 5.1\n", + "2015 Durant OKC Games 72.0\n", + " Pts 28.2\n", + " Assist 5.0\n", + " Rebound 8.2\n", + "2016 Durant GSW Games 62.0\n", + " Pts 25.1\n", + " Assist 4.8\n", + " Rebound 8.3\n", + "2017 Durant GSW Games 68.0\n", + " Pts 26.4\n", + " Assist 5.4\n", + " Rebound 6.8\n", + "2015 Ibaka OKC Games 78.0\n", + " Pts 12.6\n", + " Assist 0.8\n", + " Rebound 6.8\n", + "2016 Ibaka ORL Games 56.0\n", + " Pts 15.1\n", + " Assist 1.1\n", + " Rebound 6.8\n", + " TOR Games 23.0\n", + " Pts 14.2\n", + " Assist 0.7\n", + " Rebound 6.8\n", + "dtype: float64" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# stack stacks the data for each YEAR, PLAYER, TEAM triple. the outcome is a 'stack', each component of this stack being a table of the value of all the variables (ie non index) for a given combination of the indexes.\n", + "bball.drop(\"TeamName\", axis=1).set_index([\"Year\", \"Player\", \"Team\"]).stack()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant...Ibaka
GamesPtsAssistReboundGamesPtsAssistReboundGamesPts...AssistReboundGamesPtsAssistReboundGamesPtsAssistRebound
TeamGSWGSWGSWGSWOKCOKCOKCOKCGSWGSW...OKCOKCORLORLORLORLTORTORTORTOR
Year
201579.030.16.75.472.028.25.08.2NaNNaN...0.86.8NaNNaNNaNNaNNaNNaNNaNNaN
201679.025.36.64.5NaNNaNNaNNaN62.025.1...NaNNaN56.015.11.16.823.014.20.76.8
201751.026.46.15.1NaNNaNNaNNaN68.026.4...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + "Player Curry Durant \\\n", + " Games Pts Assist Rebound Games Pts Assist Rebound Games Pts \n", + "Team GSW GSW GSW GSW OKC OKC OKC OKC GSW GSW \n", + "Year \n", + "2015 79.0 30.1 6.7 5.4 72.0 28.2 5.0 8.2 NaN NaN \n", + "2016 79.0 25.3 6.6 4.5 NaN NaN NaN NaN 62.0 25.1 \n", + "2017 51.0 26.4 6.1 5.1 NaN NaN NaN NaN 68.0 26.4 \n", + "\n", + "Player ... Ibaka \\\n", + " ... Assist Rebound Games Pts Assist Rebound Games Pts Assist \n", + "Team ... OKC OKC ORL ORL ORL ORL TOR TOR TOR \n", + "Year ... \n", + "2015 ... 0.8 6.8 NaN NaN NaN NaN NaN NaN NaN \n", + "2016 ... NaN NaN 56.0 15.1 1.1 6.8 23.0 14.2 0.7 \n", + "2017 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "Player \n", + " Rebound \n", + "Team TOR \n", + "Year \n", + "2015 NaN \n", + "2016 6.8 \n", + "2017 NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# An intuitive idea to explain that ?\n", + "bball.drop(\"TeamName\", axis=1).set_index([\"Year\", \"Player\", \"Team\"]).stack().unstack(level=[1,3,2])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PlayerCurryDurant...Ibaka
AssistGamesPtsReboundAssistGamesPts...AssistGamesPtsRebound
TeamGSWGSWGSWGSWGSWOKCGSWOKCGSWOKC...TOROKCORLTOROKCORLTOROKCORLTOR
Year
20156.779.030.15.4NaN5.0NaN72.0NaN28.2...NaN78.0NaNNaN12.6NaNNaN6.8NaNNaN
20166.679.025.34.54.8NaN62.0NaN25.1NaN...0.7NaN56.023.0NaN15.114.2NaN6.86.8
20176.151.026.45.15.4NaN68.0NaN26.4NaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + "Player Curry Durant ... \\\n", + " Assist Games Pts Rebound Assist Games Pts ... \n", + "Team GSW GSW GSW GSW GSW OKC GSW OKC GSW OKC ... \n", + "Year ... \n", + "2015 6.7 79.0 30.1 5.4 NaN 5.0 NaN 72.0 NaN 28.2 ... \n", + "2016 6.6 79.0 25.3 4.5 4.8 NaN 62.0 NaN 25.1 NaN ... \n", + "2017 6.1 51.0 26.4 5.1 5.4 NaN 68.0 NaN 26.4 NaN ... \n", + "\n", + "Player Ibaka \n", + " Assist Games Pts Rebound \n", + "Team TOR OKC ORL TOR OKC ORL TOR OKC ORL TOR \n", + "Year \n", + "2015 NaN 78.0 NaN NaN 12.6 NaN NaN 6.8 NaN NaN \n", + "2016 0.7 NaN 56.0 23.0 NaN 15.1 14.2 NaN 6.8 6.8 \n", + "2017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# sort_index(axis=1) sort the variables in the alphabetical order. Changes the order of the columns variable only\n", + "bball.drop(\"TeamName\", axis=1).set_index([\"Year\", \"Player\", \"Team\"]).stack().unstack(level=[1,3,2]).sort_index(axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **What do you think would happen if we wrote `bball.melt(id_vars=[\"Year\", \"Player\"])` rather than `bball.melt(id_vars=[\"Year\", \"Player\", \"Team\", \"TeamName\"])`? Were you right? Write your thoughts.** " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# for bball.melt(id_vars=[\"Year\", \"Player\"]) we would get only the columns Year and Player and all the other columns \n", + "# would be put into two new columns: variable (Team, Teamname, etc) and values (the values associated with each)\n", + "\n", + "# for bball.melt(id_vars=[\"Year\", \"Player\", \"Team\", \"TeamName\"]) we would get the columns Year, Player, Team and Teamname\n", + "# and all the remaining columns will be put into two new columns: variable and values" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayervariablevalue
02015CurryTeamGSW
12016CurryTeamGSW
22017CurryTeamGSW
32015DurantTeamOKC
42016DurantTeamGSW
52017DurantTeamGSW
62015IbakaTeamOKC
72016IbakaTeamORL
82016IbakaTeamTOR
92015CurryTeamNameWarriors
102016CurryTeamNameWarriors
112017CurryTeamNameWarriors
122015DurantTeamNameThunder
132016DurantTeamNameWarriors
142017DurantTeamNameWarriors
152015IbakaTeamNameThunder
162016IbakaTeamNameMagic
172016IbakaTeamNameRaptors
182015CurryGames79
192016CurryGames79
202017CurryGames51
212015DurantGames72
222016DurantGames62
232017DurantGames68
242015IbakaGames78
252016IbakaGames56
262016IbakaGames23
272015CurryPts30.1
282016CurryPts25.3
292017CurryPts26.4
302015DurantPts28.2
312016DurantPts25.1
322017DurantPts26.4
332015IbakaPts12.6
342016IbakaPts15.1
352016IbakaPts14.2
362015CurryAssist6.7
372016CurryAssist6.6
382017CurryAssist6.1
392015DurantAssist5
402016DurantAssist4.8
412017DurantAssist5.4
422015IbakaAssist0.8
432016IbakaAssist1.1
442016IbakaAssist0.7
452015CurryRebound5.4
462016CurryRebound4.5
472017CurryRebound5.1
482015DurantRebound8.2
492016DurantRebound8.3
502017DurantRebound6.8
512015IbakaRebound6.8
522016IbakaRebound6.8
532016IbakaRebound6.8
\n", + "
" + ], + "text/plain": [ + " Year Player variable value\n", + "0 2015 Curry Team GSW\n", + "1 2016 Curry Team GSW\n", + "2 2017 Curry Team GSW\n", + "3 2015 Durant Team OKC\n", + "4 2016 Durant Team GSW\n", + "5 2017 Durant Team GSW\n", + "6 2015 Ibaka Team OKC\n", + "7 2016 Ibaka Team ORL\n", + "8 2016 Ibaka Team TOR\n", + "9 2015 Curry TeamName Warriors\n", + "10 2016 Curry TeamName Warriors\n", + "11 2017 Curry TeamName Warriors\n", + "12 2015 Durant TeamName Thunder\n", + "13 2016 Durant TeamName Warriors\n", + "14 2017 Durant TeamName Warriors\n", + "15 2015 Ibaka TeamName Thunder\n", + "16 2016 Ibaka TeamName Magic\n", + "17 2016 Ibaka TeamName Raptors\n", + "18 2015 Curry Games 79\n", + "19 2016 Curry Games 79\n", + "20 2017 Curry Games 51\n", + "21 2015 Durant Games 72\n", + "22 2016 Durant Games 62\n", + "23 2017 Durant Games 68\n", + "24 2015 Ibaka Games 78\n", + "25 2016 Ibaka Games 56\n", + "26 2016 Ibaka Games 23\n", + "27 2015 Curry Pts 30.1\n", + "28 2016 Curry Pts 25.3\n", + "29 2017 Curry Pts 26.4\n", + "30 2015 Durant Pts 28.2\n", + "31 2016 Durant Pts 25.1\n", + "32 2017 Durant Pts 26.4\n", + "33 2015 Ibaka Pts 12.6\n", + "34 2016 Ibaka Pts 15.1\n", + "35 2016 Ibaka Pts 14.2\n", + "36 2015 Curry Assist 6.7\n", + "37 2016 Curry Assist 6.6\n", + "38 2017 Curry Assist 6.1\n", + "39 2015 Durant Assist 5\n", + "40 2016 Durant Assist 4.8\n", + "41 2017 Durant Assist 5.4\n", + "42 2015 Ibaka Assist 0.8\n", + "43 2016 Ibaka Assist 1.1\n", + "44 2016 Ibaka Assist 0.7\n", + "45 2015 Curry Rebound 5.4\n", + "46 2016 Curry Rebound 4.5\n", + "47 2017 Curry Rebound 5.1\n", + "48 2015 Durant Rebound 8.2\n", + "49 2016 Durant Rebound 8.3\n", + "50 2017 Durant Rebound 6.8\n", + "51 2015 Ibaka Rebound 6.8\n", + "52 2016 Ibaka Rebound 6.8\n", + "53 2016 Ibaka Rebound 6.8" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.melt(id_vars=[\"Year\", \"Player\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayerTeamTeamNamevariablevalue
02015CurryGSWWarriorsGames79.0
12016CurryGSWWarriorsGames79.0
22017CurryGSWWarriorsGames51.0
32015DurantOKCThunderGames72.0
42016DurantGSWWarriorsGames62.0
52017DurantGSWWarriorsGames68.0
62015IbakaOKCThunderGames78.0
72016IbakaORLMagicGames56.0
82016IbakaTORRaptorsGames23.0
92015CurryGSWWarriorsPts30.1
102016CurryGSWWarriorsPts25.3
112017CurryGSWWarriorsPts26.4
122015DurantOKCThunderPts28.2
132016DurantGSWWarriorsPts25.1
142017DurantGSWWarriorsPts26.4
152015IbakaOKCThunderPts12.6
162016IbakaORLMagicPts15.1
172016IbakaTORRaptorsPts14.2
182015CurryGSWWarriorsAssist6.7
192016CurryGSWWarriorsAssist6.6
202017CurryGSWWarriorsAssist6.1
212015DurantOKCThunderAssist5.0
222016DurantGSWWarriorsAssist4.8
232017DurantGSWWarriorsAssist5.4
242015IbakaOKCThunderAssist0.8
252016IbakaORLMagicAssist1.1
262016IbakaTORRaptorsAssist0.7
272015CurryGSWWarriorsRebound5.4
282016CurryGSWWarriorsRebound4.5
292017CurryGSWWarriorsRebound5.1
302015DurantOKCThunderRebound8.2
312016DurantGSWWarriorsRebound8.3
322017DurantGSWWarriorsRebound6.8
332015IbakaOKCThunderRebound6.8
342016IbakaORLMagicRebound6.8
352016IbakaTORRaptorsRebound6.8
\n", + "
" + ], + "text/plain": [ + " Year Player Team TeamName variable value\n", + "0 2015 Curry GSW Warriors Games 79.0\n", + "1 2016 Curry GSW Warriors Games 79.0\n", + "2 2017 Curry GSW Warriors Games 51.0\n", + "3 2015 Durant OKC Thunder Games 72.0\n", + "4 2016 Durant GSW Warriors Games 62.0\n", + "5 2017 Durant GSW Warriors Games 68.0\n", + "6 2015 Ibaka OKC Thunder Games 78.0\n", + "7 2016 Ibaka ORL Magic Games 56.0\n", + "8 2016 Ibaka TOR Raptors Games 23.0\n", + "9 2015 Curry GSW Warriors Pts 30.1\n", + "10 2016 Curry GSW Warriors Pts 25.3\n", + "11 2017 Curry GSW Warriors Pts 26.4\n", + "12 2015 Durant OKC Thunder Pts 28.2\n", + "13 2016 Durant GSW Warriors Pts 25.1\n", + "14 2017 Durant GSW Warriors Pts 26.4\n", + "15 2015 Ibaka OKC Thunder Pts 12.6\n", + "16 2016 Ibaka ORL Magic Pts 15.1\n", + "17 2016 Ibaka TOR Raptors Pts 14.2\n", + "18 2015 Curry GSW Warriors Assist 6.7\n", + "19 2016 Curry GSW Warriors Assist 6.6\n", + "20 2017 Curry GSW Warriors Assist 6.1\n", + "21 2015 Durant OKC Thunder Assist 5.0\n", + "22 2016 Durant GSW Warriors Assist 4.8\n", + "23 2017 Durant GSW Warriors Assist 5.4\n", + "24 2015 Ibaka OKC Thunder Assist 0.8\n", + "25 2016 Ibaka ORL Magic Assist 1.1\n", + "26 2016 Ibaka TOR Raptors Assist 0.7\n", + "27 2015 Curry GSW Warriors Rebound 5.4\n", + "28 2016 Curry GSW Warriors Rebound 4.5\n", + "29 2017 Curry GSW Warriors Rebound 5.1\n", + "30 2015 Durant OKC Thunder Rebound 8.2\n", + "31 2016 Durant GSW Warriors Rebound 8.3\n", + "32 2017 Durant GSW Warriors Rebound 6.8\n", + "33 2015 Ibaka OKC Thunder Rebound 6.8\n", + "34 2016 Ibaka ORL Magic Rebound 6.8\n", + "35 2016 Ibaka TOR Raptors Rebound 6.8" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.melt(id_vars=[\"Year\", \"Player\", \"Team\", \"TeamName\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Read the documentation and focus on the argument `value_vars`. How does `bball.melt(id_vars=[\"Year\", \"Player\"], value_vars=[\"Pts\", \"Rebound\"])` differ from `bball.melt(id_vars=[\"Year\", \"Player\"])`?** " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayervariablevalue
02015CurryPts30.1
12016CurryPts25.3
22017CurryPts26.4
32015DurantPts28.2
42016DurantPts25.1
52017DurantPts26.4
62015IbakaPts12.6
72016IbakaPts15.1
82016IbakaPts14.2
92015CurryRebound5.4
102016CurryRebound4.5
112017CurryRebound5.1
122015DurantRebound8.2
132016DurantRebound8.3
142017DurantRebound6.8
152015IbakaRebound6.8
162016IbakaRebound6.8
172016IbakaRebound6.8
\n", + "
" + ], + "text/plain": [ + " Year Player variable value\n", + "0 2015 Curry Pts 30.1\n", + "1 2016 Curry Pts 25.3\n", + "2 2017 Curry Pts 26.4\n", + "3 2015 Durant Pts 28.2\n", + "4 2016 Durant Pts 25.1\n", + "5 2017 Durant Pts 26.4\n", + "6 2015 Ibaka Pts 12.6\n", + "7 2016 Ibaka Pts 15.1\n", + "8 2016 Ibaka Pts 14.2\n", + "9 2015 Curry Rebound 5.4\n", + "10 2016 Curry Rebound 4.5\n", + "11 2017 Curry Rebound 5.1\n", + "12 2015 Durant Rebound 8.2\n", + "13 2016 Durant Rebound 8.3\n", + "14 2017 Durant Rebound 6.8\n", + "15 2015 Ibaka Rebound 6.8\n", + "16 2016 Ibaka Rebound 6.8\n", + "17 2016 Ibaka Rebound 6.8" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.melt(id_vars=[\"Year\", \"Player\"], value_vars=[\"Pts\", \"Rebound\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YearPlayervariablevalue
02015CurryTeamGSW
12016CurryTeamGSW
22017CurryTeamGSW
32015DurantTeamOKC
42016DurantTeamGSW
52017DurantTeamGSW
62015IbakaTeamOKC
72016IbakaTeamORL
82016IbakaTeamTOR
92015CurryTeamNameWarriors
102016CurryTeamNameWarriors
112017CurryTeamNameWarriors
122015DurantTeamNameThunder
132016DurantTeamNameWarriors
142017DurantTeamNameWarriors
152015IbakaTeamNameThunder
162016IbakaTeamNameMagic
172016IbakaTeamNameRaptors
182015CurryGames79
192016CurryGames79
202017CurryGames51
212015DurantGames72
222016DurantGames62
232017DurantGames68
242015IbakaGames78
252016IbakaGames56
262016IbakaGames23
272015CurryPts30.1
282016CurryPts25.3
292017CurryPts26.4
302015DurantPts28.2
312016DurantPts25.1
322017DurantPts26.4
332015IbakaPts12.6
342016IbakaPts15.1
352016IbakaPts14.2
362015CurryAssist6.7
372016CurryAssist6.6
382017CurryAssist6.1
392015DurantAssist5
402016DurantAssist4.8
412017DurantAssist5.4
422015IbakaAssist0.8
432016IbakaAssist1.1
442016IbakaAssist0.7
452015CurryRebound5.4
462016CurryRebound4.5
472017CurryRebound5.1
482015DurantRebound8.2
492016DurantRebound8.3
502017DurantRebound6.8
512015IbakaRebound6.8
522016IbakaRebound6.8
532016IbakaRebound6.8
\n", + "
" + ], + "text/plain": [ + " Year Player variable value\n", + "0 2015 Curry Team GSW\n", + "1 2016 Curry Team GSW\n", + "2 2017 Curry Team GSW\n", + "3 2015 Durant Team OKC\n", + "4 2016 Durant Team GSW\n", + "5 2017 Durant Team GSW\n", + "6 2015 Ibaka Team OKC\n", + "7 2016 Ibaka Team ORL\n", + "8 2016 Ibaka Team TOR\n", + "9 2015 Curry TeamName Warriors\n", + "10 2016 Curry TeamName Warriors\n", + "11 2017 Curry TeamName Warriors\n", + "12 2015 Durant TeamName Thunder\n", + "13 2016 Durant TeamName Warriors\n", + "14 2017 Durant TeamName Warriors\n", + "15 2015 Ibaka TeamName Thunder\n", + "16 2016 Ibaka TeamName Magic\n", + "17 2016 Ibaka TeamName Raptors\n", + "18 2015 Curry Games 79\n", + "19 2016 Curry Games 79\n", + "20 2017 Curry Games 51\n", + "21 2015 Durant Games 72\n", + "22 2016 Durant Games 62\n", + "23 2017 Durant Games 68\n", + "24 2015 Ibaka Games 78\n", + "25 2016 Ibaka Games 56\n", + "26 2016 Ibaka Games 23\n", + "27 2015 Curry Pts 30.1\n", + "28 2016 Curry Pts 25.3\n", + "29 2017 Curry Pts 26.4\n", + "30 2015 Durant Pts 28.2\n", + "31 2016 Durant Pts 25.1\n", + "32 2017 Durant Pts 26.4\n", + "33 2015 Ibaka Pts 12.6\n", + "34 2016 Ibaka Pts 15.1\n", + "35 2016 Ibaka Pts 14.2\n", + "36 2015 Curry Assist 6.7\n", + "37 2016 Curry Assist 6.6\n", + "38 2017 Curry Assist 6.1\n", + "39 2015 Durant Assist 5\n", + "40 2016 Durant Assist 4.8\n", + "41 2017 Durant Assist 5.4\n", + "42 2015 Ibaka Assist 0.8\n", + "43 2016 Ibaka Assist 1.1\n", + "44 2016 Ibaka Assist 0.7\n", + "45 2015 Curry Rebound 5.4\n", + "46 2016 Curry Rebound 4.5\n", + "47 2017 Curry Rebound 5.1\n", + "48 2015 Durant Rebound 8.2\n", + "49 2016 Durant Rebound 8.3\n", + "50 2017 Durant Rebound 6.8\n", + "51 2015 Ibaka Rebound 6.8\n", + "52 2016 Ibaka Rebound 6.8\n", + "53 2016 Ibaka Rebound 6.8" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.melt(id_vars=[\"Year\", \"Player\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# for bball.melt(id_vars=[\"Year\", \"Player\"], value_vars=[\"Pts\", \"Rebound\"]), while we keep the columns Year and Player as\n", + "# before, we also indicate which of the remaining columns to be considered in the two new column\n", + "\n", + "# thus, variable will only get Pts and Rebound from the remaining columns and values will take the values associated " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Consider the differences between `bball.stack` and `bball.melt`. Is there a way to make them generate the same output? Write your thoughts.**\n", + " - Hint: you might need to use both `stack` and another method from above" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variablevalue
0Year2015
1PlayerCurry
2TeamGSW
3TeamNameWarriors
4Games79
.........
67TeamNameRaptors
68Games23
69Pts14.2
70Assist0.7
71Rebound6.8
\n", + "

72 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " variable value\n", + "0 Year 2015\n", + "1 Player Curry\n", + "2 Team GSW\n", + "3 TeamName Warriors\n", + "4 Games 79\n", + ".. ... ...\n", + "67 TeamName Raptors\n", + "68 Games 23\n", + "69 Pts 14.2\n", + "70 Assist 0.7\n", + "71 Rebound 6.8\n", + "\n", + "[72 rows x 2 columns]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# bball.stack() also gives as results something similar to variables and values associated, but we don't have regular columns\n", + "# plus we don't have an index \n", + "\n", + "bball.stack().reset_index().drop(\"level_0\", axis=1).rename(columns={\"level_1\":\"variable\", 0: \"value\"})\n", + "#bball.melt()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Can you think of a reason to ever use `pivot` rather than `pivot_table`? Write your thoughts.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Why use pivot rather than pivot_table ? \\\n", + "Reminders: \n", + "- The pivot method:\n", + " - takes the unique values of one column and places them along the index.\n", + " - Takes the unique values of another column and places them along the columns.\n", + " - Takes the values that correpsond to a third column and fills in the DataFrame values that correspond to that index / column pair\n", + "- The pivot_table method:\n", + " - It allows you to choose multiple columns for the index/columns/values\n", + " arguments.\n", + " - It allows you to deal with duplicate entries by\n", + " having you choose how to combine them. \n", + " \n", + "pivot_table deals with non-unique values. This can be risky for instance here, it would aggregate the two different values for (IBAKA 2016) in a probably wrong way. For instance, if the aggregator is a mean, the two part of the season in which IBAKA played for different team would be given the same weight, which is probably not the case IRL. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Create a pivot table with column `Player` as the index, `TeamName` as the columns, and `[Rebound, Assist]` as the values. What happens when you use `aggfunc=[np.max, np.min, len]`?** " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AssistRebound
TeamNameMagicRaptorsThunderWarriorsMagicRaptorsThunderWarriors
Player
CurryNaNNaNNaN6.466667NaNNaNNaN5.00
DurantNaNNaN5.05.100000NaNNaN8.27.55
Ibaka1.10.70.8NaN6.86.86.8NaN
\n", + "
" + ], + "text/plain": [ + " Assist Rebound \n", + "TeamName Magic Raptors Thunder Warriors Magic Raptors Thunder Warriors\n", + "Player \n", + "Curry NaN NaN NaN 6.466667 NaN NaN NaN 5.00\n", + "Durant NaN NaN 5.0 5.100000 NaN NaN 8.2 7.55\n", + "Ibaka 1.1 0.7 0.8 NaN 6.8 6.8 6.8 NaN" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.pivot_table(index=\"Player\", columns=\"TeamName\", values=[\"Rebound\",\"Assist\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
amaxaminlen
AssistReboundAssist...ReboundAssistRebound
TeamNameMagicRaptorsThunderWarriorsMagicRaptorsThunderWarriorsMagicRaptors...ThunderWarriorsMagicRaptorsThunderWarriorsMagicRaptorsThunderWarriors
Player
CurryNaNNaNNaN6.7NaNNaNNaN5.4NaNNaN...NaN4.5NaNNaNNaN3.0NaNNaNNaN3.0
DurantNaNNaN5.05.4NaNNaN8.28.3NaNNaN...8.26.8NaNNaN1.02.0NaNNaN1.02.0
Ibaka1.10.70.8NaN6.86.86.8NaN1.10.7...6.8NaN1.01.01.0NaN1.01.01.0NaN
\n", + "

3 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + " amax \\\n", + " Assist Rebound \n", + "TeamName Magic Raptors Thunder Warriors Magic Raptors Thunder Warriors \n", + "Player \n", + "Curry NaN NaN NaN 6.7 NaN NaN NaN 5.4 \n", + "Durant NaN NaN 5.0 5.4 NaN NaN 8.2 8.3 \n", + "Ibaka 1.1 0.7 0.8 NaN 6.8 6.8 6.8 NaN \n", + "\n", + " amin ... len \\\n", + " Assist ... Rebound Assist \n", + "TeamName Magic Raptors ... Thunder Warriors Magic Raptors Thunder Warriors \n", + "Player ... \n", + "Curry NaN NaN ... NaN 4.5 NaN NaN NaN 3.0 \n", + "Durant NaN NaN ... 8.2 6.8 NaN NaN 1.0 2.0 \n", + "Ibaka 1.1 0.7 ... 6.8 NaN 1.0 1.0 1.0 NaN \n", + "\n", + " \n", + " Rebound \n", + "TeamName Magic Raptors Thunder Warriors \n", + "Player \n", + "Curry NaN NaN NaN 3.0 \n", + "Durant NaN NaN 1.0 2.0 \n", + "Ibaka 1.0 1.0 1.0 NaN \n", + "\n", + "[3 rows x 24 columns]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bball.pivot_table(index=\"Player\", columns=\"TeamName\", values=[\"Rebound\",\"Assist\"], aggfunc=[np.max, np.min, len])" + ] + } + ], + "metadata": { + "date": 1584040763.8179712, + "filename": "reshape.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "Reshape" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/7_merge.ipynb b/Session_7/7_merge.ipynb new file mode 100644 index 0000000..501a541 --- /dev/null +++ b/Session_7/7_merge.ipynb @@ -0,0 +1,5601 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Merge\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [Reshape](https://datascience.quantecon.org/reshape.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Know the different pandas routines for combining datasets \n", + "- Know when to use `pd.concat` vs `pd.merge` vs `pd.join` \n", + "- Be able to apply the three main combining routines \n", + "\n", + "\n", + "**Data**\n", + "\n", + "- WDI data on GDP components, population, and square miles of countries \n", + "- Book ratings: 6,000,000 ratings for the 10,000 most rated books on\n", + " [Goodreads](https://www.goodreads.com/) \n", + "- Details for all delayed US domestic flights in November 2016,\n", + " obtained from the [Bureau of Transportation\n", + " Statistics](https://www.transtats.bts.gov/DL_SelectFields.asp?Table_ID=236&DB_Short_Name=On-Time) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [Merge](#Merge) \n", + " - [Combining Datasets](#Combining-Datasets) \n", + " - [`pd.concat`](#`pd.concat`) \n", + " - [`pd.merge`](#`pd.merge`) \n", + " - [Arguments to `merge`](#Arguments-to-`merge`) \n", + " - [`df.join`](#`df.join`) \n", + " - [Case Study](#Case-Study) \n", + " - [Extra Example: Airline Delays](#Extra-Example:-Airline-Delays) \n", + " - [Visualizing Merge Operations](#Visualizing-Merge-Operations) \n", + " - [Exercises](#Exercises) " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: six>=1.0.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pyarrow->qeds) (1.12.0)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: python-dateutil>=2.6.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2.8.0)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n" + ] + } + ], + "source": [ + "# Uncomment following line to install on colab\n", + "! pip install qeds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Combining Datasets\n", + "\n", + "Often, we will want perform joint analysis on data from different sources.\n", + "\n", + "For example, when analyzing the regional sales for a company, we might\n", + "want to include industry aggregates or demographic information for each\n", + "region.\n", + "\n", + "Or perhaps we are working with product-level data, have a list of\n", + "product groups in a separate dataset, and want to compute aggregate\n", + "statistics for each group." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import qeds\n", + "%matplotlib inline\n", + "# activate plot theme\n", + "import qeds\n", + "qeds.themes.mpl_style();\n", + "\n", + "from IPython.display import display" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "MultiIndex: 72 entries, (Canada, 2017) to (United States, 2000)\n", + "Data columns (total 5 columns):\n", + "GovExpend 72 non-null float64\n", + "Consumption 72 non-null float64\n", + "Exports 72 non-null float64\n", + "Imports 72 non-null float64\n", + "GDP 72 non-null float64\n", + "dtypes: float64(5)\n", + "memory usage: 3.2+ KB\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
country
Canada0.3726651.0954750.5828310.6000311.868164
Germany0.7455792.1120091.9305631.6663483.883870
United Kingdom0.5495381.8091540.8626290.9331452.818704
United States2.40574312.0192662.2870713.06995417.348627
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704\n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# from WDI. Units trillions of 2010 USD\n", + "url = \"https://datascience.quantecon.org/assets/data/wdi_data.csv\"\n", + "wdi = pd.read_csv(url).set_index([\"country\", \"year\"])\n", + "wdi.info()\n", + "\n", + "wdi2017 = wdi.xs(2017, level=\"year\")\n", + "wdi2017" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
countryyear
Canada20170.3726651.0954750.5828310.6000311.868164
20160.3648991.0584260.5763940.5757751.814016
Germany20170.7455792.1120091.9305631.6663483.883870
20160.7340142.0756151.8449491.5894953.801859
United Kingdom20170.5495381.8091540.8626290.9331452.818704
20160.5505961.7723480.8167920.9014942.768241
United States20172.40574312.0192662.2870713.06995417.348627
20162.40798111.7221332.2199372.93600416.972348
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country year \n", + "Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164\n", + " 2016 0.364899 1.058426 0.576394 0.575775 1.814016\n", + "Germany 2017 0.745579 2.112009 1.930563 1.666348 3.883870\n", + " 2016 0.734014 2.075615 1.844949 1.589495 3.801859\n", + "United Kingdom 2017 0.549538 1.809154 0.862629 0.933145 2.818704\n", + " 2016 0.550596 1.772348 0.816792 0.901494 2.768241\n", + "United States 2017 2.405743 12.019266 2.287071 3.069954 17.348627\n", + " 2016 2.407981 11.722133 2.219937 2.936004 16.972348" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi2016_17 = wdi.loc[pd.IndexSlice[:, [2016, 2017]],: ]\n", + "wdi2016_17" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sq_miles
country
United States3.8000
Canada3.8000
Germany0.1370
United Kingdom0.0936
Russia6.6000
\n", + "
" + ], + "text/plain": [ + " sq_miles\n", + "country \n", + "United States 3.8000\n", + "Canada 3.8000\n", + "Germany 0.1370\n", + "United Kingdom 0.0936\n", + "Russia 6.6000" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Data from https://www.nationmaster.com/country-info/stats/Geography/Land-area/Square-miles\n", + "# units -- millions of square miles\n", + "sq_miles = pd.Series({\n", + " \"United States\": 3.8,\n", + " \"Canada\": 3.8,\n", + " \"Germany\": 0.137,\n", + " \"United Kingdom\": 0.0936,\n", + " \"Russia\": 6.6,\n", + "}, name=\"sq_miles\").to_frame()\n", + "sq_miles.index.name = \"country\"\n", + "sq_miles" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "MultiIndex: 72 entries, (Canada, 2017) to (United States, 2000)\n", + "Data columns (total 1 columns):\n", + "Population 72 non-null float64\n", + "dtypes: float64(1)\n", + "memory usage: 1005.0+ bytes\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Population
countryyear
Canada201736.540268
201636.109487
201535.702908
201435.437435
201335.082954
201234.714222
201134.339328
201034.004889
200933.628895
200833.247118
\n", + "
" + ], + "text/plain": [ + " Population\n", + "country year \n", + "Canada 2017 36.540268\n", + " 2016 36.109487\n", + " 2015 35.702908\n", + " 2014 35.437435\n", + " 2013 35.082954\n", + " 2012 34.714222\n", + " 2011 34.339328\n", + " 2010 34.004889\n", + " 2009 33.628895\n", + " 2008 33.247118" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# from WDI. Units millions of people\n", + "pop_url = \"https://datascience.quantecon.org/assets/data/wdi_population.csv\"\n", + "pop = pd.read_csv(pop_url).set_index([\"country\", \"year\"])\n", + "pop.info()\n", + "pop.head(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Suppose that we were asked to compute a number of statistics with the data above:\n", + "\n", + "- As a measure of land usage or productivity, what is Consumption per square mile? \n", + "- What is GDP per capita (per person) for each country in each year? How about\n", + " Consumption per person? \n", + "- What is the population density of each country? How much does it change over time? \n", + "\n", + "\n", + "Notice that to answer any of the questions from above, we will have to use data\n", + "from more than one of our DataFrames.\n", + "\n", + "In this lecture, we will learn many techniques for combining datasets that\n", + "originate from different sources, careful to ensure that data is properly\n", + "aligned.\n", + "\n", + "In pandas three main methods can combine datasets:\n", + "\n", + "1. `pd.concat([dfs...])` \n", + "1. `pd.merge(df1, df2)` \n", + "1. `df1.join(df2)` \n", + "\n", + "\n", + "We’ll look at each one." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `pd.concat`\n", + "\n", + "The `pd.concat` function is used to stack two or more DataFrames\n", + "together.\n", + "\n", + "An example of when you might want to do this is if you have monthly data\n", + "in separate files on your computer and would like to have 1 year of data\n", + "in a single DataFrame.\n", + "\n", + "The first argument to `pd.concat` is a list of DataFrames to be\n", + "stitched together.\n", + "\n", + "The other commonly used argument is named `axis`.\n", + "\n", + "As we have seen before, many pandas functions have an `axis` argument\n", + "that specifies whether a particular operation should happen down rows\n", + "(`axis=0`) or along columns (`axis=1`).\n", + "\n", + "In the context of `pd.concat`, setting `axis=0` (the default case)\n", + "will stack DataFrames on top of one another while `axis=1` stacks them\n", + "side by side.\n", + "\n", + "We’ll look at each case separately." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `axis=0`\n", + "\n", + "When we call `pd.concat` and set `axis=0`, the list of DataFrames\n", + "passed in the first argument will be stacked on top of one another.\n", + "\n", + "Let’s try it out here." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\asus\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:2: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n", + "of pandas will change to not sort by default.\n", + "\n", + "To accept the future behavior, pass 'sort=False'.\n", + "\n", + "To retain the current behavior and silence the warning, pass 'sort=True'.\n", + "\n", + " \n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ConsumptionExportsGDPGovExpendImportssq_miles
country
Canada1.0954750.5828311.8681640.3726650.600031NaN
Germany2.1120091.9305633.8838700.7455791.666348NaN
United Kingdom1.8091540.8626292.8187040.5495380.933145NaN
United States12.0192662.28707117.3486272.4057433.069954NaN
United StatesNaNNaNNaNNaNNaN3.8000
CanadaNaNNaNNaNNaNNaN3.8000
GermanyNaNNaNNaNNaNNaN0.1370
United KingdomNaNNaNNaNNaNNaN0.0936
RussiaNaNNaNNaNNaNNaN6.6000
\n", + "
" + ], + "text/plain": [ + " Consumption Exports GDP GovExpend Imports \\\n", + "country \n", + "Canada 1.095475 0.582831 1.868164 0.372665 0.600031 \n", + "Germany 2.112009 1.930563 3.883870 0.745579 1.666348 \n", + "United Kingdom 1.809154 0.862629 2.818704 0.549538 0.933145 \n", + "United States 12.019266 2.287071 17.348627 2.405743 3.069954 \n", + "United States NaN NaN NaN NaN NaN \n", + "Canada NaN NaN NaN NaN NaN \n", + "Germany NaN NaN NaN NaN NaN \n", + "United Kingdom NaN NaN NaN NaN NaN \n", + "Russia NaN NaN NaN NaN NaN \n", + "\n", + " sq_miles \n", + "country \n", + "Canada NaN \n", + "Germany NaN \n", + "United Kingdom NaN \n", + "United States NaN \n", + "United States 3.8000 \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "Russia 6.6000 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# equivalent to pd.concat([wdi2017, sq_miles]) -- axis=0 is default\n", + "pd.concat([wdi2017, sq_miles], axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice a few things:\n", + "\n", + "- \n", + "
\n", + "
The number of rows in the output is the total number
\n", + "
\n", + " of rows in all inputs. The labels are all from the original\n", + " DataFrames. \n", + "
\n", + " \n", + "
\n", + " \n", + "- The column labels are all the distinct column labels from all the inputs. \n", + "- For columns that appeared only in one input, the value for all row labels\n", + " originating from a different input is equal to `NaN` (marked as missing). " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `axis=1`\n", + "\n", + "In this example, concatenating by stacking\n", + "side-by-side makes more sense.\n", + "\n", + "We accomplish this by passing `axis=1` to `pd.concat`:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\asus\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n", + "of pandas will change to not sort by default.\n", + "\n", + "To accept the future behavior, pass 'sort=False'.\n", + "\n", + "To retain the current behavior and silence the warning, pass 'sort=True'.\n", + "\n", + " \"\"\"Entry point for launching an IPython kernel.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
RussiaNaNNaNNaNNaNNaN6.6000
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "Russia NaN NaN NaN NaN NaN \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "Russia 6.6000 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.concat([wdi2017, sq_miles], axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice here that\n", + "\n", + "- The index entries are all unique index entries that appeared in any DataFrame. \n", + "- The column labels are all column labels from the inputs. \n", + "- As `wdi2017` didn’t have a `Russia` row, the value for all of its columns\n", + " is `NaN`. \n", + "\n", + "\n", + "Now we can answer one of our questions from above: What is\n", + "Consumption per square mile?" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\asus\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n", + "of pandas will change to not sort by default.\n", + "\n", + "To accept the future behavior, pass 'sort=False'.\n", + "\n", + "To retain the current behavior and silence the warning, pass 'sort=True'.\n", + "\n", + " \"\"\"Entry point for launching an IPython kernel.\n" + ] + }, + { + "data": { + "text/plain": [ + "Canada 0.288283\n", + "Germany 15.416124\n", + "Russia NaN\n", + "United Kingdom 19.328569\n", + "United States 3.162965\n", + "dtype: float64" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "temp = pd.concat([wdi2017, sq_miles], axis=1)\n", + "temp[\"Consumption\"] / temp[\"sq_miles\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `pd.merge`\n", + "\n", + "`pd.merge` operates on two DataFrames at a time and is primarily used\n", + "to bring columns from one DataFrame into another, *aligning* data based\n", + "on one or more “key” columns.\n", + "\n", + "This is a somewhat difficult concept to grasp by reading, so let’s look at some\n", + "examples." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(wdi2017, sq_miles, on=\"country\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The output here looks very similar to what we saw with `concat` and\n", + "`axis=1`, except that the row for `Russia` does not appear.\n", + "\n", + "We will talk more about why this happened soon.\n", + "\n", + "For now, let’s look at a slightly more intriguing example:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Canada0.3648991.0584260.5763940.5757751.8140163.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
Germany0.7340142.0756151.8449491.5894953.8018590.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United Kingdom0.5505961.7723480.8167920.9014942.7682410.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
United States2.40798111.7221332.2199372.93600416.9723483.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Canada 0.364899 1.058426 0.576394 0.575775 1.814016 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "Germany 0.734014 2.075615 1.844949 1.589495 3.801859 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United Kingdom 0.550596 1.772348 0.816792 0.901494 2.768241 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "United States 2.407981 11.722133 2.219937 2.936004 16.972348 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 \n", + "United States 3.8000 " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(wdi2016_17, sq_miles, on=\"country\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here’s how we think about what happened:\n", + "\n", + "- The data in `wdi2016_17` is copied over exactly as is. \n", + "- Because `country` was on the index for both DataFrames, it is on the\n", + " index of the output. \n", + "- We lost the year on the index – we’ll work on getting it back below. \n", + "- The additional column in `sq_miles` was added to column labels for the\n", + " output. \n", + "- The data from the `sq_miles` column was added to the output by looking up\n", + " rows where the `country` in the two DataFrames lined up.\n", + " - Note that all the countries appeared twice, and the data in `sq_miles` was repeated. This is because `wdi2016_17` had two rows for each country.\n", + " - Also note that because `Russia` did not appear in `wdi2016_17`, the value `sq_miles.loc[\"Russia\"]` (i.e. `6.6`) is not used the output. \n", + "\n", + "\n", + "How do we get the year back?\n", + "\n", + "We must first call `reset_index` on `wdi2016_17` so\n", + "that in the first step when all columns are copied over, `year` is included." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryyearGovExpendConsumptionExportsImportsGDPsq_miles
0Canada20170.3726651.0954750.5828310.6000311.8681643.8000
1Canada20160.3648991.0584260.5763940.5757751.8140163.8000
2Germany20170.7455792.1120091.9305631.6663483.8838700.1370
3Germany20160.7340142.0756151.8449491.5894953.8018590.1370
4United Kingdom20170.5495381.8091540.8626290.9331452.8187040.0936
5United Kingdom20160.5505961.7723480.8167920.9014942.7682410.0936
6United States20172.40574312.0192662.2870713.06995417.3486273.8000
7United States20162.40798111.7221332.2199372.93600416.9723483.8000
\n", + "
" + ], + "text/plain": [ + " country year GovExpend Consumption Exports Imports \\\n", + "0 Canada 2017 0.372665 1.095475 0.582831 0.600031 \n", + "1 Canada 2016 0.364899 1.058426 0.576394 0.575775 \n", + "2 Germany 2017 0.745579 2.112009 1.930563 1.666348 \n", + "3 Germany 2016 0.734014 2.075615 1.844949 1.589495 \n", + "4 United Kingdom 2017 0.549538 1.809154 0.862629 0.933145 \n", + "5 United Kingdom 2016 0.550596 1.772348 0.816792 0.901494 \n", + "6 United States 2017 2.405743 12.019266 2.287071 3.069954 \n", + "7 United States 2016 2.407981 11.722133 2.219937 2.936004 \n", + "\n", + " GDP sq_miles \n", + "0 1.868164 3.8000 \n", + "1 1.814016 3.8000 \n", + "2 3.883870 0.1370 \n", + "3 3.801859 0.1370 \n", + "4 2.818704 0.0936 \n", + "5 2.768241 0.0936 \n", + "6 17.348627 3.8000 \n", + "7 16.972348 3.8000 " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(wdi2016_17.reset_index(), sq_miles, on=\"country\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Multiple Columns\n", + "\n", + "Sometimes, we need to merge multiple columns.\n", + "\n", + "For example our `pop` and `wdi2016_17` DataFrames both have observations\n", + "organized by country and year.\n", + "\n", + "To properly merge these datasets, we would need to align the data by\n", + "both country and year.\n", + "\n", + "We pass a list to the `on` argument to accomplish this:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPPopulation
countryyear
Canada20170.3726651.0954750.5828310.6000311.86816436.540268
20160.3648991.0584260.5763940.5757751.81401636.109487
Germany20170.7455792.1120091.9305631.6663483.88387082.657002
20160.7340142.0756151.8449491.5894953.80185982.348669
United Kingdom20170.5495381.8091540.8626290.9331452.81870466.058859
20160.5505961.7723480.8167920.9014942.76824165.595565
United States20172.40574312.0192662.2870713.06995417.348627325.147121
20162.40798111.7221332.2199372.93600416.972348323.071342
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country year \n", + "Canada 2017 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + " 2016 0.364899 1.058426 0.576394 0.575775 1.814016 \n", + "Germany 2017 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + " 2016 0.734014 2.075615 1.844949 1.589495 3.801859 \n", + "United Kingdom 2017 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + " 2016 0.550596 1.772348 0.816792 0.901494 2.768241 \n", + "United States 2017 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + " 2016 2.407981 11.722133 2.219937 2.936004 16.972348 \n", + "\n", + " Population \n", + "country year \n", + "Canada 2017 36.540268 \n", + " 2016 36.109487 \n", + "Germany 2017 82.657002 \n", + " 2016 82.348669 \n", + "United Kingdom 2017 66.058859 \n", + " 2016 65.595565 \n", + "United States 2017 325.147121 \n", + " 2016 323.071342 " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(wdi2016_17, pop, on=[\"country\", \"year\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we can answer more of our questions from above: What is GDP per capita (per\n", + "person) for each country in each year? How about Consumption per person?" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "country year\n", + "Canada 2017 0.051126\n", + " 2016 0.050237\n", + "Germany 2017 0.046988\n", + " 2016 0.046168\n", + "United Kingdom 2017 0.042670\n", + " 2016 0.042202\n", + "United States 2017 0.053356\n", + " 2016 0.052534\n", + "dtype: float64" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi_pop = pd.merge(wdi2016_17, pop, on=[\"country\", \"year\"])\n", + "wdi_pop[\"GDP\"] / wdi_pop[\"Population\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "country year\n", + "Canada 2017 0.029980\n", + " 2016 0.029312\n", + "Germany 2017 0.025551\n", + " 2016 0.025205\n", + "United Kingdom 2017 0.027387\n", + " 2016 0.027019\n", + "United States 2017 0.036966\n", + " 2016 0.036283\n", + "dtype: float64" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi_pop[\"Consumption\"] / wdi_pop[\"Population\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Arguments to `merge`\n", + "\n", + "The `pd.merge` function can take many optional arguments.\n", + "\n", + "We’ll talk about a few of the most commonly-used ones here and refer you\n", + "to the\n", + "[documentation](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.merge.html#pandas.merge)\n", + "for more details.\n", + "\n", + "We’ll follow the pandas convention and refer to the first argument to\n", + "`pd.merge` as `left` and call the second `right`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `on`\n", + "\n", + "We have already seen this one used before, but we want to point out that on\n", + "is optional.\n", + "\n", + "If nothing is given for this argument, pandas will use **all** columns\n", + "in `left` and `right` with the same name.\n", + "\n", + "In our example, `country` is the only column that appears in both\n", + "DataFrames, so it is used for `on` if we don’t pass anything.\n", + "\n", + "The following two are equivalent." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(wdi2017, sq_miles, on=\"country\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countryGovExpendConsumptionExportsImportsGDPsq_miles
0Canada0.3726651.0954750.5828310.6000311.8681643.8000
1Germany0.7455792.1120091.9305631.6663483.8838700.1370
2United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
3United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " country GovExpend Consumption Exports Imports GDP \\\n", + "0 Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "1 Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "2 United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "3 United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "0 3.8000 \n", + "1 0.1370 \n", + "2 0.0936 \n", + "3 3.8000 " + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# if we move index back to columns, the `on` is un-necessary\n", + "pd.merge(wdi2017.reset_index(), sq_miles.reset_index())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `left_on`, `right_on`\n", + "\n", + "Above, we used the `on` argument to identify a column in both `left`\n", + "and `right` that was used to align data.\n", + "\n", + "Sometimes, both DataFrames don’t have the same name for this column.\n", + "\n", + "In that case, we use the `left_on` and `right_on` arguments, passing\n", + "the proper column name(s) to align the data.\n", + "\n", + "We’ll show you an example below, but it is somewhat silly as our\n", + "DataFrames do both have the `country` column." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(wdi2017, sq_miles, left_on=\"country\", right_on=\"country\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `left_index`, `right_index`\n", + "\n", + "Sometimes, as in our example, the key used to align data is actually in the\n", + "index instead of one of the columns.\n", + "\n", + "In this case, we can use the `left_index` or `right_index` arguments.\n", + "\n", + "We should only set these values to a boolean (`True` or `False`).\n", + "\n", + "Let’s practice with this." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(wdi2017, sq_miles, left_on=\"country\", right_index=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `how`\n", + "\n", + "The `how` is perhaps the most powerful, but most conceptually\n", + "difficult of the arguments we will cover.\n", + "\n", + "This argument controls which values from the key column(s) appear in the\n", + "output.\n", + "\n", + "The 4 possible options for this argument are summarized in\n", + "the image below.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/merge_files/merge_venns.png](https://datascience.quantecon.org/assets/_static/merge_files/merge_venns.png) \n", + "In words, we have:\n", + "\n", + "- `left`: Default and what we described above. It uses\n", + " the keys from the `left` DataFrame. \n", + "- `right`: Output will contain all keys from `right`. \n", + "- `inner`: The output will only contain keys that appear in *both*\n", + " `left` and `right`. \n", + "- `outer`: The output will contain any key found in either `left`\n", + " or `right`. \n", + "\n", + "\n", + "In addition to the above, we will use the following two DataFrames to\n", + "illustrate the `how` option." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
country
Canada0.3726651.0954750.5828310.6000311.868164
Germany0.7455792.1120091.9305631.6663483.883870
United Kingdom0.5495381.8091540.8626290.9331452.818704
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi2017_no_US = wdi2017.drop(\"United States\")\n", + "wdi2017_no_US" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sq_miles
country
United States3.8000
Canada3.8000
United Kingdom0.0936
Russia6.6000
\n", + "
" + ], + "text/plain": [ + " sq_miles\n", + "country \n", + "United States 3.8000\n", + "Canada 3.8000\n", + "United Kingdom 0.0936\n", + "Russia 6.6000" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sq_miles_no_germany = sq_miles.drop(\"Germany\")\n", + "sq_miles_no_germany" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let’s see all the possible `how` options." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# default\n", + "pd.merge(wdi2017, sq_miles, on=\"country\", how=\"left\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
RussiaNaNNaNNaNNaNNaN6.6000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "Russia NaN NaN NaN NaN NaN \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 \n", + "Russia 6.6000 " + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# notice ``Russia`` is included\n", + "pd.merge(wdi2017, sq_miles, on=\"country\", how=\"right\")" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP sq_miles\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 3.8000\n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 0.1370\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 0.0936" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# notice no United States or Russia\n", + "pd.merge(wdi2017_no_US, sq_miles, on=\"country\", how=\"inner\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.883870NaN
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United StatesNaNNaNNaNNaNNaN3.8000
RussiaNaNNaNNaNNaNNaN6.6000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP sq_miles\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 3.8000\n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 NaN\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 0.0936\n", + "United States NaN NaN NaN NaN NaN 3.8000\n", + "Russia NaN NaN NaN NaN NaN 6.6000" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# includes all 5, even though they don't all appear in either DataFrame\n", + "pd.merge(wdi2017_no_US, sq_miles_no_germany, on=\"country\", how=\"outer\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `df.merge(df2)`\n", + "\n", + "Note that the DataFrame type has a `merge` *method*.\n", + "\n", + "It is the same as the function we have been working with, but passes the\n", + "DataFrame before the period as `left`.\n", + "\n", + "Thus `df.merge(other)` is equivalent to `pd.merge(df, other)`." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
RussiaNaNNaNNaNNaNNaN6.6000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "Russia NaN NaN NaN NaN NaN \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 \n", + "Russia 6.6000 " + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi2017.merge(sq_miles, on=\"country\", how=\"right\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `df.join`\n", + "\n", + "The `join` method for a DataFrame is very similar to the `merge`\n", + "method described above, but only allows you to use the index of the\n", + "`right` DataFrame as the join key.\n", + "\n", + "Thus, `left.join(right, on=\"country\")` is equivalent to calling\n", + "`pd.merge(left, right, left_on=\"country\", right_index=True)`.\n", + "\n", + "The implementation of the `join` method calls `merge` internally,\n", + "but sets the `left_on` and `right_index` arguments for you.\n", + "\n", + "You can do anything with `df.join` that you can do with\n", + "`df.merge`, but df.join` is more convenient to use if the keys of `right`\n", + "are in the index." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi2017.join(sq_miles, on=\"country\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wdi2017.merge(sq_miles, left_on=\"country\", right_index=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case Study\n", + "\n", + "Let’s put these tools to practice by loading some real datasets and\n", + "seeing how these functions can be applied.\n", + "\n", + "We’ll analyze ratings of books from the website [Goodreads](https://www.goodreads.com/).\n", + "\n", + "We accessed the data [here](https://github.com/zygmuntz/goodbooks-10k).\n", + "\n", + "Let’s load it up." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_idbook_idrating
012585
1240814
222605
3292965
4223183
\n", + "
" + ], + "text/plain": [ + " user_id book_id rating\n", + "0 1 258 5\n", + "1 2 4081 4\n", + "2 2 260 5\n", + "3 2 9296 5\n", + "4 2 2318 3" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 5976479 entries, 0 to 5976478\n", + "Data columns (total 3 columns):\n", + "user_id int64\n", + "book_id int64\n", + "rating int64\n", + "dtypes: int64(3)\n", + "memory usage: 136.8 MB\n" + ] + } + ], + "source": [ + "ratings = qeds.data.load(\"goodreads_ratings\")\n", + "display(ratings.head())\n", + "ratings.info()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can already do some interesting things with just the ratings data.\n", + "\n", + "Let’s see how many ratings of each number are in our dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "ratings[\"rating\"].value_counts().sort_index().plot(kind=\"bar\");" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s also see how many users have rated `N` books, for all `N`\n", + "possible.\n", + "\n", + "To do this, we will use `value_counts` twice (can you think of why?).\n", + "\n", + "We will see a more flexible way of performing similar grouped operations in\n", + "a future lecture." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
N_ratingsN_users
0191
1201
2213
32213
4235
52411
62513
72623
82734
92826
\n", + "
" + ], + "text/plain": [ + " N_ratings N_users\n", + "0 19 1\n", + "1 20 1\n", + "2 21 3\n", + "3 22 13\n", + "4 23 5\n", + "5 24 11\n", + "6 25 13\n", + "7 26 23\n", + "8 27 34\n", + "9 28 26" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "users_by_n = (\n", + " ratings[\"user_id\"]\n", + " .value_counts() # Series. Index: user_id, value: n ratings by user\n", + " .value_counts() # Series. Index: n_ratings by user, value: N_users with this many ratings\n", + " .sort_index() # Sort our Series by the index (number of ratings)\n", + " .reset_index() # Dataframe with columns `index` (from above) and `user_id`\n", + " .rename(columns={\"index\": \"N_ratings\", \"user_id\": \"N_users\"})\n", + ")\n", + "users_by_n.head(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s look at some statistics on that dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
N_ratingsN_users
count181.00000181.000000
mean109.01105295.160221
std52.41342309.461848
min19.000001.000000
25%64.0000040.000000
50%109.00000158.000000
75%154.00000538.000000
max200.00000964.000000
\n", + "
" + ], + "text/plain": [ + " N_ratings N_users\n", + "count 181.00000 181.000000\n", + "mean 109.01105 295.160221\n", + "std 52.41342 309.461848\n", + "min 19.00000 1.000000\n", + "25% 64.00000 40.000000\n", + "50% 109.00000 158.000000\n", + "75% 154.00000 538.000000\n", + "max 200.00000 964.000000" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "users_by_n.describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see the same data visually in a box plot." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "N_ratings AxesSubplot(0.125,0.125;0.352273x0.755)\n", + "N_users AxesSubplot(0.547727,0.125;0.352273x0.755)\n", + "dtype: object" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "users_by_n.plot(kind=\"box\", subplots=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s practice applying the want operator…\n", + "\n", + "**Want**: Determine whether a relationship between the number of\n", + "ratings a user has written and the distribution of the ratings exists. (Maybe we\n", + "are an author hoping to inflate our ratings and wonder if we should\n", + "target “more experienced” Goodreads users, or focus on newcomers.)\n", + "\n", + "Let’s start from the result and work our way backwards:\n", + "\n", + "1. We can answer our question if we have two similar DataFrames: \n", + " - All ratings by the `N` (e.g. 5) users with the most ratings \n", + " - All ratings by the `N` users with the least number of\n", + " ratings \n", + "1. To get that, we will need to extract rows of `ratings` with\n", + " `user_id` associated with the `N` most and least prolific raters \n", + "1. For that, we need the most and least active `user_id`s \n", + "1. To get that info, we need a count of how many ratings each user left. \n", + " - We can get that with `df[\"user_id\"].value_counts()`, so let’s\n", + " start there. " + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "30944 200\n", + "12874 200\n", + "52036 199\n", + "28158 199\n", + "12381 199\n", + "Name: user_id, dtype: int64" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# step 4\n", + "n_ratings = ratings[\"user_id\"].value_counts()\n", + "n_ratings.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "# step 3\n", + "N = 5\n", + "most_prolific_users = n_ratings.nlargest(5).index.tolist()\n", + "least_prolific_users = n_ratings.nsmallest(5).index.tolist()" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "# step 2\n", + "active_ratings = ratings.loc[ratings[\"user_id\"].isin(most_prolific_users), :]\n", + "inactive_ratings = ratings.loc[ratings[\"user_id\"].isin(least_prolific_users), :]" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# step 1 -- get the answer!\n", + "active_ratings[\"rating\"].value_counts().sort_index().plot(\n", + " kind=\"bar\", title=\"Distribution of ratings by most active users\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "inactive_ratings[\"rating\"].value_counts().sort_index().plot(\n", + " kind=\"bar\", title=\"Distribution of ratings by least active users\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nice! From the picture above, the new users look much more\n", + "likely to leave 5 star ratings than more experienced users." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Book Data\n", + "\n", + "We know what you are probably thinking: “Isn’t this a lecture on merging?\n", + "Why are we only using one dataset?”\n", + "\n", + "We hear you.\n", + "\n", + "Let’s also load a dataset containing information on the actual books." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "shape: (10000, 3)\n", + "dtypes:\n", + "book_id int64\n", + "authors object\n", + "title object\n", + "dtype: object\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
book_idauthorstitle
01Suzanne CollinsThe Hunger Games (The Hunger Games, #1)
12J.K. Rowling, Mary GrandPréHarry Potter and the Sorcerer's Stone (Harry P...
23Stephenie MeyerTwilight (Twilight, #1)
34Harper LeeTo Kill a Mockingbird
45F. Scott FitzgeraldThe Great Gatsby
\n", + "
" + ], + "text/plain": [ + " book_id authors \\\n", + "0 1 Suzanne Collins \n", + "1 2 J.K. Rowling, Mary GrandPré \n", + "2 3 Stephenie Meyer \n", + "3 4 Harper Lee \n", + "4 5 F. Scott Fitzgerald \n", + "\n", + " title \n", + "0 The Hunger Games (The Hunger Games, #1) \n", + "1 Harry Potter and the Sorcerer's Stone (Harry P... \n", + "2 Twilight (Twilight, #1) \n", + "3 To Kill a Mockingbird \n", + "4 The Great Gatsby " + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "books = qeds.data.load(\"goodreads_books\")\n", + "# we only need a few of the columns\n", + "books = books[[\"book_id\", \"authors\", \"title\"]]\n", + "print(\"shape: \", books.shape)\n", + "print(\"dtypes:\\n\", books.dtypes, sep=\"\")\n", + "books.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We could do similar interesting things with just the books dataset,\n", + "but we will skip it for now and merge them together." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "rated_books = pd.merge(ratings, books)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let’s see which books have been most often rated." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Harry Potter and the Prisoner of Azkaban (Harry Potter, #3)',\n", + " \"Harry Potter and the Sorcerer's Stone (Harry Potter, #1)\",\n", + " 'Harry Potter and the Chamber of Secrets (Harry Potter, #2)',\n", + " 'The Great Gatsby',\n", + " 'To Kill a Mockingbird',\n", + " 'The Hobbit',\n", + " 'Twilight (Twilight, #1)',\n", + " 'The Hunger Games (The Hunger Games, #1)',\n", + " 'Catching Fire (The Hunger Games, #2)',\n", + " 'Mockingjay (The Hunger Games, #3)']" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "most_rated_books_id = rated_books[\"book_id\"].value_counts().nlargest(10).index\n", + "most_rated_books = rated_books.loc[rated_books[\"book_id\"].isin(most_rated_books_id), :]\n", + "list(most_rated_books[\"title\"].unique())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s use our `pivot_table` knowledge to compute the average rating\n", + "for each of these books." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rating
title
Catching Fire (The Hunger Games, #2)4.133422
Harry Potter and the Chamber of Secrets (Harry Potter, #2)4.229418
Harry Potter and the Prisoner of Azkaban (Harry Potter, #3)4.418732
Harry Potter and the Sorcerer's Stone (Harry Potter, #1)4.351350
Mockingjay (The Hunger Games, #3)3.853131
The Great Gatsby3.772224
The Hobbit4.148477
The Hunger Games (The Hunger Games, #1)4.279707
To Kill a Mockingbird4.329369
Twilight (Twilight, #1)3.214341
\n", + "
" + ], + "text/plain": [ + " rating\n", + "title \n", + "Catching Fire (The Hunger Games, #2) 4.133422\n", + "Harry Potter and the Chamber of Secrets (Harry ... 4.229418\n", + "Harry Potter and the Prisoner of Azkaban (Harry... 4.418732\n", + "Harry Potter and the Sorcerer's Stone (Harry Po... 4.351350\n", + "Mockingjay (The Hunger Games, #3) 3.853131\n", + "The Great Gatsby 3.772224\n", + "The Hobbit 4.148477\n", + "The Hunger Games (The Hunger Games, #1) 4.279707\n", + "To Kill a Mockingbird 4.329369\n", + "Twilight (Twilight, #1) 3.214341" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "most_rated_books.pivot_table(values=\"rating\", index=\"title\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These ratings seem surprisingly low, given that they are the most often\n", + "rated books on Goodreads.\n", + "\n", + "I wonder what the bottom of the distribution looks like…" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s compute the average number of ratings for each book in our sample." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rating
title
The Complete Calvin and Hobbes4.829876
ESV Study Bible4.818182
Attack of the Deranged Mutant Killer Monster Snow Goons4.768707
The Indispensable Calvin and Hobbes4.766355
The Revenge of the Baby-Sat4.761364
There's Treasure Everywhere: A Calvin and Hobbes Collection4.760456
The Authoritative Calvin and Hobbes: A Calvin and Hobbes Treasury4.757202
It's a Magical World: A Calvin and Hobbes Collection4.747396
Harry Potter Boxed Set, Books 1-5 (Harry Potter, #1-5)4.736842
The Calvin and Hobbes Tenth Anniversary Book4.728528
\n", + "
" + ], + "text/plain": [ + " rating\n", + "title \n", + "The Complete Calvin and Hobbes 4.829876\n", + "ESV Study Bible 4.818182\n", + "Attack of the Deranged Mutant Killer Monster Sn... 4.768707\n", + "The Indispensable Calvin and Hobbes 4.766355\n", + "The Revenge of the Baby-Sat 4.761364\n", + "There's Treasure Everywhere: A Calvin and Hobbe... 4.760456\n", + "The Authoritative Calvin and Hobbes: A Calvin a... 4.757202\n", + "It's a Magical World: A Calvin and Hobbes Colle... 4.747396\n", + "Harry Potter Boxed Set, Books 1-5 (Harry Potter... 4.736842\n", + "The Calvin and Hobbes Tenth Anniversary Book 4.728528" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "average_ratings = (\n", + " rated_books\n", + " .pivot_table(values=\"rating\", index=\"title\")\n", + " .sort_values(by=\"rating\", ascending=False)\n", + ")\n", + "average_ratings.head(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What does the overall distribution of average ratings look like?" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# plot a kernel density estimate of average ratings\n", + "average_ratings.plot.density(xlim=(1, 5))\n", + "\n", + "# or a histogram\n", + "average_ratings.plot.hist(bins=30, xlim=(1, 5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It looks like most books have an average rating of just below 4." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extra Example: Airline Delays\n", + "\n", + "Let’s look at one more example.\n", + "\n", + "This time, we will use a dataset from the [Bureau of Transportation\n", + "Statistics](https://www.transtats.bts.gov/DL_SelectFields.asp?Table_ID=236&DB_Short_Name=On-Time)\n", + "that describes the cause of all US domestic flight delays\n", + "in November 2016:" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 460949 entries, 0 to 460948\n", + "Data columns (total 4 columns):\n", + "CRSDepTime 460949 non-null datetime64[ns]\n", + "Carrier 460949 non-null object\n", + "CarrierDelay 460949 non-null float64\n", + "ArrDelay 452229 non-null float64\n", + "dtypes: datetime64[ns](1), float64(2), object(1)\n", + "memory usage: 14.1+ MB\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CRSDepTimeCarrierCarrierDelayArrDelay
02016-12-18 15:58:00AA0.020.0
12016-12-19 15:58:00AA0.020.0
22016-12-20 15:58:00AA0.0-3.0
32016-12-21 15:58:00AA0.0-10.0
42016-12-22 15:58:00AA0.0-8.0
\n", + "
" + ], + "text/plain": [ + " CRSDepTime Carrier CarrierDelay ArrDelay\n", + "0 2016-12-18 15:58:00 AA 0.0 20.0\n", + "1 2016-12-19 15:58:00 AA 0.0 20.0\n", + "2 2016-12-20 15:58:00 AA 0.0 -3.0\n", + "3 2016-12-21 15:58:00 AA 0.0 -10.0\n", + "4 2016-12-22 15:58:00 AA 0.0 -8.0" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "air_perf = qeds.load(\"airline_performance_dec16\")[[\"CRSDepTime\", \"Carrier\", \"CarrierDelay\", \"ArrDelay\"]]\n", + "air_perf.info()\n", + "air_perf.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `Carrier` column identifies the airline and the `CarrierDelay`\n", + "reports the number of minutes of the total delay assigned as the\n", + "“carrier’s fault”.\n", + "\n", + "**Want**: Determine which airlines, on average, contribute most to\n", + "delays.\n", + "\n", + "We can do this using `pivot_table`:" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CarrierDelay
Carrier
F97.856566
EV7.125663
OO6.705469
B65.588006
DL4.674957
HA4.577753
UA4.368148
NK4.166264
AA4.073358
VX3.342923
\n", + "
" + ], + "text/plain": [ + " CarrierDelay\n", + "Carrier \n", + "F9 7.856566\n", + "EV 7.125663\n", + "OO 6.705469\n", + "B6 5.588006\n", + "DL 4.674957\n", + "HA 4.577753\n", + "UA 4.368148\n", + "NK 4.166264\n", + "AA 4.073358\n", + "VX 3.342923" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "avg_delays = (\n", + " air_perf\n", + " .pivot_table(index=\"Carrier\", values=\"CarrierDelay\", aggfunc=\"mean\")\n", + " .sort_values(\"CarrierDelay\")\n", + " .nlargest(10, \"CarrierDelay\")\n", + ")\n", + "avg_delays" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The one issue with this dataset is that we don’t know what all those two\n", + "letter carrier codes are!\n", + "\n", + "Thankfully, we have a second dataset that maps the two letter code\n", + "into the full airline name." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Description
Code
ZWAir Wisconsin Airlines Corp (1994 - )
ZXAirbc Ltd. (1990 - 2000)
ZXAir Georgian (2002 - )
ZYAtlantic Gulf Airlines (1985 - 1986)
ZYZSkyway Aviation Inc. (1960 - 2002)
\n", + "
" + ], + "text/plain": [ + " Description\n", + "Code \n", + "ZW Air Wisconsin Airlines Corp (1994 - )\n", + "ZX Airbc Ltd. (1990 - 2000)\n", + "ZX Air Georgian (2002 - )\n", + "ZY Atlantic Gulf Airlines (1985 - 1986)\n", + "ZYZ Skyway Aviation Inc. (1960 - 2002)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "carrier_code = qeds.load(\"airline_carrier_codes\")\n", + "carrier_code.tail()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s merge these names so we know which airlines we should avoid\n", + "flying…" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CarrierDelayDescription
F97.856566Frontier Airlines Inc. (1994 - )
EV7.125663ExpressJet Airlines Inc. (2012 - )
EV7.125663Atlantic Southeast Airlines (1993 - 2011)
OO6.705469SkyWest Airlines Inc. (2003 - )
B65.588006JetBlue Airways (2000 - )
DL4.674957Delta Air Lines Inc. (1960 - )
HA4.577753Hawaiian Airlines Inc. (1960 - )
UA4.368148United Air Lines Inc. (1960 - )
NK4.166264Spirit Air Lines (1992 - )
AA4.073358American Airlines Inc. (1960 - )
VX3.342923Virgin America (2007 - )
VX3.342923Aces Airlines (1992 - 2003)
\n", + "
" + ], + "text/plain": [ + " CarrierDelay Description\n", + "F9 7.856566 Frontier Airlines Inc. (1994 - )\n", + "EV 7.125663 ExpressJet Airlines Inc. (2012 - )\n", + "EV 7.125663 Atlantic Southeast Airlines (1993 - 2011)\n", + "OO 6.705469 SkyWest Airlines Inc. (2003 - )\n", + "B6 5.588006 JetBlue Airways (2000 - )\n", + "DL 4.674957 Delta Air Lines Inc. (1960 - )\n", + "HA 4.577753 Hawaiian Airlines Inc. (1960 - )\n", + "UA 4.368148 United Air Lines Inc. (1960 - )\n", + "NK 4.166264 Spirit Air Lines (1992 - )\n", + "AA 4.073358 American Airlines Inc. (1960 - )\n", + "VX 3.342923 Virgin America (2007 - )\n", + "VX 3.342923 Aces Airlines (1992 - 2003)" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "avg_delays_w_code = avg_delays.join(carrier_code)\n", + "avg_delays_w_code.sort_values(\"CarrierDelay\", ascending=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Based on that information, which airlines would you avoid near\n", + "the holidays?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing Merge Operations\n", + "\n", + "As we did in the [reshape lecture](https://datascience.quantecon.org/reshape.html), we will visualize the\n", + "various merge operations using artificial DataFrames.\n", + "\n", + "First, we create some dummy DataFrames." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is dfL: \n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2
L1A110
L2B220
L3A330
L4C440
\n", + "
" + ], + "text/plain": [ + " Key C1 C2\n", + "L1 A 1 10\n", + "L2 B 2 20\n", + "L3 A 3 30\n", + "L4 C 4 40" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is dfR:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC3
R1A100
R2B200
R3C300
R4D400
\n", + "
" + ], + "text/plain": [ + " Key C3\n", + "R1 A 100\n", + "R2 B 200\n", + "R3 C 300\n", + "R4 D 400" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "dfL = pd.DataFrame(\n", + " {\"Key\": [\"A\", \"B\", \"A\", \"C\"], \"C1\":[1, 2, 3, 4], \"C2\": [10, 20, 30, 40]},\n", + " index=[\"L1\", \"L2\", \"L3\", \"L4\"]\n", + ")[[\"Key\", \"C1\", \"C2\"]]\n", + "\n", + "print(\"This is dfL: \")\n", + "display(dfL)\n", + "\n", + "dfR = pd.DataFrame(\n", + " {\"Key\": [\"A\", \"B\", \"C\", \"D\"], \"C3\": [100, 200, 300, 400]},\n", + " index=[\"R1\", \"R2\", \"R3\", \"R4\"]\n", + ")[[\"Key\", \"C3\"]]\n", + "\n", + "print(\"This is dfR:\")\n", + "display(dfR)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `pd.concat`\n", + "\n", + "Recall that calling `pd.concat(..., axis=0)` will stack DataFrames on top of\n", + "one another:" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\asus\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n", + "of pandas will change to not sort by default.\n", + "\n", + "To accept the future behavior, pass 'sort=False'.\n", + "\n", + "To retain the current behavior and silence the warning, pass 'sort=True'.\n", + "\n", + " \"\"\"Entry point for launching an IPython kernel.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
C1C2C3Key
L11.010.0NaNA
L22.020.0NaNB
L33.030.0NaNA
L44.040.0NaNC
R1NaNNaN100.0A
R2NaNNaN200.0B
R3NaNNaN300.0C
R4NaNNaN400.0D
\n", + "
" + ], + "text/plain": [ + " C1 C2 C3 Key\n", + "L1 1.0 10.0 NaN A\n", + "L2 2.0 20.0 NaN B\n", + "L3 3.0 30.0 NaN A\n", + "L4 4.0 40.0 NaN C\n", + "R1 NaN NaN 100.0 A\n", + "R2 NaN NaN 200.0 B\n", + "R3 NaN NaN 300.0 C\n", + "R4 NaN NaN 400.0 D" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.concat([dfL, dfR], axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here’s how we might visualize that.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/merge_files/concat_axis0.gif](https://datascience.quantecon.org/assets/_static/merge_files/concat_axis0.gif) \n", + "We can also set `axis=1` to stack side by side." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\asus\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n", + "of pandas will change to not sort by default.\n", + "\n", + "To accept the future behavior, pass 'sort=False'.\n", + "\n", + "To retain the current behavior and silence the warning, pass 'sort=True'.\n", + "\n", + " \"\"\"Entry point for launching an IPython kernel.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2KeyC3
L1A1.010.0NaNNaN
L2B2.020.0NaNNaN
L3A3.030.0NaNNaN
L4C4.040.0NaNNaN
R1NaNNaNNaNA100.0
R2NaNNaNNaNB200.0
R3NaNNaNNaNC300.0
R4NaNNaNNaND400.0
\n", + "
" + ], + "text/plain": [ + " Key C1 C2 Key C3\n", + "L1 A 1.0 10.0 NaN NaN\n", + "L2 B 2.0 20.0 NaN NaN\n", + "L3 A 3.0 30.0 NaN NaN\n", + "L4 C 4.0 40.0 NaN NaN\n", + "R1 NaN NaN NaN A 100.0\n", + "R2 NaN NaN NaN B 200.0\n", + "R3 NaN NaN NaN C 300.0\n", + "R4 NaN NaN NaN D 400.0" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.concat([dfL, dfR], axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here’s how we might visualize that.\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/merge_files/concat_axis1.gif](https://datascience.quantecon.org/assets/_static/merge_files/concat_axis1.gif) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `pd.merge`\n", + "\n", + "The animation below shows a visualization of what happens when we call" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2C3
0A110100
1A330100
2B220200
3C440300
\n", + "
" + ], + "text/plain": [ + " Key C1 C2 C3\n", + "0 A 1 10 100\n", + "1 A 3 30 100\n", + "2 B 2 20 200\n", + "3 C 4 40 300" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(dfL, dfR, on=\"Key\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![https://datascience.quantecon.org/assets/_static/merge_files/left_merge.gif](https://datascience.quantecon.org/assets/_static/merge_files/left_merge.gif) \n", + "Now, let’s focus on what happens when we set `how=\"right\"`.\n", + "\n", + "Pay special attention to what happens when filling the output value for\n", + "the key `A`." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2C3
0A1.010.0100
1A3.030.0100
2B2.020.0200
3C4.040.0300
4DNaNNaN400
\n", + "
" + ], + "text/plain": [ + " Key C1 C2 C3\n", + "0 A 1.0 10.0 100\n", + "1 A 3.0 30.0 100\n", + "2 B 2.0 20.0 200\n", + "3 C 4.0 40.0 300\n", + "4 D NaN NaN 400" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.merge(dfL, dfR, on=\"Key\", how=\"right\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![https://datascience.quantecon.org/assets/_static/merge_files/right_merge.gif](https://datascience.quantecon.org/assets/_static/merge_files/right_merge.gif) " + ] + } + ], + "metadata": { + "date": 1584040762.8915727, + "filename": "merge.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "Merge" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/7_merge_exercises.ipynb b/Session_7/7_merge_exercises.ipynb new file mode 100644 index 0000000..a8c7694 --- /dev/null +++ b/Session_7/7_merge_exercises.ipynb @@ -0,0 +1,2465 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: six>=1.0.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pyarrow->qeds) (1.12.0)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: python-dateutil in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (2.8.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import pandas as pd\n", + "import qeds\n", + "%matplotlib inline\n", + "import qeds\n", + "qeds.themes.mpl_style();\n", + "from IPython.display import display" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Merge - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercises 1-3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For these exercises we use several DataFrames:**\n", + "- WDI data on GDP components\n", + "- population\n", + "- square miles of countries " + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "# from WDI. Units trillions of 2010 USD\n", + "url = \"https://datascience.quantecon.org/assets/data/wdi_data.csv\"\n", + "wdi = pd.read_csv(url).set_index([\"country\", \"year\"])\n", + "#we create a DataFrame corresponding to 2017 that we need later on\n", + "wdi2017 = wdi.xs(2017, level=\"year\")" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "# Data from https://www.nationmaster.com/country-info/stats/Geography/Land-area/Square-miles\n", + "# units -- millions of square miles\n", + "sq_miles = pd.Series({\n", + " \"United States\": 3.8,\n", + " \"Canada\": 3.8,\n", + " \"Germany\": 0.137,\n", + " \"United Kingdom\": 0.0936,\n", + " \"Russia\": 6.6,\n", + "}, name=\"sq_miles\").to_frame()\n", + "sq_miles.index.name = \"country\"" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "# from WDI. Units millions of people\n", + "pop_url = \"https://datascience.quantecon.org/assets/data/wdi_population.csv\"\n", + "pop = pd.read_csv(pop_url).set_index([\"country\", \"year\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Use your new `merge` skills to answer the final question from above: What is the population density of each country? How much does it change over time?**" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Populationsq_miles
countryyear
Canada201736.5402683.8
201636.1094873.8
201535.7029083.8
201435.4374353.8
201335.0829543.8
\n", + "
" + ], + "text/plain": [ + " Population sq_miles\n", + "country year \n", + "Canada 2017 36.540268 3.8\n", + " 2016 36.109487 3.8\n", + " 2015 35.702908 3.8\n", + " 2014 35.437435 3.8\n", + " 2013 35.082954 3.8" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#we first merge the DataFrames that allow us to compute the population density, namely pop and sq_miles\n", + "sqm_pop = pop.join(sq_miles, on='country')\n", + "sqm_pop.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Populationsq_milesdensity
countryyear
Canada201736.5402683.89.615860
201636.1094873.89.502497
201535.7029083.89.395502
201435.4374353.89.325641
201335.0829543.89.232356
\n", + "
" + ], + "text/plain": [ + " Population sq_miles density\n", + "country year \n", + "Canada 2017 36.540268 3.8 9.615860\n", + " 2016 36.109487 3.8 9.502497\n", + " 2015 35.702908 3.8 9.395502\n", + " 2014 35.437435 3.8 9.325641\n", + " 2013 35.082954 3.8 9.232356" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# we next compute the population density of each country as Population/sq_miles\n", + " # and store it in a new column called \"density\"\n", + "sqm_pop[\"density\"] = sqm_pop[\"Population\"] / sqm_pop[\"sq_miles\"]\n", + "sqm_pop.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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e/fuhISEEBAQwK233sru3buxWCwAnDlzhqNHj3LLLbfU3RvTzEhQEEJUy5kzZygqKqJbt24VTouMjMTLy0tPi46ORlEUzpw5U6PlREREOHX0gYGB1b4613GLAKB37964ubmxd+9ewLaVEBUVRbt27WpUpz8TCQpCiDrh6oIpe7rBYEDTNKdpFR0MLnvPIEVRys3nioeHh9NrNzc3+vXrx44dO7BarezatUu2EqogQUEIUS0RERGYTCZ9V07ZaadOncJsNutpR44cQdM0wsPDAdu+/8zMTKf5Tp06VeN6uLm5oapqtfMPGDCAX3/9lfj4eAoKCujTp0+Nl/lnIkFBCFEtXl5e3HbbbXz88cfs2LGDc+fOcfToUeLj4+nbty+enp68/fbb/P777xw+fJhFixZx7bXX0qZNGwCuvPJKTp48yfbt20lOTmbDhg389ttvNa5HcHAwx44dIzU1lezs7CoDRFhYGJ07d2bFihVcd911tb6l9J+FnH0khKi2+++/Hx8fHz799FPS0tJo0aIF/fr1w8PDg+eff57333+fqVOnOp2SaveXv/yFkSNHEhcXR2FhIX379mXw4MH88MMPNarD8OHDmT9/PpMnT8ZisRAbG1vlPLfeeisJCQmy66gaFLPZXL2ddU1MamoqYNskvZTl5OTg5+fX2NW4aM2hHXXRhjNnzhAREVFHNao5GYugYuvXr2f79u289dZbdVquK03hc6jsu+jp6elyPtlSEEI0W2azmbNnz7J582buuuuuxq7OJUGCghCi2Vq2bBm7d+/m6quvZuDAgY1dnUuCBAUhRLM1adIkJk2a1NjVuKTI2UdCCCF0EhSEEELoJCgIIYTQSVAQQgihk6AghBBCJ0FBCCGEToKCEOKSMGXKFFatWtXY1Wj25DoFIYQuMzOTtWvX8tNPP5GWloafnx+RkZEMHTqUnj17Nnb1RAOQoCCEAGz3E5s2bRpeXl7cf//9REZGomkaBw8eZPHixSxcuLCxqygagAQFIQQAS5cuBeCll15yGkEtIiKCvn37AvD555/z1VdfkZKSgre3Nz169GDMmDH4+PgAsGPHDpYtW8YzzzzDe++9R2pqKlFRUUyYMIGQkBAAzp07xwcffMDRo0cpKCggLCyMe++9l169eunLzMrKYuHChfz8888EBAQwcuTIcvWtqi6idiQoCCHIycnhwIED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U4mKimLChAmEhISQmprKpEmTmDt3rl5HgG3btvHxxx+zaNGiSq/B+rORoCCEICcnh59//pnRo0e73N+sKAqapjF37ly8vb159tln8fX1ZefOncyaNYs333xTv+6oqKiINWvW8Oijj+Lv76+nJyQkEBQUxKxZszh58iRvvfUWp06dokOHDvznP//h119/ZcmSJXTv3l3vwA0GAw899BAhISGcP3+ed999l2XLlvGPf/xDr1txcTHr1q1jwoQJ+khuS5YsYdq0abRu3ZqrrrqK7du3OwWF7du3069fPwkIZUhQEKKenV++hsLfG+jGj5oGioJHZATBY+6u9mznzp1D0zTCwsKc0sePH09eXh4A/fr14/rrr+fUqVMsW7YMDw8PAO677z5++OEHdu3axYgRIwDbLqO///3vTp0wgLe3N+PGjcNoNBIeHs7nn39ORkYG06ZNA2wD7Kxbt45Dhw7p8w4bNkyfv3Xr1jzwwAO88sorTJo0SR/602q1Mm7cOH1s6OHDhxMbG4uqqhgMBm699VYWLVpETEwM7u7unDlzhqNHj+q3/xelJCgIIVyaPXs2qqqyaNEiLBYLJ06cwGKxMG7cOKd8RUVFnDt3Tn9tNBrL3WIfICIiwunYQkBAgL4byDEtKytLf33w4EHWrVtHUlIS+fn5qKpKcXExmZmZtGzZEgCTyaQHBLDdRcFqtZKXl4efnx+9e/dm2bJl7N27l759+7J9+3aioqJo167dRb0/zZEEBSHqWU3W2C9WbU+FDA0NRVEUzp4965QeEhICoG8VaJpGQEAAs2fPLleG43VJbm5uFdajbJqiKBWm2Y9fnD9/nrlz5zJgwADuvfde/Pz8OHnyJG+88QbFxcX6PPYtBscy7PW116dfv37s2LGDG264gV27dnHvvfdW8o78eckYzUII/Pz8uOqqq/jiiy8wm80u83Xo0IGsrCwMBgNt2rRx+gsICKjzeh0/fpzi4mJiYmLo1KkTYWFhpKen16qsAQMG8OuvvxIfH09BQQF9+vSp49o2DxIUhBAAPPLII2iaxjPPPMM333zD6dOnOXv2LN988w2///47BoOBq666ik6dOvHyyy+zf/9+UlJS+O2331i5ciUJCQl1Xqc2bdqgaRqbN28mJSWFb775hk2bNtWqrLCwMDp37syKFSu47rrrnLZsRCnZfSSEAGy7il555RXW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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# finally, we plot the time series of population density for each country\n", + " \n", + "sqm_pop=sqm_pop.sort_index()\n", + "sqm_pop.head()\n", + "sqm_pop['density'].unstack(level=0).plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Create two new DataFrames:**\n", + "\n", + " - wdi2017_no_US, which excludes the United States\n", + " - sq_miles_no_germant, which excludes Germany\n", + "\n", + " **Compare the `how=\"left\"` with `how=\"inner\"` options using the DataFrames `wdi2017_no_US` and `sq_miles_no_germany`. Are they different? How?**" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is wdi2017_no_US\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDP
country
Canada0.3726651.0954750.5828310.6000311.868164
Germany0.7455792.1120091.9305631.6663483.883870
United Kingdom0.5495381.8091540.8626290.9331452.818704
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164\n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is sq_miles_no_germany\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sq_miles
country
United States3.8000
Canada3.8000
United Kingdom0.0936
Russia6.6000
\n", + "
" + ], + "text/plain": [ + " sq_miles\n", + "country \n", + "United States 3.8000\n", + "Canada 3.8000\n", + "United Kingdom 0.0936\n", + "Russia 6.6000" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# We create the two DataFrames\n", + "wdi2017_no_US = wdi2017.drop(\"United States\")\n", + "print(\"This is wdi2017_no_US\")\n", + "display(wdi2017_no_US)\n", + "\n", + "sq_miles_no_germany = sq_miles.drop(\"Germany\")\n", + "print(\"This is sq_miles_no_germany\")\n", + "display(sq_miles_no_germany)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is how=\"left\"\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.883870NaN
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP sq_miles\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 3.8000\n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 NaN\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 0.0936" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is how=\"inner\"\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP sq_miles\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 3.8000\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 0.0936" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "req1 = pd.merge(wdi2017_no_US, sq_miles_no_germany, on=\"country\", how=\"left\")\n", + "print(\"This is how=\\\"left\\\"\")\n", + "display(req1)\n", + "\n", + "req2 = pd.merge(wdi2017_no_US, sq_miles_no_germany, on=\"country\", how=\"inner\")\n", + "print(\"This is how=\\\"inner\\\"\")\n", + "display(req2)" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [], + "source": [ + "# the how=\"left\" version includes the countries that are common to both DataFrames (Canada & UK),\n", + " # plus the countries that are included in the left DataFrame (wdi2017_no_US) such as Germany, \n", + " # but not in the right DataFrame (sq_miles_no_germany)\n", + " \n", + "# the how=\"inner\" version includes only the countries that are common to both DataFrames (Canada & UK) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Will this happen for all pairs of DataFrames, or are `wdi2017_no_US` and `sq_miles_no_germany` special in some way?**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As explained earlier: \n", + "- with the 'left' method, the result contains all the keys from the left (\"base\", here wdi2017_no_US) dataframe. This implies that, for the keys (here, countries) that exist on the left dataframe but not on the right dataframe, the \"new column\" (here sq_miles) while be NaN.\n", + " - Here, the result has all the country because the wdi2017_no_US has all the country. But, since sq_miles does not have an entry for germany, the result returns NaN in the corresponding cell. \n", + "- With the 'inner' method, the result containts only the keys that exist in both the left (\"base\", here wdi2017_no_US) and right (here sq_miles) dataframe. \n", + " - Here, the wdi_2017_no_US does have the US and the sq_miles dataframe doesn't have germany so the resulting dataframe have neither" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Also compare `how=\"right\"` and `how=\"outer\"` and answer the same questions.**" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is how=\"right\"\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United StatesNaNNaNNaNNaNNaN3.8000
RussiaNaNNaNNaNNaNNaN6.6000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP sq_miles\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 3.8000\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 0.0936\n", + "United States NaN NaN NaN NaN NaN 3.8000\n", + "Russia NaN NaN NaN NaN NaN 6.6000" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is how=\"outer\"\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.883870NaN
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United StatesNaNNaNNaNNaNNaN3.8000
RussiaNaNNaNNaNNaNNaN6.6000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP sq_miles\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 3.8000\n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 NaN\n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 0.0936\n", + "United States NaN NaN NaN NaN NaN 3.8000\n", + "Russia NaN NaN NaN NaN NaN 6.6000" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "req1bis = pd.merge(wdi2017_no_US, sq_miles_no_germany, on=\"country\", how=\"right\")\n", + "print(\"This is how=\\\"right\\\"\")\n", + "display(req1bis)\n", + "\n", + "req2bis = pd.merge(wdi2017_no_US, sq_miles_no_germany, on=\"country\", how=\"outer\")\n", + "print(\"This is how=\\\"outer\\\"\")\n", + "display(req2bis)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [], + "source": [ + "# the how=\"right\" version includes the countries that are common to both DataFrames (Canada & UK),\n", + " # plus the countries that are included in the right DataFrame (sq_miles_no_germany) such as US & Russia, \n", + " # but not in the left DataFrame (wdi2017_no_us)\n", + " \n", + "# the how=\"outer\" version includes all the countries from both DataFrames (Canada, Germany, UK, US, Russia) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Can you pick the correct argument for `how` such that `pd.merge(wdi2017, sq_miles, how=\"left\")` is equal to `pd.merge(sq_miles, wdi2017, how=XXX)`?**" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
GovExpendConsumptionExportsImportsGDPsq_miles
country
Canada0.3726651.0954750.5828310.6000311.8681643.8000
Germany0.7455792.1120091.9305631.6663483.8838700.1370
United Kingdom0.5495381.8091540.8626290.9331452.8187040.0936
United States2.40574312.0192662.2870713.06995417.3486273.8000
\n", + "
" + ], + "text/plain": [ + " GovExpend Consumption Exports Imports GDP \\\n", + "country \n", + "Canada 0.372665 1.095475 0.582831 0.600031 1.868164 \n", + "Germany 0.745579 2.112009 1.930563 1.666348 3.883870 \n", + "United Kingdom 0.549538 1.809154 0.862629 0.933145 2.818704 \n", + "United States 2.405743 12.019266 2.287071 3.069954 17.348627 \n", + "\n", + " sq_miles \n", + "country \n", + "Canada 3.8000 \n", + "Germany 0.1370 \n", + "United Kingdom 0.0936 \n", + "United States 3.8000 " + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#first, we check how pd.merge(wdi2017, sq_miles, on=\"country\", how=\"left\") looks like\n", + "pd.merge(wdi2017, sq_miles, on=\"country\", how=\"left\")\n", + "\n", + "#the version below is more elegant as it sorts values and orders columns\n", + " #merged1 = pd.DataFrame(pd.merge(wdi2017, sq_miles, on=\"country\", how=\"left\").sort_values(\"country\", axis = 0) , \n", + " # columns=[\"GovExpend\", \"Consumption\", \"Exports\", \"Imports\", \"GDP\", \"sq_miles\"])\n", + " #merged1" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sq_milesGovExpendConsumptionExportsImportsGDP
country
United States3.80002.40574312.0192662.2870713.06995417.348627
Canada3.80000.3726651.0954750.5828310.6000311.868164
Germany0.13700.7455792.1120091.9305631.6663483.883870
United Kingdom0.09360.5495381.8091540.8626290.9331452.818704
\n", + "
" + ], + "text/plain": [ + " sq_miles GovExpend Consumption Exports Imports \\\n", + "country \n", + "United States 3.8000 2.405743 12.019266 2.287071 3.069954 \n", + "Canada 3.8000 0.372665 1.095475 0.582831 0.600031 \n", + "Germany 0.1370 0.745579 2.112009 1.930563 1.666348 \n", + "United Kingdom 0.0936 0.549538 1.809154 0.862629 0.933145 \n", + "\n", + " GDP \n", + "country \n", + "United States 17.348627 \n", + "Canada 1.868164 \n", + "Germany 3.883870 \n", + "United Kingdom 2.818704 " + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#second, we find the right \"how\"\n", + "pd.merge(sq_miles, wdi2017, on=\"country\" , how=\"right\")\n", + "\n", + "#the version below is more elegant as it sorts values and orders columns and gives the exact same DataFrame in visual terms\n", + " #merged2 = pd.DataFrame(pd.merge(wdi2017, sq_miles, on=\"country\", how=\"right\").sort_values(\"country\", axis = 0) , \n", + " # columns=[\"GovExpend\", \"Consumption\", \"Exports\", \"Imports\", \"GDP\", \"sq_miles\"])\n", + " #merged2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is a matter of keys ! \n", + "- In the first proposed code, we want all the keys from the left dataframe, ie all the countries (keys) in wdi2017.\n", + "- To have the same dataframe in the second case, we want to have the same keys as in the previous dataframe, i.e. the countries in wdi2017. In this case, wdi2017 is the \"on the right\" (it is the dataframe that we put onto the base one) so we chose, thanks to how='right', to have the keys from the right." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For this exercise we use a dataset containing ratings of books from the website [Goodreads](https://www.goodreads.com/) and a dataset containing information on the actual books, that we are going to merge.**" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "#dataset containing ratings of books from the website [Goodreads]\n", + "ratings = qeds.data.load(\"goodreads_ratings\")" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "#dataset containing information on the actual books\n", + "books = qeds.data.load(\"goodreads_books\")\n", + "# we only need a few of the columns\n", + "books = books[[\"book_id\", \"authors\", \"title\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "#merged dataset\n", + "rated_books = pd.merge(ratings, books)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Determine the average rating for the books with the *most*/*least* number ratings.**" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Harry Potter and the Prisoner of Azkaban (Harry Potter, #3)',\n", + " \"Harry Potter and the Sorcerer's Stone (Harry Potter, #1)\",\n", + " 'Harry Potter and the Chamber of Secrets (Harry Potter, #2)',\n", + " 'The Great Gatsby',\n", + " 'To Kill a Mockingbird',\n", + " 'The Hobbit',\n", + " 'Twilight (Twilight, #1)',\n", + " 'The Hunger Games (The Hunger Games, #1)',\n", + " 'Catching Fire (The Hunger Games, #2)',\n", + " 'Mockingjay (The Hunger Games, #3)']" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#most rated\n", + "most_rated_books_id = rated_books[\"book_id\"].value_counts().nlargest(10).index\n", + "most_rated_books = rated_books.loc[rated_books[\"book_id\"].isin(most_rated_books_id), :]\n", + "list(most_rated_books[\"title\"].unique())" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['The Batman Chronicles, Vol. 1',\n", + " \"The King's Agent\",\n", + " 'The Magic (The Secret, #3)',\n", + " 'Fifty Shades Duo: Fifty Shades Darker / Fifty Shades Freed (Fifty Shades, #2-3)',\n", + " 'The Lake (The Lake Trilogy #1)',\n", + " 'Diary ng Panget',\n", + " \"Kindle Paperwhite User's Guide\",\n", + " \"Kindle User's Guide\",\n", + " 'Attack on Titan: No Regrets, Volume 01',\n", + " 'Manga Classics: Les Misérables']" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#least rated\n", + "least_rated_books_id = rated_books[\"book_id\"].value_counts().nsmallest(10).index\n", + "least_rated_books = rated_books.loc[rated_books[\"book_id\"].isin(least_rated_books_id), :]\n", + "list(least_rated_books[\"title\"].unique())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Is there a distinguishable difference in the average rating compared to the most rated books?**" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "least=least_rated_books.pivot_table(values=\"rating\", index=\"title\")\n", + "most=most_rated_books.pivot_table(values=\"rating\", index=\"title\")" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rating
title
Attack on Titan: No Regrets, Volume 014.292683
Diary ng Panget3.545455
Fifty Shades Duo: Fifty Shades Darker / Fifty Shades Freed (Fifty Shades, #2-3)4.041667
Kindle Paperwhite User's Guide3.757576
Kindle User's Guide3.375000
Manga Classics: Les Misérables4.187500
The Batman Chronicles, Vol. 13.822222
The King's Agent3.722222
The Lake (The Lake Trilogy #1)2.960000
The Magic (The Secret, #3)4.041667
\n", + "
" + ], + "text/plain": [ + " rating\n", + "title \n", + "Attack on Titan: No Regrets, Volume 01 4.292683\n", + "Diary ng Panget 3.545455\n", + "Fifty Shades Duo: Fifty Shades Darker / Fifty S... 4.041667\n", + "Kindle Paperwhite User's Guide 3.757576\n", + "Kindle User's Guide 3.375000\n", + "Manga Classics: Les Misérables 4.187500\n", + "The Batman Chronicles, Vol. 1 3.822222\n", + "The King's Agent 3.722222\n", + "The Lake (The Lake Trilogy #1) 2.960000\n", + "The Magic (The Secret, #3) 4.041667" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rating
title
Catching Fire (The Hunger Games, #2)4.133422
Harry Potter and the Chamber of Secrets (Harry Potter, #2)4.229418
Harry Potter and the Prisoner of Azkaban (Harry Potter, #3)4.418732
Harry Potter and the Sorcerer's Stone (Harry Potter, #1)4.351350
Mockingjay (The Hunger Games, #3)3.853131
The Great Gatsby3.772224
The Hobbit4.148477
The Hunger Games (The Hunger Games, #1)4.279707
To Kill a Mockingbird4.329369
Twilight (Twilight, #1)3.214341
\n", + "
" + ], + "text/plain": [ + " rating\n", + "title \n", + "Catching Fire (The Hunger Games, #2) 4.133422\n", + "Harry Potter and the Chamber of Secrets (Harry ... 4.229418\n", + "Harry Potter and the Prisoner of Azkaban (Harry... 4.418732\n", + "Harry Potter and the Sorcerer's Stone (Harry Po... 4.351350\n", + "Mockingjay (The Hunger Games, #3) 3.853131\n", + "The Great Gatsby 3.772224\n", + "The Hobbit 4.148477\n", + "The Hunger Games (The Hunger Games, #1) 4.279707\n", + "To Kill a Mockingbird 4.329369\n", + "Twilight (Twilight, #1) 3.214341" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(least)\n", + "display(most)" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Ttest_indResult(statistic=-1.7299828900907714, pvalue=0.1007424590612311)" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# To decide whether they are really different, a small ttest, underpowered and with no care for the hypothesis ^^\n", + "\n", + "import scipy.stats as stats\n", + "stats.ttest_ind(least['rating'], most['rating'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercises 5-7" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**For these exercises we create the DataFrames dfL and dfR, as specified below:**" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is dfL.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2
L1A110
L2B220
L3A330
L4C440
\n", + "
" + ], + "text/plain": [ + " Key C1 C2\n", + "L1 A 1 10\n", + "L2 B 2 20\n", + "L3 A 3 30\n", + "L4 C 4 40" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is dfR.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC3
R1A100
R2B200
R3C300
R4D400
\n", + "
" + ], + "text/plain": [ + " Key C3\n", + "R1 A 100\n", + "R2 B 200\n", + "R3 C 300\n", + "R4 D 400" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "dfL = pd.DataFrame(\n", + " {\"Key\": [\"A\", \"B\", \"A\", \"C\"], \"C1\":[1, 2, 3, 4], \"C2\": [10, 20, 30, 40]},\n", + " index=[\"L1\", \"L2\", \"L3\", \"L4\"]\n", + ")[[\"Key\", \"C1\", \"C2\"]]\n", + "print(\"This is dfL.\")\n", + "display(dfL)\n", + "\n", + "dfR = pd.DataFrame(\n", + " {\"Key\": [\"A\", \"B\", \"C\", \"D\"], \"C3\": [100, 200, 300, 400]},\n", + " index=[\"R1\", \"R2\", \"R3\", \"R4\"]\n", + ")[[\"Key\", \"C3\"]]\n", + "print(\"This is dfR.\")\n", + "display(dfR)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**In writing, describe what the output looks like when you do `pd.concat([dfL, dfR], axis=1)` (see above and/or run the cell below). Be sure to describe things like:**\n", + "\n", + "- What are the columns? What about columns with the same name? \n", + "- What is the index? \n", + "- Do any `NaN`s get introduced? If so, where? Why? " + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\asus\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n", + "of pandas will change to not sort by default.\n", + "\n", + "To accept the future behavior, pass 'sort=False'.\n", + "\n", + "To retain the current behavior and silence the warning, pass 'sort=True'.\n", + "\n", + " \"\"\"Entry point for launching an IPython kernel.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2KeyC3
L1A1.010.0NaNNaN
L2B2.020.0NaNNaN
L3A3.030.0NaNNaN
L4C4.040.0NaNNaN
R1NaNNaNNaNA100.0
R2NaNNaNNaNB200.0
R3NaNNaNNaNC300.0
R4NaNNaNNaND400.0
\n", + "
" + ], + "text/plain": [ + " Key C1 C2 Key C3\n", + "L1 A 1.0 10.0 NaN NaN\n", + "L2 B 2.0 20.0 NaN NaN\n", + "L3 A 3.0 30.0 NaN NaN\n", + "L4 C 4.0 40.0 NaN NaN\n", + "R1 NaN NaN NaN A 100.0\n", + "R2 NaN NaN NaN B 200.0\n", + "R3 NaN NaN NaN C 300.0\n", + "R4 NaN NaN NaN D 400.0" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.concat([dfL, dfR], axis=1)\n", + "\n", + "#pd.concat([dfL, dfR], axis=1).info()\n", + "\n", + "#the columns are Key, C1, C2, Key, C3 (since Key is defined as a column and not as an index in both DataFrames, we end up with two columns Key)\n", + "#the index goes through 8 entries: L1 - L4, R1 - R4\n", + "#missing values for:\n", + " #L rows corresponding to columns Key and C3 (because the L rows do not exist in dfR)\n", + " #R rows corresponding to columns Key, C1 and C2 (because the R rows do not exist in dfL)\n", + "#while axis = 1 arranges the DataFrames side-by-side, the fact that there are no common values for the index leads to a DataFrame like this" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Determine what happens when you run each of the two cells below. For each cell, answer the list of questions from the previous exercise.**" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2
L1A110
L2B220
L3A330
L4C440
L1A110
L2B220
L3A330
L4C440
\n", + "
" + ], + "text/plain": [ + " Key C1 C2\n", + "L1 A 1 10\n", + "L2 B 2 20\n", + "L3 A 3 30\n", + "L4 C 4 40\n", + "L1 A 1 10\n", + "L2 B 2 20\n", + "L3 A 3 30\n", + "L4 C 4 40" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# First code cell for above exercise\n", + "pd.concat([dfL, dfL], axis=0)\n", + "#pd.concat([dfL, dfL], axis=0).info()\n", + "\n", + "#the columns are Key, C1, C2\n", + "#the index goes through 4 entries: L1 to L4\n", + "#we don' have any missing values, because the Dataframes have identical structures\n", + "#since we used axis = 0, the DataFrames are arranged on top of one another" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC3KeyC3
R1A100A100
R2B200B200
R3C300C300
R4D400D400
\n", + "
" + ], + "text/plain": [ + " Key C3 Key C3\n", + "R1 A 100 A 100\n", + "R2 B 200 B 200\n", + "R3 C 300 C 300\n", + "R4 D 400 D 400" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Second code cell for above exercise\n", + "pd.concat([dfR, dfR], axis=1)\n", + "#pd.concat([dfR, dfR], axis=1).info()\n", + "\n", + "#the columns are Key, C3\n", + "#the index goes through 4 entries: R1 to R4\n", + "#we don' have any missing values, because the Dataframes have identical structures\n", + "#since we used axis = 1, the DataFrames are arranged side-by-side" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 7" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Describe in words why the output of `pd.merge(dfL, dfR, how=\"right\")` has more rows than either `dfL` or `dfR`. Run the cell below to see the output of that operation.**" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is merged:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2C3
0A1.010.0100
1A3.030.0100
2B2.020.0200
3C4.040.0300
4DNaNNaN400
\n", + "
" + ], + "text/plain": [ + " Key C1 C2 C3\n", + "0 A 1.0 10.0 100\n", + "1 A 3.0 30.0 100\n", + "2 B 2.0 20.0 200\n", + "3 C 4.0 40.0 300\n", + "4 D NaN NaN 400" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is dfL:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC1C2
L1A110
L2B220
L3A330
L4C440
\n", + "
" + ], + "text/plain": [ + " Key C1 C2\n", + "L1 A 1 10\n", + "L2 B 2 20\n", + "L3 A 3 30\n", + "L4 C 4 40" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is dfR:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
KeyC3
R1A100
R2B200
R3C300
R4D400
\n", + "
" + ], + "text/plain": [ + " Key C3\n", + "R1 A 100\n", + "R2 B 200\n", + "R3 C 300\n", + "R4 D 400" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# the output of pd.merge(dfL, dfR, how=\"right\") has more rows than either dfL and dfR because, \n", + " # besides the information common to both DataFrames (A, B, C), \n", + " # it includes information that is in dfR and not in dfL (D)\n", + " # Note: all elements from dfL are in dfR, but A appears twice in dfL, which means that the merged DataFrame will include A twice, plus B, plus C, plus D\n", + " \n", + "merged=pd.merge(dfL, dfR, how=\"right\")\n", + "print(\"This is merged:\")\n", + "display(merged)\n", + "\n", + "print(\"This is dfL:\")\n", + "display(dfL)\n", + "\n", + "print(\"This is dfR:\")\n", + "display(dfR)" + ] + } + ], + "metadata": { + "date": 1584040762.8915727, + "filename": "merge.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "Merge" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/8_groupby.ipynb b/Session_7/8_groupby.ipynb new file mode 100644 index 0000000..94e12fe --- /dev/null +++ b/Session_7/8_groupby.ipynb @@ -0,0 +1,3015 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GroupBy\n", + "\n", + "**Prerequisites**\n", + "\n", + "- [Functions](https://datascience.quantecon.org/../python_fundamentals/functions.html) \n", + "- pandas introduction [1](https://datascience.quantecon.org/intro.html) and [2](https://datascience.quantecon.org/basics.html) \n", + "- [Reshape](https://datascience.quantecon.org/reshape.html) \n", + "\n", + "\n", + "**Outcomes**\n", + "\n", + "- Understand the split-apply-combine strategy for aggregate\n", + " computations on groups of data \n", + "- Be able use basic aggregation methods on `df.groupby` to compute\n", + " within group statistics \n", + "- Understand how to group by multiple keys at once \n", + "\n", + "\n", + "**Data**\n", + "\n", + "- Details for all delayed US domestic flights in December 2016,\n", + " obtained from the [Bureau of Transportation\n", + " Statistics](https://www.transtats.bts.gov/DL_SelectFields.asp?Table_ID=236&DB_Short_Name=On-Time) " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "# Uncomment following line to install on colab\n", + "#! pip install qeds" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "import random\n", + "import numpy as np\n", + "import pandas as pd\n", + "import qeds\n", + "import matplotlib.pyplot as plt\n", + "\n", + "%matplotlib inline\n", + "# activate plot theme\n", + "import qeds\n", + "qeds.themes.mpl_style();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Outline\n", + "\n", + "- [GroupBy](#GroupBy) \n", + " - [Split-Apply-Combine](#Split-Apply-Combine) \n", + " - [Case Study: Airline Delays](#Case-Study:-Airline-Delays) \n", + " - [Exercise: Cohort Analysis using Shopify Data](#Exercise:-Cohort-Analysis-using-Shopify-Data) \n", + " - [Exercises](#Exercises) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Split-Apply-Combine\n", + "\n", + "One powerful paradigm for analyzing data is the “Split-Apply-Combine”\n", + "strategy.\n", + "\n", + "This strategy has three steps:\n", + "\n", + "1. `Split`: split the data into groups based on values in one or more columns. \n", + "1. `Apply`: apply a function or routine to each group separately. \n", + "1. `Combine`: combine the output of the apply step into a DataFrame,\n", + " using the group identifiers as the index. \n", + "\n", + "\n", + "We will cover the main components in this lecture, but we encourage you\n", + "to also study the [official\n", + "documentation](https://pandas.pydata.org/pandas-docs/stable/groupby.html)\n", + "to learn more about what is possible.\n", + "\n", + "To describe the concepts, we will need some data.\n", + "\n", + "We will begin with a simple made-up dataset to discuss the concepts and\n", + "then work through extended example and exercises with real data." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
0111.0
1112.0
2123.0
322NaN
4215.0
521NaN
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "0 1 1 1.0\n", + "1 1 1 2.0\n", + "2 1 2 3.0\n", + "3 2 2 NaN\n", + "4 2 1 5.0\n", + "5 2 1 NaN" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "C = np.arange(1, 7, dtype=float)\n", + "C[[3, 5]] = np.nan\n", + "df = pd.DataFrame({\n", + " \"A\" : [1, 1, 1, 2, 2, 2],\n", + " \"B\" : [1, 1, 2, 2, 1, 1],\n", + " \"C\": C,\n", + "})\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Simple Example\n", + "\n", + "To perform the *Split* step, we call the `groupby` method on our\n", + "DataFrame.\n", + "\n", + "The first argument to `groupby` is a description of how we want to\n", + "construct groups.\n", + "\n", + "In the most basic version, we will pass a string identifying the column\n", + "name." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "gbA = df.groupby(\"A\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `type` of variable we get back is a `DataFrameGroupBy`, which we\n", + "will sometimes refer to as GroupBy for short." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.groupby.generic.DataFrameGroupBy" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(gbA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Looking at the “groups” inside of the GroupBy object can help us\n", + "understand what the GroupBy represents.\n", + "\n", + "We can do this with the `gb.get_group(group_name)` method." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
0111.0
1112.0
2123.0
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "0 1 1 1.0\n", + "1 1 1 2.0\n", + "2 1 2 3.0" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbA.get_group(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
322NaN
4215.0
521NaN
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "3 2 2 NaN\n", + "4 2 1 5.0\n", + "5 2 1 NaN" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbA.get_group(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can *apply* some of our favorite aggregation functions directly on the `GroupBy` object.\n", + "\n", + "If we pass a list of strings to `groupby`, it will group based on unique combinations of values from all columns in the list.\n", + "\n", + "Let’s see an example." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.groupby.generic.DataFrameGroupBy" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbAB = df.groupby([\"A\", \"B\"])\n", + "type(gbAB)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
0111.0
1112.0
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "0 1 1 1.0\n", + "1 1 1 2.0" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbAB.get_group((1, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that we still have a GroupBy object, so we can apply our favorite\n", + "aggregations." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
C
AB
112
21
211
20
\n", + "
" + ], + "text/plain": [ + " C\n", + "A B \n", + "1 1 2\n", + " 2 1\n", + "2 1 1\n", + " 2 0" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbAB.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that the output is a DataFrame with two levels on the index\n", + "and a single column `C`. (Quiz: how do we know it is a DataFrame with\n", + "one column and not a Series?)\n", + "\n", + "This highlights a principle of how pandas handles the *Combine* part of\n", + "the strategy:\n", + "\n", + "> The index of the combined DataFrame will be the group identifiers,\n", + "with one index level per group key." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom Aggregate Functions\n", + "\n", + "So far, we have been applying built-in aggregations to our GroupBy object.\n", + "\n", + "We can also apply custom aggregations to each group of a GroupBy in two\n", + "steps:\n", + "\n", + "1. Write our custom aggregation as a Python function. \n", + "1. Passing our function as an argument to the `.agg` method of a GroupBy. \n", + "\n", + "\n", + "Let’s see an example." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "def num_missing(df):\n", + " \"Return the number of missing items in each column of df\"\n", + " return df.isnull().sum()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can call this function on our original DataFrame to get the number of\n", + "missing items in each column." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "A 0\n", + "B 0\n", + "C 2\n", + "dtype: int64" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "num_missing(df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also apply it to a GroupBy object to get the number of missing\n", + "items in each column *for each group*." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
A
100.0
202.0
\n", + "
" + ], + "text/plain": [ + " B C\n", + "A \n", + "1 0 0.0\n", + "2 0 2.0" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbA.agg(num_missing)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The key to keep in mind is that the function we pass to `agg` should\n", + "take in a DataFrame (or Series) and return a Series (or single value)\n", + "with one item per column in the original DataFrame.\n", + "\n", + "When the function is called, the data for each group will be passed to\n", + "our function as a DataFrame (or Series)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Transforms: The `apply` Method\n", + "\n", + "As we saw in the [basics lecture](https://datascience.quantecon.org/basics.html), we can apply transforms to DataFrames.\n", + "\n", + "We can do the same with GroupBy objects using the `.apply` method.\n", + "\n", + "Let’s see an example." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
0111.0
1112.0
2123.0
322NaN
4215.0
521NaN
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "0 1 1 1.0\n", + "1 1 1 2.0\n", + "2 1 2 3.0\n", + "3 2 2 NaN\n", + "4 2 1 5.0\n", + "5 2 1 NaN" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "def smallest_by_b(df):\n", + " return df.nsmallest(2, \"B\")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
A
10111.0
1112.0
24215.0
521NaN
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "A \n", + "1 0 1 1 1.0\n", + " 1 1 1 2.0\n", + "2 4 2 1 5.0\n", + " 5 2 1 NaN" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbA.apply(smallest_by_b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that the return value from applying our series transform to `gbA`\n", + "was the group key on the outer level (the `A` column) and the original\n", + "index from `df` on the inner level.\n", + "\n", + "The original index came along because that was the index of the\n", + "DataFrame returned by `smallest_by_b`.\n", + "\n", + "Had our function returned something other than the index from `df`,\n", + "that would appear in the result of the call to `.apply`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `pd.Grouper`\n", + "\n", + "Sometimes, in order to construct the groups you want, you need to give\n", + "pandas more information than just a column name.\n", + "\n", + "Some examples are:\n", + "\n", + "- Grouping by a column and a level of the index. \n", + "- Grouping time series data at a particular frequency. \n", + "\n", + "\n", + "pandas lets you do this through the `pd.Grouper` type.\n", + "\n", + "To see it in action, let’s make a copy of `df` with `A` moved to the\n", + "index and a `Date` column added." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BCDate
A
111.02020-03-31
112.02020-06-30
123.02020-09-30
22NaN2020-12-31
215.02021-03-31
21NaN2021-06-30
\n", + "
" + ], + "text/plain": [ + " B C Date\n", + "A \n", + "1 1 1.0 2020-03-31\n", + "1 1 2.0 2020-06-30\n", + "1 2 3.0 2020-09-30\n", + "2 2 NaN 2020-12-31\n", + "2 1 5.0 2021-03-31\n", + "2 1 NaN 2021-06-30" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2 = df.copy()\n", + "df2[\"Date\"] = pd.date_range(\n", + " start=pd.datetime.today().strftime(\"%m/%d/%Y\"),\n", + " freq=\"BQ\",\n", + " periods=df.shape[0]\n", + ")\n", + "df2 = df2.set_index(\"A\")\n", + "df2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can group by year." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
Date
2020-12-3143
2021-12-3121
\n", + "
" + ], + "text/plain": [ + " B C\n", + "Date \n", + "2020-12-31 4 3\n", + "2021-12-31 2 1" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2.groupby(pd.Grouper(key=\"Date\", freq=\"A\")).count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can group by the `A` level of the index." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BCDate
A
1333
2313
\n", + "
" + ], + "text/plain": [ + " B C Date\n", + "A \n", + "1 3 3 3\n", + "2 3 1 3" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2.groupby(pd.Grouper(level=\"A\")).count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can combine these to group by both." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
DateA
2020-12-31133
210
2021-12-31221
\n", + "
" + ], + "text/plain": [ + " B C\n", + "Date A \n", + "2020-12-31 1 3 3\n", + " 2 1 0\n", + "2021-12-31 2 2 1" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2.groupby([pd.Grouper(key=\"Date\", freq=\"A\"), pd.Grouper(level=\"A\")]).count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can combine `pd.Grouper` with a string, where the string\n", + "denotes a column name" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
C
DateB
2020-12-3112
21
2021-12-3111
\n", + "
" + ], + "text/plain": [ + " C\n", + "Date B \n", + "2020-12-31 1 2\n", + " 2 1\n", + "2021-12-31 1 1" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2.groupby([pd.Grouper(key=\"Date\", freq=\"A\"), \"B\"]).count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case Study: Airline Delays\n", + "\n", + "Let’s apply our new split-apply-combine skills to the airline dataset we\n", + "saw in the [merge](https://datascience.quantecon.org/merge.html) lecture." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "air_dec = qeds.load(\"airline_performance_dec16\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we compute the average delay in arrival time for all carriers\n", + "each week." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CarrierAAASB6DLEVF9HANKOOUAVXWN
Date
2016-12-04-1.7148872.724273-2.894269-5.0883518.655332-2.894212-0.5582825.4689092.7495735.564496-2.121821-1.663695
2016-12-111.14883312.0520315.7950622.50774513.2206734.5788612.0543028.71375515.4296604.09417612.0809381.865933
2016-12-1816.3575617.64376734.60835618.00000023.87662245.0148889.38888922.85789930.90163922.39813033.65112818.373400
2016-12-256.3645132.7196995.586836-0.9161136.85714354.0849595.07574710.44336915.0047805.33247417.28691710.197685
2017-01-012.3218361.22666210.6615772.0481166.8008988.2802986.9700168.3611238.9710830.0617861.3495805.213019
\n", + "
" + ], + "text/plain": [ + "Carrier AA AS B6 DL EV F9 \\\n", + "Date \n", + "2016-12-04 -1.714887 2.724273 -2.894269 -5.088351 8.655332 -2.894212 \n", + "2016-12-11 1.148833 12.052031 5.795062 2.507745 13.220673 4.578861 \n", + "2016-12-18 16.357561 7.643767 34.608356 18.000000 23.876622 45.014888 \n", + "2016-12-25 6.364513 2.719699 5.586836 -0.916113 6.857143 54.084959 \n", + "2017-01-01 2.321836 1.226662 10.661577 2.048116 6.800898 8.280298 \n", + "\n", + "Carrier HA NK OO UA VX WN \n", + "Date \n", + "2016-12-04 -0.558282 5.468909 2.749573 5.564496 -2.121821 -1.663695 \n", + "2016-12-11 2.054302 8.713755 15.429660 4.094176 12.080938 1.865933 \n", + "2016-12-18 9.388889 22.857899 30.901639 22.398130 33.651128 18.373400 \n", + "2016-12-25 5.075747 10.443369 15.004780 5.332474 17.286917 10.197685 \n", + "2017-01-01 6.970016 8.361123 8.971083 0.061786 1.349580 5.213019 " + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weekly_delays = (\n", + " air_dec\n", + " .groupby([pd.Grouper(key=\"Date\", freq=\"W\"), \"Carrier\"])\n", + " [\"ArrDelay\"] # extract one column\n", + " .mean() # take average\n", + " .unstack(level=\"Carrier\") # Flip carrier up as column names\n", + ")\n", + "weekly_delays" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s also plot this data." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# plot\n", + "axs = weekly_delays.plot.bar(\n", + " figsize=(10, 8), subplots=True, legend=False, sharex=True,\n", + " sharey=True, layout=(4, 3), grid=False\n", + ")\n", + "\n", + "# tweak spacing between subplots and xaxis labels\n", + "axs[0,0].get_figure().tight_layout()\n", + "for ax in axs[-1, :]:\n", + " ax.set_xticklabels(weekly_delays.index.strftime(\"%a, %b. %d'\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It looks like more delays occurred during the week ending Sunday\n", + "December 18th than any other week (except for Frontier, who did *worse*\n", + "on Christmas week).\n", + "\n", + "Let’s see why.\n", + "\n", + "The `air_dec` DataFrame has information on the minutes of delay\n", + "attributed to 5 different categories:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "delay_cols = [\n", + " 'CarrierDelay',\n", + " 'WeatherDelay',\n", + " 'NASDelay',\n", + " 'SecurityDelay',\n", + " 'LateAircraftDelay'\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s take a quick look at each of those delay categories for the week ending December 18, 2016." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CarrierDelayWeatherDelayNASDelaySecurityDelayLateAircraftDelay
summeanpositivesummeanpositivesummeanpositivesummeanpositivesummeanpositive
Carrier
AA105732.06.2585532922.021820.01.291583456.077279.04.5743463159.0721.00.04267835.0141249.08.3608972574.0
AS8762.02.691032250.03219.00.98863661.016344.05.019656614.0163.00.05006110.013599.04.176597271.0
B649421.09.0316151575.09894.01.808114112.038741.07.0798611326.0672.00.12280730.0100811.018.4230631433.0
DL151188.08.8642122878.039145.02.295087783.075110.04.4037292605.0107.00.0062732.0122896.07.2054412289.0
EV87408.09.9395041375.03824.00.43484276.049703.05.6519221580.00.00.0000000.089773.010.2084381568.0
F919568.010.430704361.06198.03.30383857.022459.011.971748493.00.00.0000000.032236.017.183369316.0
HA7199.05.034266218.03650.02.552448145.086.00.0601404.035.00.0244763.04024.02.813986189.0
NK14735.05.294646452.02240.00.80488756.030361.010.909450840.050.00.0179665.022247.07.993891372.0
OO120307.010.4396911378.026349.02.286446308.054141.04.6981082289.0171.00.01483912.0166102.014.4135722459.0
UA66693.06.3126361851.031602.02.991197521.074992.07.0981542065.00.00.0000000.0118728.011.2378611696.0
VX8048.05.608362246.03807.02.652962126.012619.08.793728224.073.00.0508714.025242.017.590244331.0
WN123882.04.8737905393.023516.00.925171328.078645.03.0940674247.0252.00.00991418.0285073.011.2153996472.0
\n", + "
" + ], + "text/plain": [ + " CarrierDelay WeatherDelay \\\n", + " sum mean positive sum mean positive \n", + "Carrier \n", + "AA 105732.0 6.258553 2922.0 21820.0 1.291583 456.0 \n", + "AS 8762.0 2.691032 250.0 3219.0 0.988636 61.0 \n", + "B6 49421.0 9.031615 1575.0 9894.0 1.808114 112.0 \n", + "DL 151188.0 8.864212 2878.0 39145.0 2.295087 783.0 \n", + "EV 87408.0 9.939504 1375.0 3824.0 0.434842 76.0 \n", + "F9 19568.0 10.430704 361.0 6198.0 3.303838 57.0 \n", + "HA 7199.0 5.034266 218.0 3650.0 2.552448 145.0 \n", + "NK 14735.0 5.294646 452.0 2240.0 0.804887 56.0 \n", + "OO 120307.0 10.439691 1378.0 26349.0 2.286446 308.0 \n", + "UA 66693.0 6.312636 1851.0 31602.0 2.991197 521.0 \n", + "VX 8048.0 5.608362 246.0 3807.0 2.652962 126.0 \n", + "WN 123882.0 4.873790 5393.0 23516.0 0.925171 328.0 \n", + "\n", + " NASDelay SecurityDelay \\\n", + " sum mean positive sum mean positive \n", + "Carrier \n", + "AA 77279.0 4.574346 3159.0 721.0 0.042678 35.0 \n", + "AS 16344.0 5.019656 614.0 163.0 0.050061 10.0 \n", + "B6 38741.0 7.079861 1326.0 672.0 0.122807 30.0 \n", + "DL 75110.0 4.403729 2605.0 107.0 0.006273 2.0 \n", + "EV 49703.0 5.651922 1580.0 0.0 0.000000 0.0 \n", + "F9 22459.0 11.971748 493.0 0.0 0.000000 0.0 \n", + "HA 86.0 0.060140 4.0 35.0 0.024476 3.0 \n", + "NK 30361.0 10.909450 840.0 50.0 0.017966 5.0 \n", + "OO 54141.0 4.698108 2289.0 171.0 0.014839 12.0 \n", + "UA 74992.0 7.098154 2065.0 0.0 0.000000 0.0 \n", + "VX 12619.0 8.793728 224.0 73.0 0.050871 4.0 \n", + "WN 78645.0 3.094067 4247.0 252.0 0.009914 18.0 \n", + "\n", + " LateAircraftDelay \n", + " sum mean positive \n", + "Carrier \n", + "AA 141249.0 8.360897 2574.0 \n", + "AS 13599.0 4.176597 271.0 \n", + "B6 100811.0 18.423063 1433.0 \n", + "DL 122896.0 7.205441 2289.0 \n", + "EV 89773.0 10.208438 1568.0 \n", + "F9 32236.0 17.183369 316.0 \n", + "HA 4024.0 2.813986 189.0 \n", + "NK 22247.0 7.993891 372.0 \n", + "OO 166102.0 14.413572 2459.0 \n", + "UA 118728.0 11.237861 1696.0 \n", + "VX 25242.0 17.590244 331.0 \n", + "WN 285073.0 11.215399 6472.0 " + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pre_christmas = air_dec.loc[\n", + " (air_dec[\"Date\"] >= \"2016-12-12\") & (air_dec[\"Date\"] <= \"2016-12-18\")\n", + "]\n", + "\n", + "# custom agg function\n", + "def positive(df):\n", + " return (df > 0).sum()\n", + "\n", + "delay_totals = pre_christmas.groupby(\"Carrier\")[delay_cols].agg([\"sum\", \"mean\", positive])\n", + "delay_totals" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Want**: plot total, average, and number of each type of delay by\n", + "carrier\n", + "\n", + "To do this, we need to have a DataFrame with:\n", + "\n", + "- Delay type in index (so it is on horizontal-axis) \n", + "- Aggregation method on *outer* most level of columns (so we can do\n", + " `data[\"mean\"]` to get averages) \n", + "- Carrier name on inner level of columns \n", + "\n", + "\n", + "Many sequences of the reshaping commands can accomplish this.\n", + "\n", + "We show one example below." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mean...sum
CarrierAAASB6DLEVF9HANKOOUA...B6DLEVF9HANKOOUAVXWN
CarrierDelay6.2585532.6910329.0316158.8642129.93950410.4307045.0342665.29464610.4396916.312636...49421.0151188.087408.019568.07199.014735.0120307.066693.08048.0123882.0
WeatherDelay1.2915830.9886361.8081142.2950870.4348423.3038382.5524480.8048872.2864462.991197...9894.039145.03824.06198.03650.02240.026349.031602.03807.023516.0
NASDelay4.5743465.0196567.0798614.4037295.65192211.9717480.06014010.9094504.6981087.098154...38741.075110.049703.022459.086.030361.054141.074992.012619.078645.0
SecurityDelay0.0426780.0500610.1228070.0062730.0000000.0000000.0244760.0179660.0148390.000000...672.0107.00.00.035.050.0171.00.073.0252.0
LateAircraftDelay8.3608974.17659718.4230637.20544110.20843817.1833692.8139867.99389114.41357211.237861...100811.0122896.089773.032236.04024.022247.0166102.0118728.025242.0285073.0
\n", + "

5 rows × 36 columns

\n", + "
" + ], + "text/plain": [ + " mean \\\n", + "Carrier AA AS B6 DL EV \n", + "CarrierDelay 6.258553 2.691032 9.031615 8.864212 9.939504 \n", + "WeatherDelay 1.291583 0.988636 1.808114 2.295087 0.434842 \n", + "NASDelay 4.574346 5.019656 7.079861 4.403729 5.651922 \n", + "SecurityDelay 0.042678 0.050061 0.122807 0.006273 0.000000 \n", + "LateAircraftDelay 8.360897 4.176597 18.423063 7.205441 10.208438 \n", + "\n", + " ... \\\n", + "Carrier F9 HA NK OO UA ... \n", + "CarrierDelay 10.430704 5.034266 5.294646 10.439691 6.312636 ... \n", + "WeatherDelay 3.303838 2.552448 0.804887 2.286446 2.991197 ... \n", + "NASDelay 11.971748 0.060140 10.909450 4.698108 7.098154 ... \n", + "SecurityDelay 0.000000 0.024476 0.017966 0.014839 0.000000 ... \n", + "LateAircraftDelay 17.183369 2.813986 7.993891 14.413572 11.237861 ... \n", + "\n", + " sum \\\n", + "Carrier B6 DL EV F9 HA NK \n", + "CarrierDelay 49421.0 151188.0 87408.0 19568.0 7199.0 14735.0 \n", + "WeatherDelay 9894.0 39145.0 3824.0 6198.0 3650.0 2240.0 \n", + "NASDelay 38741.0 75110.0 49703.0 22459.0 86.0 30361.0 \n", + "SecurityDelay 672.0 107.0 0.0 0.0 35.0 50.0 \n", + "LateAircraftDelay 100811.0 122896.0 89773.0 32236.0 4024.0 22247.0 \n", + "\n", + " \n", + "Carrier OO UA VX WN \n", + "CarrierDelay 120307.0 66693.0 8048.0 123882.0 \n", + "WeatherDelay 26349.0 31602.0 3807.0 23516.0 \n", + "NASDelay 54141.0 74992.0 12619.0 78645.0 \n", + "SecurityDelay 171.0 0.0 73.0 252.0 \n", + "LateAircraftDelay 166102.0 118728.0 25242.0 285073.0 \n", + "\n", + "[5 rows x 36 columns]" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reshaped_delays = (\n", + " delay_totals\n", + " .stack() # move aggregation method into index (with Carrier)\n", + " .T # put delay type in index and Carrier+agg in column\n", + " .swaplevel(axis=1) # make agg method outer level of column label\n", + " .sort_index(axis=1) # sort column labels so it prints nicely\n", + ")\n", + "reshaped_delays" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "for agg in [\"mean\", \"sum\", \"positive\"]:\n", + " axs = reshaped_delays[agg].plot(\n", + " kind=\"bar\", subplots=True, layout=(4, 3), figsize=(10, 8), legend=False,\n", + " sharex=True, sharey=True\n", + " )\n", + " fig = axs[0, 0].get_figure()\n", + " fig.suptitle(agg)\n", + "# fig.tight_layout();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s summarize what we did:\n", + "\n", + "- Computed average flight delay for each airline for each week. \n", + "- Noticed that one week had more delays for all airlines. \n", + "- Studied the flights in that week to determine the *cause* of the\n", + " delays in that week. \n", + "\n", + "\n", + "Suppose now that we want to repeat that analysis, but at a daily\n", + "frequency instead of weekly.\n", + "\n", + "We could copy/paste the code from above and change the `W` to a `D`,\n", + "but there’s a better way…\n", + "\n", + "Let’s convert the steps above into two functions:\n", + "\n", + "1. Produce the set of bar charts for average delays at each frequency. \n", + "1. Produce the second set of charts for the total, average, and number\n", + " of occurrences of each type of delay. " + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "hide-output": false + }, + "outputs": [], + "source": [ + "def mean_delay_plot(df, freq, figsize=(10, 8)):\n", + " \"\"\"\n", + " Make a bar chart of average flight delays for each carrier at\n", + " a given frequency.\n", + " \"\"\"\n", + " mean_delays = (\n", + " df\n", + " .groupby([pd.Grouper(key=\"Date\", freq=freq), \"Carrier\"])\n", + " [\"ArrDelay\"] # extract one column\n", + " .mean() # take average\n", + " .unstack(level=\"Carrier\") # Flip carrier up as column names\n", + " )\n", + "\n", + " # plot\n", + " axs = mean_delays.plot.bar(\n", + " figsize=figsize, subplots=True, legend=False, sharex=True,\n", + " sharey=True, layout=(4, 3), grid=False\n", + " )\n", + "\n", + " # tweak spacing between subplots and x-axis labels\n", + " axs[0, 0].get_figure().tight_layout()\n", + " for ax in axs[-1, :]:\n", + " ax.set_xticklabels(mean_delays.index.strftime(\"%a, %b. %d'\"))\n", + "\n", + " # return the axes in case we want to further tweak the plot outside the function\n", + " return axs\n", + "\n", + "\n", + "def delay_type_plot(df, start, end):\n", + " \"\"\"\n", + " Make bar charts for total minutes, average minutes, and number of\n", + " occurrences for each delay type, for all flights that were scheduled\n", + " between `start` date and `end` date\n", + " \"\"\"\n", + " sub_df = df.loc[\n", + " (df[\"Date\"] >= start) & (df[\"Date\"] <= end)\n", + " ]\n", + "\n", + " def positive(df):\n", + " return (df > 0).sum()\n", + "\n", + " aggs = sub_df.groupby(\"Carrier\")[delay_cols].agg([\"sum\", \"mean\", positive])\n", + "\n", + " reshaped = aggs.stack().T.swaplevel(axis=1).sort_index(axis=1)\n", + "\n", + " for agg in [\"mean\", \"sum\", \"positive\"]:\n", + " axs = reshaped[agg].plot(\n", + " kind=\"bar\", subplots=True, layout=(4, 3), figsize=(10, 8), legend=False,\n", + " sharex=True, sharey=True\n", + " )\n", + " fig = axs[0, 0].get_figure()\n", + " fig.suptitle(agg)\n", + "# fig.tight_layout();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let’s look at that plot at a daily frequency. (Note that we need the\n", + "figure to be a bit wider in order to see the dates.)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "mean_delay_plot(air_dec, \"D\", figsize=(16, 8));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we expected given our analysis above, the longest average delays\n", + "seemed to happen in the third week.\n", + "\n", + "In particular, it looks like December 17th and 18th had — on average —\n", + "higher delays than other days in December.\n", + "\n", + "Let’s use the `delay_type_plot` function to determine the cause of the\n", + "delays on those two days.\n", + "\n", + "Because our analysis is captured in a single function, we can look at\n", + "the days together and separately without much effort." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnkAAAJfCAYAAAAD/MCKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzs3X+8XGV96PtPBMVfSTZo+SGB+it6pNzKLRRotS1IvhC8CtgDCFaJisRj4ei1nCpYbqNCK95ea6ml1MAOCbYFvJ5DoTYav4202B4RKP6o1PY0YtzEIKgJuKk/MDDnj/VsmWxmz2z2nsyarPm8X6957ZnvetZ6vjPsh3z3s9Z6ZkGr1UKSJEnN8qS6E5AkSVL/WeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA+1ZdwKSNEgR8W7g7cAiYCvwm8AbgC2ZeVFpcwzw55m5pLzeDFxe2r0AuA54D7AWeDnwBeC0zNw+wLciSV05kydpZETEi4HzgF/MzIXACcDmWe7+n4EAXgS8GvgUVaH3bKr/l7693/lK0nw4kydplDwC7AUcEhHfyczNABExm30/kpn3lfafA+7PzC+W1zcAx+2SjCVpjpzJkzQyMnMT8H8D7wXuj4jrIuI5s9z9vrbnP+zw+pl9SVKS+sQiT9JIycy/zMyXAz8LtIAPAv8BPL2t2f515CZJ/eTpWkkjo1yTdyDwj8CPqGbgngR8CTg/Ii4BnkI12ydJuzVn8iSNkr2AS4HvAt8G9qW6eeJjwJepbsL4DHB9TflJUt8saLVadecgSZKkPnMmT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYH2rDsBDaeI2B/YDDwAHJSZP+nQ5nDgNuDLmfkLg81QGqxuYyIingWsAl4NPAf4PvCvwJ9m5rWDz1badSJiLbCiLfR94F+AizNzfVu7nwV+HzgBeCYwAbwrM/9qYMmOOGfyNJM3A38DfA84eYY2bwWuAJ4bEUcMKjGpJt3GxH8HfpVqTLwIWA5cCzxrkAlKA/Q54IDyOBq4E/iriHgBQEQcCNwKLABeBfwn4BzgnlqyHVHO5OlxIuJJVIPxHVQDcyXwiWltFgJnAi+j+mNhJXDHYDOVBqPbmIiIMeDXgFdn5mfKLt8E/qmGVKVBeTgzv12efzsiLgB+E/h54OtUM3ibM/N1bftsHmyKciZPnRwPPANYD3wMOCYinj+tzW8A/56ZXwHWAmdGxDMHmqU0ON3GxEPAJHByRDyjpvyk2kTEU6j+CPoxcGf5o+gU4PMRcW1E3B8R/xwRF0aEk0sDZJGnTt4K/EVm7sjMe4G/Bd4yrc1KYB1AZt5Gda3F65CaacYxkZk7qK5Peg2wPSLuiIjLIuIV9aUr7XLHRMRDEfEQ8CPg/cBZmflN4GeARVQze/dQXZN3KfDbwPtqynckWeRpJxFxANX1E+vawmuBN039BRYRRwL/B/CXbW3WURV+UqPMZkxk5g3AgVTX4v134BBgY0RcPthspYH5AnBYefwCVZG3LiJOAPYobb6Sme/KzC9m5l9QncI9r5ZsR5TTpprubKrfizsioj2+B3AS8D+oirk9gXvb2iwAnhQRv5CZdw4uXWmXm82YIDN/DHy2PD4QERcBF0fEH2Tm5oFmLO16P8zMTW2vvxQRxwG/AxwH/ITqjtt2dwGLImLvzNw+oDxHmjN5+qlyHcVbqP7aOmza48+BlRGxCDgDOHfa9pcCN+NsnhpkNmOiy+5fKz9/ZlfmKA2RHcDTy/JCXwBePG37i4EHLfAGx5k8tVsOHAx8NDMn2jdExNVAAq8HWsDVmfnDaW3+HPijiDg/M/9jQDlLu1LPMVHWi/wQcDXwZap19A4FPgB8A/jSQDOWBuMpZe1IqG5KOqE8VpXYB4BPRsTvUl3acwjVLN9lg050lDmTp3ZvBb4w/R+z4u+B71BdSPvJ6QVecQPwVKqlVaQmmM2YOBX4n1Sz25+lmsH74/L81zotJC41wK8A95bHP1P9/l9AVdxRFkU+Ezgd+CrVH0IfAi6uI9lRtaDVatWdgyRJkvrMmTxJkqQGssiTJElqIIs8SZKkBhqJIm9iYqI1MTHhxYdS4ZiQduaYUBON1BIqDzzwwLwG8OTkJAsXLuxXOuawm/bfrxzGxsYW9CmdOXNM7P79NykHx0R/1J1D3f03JYd+jIeRmMmTJEkaNRZ5kiRJDWSRJ0mS1EAWeZIkSQ3U88aLiFgDvAq4PzMPLbH3AudQfaUPwHvKV5gQERcCZwOPAG/PzA0lvpzqO+v2AK7KzEtL/HnAdcA+wJ3AGzLz4YjYC7gGOBz4HvDazNzch/csSZLUeLOZyVtL9SXd0304Mw8rj6kC7xDgDODnyj5/GhF7RMQewOXAiVRfUnxmaQvwwXKspcB2qgKR8nN7Zr4Q+HBpJ0mSpFnoWeRl5i3Atlke72Tgusz8cWZ+A9gEHFkemzLz7sx8mGrm7uSIWAC8AvhE2X8dcErbsdaV558AjivtJUmS1MN81sk7LyLOAu4Azs/M7cCBwK1tbbaUGMA90+JHAc8CHsjMHR3aHzi1T2buiIgHS/vvticRESuBlV3yXDw+Pg5Ua9bMR6vVmvcx5ssc6u+/XzmMjY31KZudOSZGq/8m5eCY6I+6c6i7/6bk0I/xMNci7wrgYqBVfn4IeDPQaaatRecZw1aX9vTY9lOZuRpY3S3ZqVXM57swYhMWV2xCDnX3Pyw5zMQxMVr9m0NvjonR6t8cHjOnu2sz877MfCQzHwWupDodC9VM3EFtTZcAW7vEvwuMRcSe0+I7HatsX8zsTxtLkiSNtDkVeRFxQNvL1wBfLc9vAs6IiL3KXbNLgduA24GlEfG8iHgK1c0ZN2VmC7gZOLXsvwK4se1YK8rzU4HPlvaSJEnqYTZLqFwLHAM8OyK2AKuAYyLiMKrTp5uBtwJk5l0R8XHgX4AdwLmZ+Ug5znnABqolVNZk5l2li3cD10XEJcAXgfESHwc+FhGbqGbwzpj3u5UkSRoRC1qt5k+OTV1rsWjRonkdZxjOr5tD/f33K4c6v4zdMdGc/puUg2OiP+rOoe7+m5JDP8aD33ghSZLUQBZ5kiRJDWSRJ0mS1EAWeZIkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDWSRJ0mS1EAWeZIkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDWSRJ0mS1EAWeZIkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDbRnrwYRsQZ4FXB/Zh5aYvsA1wPPBTYDp2fm9ohYAFwGvBL4AfDGzLyz7LMCuKgc9pLMXFfihwNrgacB64F3ZGZrpj7m/Y4lSZJGwGxm8tYCy6fFLgA2ZuZSYGN5DXAisLQ8VgJXwE+LwlXAUcCRwKqI2Lvsc0VpO7Xf8h59SJIkqYeeRV5m3gJsmxY+GVhXnq8DTmmLX5OZrcy8FRiLiAOAE6pD5bYyG5fA8rJtUWZ+PjNbwDXTjtWpD0mSJPXQ83TtDPbLzHsBMvPeiNi3xA8E7mlrt6XEusW3dIh362MnEbGSaiZwJovHx8cBmJyc7P3Oumi1WvM+xnyZQ/399yuHsbGxPmWzM8fEaPXfpBwcE/1Rdw5199+UHPoxHuZa5M1kQYdYaw7xWcvM1cDqbm0mJiZaAAsXLnwih36cycnJeR9jvsyh/v6HJYeZOCZGq39z6M0xMVr9m8Nj5np37X3lVCvl5/0lvgU4qK3dEmBrj/iSDvFufUiSJKmHuRZ5NwEryvMVwI1t8bMiYkFEHA08WE65bgCOj4i9yw0XxwMbyrbJiDi63Jl71rRjdepDkiRJPcxmCZVrgWOAZ0fEFqq7ZC8FPh4RZwMTwGml+Xqq5VM2US2h8iaAzNwWERcDt5d278/MqZs53sZjS6h8qjzo0ockSZJ6WNBqPaFL4HZLU9daLFq0aF7HGYbz6+YwmP5ffO6nu25ff+ERvPIDd8y4/d8un77q0OONjY11uiZ1IBwTzem/STk4Jvqj7hzq7r8pOfRjPPiNF5IkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDWSRJ0mS1EAWeZIkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDbRn3QlIkiTtbhZ/7diu2x/a/2oWf+2kGbc/+JKb+53S4ziTJ0mS1EAWeZIkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQN5d2+bF53666/b1Fx7BERf844zb/+3y5f1OSZIkaU6cyZMkSWogizxJkqQGmtfp2ojYDEwCjwA7MvOIiNgHuB54LrAZOD0zt0fEAuAy4JXAD4A3Zuad5TgrgIvKYS/JzHUlfjiwFngasB54R2a25pOzJEnSKOjHTN6xmXlYZh5RXl8AbMzMpcDG8hrgRGBpeawErgAoReEq4CjgSGBVROxd9rmitJ3az4veJEmSZmFXnK49GVhXnq8DTmmLX5OZrcy8FRiLiAOAE4DMzG2ZuR1IYHnZtigzP19m765pO5YkSZK6mO/dtS3gMxHRAj6amauB/TLzXoDMvDci9i1tDwTuadt3S4l1i2/pEN9JRKykmu2byeLx8XEAJicnu76Z9Rce0XX7Ps98ctc2vY7fD61WayD9DHMOg+h/EL8LY2NjTziv2ejnmOil7t+FYcih7v6blINjoj/qzqHu/geVw0P7X911+6NPGuNbXdq0euTXj/Ew3yLvZZm5tRRyGRH/2qXtgg6x1hziOymF5epuSU5MTLQAFi5c2K1Z1+VRoPqH/5UfuGPG7YNYQmVycrLn+2h6DoPof3f4XZhJP8dEL3X/LgxDDnX3bw69OSZGq/9B5bD4ayd13f6t/a/mwG+/acbtD77k5n6n9DjzOl2bmVvLz/uBG6iuqbuvnGql/Ly/NN8CHNS2+xJga4/4kg5xSZIk9TDnIi8inhERC6eeA8cDXwVuAlaUZiuAG8vzm4CzImJBRBwNPFhO624Ajo+IvcsNF8cDG8q2yYg4utyZe1bbsSRJktTFfGby9gP+ISK+DNwG/E1mfhq4FIiI+HcgymuolkC5G9gEXAn8JkBmbgMuBm4vj/eXGMDbgKvKPl8HPjWPfCVJkkbGnK/Jy8y7gZd2iH8POK5DvAWcO8Ox1gBrOsTvAA6da46SJEmjym+8kCRJaiCLPEmSpAayyJMkSWogizxJkqQGmu9iyGqYF5/76Z5t1l94RNfFgutcCFiSJFUs8iRJmqXFXzu26/aH9r+66zchDOJbDqQpnq6VJElqIIs8SZKkBrLIkyRJaiCLPEmSpAayyJMkSWogizxJkqQGcgkVSZI0a/NdRgZcSmZQLPKGiAsRS5KkfvF0rSRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kDdeSJK0m+h1Zyv0vrvVO1tHx9AXeRGxHLgM2AO4KjMvrTklSRo5m173X7tuf9al72bTW98z4/YX/uVH+p2SpB6GusiLiD2Ay4EAtgC3R8RNmfkv9WYmaVTMt7gBCxxJ9VjQarXqzmFGEfFLwHsz84Ty+kKAzPzAEznOxMTE8L5JjbSDDz54QR39OiY0rBwT0mPmOx6GeiYPOBC4p+31FuCo9gYRsRJY2eUYi8fHx3dBatJwckxIO3NMaGS1Wq2hfSxbtuy0ZcuWXdX2+g3Lli37SI35fGcIPpORz6Hu/oclh2F4DMPnUHcOdfdvDsP1GIbPoe4c6u7fHB57DPsSKluAg9peLwG21pQLwAM19j3FHOrvH4Yjh2EwDJ9D3TnU3T+YwzAZhs+h7hzq7h/MARj+07W3A0sj4nnAt4AzgNfVmM+DNfY9xRzq7x+GI4dhMAyfQ9051N0/mMMwGYbPoe4c6u4fzAEY8iIvM3dExHnABqolVNZk5l01p9VoEbEWWFFePgJ8H/g34NPARzJzW2n3XuD1mfnCwWcpDc60MdHuP4CNwEtm2O8pVGce/iwzL9pV+Ul16DIuzizb3wWcDfws1bX1f5SZlw8qP1WGusgDyMz1wPq68xgxnwNOp/pGlL2pbnZ5F/BfIuLX6kxMqsnUmGj3KHAEcFJEvDQzvzxt+69TjZ+rBpCfVIdO4+IB4MPAb1Pd7PJl4JeA1RHxcGZeOdgUR9vQF3mqxcOZ+e3yfCtwV0R8Avgi8Gf1pSXVpn1M/FREfBp4GDgHOG/a5nOAzMzNuz49qRYzjYtnAb+bmTeU0N0RcSTwO4BF3gAN+40XGhKZ+X3gCuAY/ONAAiAzHwW+C7w+Ip42FY+IFwDHAqvryk2q0QLgR9NiPwR+NiJ+toZ8Rpb/WOuJ+CrV4H1K3YlIA3ZMRDw0LXZzZr6aqsjbFzgNuKZsewtwH3DT4FKUBm76uLgvM19AdS332yNiI9W/G0cCby5tngN8c7Bpji6LPD0RtaxELw2BL/D4i8x/UH7+BPgk1enZayJiT+CNwNWZuWNgGUqDN31cTP2+TwD/DnwJaFFd9jMOXEB1Q58GxCLviRmGUy915nAo1YC9ElhcYx6j/t9hmAzD5zCIHH6YmZu69D8BfCoiXkJ1t+1+DPaGi1H577A7GIbPYVA5zDQursjM1eUO832pirz/UrZ9Y0C5jdJ/hxkN9XfXavDKbfFLMnPZtPgiqr/Kvp6Z4RIqGhUzjYlpbZ4EfB24garI2yMzjx9IglINZjMuprX/HPBoZrpCwwA5k6dOnhIR+1Odnt0bOJpqCZW9gLdNa3fYtH0fzcyvDCZNaWCmxsR092VmKzMfjYgrqcbJQuC1g01PGh4R8YvAc4E7qWbyzgcOA15eY1ojySJPnfwKcC/VtROTVIsh/yXVYsjb29odRLWsSrsfA08dRJLSAE2Niel+hurGC4A1wPvK6xsHlJc0jPYCVgEvoFpi6BbglzPzn2vNagR5ulaSJKmBXCdPkiSpgSzyJEmSGsgiT5IkqYFGosibmJhoTUxMePGhVDgmpJ05JtREI3V37QMPPDCvATw5OcnChQv7lY457Kb99yuHsbGx2r9BxDGx+/ffpBwcE/1Rdw5199+UHPoxHkZiJk+SJGnUWORJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgP1vLs2ItYArwLuz8xDS+y9wDnAd0qz92Tm+rLtQuBsqu89fXtmbijx5cBlwB7AVZl5aYk/D7gO2Ifqy4zfkJkPR8RewDXA4cD3gNdm5uY+vGdJkqTGm81M3lpgeYf4hzPzsPKYKvAOAc4Afq7s86cRsUdE7AFcDpwIHAKcWdoCfLAcaymwnapApPzcnpkvBD5c2kmSJGkWehZ5mXkLsG2WxzsZuC4zf5yZ3wA2AUeWx6bMvDszH6aauTs5IhYArwA+UfZfB5zSdqx15fkngONKe0mSJPUwn8WQz4uIs4A7gPMzcztwIHBrW5stJQZwz7T4UcCzgAcyc0eH9gdO7ZOZOyLiwdL+u+1JRMRKYGWXPBePj48D1cKE89FqteZ9jPkyh/r771cOY2NjfcpmZ46J0eq/STk4Jvqj7hzq7r8pOfRjPMy1yLsCuBholZ8fAt4MdJppa9F5xrDVpT09tv1UZq4GVndLduqraua7+nUTVtBuQg519z8sOczEMTFa/ZtDb46J0erfHB4zp7trM/O+zHwkMx8FrqQ6HQvVTNxBbU2XAFu7xL8LjEXEntPiOx2rbF/M7E8bS5IkjbQ5FXkRcUDby9cAXy3PbwLOiIi9yl2zS4HbgNuBpRHxvIh4CtXNGTdlZgu4GTi17L8CuLHtWCvK81OBz5b2kiRJ6mE2S6hcCxwDPDsitgCrgGMi4jCq06ebgbcCZOZdEfFx4F+AHcC5mflIOc55wAaqJVTWZOZdpYt3A9dFxCXAF4HxEh8HPhYRm6hm8M6Y97uVJEkaEQtareZPjk1da7Fo0aJ5HWcYzq+bQ/399yuHsbGx2u4Wd0w0p/8m5eCY6I+6c6i7/6bk0I/x4DdeSJIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA1nkSZIkNdCevRpExBrgVcD9mXloie0DXA88F9gMnJ6Z2yNiAXAZ8ErgB8AbM/POss8K4KJy2Esyc12JHw6sBZ4GrAfekZmtmfqY9zuWJEkaAbOZyVsLLJ8WuwDYmJlLgY3lNcCJwNLyWAlcAT8tClcBRwFHAqsiYu+yzxWl7dR+y3v0IUmSpB56FnmZeQuwbVr4ZGBdeb4OOKUtfk1mtjLzVmAsIg4ATqgOldvKbFwCy8u2RZn5+cxsAddMO1anPiRJktRDz9O1M9gvM+8FyMx7I2LfEj8QuKet3ZYS6xbf0iHerY+dRMRKqpnAmSweHx8HYHJysvc766LVas37GPNlDvX3368cxsbG+pTNzhwTo9V/k3JwTPRH3TnU3X9TcujHeJhrkTeTBR1irTnEZy0zVwOru7WZmJhoASxcuPCJHPpxJicn532M+TKH+vsflhxm4pgYrf7NoTfHxGj1bw6PmevdtfeVU62Un/eX+BbgoLZ2S4CtPeJLOsS79SFJkqQe5lrk3QSsKM9XADe2xc+KiAURcTTwYDnlugE4PiL2LjdcHA9sKNsmI+LocmfuWdOO1akPSZIk9TCbJVSuBY4Bnh0RW6jukr0U+HhEnA1MAKeV5uuplk/ZRLWEypsAMnNbRFwM3F7avT8zp27meBuPLaHyqfKgSx+SJEnqoWeRl5lnzrDpuA5tW8C5MxxnDbCmQ/wO4NAO8e916kOSJEm9+Y0XkiRJDWSRJ0mS1ED9XkJlt3bHO7d23f7885/OHb87c5sjPvycfqckSZI0J87kSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDeeOF1IE34UiSdnfO5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgPtOZ+dI2IzMAk8AuzIzCMiYh/geuC5wGbg9MzcHhELgMuAVwI/AN6YmXeW46wALiqHvSQz15X44cBa4GnAeuAdmdmaT86SJEmjoB8zecdm5mGZeUR5fQGwMTOXAhvLa4ATgaXlsRK4AqAUhauAo4AjgVURsXfZ54rSdmq/5X3IV5IkqfF2xenak4F15fk64JS2+DWZ2crMW4GxiDgAOAHIzNyWmduBBJaXbYsy8/Nl9u6atmNJkiSpi3mdrgVawGciogV8NDNXA/tl5r0AmXlvROxb2h4I3NO275YS6xbf0iG+k4hYSTXbN5PF4+PjAExOTnZ9M88//+ldt+/xzAVd2/Q6fj+0Wq2B9DPMOQyi/0H8LoyNjT3hvGajn2Oil7p/F4Yhh7r7b1IOjon+qDuHuvtvSg79GA/zLfJelplbSyGXEfGvXdou6BBrzSG+k1JYru6W5MTERAtg4cKF3Zpxx+9u7br9+ec/nbs/9IMZtx/x4ed03b8fJicne76PpucwiP53h9+FmfRzTPRS9+/CMORQd//m0JtjYrT6N4fHzOt0bWZuLT/vB26guqbuvnKqlfLz/tJ8C3BQ2+5LgK094ks6xCVJktTDnIu8iHhGRCyceg4cD3wVuAlYUZqtAG4sz28CzoqIBRFxNPBgOa27ATg+IvYuN1wcD2wo2yYj4uhyZ+5ZbceSJElSF/M5XbsfcENETB3nLzPz0xFxO/DxiDgbmABOK+3XUy2fsolqCZU3AWTmtoi4GLi9tHt/Zm4rz9/GY0uofKo8JEkD9uT/90XdG7zhUzz5isNn3PyTd/2vPmckqZc5F3mZeTfw0g7x7wHHdYi3gHNnONYaYE2H+B3AoXPNUZIkaVTN98YLSQ3m7I0k7b78WjNJkqQGssiTJElqIIs8SZKkBrLIkyRJaiBvvBgid7yz91rPzz//6V2/jaHOb1qQJEnDw5k8SZKkBrLIkyRJaiCLPEmSpAbymjztxOsCJUlqBos8Sepivt/6AX7zh6R6WORJkiQ9Qfv97Tldt//DYb/LC7/wWzNuv2/Zlf1O6XG8Jk+SJKmBLPIkSZIayCJPkiSpgbwmT5KkWdodrsOSpljkSZKkWZtvoQsWu4Pi6VpJkqQGssiTJElqIIs8SZKkBhr6a/IiYjlwGbAHcFVmXlpzSpIk1aLX9XDgzR96zFDP5EXEHsDlwInAIcCZEXFIvVlJkiQNvwWtVqvuHGYUEb8EvDczTyivLwTIzA88keNMTEwM75vUSDv44IMX1NGvY0LDyjEhPWa+42HYT9ceCNzT9noLcFR7g4hYCazscozF4+PjuyA1aTg5JqSdOSY0slqt1tA+li1bdtqyZcuuanv9hmXLln2kxny+MwSfycjnUHf/w5LDMDyG4XOoO4e6+zeH4XoMw+dQdw51928Ojz2G+po8qpm7g9peLwG21pQLwAM19j3FHOrvH4Yjh2EwDJ9D3TnU3T+YwzAZhs+h7hzq7h/MARj+07W3A0sj4nnAt4AzgNfVmM+DNfY9xRzq7x+GI4dhMAyfQ9051N0/mMMwGYbPoe4c6u4fzAEY8iIvM3dExHnABqolVNZk5l01p9VoEbEWWJKZyzpsawFvmBY7FbgeuDEzf30QOUqDVMbECuCPMvOd07a1gG+U55uplnm6pG37CuBKqhvIfn9AKUu7VETsB1wEvBp4DlUx8/fAJZn5pbZ2TwbeCbweWAr8BPgicFlm/o9B5z2Khv10LZm5PjNflJkvyMzfqzsfPc5K4IPAiRGxf93JSLvID4FzI+JFs92hrAZwJfAWCzw1RUQcBNwB/DKQqvUHAAAgAElEQVTwNuCFwP9FVcDdWta2nSrwPgWcD/wR1TJoRwOfBa6PiPcOPPkRNNQzeRpuEfF84FepTqEfBrwZ8B8zNdH/BJ4B/AFwcreGEfEk4I+pZv9enZkbdn160sBcDjwZODYzv19iE1Tr2K4H1lJdXvVfgeOAozPzC237vy8ifgR8ICL+OjP/aXCpj56hn8nTUFsJrM/M71IN7LdERC1rXEkD8E7g1RFxbJc2TwU+AZwKHGOBpyaJiL2pZu3+pK3Aa/cBYD9gEdWlPRunFXhTLqOaHf+NXZWrKs7kqZNjIuKhbg3KVPybeGztqRuBPwMC+MyuTU8avMy8NSKuB/4wIg7PzEc7NPtt4FHg5zPz3webobTLLaWaHJrp2vip+FOp1rnt+P1pmfmjiPg68OK+Z6idOJOnTr5Adfp1+qPda6h+f9YDZOaPgevovuCotLu7APhPwBtn2P63VNcm/X75Q0hqkl5navzWkCHjTN4Ts7ruBBhMDj/MzE3TgxHRnsNK4NnAD9viC4BHImK/zLxvF+Y3Kv8ddgfD8DkMLIfM/GZEfBi4JCI+XsI3tzX5PPBeqhUBboiIUzPzRwNIbaT+Owy5YfgcdlUO/041U30ocEOH7YeWnzcCL297vZOIeCrwAqo/inaVJv93mLWh/u5aDd4sl1C5FfhfwK8D04vBTwBrM/PSXZupNBjTx0RELKT6x+5KqmUk3pCZf96+hEpE/DyQwD8DJ2fmf9SRu9RvEfFJ4AjgRdOvy4uITwH/J/A84FyqG5Wm33hBRLwbuBQ4whsvdi1n8jQXK4G7M/Ovpm8osxtviYgPZqZ/QahxMnMyIv4fqovHZ2rzlYj4VaqZig0R8coZLlSXdjfnUt1t/tmIuIjqOrz9qW5MOhY4JTN/GBGXUd2kcVNEXAD8HdW1eqdT/XH0fgu8Xc9r8vREPYnqeqT/f4bt11NNwx83qISkGoxTzebNKDP/DfgV4ABgY0TsM4jEpF0pM79JNZP3BeCjwNep1sPbC/ilzPx0afcT4ATgw1Rr5X0NuI3q34YzMnPV4LMfPZ6ulSRJaiBn8iRJkhrIIk+SJKmBLPIkSZIaaCSKvImJidbExIQXH0qFY0LamWNCTTRSS6g88MAD8xrAk5OTLFy4sF/pmMNu2n+/chgbG6v9e34dE7t//03KwTHRH3XnUHf/TcmhH+NhJGbyJEmSRo1FniRJUgNZ5EmSJDWQRZ4kSVID9bzxIiLWAK8C7s/MQ0vsvcA5wHdKs/dk5vqy7ULgbOAR4O2ZuaHEl1N91+MeVF/ifWmJPw+4DtgHuJPqy74fjoi9gGuAw4HvAa/NzM19eM+SJEmNN5uZvLXA8g7xD2fmYeUxVeAdApwB/FzZ508jYo+I2AO4HDgROAQ4s7QF+GA51lJgO1WBSPm5PTNfSPXddx+cyxuUJEkaRT2LvMy8Bdg2y+OdDFyXmT/OzG8Am4Ajy2NTZt6dmQ9TzdydHBELgFcAnyj7rwNOaTvWuvL8E8Bxpb0kSZJ6mM86eedFxFnAHcD5mbkdOBC4ta3NlhIDuGda/CjgWcADmbmjQ/sDp/bJzB0R8WBp/932JCJiJbCyS56Lx8fHgWrNmvlotVrzPsZ8mUP9/fcrh7GxsT5lszPHxGj136QcHBP9UXcOdffflBz6MR7mWuRdAVwMtMrPDwFvBjrNtLXoPGPY6tKeHtt+KjNXA6u7JTu1ivl8F0ZswuKKTcih7v6HJYeZOCZGq39z6M0xMVr9m8Nj5nR3bWbel5mPZOajwJVUp2Ohmok7qK3pEmBrl/h3gbGI2HNafKdjle2Lmf1pY0mSpJE2pyIvIg5oe/ka4Kvl+U3AGRGxV7lrdilwG3A7sDQinhcRT6G6OeOmzGwBNwOnlv1XADe2HWtFeX4q8NnSXpIkST3MZgmVa4FjgGdHxBZgFXBMRBxGdfp0M/BWgMy8KyI+DvwLsAM4NzMfKcc5D9hAtYTKmsy8q3TxbuC6iLgE+CIwXuLjwMciYhPVDN4Z8363kiRJI2JBq9X8ybGpay0WLVo0r+MMw/l1c6i//37lUOeXsTsmmtN/k3JwTPRH3TnU3X9TcujHePAbLyRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmB9uzVICLWAK8C7s/MQ0tsH+B64LnAZuD0zNweEQuAy4BXAj8A3piZd5Z9VgAXlcNekpnrSvxwYC3wNGA98I7MbM3Ux7zfsSRJ0giYzUzeWmD5tNgFwMbMXApsLK8BTgSWlsdK4Ar4aVG4CjgKOBJYFRF7l32uKG2n9lveow9JkiT10LPIy8xbgG3TwicD68rzdcApbfFrMrOVmbcCYxFxAHBCdajcVmbjElheti3KzM9nZgu4ZtqxOvUhSZKkHnqerp3Bfpl5L0Bm3hsR+5b4gcA9be22lFi3+JYO8W597CQiVlLNBM5k8fj4OACTk5O931kXrVZr3seYL3Oov/9+5TA2NtanbHbmmBit/puUg2OiP+rOoe7+m5JDP8bDXIu8mSzoEGvNIT5rmbkaWN2tzcTERAtg4cKFT+TQjzM5OTnvY8yXOdTf/7DkMBPHxGj1bw69OSZGq39zeMxc7669r5xqpfy8v8S3AAe1tVsCbO0RX9Ih3q0PSZIk9TDXIu8mYEV5vgK4sS1+VkQsiIijgQfLKdcNwPERsXe54eJ4YEPZNhkRR5c7c8+adqxOfUiSJKmH2Syhci1wDPDsiNhCdZfspcDHI+JsYAI4rTRfT7V8yiaqJVTeBJCZ2yLiYuD20u79mTl1M8fbeGwJlU+VB136kCRJUg89i7zMPHOGTcd1aNsCzp3hOGuANR3idwCHdoh/r1MfkiRJ6s1vvJAkSWogizxJkqQGssiTJElqIIs8SZKkBrLIkyRJaqB+f+OFJElS4+39vmO7br/tnKs5+A9PmnH79lU39zulx3EmT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYEs8iRJkhrIIk+SJKmBLPIkSZIayCJPkiSpgSzyJEmSGsgiT5IkqYH2nM/OEbEZmAQeAXZk5hERsQ9wPfBcYDNwemZuj4gFwGXAK4EfAG/MzDvLcVYAF5XDXpKZ60r8cGAt8DRgPfCOzGzNJ2dJkuZq7/cd23X7bedczcF/eNKM27evurnfKUkz6sdM3rGZeVhmHlFeXwBszMylwMbyGuBEYGl5rASuAChF4SrgKOBIYFVE7F32uaK0ndpveR/ylSRJarxdcbr2ZGBdeb4OOKUtfk1mtjLzVmAsIg4ATgAyM7dl5nYggeVl26LM/HyZvbum7ViSJEnqYr5FXgv4TET8U0SsLLH9MvNegPJz3xI/ELinbd8tJdYtvqVDXJIkST3M65o84GWZuTUi9gUyIv61S9sFHWKtOcR3UorLlR3aTlk8Pj4OwOTkZJdmvbVarXkfY77Mof7++5XD2NhYn7LZmWNitPpvUg67w5i47Zyru25/9tPHurYZxH+nun8f6u5/UDns6t+FfoyHeRV5mbm1/Lw/Im6guqbuvog4IDPvLadc7y/NtwAHte2+BNha4sdMi/9diS/p0H56DquB1d3ynJiYaAEsXLhwtm+to8nJyXkfY77Mof7+hyWHmTgmRqt/c+itn2Oi200VUP3Df+SVb5px+yBuvKj7v0Xd/Q8qh93hd2HOp2sj4hkRsXDqOXA88FXgJmBFabYCuLE8vwk4KyIWRMTRwIPldO4G4PiI2LvccHE8sKFsm4yIo8uduWe1HUuSJEldzOeavP2Af4iILwO3AX+TmZ8GLgUiIv4diPIaqiVQ7gY2AVcCvwmQmduAi4Hby+P9JQbwNuCqss/XgU/NI19JkqSRMefTtZl5N/DSDvHvAcd1iLeAc2c41hpgTYf4HcChc81RkiRpVPmNF5IkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDWSRJ0mS1EAWeZIkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDWSRJ0mS1EAWeZIkSQ20Z90JSJKk3cfe7zu26/bbzrmag//wpK5ttq+6uZ8paQbO5EmSJDWQM3mS1MXn/vAFXbcfcuZn+NyVh3Vt8yu/9fV+pqQR1msWDXrPpDmLNjos8iRJPc232LXQlQbP07WSJEkNZJEnSZLUQJ6ulTQjT9FJ0u5r6Iu8iFgOXAbsAVyVmZfWnJIkSdLQG+rTtRGxB3A5cCJwCHBmRBxSb1aSJEnDb0Gr1ao7hxlFxC8B783ME8rrCwEy8wNP5DgTExPD+yY10g4++OAFdfTrmNCwckxIj5nveBj207UHAve0vd4CHNXeICJWAiu7HGPx+Pj4LkhNGk6OCWlnjgmNrFarNbSPZcuWnbZs2bKr2l6/YdmyZR+pMZ/vDMFnMvI51N3/sOQwDI9h+BzqzqHu/s1huB7D8DnUnUPd/ZvDY4+hviaPaubuoLbXS4CtNeUC8ECNfU8xh/r7h+HIYRgMw+dQdw519w/mMEyG4XOoO4e6+wdzAIb/dO3twNKIeB7wLeAM4HU15vNgjX1PMYf6+4fhyGEYDMPnUHcOdfcP5jBMhuFzqDuHuvsHcwCGvMjLzB0RcR6wgWoJlTWZeVfNaTVaRPwdsCkz3zItvoTq+shjp8X/BHgb8M7M/ONB5SkNQkTcCByQmUd22PYUqjMLOyLiLuCrmfnatu1PBj4PfDszXzWonKV+i4izgT8D9snMybb4V4CXTI8Dh0TEOuBm4GrgTuAXM/PRtn3/jg7/1qi/hv10LZm5PjNflJkvyMzfqzsfPSYing68Hvh9ul/ULO2uPgr8YkS8tMO2Xwf2Bu6nGgenRMQb2ra/DzgYOHuXZyntWn9LNSn0a1OBiHg28HPAvR3iTwM2llCrtDtrUMnqMUNf5GmovRa4G7gEeE5E/HLN+Uj99mngm8A5HbadAyTwcGZ+Efhd4E8i4mcj4uXAu4CzM/O+gWUr7QKZ+U3g68BxbeFXAF8FbuwQh8eKvEeBPwJ+LyKesYtT1TQWeZqPtwJrM/PHwHU4m6eGKaeXrgJeHxFPm4pHxAuoLl1Y3db8D4AvAX8BXAOMZ+ZfDzBdaVfayOOLuc+Wx/T4jzLzW22x36eaCXzXrk5SO7PI05yU01e/AFxbQmuB0yNirLakpF1jHHgGcFpb7C3AfcBNU4FSEJ4DvIzqGuLfGmCO0q62ETg0IvYtr19Bdc3d31Ndg9ce/377jpn5faqZ7v9Wru/WgFjkaa7eCqzPzO8AZOZtwDeork2SGiMz7wU+STllGxF7Am8Ers7MHdOarwT+AzgAeNEA05R2tc+Wn8eVQu35wN9n5jbgK23xpcBkh/2vorq85/cHkawqFnlPzOreTXa5XZ3Dj4HFHeJTM3Q/opq1+w3gpIjYMfWgustqEKdsR+G/w+5iGD6HQeTwUeDlEfES4CRgP6p/tH7af0QcC7wTOJ3qOqWPRcReA8jtpznUbBhyGAbD8Dn0PYfM/C7wZapTs8cBd2bm1BIhN7fFHwE+0mH/R4DzqS59OKLf+XXQyP8OT9RQf3etBi8iLgNeDSwtg3Iq/mbgSmBf4BSq649+jerOqSmLgVuAl2XmrQNLWtrFIuJJVBee30D1x8wemXl82/YxqtmMT2bmb0bEPlQXpV+bmefXkbPUbxHx/wH/mer/8/dm5gUl/iqqwu4W4MWZeXSJvxG4KjP3bDvGeuCZVDdkuITKLjbU6+SpFn9GdVrq6lLwPQD8ItUU+zWZ+b2IeCtwQ2b+8/SdI+IfqWbzLPLUGJn5aERcSXXh+EKqO8vb/SnwQ+C/lfbbIuJNwPqI+OvM/LtB5ivtIhupZuOeBZzaFr+F6tupXkOHWbxpzqf6g+gnwKZdkKPaeLpWO8nMrwFHU52e/Wuqwfg7wB8Cb42Iw6iKvo/PcIjrgddGRKdTvtLubA3VDRjfpTodC0BEvI7qpozXZ+YPpuKZuYHqj6a1EbFowLlKu8ItVMXZU4F/mAqWGyv+ieoPoL/tdoDyb8xHqdbS0y7m6VpJkqQGciZPkiSpgSzyJEmSGsgiT5IkqYFGosibmJhoTUxMePGhVDgmpJ05JtREI7WEygMPPDCvATw5OcnChQv7lY457Kb99yuHsbGxBX1KZ84cE7t//03KwTHRH3XnUHf/TcmhH+NhJGbyJEmSRo1FniRJUgNZ5EmSJDWQRZ4kSVID9bzxIiLWAK8C7s/MQ0vsvVTfb/qd0uw9mbm+bLsQOBt4BHh7+WofImI5cBmwB9UXFl9a4s8DrgP2Ae4E3pCZD0fEXsA1wOHA94DXZubmPrxnSZKkeVn8tWO7bn9o/6tZ/LWTZtz+4Etu7ndKjzObmby1wPIO8Q9n5mHlMVXgHQKcAfxc2edPI2KPiNgDuBw4ETgEOLO0BfhgOdZSYDtVgUj5uT0zXwh8uLSTJEnSLPQs8jLzFmDbLI93MnBdZv44M78BbAKOLI9NmXl3Zj5MNXN3ckQsAF4BfKLsvw44pe1Y68rzTwDHlfaSJEnqYT7X5J0XEV+JiDURsXeJHQjc09ZmS4nNFH8W8EBm7pgW3+lYZfuDpb0kSZJ6mOtiyFcAFwOt8vNDwJuBTjNtLToXk60u7emx7aciYiWwskuui8fHx4FqYcL5aLVa8z7GfJlD/f33K4exsbE+ZbMzx8Ro9d+kHBwT/VF3DnX3P6gcHtr/6q7bH33SGN/q0qbVI79+jIc5FXmZed/U84i4EvhkebkFOKit6RJga3neKf5dYCwi9iyzde3tp461JSL2BBbT4bRxZq4GVnfLd+qraua7+nUTVtBuQg519z8sOczEMTFa/ZtDb46J0ep/UDl0u6kC4Fv7X82B337TjNuH5caLx4mIA9pevgb4anl+E3BGROxV7ppdCtwG3A4sjYjnRcRTqG7OuCkzW8DNwKll/xXAjW3HWlGenwp8trSXJElSD7NZQuVa4Bjg2RGxBVgFHBMRh1GdPt0MvBUgM++KiI8D/wLsAM7NzEfKcc4DNlAtobImM+8qXbwbuC4iLgG+CIyX+DjwsYjYRDWDd8a8360kSdKI6FnkZeaZHcLjHWJT7X8P+L0O8fXA+g7xu6nuvp0e/xFwWq/8JEmS9Hh+44UkSVIDWeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ1kEWeJElSA1nkSZIkNZBFniRJUgNZ5EmSJDWQRZ4kSVIDWeRJkiQ10J69GkTEGuBVwP2ZeWiJ7QNcDzwX2AycnpnbI2IBcBnwSuAHwBsz886yzwrgonLYSzJzXYkfDqwFngasB96Rma2Z+pj3O5YkSRoBs5nJWwssnxa7ANiYmUuBjeU1wInA0vJYCVwBPy0KVwFHAUcCqyJi77LPFaXt1H7Le/QhSZKkHnoWeZl5C7BtWvhkYF15vg44pS1+TWa2MvNWYCwiDgBOqA6V28psXALLy7ZFmfn5zGwB10w7Vqc+JEmS1EPP07Uz2C8z7wXIzHsjYt8SPxC4p63dlhLrFt/SId6tj51ExEqqmcCZLB4fHwdgcnKy9zvrotVqzfsY82UO9fffrxzGxsb6lM3OHBOj1X+TcnBM9EfdOdTd/6ByeGj/q7tuf/RJY3yrS5tWj/z6MR7mWuTNZEGHWGsO8VnLzNXA6m5tJiYmWgALFy58Iod+nMnJyXkfY77Mof7+hyWHmTgmRqt/c+jNMTFa/Q8qh8VfO6nr9m/tfzUHfvtNM25/8CU39zulx5nr3bX3lVOtlJ/3l/gW4KC2dkuArT3iSzrEu/UhSZKkHuZa5N0ErCjPVwA3tsXPiogFEXE08GA55boBOD4i9i43XBwPbCjbJiPi6HJn7lnTjtWpD0mSJPUwmyVUrgWOAZ4dEVuo7pK9FPh4RJwNTACnlebrqZZP2US1hMqbADJzW0RcDNxe2r0/M6du5ngbjy2h8qnyoEsfkiRJ6qFnkZeZZ86w6bgObVvAuTMcZw2wpkP8DuDQDvHvdepDkiRJvfmNF5IkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDWSRJ0mS1EAWeZIkSQ1kkSdJktRAFnmSJEkNZJEnSZLUQBZ5kiRJDdTzu2slSVJl8deO7br9of2vZvHXTppx+4MvubnfKUkzciZPkiSpgSzyJEmSGsgiT5IkqYG8Jk/q4MXnfrrr9vUXHsERF/zjjNv/7fLl/U5JkqQnxJk8SZKkBrLIkyRJaiCLPEmSpAayyJMkSWqged14ERGbgUngEWBHZh4REfsA1wPPBTYDp2fm9ohYAFwGvBL4AfDGzLyzHGcFcFE57CWZua7EDwfWAk8D1gPvyMzWfHKWJEkaBf2YyTs2Mw/LzCPK6wuAjZm5FNhYXgOcCCwtj5XAFQClKFwFHAUcCayKiL3LPleUtlP7ecuiJEnSLOyK07UnA+vK83XAKW3xazKzlZm3AmMRcQBwApCZuS0ztwMJLC/bFmXm58vs3TVtx5IkSVIX810nrwV8JiJawEczczWwX2beC5CZ90bEvqXtgcA9bftuKbFu8S0d4juJiJVUs30zWTw+Pg7A5OTk7N9ZB61Wa97HmC9zGEz/6y88ouv2fZ755K5tZpPf2NjYE85rNhwTo9V/k3LYHcbEQ/tf3XX7o08a41td2rQG8N+p7t+HuvsfVA67+nehH+NhvkXeyzJzaynkMiL+d3t3HmdnVed5/FMEkRCSsAojJEQjEJHFpsEOwRGj96uNC9pt+tUsIoItMCCL0Z5usFtUnMYR98ighBBsZFBw1Ka7I/KzQRwQlIhsbRhBEAiLLCKERUKw5o/zVHKrcutWJNQ5h3u/79erXkk9N5XzpVLfy7nPPc95bunyZwc6HBt8DseHaSaWZ3ULeddddw0CTJ48udsfG9OKFSvW++9YX86QZ/xuGx1DmgS+5bSloz5ecjNkd6K/xneGsT2fnZi67ICuj9+z7WK2u//wUR9/9JWXd/3650Ppf4vS4+fK8EL4WVivt2sj4t7m1weA75DW1P2meauV5tcHmj++HJjW9uXbA/eOcXz7DsfNzMzMbAzPeZInaZKkyUO/B94E3AxcDBzW/LHDgH9pfn8x8B5JA5JmA482b+t+H3iTpM2bCy7eBHy/eWyFpNnNlbnvafu7zMzMzKyL9TmTtw1wpaQbgJ8C/x4RlwCfAiTpVkDN55C2QLkduA1YCBwDEBG/BU4Frm0+PtEcA/hvwNnN1/wK+N565DUzMzPrG895TV5E3A7s0eH4w8AbOxwfBI4d5e86Bzinw/GlwK7PNaOZmZlZv/IdL8zMzMx6kCd5ZmZmZj3IkzwzMzOzHuRJnpmZmVkPWt/NkHvKzsde0vXxJSft1XWT3JIb4JqZmZm185k8MzMzsx7kSZ6ZmZlZD/LbtWZmZrbOpi6b2/Xxx7ddPOZ9XXPct9U8yavKWGsCYfzXBdaQwczMzNaf3641MzMz60Ge5JmZmZn1IE/yzMzMzHqQJ3lmZmZmPciTPDMzM7Me5KtrzczMXiDG2r4Ext7CxNuX9A+fyTMzMzPrQT6TZ2ZmY7rt4OO6Pr7lp/6O2446edTHX/G/FzzfkcxsDD6TZ2ZmZtaDPMkzMzMz60Ge5JmZmZn1oOrX5En6c+CLwATg7Ij4VOFIZtZH1nctGng9mpmVUfUkT9IE4AxAwHLgWkkXR8QvyiYz6w9ebG9m9sI1MDg4WDrDqCTtA3wsIt7cfH4SQESc9sf8PXfddVe9/5HW16ZPnz5QYlx3wmrlTpitsb59qPpMHrAdcHfb58uBP2v/A5KOBI7s8ndMXbRo0ThEM6uTO2E2nDthfWtwcLDaj1ar9VetVuvsts8PbbVaCwrmebCC70nfZyg9fi0Zavio4ftQOkPp8Z2hro8avg+lM5Qe3xnWfNR+de1yYFrb59sD9xbKAvC7gmMPcYby40MdGWpQw/ehdIbS44Mz1KSG70PpDKXHB2cA6n+79lpgR0kvA+4BDgQOLpjn0YJjD3GG8uNDHRlqUMP3oXSG0uODM9Skhu9D6QylxwdnACrfJy8iVgEfAL4PLAMujIj/LJvKzMzMrH61n8kjIpYAS0rnMDMzM3shqfpMnpmZmZk9N57kmZmZmfUgT/LMzMzMepAneWZmZmY9yJO8P85ZpQPgDDWMD3VkqEEN34fSGUqPD85Qkxq+D6UzlB4fnAGo/N61ZmZmZvbc+EyemZmZWQ/yJM/MzMysB3mSZ2ZmZtaDPMkzMzMz60Ge5HUh6f9IequkYt8nSRNKjd2udA5Jbyv579Bk2KLk+DVwJ6rK4E5UwJ2oKoM7MYIned2dCRwM3CrpU5JmFchwm6TTJe1SYOyachxI+nf4tKRXFsrwE0kXSXqLpIFCGUpzJ+rJ4E7UwZ2oJ4M7MYK3UFkHkqYCBwEfAe4GFgJfj4hnMow9mfSDezhpUn4O8I2IeGy8x64th6QppH+Hw4FBYDFwQUSsyDT+ANACjgBeA3wTODcifplj/Jr0eydqyNDkcCcq4U6Uz9DkcCfaeJI3BklbAu8GDgXuBc4HXgvsFhGvz5zldcAFwGbAt4BTI+K2nBlK55C0Fenf40RgGfAK4EsRsSDH+G055gJfByYBNwB/HxFX58xQijtRVwZ3ojx3oq4M7sQaG+Yc7IVG0reBWcB5wNsj4r7moW9KWpopwwTgraRXJTOAz5KeQP4rsATYqR9ySHo76ZXRTNK/x2si4gFJm5BKPO7lHfFE/hvgOOBi4NXARcDLxjtDae5EVb6lWeIAABUSSURBVBnciQq4E1VlcCdG8CSvuy9HxGWdHoiIvTJluBW4HDg9In7cdvxbzaulXErn+Cvg8xHxo/aDEfGkpCMyjA9wNemJ450Rsbzt+FJJX8mUoTR3op4M7kQd3Il6MrgTI/jt2jFI2hXYBdh46FhE/HPG8TeNiMdzjVd7jpIkDURE3xfGnagjQw3cicSdqCNDDWrrhM/kdSHpFOD1pPIuAfYHrgSylRdYJelY4FUMfwLJ9aqkihySZpNOtb8S2AiYADwREVNyjN/YStJ/Z+3vwRsyZijKnagngztRB3eingzuxNq8hUp384A3AvdHxOHAHsCLM2c4D9gWeDNwBbA9kOUqocpyfJl0xdStwETgb8iwvmKE84FbSGsqPg78Grg2c4bS3Il6MrgTdXAn6sngTozgSV53T0XEH0ivUKYADwAvz5zhFRHxj6RXI18jLWzdLXOGKnI0V2dNiIhnI2IxMDfn+MCWEbEIeCYirmheoc7OnKE0d6KeDO5EHdyJejK4EyP47drulkrajLTf0c+Ax4GfZs4wtMfS75p1H/eTrlzKrXSOJyVtBFwv6dPAfaTL0nMa+h7cJ+mtpK0Sts+coTR3op4M7kQd3Il6MrgTI3iS10VEHNP89iuSLgGmRMSNmWOcJWlz4B9Jl2FvCnw0c4YachxKWl/xAeCDwDTgXRnHB/hks+Hph0hvAUxpsvQNd6KqDO5EBdyJqjK4EyP46toOJO3Z7fGIuC5XFrMauBNmw7kT9kLgM3mdfbbLY4PAuF8lI2l+t8cj4nPjnaGGHJJuIn3PRxt/9/Ecv8mwYIwMx493hgq4E/VkcCfq4E7Uk8GdGIUneR1ERO6Fmp1MLh2gUTrH2wqPD5Bl1/qauROr1ZDBnaiAO7FaDRnciVH47doumluhzAemR8SRknYEdo6IfyscrS9J2gHYMSJ+IGkisGFkuun0iByTIuKJ3OPWwJ2oiztRnjtRF3diOJ/J624x6WqpOc3ny0n3nstWXkk7AWcC20TErpJ2Bw6IiE/mylBDDknvB44EtiDdl3B74Cuk/amykLQPsIi0oHi6pD2Ao9oWXvcDd6KeDO5EHdyJejK4EyN4n7zuZkbEp2kuiY6Ip4CBzBkWAie1ZbgRODBzhhpyHAvsCzzWjH8r8JKM4wN8gbTR58NNhhuAnPcProE7UU8Gd6IO7kQ9GdyJETzJ625lc7p3EEDSTODpzBk2iYiRey6typyhhhxPR8TKoU8kbUiXRa7jJSLuHnHo2dwZCnMn6sngTtTBnagngzsxgt+u7e4U4BJgmqTzSa8Q3ps5w0PNk8bQE8g80gaPuZXOcYWkk4GJkgQcA/xrxvEB7pY0BxhsNtw8HliWOUNp7kQ9GdyJOrgT9WRwJ0bwJK+LiAhJ15FuSTIAnBARD2WOcSxwFjBL0j3AHcAhmTPUkOPvgfcBNwFHkW4EfnbG8QGOBr4IbEdad3Mp6fvSN9yJqjK4ExVwJ6rK4E6M4KtrR9Gc5t0fmNUcWgZcEhEl3ipF0iRggxJXCdWSQ9LWABHxYO6xzZ2oMYM7UZY7UV8Gd2I4T/I6kPRS4HLSqeafk16d/QmwLTA3Iu7NlGNn0pVC7U8gZ0XEL3OMX0MOSQOkt0M+QPp3GCCtb1gQEZ8Y7/HbcswFjgN2bg4tA74cET/MlaEkd6KeDO5EHdyJejK4E6PzhRed/RNwZkS8PiI+GBEnRsR+wBnAaTkCNJdh/xBYQToFvhB4AvihpNk5MlSS40TSGpe9I2LLiNgC+DNgX0lZ7geodJPpc0hrOw4mvQWxBDhH0ltyZKiAO1FJBtyJWrgTlWTAnRiV1+R1Njsi3jvyYER8SdL/y5Tho8BBI14BfFfSZaRXLPv3SY73AGpf4xIRt0t6N2mtw+fHeXyAvwXe2VwKP+R6SUtJN6BekiFDae5EPRnciTq4E/VkcCdG4TN5nT3V5bEnM2WY2ekUb0RcAbw8U4Yacryo0yLmZr3FizKMD7DtiOIOZbgR2CZThtLciXoyuBN1cCfqyeBOjMJn8jqbKukvOxwfAKZkytBt0WrOW6WUzrHyOT72fOr231n8tjWZuBP1ZHAn6uBO1JPBnRiFJ3mdXQG8fZTHfpQpwzRJX+pwfIB0aXYupXPsIemxZrz2q4QGgI0zjA8wU9LFHY4PkPesaknuRD0Z3Ik6uBP1ZHAnRuFJXgcRcbikDYB5EXFhoRh/2+WxpdlSFM4RERPGe4x18I4uj30mW4qC3Il6MrgTdXAn6sngTnQxODjoj1E+Wq3WjwqPP6HVap1e+vvQIdfmrVZrIPOYn2m1WrsU/u8+YV2O9fKHO9ExU/Y+NOO6ExV8uBMdM7kTYxzL9eEzed2FpA8D36TtPfWI+G2WwSOelfSnOcYajaSPAhdGxC2SXgx8D3g1sErSwRHxg0xRbgEWNpuPLgYuiIhHM4095DDSTubt3tvhWC/r605U1AdwJ2rhTrgT7arqhCd53R3R/Np+S5JB8r6//vPmff6LGP4E8u1M4/81cGrz+8NI6wu2BnYCvgZkKXBEnA2c3Wy6eThwo6SrgIURcfl4ji3pINK+Ry8fseZiMvDweI5doX7vRBV9AHeiIu6EO1FtJzzJ6yIiXlY6A7AF6QfkDW3HBoFck7yVETG0kPXNwDci4llgWfNqKRtJE0g7qs8CHgJuAOZLOioiDhzHoa8j7Wq/FfDZtuMrgBvHcdzquBP19AHciRq4E+5Eo8pOeJLXhaRNgPnA9Ig4UtKOwM4R8W+5MkTE4bnGGsXTknYFfgPMBT7c9tgmuUJI+hzpSrbLgH+KiJ82D/3PDBuPXhARe0r6VbP3U99yJ+roA7gTtXAn3IlGlZ3wJK+7xcDPgDnN58tJp8OzlVfSTsCZwDYRsauk3YEDIuKTmSKcAHyLdPr98xFxR5PrLaT7NeZyM/APEdFpk9HXjPPYG0k6DNin075YGd86r0G/d6KWPoA7UQt3wp2ASjvhO150NzMiPg08AxART5HWG+S0EDipLcONwHiech4mIn4SEbMi3Q/w1LbjS0j3C8zlkJHFlfQfTZbxXlh7NDAb2Iz0KrH9423jPHZt+roTFfUB3IlauBPuBFTaCZ/J626lpIk0mytKmgk8nTnDJhHxU0ntx1ZlzrCapKnAu0gLTF/JOG92KWlj0in/rSRtzponzynAS8dz7CERcSVwpaSlEbEox5gVcyfa5O5DM6Y7URd3oo07UVcnPMnr7hTgEtKO3ucD+5Iuhc7poeZJY+gJZB5pcWc2zRPYAaTS7km6Wuid5NnV/SjSq8GXkha2DnkMOCPD+KtFxKJm7ckutO2iHhH/nDNHYX3ficJ9AHeiNu6EO7FabZ0YGBwcHPtP9TFJW5JOwQ4A10SHmyCP8/gvB84irfd4BLgDeHdE/DrT+OcDrwMuBb5BWtB6W+4ryiQdFxELco7ZIcMpwOtJ5V0C7A9cGRHzSubKrZ87UUsfmizuRCXcCXeiLUNVnfCZvA4kzWo2dtyzOTT0imi6pOkRcd1oX/t8i4jbgZakScAGEdHtZtDjYVfSk8Yy4JZm481srwwkvSEiLgPuqWAx6zxgD+DnkW5ptA1wdsbxi3EnVivaB3AnauFOrOZODFdVJzzJ62w+cCTD97oZMsjwvYjGldIO4u8CZgAbDq25iIhP5Bg/IvaQNIt0Gv4Hkh4AJkvaNiLuzxBhP9Irw043As+5XyDAUxHxB0mrJE0BHqB/bsbuTlBFH8CdqIU7gTvRQVWd8Nu1o1C68fQ+EXFV4RyXAI+SLtF/duh4RHR6YsmRZy9SmecByyNizhhf8nyMWfom4EM5/hdwMumqtQ8BjwPXF96jKht3omOW7H1oxnUnKuBOdMziTtTUidI3Mq75o9VqXV1BhptLZxgl10Cr1dov43ilbwI+0Gq1prV9PqPVau1e+t+hwPfBneicKWsfmjHdiQo+3ImuPx/7ZR7TnRjx4bdru7tU0ruAb8ea27bk9mNJu0XETSUGV7r5dDe5dvYufRPwQUnfBf60+fzXOcatUF93oqI+gDtRC3eiO3eiIE/yupsPTAJWSfo96cqpwYiYMt4DS7qJtJZgQ+BwSbeT9l4ayrD7eGdoPNHh2CTgfcCWQJa1gdRxE/BrJO0dEddmHLM2/d6JWvoA7kQt3Im1uROVdMJr8kYhaQCYFhF3FRp/h26PR8SdubIMkTSZdAub9wEXAp+NiAdy5yhF0i+AnYA7SU9suSfcRbkTw/V7H8CdcCeGcyfq64TP5I2iOe36HZrTrgXGvxNA0nkRcWj7Y5LOAw7t+IXjQNIWpFerhwBfA/aMiEdyjd9keE+n45k3mNw/41jVcSdWj1W8D00Od6Iwd2L1WO7EGlV1wpO87mo47fqq9k8kTSDjE4qk04G/JG20uVtEPJ5r7BH2bvv9xsAbSTub5yzvfwH+c2gPquZV6y6kV2z9oq87UVEfwJ2ohTvhTrSrqhOe5HU3FzhKUvbTrpJOIl2GPVHSY83hAWAlqUy5fIi0xuMfgI9ozb0Rs607AYiI49o/V7o/4nk5xm5zJumWPUOe6HCs1/V7J6roA7gTFXEn3Il2VXXCk7zuip12jYjTgNMknRYRJxXMsUGpscfwJLBj5jEH2q+eaza87LcO9XUnKu4DuBOluBP16vtO9FsZ/yht6x1eQtuNhjNnOEnS5qQf1PabHee68XMVJP0rzc23gQ1Ip79zb3p5u6TjSa/KAI4Bbs+coSh3oh7uRB3ciXq4E2vzJK8LSQeQblnzUtKtSXYg3Z/vVd2+7nnO8Dekq5W2B64n3QT7ajLeMqcSn2n7/SrgzohYnjnD0cCXSG9LDAL/QbqtUd9wJ6riTlTAnaiKOzGCJ3ndnUoqyw8i4k8kzQUOypzhBNJi0msiYm5zj8CPZ85Qg7uA+yLi9wCSJkqakWuzyWYh8yERcWCO8SrmTtTDnaiDO1EPd2KEmt9Lr8EzEfEwsIGkDSLicuDVmTP8vu0H9sURcQuwc+YMNbgI+EPb5882x7KIiGeBd+Qar2LuRD3ciTq4E/VwJ0bwmbzufidpU+BHwPmSHiCdAs5puaTNgO+SbtnyCHBv5gw12DAiVg59EhErJW2UOcNVkr7M2rfMuS5zjpLciXq4E3VwJ+rhTozgSV4Hkl4BbEOakT8FfJC0yeMOwHFdvvR5FxF/0fz2Y5IuB6YCl+TMUIkHJR0QERcDSHoH8FDmDHOaX9tv0zNIH6x7cSeq5E4U5E5UyZ0YwZO8zr4AnBwRQ7PwPwBfk7QX8DHg7TnDSHotsGNELJa0NbAdcEfODBU4mvQq+QxSYZYDHXc3Hy8RMTfneJVxJ+rjTpTlTtTHnRjBk7zOZkTEjSMPRsRSSTNyBpF0CrAXaX3FYuBFwNeBfXPmKC0ifgXMbt4WGRjaTTwHSe+OiK9Lmj9Kts/lylKQO1EZd6I4d6Iy7sTafOFFZ932OpqYLUXyF8ABNO/tR8S9wOTMGYqTtI2kRcBFEbFC0i6S3pdp+EnNr5M7fGyaKUNp7kRl3Ini3InKuBNr85m8zq6V9P6IWNh+sPlh+VnmLCsj3QR7sMkwaawv6FHnkl6hfqT5/Jekha2LxnvgiPhq8+taWxJI2nvtr+hJ7kR9zsWdKMmdqM+5uBPDeJLX2YnAdyQdwpqy7gVsRHrFlNOFkr4KbCbp/cARwMIxvqYXbRURFyrdq5GIWCXp2RJBJO0CHEjaC+tR0s9Gr3Mn6uNOlOVO1MedGMGTvA4i4jfAnGZTy12bw/8eEZflyiDpROAq0uLeucBjpPUWH42IyJWjIk9I2pLmljWSZpOKk4WkHUhlPYi0PcIOwF65NtkszZ2okjtRkDtRJXdiBE/yumg2tby80PDbA18EZgE3Aj8mlTn32wC1mA9cDMyUdBWwNTAvx8CSfkzakuAbwLyIuFXSHf3yP7N27kRV3IkKuBNVcSdG8IUXlYqID0fEHGBb4GTgt6RT8DdL+kXRcBlJ2lvSts1GkvuRvhdPA5eSLo/P4UHS4tltSE8asOYm2JaJO5G4EzbEnUjcidF5kle/icAU0iuEqaRdzH9SNFFeXwWGdjCfQ1pQewbwCHBWjgAR8Q5gN+A64OOS7gA2l/SaHOPbWtwJd8KGcyfciY4GBgeLTzStA0lnAa8CVpDKeg3p5tOPFA2WmaQbImKP5vdnAA9GxMeaz6+PiNz3iETSS4C/Jq27mBYR03Jn6EfuROJO2BB3InEnRuczefWaDrwYuB+4h3TK+XdFE5UxQdLQ2tE3Au2LmkutKX0iIhY0b5O8tlCGfuROJO6EDXEnEndiFJ7kVSoi/hzYG/hMc+hDpH2ZLpW01j48PewC4ApJ/0K6P+T/hdX3jcx21VQz5pxmncuy5vM9gL/LmaGfuROruRMGuBNt3IlReJJXsYgYjIibgSXA90hXTc0ETigaLKOI+B+kJ65zgddGxND6gg3IfBNw4PPAm4GHm2w3AK/LnKGvuRPuhA3nTrgT3XgLlUpJOp60gHRf4BlSca8GzgFuKhgtu4i4psOxXxbKcrek9kNFNtrsR+7EGu6EgTvRzp3ozJO8es0AvgV8MCLuK5zFkrslzQEGJW0EHE9zSt6ymIE7URt3oqwZuBO1qaoTnuRVKiLml85gazmatPHodqQFzpcCxxRN1EfciSq5EwW5E1WqqhOe5Jmtu50j4pD2A5L2Jb1FYtaP3Amz4arqhC+8MFt3C9bxmFm/cCfMhquqEz6TZzYGSfuQFjdvLan97ZEpwIQyqczKcSfMhqu1E57kmY1tI2BTUl8mtx1/jEw3vzarjDthNlyVnfBtzczWkaQdIuLO0jnMauFOmA1XWyd8Js9s3T0p6XTSvSI3HjoYEW8oF8msKHfCbLiqOuELL8zW3fnALcDLgI8DvwauLRnIrDB3wmy4qjrhSZ7ZutsyIhYBz0TEFRFxBDC7dCizgtwJs+Gq6oTfrjVbd880v94n6a3AvcD2BfOYleZOmA1XVSc8yTNbd5+UNJV0I+wFpEvjTywbyawod8JsuKo64atrzdaDpBMj4gulc5jVwp0wG65kJ7wmz2z9+N6RZsO5E2bDFeuEJ3lm62egdACzyrgTZsMV64QneWbrx+sdzIZzJ8yGK9YJX3hhNgZJK+hc0gFgYuY4ZsW5E2bD1doJX3hhZmZm1oP8dq2ZmZlZD/Ikz8zMzKwHeZJnZmZm1oM8yTMzMzPrQf8fx8kzb+FHvy8AAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# both days\n", + "delay_type_plot(air_dec, \"12-17-16\", \"12-18-16\")" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# only the 17th\n", + "delay_type_plot(air_dec, \"12-17-16\", \"12-17-16\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# only the 18th\n", + "delay_type_plot(air_dec, \"12-18-16\", \"12-18-16\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The purpose of this exercise was to drive home the ability to *automate*\n", + "tasks.\n", + "\n", + "We were able to write a pair of `functions` that allows us to easily\n", + "repeat the exact same analysis on different subsets of the data, or\n", + "different datasets entirely (e.g. we could do the same analysis on\n", + "November 2016 data, with two lines of code).\n", + "\n", + "These principles can be applied in many settings.\n", + "\n", + "Keep that in mind as we work through the rest of the materials." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise: Cohort Analysis using Shopify Data\n", + "\n", + "The `qeds` library includes routines to simulate data sets in the\n", + "format of common sources\n", + "\n", + "One of these sources is [Shopify](https://www.shopify.com/) — an\n", + "e-commerce platform used by many retail companies for online sales\n", + "\n", + "The code below will simulate a fairly large data set that has the\n", + "properties of a order-detail report from Shopify\n", + "\n", + "We’ll first look at the data, and then describe the exercise" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 502079 entries, 0 to 502078\n", + "Data columns (total 14 columns):\n", + "Day 502079 non-null object\n", + "customer_type 502079 non-null object\n", + "Customer ID 502079 non-null int64\n", + "orders 502079 non-null int64\n", + "total_sales 502079 non-null float64\n", + "Returns 502079 non-null float64\n", + "Ordered quantity 502079 non-null int64\n", + "Gross sales 502079 non-null float64\n", + "Net sales 502079 non-null float64\n", + "Shipping 502079 non-null float64\n", + "Tax 502079 non-null float64\n", + "Net quantity 502079 non-null int64\n", + "Returned quantity 502079 non-null int64\n", + "Discounts 502079 non-null float64\n", + "dtypes: float64(7), int64(5), object(2)\n", + "memory usage: 53.6+ MB\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Daycustomer_typeCustomer IDorderstotal_salesReturnsOrdered quantityGross salesNet salesShippingTaxNet quantityReturned quantityDiscounts
02017-01-03Returning9111616584181.140.0281.1481.140.00.0200.0
12016-07-19First-time9139556302117.740.0217.7417.740.00.0200.0
22015-08-26Returning89914591281230.030.05230.03230.030.00.0500.0
32017-10-20Returning3437913651115.280.07115.28115.280.00.0700.0
42017-12-28Returning95592596581234.380.07234.38234.380.00.0700.0
\n", + "
" + ], + "text/plain": [ + " Day customer_type Customer ID orders total_sales Returns \\\n", + "0 2017-01-03 Returning 9111616584 1 81.14 0.0 \n", + "1 2016-07-19 First-time 9139556302 1 17.74 0.0 \n", + "2 2015-08-26 Returning 8991459128 1 230.03 0.0 \n", + "3 2017-10-20 Returning 343791365 1 115.28 0.0 \n", + "4 2017-12-28 Returning 9559259658 1 234.38 0.0 \n", + "\n", + " Ordered quantity Gross sales Net sales Shipping Tax Net quantity \\\n", + "0 2 81.14 81.14 0.0 0.0 2 \n", + "1 2 17.74 17.74 0.0 0.0 2 \n", + "2 5 230.03 230.03 0.0 0.0 5 \n", + "3 7 115.28 115.28 0.0 0.0 7 \n", + "4 7 234.38 234.38 0.0 0.0 7 \n", + "\n", + " Returned quantity Discounts \n", + "0 0 0.0 \n", + "1 0 0.0 \n", + "2 0 0.0 \n", + "3 0 0.0 \n", + "4 0 0.0 " + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Set the \"randomness\" seeds\n", + "random.seed(42)\n", + "np.random.seed(42)\n", + "\n", + "orders = qeds.data.shopify.simulate_orders(500000)\n", + "orders.info()\n", + "\n", + "orders.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define a customer’s cohort as the month in which a customer placed\n", + "their first order and the customer type as an indicator of whether this\n", + "was their first order or a returning order.\n", + "\n", + "We now describe the *want* for the exercise, which we ask you to\n", + "complete.\n", + "\n", + "**Want**: Compute the monthly total number of orders, total sales, and\n", + "total quantity separated by customer cohort and customer type.\n", + "\n", + "Read that carefully one more time…" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extended Exercise\n", + "\n", + "Using the reshape and `groupby` tools you have learned, apply the want\n", + "operator described above.\n", + "\n", + "See below for advice on how to proceed.\n", + "\n", + "When you are finished, you should have something that looks like this:\n", + "\n", + "![https://datascience.quantecon.org/assets/_static/groupby_files/groupby_cohort_analysis_exercise_output.png](https://datascience.quantecon.org/assets/_static/groupby_files/groupby_cohort_analysis_exercise_output.png) \n", + "Two notes on the table above:\n", + "\n", + "1. \n", + "
\n", + "
Your actual output will be much bigger. This is just to give you an
\n", + "
\n", + " idea of what it might look like. \n", + "
\n", + " \n", + "
\n", + " \n", + "1. \n", + "
\n", + "
The numbers you produce should actually be the same as what are
\n", + "
\n", + " included in this table… Index into your answer and compare what you\n", + " have with this table to verify your progress. \n", + "
\n", + " \n", + "
\n", + " \n", + "\n", + "\n", + "Now, how to do it?\n", + "\n", + "There is more than one way to code this, but here are some suggested\n", + "steps.\n", + "\n", + "1. Convert the `Day` column to have a `datetime` `dtype` instead\n", + " of object (Hint: use the `pd.to_datetime` function). \n", + "1. Add a new column that specifies the date associated with each\n", + " customer’s `\"First-time\"` order. \n", + " - Hint 1: You can do this with a combination of `groupby` and\n", + " `join`. \n", + " - Hint 2: `customer_type` is always one of `Returning` and\n", + " `First-time`. \n", + " - Hint 3: Some customers don’t have a\n", + " `customer_type == \"First-time\"` entry. You will need to set the\n", + " value for these users to some date that precedes the dates in the\n", + " sample. After adding valid data back into `orders` DataFrame,\n", + " you can identify which customers don’t have a `\"First-Time\"`\n", + " entry by checking for missing data in the new column. \n", + "1. You’ll need to group by 3 things. \n", + "1. You can apply one of the built-in aggregation functions to the GroupBy. \n", + "1. After doing the aggregation, you’ll need to use your reshaping skills to\n", + " move things to the right place in rows and columns. \n", + "\n", + "\n", + "Good luck!" + ] + } + ], + "metadata": { + "date": 1584040760.646586, + "filename": "groupby.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.3" + }, + "title": "GroupBy" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/8_groupby_exercises.ipynb b/Session_7/8_groupby_exercises.ipynb new file mode 100644 index 0000000..e6db260 --- /dev/null +++ b/Session_7/8_groupby_exercises.ipynb @@ -0,0 +1,1547 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 233, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: qeds in c:\\users\\asus\\anaconda3\\lib\\site-packages (0.6.2)\n", + "Requirement already satisfied: pandas in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.25.1)\n", + "Requirement already satisfied: numpy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.16.5)\n", + "Requirement already satisfied: quantecon in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.4.6)\n", + "Requirement already satisfied: matplotlib in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.1.1)\n", + "Requirement already satisfied: scipy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (1.3.1)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.21.3)\n", + "Requirement already satisfied: seaborn in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.9.0)\n", + "Requirement already satisfied: statsmodels in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.10.1)\n", + "Requirement already satisfied: pandas-datareader in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.8.1)\n", + "Requirement already satisfied: plotly in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (4.5.4)\n", + "Requirement already satisfied: pyarrow in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (0.16.0)\n", + "Requirement already satisfied: quandl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.5.0)\n", + "Requirement already satisfied: openpyxl in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (3.0.0)\n", + "Requirement already satisfied: requests in c:\\users\\asus\\anaconda3\\lib\\site-packages (from qeds) (2.22.0)\n", + "Requirement already satisfied: pytz>=2017.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2019.3)\n", + "Requirement already satisfied: python-dateutil>=2.6.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas->qeds) (2.8.0)\n", + "Requirement already satisfied: numba>=0.38 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (0.45.1)\n", + "Requirement already satisfied: sympy in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quantecon->qeds) (1.4)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (1.1.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from matplotlib->qeds) (2.4.2)\n", + "Requirement already satisfied: joblib>=0.11 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from scikit-learn->qeds) (0.13.2)\n", + "Requirement already satisfied: patsy>=0.4.0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from statsmodels->qeds) (0.5.1)\n", + "Requirement already satisfied: lxml in c:\\users\\asus\\anaconda3\\lib\\site-packages (from pandas-datareader->qeds) (4.4.1)\n", + "Requirement already satisfied: six in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.12.0)\n", + "Requirement already satisfied: retrying>=1.3.3 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from plotly->qeds) (1.3.3)\n", + "Requirement already satisfied: more-itertools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (7.2.0)\n", + "Requirement already satisfied: inflection>=0.3.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from quandl->qeds) (0.3.1)\n", + "Requirement already satisfied: et-xmlfile in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.0.1)\n", + "Requirement already satisfied: jdcal in c:\\users\\asus\\anaconda3\\lib\\site-packages (from openpyxl->qeds) (1.4.1)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2019.9.11)\n", + "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (1.24.2)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (3.0.4)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from requests->qeds) (2.8)\n", + "Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\asus\\anaconda3\\lib\\site-packages (from sympy->quantecon->qeds) (1.1.0)\n", + "Requirement already satisfied: setuptools in c:\\users\\asus\\anaconda3\\lib\\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)\n" + ] + } + ], + "source": [ + "! pip install qeds\n", + "import random\n", + "import numpy as np\n", + "import pandas as pd\n", + "import qeds\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "import qeds\n", + "qeds.themes.mpl_style();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GroupBy - Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**We will begin with a simple made-up dataset to discuss the concepts and then work through extended example and exercises with real data.**" + ] + }, + { + "cell_type": "code", + "execution_count": 234, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
0111.0
1112.0
2123.0
322NaN
4215.0
521NaN
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "0 1 1 1.0\n", + "1 1 1 2.0\n", + "2 1 2 3.0\n", + "3 2 2 NaN\n", + "4 2 1 5.0\n", + "5 2 1 NaN" + ] + }, + "execution_count": 234, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "C = np.arange(1, 7, dtype=float)\n", + "C[[3, 5]] = np.nan\n", + "df = pd.DataFrame({\n", + " \"A\" : [1, 1, 1, 2, 2, 2],\n", + " \"B\" : [1, 1, 2, 2, 1, 1],\n", + " \"C\": C,\n", + "})\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**We create a DataFrameGroupBy to use in what follows.**" + ] + }, + { + "cell_type": "code", + "execution_count": 235, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABC
0111.0
1112.0
2123.0
322NaN
4215.0
521NaN
\n", + "
" + ], + "text/plain": [ + " A B C\n", + "0 1 1 1.0\n", + "1 1 1 2.0\n", + "2 1 2 3.0\n", + "3 2 2 NaN\n", + "4 2 1 5.0\n", + "5 2 1 NaN" + ] + }, + "execution_count": 235, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gbA = df.groupby(\"A\")\n", + "gbA.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Try the following operations: gbA.sum(), gbA.mean(), gbA.count(). How did pandas compute the sum of `gbA`? What happened to the `NaN` entries in column `C`? Write your thoughts.** " + ] + }, + { + "cell_type": "code", + "execution_count": 236, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is gbA.sum()\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
A
146.0
245.0
\n", + "
" + ], + "text/plain": [ + " B C\n", + "A \n", + "1 4 6.0\n", + "2 4 5.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is gbA.mean()\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
A
11.3333332.0
21.3333335.0
\n", + "
" + ], + "text/plain": [ + " B C\n", + "A \n", + "1 1.333333 2.0\n", + "2 1.333333 5.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is gbA.count()\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
A
133
231
\n", + "
" + ], + "text/plain": [ + " B C\n", + "A \n", + "1 3 3\n", + "2 3 1" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# the NaN entries in column C are disregarded in the analysis, regardless of the operation we use\n", + " # for A = 2: the sum is 5, the mean is also 5 (computed with one element), the count gives us 1 element\n", + "\n", + "print(\"This is gbA.sum()\")\n", + "display(gbA.sum())\n", + "print(\"This is gbA.mean()\")\n", + "display(gbA.mean())\n", + "print(\"This is gbA.count()\")\n", + "display(gbA.count())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Use introspection (tab completion) to see what other aggregations are defined for GroupBy objects. Pick three and evaluate them in the cells below.**" + ] + }, + { + "cell_type": "code", + "execution_count": 237, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is gbA.max()\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
A
123.0
225.0
\n", + "
" + ], + "text/plain": [ + " B C\n", + "A \n", + "1 2 3.0\n", + "2 2 5.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is gbA.median()\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
A
112.0
215.0
\n", + "
" + ], + "text/plain": [ + " B C\n", + "A \n", + "1 1 2.0\n", + "2 1 5.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is gbA.diff()\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
0NaNNaN
10.01.0
21.01.0
3NaNNaN
4-1.0NaN
50.0NaN
\n", + "
" + ], + "text/plain": [ + " B C\n", + "0 NaN NaN\n", + "1 0.0 1.0\n", + "2 1.0 1.0\n", + "3 NaN NaN\n", + "4 -1.0 NaN\n", + "5 0.0 NaN" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"This is gbA.max()\")\n", + "display(gbA.max())\n", + "print(\"This is gbA.median()\")\n", + "display(gbA.median())\n", + "print(\"This is gbA.diff()\")\n", + "display(gbA.diff())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Does the output of each of these commands have the same features as the output of `gbA.sum()` from above? If not, what is different?**" + ] + }, + { + "cell_type": "code", + "execution_count": 238, + "metadata": {}, + "outputs": [], + "source": [ + "#the three commands chosen seem to have the same features, excet for the last one where the key disappears" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Write a function that, given a DataFrame, computes each entry's deviation from the mean of its column and apply the function to `gbA`.**" + ] + }, + { + "cell_type": "code", + "execution_count": 239, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BC
0-0.333333-1.0
1-0.3333330.0
20.6666671.0
30.666667NaN
4-0.3333330.0
5-0.333333NaN
\n", + "
" + ], + "text/plain": [ + " B C\n", + "0 -0.333333 -1.0\n", + "1 -0.333333 0.0\n", + "2 0.666667 1.0\n", + "3 0.666667 NaN\n", + "4 -0.333333 0.0\n", + "5 -0.333333 NaN" + ] + }, + "execution_count": 239, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# write function here\n", + "def mean_deviation(x):\n", + " avg = x.mean()\n", + " \n", + " return x - avg\n", + "\n", + "# apply function here\n", + "mean_deviation = gbA.apply(mean_deviation)\n", + "mean_deviation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Describe what the index and and columns are? Where are the group keys (the `A` column)?**" + ] + }, + { + "cell_type": "code", + "execution_count": 240, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 6 entries, 0 to 5\n", + "Data columns (total 2 columns):\n", + "B 6 non-null float64\n", + "C 4 non-null float64\n", + "dtypes: float64(2)\n", + "memory usage: 224.0 bytes\n" + ] + } + ], + "source": [ + "mean_deviation.info()\n", + "#the index contains 6 entries, from 0 to 5\n", + "#the columns are B and C\n", + "#the group keys no longer appear\n", + " #gbA.groups.keys()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Determine the correct way to add these results back into `df` as new columns.** \n", + " - Hint: remember the merge lecture" + ] + }, + { + "cell_type": "code", + "execution_count": 241, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABCB_devC_dev
0111.0-0.333333-1.0
1112.0-0.3333330.0
2123.00.6666671.0
322NaN0.666667NaN
4215.0-0.3333330.0
521NaN-0.333333NaN
\n", + "
" + ], + "text/plain": [ + " A B C B_dev C_dev\n", + "0 1 1 1.0 -0.333333 -1.0\n", + "1 1 1 2.0 -0.333333 0.0\n", + "2 1 2 3.0 0.666667 1.0\n", + "3 2 2 NaN 0.666667 NaN\n", + "4 2 1 5.0 -0.333333 0.0\n", + "5 2 1 NaN -0.333333 NaN" + ] + }, + "execution_count": 241, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# add output of function as new columns to df here...\n", + "mean_deviation_tu = mean_deviation.rename(columns={\"B\":\"B_dev\", \"C\":\"C_dev\"},inplace=True)\n", + "\n", + "merged=pd.concat([df, mean_deviation], axis=1)\n", + "merged\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
Note that if the group keys
\n", + "
\n", + "remained in the index as the `.apply`'s output, the merge/join step would have been complicated." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**We use an airline DataFrame:**" + ] + }, + { + "cell_type": "code", + "execution_count": 242, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CarrierTailNumFlightNumOriginCityMarketIDOriginOriginCityNameOriginStateNameDestCityMarketIDDestDestCityName...AirTimeDistanceCarrierDelayWeatherDelayNASDelaySecurityDelayLateAircraftDelayFirstDepTimeTotalAddGTimeDate
0AAN3JHAA4631650MSPMinneapolis, MNMinnesota30977ORDChicago, IL...58.0334.00.00.020.00.00.0NaNNaN2016-12-18
1AAN3DPAA4631650MSPMinneapolis, MNMinnesota30977ORDChicago, IL...57.0334.00.00.020.00.00.0NaNNaN2016-12-19
2AAN3KUAA4631650MSPMinneapolis, MNMinnesota30977ORDChicago, IL...49.0334.00.00.00.00.00.0NaNNaN2016-12-20
3AAN3FBAA4631650MSPMinneapolis, MNMinnesota30977ORDChicago, IL...51.0334.00.00.00.00.00.0NaNNaN2016-12-21
4AAN3BLAA4631650MSPMinneapolis, MNMinnesota30977ORDChicago, IL...51.0334.00.00.00.00.00.0NaNNaN2016-12-22
\n", + "

5 rows × 36 columns

\n", + "
" + ], + "text/plain": [ + " Carrier TailNum FlightNum OriginCityMarketID Origin OriginCityName \\\n", + "0 AA N3JHAA 46 31650 MSP Minneapolis, MN \n", + "1 AA N3DPAA 46 31650 MSP Minneapolis, MN \n", + "2 AA N3KUAA 46 31650 MSP Minneapolis, MN \n", + "3 AA N3FBAA 46 31650 MSP Minneapolis, MN \n", + "4 AA N3BLAA 46 31650 MSP Minneapolis, MN \n", + "\n", + " OriginStateName DestCityMarketID Dest DestCityName ... AirTime Distance \\\n", + "0 Minnesota 30977 ORD Chicago, IL ... 58.0 334.0 \n", + "1 Minnesota 30977 ORD Chicago, IL ... 57.0 334.0 \n", + "2 Minnesota 30977 ORD Chicago, IL ... 49.0 334.0 \n", + "3 Minnesota 30977 ORD Chicago, IL ... 51.0 334.0 \n", + "4 Minnesota 30977 ORD Chicago, IL ... 51.0 334.0 \n", + "\n", + " CarrierDelay WeatherDelay NASDelay SecurityDelay LateAircraftDelay \\\n", + "0 0.0 0.0 20.0 0.0 0.0 \n", + "1 0.0 0.0 20.0 0.0 0.0 \n", + "2 0.0 0.0 0.0 0.0 0.0 \n", + "3 0.0 0.0 0.0 0.0 0.0 \n", + "4 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " FirstDepTime TotalAddGTime Date \n", + "0 NaN NaN 2016-12-18 \n", + "1 NaN NaN 2016-12-19 \n", + "2 NaN NaN 2016-12-20 \n", + "3 NaN NaN 2016-12-21 \n", + "4 NaN NaN 2016-12-22 \n", + "\n", + "[5 rows x 36 columns]" + ] + }, + "execution_count": 242, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "air_dec = qeds.load(\"airline_performance_dec16\")\n", + "air_dec.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. **Which type of delay was the most common?**" + ] + }, + { + "cell_type": "code", + "execution_count": 243, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SecurityDelay 356\n", + "WeatherDelay 5946\n", + "NASDelay 55765\n", + "LateAircraftDelay 56377\n", + "CarrierDelay 57189\n", + "dtype: int64" + ] + }, + "execution_count": 243, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#The air_dec DataFrame has information on the minutes of delay attributed to 5 different categories:\n", + "delay_cols = [\n", + " 'CarrierDelay',\n", + " 'WeatherDelay',\n", + " 'NASDelay',\n", + " 'SecurityDelay',\n", + " 'LateAircraftDelay'\n", + "]\n", + "\n", + "air_dec[delay_cols]=(air_dec[delay_cols] > 0) \n", + "air_dec[delay_cols][air_dec[delay_cols]==True].count().sort_values()\n", + "#CarrierDelay was the most frequent one" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. **Which one caused the largest average delay?** " + ] + }, + { + "cell_type": "code", + "execution_count": 244, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SecurityDelay 0.000772\n", + "WeatherDelay 0.012899\n", + "NASDelay 0.120979\n", + "LateAircraftDelay 0.122306\n", + "CarrierDelay 0.124068\n", + "dtype: float64" + ] + }, + "execution_count": 244, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "air_dec[delay_cols].mean().sort_values()\n", + "#CarrierDelay caused the largest average delay" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. **Does that vary by airline?** " + ] + }, + { + "cell_type": "code", + "execution_count": 245, + "metadata": { + "hide-output": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CarrierDelayWeatherDelayNASDelaySecurityDelayLateAircraftDelay
Carrier
AA0.1126120.0123170.1181270.0012330.089361
AS0.0671720.0161210.1544610.0020670.078333
B60.1977970.0058780.1495400.0029180.158089
DL0.1041860.0204990.0991870.0001680.076663
EV0.1134540.0045580.1240100.0000000.122304
F90.1800270.0105250.1810060.0000000.154693
HA0.1154880.0277300.0023630.0009450.077517
NK0.1178980.0074840.2032830.0014490.089731
OO0.0902510.0163820.1498950.0004840.150500
UA0.1293140.0186580.1196680.0001750.100901
VX0.1131020.0499750.1205000.0031230.142693
WN0.1500460.0062810.1060320.0006950.170568
\n", + "
" + ], + "text/plain": [ + " CarrierDelay WeatherDelay NASDelay SecurityDelay \\\n", + "Carrier \n", + "AA 0.112612 0.012317 0.118127 0.001233 \n", + "AS 0.067172 0.016121 0.154461 0.002067 \n", + "B6 0.197797 0.005878 0.149540 0.002918 \n", + "DL 0.104186 0.020499 0.099187 0.000168 \n", + "EV 0.113454 0.004558 0.124010 0.000000 \n", + "F9 0.180027 0.010525 0.181006 0.000000 \n", + "HA 0.115488 0.027730 0.002363 0.000945 \n", + "NK 0.117898 0.007484 0.203283 0.001449 \n", + "OO 0.090251 0.016382 0.149895 0.000484 \n", + "UA 0.129314 0.018658 0.119668 0.000175 \n", + "VX 0.113102 0.049975 0.120500 0.003123 \n", + "WN 0.150046 0.006281 0.106032 0.000695 \n", + "\n", + " LateAircraftDelay \n", + "Carrier \n", + "AA 0.089361 \n", + "AS 0.078333 \n", + "B6 0.158089 \n", + "DL 0.076663 \n", + "EV 0.122304 \n", + "F9 0.154693 \n", + "HA 0.077517 \n", + "NK 0.089731 \n", + "OO 0.150500 \n", + "UA 0.100901 \n", + "VX 0.142693 \n", + "WN 0.170568 " + ] + }, + "execution_count": 245, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "air_dec.groupby(\"Carrier\")[delay_cols].mean()\n", + "#it does: \n", + " #AA - LateAircraftDelay\n", + " #EV - CarrierDelay" + ] + } + ], + "metadata": { + "date": 1584040760.646586, + "filename": "groupby.rst", + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "title": "GroupBy" + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Session_7/README.md b/Session_7/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/Session_7/Readme.md.txt b/Session_7/Readme.md.txt new file mode 100644 index 0000000..304360c --- /dev/null +++ b/Session_7/Readme.md.txt @@ -0,0 +1 @@ +Readme diff --git a/Session_8/Readme.md.txt b/Session_8/Readme.md.txt new file mode 100644 index 0000000..304360c --- /dev/null +++ b/Session_8/Readme.md.txt @@ -0,0 +1 @@ +Readme