diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a580852 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ipynb_checkpoints +.DS_Store \ No newline at end of file diff --git a/exercises/day-01/exercise_set_1.ipynb b/exercises/day-01/exercise_set_1.ipynb new file mode 100644 index 0000000..0647321 --- /dev/null +++ b/exercises/day-01/exercise_set_1.ipynb @@ -0,0 +1,415 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2cebb81f", + "metadata": {}, + "source": [ + "# Exercise Set: Python Fundamentals and Essentials" + ] + }, + { + "cell_type": "markdown", + "id": "62016856-b878-4e73-85f3-361386ccd1c4", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "6088326e", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Summer Course (July 2024)\n", + "#### Author: [Hengcheng Zhang](https://github.com/HengchengZhang)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfebd2a0", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "dab638d6", + "metadata": {}, + "source": [ + "### Exercise 1" + ] + }, + { + "cell_type": "markdown", + "id": "a872c861", + "metadata": {}, + "source": [ + "1. How do you assign the value `10` to a variable named `a`?\n", + "2. How do you assign `10` to `a` and `20` to `b` in one line?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cc09ea6", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Try to add your first code-cell below and \n", + "# assign the value to corresponding variables" + ] + }, + { + "cell_type": "markdown", + "id": "e1945ded", + "metadata": {}, + "source": [ + "### Exercise 2" + ] + }, + { + "cell_type": "markdown", + "id": "bdb9f7eb", + "metadata": {}, + "source": [ + "What are the types of the following variables `a`, `b` and `c`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4344370e", + "metadata": {}, + "outputs": [], + "source": [ + "a = 1\n", + "b = 4.3\n", + "c = \"Hi there and welcome to the workshop\"" + ] + }, + { + "cell_type": "markdown", + "id": "9080d058", + "metadata": {}, + "source": [ + "### Exercise 3\n", + "\n", + "Using the variable `c`, how can you access the *second character* in the sentence `\"Hi there and welcome to the workshop\"` (which is `i`)?\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7ae4035", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "id": "b092f809", + "metadata": {}, + "source": [ + "### Exercise 4\n", + "\n", + "Using string methods, how can you capitalize each word in the sentence `\"Hi there and welcome to the workshop\"` ?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50ffe758", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "id": "0ecc82ab", + "metadata": {}, + "source": [ + "### Exercise 5\n", + "\n", + "How can you split the sentence into a list of words such as `['Hi', 'there', ...]`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "173d6e95", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "id": "d6637060", + "metadata": {}, + "source": [ + "### Exercise 6" + ] + }, + { + "cell_type": "markdown", + "id": "4c3f4213", + "metadata": {}, + "source": [ + "Write a function `square` that returns the square of its argument $f(x) = x^2$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aace2776", + "metadata": {}, + "outputs": [], + "source": [ + "def square(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "8219a540", + "metadata": {}, + "source": [ + "**You can check your code using the following tests**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b247ced6", + "metadata": {}, + "outputs": [], + "source": [ + "square(1) == 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f7ef9fd", + "metadata": {}, + "outputs": [], + "source": [ + "square(-5) == 25" + ] + }, + { + "cell_type": "markdown", + "id": "b3e24ea7", + "metadata": {}, + "source": [ + "### Exercise 7\n", + "\n", + "Use a `for` loop and the `square` function to print the square of each element of the list `[1,5,10,20]`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a83338d", + "metadata": {}, + "outputs": [], + "source": [ + "nums = [1, 5, 10, 20]\n", + "\n", + "# TODO: Comment out and complete the following code" + ] + }, + { + "cell_type": "markdown", + "id": "3fcfa249", + "metadata": {}, + "source": [ + "### Exercise 8\n", + "\n", + "Use a list comprehension, and the `square` function, to print the square of each element of the list `[1,5,10,20]`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e68eaf3", + "metadata": {}, + "outputs": [], + "source": [ + "nums = [1, 5, 10, 20]\n", + "\n", + "# TODO: Comment out and complete the following code" + ] + }, + { + "cell_type": "markdown", + "id": "b324a686", + "metadata": {}, + "source": [ + "### Exercise 9" + ] + }, + { + "cell_type": "markdown", + "id": "7315ae3a", + "metadata": {}, + "source": [ + "Use the python `range` function to construct a list of 20 numbers from `0` to `19`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c44ec3fd", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "id": "d2fb4090", + "metadata": {}, + "source": [ + "### Exercise 10\n", + "\n", + "If you run the following code, what do you think the `range(0,20)` object is, and why is a list of values not given?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3398a147", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "range(20)" + ] + }, + { + "cell_type": "markdown", + "id": "d3b45136", + "metadata": {}, + "source": [ + "### Exercise 11\n", + "\n", + "Build a `numpy` array containing values from `0` to `19` and save it in the variable `c`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f12e8109", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "id": "a01558b8", + "metadata": {}, + "source": [ + "### Exercise 12" + ] + }, + { + "cell_type": "markdown", + "id": "28f1e83d", + "metadata": {}, + "source": [ + "Using `plot` method in `matplotlib`, plot the data defined in `d = np.array(range(20))`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35d26d29", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c35ddb39", + "metadata": {}, + "outputs": [], + "source": [ + "d = np.array(range(20))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "acca8246", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "\n", + "# TODO: Plot d using the plot() method" + ] + }, + { + "cell_type": "markdown", + "id": "f37a8aa9", + "metadata": {}, + "source": [ + "### Exercise 13\n", + "\n", + "Now, plot the square of the values in `d` using $f(x) = x^2$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "424e5f38", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/exercises/day-01/exercise_set_1_with_solution.ipynb b/exercises/day-01/exercise_set_1_with_solution.ipynb new file mode 100644 index 0000000..0dc27b4 --- /dev/null +++ b/exercises/day-01/exercise_set_1_with_solution.ipynb @@ -0,0 +1,645 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2cebb81f", + "metadata": {}, + "source": [ + "# Exercise Set: Python Fundamentals and Essentials" + ] + }, + { + "cell_type": "markdown", + "id": "a83d55a6-daad-4404-8ef1-30f113f1828a", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "ccaad8ac", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Summer Course (July 2024)\n", + "#### Author: [Hengcheng Zhang](https://github.com/HengchengZhang)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfebd2a0", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "dab638d6", + "metadata": {}, + "source": [ + "### Exercise 1" + ] + }, + { + "cell_type": "markdown", + "id": "a872c861", + "metadata": {}, + "source": [ + "1. How do you assign the value `10` to a variable named `a`?\n", + "2. How do you assign `10` to `a` and `20` to `b` in one line?" + ] + }, + { + "cell_type": "markdown", + "id": "33ec6a0b", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0f70dc0", + "metadata": {}, + "outputs": [], + "source": [ + "a = 10\n", + "a, b = 10, 20" + ] + }, + { + "cell_type": "markdown", + "id": "e1945ded", + "metadata": {}, + "source": [ + "### Exercise 2" + ] + }, + { + "cell_type": "markdown", + "id": "bdb9f7eb", + "metadata": {}, + "source": [ + "What are the types of the following variables `a`, `b` and `c`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4344370e", + "metadata": {}, + "outputs": [], + "source": [ + "a = 1\n", + "b = 4.3\n", + "c = \"Hi there and welcome to the workshop\"" + ] + }, + { + "cell_type": "markdown", + "id": "e6eb8d17", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d14b552b", + "metadata": {}, + "outputs": [], + "source": [ + "print(type(a))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48dd12d5", + "metadata": {}, + "outputs": [], + "source": [ + "print(type(b))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8690da8e", + "metadata": {}, + "outputs": [], + "source": [ + "print(type(c))" + ] + }, + { + "cell_type": "markdown", + "id": "1b6a1b58", + "metadata": {}, + "source": [ + "Here `int` indicates integers, `float` floating-point-numbers, and `str` strings." + ] + }, + { + "cell_type": "markdown", + "id": "c49a93eb", + "metadata": {}, + "source": [ + "Please also note that we are using the `print()` function here to print out our results.\n", + "\n", + "However, Jupyter Notebook has a default cell output, which allows us to print out the last variable without the `print()` function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a991b9a", + "metadata": {}, + "outputs": [], + "source": [ + "type(a)" + ] + }, + { + "cell_type": "markdown", + "id": "fcf6c7da", + "metadata": {}, + "source": [ + "We will be using this feature much in this workshop." + ] + }, + { + "cell_type": "markdown", + "id": "9080d058", + "metadata": {}, + "source": [ + "### Exercise 3\n", + "\n", + "Using the variable `c` how can you access the *second character* in the sentence `\"Hi there and welcome to the workshop\"` (which is `i`).\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "938223a2", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e5b58d3", + "metadata": {}, + "outputs": [], + "source": [ + "c[1] # use 1 to get the second element, since Python indices start from zero" + ] + }, + { + "cell_type": "markdown", + "id": "b092f809", + "metadata": {}, + "source": [ + "### Exercise 4\n", + "\n", + "Using string methods, how can you capitalize each word in the sentence `\"Hi there and welcome to the workshop\"` ?" + ] + }, + { + "cell_type": "markdown", + "id": "befbc899", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8032994e", + "metadata": {}, + "outputs": [], + "source": [ + "c.title()" + ] + }, + { + "cell_type": "markdown", + "id": "0ecc82ab", + "metadata": {}, + "source": [ + "### Exercise 5\n", + "\n", + "How can you split the sentence into a list of words such as `['Hi', 'there', ...]`" + ] + }, + { + "cell_type": "markdown", + "id": "ddaec2ba", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14937e8e", + "metadata": {}, + "outputs": [], + "source": [ + "c.split()" + ] + }, + { + "cell_type": "markdown", + "id": "d6637060", + "metadata": {}, + "source": [ + "### Exercise 6" + ] + }, + { + "cell_type": "markdown", + "id": "4c3f4213", + "metadata": {}, + "source": [ + "Write a function `square` that returns the square of its argument $f(x) = x^2$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aace2776", + "metadata": {}, + "outputs": [], + "source": [ + "def square(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "1691a446", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26d75f84", + "metadata": {}, + "outputs": [], + "source": [ + "def square(x):\n", + " return x**2 " + ] + }, + { + "cell_type": "markdown", + "id": "8219a540", + "metadata": {}, + "source": [ + "**You can check your code using the following tests**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b247ced6", + "metadata": {}, + "outputs": [], + "source": [ + "square(1) == 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f7ef9fd", + "metadata": {}, + "outputs": [], + "source": [ + "square(-5) == 25" + ] + }, + { + "cell_type": "markdown", + "id": "b3e24ea7", + "metadata": {}, + "source": [ + "### Exercise 7\n", + "\n", + "Use a `for` loop and the `square` function to print the square of each element of the list `[1,5,10,20]`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a83338d", + "metadata": {}, + "outputs": [], + "source": [ + "nums = [1, 5, 10, 20]\n", + "\n", + "# TODO: Comment out and complete the following code" + ] + }, + { + "cell_type": "markdown", + "id": "8bc11bb5", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b01ea37", + "metadata": {}, + "outputs": [], + "source": [ + "nums = [1, 5, 10, 20]\n", + "for num in nums:\n", + " print(square(num))" + ] + }, + { + "cell_type": "markdown", + "id": "3fcfa249", + "metadata": {}, + "source": [ + "### Exercise 8\n", + "\n", + "Use a list comprehension, and the `square` function, to print the square of each element of the list `[1,5,10,20]`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e68eaf3", + "metadata": {}, + "outputs": [], + "source": [ + "nums = [1, 5, 10, 20]\n", + "\n", + "# TODO: Comment out and complete the following code" + ] + }, + { + "cell_type": "markdown", + "id": "f7f55711", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1740208d", + "metadata": {}, + "outputs": [], + "source": [ + "nums = [1, 5, 10, 20]\n", + "[square(x) for x in nums]" + ] + }, + { + "cell_type": "markdown", + "id": "b324a686", + "metadata": {}, + "source": [ + "### Exercise 9" + ] + }, + { + "cell_type": "markdown", + "id": "7315ae3a", + "metadata": {}, + "source": [ + "Use the python `range` function to construct a list of 20 numbers from `0` to `19`" + ] + }, + { + "cell_type": "markdown", + "id": "a6ad1d74", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55e2f914", + "metadata": {}, + "outputs": [], + "source": [ + "list(range(20))" + ] + }, + { + "cell_type": "markdown", + "id": "d2fb4090", + "metadata": {}, + "source": [ + "### Exercise 10\n", + "\n", + "If you run the following code, what do you think the `range(0,20)` object is, and why is a list of values not given?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3398a147", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "range(20)" + ] + }, + { + "cell_type": "markdown", + "id": "2630aee2", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "raw", + "id": "2d004597", + "metadata": {}, + "source": [ + "The python function range returns an object that represents the range of values that have been defined when called.\n", + "It needs to be iterated over to actually produce the list of values in memory.\n", + "Please note that Python index starts from 0." + ] + }, + { + "cell_type": "markdown", + "id": "d3b45136", + "metadata": {}, + "source": [ + "### Exercise 11\n", + "\n", + "Build a `numpy` array containing values from `0` to `19` and save it in the variable `c`." + ] + }, + { + "cell_type": "markdown", + "id": "ad71af9b", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b49b08e5", + "metadata": {}, + "outputs": [], + "source": [ + "c = np.array(range(20))\n", + "c" + ] + }, + { + "cell_type": "markdown", + "id": "a01558b8", + "metadata": {}, + "source": [ + "### Exercise 12" + ] + }, + { + "cell_type": "markdown", + "id": "28f1e83d", + "metadata": {}, + "source": [ + "Using `plot` method in `matplotlib`, plot the data defined in `d = np.array(range(20))`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e48b921", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "e50029ab", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d9aed5f", + "metadata": {}, + "outputs": [], + "source": [ + "d = np.array(range(20))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11ae88d3", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(d)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "f37a8aa9", + "metadata": {}, + "source": [ + "### Exercise 13\n", + "\n", + "Now, plot the square of the values in `d` using $f(x) = x^2$" + ] + }, + { + "cell_type": "markdown", + "id": "41dc943e", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb695613", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(d**2)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0ff8b8f", + "metadata": {}, + "outputs": [], + "source": [ + "# You could also use your square function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(square(d))\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/exercises/day-02/exercise_set_2.ipynb b/exercises/day-02/exercise_set_2.ipynb new file mode 100644 index 0000000..c273717 --- /dev/null +++ b/exercises/day-02/exercise_set_2.ipynb @@ -0,0 +1,484 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python and Linear Algebra Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [John Stachurski](http://johnstachurski.net/), [Hengcheng Zhang](https://github.com/HengchengZhang), and [Smit Lunagariya](https://github.com/Smit-create)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import eig\n", + "from numpy.random import randn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 1\n", + "\n", + "Complete the following function that returns the number of odd elements in the given list." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_odd_num_from_list(nums):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert get_odd_num_from_list([1, 2, 3]) == 2\n", + " assert get_odd_num_from_list(list(range(1, 20))) == 10\n", + " assert get_odd_num_from_list(list(range(0, 20, 2))) == 0\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 2\n", + "\n", + "Consider the following time-series\n", + "\n", + "$$\n", + " a_{t+1} = (0.5 + r)a_t - br^2a_t\n", + "$$\n", + "\n", + "Assume that $r=0.05$, $b=100$ and $a_0=1.5$.\n", + "\n", + "Generate and plot the sequence $a_0, a_1, ..., a_T$.\n", + "\n", + "Use NumPy arrays to store the sequence $a$.\n", + "\n", + "Use $T=25$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 3\n", + "\n", + "Warm up on NumPy Basics.\n", + "\n", + "Feel free to refer to the [numpy documentation](https://numpy.org/doc/stable/reference/index.html) for API." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.1**: Write a function that creates numpy array from the given list/tuple." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def create_array(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert type(create_array([1, 2, 3])) == np.ndarray\n", + " assert type(create_array((1, 2, 3))) == np.ndarray\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.2**: Write a function to return the transpose of the given matrix." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_transpose(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert np.allclose(get_transpose(np.arange(6).reshape((3,2))), np.array([[0, 2, 4], [1, 3, 5]]))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.3**: Write a function to return the inverse of the given matrix." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_inverse(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "a_test = np.array([[1., 2.], [3., 4.]])\n", + "a_test_inv = get_inverse(a_test)\n", + "try:\n", + " assert np.allclose(np.dot(a_test, a_test_inv), np.eye(2))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.4**: Write a function to compute the norm of the vector." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_norm(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert np.allclose(get_norm([1, 2, 2, 4, 12, 5]), 13.92838827718412)\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.5**: Write a function that returns the standardized vector of the given vector such that the mean is $0$ and standard deviation is $1$. Mathematically:\n", + "$$\n", + "\\forall x_{i}\\in x:\\hspace{1em}x_{i}^{\\prime}=\\frac{x_{i}-\\mu}{\\sigma}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def standardize(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "a_test = np.random.randint(100, 2000, size=1000)\n", + "a_test_stdz = standardize(a_test)\n", + "try:\n", + " assert np.isclose(a_test_stdz.mean(), 0)\n", + " assert np.isclose(a_test_stdz.std(), 1)\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 4.1**: Write a function that takes two numpy vectors as an argument and returns `True` if they are orthogonal else returns `False`.\n", + "\n", + "*Note: Two vectors are called orthogonal if their inner product is zero.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def is_orthogonal(x, y):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert is_orthogonal(np.array([0, 1, 0, -2, 4]), np.array([-1, -4, 1, 2, 2]))\n", + " assert not is_orthogonal(np.array([0, 1, 0, -2, 4]), np.array([-1, -4, 1, 2, 4]))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 4.2**: Write a function to check whether the given matrix is symmetric or not." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def is_symmetric(x):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert is_symmetric(np.eye(3))\n", + " assert is_symmetric(np.array([[1, 3], [3, 1]]))\n", + " assert not is_symmetric(np.array([[0, 1, 0, -2, 4], [-1, -4, 1, 2, 2]]))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Please refer to this [quantecon lecture](https://intro.quantecon.org/time_series_with_matrices.html) before solving this exercise." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let $ t = 0, \\pm 1, \\pm 2, \\ldots $ index time.\n", + "\n", + "For $ t = 1, 2, 3, \\ldots, T $ suppose that\n", + "\n", + "\n", + "\n", + "$$\n", + "y_{t} = \\alpha_{0} + \\alpha_{1} y_{t-1}\n", + "$$\n", + "\n", + "where we assume that $ y_0 = 1$, $\\alpha_{0}=5$, and $\\alpha_{1}=1.2$.\n", + "\n", + "\n", + "Use the matrix algebra to solve the above time series equation, and plot the solution.\n", + "\n", + "*Hint:*\n", + "\n", + "\n", + "*Let’s write our equations as a stacked system*\n", + "\n", + "$$\n", + "\\underset{\\equiv A}{\\underbrace{\\left[\\begin{array}{cccccccc}\n", + "1 & 0 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "-\\alpha_{1} & 1 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "0 & -\\alpha_{1} & 1 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "0 & 0 & -\\alpha_{1} & 1 & \\cdots & 0 & 0 & 0\\\\\n", + "\\vdots & \\vdots & \\vdots & \\vdots & \\cdots & \\vdots & \\vdots & \\vdots\\\\\n", + "0 & 0 & 0 & 0 & \\cdots & 0 & -\\alpha_{1} & 1\n", + "\\end{array}\\right]}}\\left[\\begin{array}{c}\n", + "y_{1}\\\\\n", + "y_{2}\\\\\n", + "y_{3}\\\\\n", + "y_{4}\\\\\n", + "\\vdots\\\\\n", + "y_{T}\n", + "\\end{array}\\right]=\\underset{\\equiv b}{\\underbrace{\\left[\\begin{array}{c}\n", + "\\alpha_{0}+\\alpha_{1}y_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\vdots\\\\\n", + "\\alpha_{0}\n", + "\\end{array}\\right]}}\n", + "$$\n", + "\n", + "or\n", + "\n", + "$$\n", + "A y = b\n", + "$$\n", + "\n", + "where\n", + "\n", + "$$\n", + "y = \\begin{bmatrix} y_1 \\cr y_2 \\cr \\vdots \\cr y_T \\end{bmatrix}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Parameters\n", + "\n", + "T = 20\n", + "\n", + "𝛼0 = 5.0\n", + "𝛼1 = 1.2\n", + "\n", + "y0 = 1.0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your solution here" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-02/exercise_set_2_with_solution.ipynb b/exercises/day-02/exercise_set_2_with_solution.ipynb new file mode 100644 index 0000000..54eee50 --- /dev/null +++ b/exercises/day-02/exercise_set_2_with_solution.ipynb @@ -0,0 +1,516 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python and Linear Algebra Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [John Stachurski](http://johnstachurski.net/), [Hengcheng Zhang](https://github.com/HengchengZhang), and [Smit Lunagariya](https://github.com/Smit-create)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import eig\n", + "from numpy.random import randn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 1\n", + "\n", + "Complete the following function that returns the number of odd elements in the given list." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_odd_num_from_list(nums):\n", + " c = 0\n", + " for num in nums:\n", + " if num%2 == 1:\n", + " c += 1\n", + " return c" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert get_odd_num_from_list([1, 2, 3]) == 2\n", + " assert get_odd_num_from_list(list(range(1, 20))) == 10\n", + " assert get_odd_num_from_list(list(range(0, 20, 2))) == 0\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 2\n", + "\n", + "Consider the following time-series\n", + "\n", + "$$\n", + " a_{t+1} = (0.5 + r)a_t - br^2a_t\n", + "$$\n", + "\n", + "Assume that $r=0.05$, $b=100$ and $a_0=1.5$.\n", + "\n", + "Generate and plot the sequence $a_0, a_1, ..., a_T$.\n", + "\n", + "Use NumPy arrays to store the sequence $a$.\n", + "\n", + "Use $T=25$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "r = 0.05\n", + "T = 25\n", + "a = np.empty(T+1)\n", + "b = 100\n", + "a[0] = 1.5\n", + "\n", + "for t in range(T):\n", + " a[t+1] = (0.5 + r) * a[t] - b * r**2 * a[t]\n", + "\n", + "plt.plot(a, label='a')\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 3\n", + "\n", + "Warm up on NumPy Basics.\n", + "\n", + "Feel free to refer to the [numpy documentation](https://numpy.org/doc/stable/reference/index.html) for API." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.1**: Write a function that creates numpy array from the given list/tuple." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def create_array(x):\n", + " return np.array(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert type(create_array([1, 2, 3])) == np.ndarray\n", + " assert type(create_array((1, 2, 3))) == np.ndarray\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.2**: Write a function to return the transpose of the given matrix." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_transpose(x):\n", + " return x.T" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert np.allclose(get_transpose(np.arange(6).reshape((3,2))), np.array([[0, 2, 4], [1, 3, 5]]))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.3**: Write a function to return the inverse of the given matrix." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_inverse(x):\n", + " return np.linalg.inv(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "a_test = np.array([[1., 2.], [3., 4.]])\n", + "a_test_inv = get_inverse(a_test)\n", + "try:\n", + " assert np.allclose(np.dot(a_test, a_test_inv), np.eye(2))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.4**: Write a function to compute the norm of the vector." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_norm(x):\n", + " return np.linalg.norm(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert np.allclose(get_norm([1, 2, 2, 4, 12, 5]), 13.92838827718412)\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 3.5**: Write a function that returns the standardized vector of the given vector such that the mean is $0$ and standard deviation is $1$. Mathematically:\n", + "$$\n", + "\\forall x_{i}\\in x:\\hspace{1em}x_{i}^{\\prime}=\\frac{x_{i}-\\mu}{\\sigma}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def standardize(x):\n", + " mean, std = x.mean(), x.std()\n", + " return (x - mean) / std" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "a_test = np.random.randint(100, 2000, size=1000)\n", + "a_test_stdz = standardize(a_test)\n", + "try:\n", + " assert np.isclose(a_test_stdz.mean(), 0)\n", + " assert np.isclose(a_test_stdz.std(), 1)\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 4.1**: Write a function that takes two numpy vectors as an argument and returns `True` if they are orthogonal else returns `False`.\n", + "\n", + "*Note: Two vectors are called orthogonal if their inner product is zero.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def is_orthogonal(x, y):\n", + " return np.allclose(x.T @ y, 0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert is_orthogonal(np.array([0, 1, 0, -2, 4]), np.array([-1, -4, 1, 2, 2]))\n", + " assert not is_orthogonal(np.array([0, 1, 0, -2, 4]), np.array([-1, -4, 1, 2, 4]))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 4.2**: Write a function to check whether the given matrix is symmetric or not." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def is_symmetric(x):\n", + " if x.shape[0] != x.shape[1]:\n", + " return False\n", + " return np.allclose(x.T, x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert is_symmetric(np.eye(3))\n", + " assert is_symmetric(np.array([[1, 3], [3, 1]]))\n", + " assert not is_symmetric(np.array([[0, 1, 0, -2, 4], [-1, -4, 1, 2, 2]]))\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Please refer to this [quantecon lecture](https://intro.quantecon.org/time_series_with_matrices.html) before solving this exercise." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let $ t = 0, \\pm 1, \\pm 2, \\ldots $ index time.\n", + "\n", + "For $ t = 1, 2, 3, \\ldots, T $ suppose that\n", + "\n", + "\n", + "\n", + "$$\n", + "y_{t} = \\alpha_{0} + \\alpha_{1} y_{t-1}\n", + "$$\n", + "\n", + "where we assume that $ y_0 = 1$, $\\alpha_{0}=5$, and $\\alpha_{1}=1.2$.\n", + "\n", + "\n", + "Use the matrix algebra to solve the above time series equation, and plot the solution.\n", + "\n", + "*Hint:*\n", + "\n", + "\n", + "*Let’s write our equations as a stacked system*\n", + "\n", + "$$\n", + "\\underset{\\equiv A}{\\underbrace{\\left[\\begin{array}{cccccccc}\n", + "1 & 0 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "-\\alpha_{1} & 1 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "0 & -\\alpha_{1} & 1 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "0 & 0 & -\\alpha_{1} & 1 & \\cdots & 0 & 0 & 0\\\\\n", + "\\vdots & \\vdots & \\vdots & \\vdots & \\cdots & \\vdots & \\vdots & \\vdots\\\\\n", + "0 & 0 & 0 & 0 & \\cdots & 0 & -\\alpha_{1} & 1\n", + "\\end{array}\\right]}}\\left[\\begin{array}{c}\n", + "y_{1}\\\\\n", + "y_{2}\\\\\n", + "y_{3}\\\\\n", + "y_{4}\\\\\n", + "\\vdots\\\\\n", + "y_{T}\n", + "\\end{array}\\right]=\\underset{\\equiv b}{\\underbrace{\\left[\\begin{array}{c}\n", + "\\alpha_{0}+\\alpha_{1}y_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\vdots\\\\\n", + "\\alpha_{0}\n", + "\\end{array}\\right]}}\n", + "$$\n", + "\n", + "or\n", + "\n", + "$$\n", + "A y = b\n", + "$$\n", + "\n", + "where\n", + "\n", + "$$\n", + "y = \\begin{bmatrix} y_1 \\cr y_2 \\cr \\vdots \\cr y_T \\end{bmatrix}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Parameters\n", + "\n", + "T = 20\n", + "\n", + "𝛼0 = 5.0\n", + "𝛼1 = 1.2\n", + "\n", + "y0 = 1.0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.identity(T) # The T x T identity matrix\n", + "\n", + "for i in range(T):\n", + " if i-1 >= 0:\n", + " A[i, i-1] = -𝛼1\n", + "\n", + "b = np.full(T, 𝛼0)\n", + "b[0] = 𝛼0 + 𝛼1 * y0\n", + "\n", + "y = np.linalg.solve(A, b)\n", + "\n", + "plt.plot(np.arange(T) + 1, y)\n", + "plt.xlabel('t')\n", + "plt.ylabel('y')\n", + "\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-03/exercise_set_3.ipynb b/exercises/day-03/exercise_set_3.ipynb new file mode 100644 index 0000000..79e7bc2 --- /dev/null +++ b/exercises/day-03/exercise_set_3.ipynb @@ -0,0 +1,419 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "psy6Az1k5IeC" + }, + "source": [ + "# Probability Exercise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Smit Lunagariya](https://github.com/Smit-create)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook provides some exercises on basic probability concepts." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j8ZQc6Fc9Gn_" + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sELGoYXB5ptX" + }, + "source": [ + "### Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sELGoYXB5ptX" + }, + "source": [ + "**Question 1.1**: Consider you have $n$ cards numbered from $1$ to $n$. You need to complete the following function that returns the probability of getting an odd-numbered card." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8R9sI21c61l2" + }, + "outputs": [], + "source": [ + "def odd_card_probability(n):\n", + " # TODO: Finish the function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(odd_card_probability(5) - 3/5) < 1e-12\n", + " assert abs(odd_card_probability(240) - 1/2) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fERHpY9l8lAS" + }, + "source": [ + "### Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fERHpY9l8lAS" + }, + "source": [ + "The **Newcomb–Benford law** fits many data sets, e.g., reports of incomes to tax authorities, in which\n", + "the leading digit is more likely to be small than large.\n", + "\n", + "See [Benford's law](https://en.wikipedia.org/wiki/Benford%27s_law)\n", + "\n", + "A Benford probability distribution is\n", + "\n", + "$$\n", + "\\textrm{Prob}\\{X=d\\}=\\log _{10}(d+1)-\\log _{10}(d)=\\log _{10}\\left(1+\\frac{1}{d}\\right)\n", + "$$\n", + "\n", + "where $ d\\in\\{1,2,\\cdots,9\\} $." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f1PVcKvv9MSx" + }, + "source": [ + "**Question 2.1**: Write a function that returns the probability at any given point $d$ using the Benford probability distribution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ffmK3bkW9LJ0" + }, + "outputs": [], + "source": [ + "def probability_benford(d):\n", + " # TODO: Finish the function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Pt4p5QQh7zM4" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(probability_benford(2) - 0.17609125905568124) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cix3Fecl-XQF" + }, + "source": [ + "**Question 2.2**: Using the above function, write a function that returns the sum of probabilities at all the points in the state space of Benford's distribution i.e $d \\in \\{1, 2, ... 9\\}$. This function will help us to verify that the sum of probabilities sum to $1$.\n", + "\n", + "$$\n", + "\\quad\\sum_{d=1}^{9}\\textrm{Prob}\\{X=d\\}=1\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5RRZNe2H-Fy4" + }, + "outputs": [], + "source": [ + "def test_probability_benford():\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "eRwRb3CmAHHJ" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(test_probability_benford() - 1.0) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CYB3Q2I5Axyy" + }, + "source": [ + "**Question 2.3**: Using the above given probability distribution function, compute the cumulative density distribution. Also, plot the PMF and CDF in the same graph.\n", + "\n", + "*Hint 1: If $ X $ ia a random variable then CDF $ F_X(x)=F(x)=\\textrm{Prob}\\{X\\le x\\} $.*\n", + "\n", + "*Hint 2: See the documentation of [numpy.cumsum](https://numpy.org/doc/stable/reference/generated/numpy.cumsum.html)*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "L6vNodulJepD" + }, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dv0z2an6K5D2" + }, + "source": [ + "### Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dv0z2an6K5D2" + }, + "source": [ + "Consider the following joint distribution over $(X, Y)$ as:\n", + "\n", + "$$\n", + "F=[f_{ij}]=\\left[\\begin{array}{cc}\n", + "0.2 & 0.15 & 0.15\\\\\n", + "0.1 & 0.15 & 0.05\\\\\n", + "0.025 & 0.025 & 0.15\n", + "\\end{array}\\right]\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2jMWxxdZLul7" + }, + "outputs": [], + "source": [ + "F = np.array([\n", + " [0.2, 0.15, 0.15],\n", + " [0.1, 0.15, 0.05],\n", + " [0.025, 0.025, 0.15]\n", + "])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vPMwRWmAL5hx" + }, + "source": [ + "**Question 3.1**: Write two functions that help to calculate the marginal distribution for $\\textrm{Prob}(X=i)$ and $\\textrm{Prob}(Y=j)$ respectively.\n", + "\n", + "*Hint: See the documentation of [numpy.sum](https://numpy.org/doc/stable/reference/generated/numpy.sum.html). Read about `axis` argument.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TC0N7tsVMW3a" + }, + "outputs": [], + "source": [ + "def marginal_x(i):\n", + " # TODO: Finish this function\n", + " pass\n", + "\n", + "def marginal_y(j):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Lg-wTBk4NuTg" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(marginal_x(0) - 0.5) < 1e-12\n", + " assert abs(marginal_y(0) - 0.325) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "T4CuMxHtOB9L" + }, + "source": [ + "**Question 3.2**: Using the above two functions, write two new functions for computing the conditional distribution of $\\textrm{Prob}\\{X=i\\vert Y=j\\}$ and $\\textrm{Prob}\\{Y=i\\vert X=j\\}$ respectively.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZQWdN5QlOycF" + }, + "outputs": [], + "source": [ + "def conditional_x_given_y(i, j):\n", + " # TODO: Finish this function\n", + " pass\n", + "\n", + "def conditional_y_given_x(i, j):\n", + " # TODO: Finish this function\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DpuDU7NEO1ZX" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(conditional_x_given_y(0, 1) - 0.4615384615384615) < 1e-12\n", + " assert abs(conditional_y_given_x(2, 0) - 0.3) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generate 100000 data points from the [exponential distribution](https://en.wikipedia.org/wiki/Exponential_distribution) with density\n", + "\n", + "$$\n", + "f(x; \\alpha) = \\alpha \\exp(-\\alpha x)\n", + "\\qquad\n", + "(x > 0, \\alpha > 0)\n", + "$$\n", + "\n", + "taking $\\alpha = 0.5$. Then\n", + "\n", + "1. Plot a histogram of your sample and compare it to the density of the exponential distribution.\n", + "2. After looking up the maximum likelihood estimator of $\\alpha$, compute the estimate given your data and check that it is in fact close to $\\alpha$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "probability_fundamentals.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-03/exercise_set_3_with_solution.ipynb b/exercises/day-03/exercise_set_3_with_solution.ipynb new file mode 100644 index 0000000..d61495c --- /dev/null +++ b/exercises/day-03/exercise_set_3_with_solution.ipynb @@ -0,0 +1,488 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "psy6Az1k5IeC" + }, + "source": [ + "# Probability Exercise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Smit Lunagariya](https://github.com/Smit-create)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook provides some exercises on basic probability concepts." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j8ZQc6Fc9Gn_" + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sELGoYXB5ptX" + }, + "source": [ + "### Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sELGoYXB5ptX" + }, + "source": [ + "**Question 1.1**: Consider you have $n$ cards numbered from $1$ to $n$. You need to complete the following function that returns the probability of getting an odd-numbered card." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8R9sI21c61l2" + }, + "outputs": [], + "source": [ + "def odd_card_probability(n):\n", + " possible_odds = n//2\n", + " if n%2 == 1:\n", + " possible_odds += 1\n", + " return possible_odds/n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2043nDRa7bPj" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(odd_card_probability(5) - 3/5) < 1e-12\n", + " assert abs(odd_card_probability(240) - 1/2) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fERHpY9l8lAS" + }, + "source": [ + "### Exercise 2" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fERHpY9l8lAS" + }, + "source": [ + "The **Newcomb–Benford law** fits many data sets, e.g., reports of incomes to tax authorities, in which\n", + "the leading digit is more likely to be small than large.\n", + "\n", + "See [Benford's law](https://en.wikipedia.org/wiki/Benford%27s_law)\n", + "\n", + "A Benford probability distribution is\n", + "\n", + "$$\n", + "\\textrm{Prob}\\{X=d\\}=\\log _{10}(d+1)-\\log _{10}(d)=\\log _{10}\\left(1+\\frac{1}{d}\\right)\n", + "$$\n", + "\n", + "where $ d\\in\\{1,2,\\cdots,9\\} $." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f1PVcKvv9MSx" + }, + "source": [ + "**Question 2.1**: Write a function that returns the probability at any given point $d$ using the Benford probability distribution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ffmK3bkW9LJ0" + }, + "outputs": [], + "source": [ + "def probability_benford(d):\n", + " return np.log10(1 + 1/d)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dD0GrlpA9qhk" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(probability_benford(2) - 0.17609125905568124) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cix3Fecl-XQF" + }, + "source": [ + "**Question 2.2**: Using the above function, write a function that returns the sum of probabilities at all the points in the state space of Benford's distribution i.e $d \\in \\{1, 2, ... 9\\}$. This function will help us to verify that the sum of probabilities sum to $1$.\n", + "\n", + "$$\n", + "\\quad\\sum_{d=1}^{9}\\textrm{Prob}\\{X=d\\}=1\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5RRZNe2H-Fy4" + }, + "outputs": [], + "source": [ + "def test_probability_benford():\n", + " return sum(probability_benford(d) for d in range(1, 10))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RQGsgFdl_2v3" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(test_probability_benford() - 1.0) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CYB3Q2I5Axyy" + }, + "source": [ + "**Question 2.3**: Using the above given probability distribution function, compute the cumulative density distribution. Also, plot the PMF and CDF in the same graph.\n", + "\n", + "*Hint 1: If $ X $ ia a random variable then CDF $ F_X(x)=F(x)=\\textrm{Prob}\\{X\\le x\\} $.*\n", + "\n", + "*Hint 2: See the documentation of [numpy.cumsum](https://numpy.org/doc/stable/reference/generated/numpy.cumsum.html)*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 281 + }, + "id": "q0wM7YtfCe-Y", + "outputId": "7639fbe7-ce8f-4b58-b92b-0eda043bcbce" + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "\n", + "benford_pmf = np.array([probability_benford(d) for d in range(1,10)])\n", + "benford_cdf = np.cumsum(benford_pmf)\n", + "\n", + "ax.plot(range(1,10), benford_pmf, 'o', label=\"PMF\")\n", + "ax.plot(range(1,10), benford_cdf, '*', label=\"CDF\")\n", + "plt.title('Benford\\'s distribution')\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dv0z2an6K5D2" + }, + "source": [ + "### Exercise 3" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dv0z2an6K5D2" + }, + "source": [ + "Consider the following joint distribution over $(X, Y)$ as:\n", + "\n", + "$$\n", + "F=[f_{ij}]=\\left[\\begin{array}{cc}\n", + "0.2 & 0.15 & 0.15\\\\\n", + "0.1 & 0.15 & 0.05\\\\\n", + "0.025 & 0.025 & 0.15\n", + "\\end{array}\\right]\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2jMWxxdZLul7" + }, + "outputs": [], + "source": [ + "F = np.array([\n", + " [0.2, 0.15, 0.15],\n", + " [0.1, 0.15, 0.05],\n", + " [0.025, 0.025, 0.15]\n", + "])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vPMwRWmAL5hx" + }, + "source": [ + "**Question 3.1**: Write two functions that help to calculate the marginal distribution for $\\textrm{Prob}(X=i)$ and $\\textrm{Prob}(Y=j)$ respectively.\n", + "\n", + "*Hint: See the documentation of [numpy.sum](https://numpy.org/doc/stable/reference/generated/numpy.sum.html). Read about `axis` argument.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TC0N7tsVMW3a" + }, + "outputs": [], + "source": [ + "def marginal_x(i):\n", + " return F.sum(axis=1)[i]\n", + "\n", + "def marginal_y(j):\n", + " return F.sum(axis=0)[j]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nsg486HCNdPb" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(marginal_x(0) - 0.5) < 1e-12\n", + " assert abs(marginal_y(0) - 0.325) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "T4CuMxHtOB9L" + }, + "source": [ + "**Question 3.2**: Using the above two functions, write two new functions for computing the conditional distribution of $\\textrm{Prob}\\{X=i\\vert Y=j\\}$ and $\\textrm{Prob}\\{Y=i\\vert X=j\\}$ respectively.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZQWdN5QlOycF" + }, + "outputs": [], + "source": [ + "def conditional_x_given_y(i, j): # Prob {X = i | Y = j}\n", + " return F[i][j]/marginal_y(j)\n", + "\n", + "def conditional_y_given_x(i, j): # Prob {Y = i | X = j}\n", + " return F[j][i]/marginal_x(j)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nyGKNmz3PhLz" + }, + "outputs": [], + "source": [ + "# Test the solution\n", + "try:\n", + " assert abs(conditional_x_given_y(0, 1) - 0.4615384615384615) < 1e-12\n", + " assert abs(conditional_y_given_x(2, 0) - 0.3) < 1e-12\n", + " print(\"Congratulations!\")\n", + "except:\n", + " print(\"Wrong answer, please check your code again.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generate 100000 data points from the [exponential distribution](https://en.wikipedia.org/wiki/Exponential_distribution) with density\n", + "\n", + "$$\n", + "f(x; \\alpha) = \\alpha \\exp(-\\alpha x)\n", + "\\qquad\n", + "(x > 0, \\alpha > 0)\n", + "$$\n", + "\n", + "taking $\\alpha = 0.5$. Then\n", + "\n", + "1. Plot a histogram of your sample and compare it to the density of the exponential distribution.\n", + "2. After looking up the maximum likelihood estimator of $\\alpha$, compute the estimate given your data and check that it is in fact close to $\\alpha$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution\n", + "\n", + "After checking [the docs for the exponential distribution](http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.expon.html) we proceed as follows" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.stats import expon\n", + "import numpy as np\n", + "\n", + "alpha = 0.5\n", + "n = int(1e5)\n", + "# Scale controls the exponential parameter\n", + "ep = expon(scale=1.0/alpha)\n", + "# Generate n randome variables\n", + "x = ep.rvs(size=n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's a histogram and density." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(8, 5))\n", + "xmin, xmax = 0.001, 10.0\n", + "ax.set_xlim(xmin, xmax)\n", + "ax.hist(x, density=True, bins=60, alpha=0.3)\n", + "grid = np.linspace(xmin, xmax, 200)\n", + "ax.plot(grid, ep.pdf(grid), 'k-', lw=2, label='true density')\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It's [well-known](http://en.wikipedia.org/wiki/Exponential_distribution) that the MLE of $\\alpha$ is $1/\\bar x$ where $\\bar x$ is the mean of the sample. Let's check that it is indeed close to $\\alpha$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "alpha_mle = 1.0 / x.mean()\n", + "print(f\"max likelihood estimate of alpha is {alpha_mle}.\")" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "probability_fundamentals.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-04/exercise_set_4.ipynb b/exercises/day-04/exercise_set_4.ipynb new file mode 100644 index 0000000..05be2d3 --- /dev/null +++ b/exercises/day-04/exercise_set_4.ipynb @@ -0,0 +1,740 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "-pnHB5q0yBp7" + }, + "source": [ + "# Scientific Libraries, Monte Carlo, and More Linear Algebra Exercises" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Smit Lunagariya](https://github.com/Smit-create), [Humphrey Yang](https://github.com/HumphreyYang) and [Shu Hu](https://shu-hu.com/)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook contains exercises on scientific libraries, Monte Carlo simulation, eigenvalues and eigenvectors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "B4DjbqlLyYXB" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import eig\n", + "from numpy.random import randn" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercises\n", + "\n", + "Before you attempt these exercises, we recommend that you read\n", + "\n", + "1. the [lecture on NumPy](https://python-programming.quantecon.org/numpy.html),\n", + "2. the [lecture on Matplotlib](https://python-programming.quantecon.org/matplotlib.html) and\n", + "3. the [lecture on SciPy](https://python-programming.quantecon.org/scipy.html).\n", + "4. [An introduction to Monte Carlo](https://intro.quantecon.org/monte_carlo.html#an-introduction-to-monte-carlo)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 1\n", + "\n", + "In this exercise, use the following imports to get started." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.stats import norm" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.1** Draw 1000 independent draws from the standard normal distribution using [`scipy.stats`](https://docs.scipy.org/doc/scipy/reference/stats.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.2** Calculate the sample mean and variance of the draws and compare them to the theoretical values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.3** Visualize the empirical distribution of the draws using a histogram. Mark the sample mean and $\\pm$ one standard deviation using vertical lines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.4** Calculate the probability that a draw from the distribution is less than 0 and compare it to the proportion of the sample that is less than 0." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.5** Will results in Exercise 1.3 change with different \n", + "sample sizes? \n", + "\n", + "Try to draw 10, 100, 500, 1000, and 10000 samples. Repeat 100 times for each sample size and plot the results. What do you observe when comparing the sample estimates to the population parameters (the ground truth)?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 2\n", + "\n", + "Consider a random variable $S$ in the following form\n", + "\n", + "$$\n", + "S = \\left ( \\sum^M_{i=1} X_i \\right )^p\n", + "$$\n", + "\n", + "where $X_i \\sim LN (\\mu_i, \\sigma_i)$, $M\\in \\mathbb N$ and $p$ is a positive number known to us." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.1\n", + "\n", + "First let $M=1$ and $p=1$. Now we have\n", + "\n", + "$$\n", + " S = X_1\n", + "$$\n", + "where $X_1 \\sim LN (\\mu_1, \\sigma_1)$.\n", + "\n", + "Answer the following questions:\n", + "\n", + "**Exercise 2.1.1**\n", + "\n", + "Write down the analytical solutions to $\\mathbb E S$ and $\\mathop{\\mathrm{Var}} S$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your answers in the markdown cell above" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.2**\n", + "\n", + "Define two Python functions `mean_analytical` and `var_analytical` to compute the $\\mathbb E S$ and $\\mathop{\\mathrm{Var}} S$ directly according to their analytical solutions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def mean_analytical(μ_1, σ_1):\n", + " # TODO: Write your code here\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def var_analytical(μ_1, σ_1):\n", + " # TODO: Write your code here\n", + " pass" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.3**\n", + "\n", + "Given " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 1\n", + "μ_1 = 0.2\n", + "σ_1 = 0.1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Approximate $\\mathbb E S$ by Monte Carlo simulation using loop. \n", + "\n", + "Compare the result with the analytical solution.\n", + "\n", + "Hint. \n", + "$$\n", + "\\mathbb E S \\approx \n", + "\\frac{1}{n} \\sum_{i=1}^n S_i \n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.4**\n", + "\n", + "With the same setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 1\n", + "μ_1 = 0.2\n", + "σ_1 = 0.1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and given $\\mathbb ES$, approximate $\\mathop{\\mathrm{Var}} S$ by Monte Carlo simulation.\n", + "\n", + "Compare it with the analytical solution.\n", + "\n", + "Hint. Note that $\\mathop{\\mathrm{Var}} S = \\mathbb E \\left [S - \\mathbb E S \\right ]^2$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.5**\n", + "\n", + "With the same setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 1\n", + "μ_1 = 0.2\n", + "σ_1 = 0.1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rewrite the loops in Exercises 2.1.3 and 2.1.4 with vectorization." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.2\n", + "\n", + "Let $M=3$. Then we have\n", + "\n", + "$$\n", + " S = (X_1 + X_2 + X_3)^p\n", + "$$\n", + "which is the same form as our lecture [here](https://intro.quantecon.org/monte_carlo.html#share-price-with-unknown-distribution).\n", + "\n", + "Now we don't have analytical solutions for $\\mathbb E S$ and $\\mathop{\\mathrm{Var}} S$.\n", + "\n", + "We use the following values for $ p $ and each $ \\mu_i $ and $ \\sigma_i $." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 0.5\n", + "μ_1, μ_2, μ_3 = 0.2, 0.8, 0.4\n", + "σ_1, σ_2, σ_3 = 0.1, 0.05, 0.2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_mean_vectorized(n=1_000_000):\n", + " X_1 = np.exp(μ_1 + σ_1 * randn(n))\n", + " X_2 = np.exp(μ_2 + σ_2 * randn(n))\n", + " X_3 = np.exp(μ_3 + σ_3 * randn(n))\n", + " S = (X_1 + X_2 + X_3)**p\n", + " return S.mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "S_mean_mc_new = compute_mean_vectorized(n)\n", + "print(\"Monte Carlo simulation of ES in vectorization is \", S_mean_mc_new) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.2.1** \n", + "\n", + "Given the monte carlo simulation of $\\mathbb ES$, approximate $\\mathop{\\mathrm{Var}} S$ by Monte Carlo simulation using loop." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.2.2**\n", + "\n", + "Rewrite the loop in Exercise 2.2.1 with vectorization." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 3" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Simulate and plot the correlated time series\n", + "\n", + "$$\n", + " x_{t+1} = \\alpha \\, x_t + \\epsilon_{t+1}\n", + " \\quad \\text{where} \\quad\n", + " x_0 = 0 \n", + " \\quad \\text{and} \\quad t = 0,\\ldots,T\n", + "$$\n", + "\n", + "Here $\\{\\epsilon_t\\}$ is iid and standard normal.\n", + "\n", + "In your solution, restrict your import statements to" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from random import normalvariate\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set $T=200$ and $\\alpha = 0.9$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On day 3, we generated 100000 data points from the [exponential distribution](https://en.wikipedia.org/wiki/Exponential_distribution) with density\n", + "\n", + "$$\n", + "f(x; \\alpha) = \\alpha \\exp(-\\alpha x)\n", + "\\qquad\n", + "(x > 0, \\alpha > 0)\n", + "$$\n", + "\n", + "taking $\\alpha = 0.5$. Then\n", + "\n", + "Using the same data set, implement maximum likelihood again, but this time pretending that you don't know the analytical expression for the maximum likelihood estimator. Instead, set up the log likelihood function and maximize it numerically using a routine from `scipy.optimize`. \n", + "\n", + "(Hint: Have a look at the optimization examples from the scientific Python quickstart notebook.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 5" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recall that a discrete Lyapunov equation is a matrix equation of the form\n", + "\n", + "\n", + "\\begin{equation}\n", + " X = A X A^\\top + M\n", + "\\end{equation}\n", + "\n", + "\n", + "Here all matrices are $n \\times n$ and $X$ is the unknown. $A^\\top$ is the transpose of $A$. The equation has a unique solution if the spectral radius of $A$ is less than 1.\n", + "\n", + "There is a solver for Lyapunov equations in SciPy. Let's try it out with these matrices:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "A = np.array([[0, 1],[-1/2, -1]])\n", + "M = np.array([[0, 0], [0, 9]])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "M" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's the solver and the solution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.linalg import solve_discrete_lyapunov\n", + "solve_discrete_lyapunov(A, M)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In fact it's possible to obtain this solution by iteration, starting with a guess $X_0$, such as $X_0 = M$, and then iterating on\n", + "\n", + "$$\n", + " X_{n+1} = A X_n A^\\top + M\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try to obtain the same solution using an iterative scheme. (That is, start with $X_0$, then compute $X_1$, then $X_2$, etc. You can stop when $X_{n+1}$ and $X_n$ are close, or by using some other simpler method. But check that you get a result close to the solution above.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 6\n", + "\n", + "The task is to compute an approximation to $\\pi$ using Monte Carlo\n", + "\n", + "Your hints are as follows:\n", + "\n", + "* If $U$ is a bivariate uniform random variable on the unit square $(0, 1)^2$, then the probability that $U$ lies in a subset $B$ of $(0,1)^2$ is equal to the area of $B$.\n", + "* If $U_1,\\ldots,U_n$ are IID copies of $U$, then, as $n$ gets large, the fraction that falls in $B$, converges to the probability of landing in $B$.\n", + "* For a circle, $area = \\pi * radius^2$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 7\n", + "\n", + "Rewrite the Monte Carlo approximation of $\\pi$ in Exercise 6 using vectorized code. Compare the time it costs to run the vectorized code and the loop code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Write your code here" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-04/exercise_set_4_with_solution.ipynb b/exercises/day-04/exercise_set_4_with_solution.ipynb new file mode 100644 index 0000000..60ffe5a --- /dev/null +++ b/exercises/day-04/exercise_set_4_with_solution.ipynb @@ -0,0 +1,1152 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "-pnHB5q0yBp7" + }, + "source": [ + "# Scientific Libraries, Monte Carlo, and More Linear Algebra Exercises" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Smit Lunagariya](https://github.com/Smit-create), [Humphrey Yang](https://github.com/HumphreyYang) and [Shu Hu](https://shu-hu.com/)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook contains exercises on scientific libraries, Monte Carlo simulation, and eigenvalues and eigenvectors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "B4DjbqlLyYXB" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import eig\n", + "from numpy.random import randn" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercises\n", + "\n", + "Before you attempt these exercises, we recommend that you read\n", + "\n", + "1. the [lecture on NumPy](https://python-programming.quantecon.org/numpy.html),\n", + "2. the [lecture on Matplotlib](https://python-programming.quantecon.org/matplotlib.html) and\n", + "3. the [lecture on SciPy](https://python-programming.quantecon.org/scipy.html).\n", + "4. [An introduction to Monte Carlo](https://intro.quantecon.org/monte_carlo.html#an-introduction-to-monte-carlo)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 1\n", + "\n", + "In this exercise, use the following imports to get started." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.stats import norm" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.1** Draw 1000 independent draws from the standard normal distribution using [`scipy.stats`](https://docs.scipy.org/doc/scipy/reference/stats.html).\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Define the parameters of the standard normal distribution\n", + "mu = 0\n", + "sigma = 1\n", + "\n", + "# Generate a sample of 10000 draws from the normal distribution\n", + "samples = norm.rvs(mu, sigma, size=10_000)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.2** Calculate the sample mean and variance of the draws and compare them to the theoretical values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate the mean and standard deviation of the sample\n", + "mean = np.mean(samples)\n", + "std = np.std(samples)\n", + "\n", + "print(\"Sample mean: {:.4f}\".format(mean))\n", + "print(\"Theoretical mean: {:.4f}\".format(mu))\n", + "print(\"Sample standard deviation: {:.4f}\".format(std))\n", + "print(\"Theoretical standard deviation: {:.4f}\".format(sigma))\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.3** Visualize the empirical distribution of the draws using a histogram. Mark the sample mean and $\\pm$ one standard deviation using vertical lines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the histogram of the sample\n", + "plt.hist(samples, bins=100)\n", + "plt.axvline(mean, color='red')\n", + "plt.axvline(mean + std, color='grey')\n", + "plt.axvline(mean - std, color='grey')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.4** Calculate the probability that a draw from the distribution is less than 0 and compare it to the proportion of the sample that is less than 0." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate the probability that a draw from the distribution is less than 0\n", + "probability = norm.cdf(0, mu, sigma)\n", + "\n", + "print(\"The probability that a draw from the distribution is less than 0 is:\", \n", + " probability)\n", + "\n", + "# Calculate the proportion of samples is less than 0\n", + "proportion = np.mean(samples < 0)\n", + "\n", + "print(\"The proportion of samples is less than 0 is:\", proportion)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 1.5** Will results in Exercise 1.3 change with different \n", + "sample sizes? \n", + "\n", + "Try to draw 10, 100, 500, 1000, and 10000 samples. Repeat 100 times for each sample size and plot the results. What do you observe when comparing the sample estimates to the population parameters (the ground truth)?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a function that draws n samples from \n", + "# the standard normal distribution and returns \n", + "# mean and starndard deviation\n", + "def draw_samples(n):\n", + " samples = norm.rvs(mu, sigma, size=n)\n", + " mean = np.mean(samples)\n", + " std = np.std(samples)\n", + " return mean, std\n", + "\n", + "sample_sizes = [10, 100, 500, 1000, 10_000]\n", + "sizes_arr = np.repeat(sample_sizes, 100)\n", + "\n", + "# Draw 100 samples for each sample size using vectorized numpy code\n", + "means, stds = np.vectorize(draw_samples)(sizes_arr)\n", + "means, stds = means.reshape(5, 100), stds.reshape(5, 100)\n", + "\n", + "for i in range(5):\n", + " # Plot scatter plot of means and standard deviations\n", + " plt.scatter(means[i], stds[i], alpha=0.5, \n", + " label=\"n = {}\".format(sample_sizes[i]))\n", + " plt.axhline(sigma, color='red')\n", + " plt.axvline(mu, color='red')\n", + " plt.xlabel(\"Sample mean\")\n", + " plt.ylabel(\"Sample standard deviation\")\n", + " plt.legend()\n", + " # Limit the axis to zoom in on the plot\n", + " plt.xlim(-0.5, 0.5)\n", + " plt.ylim(0.5, 1.5)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 2\n", + "\n", + "Consider a random variable $S$ in the following form\n", + "\n", + "$$\n", + "S = \\left ( \\sum^M_{i=1} X_i \\right )^p\n", + "$$\n", + "\n", + "where $X_i \\sim LN (\\mu_i, \\sigma_i)$, $M\\in \\mathbb N$ and $p$ is a positive number known to us." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.1\n", + "\n", + "First let $M=1$ and $p=1$. Now we have\n", + "\n", + "$$\n", + " S = X_1\n", + "$$\n", + "where $X_1 \\sim LN (\\mu_1, \\sigma_1)$.\n", + "\n", + "Answer the following questions:\n", + "\n", + "**Exercise 2.1.1**\n", + "\n", + "Write down the analytical solutions to $\\mathbb E S$ and $\\mathop{\\mathrm{Var}} S$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution to Exercise 2.1.1**\n", + "\n", + "See section [*Share price with known distribution*](https://intro.quantecon.org/monte_carlo.html#share-price-with-known-distribution)." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.2**\n", + "\n", + "Define two Python functions `mean_analytical` and `var_analytical` to compute the $\\mathbb E S$ and $\\mathop{\\mathrm{Var}} S$ directly according to their analytical solutions." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution to Exercise 2.1.2**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def mean_analytical(μ_1, σ_1):\n", + " return np.exp(μ_1 + σ_1 ** 2 / 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def var_analytical(μ_1, σ_1):\n", + " return (np.exp(σ_1 ** 2) - 1) * np.exp(2 * μ_1 + σ_1 ** 2)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.3**\n", + "\n", + "Given " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 1\n", + "μ_1 = 0.2\n", + "σ_1 = 0.1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Approximate $\\mathbb E S$ by Monte Carlo simulation using loop. \n", + "\n", + "Compare the result with the analytical solution.\n", + "\n", + "Hint. \n", + "$$\n", + "\\mathbb E S \\approx \n", + "\\frac{1}{n} \\sum_{i=1}^n S_i \n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution to Exercise 2.1.3**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "S = 0.0\n", + "for i in range(n):\n", + " X_1 = np.exp(μ_1 + σ_1 * randn())\n", + " S += (X_1)**p\n", + "S_mean_mc = S / n\n", + "S_mean_analytical = mean_analytical(μ_1, σ_1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Monte Carlo simulation of ES in loop is \", S_mean_mc) \n", + "print(\"Analytical solution result of ES is \", S_mean_analytical)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.4**\n", + "\n", + "With the same setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 1\n", + "μ_1 = 0.2\n", + "σ_1 = 0.1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and given $\\mathbb ES$, approximate $\\mathop{\\mathrm{Var}} S$ by Monte Carlo simulation.\n", + "\n", + "Compare it with the analytical solution.\n", + "\n", + "Hint. Note that $\\mathop{\\mathrm{Var}} S = \\mathbb E \\left [S - \\mathbb E S \\right ]^2$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution to Exercise 2.1.4**\n", + "\n", + "We can use the result of either the analytical solution or the Monte Carolo simulation for $\\mathbb S$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "S = 0.0\n", + "for i in range(n):\n", + " X_1 = np.exp(μ_1 + σ_1 * randn())\n", + " S += ((X_1)**p - S_mean_analytical) ** 2 \n", + "S_var_mc = S / n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "S_var_analytical = var_analytical(μ_1, σ_1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Monte Carlo simulation of VarS in loop is \", S_var_mc) \n", + "print(\"Analytical solution result of VarS is \", S_var_analytical)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.1.5**\n", + "\n", + "With the same setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 1\n", + "μ_1 = 0.2\n", + "σ_1 = 0.1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rewrite the loops in Exercises 2.1.3 and 2.1.4 with vectorization." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution to Exercise 2.1.5**\n", + "\n", + "First $\\mathbb E S$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "X_1 = np.exp(μ_1 + σ_1 * randn(n))\n", + "S = (X_1)**p\n", + "S_mean_mc = S.mean()\n", + "print(\"Monte Carlo simulation of ES in vectorization is \", S_mean_mc) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then $\\mathop{\\mathrm{Var}} S$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "X_1 = np.exp(μ_1 + σ_1 * randn(n))\n", + "S = ((X_1)**p - S_mean_analytical) ** 2\n", + "S_var_mc = S.mean()\n", + "print(\"Monte Carlo simulation of VarS in vectorization is \", S_var_mc) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.2\n", + "\n", + "Let $M=3$. Then we have\n", + "\n", + "$$\n", + " S = (X_1 + X_2 + X_3)^p\n", + "$$\n", + "which is the same form as our lecture [here](https://intro.quantecon.org/monte_carlo.html#share-price-with-unknown-distribution).\n", + "\n", + "Now we don't have analytical solutions for $\\mathbb E S$ and $\\mathop{\\mathrm{Var}} S$.\n", + "\n", + "We use the following values for $ p $ and each $ \\mu_i $ and $ \\sigma_i $." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1_000_000\n", + "p = 0.5\n", + "μ_1, μ_2, μ_3 = 0.2, 0.8, 0.4\n", + "σ_1, σ_2, σ_3 = 0.1, 0.05, 0.2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_mean_vectorized(n=1_000_000):\n", + " X_1 = np.exp(μ_1 + σ_1 * randn(n))\n", + " X_2 = np.exp(μ_2 + σ_2 * randn(n))\n", + " X_3 = np.exp(μ_3 + σ_3 * randn(n))\n", + " S = (X_1 + X_2 + X_3)**p\n", + " return S.mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "S_mean_mc_new = compute_mean_vectorized(n)\n", + "print(\"Monte Carlo simulation of ES in vectorization is \", S_mean_mc_new) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.2.1** \n", + "\n", + "Given the monte carlo simulation of $\\mathbb ES$, approximate $\\mathop{\\mathrm{Var}} S$ by Monte Carlo simulation using loop." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution to Exercise 2.2.1**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "S = 0.0\n", + "for i in range(n):\n", + " X_1 = np.exp(μ_1 + σ_1 * randn())\n", + " X_2 = np.exp(μ_2 + σ_2 * randn())\n", + " X_3 = np.exp(μ_3 + σ_3 * randn())\n", + " S += ((X_1 + X_2 + X_3)**p - S_mean_mc_new) ** 2\n", + "S_var_mc_new_loop = S / n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Monte Carlo simulation of VarS in loop is\", S_var_mc_new_loop) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise 2.2.2**\n", + "\n", + "Rewrite the loop in Exercise 2.2.1 with vectorization." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution to Exercise 2.2.2**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "X_1 = np.exp(μ_1 + σ_1 * randn(n))\n", + "X_2 = np.exp(μ_2 + σ_2 * randn(n))\n", + "X_3 = np.exp(μ_3 + σ_3 * randn(n))\n", + "S = ((X_1 + X_2 + X_3)**p - S_mean_mc_new) ** 2\n", + "S_var_mc_new = S.mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Monte Carlo simulation of VarS in vectorization is\", S_var_mc_new) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 3" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Simulate and plot the correlated time series\n", + "\n", + "$$\n", + " x_{t+1} = \\alpha \\, x_t + \\epsilon_{t+1}\n", + " \\quad \\text{where} \\quad\n", + " x_0 = 0 \n", + " \\quad \\text{and} \\quad t = 0,\\ldots,T\n", + "$$\n", + "\n", + "Here $\\{\\epsilon_t\\}$ is iid and standard normal.\n", + "\n", + "In your solution, restrict your import statements to" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from random import normalvariate\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set $T=200$ and $\\alpha = 0.9$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "# Set random seed to replicate the solution\n", + "# (This is optional and used so that each time you run the cell, \n", + "# you get same results)\n", + "random.seed(2024)\n", + "\n", + "alpha = 0.9\n", + "ts_length = 200\n", + "x = 0\n", + "\n", + "x_values = []\n", + "for i in range(ts_length):\n", + " x_values.append(x)\n", + " x = alpha * x + normalvariate(0, 1)\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x_values, '-')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On day 2, we generated 100000 data points from the [exponential distribution](https://en.wikipedia.org/wiki/Exponential_distribution) with density\n", + "\n", + "$$\n", + "f(x; \\alpha) = \\alpha \\exp(-\\alpha x)\n", + "\\qquad\n", + "(x > 0, \\alpha > 0)\n", + "$$\n", + "\n", + "taking $\\alpha = 0.5$. Then\n", + "\n", + "Using the same data set, implement maximum likelihood again, but this time pretending that you don't know the analytical expression for the maximum likelihood estimator. Instead, set up the log likelihood function and maximize it numerically using a routine from `scipy.optimize`. \n", + "\n", + "(Hint: Have a look at the optimization examples from the scientific Python quickstart notebook.)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First let's set up the log likelihood function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.stats import expon\n", + "\n", + "alpha = 0.5\n", + "n = int(1e5)\n", + "# Scale controls the exponential parameter\n", + "ep = expon(scale=1.0/alpha)\n", + "# Generate n randome variables\n", + "x = ep.rvs(size=n)\n", + "\n", + "s = x.sum()\n", + "def neg_loglike(a):\n", + " return - n * np.log(a) + a * s" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function is minus the log likelihood function for the exponential distribution." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Minimize over a reasonable parameter space" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.optimize import minimize_scalar\n", + "res = minimize_scalar(neg_loglike, bounds=(0.01, 10.0), method='bounded')\n", + "res.x" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is close to the analytical value of the max likelihood estimator we got on day 2." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 5" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recall that a discrete Lyapunov equation is a matrix equation of the form\n", + "\n", + "\n", + "\\begin{equation}\n", + " X = A X A^\\top + M\n", + "\\end{equation}\n", + "\n", + "\n", + "Here all matrices are $n \\times n$ and $X$ is the unknown. $A^\\top$ is the transpose of $A$. The equation has a unique solution if the spectral radius of $A$ is less than 1.\n", + "\n", + "There is a solver for Lyapunov equations in SciPy. Let's try it out with these matrices:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "A = np.array([[0, 1],[-1/2, -1]])\n", + "M = np.array([[0, 0], [0, 9]])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "M" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's the solver and the solution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.linalg import solve_discrete_lyapunov\n", + "solve_discrete_lyapunov(A, M)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In fact it's possible to obtain this solution by iteration, starting with a guess $X_0$, such as $X_0 = M$, and then iterating on\n", + "\n", + "$$\n", + " X_{n+1} = A X_n A^\\top + M\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try to obtain the same solution using an iterative scheme. (That is, start with $X_0$, then compute $X_1$, then $X_2$, etc. You can stop when $X_{n+1}$ and $X_n$ are close, or by using some other simpler method. But check that you get a result close to the solution above.)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's an iterative algorithm that computes the solution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "P = M\n", + "tol = 1e-6\n", + "max_iter = 500\n", + "\n", + "for i in range(max_iter):\n", + " P_new = A @ P @ A.T + M\n", + " error = np.linalg.norm(P - P_new, ord=2)\n", + " if error < tol:\n", + " break\n", + " P = P_new\n", + "P" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is close to what we had before:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "solve_discrete_lyapunov(A, M)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 6\n", + "\n", + "The task is to compute an approximation to $\\pi$ using Monte Carlo in loop.\n", + "\n", + "Your hints are as follows:\n", + "\n", + "* If $U$ is a bivariate uniform random variable on the unit square $(0, 1)^2$, then the probability that $U$ lies in a subset $B$ of $(0,1)^2$ is equal to the area of $B$.\n", + "* If $U_1,\\ldots,U_n$ are IID copies of $U$, then, as $n$ gets large, the fraction that falls in $B$, converges to the probability of landing in $B$.\n", + "* For a circle, $area = \\pi * radius^2$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "n = 1_000_000 # sample size for Monte Carlo simulation\n", + "\n", + "count = 0\n", + "for i in range(n):\n", + "\n", + " # drawing random positions on the square\n", + " u, v = np.random.uniform(), np.random.uniform()\n", + "\n", + " # check whether the point falls within the boundary\n", + " # of the unit circle centered at (0.5,0.5)\n", + " d = np.sqrt((u - 0.5)**2 + (v - 0.5)**2)\n", + "\n", + " # if it falls within the inscribed circle, \n", + " # add it to the count\n", + " if d < 0.5:\n", + " count += 1\n", + "\n", + "area_estimate = count / n\n", + "\n", + "print(area_estimate * 4) # dividing by radius**2" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 7\n", + "\n", + "Rewrite the Monte Carlo approximation of $\\pi$ in Exercise 6 using vectorized code. Compare the time it costs to run the vectorized code and the loop code." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "n = 1_000_000\n", + "\n", + "u, v = np.random.uniform(size=n), np.random.uniform(size=n)\n", + "\n", + "d = np.sqrt((u - 0.5)**2 + (v - 0.5)**2)\n", + "\n", + "count = np.sum(d < 0.5)\n", + "\n", + "area_estimate = count / n\n", + "\n", + "print(area_estimate * 4) # dividing by radius**2" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We find that the vectorized version runs much faster. \n", + "\n", + "It enables us to do more simulations in the same amount of time to increase the precision of our simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "# Try to increase the sample size to 100 million\n", + "n = 100_000_000\n", + "\n", + "# Drawing random positions on the square\n", + "u, v = np.random.uniform(size=n), np.random.uniform(size=n)\n", + "\n", + "d = np.sqrt((u - 0.5)**2 + (v - 0.5)**2)\n", + "\n", + "count = np.sum(d < 0.5)\n", + "\n", + "area_estimate = count / n\n", + "\n", + "print(area_estimate * 4) # dividing by radius**2" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-05/exercise_set_5.ipynb b/exercises/day-05/exercise_set_5.ipynb new file mode 100644 index 0000000..56953a4 --- /dev/null +++ b/exercises/day-05/exercise_set_5.ipynb @@ -0,0 +1,697 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Equilibrium and Present Values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [John Stachurski](http://johnstachurski.net/), [Frank](https://github.com/chappiewuzefan) and [Shu Hu](https://shu-hu.com/)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy as sp\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 1 (Numpy)\n", + "\n", + "Read the section [NumPy Arrays](https://python-programming.quantecon.org/numpy.html#numpy-arrays) before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.1\n", + "\n", + "Create a zero numpy array with dimension ``(10, )`` and ``dtype`` to ``np.float32``.\n", + "\n", + "Assign this array to a global variable called ``a``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.2\n", + "\n", + "Inspect the dimension of the array created in Exercise 1.1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.3\n", + "\n", + "Use ``np.linspace`` to create a same array as in Exercise 1.1.\n", + "\n", + "Assign this array to a global variable called ``b``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.4\n", + "\n", + "Replace the third element of variable ``b`` with $10$.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.5\n", + "\n", + "Sort the new ``b`` from Exercise 1.4.\n", + "\n", + "Compute its sum, mean, max, argmax, cumulative sum, cumulative product, variance, and standard deviation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.6\n", + "\n", + "Find the index of the first element of the new ``b`` from Exercise 1.4 that is ``>= 5``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 2\n", + "\n", + "Read the sections [Arithmetic Operations](https://python-programming.quantecon.org/numpy.html#arithmetic-operations) to [Mutability and Copying Arrays](https://python-programming.quantecon.org/numpy.html#mutability-and-copying-arrays) before you attempt the following exercises.\n", + "\n", + "- element-wise arithmetic operations\n", + "- matrix multiplication\n", + "- mutability using index\n", + "- copying using .copy\n", + "- broadcasting" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Given the following arrays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C = 3 * np.ones((3, 3)) \n", + "D = np.ones((3, 3)) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.1\n", + "\n", + "Perform the operations `+`, `-`, `*`, `/` between ``C`` and ``D``.\n", + "\n", + "Assign the value of the sum to a global variable called ``E``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.2\n", + "\n", + "Perform the operation ``**`` on ``E`` with a power $5$.\n", + "\n", + "Assign the value after the power operation to a global variable called ``F``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.3\n", + "\n", + "Compute the matrix multiplication between ``E`` and ``F``.\n", + "\n", + "Assign the value after the matrix multiplication to a global variable called ``G``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.4\n", + "\n", + "Change the element in the second row and third column of ``G`` to $100$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.5\n", + "\n", + "Copy the array from Exercise 2.4 to a new global variable called ``H``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 3\n", + "\n", + "Read the section [Roots and Fixed Points](https://python-programming.quantecon.org/scipy.html#roots-and-fixed-points) before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.1\n", + "\n", + "Plot the following function $f$ on $[-5, 0]$:\n", + "$$\n", + " f(x) = 5 ( \\sin x - \\frac{1}{5}) + x^{2} + x^{3} +20\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.2\n", + "\n", + "Read the section [bisection](https://python-programming.quantecon.org/scipy.html#bisection).\n", + "\n", + "Use the bisection function from ``SciPy`` to find the root for the function $f$ defined in Exercise 3.1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.3\n", + "\n", + "Read the section [The Newton-Raphson Method](https://python-programming.quantecon.org/scipy.html#the-newton-raphson-method).\n", + "\n", + "With different initial conditions $x=0, -2.5, -5$, \n", + "\n", + "try to use the newton function from ``SciPy`` to find the root for the function $f$ defined in Exercise 3.1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.4\n", + "\n", + "Read the section [Hybrid Methods](https://python-programming.quantecon.org/scipy.html#hybrid-methods).\n", + "\n", + "Find the root for the function $f$ defined in Exercise 3.1 using the brentq function from ``SciPy``" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.5\n", + "\n", + "Read the section [Fixed Points](https://python-programming.quantecon.org/scipy.html#fixed-points).\n", + "\n", + "With different initial guesses $x=-5, -2.5, 0$,\n", + "\n", + "Find the root for the function $f$ defined in Exercise 3.1 using the fixed point function from ``SciPy``" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.6\n", + "\n", + "Read the section [Optimization](https://python-programming.quantecon.org/scipy.html#optimization).\n", + "\n", + "Use functions from ``SciPy`` to find the maximizer and minimizer of the function $f$ defined in Exercise 3.1 over domain $D = [-5, 0]$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.7\n", + "\n", + "Read the section [Integration](https://python-programming.quantecon.org/scipy.html#integration).\n", + "\n", + "Use functions from ``SciPy`` to find the integral for the function $f$ defined in Exercise 3.1 over domain $D = [-5, 0]$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4 (Present Value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.1: Computing Present Value\n", + "\n", + "Imagine you have the opportunity to receive $500 two years from now. If the annual discount rate is 5%, what is the present value of this future cash flow?\n", + "\n", + "*Hint: Use the formula of [present value](https://en.wikipedia.org/wiki/Present_value).*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " assert abs(present_value(500, 0.05, 2) - 453.51) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.2: Evaluating a Series of Future Cash Flows\n", + "\n", + "Suppose you are evaluating an investment that promises to pay $1000 at the end of each year for the next five years. If your discount rate is still 5% per annum, what is the present value of these future cash flows?\n", + "\n", + "*Hint: In this case, you will have to sum the present values of each future cash flow.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " assert abs(present_value_series(1000, 0.05, range(1, 6)) - 4329.48) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.3: Asset Pricing Using the Present Value Model\n", + "\n", + "Consider a stock that is expected to pay dividends of $100$ at the end of each year for the next three years, after which point it is expected to be sold for $1500$. If the annual discount rate is 6%, calculate:\n", + "\n", + "1. The present value of the dividends.\n", + "2. The present value of the terminal price of the stock.\n", + "3. The total present value of the stock (which should be equal to its current price).\n", + "\n", + "*Hint: Use the same method as in the second exercise for the dividends, and the method from the first exercise for the terminal price.*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " PV_dividends, PV_terminal, PV_total = calculate_stock_value(100, 1500, 0.06, range(1, 4))\n", + " assert abs(PV_dividends - 267.3) < 1e-2\n", + " assert abs(PV_terminal - 1259.43) < 1e-2\n", + " assert abs(PV_total - 1526.73) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.4: Matrix Multiplication in Asset Pricing\n", + "\n", + "Consider an asset that is expected to yield dividends of $100$ at the end of each year for the next five years, after which point it is predicted to be sold for $2000$. The annual discount rate is set to be 5%. Your task is to compute:\n", + "\n", + "1. The present value of the dividends using matrix multiplication.\n", + "2. The present value of the final price of the asset.\n", + "3. The total present value of the asset (which should be equal to its current price).\n", + "\n", + "*Hint: Use matrix multiplication to solve for the present value of dividends, and use the same method as in the previous exercise for the final price.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " PV_dividends, PV_final_price, PV_total = calculate_asset_value(100, 2000, 0.05, range(1, 6))\n", + " assert abs(PV_dividends - 432.95) < 1e-2\n", + " assert abs(PV_final_price - 1567.05) < 1e-2\n", + " assert abs(PV_total - 2000.0) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 5\n", + "\n", + "Read section [present value calculation](https://intro.quantecon.org/pv.html#present-value-calculations) before attempting exercises 6.1 and 6.1.\n", + "\n", + "Let $A, p, d, b$ be as defined in that section.\n", + "\n", + "So we have\n", + "\n", + "$$\n", + " A p = d + b\n", + "$$\n", + "\n", + "#### Exercise 5.1: Price of a worthless stock\n", + "\n", + "Compute and plot the corresponding asset price sequence when $T=6$, $p^*_{T+1} = 0$, $d_t=0$ and $\\delta\n", + "= 0.98$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 5.2: Gorden growth formula\n", + "\n", + "Let $\\delta$ be the same as Exercise 5.1.\n", + "\n", + "Compute and plot the corresponding asset price sequence when $T=100$, $p^*_{T+1} = g^{T+1} d_0$ and $d_t=g^t d_0$\n", + "where $g=1.1$ and $d_0=0.1$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 5.3: Analytical expressions\n", + "\n", + "Read section [analytical expressions](https://intro.quantecon.org/pv.html#analytical-expressions).\n", + "\n", + "Give analytical expressions for the asset price $p_t$ in Exercise 5.2." + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-05/exercise_set_5_with_solution.ipynb b/exercises/day-05/exercise_set_5_with_solution.ipynb new file mode 100644 index 0000000..5161008 --- /dev/null +++ b/exercises/day-05/exercise_set_5_with_solution.ipynb @@ -0,0 +1,1221 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Equilibrium and Present Values" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [John Stachurski](http://johnstachurski.net/), [Frank](https://github.com/chappiewuzefan) and [Shu Hu](https://shu-hu.com/)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy as sp\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 1 (Numpy)\n", + "\n", + "Read the section [NumPy Arrays](https://python-programming.quantecon.org/numpy.html#numpy-arrays) before you attempt the following exercises." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.1\n", + "\n", + "Create a zero numpy array with dimension ``(10, )`` and ``dtype`` to ``np.float32``.\n", + "\n", + "Assign this array to a global variable called ``a``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.zeros(10, dtype=np.float32)\n", + "a" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.2\n", + "\n", + "Inspect the dimension of the array created in Exercise 1.1." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a.shape" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.3\n", + "\n", + "Use ``np.linspace`` to create a same array as in Exercise 1.1.\n", + "\n", + "Assign this array to a global variable called ``b``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = np.linspace(0, 0, 10, dtype=np.float32)\n", + "b" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.4\n", + "\n", + "Replace the third element of variable ``b`` with $10$.\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b[2] = 10\n", + "b" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.5\n", + "\n", + "Sort the new ``b`` from Exercise 1.4.\n", + "\n", + "Compute its sum, mean, max, argmax, cumulative sum, cumulative product, variance, and standard deviation." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.sort()\n", + "b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.sum()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.max()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.argmax()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.cumsum()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.cumprod()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.var()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.std()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 1.6\n", + "\n", + "Find the index of the first element of the new ``b`` from Exercise 1.4 that is ``>= 5``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.searchsorted(5, side='right')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 2\n", + "\n", + "Read the sections [Arithmetic Operations](https://python-programming.quantecon.org/numpy.html#arithmetic-operations) to [Mutability and Copying Arrays](https://python-programming.quantecon.org/numpy.html#mutability-and-copying-arrays) before you attempt the following exercises.\n", + "\n", + "- element-wise arithmetic operations\n", + "- matrix multiplication\n", + "- mutability using index\n", + "- copying using .copy\n", + "- broadcasting" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Given the following arrays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C = 3 * np.ones((3, 3)) \n", + "D = np.ones((3, 3)) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.1\n", + "\n", + "Perform the operations `+`, `-`, `*`, `/` between ``C`` and ``D``.\n", + "\n", + "Assign the value of the sum to a global variable called ``E``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "E = C + D\n", + "E" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C - D" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C * D" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C / D" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.2\n", + "\n", + "Perform the operation ``**`` on ``E`` with a power $5$.\n", + "\n", + "Assign the value after the power operation to a global variable called ``F``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "F = E ** 5\n", + "F" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.3\n", + "\n", + "Compute the matrix multiplication between ``E`` and ``F``.\n", + "\n", + "Assign the value after the matrix multiplication to a global variable called ``G``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "G = E @ F\n", + "G" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.4\n", + "\n", + "Change the element in the second row and third column of ``G`` to $100$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "G[1, 2] = 100\n", + "G" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 2.5\n", + "\n", + "Copy the array from Exercise 2.4 to a new global variable called ``H``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "H = np.copy(G)\n", + "H" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 3\n", + "\n", + "Read the section [Roots and Fixed Points](https://python-programming.quantecon.org/scipy.html#roots-and-fixed-points) before you attempt the following exercises." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.1\n", + "\n", + "Plot the following function $f$ on $[-5, 0]$:\n", + "$$\n", + " f(x) = 5 ( \\sin x - \\frac{1}{5}) + x^{2} + x^{3} +20\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def f(x): return 5 * (np.sin(x) - 1/5) + x**2 + x**3 + 20" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = np.linspace(-5, 0, 100)\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x, f(x), label='$f(x)$')\n", + "ax.axhline(ls='--', c='k')\n", + "ax.set_xlabel('$x$', fontsize=12)\n", + "ax.set_ylabel('$f(x)$', fontsize=12)\n", + "ax.legend(fontsize=12)\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.2\n", + "\n", + "Read the section [bisection](https://python-programming.quantecon.org/scipy.html#bisection).\n", + "\n", + "Use the bisection function from ``SciPy`` to find the root for the function $f$ defined in Exercise 3.1." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.bisect(f, -5, 0)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.3\n", + "\n", + "Read the section [The Newton-Raphson Method](https://python-programming.quantecon.org/scipy.html#the-newton-raphson-method).\n", + "\n", + "With different initial conditions $x=0, -2.5, -5$, \n", + "\n", + "try to use the newton function from ``SciPy`` to find the root for the function $f$ defined in Exercise 3.1." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.newton(f, 0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.newton(f, -2.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.newton(f, -5)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.4\n", + "\n", + "Read the section [Hybrid Methods](https://python-programming.quantecon.org/scipy.html#hybrid-methods).\n", + "\n", + "Find the root for the function $f$ defined in Exercise 3.1 using the brentq function from ``SciPy``" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.brentq(f, -5, 0)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.5\n", + "\n", + "Read the section [Fixed Points](https://python-programming.quantecon.org/scipy.html#fixed-points).\n", + "\n", + "With different initial guesses $x=-5, -2.5, 0$,\n", + "\n", + "Find the root for the function $f$ defined in Exercise 3.1 using the fixed point function from ``SciPy``" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.fixed_point(f, -5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.fixed_point(f, -2.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.fixed_point(f, 0)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.6\n", + "\n", + "Read the section [Optimization](https://python-programming.quantecon.org/scipy.html#optimization).\n", + "\n", + "Use functions from ``SciPy`` to find the maximizer and minimizer of the function $f$ defined in Exercise 3.1 over domain $D = [-5, 0]$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.minimize_scalar(f, bounds=(-5, 0))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "g = lambda x: f(-x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sp.optimize.minimize_scalar(g, bounds=(-5, 0))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 3.7\n", + "\n", + "Read the section [Integration](https://python-programming.quantecon.org/scipy.html#integration).\n", + "\n", + "Use functions from ``SciPy`` to find the integral for the function $f$ defined in Exercise 3.1 over domain $D = [-5, 0]$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "integral, _ = sp.integrate.quad(f, -5, 0)\n", + "integral" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 4 (Present Value)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.1: Computing Present Value\n", + "\n", + "Imagine you have the opportunity to receive $500 two years from now. If the annual discount rate is 5%, what is the present value of this future cash flow?\n", + "\n", + "*Hint: Use the formula of [present value](https://en.wikipedia.org/wiki/Present_value).*" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def present_value(FV, r, n):\n", + " PV = FV / (1 + r)**n\n", + " return round(PV, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " assert abs(present_value(500, 0.05, 2) - 453.51) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.2: Evaluating a Series of Future Cash Flows\n", + "\n", + "Suppose you are evaluating an investment that promises to pay $1000 at the end of each year for the next five years. If your discount rate is still 5% per annum, what is the present value of these future cash flows?\n", + "\n", + "*Hint: In this case, you will have to sum the present values of each future cash flow.*" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def present_value_series(annual_cash_flow, r, years):\n", + " result = sum([annual_cash_flow / (1 + r)**n for n in years])\n", + " return round(result, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " assert abs(present_value_series(1000, 0.05, range(1, 6)) - 4329.48) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.3: Asset Pricing Using the Present Value Model\n", + "\n", + "Consider a stock that is expected to pay dividends of $100$ at the end of each year for the next three years, after which point it is expected to be sold for $1500$. If the annual discount rate is 6%, calculate:\n", + "\n", + "1. The present value of the dividends.\n", + "2. The present value of the terminal price of the stock.\n", + "3. The total present value of the stock (which should be equal to its current price).\n", + "\n", + "*Hint: Use the same method as in the second exercise for the dividends, and the method from the first exercise for the terminal price.*" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_stock_value(dividend, terminal_price, r, years):\n", + " dividend = 100\n", + " terminal_price = 1500\n", + " r = 0.06\n", + " years = range(1, 4) # from 1 to 3 inclusive\n", + " PV_dividends = sum([dividend / (1 + r)**n for n in years])\n", + " PV_terminal = terminal_price / (1 + r)**3\n", + " PV_total = PV_dividends + PV_terminal\n", + " return round(PV_dividends, 2), round(PV_terminal, 2), round(PV_total, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " PV_dividends, PV_terminal, PV_total = calculate_stock_value(100, 1500, 0.06, range(1, 4))\n", + " assert abs(PV_dividends - 267.3) < 1e-2\n", + " assert abs(PV_terminal - 1259.43) < 1e-2\n", + " assert abs(PV_total - 1526.73) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 4.4: Matrix Multiplication in Asset Pricing\n", + "\n", + "Consider an asset that is expected to yield dividends of $100$ at the end of each year for the next five years, after which point it is predicted to be sold for $2000$. The annual discount rate is set to be 5%. Your task is to compute:\n", + "\n", + "1. The present value of the dividends using matrix multiplication.\n", + "2. The present value of the final price of the asset.\n", + "3. The total present value of the asset (which should be equal to its current price).\n", + "\n", + "*Hint: Use matrix multiplication to solve for the present value of dividends, and use the same method as in the previous exercise for the final price.*" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_asset_value(dividend, final_price, discount_rate, years):\n", + " dividend = np.array([100]*5)\n", + " final_price = 2000\n", + " discount_rate = 0.05\n", + " years = np.array(range(1, 6)) # from 1 to 5 inclusive\n", + " \n", + " # Create a discount factor matrix\n", + " discount_matrix = 1 / (1 + discount_rate) ** years\n", + "\n", + " # Calculate the present value of dividends using matrix multiplication\n", + " PV_dividends = np.dot(dividend, discount_matrix)\n", + "\n", + " # Calculate the present value of the final price\n", + " PV_final_price = final_price * (1 / (1 + discount_rate) ** years[-1])\n", + "\n", + " # Calculate the total present value\n", + " PV_total = PV_dividends + PV_final_price\n", + "\n", + " return round(PV_dividends, 2), round(PV_final_price, 2), round(PV_total, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " PV_dividends, PV_final_price, PV_total = calculate_asset_value(100, 2000, 0.05, range(1, 6))\n", + " assert abs(PV_dividends - 432.95) < 1e-2\n", + " assert abs(PV_final_price - 1567.05) < 1e-2\n", + " assert abs(PV_total - 2000.0) < 1e-2\n", + " print(\"Test passed!\")\n", + "except AssertionError:\n", + " print(\"Test failed.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred during testing: {e}\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise 5\n", + "\n", + "Read section [present value calculation](https://intro.quantecon.org/pv.html#present-value-calculations) before attempting exercises 6.1 and 6.1.\n", + "\n", + "Let $A, p, d, b$ be as defined in that section.\n", + "\n", + "So we have\n", + "\n", + "$$\n", + " A p = d + b\n", + "$$\n", + "\n", + "#### Exercise 5.1: Price of a worthless stock\n", + "\n", + "Compute and plot the corresponding asset price sequence when $T=6$, $p^*_{T+1} = 0$, $d_t=0$ and $\\delta\n", + "= 0.98$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "T = 6\n", + "p_star = 0.0\n", + "δ = 0.98" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d = np.zeros(T+1)\n", + "A = np.zeros((T+1, T+1))\n", + "for i in range(T+1):\n", + " for j in range(T+1):\n", + " if i == j:\n", + " A[i, j] = 1\n", + " if j < T:\n", + " A[i, j+1] = -δ\n", + "\n", + "b = np.zeros(T+1)\n", + "b[-1] = δ * p_star\n", + "p = np.linalg.solve(A, d + b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(p, 'o-', ms=4, alpha=0.8, label='asset price')\n", + "ax.legend()\n", + "ax.set_xlabel('time')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 5.2: Gorden growth formula\n", + "\n", + "Let $\\delta$ be the same as Exercise 5.1.\n", + "\n", + "Compute and plot the corresponding asset price sequence when $T=100$, $p^*_{T+1} = g^{T+1} d_0$ and $d_t=g^t d_0$\n", + "where $g=1.1$ and $d_0=0.1$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "T = 100\n", + "δ = 0.98\n", + "g = 1.1\n", + "current_d = 0.1 # d_0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p_star = g**(T+1) * current_d\n", + "\n", + "d = []\n", + "for t in range(T+1):\n", + " d.append(current_d)\n", + " current_d = current_d * 1.1**t " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.zeros((T+1, T+1))\n", + "for i in range(T+1):\n", + " for j in range(T+1):\n", + " if i == j:\n", + " A[i, j] = 1\n", + " if j < T:\n", + " A[i, j+1] = -δ\n", + "\n", + "b = np.zeros(T+1)\n", + "b[-1] = δ * p_star\n", + "p = np.linalg.solve(A, d + b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(p, 'o-', ms=4, alpha=0.8, label='asset price')\n", + "ax.legend()\n", + "ax.set_xlabel('time')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Exercise 5.3: Analytical expressions\n", + "\n", + "Read section [analytical expressions](https://intro.quantecon.org/pv.html#analytical-expressions).\n", + "\n", + "Give analytical expressions for the asset price $p_t$ in Exercise 5.2." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution\n", + "\n", + "$$\n", + " p_t = \\sum_{s=t}^T \\delta^{s-t} g^s d_0 + \\delta^{T+1-t} g^{T+1} d_0\n", + "$$\n" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-06/exercise_set_6.ipynb b/exercises/day-06/exercise_set_6.ipynb new file mode 100644 index 0000000..fb94001 --- /dev/null +++ b/exercises/day-06/exercise_set_6.ipynb @@ -0,0 +1,351 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Eigenvalues and Eigenvectors, Matplotlib, and Univariate Time Series" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Humphrey Yang](https://github.com/HumphreyYang)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import eig\n", + "from matplotlib import cm" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 1.1*** Given a matrix $A$, compute the eigenvalues, eigenvectors and plot them." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array([[1, 4],\n", + " [5, 7]])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 1.2*** Given a matrix $A$, compute the eigenvalues, eigenvectors of the inverse of $A$ ($A^{-1}$). Compare it to the eigenvalue of $A$.\n", + "\n", + "(Hint: Try to compute 1/eigenvalue of $A$ and compare it to the eigenvalue of $A^{-1}$)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 1.3*** Try to come up with a simple proof of the relationship between the eigenvalues of $A$ and $A^{-1}$ you found in Exercise 1.2 (Think about what conditions are needed for the proof to hold)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2\n", + "\n", + "Compute the spectral radius of the matrix A." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3\n", + "\n", + "Without using the `eig` function, compute eigenvalues and its corresponding eigenvectors of the matrix $A$ in Question 3.1.\n", + "\n", + "(Hint: you can use [power iteration method](https://en.wikipedia.org/wiki/Power_iteration) to solve this problem.)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this simple matrix, the result is very accurate." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4\n", + "\n", + "[Wassily Leontief](https://en.wikipedia.org/wiki/Wassily_Leontief) developed a model of an economy with $n$ sectors producing $n$ different commodities representing the interdependencies of different sectors of an economy.\n", + "\n", + "Under this model some of the output is consumed internally by the industries and the rest is consumed by external consumers.\n", + "\n", + "We define a simple model with 3 sectors - agriculture, industry, and service.\n", + "\n", + "The following table describes how output is distributed within the economy:\n", + "\n", + "| | Total output | Agriculture | Industry | Service | Consumer |\n", + "|:-----------:|:------------:|:-----------:|:--------:|:-------:|:--------:|\n", + "| Agriculture | $x_1$ | 0.3 $x_1$ | 0.2 $x_2$ |0.3 $x_3$ | 4 |\n", + "| Industry | $x_2$ | 0.2 $x_1$ | 0.4 $x_2$ |0.3 $x_3$ | 5 |\n", + "| Service | $x_3$ | 0.2 $x_1$ | 0.5 $x_2$ |0.1 $x_3$ | 12 |\n", + "\n", + "The first row depicts how agriculture's total output $x_1$ is distributed\n", + "\n", + "* $0.3x_1$ is used as inputs within agriculture itself,\n", + "* $0.2x_2$ is used as inputs by the industry sector to produce $x_2$ units,\n", + "* $0.3x_3$ is used as inputs by the service sector to produce $x_3$ units and\n", + "* 4 units is the external demand by consumers.\n", + "\n", + "We can transform this into a system of linear equations for the 3 sectors as\n", + "given below:\n", + "\n", + "$$\n", + " x_1 = 0.3x_1 + 0.2x_2 + 0.3x_3 + 4 \\\\\n", + " x_2 = 0.2x_1 + 0.4x_2 + 0.3x_3 + 5 \\\\\n", + " x_3 = 0.2x_1 + 0.5x_2 + 0.1x_3 + 12\n", + "$$\n", + "\n", + "This can be transformed into the matrix equation $x = Ax + d$ where\n", + "\n", + "$$\n", + "x =\n", + "\\begin{bmatrix}\n", + " x_1 \\\\\n", + " x_2 \\\\\n", + " x_3\n", + "\\end{bmatrix}\n", + ", \\; A =\n", + "\\begin{bmatrix}\n", + " 0.3 & 0.2 & 0.3 \\\\\n", + " 0.2 & 0.4 & 0.3 \\\\\n", + " 0.2 & 0.5 & 0.1\n", + "\\end{bmatrix}\n", + "\\; \\text{and} \\;\n", + "d =\n", + "\\begin{bmatrix}\n", + " 4 \\\\\n", + " 5 \\\\\n", + " 12\n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "The solution $x^{*}$ is given by the equation $x^{*} = (I-A)^{-1} d$\n", + "\n", + "***Exercise 4.1*** Find the spectral radius of $A$ and verify if the spectral radius is less than 1." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 4.2*** Use the Neumann Series Lemma to find the solution $x^{*}$ if it exists." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 5\n", + "\n", + "Represent and solve a third order linear difference equation as shown in the [consumption smoothing lecture](https://intro.quantecon.org/cons_smooth.html). How many initial conditions must you specify?" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 6\n", + "\n", + "Using the following parameters, compute the $y$ for process:\n", + "\n", + "$$\n", + "y_{t} = \\alpha_{0} + \\alpha_{1} y_{t-1} + \\alpha_{2} y_{t-2} + \\alpha_{3} y_{t-3} \\quad where \\quad t = 1, 2 \\ldots\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the following parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "T = 100\n", + "\n", + "# parameters\n", + "𝛼0 = 10.0\n", + "𝛼1 = 1.53\n", + "𝛼2 = -.9\n", + "𝛼3 = -.04\n", + "\n", + "y_2 = 32. # y_{-2}\n", + "y_1 = 28. # y_{-1}\n", + "y0 = 24." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try to visualize the process as shown in the [lecture](https://intro.quantecon.org/time_series_with_matrices.html) (Hint: you can use some insights from Exercise 5)." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your solution here" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-06/exercise_set_6_with_solution.ipynb b/exercises/day-06/exercise_set_6_with_solution.ipynb new file mode 100644 index 0000000..89580b7 --- /dev/null +++ b/exercises/day-06/exercise_set_6_with_solution.ipynb @@ -0,0 +1,636 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Eigenvalues and Eigenvectors, Matplotlib, and Univariate Time Series" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Humphrey Yang](https://github.com/HumphreyYang)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import eig\n", + "from matplotlib import cm" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 1.1*** Given a matrix $A$, compute the eigenvalues, eigenvectors and plot them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array([[1, 4],\n", + " [5, 7]])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array(A)\n", + "evals, evecs = eig(A)\n", + "evals = evals.real\n", + "evecs = evecs[:, 0], evecs[:, 1]\n", + "\n", + "print(\"Eigenvalues:\", evals)\n", + "print(\"Eigenvectors:\", evecs)\n", + "\n", + "fig, ax = plt.subplots(figsize=(7, 5))\n", + "\n", + "# Set the axes through the origin\n", + "for spine in ['left', 'bottom']:\n", + " ax.spines[spine].set_position('zero')\n", + "for spine in ['right', 'top']:\n", + " ax.spines[spine].set_color('none')\n", + "\n", + "ax.grid(alpha=0.4)\n", + "\n", + "xmin, xmax = -3, 3\n", + "ymin, ymax = -3, 3\n", + "ax.set(xlim=(xmin, xmax), ylim=(ymin, ymax))\n", + "\n", + "# Plot each eigenvector\n", + "for v in evecs:\n", + " ax.annotate('', xy=v, xytext=(0, 0),\n", + " arrowprops=dict(facecolor='blue',\n", + " shrink=0,\n", + " alpha=0.6,\n", + " width=0.5))\n", + "\n", + "# Plot the image of each eigenvector\n", + "for v in evecs:\n", + " z = A @ v\n", + " ax.annotate('', xy=z, xytext=(0, 0),\n", + " arrowprops=dict(facecolor='red',\n", + " shrink=0,\n", + " alpha=0.6,\n", + " width=0.5))\n", + "\n", + "# Plot the lines they run through\n", + "x = np.linspace(xmin, xmax, 3)\n", + "for v in evecs:\n", + " a = v[1] / v[0]\n", + " ax.plot(x, a * x, 'b-', lw=0.4)\n", + "\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 1.2*** Given a matrix $A$, compute the eigenvalues, eigenvectors of the inverse of $A$ ($A^{-1}$). Compare it to the eigenvalue of $A$.\n", + "\n", + "(Hint: Try to compute 1/eigenvalue of $A$ and compare it to the eigenvalue of $A^{-1}$)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "eig(np.linalg.inv(A))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "eig(A)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.allclose(1/eig(A)[0], eig(np.linalg.inv(A))[0])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 1.3*** Try to come up with a simple proof of the relationship between the eigenvalues of $A$ and $A^{-1}$ you found in Exercise 1.2 (Think about what conditions are needed for the proof to hold)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We start with the definition of eigenvalues:\n", + "$$ \n", + "A v = \\lambda\\ v\n", + "$$\n", + "\n", + "Then we multiply both sides by $A^{-1}$:\n", + "\n", + "$$\n", + "A^{-1}A v = \\lambda A^{-1} v\n", + "$$ \n", + "\n", + "Since $A^{-1}A = I$, we have:\n", + "\n", + "$$\n", + "\\frac{1}{\\lambda} v = A^{-1} v\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2\n", + "\n", + "Compute the spectral radius of the matrix A." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array([[1, 4],\n", + " [5, 7]])\n", + "\n", + "evals, evecs = eig(A) # find eigenvalues and eigenvectors\n", + "\n", + "r = max(abs(evals)) # compute spectral radius\n", + "print(r)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3\n", + "\n", + "Without using the `eig` function, compute the dominant eigenvalue and its corresponding eigenvector of the matrix $A$ in Question 3.1.\n", + "\n", + "(Hint: you can use [power iteration method](https://en.wikipedia.org/wiki/Power_iteration) to solve this problem.)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def power_iteration(A, num_iterations=1000):\n", + " n = A.shape[0]\n", + " b_k = np.ones(n)\n", + " for _ in range(num_iterations):\n", + " b_k1 = A @ b_k\n", + " b_k1_norm = np.linalg.norm(b_k1)\n", + " b_k = b_k1 / b_k1_norm\n", + " eigenvalue = b_k @ A @ b_k # Rayleigh quotient\n", + " return eigenvalue, b_k" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array([[1, 4],\n", + " [5, 7]])\n", + "\n", + "eigenvalue, eigenvector = power_iteration(A)\n", + "print(\"Dominant Eigenvalue: \\n\", eigenvalue)\n", + "print(\"Corresponding Eigenvector: \\n\", np.abs(eigenvector))\n", + "\n", + "# Compare your result to the output of `np.linalg.eig`:\n", + "A = np.array(A)\n", + "evals, evecs = eig(A)\n", + "evals = evals.real\n", + "evecs = evecs[:, 0], evecs[:, 1]\n", + "\n", + "print(\"\\nEigenvalues (numpy): \\n\", evals)\n", + "print(\"Eigenvectors (numpy): \\n\", np.abs(evecs))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this simple matrix, the result is very accurate." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4\n", + "\n", + "[Wassily Leontief](https://en.wikipedia.org/wiki/Wassily_Leontief) developed a model of an economy with $n$ sectors producing $n$ different commodities representing the interdependencies of different sectors of an economy.\n", + "\n", + "Under this model some of the output is consumed internally by the industries and the rest is consumed by external consumers.\n", + "\n", + "We define a simple model with 3 sectors - agriculture, industry, and service.\n", + "\n", + "The following table describes how output is distributed within the economy:\n", + "\n", + "| | Total output | Agriculture | Industry | Service | Consumer |\n", + "|:-----------:|:------------:|:-----------:|:--------:|:-------:|:--------:|\n", + "| Agriculture | $x_1$ | 0.3 $x_1$ | 0.2 $x_2$ |0.3 $x_3$ | 4 |\n", + "| Industry | $x_2$ | 0.2 $x_1$ | 0.4 $x_2$ |0.3 $x_3$ | 5 |\n", + "| Service | $x_3$ | 0.2 $x_1$ | 0.5 $x_2$ |0.1 $x_3$ | 12 |\n", + "\n", + "The first row depicts how agriculture's total output $x_1$ is distributed\n", + "\n", + "* $0.3x_1$ is used as inputs within agriculture itself,\n", + "* $0.2x_2$ is used as inputs by the industry sector to produce $x_2$ units,\n", + "* $0.3x_3$ is used as inputs by the service sector to produce $x_3$ units and\n", + "* 4 units is the external demand by consumers.\n", + "\n", + "We can transform this into a system of linear equations for the 3 sectors as\n", + "given below:\n", + "\n", + "$$\n", + " x_1 = 0.3x_1 + 0.2x_2 + 0.3x_3 + 4 \\\\\n", + " x_2 = 0.2x_1 + 0.4x_2 + 0.3x_3 + 5 \\\\\n", + " x_3 = 0.2x_1 + 0.5x_2 + 0.1x_3 + 12\n", + "$$\n", + "\n", + "This can be transformed into the matrix equation $x = Ax + d$ where\n", + "\n", + "$$\n", + "x =\n", + "\\begin{bmatrix}\n", + " x_1 \\\\\n", + " x_2 \\\\\n", + " x_3\n", + "\\end{bmatrix}\n", + ", \\; A =\n", + "\\begin{bmatrix}\n", + " 0.3 & 0.2 & 0.3 \\\\\n", + " 0.2 & 0.4 & 0.3 \\\\\n", + " 0.2 & 0.5 & 0.1\n", + "\\end{bmatrix}\n", + "\\; \\text{and} \\;\n", + "d =\n", + "\\begin{bmatrix}\n", + " 4 \\\\\n", + " 5 \\\\\n", + " 12\n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "The solution $x^{*}$ is given by the equation $x^{*} = (I-A)^{-1} d$\n", + "\n", + "***Exercise 4.1*** Find the spectral radius of $A$ and verify if the spectral radius is less than 1." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array([[0.3, 0.2, 0.3],\n", + " [0.2, 0.4, 0.3],\n", + " [0.2, 0.5, 0.1]])\n", + "\n", + "evals, evecs = eig(A)\n", + "\n", + "r = max(abs(evals)) # dominant eigenvalue/spectral radius\n", + "print(r)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Exercise 4.2*** Use the Neumann Series Lemma to find the solution $x^{*}$ if it exists." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "I = np.identity(3)\n", + "B = I - A\n", + "\n", + "d = np.array([4, 5, 12])\n", + "d.shape = (3, 1)\n", + "\n", + "B_inv = np.linalg.inv(B)\n", + "x_star = B_inv @ d\n", + "print(x_star)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 5\n", + "\n", + "As an exercise, we ask you to represent and solve a third order linear difference equation. How many initial conditions must you specify?" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "$$\n", + "\\begin{bmatrix} \n", + "1 & 0 & 0 & 0 &\\cdots & 0 & 0 & 0 \\cr\n", + "-\\lambda_1 & 1 & 0 & 0 &\\cdots & 0 & 0 & 0 \\cr\n", + "-\\lambda_2 & -\\lambda_1 & 1 & 0 & \\cdots & 0 & 0 & 0 \\cr\n", + "-\\lambda_3 & -\\lambda_2 & -\\lambda_1 & 1 & \\cdots & 0 & 0 & 0 \\cr\n", + " \\vdots & \\vdots & \\vdots & \\vdots & \\cdots & \\vdots & \\vdots & \\vdots \\cr\n", + "0 & 0 & 0 & 0 & \\cdots & -\\lambda_2 & -\\lambda_1 & 1 \n", + "\\end{bmatrix} \n", + "\\begin{bmatrix} \n", + "y_1 \\cr y_2 \\cr y_3 \\cr y_4 \\cr \\vdots \\cr y_T \n", + "\\end{bmatrix}\n", + "= \n", + "\\begin{bmatrix} \n", + "\\lambda_1 y_0 + \\lambda_2 y_{-1} + \\lambda_3 y_{-2} \\cr \\lambda_2 y_0 + \\lambda_3 y_{-1} \\cr \\lambda_3 y_0 \\cr 0 \\cr \\vdots \\cr 0 \n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "where $y_{0}$, $y_{-1}$, and $y_{-2}$ are initial conditions." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 6\n", + "\n", + "Using the following parameters, compute the $y$ for process:\n", + "\n", + "$$\n", + "y_{t} = \\alpha_{0} + \\alpha_{1} y_{t-1} + \\alpha_{2} y_{t-2} + \\alpha_{3} y_{t-3} \\quad where \\quad t = 1, 2 \\ldots\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the following parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "T = 100\n", + "\n", + "# parameters\n", + "𝛼0 = 10.0\n", + "𝛼1 = 1.53\n", + "𝛼2 = -.9\n", + "𝛼3 = -.04\n", + "\n", + "y_2 = 32. # y_{-2}\n", + "y_1 = 28. # y_{-1}\n", + "y0 = 24." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try to visualize the process as shown in the [lecture](https://intro.quantecon.org/time_series_with_matrices.html) (Hint: you can use some insights from Exercise 5)." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.identity(T) # The T x T identity matrix\n", + "\n", + "for i in range(T):\n", + "\n", + " if i-1 >= 0:\n", + " A[i, i-1] = -𝛼1\n", + "\n", + " if i-2 >= 0:\n", + " A[i, i-2] = -𝛼2\n", + "\n", + " if i-3 >= 0:\n", + " A[i, i-3] = -𝛼3\n", + "\n", + "b = np.full(T, 𝛼0)\n", + "b[0] = 𝛼0 + 𝛼1 * y0 + 𝛼2 * y_1 + 𝛼3 * y_2\n", + "b[1] = 𝛼0 + 𝛼1 * y0 + 𝛼2 * y_1\n", + "b[2] = 𝛼0 + 𝛼2 * y0\n", + "\n", + "print(A)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A_inv = np.linalg.inv(A)\n", + "\n", + "y = A_inv @ b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(np.arange(T)+1, y)\n", + "plt.xlabel('t')\n", + "plt.ylabel('y')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "N = 100\n", + "𝜎u = 2.\n", + "fig, ax = plt.subplots()\n", + "\n", + "for i in range(N):\n", + " col = cm.viridis(np.random.rand()) # Choose a random color from viridis\n", + " u = np.random.normal(0, 𝜎u, size=T)\n", + " y = A_inv @ (b + u)\n", + " ax.plot(np.arange(T)+1, y, lw=0.5, color=col)\n", + "\n", + "plt.xlabel('t')\n", + "plt.ylabel('y')\n", + "\n", + "plt.show()" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-07/exercise_set_7.ipynb b/exercises/day-07/exercise_set_7.ipynb new file mode 100644 index 0000000..40c8748 --- /dev/null +++ b/exercises/day-07/exercise_set_7.ipynb @@ -0,0 +1,452 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Object Oriented Programming, Numba, and Equalizing Differences Model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Humphrey Yang](https://github.com/HumphreyYang) and [Smit Lunagariya](https://github.com/Smit-create)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import numba as nb\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from scipy.optimize import newton" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1\n", + "\n", + "We start with some exercises on objects and names in Python.\n", + "\n", + "\n", + "### ***Exercise 1.1***\n", + "\n", + "Print the type of the following objects:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 0.5\n", + "b = 5\n", + "c = 'a'\n", + "d = ...\n", + "e = 1.0 + 1.0j\n", + "f = lambda x: x + 1\n", + "g = np.array([1, 2, 3])\n", + "h = list\n", + "j = _\n", + "\n", + "var_list = [a, b, c, d, e, f, g, h, j]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 1.2***\n", + "\n", + "What are unique identifiers of the following objects?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = b = 1\n", + "# TODO: Check the unique identifiers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c = [a, b, 2]\n", + "# TODO: Check the unique identifiers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "j = c\n", + "# TODO: Check the unique identifiers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "j[0] = 2\n", + "# TODO: Check the unique identifiers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### *Exercise 1.3*\n", + "\n", + "Check the documentation of the `dir()` function using `?dir` and print the namespace of string `'a'` and." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2\n", + "\n", + "\n", + "Let's start with an easy class. Define a class called `Person` with the following attributes:\n", + "\n", + "- `name`: a string\n", + "- `age`: an integer\n", + "\n", + "and the following methods:\n", + "\n", + "- `greet(self)`: prints out a greeting that includes the person's name and age\n", + "- `respond(self, person)`: prints out a response to a greeting from another `Person` instance that introduces `self.name`.\n", + "\n", + "Create two instances of `Person` with different names and ages and have one `respond` to the other's `greet`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3\n", + "\n", + "#### The Market" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We consider a market for coffee beans. The price per kilo is $p$. Total supply at price $p$ is\n", + "\n", + "$$ q_s (p) = b \\sqrt{p} $$\n", + "\n", + "and total demand is \n", + "\n", + "$$ q_d (p) = a \\frac{1}{p}, $$\n", + "\n", + "where $a$ and $b$ are positive parameters." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's write routines to compute supply and demand as functions of price and parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def supply(p, b):\n", + " return b * np.sqrt(p)\n", + "\n", + "def demand(p, a):\n", + " return a * (1/p)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 3.1***\n", + "\n", + "Plot both supply and demand as functions of $p$ when $a=1$ and $b=0.5$. Plot for prices in the interval from $0.2$ up to $4$. Although it is unusual, put price on the horizonal axis. Use a legend to label the two functions and be sure to label the axes. Looking at the picture, make a rough estimate of the equilibrium price,\n", + "where demand equals supply." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 3.2***\n", + "\n", + "Write a function that takes arguments $a, b, p$ and returns *excess demand*, which is defined as\n", + "\n", + "$$ e(p) = q_d(p) - q_s(p) $$\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 3.3***\n", + "\n", + "Write a class definition that creates a class called `Market` with four methods:\n", + "\n", + "1. An `__init__` method that specifies default parameter values $a=1$ and $b=0.5$.\n", + "2. A `demand` method that returns $q_d(p)$ given $p$\n", + "3. A `supply` method that returns $q_s(p)$ given $p$\n", + "4. An `excess_demand` method that returns $q_d(p) - q_s(p)$ given $p$. \n", + "\n", + "Using an instance of the class, plot excess demand over the interval from $0.2$ up to $4$. Also plot a horizontal line at zero. The equilibrium price is where excess demand crosses zero. Compute the equilibrium price." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4\n", + "\n", + "[Martingales](https://en.wikipedia.org/wiki/Martingale_%28probability_theory%29) are a class of discrete-time stochastic processes that originates from a class of betting strategy that doubles the bet after every loss with the hope that the first win would recover all previous losses plus win a profit equal to the original stake (Read this [lecture](https://python.quantecon.org/perm_income.html#preliminaries) for more information about how martingales relate to the permanent income model).\n", + "\n", + "In this exercise, Let's simulate the betting strategy and see if it really works out. \n", + "\n", + "### ***Exercise 4.1***\n", + "\n", + "Write a simulator called `MartingaleSimulator` to simulate a person who doubles the bet when losses and halfs the bet when wins. The process stops once the person cannot afford the next bet.\n", + "\n", + "Use the skeloton code below to define the class `MartingaleSimulator`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class MartingaleSimulator:\n", + " def __init__(self, initial_balance, bet_amount, prob=0.5):\n", + " # Complete the code\n", + " pass\n", + "\n", + " def play_round(self):\n", + " # Complete the code\n", + " pass\n", + "\n", + " def _play_game(self, prob=0.5):\n", + " # Complete the code\n", + " pass\n", + "\n", + " def simulate(self, num_rounds):\n", + " for _ in range(num_rounds):\n", + " try:\n", + " self.play_round()\n", + " except AssertionError:\n", + " break \n", + " if self.balance <= self.initial_balance:\n", + " return False\n", + " else:\n", + " return True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.2***\n", + "\n", + "Calculate the total wins, losses and the final balance of the person after 200 rounds with an initial wealth and bet amount of 1000 and 100." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.3***\n", + "\n", + "Run a simulation of 50 rounds with initial wealth of 100 and initial bet size of 1. Plot the wealth over time for 20 simulations if you can." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.4***\n", + "\n", + "Run a simulation of 50 rounds with initial wealth of 100 and inital bet size of 1. \n", + "\n", + "- Calculate the proportion of simulations that end up with a wealth below initial wealth.\n", + "\n", + "- Visualize the distribution of the final wealth if you can." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.5***\n", + "\n", + "Use the same setup as Exercise 4.4, but set up an unfair game with the probability of winning 0.4." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 5\n", + "\n", + "Repeat the same [Exercise 3.3](#Exercise-3.3) using Numba's `jitclass`, and the class name as `MarketNB`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write your solution here" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-07/exercise_set_7_with_solution.ipynb b/exercises/day-07/exercise_set_7_with_solution.ipynb new file mode 100644 index 0000000..900a64f --- /dev/null +++ b/exercises/day-07/exercise_set_7_with_solution.ipynb @@ -0,0 +1,762 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Object Oriented Programming, Numba, and Equalizing Differences Model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Humphrey Yang](https://github.com/HumphreyYang) and [Smit Lunagariya](https://github.com/Smit-create)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import numba as nb\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from scipy.optimize import newton" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1\n", + "\n", + "We start with some exercises on objects and names in Python.\n", + "\n", + "\n", + "### ***Exercise 1.1***\n", + "\n", + "Print the type of the following objects:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 0.5\n", + "b = 5\n", + "c = 'a'\n", + "d = ...\n", + "e = 1.0 + 1.0j\n", + "f = lambda x: x + 1\n", + "g = np.array([1, 2, 3])\n", + "h = list\n", + "j = _\n", + "\n", + "var_list = [a, b, c, d, e, f, g, h, j]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for i in var_list:\n", + " print(type(i))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 1.2***\n", + "\n", + "What are unique identifiers of the following objects?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = b = 1\n", + "id(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c = [a, b, 2]\n", + "\n", + "id(c[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "j = c\n", + "id(j[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "j[0] = 2\n", + "id(j[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### *Exercise 1.3*\n", + "\n", + "Check the documentation of the `dir()` function using `?dir` and print the namespace of string `'a'` and." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "?dir" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dir('a')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2\n", + "\n", + "\n", + "Let's start with an easy class. Define a class called `Person` with the following attributes:\n", + "\n", + "- `name`: a string\n", + "- `age`: an integer\n", + "\n", + "and the following methods:\n", + "\n", + "- `greet(self)`: prints out a greeting that includes the person's name and age\n", + "- `respond(self, person)`: prints out a response to a greeting from another `Person` instance that introduces `self.name`.\n", + "\n", + "Create two instances of `Person` with different names and ages and have one `respond` to the other's `greet`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Person:\n", + " def __init__(self, name, age):\n", + " self.name = name\n", + " self.age = age\n", + " \n", + " def greet(self):\n", + " print(f\"Hello, my name is {self.name}, and I am {self.age} years old.\")\n", + " \n", + " def respond(self, person):\n", + " print(f\"Hello, {person.name}! My name is {self.name}.\")\n", + "\n", + "a = Person('Alice', 25)\n", + "b = Person('Bob', 20)\n", + "\n", + "a.greet()\n", + "b.respond(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3\n", + "\n", + "#### The Market" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We consider a market for coffee beans. The price per kilo is $p$. Total supply at price $p$ is\n", + "\n", + "$$ q_s (p) = b \\sqrt{p} $$\n", + "\n", + "and total demand is \n", + "\n", + "$$ q_d (p) = a \\frac{1}{p}, $$\n", + "\n", + "where $a$ and $b$ are positive parameters." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's write routines to compute supply and demand as functions of price and parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def supply(p, b):\n", + " return b * np.sqrt(p)\n", + "\n", + "def demand(p, a):\n", + " return a * (1/p)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 3.1***\n", + "\n", + "Plot both supply and demand as functions of $p$ when $a=1$ and $b=0.5$. Plot for prices in the interval from $0.2$ up to $4$. Although it is unusual, put price on the horizonal axis. Use a legend to label the two functions and be sure to label the axes. Looking at the picture, make a rough estimate of the equilibrium price,\n", + "where demand equals supply." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "p_grid = np.linspace(0.2, 4, 200)\n", + "ax.plot(p_grid, supply(p_grid, 0.5), label='supply')\n", + "ax.plot(p_grid, demand(p_grid, 1.0), label='demand')\n", + "ax.set_xlabel(\"price\")\n", + "ax.set_ylabel(\"quantity\")\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The equilibrium price looks to be about 1.6." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 3.2***\n", + "\n", + "Write a function that takes arguments $a, b, p$ and returns *excess demand*, which is defined as\n", + "\n", + "$$ e(p) = q_d(p) - q_s(p) $$\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def excess_demand(p, a, b):\n", + " return demand(p, a) - supply(p, b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 3.3***\n", + "\n", + "Write a class definition that creates a class called `Market` with four methods:\n", + "\n", + "1. An `__init__` method that specifies default parameter values $a=1$ and $b=0.5$.\n", + "2. A `demand` method that returns $q_d(p)$ given $p$\n", + "3. A `supply` method that returns $q_s(p)$ given $p$\n", + "4. An `excess_demand` method that returns $q_d(p) - q_s(p)$ given $p$. \n", + "\n", + "Using an instance of the class, plot excess demand over the interval from $0.2$ up to $4$. Also plot a horizontal line at zero. The equilibrium price is where excess demand crosses zero. Compute the equilibrium price." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Market:\n", + "\n", + " def __init__(self, a=1.0, b=0.5):\n", + " self.a, self.b = a, b\n", + "\n", + " def supply(self, p):\n", + " return self.b * np.sqrt(p)\n", + "\n", + " def demand(self, p):\n", + " return self.a * (1/p)\n", + "\n", + " def excess_demand(self, p):\n", + " return self.demand(p) - self.supply(p)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "market = Market()\n", + "\n", + "fig, ax = plt.subplots()\n", + "p_grid = np.linspace(0.2, 4, 200)\n", + "ax.plot(p_grid, market.excess_demand(p_grid), label='excess demand')\n", + "ax.plot(p_grid, np.zeros_like(p_grid), 'k--')\n", + "ax.set_xlabel(\"price\")\n", + "ax.set_ylabel(\"quantity\")\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we'll write a function that takes an instance of the `Market` class (i.e., an object `market` constructed via `market = Market()`) and returns a market clearing price via Newton's method. If necessary, adjust your code above so that this routine works." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_equilibrium(market, price_init=2.0):\n", + " p_star = newton(market.excess_demand, price_init)\n", + " return p_star" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "market = Market()\n", + "compute_equilibrium(market)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 4\n", + "\n", + "[Martingales](https://en.wikipedia.org/wiki/Martingale_%28probability_theory%29) are a class of discrete-time stochastic processes that originates from a class of betting strategy that doubles the bet after every loss with the hope that the first win would recover all previous losses plus win a profit equal to the original stake (Read this [lecture](https://python.quantecon.org/perm_income.html#preliminaries) for more information about how martingales relate to the permanent income model).\n", + "\n", + "In this exercise, Let's simulate the betting strategy and see if it really works out. \n", + "\n", + "### ***Exercise 4.1***\n", + "\n", + "Write a simulator called `MartingaleSimulator` to simulate a person who doubles the bet when losses and halfs the bet when wins. The process stops once the person cannot afford the next bet.\n", + "\n", + "Use the skeloton code below to define the class `MartingaleSimulator`:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class MartingaleSimulator:\n", + " def __init__(self, initial_balance, bet_amount, prob=0.5):\n", + " self.initial_balance = initial_balance\n", + " self.bet_amount = bet_amount\n", + " self.balance = initial_balance\n", + " self.rounds_played = 0\n", + " self.total_wins = 0\n", + " self.total_losses = 0\n", + " self.balance_history = [initial_balance]\n", + " self.bet_history = [bet_amount]\n", + " self.prob = prob\n", + "\n", + " def play_round(self):\n", + " self.rounds_played += 1\n", + " assert self.balance > self.bet_amount\n", + "\n", + " if self._play_game(prob=self.prob):\n", + " self.total_wins += 1\n", + " self.balance += self.bet_amount\n", + " self.bet_amount /= 2 # Half the bet amount after a win\n", + " self.bet_amount = int(self.bet_amount)\n", + " else:\n", + " self.total_losses += 1\n", + " self.balance -= self.bet_amount\n", + " self.bet_amount *= 2 # Double the bet amount after a loss\n", + "\n", + " self.balance_history.append(self.balance)\n", + " self.bet_history.append(self.bet_amount)\n", + "\n", + " def _play_game(self, prob=0.5):\n", + " return np.random.choice([True, False], p=[prob, 1-prob])\n", + "\n", + " def simulate(self, num_rounds):\n", + " for _ in range(num_rounds):\n", + " try:\n", + " self.play_round()\n", + " except AssertionError:\n", + " break\n", + " if self.balance <= self.initial_balance:\n", + " return False\n", + " else:\n", + " return True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.2***\n", + "\n", + "Calculate the total wins, losses and the final balance of the person after 200 rounds with an initial wealth and bet amount of 1000 and 100." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "simulator = MartingaleSimulator(initial_balance=1000, bet_amount=100)\n", + "simulator.simulate(num_rounds=200)\n", + "\n", + "print(f\"Total wins: {simulator.total_wins}\")\n", + "print(f\"Total losses: {simulator.total_losses}\")\n", + "print(f\"Final balance: {simulator.balance}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.3***\n", + "\n", + "Run a simulation of 50 rounds with initial wealth of 100 and initial bet size of 1. Plot the wealth over time for 20 simulations if you can." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(2, 1, figsize=(6, 8), dpi=300)\n", + "\n", + "balances = []\n", + "for i in range(20):\n", + " simulator = MartingaleSimulator(initial_balance=50, bet_amount=10)\n", + " simulator.simulate(num_rounds=50)\n", + " axes[0].plot(simulator.balance_history, alpha=0.3)\n", + " axes[1].plot(simulator.bet_history, alpha=0.3)\n", + "\n", + "axes[1].set_xlabel(\"Round\")\n", + "axes[0].set_ylabel(\"Balance\")\n", + "axes[1].set_ylabel(\"Bet\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.4***\n", + "\n", + "Run a simulation of 50 rounds with initial wealth of 100 and inital bet size of 1. \n", + "\n", + "- Calculate the proportion of simulations that end up with a wealth below initial wealth.\n", + "\n", + "- Visualize the distribution of the final wealth if you can." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "outcome = []\n", + "balances = []\n", + "for i in range(1000):\n", + " simulator = MartingaleSimulator(initial_balance=30, bet_amount=10)\n", + " outcome.append(simulator.simulate(num_rounds=100))\n", + " balances.append(simulator.balance)\n", + "\n", + "plt.hist(balances, bins=20)\n", + "plt.show()\n", + "\n", + "print(f\"Probability of winning: {np.mean(outcome)}\")\n", + "print(f\"Median balance: {np.median(balances)}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We find that most people end up with a wealth below the initial wealth (Takeaway: Do Not Gamble)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ***Exercise 4.5***\n", + "\n", + "Use the same setup as Exercise 4.4, but set up an unfair game with the probability of winning 0.4." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "outcome = []\n", + "balances = []\n", + "for i in range(1000):\n", + " simulator = MartingaleSimulator(initial_balance=30, bet_amount=10, prob=0.4)\n", + " outcome.append(simulator.simulate(num_rounds=100))\n", + " balances.append(simulator.balance)\n", + "\n", + "plt.hist(balances, bins=20)\n", + "plt.show()\n", + "\n", + "print(f\"Probability of winning: {np.mean(outcome)}\")\n", + "print(f\"Median balance: {np.median(balances)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We find that the probability of winning is even lower." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 5\n", + "\n", + "Repeat the same [Exercise 3.3](#Exercise-3.3) using Numba's `jitclass`, and the class name as `MarketNB`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "spec = [\n", + " ('a', nb.float64),\n", + " ('b', nb.float64),\n", + "]\n", + "\n", + "@nb.experimental.jitclass(spec)\n", + "class MarketNB:\n", + " \n", + " def __init__(self, a=1.0, b=0.5):\n", + " self.a, self.b = a, b\n", + " \n", + " def supply(self, p):\n", + " return self.b * np.sqrt(p)\n", + " \n", + " def demand(self, p):\n", + " return self.a * (1/p)\n", + " \n", + " def excess_demand(self, p):\n", + " return self.demand(p) - self.supply(p)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "market = MarketNB()\n", + "\n", + "fig, ax = plt.subplots()\n", + "p_grid = np.linspace(0.2, 4, 200)\n", + "ax.plot(p_grid, market.excess_demand(p_grid), label='excess demand')\n", + "ax.plot(p_grid, np.zeros_like(p_grid), 'k--')\n", + "ax.set_xlabel(\"price\")\n", + "ax.set_ylabel(\"quantity\")\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "market = MarketNB()\n", + "compute_equilibrium(market)" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/exercises/day-08/exercise_set_08.ipynb b/exercises/day-08/exercise_set_08.ipynb new file mode 100644 index 0000000..f19b461 --- /dev/null +++ b/exercises/day-08/exercise_set_08.ipynb @@ -0,0 +1,412 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c3db049e-27e8-475f-9a9c-a1190ba7d664", + "metadata": {}, + "source": [ + "# Commodity prices and Markov chains\n", + "\n", + "\n", + "\n", + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Shu Hu](https://shu-hu.com/)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c0e9460-6285-4f41-a58a-80d71649048d", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install quantecon" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c41a1de-64b9-445d-84fa-a8f43ba43554", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import quantecon as qe\n", + "import matplotlib.pyplot as plt\n", + "from scipy.interpolate import interp1d\n", + "from scipy.optimize import minimize_scalar, brentq\n", + "from scipy.stats import norm, pareto, beta" + ] + }, + { + "cell_type": "markdown", + "id": "9ec10adf-947e-4612-b8c7-9868770ee969", + "metadata": {}, + "source": [ + "### Exercise 1 (Commodity prices)\n", + "\n", + "Read the lecture [Commodity Prices](https://intro.quantecon.org/commod_price.html) before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "85894bbf-eb54-4c5e-a0f6-b853a7231b6d", + "metadata": {}, + "source": [ + "**Exercise 1.1**\n", + "\n", + "Keep all the other code the same as section [Code](https://intro.quantecon.org/commod_price.html#code), \n", + "\n", + "except that the shock $Z$ is set to\n", + "$$\n", + " Z = a + c \\cdot \\xi\n", + "$$\n", + "where $\\xi \\sim N (0, 1)$.\n", + "\n", + "In this exercise:\n", + "\n", + "- Compute the the approximation of $p^*$ and \n", + "- plot the approximation along with the inverse demand curve $P$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37a57410-dafc-4d38-8abd-c6f91e3c124f", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "bde053a6-db2b-40e9-8851-104ee4d2067d", + "metadata": {}, + "source": [ + "**Exercise 1.2**\n", + "\n", + "Recall that you have learned the lecture [Heavy-Tailed Distributions](https://intro.quantecon.org/heavy_tails.html).\n", + "\n", + "Now do the same job as in Exercise 1.1 except that the shock $Z$ is set to\n", + "$$\n", + " Z = a + c \\cdot \\chi\n", + "$$\n", + "where $\\chi$ follows a Pareto distribution with a tail exponent of $b=1.5$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c805bec-57de-4230-bde6-b591f5453216", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "a5123209-380c-4b86-a71e-b4b40ddef230", + "metadata": {}, + "source": [ + "**Exercise 1.3**\n", + "\n", + "Read section [Code](https://intro.quantecon.org/commod_price.html#code).\n", + "\n", + "Using the approximation of $p^*$ from Exercise 1.2, simulate a time series of prices with length $T=100$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ea1cf55-fa3d-43ba-a335-b199b88ecb25", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "454f83d3-0c37-403e-b8cb-b8b99d0e4c98", + "metadata": {}, + "source": [ + "### Exercise 2 (Markov chains)\n", + "\n", + "Read the \n", + "- lecture [Markov Chains: Basic Concepts](https://intro.quantecon.org/markov_chains_I.html) and \n", + "- the [corresponding methods in the QuantEcon package](https://quanteconpy.readthedocs.io/en/latest/markov/core.html) \n", + "\n", + "before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "412ba983-c477-4b49-88f2-cf9509ad6d50", + "metadata": {}, + "source": [ + "**Exercise 2.1**\n", + "\n", + "Using a method from the [QuantEcon package](https://quanteconpy.readthedocs.io/en/latest/markov/core.html), define a Markov chain object, called ``mc``, characterised by a stochastic matrix ``P`` and state values ``state_values``" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0808bd1c-4e8b-418b-8d1a-227e3defa7ba", + "metadata": {}, + "outputs": [], + "source": [ + "P = [[0.1, 0.3, 0.2, 0.4],\n", + " [0.1, 0.4, 0.1, 0.4], \n", + " [0.3, 0.2, 0.3, 0.2], \n", + " [0.2, 0.1, 0.2, 0.5]]\n", + "\n", + "state_values = [\"recession\", \"slump\", \"recovery\", \"boom\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7386ba32-ab28-4c73-928e-391d360e4a83", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "4bdb6ee9-08d1-470f-a2b0-a08ae912fb76", + "metadata": {}, + "source": [ + "**Exercise 2.2**\n", + "\n", + "Simulate a Markov chain with length of ``T=5`` using the Markov chain defined from Exercise 2.1 with an initial value ``initial_value``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b1c5723-d708-4e17-8ac4-76c55bd3ced8", + "metadata": {}, + "outputs": [], + "source": [ + "initial_value = \"recession\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3ec1bfb-d61b-4876-9d9e-0ba85917be3c", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "5634d2e0-8370-4144-ac19-f577f11593d4", + "metadata": {}, + "source": [ + "**Exercise 2.3**\n", + "\n", + "Calculate the stationary distribution(s), called ``ψ_star``, for the Markov chain defined from Exercise 2.1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a26a2603-8bc9-4418-81be-2aa680db2c08", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "17dd6031-b74c-46eb-ad6d-2bb54793b8af", + "metadata": {}, + "source": [ + "**Exercise 2.4**\n", + "\n", + "With the Markov chain defined from Exercise 2.1., compute the marignal distribution $\\psi_t = \\psi_0 P^t$ with ``t=100`` and an initial distribution ``ψ_0``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f2ba66e-bdc7-44fc-89cf-d8c389eb71a2", + "metadata": {}, + "outputs": [], + "source": [ + "ψ_0 = [0.1, 0.4, 0.3, 0.2]" + ] + }, + { + "cell_type": "markdown", + "id": "9393569d-fd5e-47c9-89d2-0b7d43b27959", + "metadata": {}, + "source": [ + "TODO \n", + "- Compare $\\psi_t$ with the ``ψ_star`` from Exercise 2.3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "290be6b1-753a-4b69-90bd-ac03ddbf0a3e", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "0dbacc7a-d570-4ffd-973f-0cd210ee9657", + "metadata": {}, + "source": [ + "Read\n", + "- lecture [Markov Chains: Irreducibility and Ergodicity](https://intro.quantecon.org/markov_chains_II.html)\n", + "\n", + "\n", + "before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "5b7ccd83-025d-4408-a0dc-dc4647c31574", + "metadata": {}, + "source": [ + "**Exercise 2.5**\n", + "\n", + "With the Markov chain defined from Exercise 2.1., check whether its stochastic matrix is irreducible." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a5bebbc-fd24-4269-a5dc-452c0eab4f98", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "65b5f5d0-cd18-4fa5-a4b3-5b1de44505d4", + "metadata": {}, + "source": [ + "**Exercise 2.6**\n", + "\n", + "With the Markov chain defined from Exercise 2.1.,\n", + "- simulate a path of length ``T = 100_000`` for it,\n", + "- calculate the fraction of time spent on each state values, called ``p_hats`` and\n", + "- compare it with the stationary distribution we computed from Exercise 2.3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6242cefd-a8bb-43cf-98af-71b2fb4a8ef7", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "2bd801b6-10f3-4f70-93ff-88b2f5e736f5", + "metadata": {}, + "source": [ + "### Exercise 3 (Commodity prices II)\n", + "\n", + "Read the lecture [Commodity Prices](https://intro.quantecon.org/commod_price.html) before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "7066964e-f363-4c3c-917f-2998ce2086a5", + "metadata": {}, + "source": [ + "**Exercise 3.1**\n", + "\n", + "Keep all the other code the same as Exercuse 1.1, \n", + "\n", + "except that the inverse demand $P(x)$ is set to\n", + "$$\n", + " P (x) = d + e \\cdot x\n", + "$$\n", + "where $d, e = 100, -1$ and $x \\in S$.\n", + "\n", + "In this exercise:\n", + "\n", + "- Compute the approximation of $p^*$ and\n", + "- plot the approximation along with the inverse demand curve $P$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70ad7e59-1b54-4bee-9b59-9be1f12dae18", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "9207e19a-e24f-45fd-ab01-73a9302e4c6e", + "metadata": {}, + "source": [ + "**Exercise 3.2**\n", + "\n", + "In this exercise, do the same job as Exercuse 3.1, except that the inverse demand $P(x)$ is set to\n", + "$$\n", + " P (x) = x^{-\\rho}\n", + "$$\n", + "where $\\rho = 1$ and $x \\in S$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "659964ed-e93a-4440-8a03-d04ed64c861a", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO type your answer here" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/exercises/day-08/exercise_set_08_with_solutions.ipynb b/exercises/day-08/exercise_set_08_with_solutions.ipynb new file mode 100644 index 0000000..aea3fe8 --- /dev/null +++ b/exercises/day-08/exercise_set_08_with_solutions.ipynb @@ -0,0 +1,752 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6cc2b576-34fb-4294-b1f7-e8e6af16a6d6", + "metadata": {}, + "source": [ + "# Commodity prices and Markov chains\n", + "\n", + "\n", + "\n", + "\n", + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Shu Hu](https://shu-hu.com/)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19d6b3bb-875a-4c90-bca3-d513f753ac78", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install quantecon" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b0842ac-7deb-4a80-8b7e-4adb2143d6a6", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import quantecon as qe\n", + "import matplotlib.pyplot as plt\n", + "from scipy.interpolate import interp1d\n", + "from scipy.optimize import minimize_scalar, brentq\n", + "from scipy.stats import norm, pareto, beta" + ] + }, + { + "cell_type": "markdown", + "id": "d428841c-6525-4cd5-a4a3-f7bfd0396ecb", + "metadata": {}, + "source": [ + "### Exercise 1 (Commodity prices I)\n", + "\n", + "Read the lecture [Commodity Prices](https://intro.quantecon.org/commod_price.html) before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "561171fd-2381-492b-bd09-7c908ded7c17", + "metadata": {}, + "source": [ + "**Exercise 1.1**\n", + "\n", + "Keep all the other code the same as section [Code](https://intro.quantecon.org/commod_price.html#code), \n", + "\n", + "except that the shock $Z$ is set to\n", + "$$\n", + " Z = a + c \\cdot \\xi\n", + "$$\n", + "where $\\xi \\sim N (0, 1)$.\n", + "\n", + "In this exercise:\n", + "\n", + "- Compute the the approximation of $p^*$ and \n", + "- plot the approximation along with the inverse demand curve $P$." + ] + }, + { + "cell_type": "markdown", + "id": "6c2cc54c-d5fb-4eab-8e10-8f39c0daa74c", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "037908bd-d740-4ad6-a166-c7062c536621", + "metadata": {}, + "outputs": [], + "source": [ + "α, a, c = 0.8, 1.0, 2.0\n", + "mc_draw_size = 250\n", + "gridsize = 150\n", + "grid_max = 35\n", + "grid = np.linspace(a, grid_max, gridsize)\n", + "\n", + "Z = a + norm.rvs(size=mc_draw_size) * c # Shock observations\n", + "D = P = lambda x: 1.0 / x\n", + "tol = 1e-4\n", + "\n", + "\n", + "def T(p_array):\n", + "\n", + " new_p = np.empty_like(p_array)\n", + "\n", + " # Interpolate to obtain p as a function.\n", + " p = interp1d(grid,\n", + " p_array,\n", + " fill_value=(p_array[0], p_array[-1]),\n", + " bounds_error=False)\n", + "\n", + " # Update\n", + " for i, x in enumerate(grid):\n", + "\n", + " h = lambda q: q - max(α * np.mean(p(α * (x - D(q)) + Z)), P(x))\n", + " new_p[i] = brentq(h, 1e-8, 100)\n", + "\n", + " return new_p\n", + "\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "price = P(grid)\n", + "ax.plot(grid, price, alpha=0.5, lw=1, label=\"inverse demand curve\")\n", + "error = tol + 1\n", + "while error > tol:\n", + " new_price = T(price)\n", + " error = max(np.abs(new_price - price))\n", + " price = new_price\n", + "\n", + "ax.plot(grid, price, 'k-', alpha=0.5, lw=2, label=r'$p^*$')\n", + "ax.legend()\n", + "ax.set_xlabel('$x$', fontsize=12)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "5220771a-30cf-4307-84a7-32f78ac18bbf", + "metadata": {}, + "source": [ + "**Exercise 1.2**\n", + "\n", + "Recall that you have learned the lecture [Heavy-Tailed Distributions](https://intro.quantecon.org/heavy_tails.html).\n", + "\n", + "Now do the same job as in Exercise 1.1 except that the shock $Z$ is set to\n", + "$$\n", + " Z = a + c \\cdot \\chi\n", + "$$\n", + "where $\\chi$ follows a Pareto distribution with a tail exponent of $b=1.5$." + ] + }, + { + "cell_type": "markdown", + "id": "431caf3f-4fca-4842-987a-4e63c5aa0449", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80ce5270-5180-472a-a534-4ee74c6794f0", + "metadata": {}, + "outputs": [], + "source": [ + "α, a, c = 0.8, 1.0, 2.0\n", + "b = 1.5 # set the Pareto tail index\n", + "mc_draw_size = 250\n", + "gridsize = 150\n", + "grid_max = 35\n", + "grid = np.linspace(a, grid_max, gridsize)\n", + "\n", + "Z = a + pareto.rvs(b, size=mc_draw_size) * c # Shock observations\n", + "D = P = lambda x: 1.0 / x\n", + "tol = 1e-4\n", + "\n", + "\n", + "def T(p_array):\n", + "\n", + " new_p = np.empty_like(p_array)\n", + "\n", + " # Interpolate to obtain p as a function.\n", + " p = interp1d(grid,\n", + " p_array,\n", + " fill_value=(p_array[0], p_array[-1]),\n", + " bounds_error=False)\n", + "\n", + " # Update\n", + " for i, x in enumerate(grid):\n", + "\n", + " h = lambda q: q - max(α * np.mean(p(α * (x - D(q)) + Z)), P(x))\n", + " new_p[i] = brentq(h, 1e-8, 100)\n", + "\n", + " return new_p\n", + "\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "price = P(grid)\n", + "ax.plot(grid, price, alpha=0.5, lw=1, label=\"inverse demand curve\")\n", + "error = tol + 1\n", + "while error > tol:\n", + " new_price = T(price)\n", + " error = max(np.abs(new_price - price))\n", + " price = new_price\n", + "\n", + "ax.plot(grid, price, 'k-', alpha=0.5, lw=2, label=r'$p^*$')\n", + "ax.legend()\n", + "ax.set_xlabel('$x$', fontsize=12)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "71c632f9-b661-4339-a9b1-27a8826a5851", + "metadata": {}, + "source": [ + "**Exercise 1.3**\n", + "\n", + "Read section [Code](https://intro.quantecon.org/commod_price.html#code).\n", + "\n", + "Using the approximation of $p^*$ from Exercise 1.2, simulate a time series of prices with length $T=100$." + ] + }, + { + "cell_type": "markdown", + "id": "8ddf9fc7-b2cf-4948-bbd7-fc9478a7f567", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d8cc14e-efa6-4786-b94d-d2e6c80cbc0c", + "metadata": {}, + "outputs": [], + "source": [ + "T = 100\n", + "\n", + "# Turn the price array into a price function\n", + "p_star = interp1d(grid,\n", + " price,\n", + " fill_value=(price[0], price[-1]),\n", + " bounds_error=False)\n", + "\n", + "def carry_over(x):\n", + " return α * (x - D(p_star(x)))\n", + "\n", + "def generate_cp_ts(init=1, n=T):\n", + " X = np.empty(n)\n", + " X[0] = init\n", + " for t in range(n-1):\n", + " Z = a + c * pareto.rvs(b)\n", + " X[t+1] = carry_over(X[t]) + Z\n", + " return p_star(X)\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(generate_cp_ts(), label=\"price\")\n", + "ax.set_xlabel(\"time\")\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "56eccac9-5e22-49a0-8caa-0894cabb2b5e", + "metadata": {}, + "source": [ + "### Exercise 2 (Markov chains)\n", + "\n", + "Read the \n", + "- lecture [Markov Chains: Basic Concepts](https://intro.quantecon.org/markov_chains_I.html) and \n", + "- the [corresponding methods in the QuantEcon package](https://quanteconpy.readthedocs.io/en/latest/markov/core.html) \n", + "\n", + "before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "f98877af-c915-4a2c-b3e8-16a7441b008f", + "metadata": {}, + "source": [ + "**Exercise 2.1**\n", + "\n", + "Using a method from the [QuantEcon package](https://quanteconpy.readthedocs.io/en/latest/markov/core.html), define a Markov chain object, called ``mc``, characterised by a stochastic matrix ``P`` and state values ``state_values``" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41e51a41-e8cd-4d88-8990-0d5114902700", + "metadata": {}, + "outputs": [], + "source": [ + "P = [[0.1, 0.3, 0.2, 0.4],\n", + " [0.1, 0.4, 0.1, 0.4], \n", + " [0.3, 0.2, 0.3, 0.2], \n", + " [0.2, 0.1, 0.2, 0.5]]\n", + "\n", + "state_values = [\"recession\", \"slump\", \"recovery\", \"boom\"]" + ] + }, + { + "cell_type": "markdown", + "id": "1916e37a-032b-4a48-bf7c-c0e635215af7", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08ceee9d-5cab-45db-a29e-49b914d1cdbb", + "metadata": {}, + "outputs": [], + "source": [ + "T = 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04b8b90d-7a61-4f30-bfb4-7bd3d4e48acd", + "metadata": {}, + "outputs": [], + "source": [ + "mc = qe.MarkovChain(P, state_values=state_values)" + ] + }, + { + "cell_type": "markdown", + "id": "b71f9177-6f98-4f71-a330-75a4a28602aa", + "metadata": {}, + "source": [ + "**Exercise 2.2**\n", + "\n", + "Simulate a Markov chain with length of ``T=5`` using the Markov chain defined from Exercise 2.1 with an initial value ``initial_value``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be81c1ce-6769-47c1-a566-4efab6218968", + "metadata": {}, + "outputs": [], + "source": [ + "initial_value = \"recession\"" + ] + }, + { + "cell_type": "markdown", + "id": "12a2bb77-56f1-4ea8-825b-e8082f61e60d", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73df31a4-2444-456e-8ad0-6b28bcdd7213", + "metadata": {}, + "outputs": [], + "source": [ + "mc.simulate(ts_length=T, init=initial_value)" + ] + }, + { + "cell_type": "markdown", + "id": "9f9d2598-006f-4320-8657-c949349149ad", + "metadata": {}, + "source": [ + "**Exercise 2.3**\n", + "\n", + "Calculate the stationary distribution(s), called ``ψ_star``, for the Markov chain defined from Exercise 2.1." + ] + }, + { + "cell_type": "markdown", + "id": "333528d9-e01f-4e3b-b9b5-2bb23d3d254b", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7d1a9e5-7c56-45be-a2c8-8a552ee758db", + "metadata": {}, + "outputs": [], + "source": [ + "ψ_star = mc.stationary_distributions[0]\n", + "ψ_star" + ] + }, + { + "cell_type": "markdown", + "id": "ab2c5084-37ea-4455-a1e0-cb07fca224dc", + "metadata": {}, + "source": [ + "**Exercise 2.4**\n", + "\n", + "With the Markov chain defined from Exercise 2.1., compute the marignal distribution $\\psi_t = \\psi_0 P^t$ with ``t=100`` and an initial distribution ``ψ_0``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4eb43cea-f8d4-415c-8db9-1382f819d645", + "metadata": {}, + "outputs": [], + "source": [ + "ψ_0 = [0.1, 0.4, 0.3, 0.2]" + ] + }, + { + "cell_type": "markdown", + "id": "b334b206-c7bc-438e-bd73-2cc230058d44", + "metadata": {}, + "source": [ + "Compare $\\psi_t$ with the ``ψ_star`` from Exercise 2.3." + ] + }, + { + "cell_type": "markdown", + "id": "e1df78ee-5f92-4422-9e47-952fa716e179", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d962ec4-5e41-485c-948e-cd36634fe4a7", + "metadata": {}, + "outputs": [], + "source": [ + "t = 100\n", + "P_power = np.linalg.matrix_power(P, t)\n", + "ψ = ψ_0 @ P_power\n", + "ψ" + ] + }, + { + "cell_type": "markdown", + "id": "7cfb81c3-bf60-49c3-a1bd-d150510eee62", + "metadata": {}, + "source": [ + "Read\n", + "- lecture [Markov Chains: Irreducibility and Ergodicity](https://intro.quantecon.org/markov_chains_II.html)\n", + "\n", + "\n", + "before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "a31396df-111c-46b3-92be-e761a93b1a57", + "metadata": {}, + "source": [ + "**Exercise 2.5**\n", + "\n", + "With the Markov chain defined from Exercise 2.1., check whether its stochastic matrix is irreducible." + ] + }, + { + "cell_type": "markdown", + "id": "ec272df3-76b1-46eb-9156-9d836e716052", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55e4a8ee-c691-412e-8a31-d80ea95edb29", + "metadata": {}, + "outputs": [], + "source": [ + "mc.is_irreducible" + ] + }, + { + "cell_type": "markdown", + "id": "91bf9e04-4596-4c4f-a301-de453ee20cc7", + "metadata": {}, + "source": [ + "**Exercise 2.6**\n", + "\n", + "With the Markov chain defined from Exercise 2.1.,\n", + "- simulate a path of length ``T = 100_000`` for it,\n", + "- calculate the fraction of time spent on each state values, called ``p_hats`` and\n", + "- compare it with the stationary distribution we computed from Exercise 2.3." + ] + }, + { + "cell_type": "markdown", + "id": "3e7ee6c3-60da-4b75-8fd8-8778e1a4bb1e", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9fc23f5a-e880-4e6b-bde4-8c925f18442e", + "metadata": {}, + "outputs": [], + "source": [ + "T = 100_000\n", + "X = mc.simulate(ts_length=T)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2aacd57a-d6d1-4474-bc33-2e43aaba40d3", + "metadata": {}, + "outputs": [], + "source": [ + "p_hats = []\n", + "for x0 in state_values:\n", + " p_hat = (X == x0).cumsum() / (1 + np.arange(T, dtype=float))\n", + " p_hats.append(p_hat[-1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9be86a39-08f8-4b2f-b848-b30623947890", + "metadata": {}, + "outputs": [], + "source": [ + "p_hats" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f1ddb3-f843-4927-ac97-cdfb1dbbc077", + "metadata": {}, + "outputs": [], + "source": [ + "ψ_star" + ] + }, + { + "cell_type": "markdown", + "id": "ad0d185b-fc7b-4739-8e7f-12d7eae7f088", + "metadata": {}, + "source": [ + "### Exercise 3 (Commodity prices II)\n", + "\n", + "Read the lecture [Commodity Prices](https://intro.quantecon.org/commod_price.html) before you attempt the following exercises." + ] + }, + { + "cell_type": "markdown", + "id": "a213cf41-edcd-4bf8-97fc-03092d2f7fe5", + "metadata": {}, + "source": [ + "**Exercise 3.1**\n", + "\n", + "Keep all the other code the same as Exercuse 1.1, \n", + "\n", + "except that the inverse demand $P(x)$ is set to\n", + "$$\n", + " P (x) = d + e \\cdot x\n", + "$$\n", + "where $d, e = 100, -1$ and $x \\in S$.\n", + "\n", + "In this exercise:\n", + "\n", + "- Compute the approximation of $p^*$ and\n", + "- plot the approximation along with the inverse demand curve $P$." + ] + }, + { + "cell_type": "markdown", + "id": "344d4680-9f88-4c1b-a28c-1cffd8540e99", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "214095bc-f3e1-4081-b910-42ed64798a94", + "metadata": {}, + "outputs": [], + "source": [ + "α, a, c = 0.8, 1.0, 2.0\n", + "d, e = 100, -1\n", + "mc_draw_size = 250\n", + "gridsize = 150\n", + "grid_max = 35\n", + "grid = np.linspace(a, grid_max, gridsize)\n", + "\n", + "Z = a + norm.rvs(size=mc_draw_size) * c # Shock observations\n", + "P = lambda x: d + e * x\n", + "D = lambda x: (x - d)/e\n", + "tol = 1e-4\n", + "\n", + "\n", + "def T(p_array):\n", + "\n", + " new_p = np.empty_like(p_array)\n", + "\n", + " # Interpolate to obtain p as a function.\n", + " p = interp1d(grid,\n", + " p_array,\n", + " fill_value=(p_array[0], p_array[-1]),\n", + " bounds_error=False)\n", + "\n", + " # Update\n", + " for i, x in enumerate(grid):\n", + "\n", + " h = lambda q: q - max(α * np.mean(p(α * (x - D(q)) + Z)), P(x))\n", + " new_p[i] = brentq(h, 1e-8, 100)\n", + "\n", + " return new_p\n", + "\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "price = P(grid)\n", + "ax.plot(grid, price, alpha=0.5, lw=1, label=\"inverse demand curve\")\n", + "error = tol + 1\n", + "while error > tol:\n", + " new_price = T(price)\n", + " error = max(np.abs(new_price - price))\n", + " price = new_price\n", + "\n", + "ax.plot(grid, price, 'k-', alpha=0.5, lw=2, label=r'$p^*$')\n", + "ax.legend()\n", + "ax.set_xlabel('$x$', fontsize=12)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "f484f474-f6d5-48b8-b3fc-9b7b5ca105c2", + "metadata": {}, + "source": [ + "**Exercise 3.2**\n", + "\n", + "In this exercise, do the same job as Exercuse 3.1, except that the inverse demand $P(x)$ is set to\n", + "$$\n", + " P (x) = x^{-\\rho}\n", + "$$\n", + "where $\\rho = 1$ and $x \\in S$." + ] + }, + { + "cell_type": "markdown", + "id": "18bb3d9b-e1db-4721-8cbc-bb5e9310ef36", + "metadata": {}, + "source": [ + "**Solution**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58878a8b-ccbf-4d6f-83f4-5a4fbc32a525", + "metadata": {}, + "outputs": [], + "source": [ + "α, a, c = 0.8, 1.0, 2.0\n", + "ρ = 1\n", + "mc_draw_size = 250\n", + "gridsize = 150\n", + "grid_max = 35\n", + "grid = np.linspace(a, grid_max, gridsize)\n", + "\n", + "Z = a + norm.rvs(size=mc_draw_size) * c # Shock observations\n", + "P = lambda x: x**(-ρ)\n", + "D = lambda x: np.exp(- np.log(x) / ρ)\n", + "tol = 1e-4\n", + "\n", + "\n", + "def T(p_array):\n", + "\n", + " new_p = np.empty_like(p_array)\n", + "\n", + " # Interpolate to obtain p as a function.\n", + " p = interp1d(grid,\n", + " p_array,\n", + " fill_value=(p_array[0], p_array[-1]),\n", + " bounds_error=False)\n", + "\n", + " # Update\n", + " for i, x in enumerate(grid):\n", + "\n", + " h = lambda q: q - max(α * np.mean(p(α * (x - D(q)) + Z)), P(x))\n", + " new_p[i] = brentq(h, 1e-8, 100)\n", + "\n", + " return new_p\n", + "\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "price = P(grid)\n", + "ax.plot(grid, price, alpha=0.5, lw=1, label=\"inverse demand curve\")\n", + "error = tol + 1\n", + "while error > tol:\n", + " new_price = T(price)\n", + " error = max(np.abs(new_price - price))\n", + " price = new_price\n", + "\n", + "ax.plot(grid, price, 'k-', alpha=0.5, lw=2, label=r'$p^*$')\n", + "ax.legend()\n", + "ax.set_xlabel('$x$', fontsize=12)\n", + "\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/exercises/day-09/exercise_set_9.ipynb b/exercises/day-09/exercise_set_9.ipynb new file mode 100644 index 0000000..99ffcde --- /dev/null +++ b/exercises/day-09/exercise_set_9.ipynb @@ -0,0 +1,782 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "93e38185", + "metadata": {}, + "source": [ + "# Pandas fundamentals" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "be5baee1", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4cd356b2", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Shu Hu](https://shu-hu.com/intro.html) and [Hengcheng Zhang](https://github.com/HengchengZhang)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f30d8e65", + "metadata": {}, + "source": [ + "First we install and import necessary packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04e9ea22", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "! pip install --upgrade pandas-datareader\n", + "! pip install --upgrade statsmodels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ac3cb05", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "84d7222c", + "metadata": {}, + "source": [ + "### Exercise 1 (View data)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "82d990c4", + "metadata": {}, + "source": [ + "Given the dataframe below you are required to do the following exercises." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3f05b7c", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv(\n", + " 'https://raw.githubusercontent.com/QuantEcon/lecture-python-programming/master/source/_static/lecture_specific/pandas/data/test_pwt.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8566b111", + "metadata": {}, + "outputs": [], + "source": [ + "df" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "bfe639a4", + "metadata": {}, + "source": [ + "### Exercise 1.1\n", + "\n", + "Show the top 5 rows of the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82404779", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9e6118a5", + "metadata": {}, + "source": [ + "### Exercise 1.2\n", + "\n", + "Show the bottom 5 rows of the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93f6d669", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9ccf345a", + "metadata": {}, + "source": [ + "### Exercise 1.3\n", + "\n", + "Show a quick statistic summary of the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "706fb250", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "46c691a0", + "metadata": {}, + "source": [ + "### Exercise 1.4\n", + "\n", + "Transpose the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3b3b2ba", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a9e76dc9", + "metadata": {}, + "source": [ + "### Exercise 1.5\n", + "\n", + "Sort the dataframe ``df`` by values in column ``tcgdp`` ascendingly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1605fb7d", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6fc52a2c", + "metadata": {}, + "source": [ + "### Exercise 2 (Select data)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c230f415", + "metadata": {}, + "source": [ + "### Exercise 2.1\n", + "\n", + "Select the column ``tcgdp`` from the dataframe ``df``, yielding a series." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a31e7945", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "db206ace", + "metadata": {}, + "source": [ + "### Exercise 2.2\n", + "\n", + "Select the top 3 rows from the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "978a7e93", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b141c3b0", + "metadata": {}, + "source": [ + "### Exercise 2.3\n", + "\n", + "\n", + "Get the first row of data across all the columns." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d24a4e1", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "3c43aa2e", + "metadata": {}, + "source": [ + "### Exercise 2.4\n", + "\n", + "Select all values on two columns ``country`` and ``POP``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aaaabcad", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8efc6931", + "metadata": {}, + "source": [ + "### Exercise 2.5\n", + "\n", + "Select values in rows 2-4 on two columns ``country`` and ``POP``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a16f2e55", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "45257c92", + "metadata": {}, + "source": [ + "### Exercise 2.6\n", + "\n", + "Get a scalar value for the 2nd row in the column ``POP`` which should be ``1006300.297``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30461e8c", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "df59f094", + "metadata": {}, + "source": [ + "### Exercise 3 (Boolean indexing)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8b27f547", + "metadata": {}, + "source": [ + "### Exercise 3.1 \n", + "\n", + "Select data with column ``POP``'s values greater than ``30_000``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3914a393", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "34e703ec", + "metadata": {}, + "source": [ + "### Exercise 3.2\n", + "\n", + "We see" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c04858cd", + "metadata": {}, + "outputs": [], + "source": [ + "df1 = df.copy()\n", + "df1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da845220", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"X\"] = [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\",\"H\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b05c4c5f", + "metadata": {}, + "outputs": [], + "source": [ + "df1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f803f63e", + "metadata": {}, + "source": [ + "Filter rows containing ``A``, ``C``, ``G`` in column ``X`` using method [isin()](https://pandas.pydata.org/docs/reference/api/pandas.Series.isin.html#pandas.Series.isin)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d5b4f10", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ab9b50a6", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4c0f7d73", + "metadata": {}, + "source": [ + "Let's consider the following dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6737b1a", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://datascience.quantecon.org/assets/data/bball.csv\"\n", + "df = pd.read_csv(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f495d87", + "metadata": {}, + "outputs": [], + "source": [ + "df" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "34d85843", + "metadata": {}, + "source": [ + "### Exercise 4.1 (Merge vs Group)\n", + "\n", + "Given two dataframes ``df1`` and ``df2``, concatenate them together." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5630ea25", + "metadata": {}, + "outputs": [], + "source": [ + "df1 = df[0:3]\n", + "df2 = df[3:]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1c4218b", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "05cf339d", + "metadata": {}, + "source": [ + "### Exercise 4.2 (Group)\n", + "\n", + "Group the dataframe ``df`` by column ``Player`` and apply the ``sum()`` function to the resulting groups." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c9f87cd", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "19e99c17", + "metadata": {}, + "source": [ + "### Exercise 4.3 (Group)\n", + "\n", + "Group the dataframe ``df`` by column ``Player`` and apply ``mean()`` function to the resulting groups." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca14399f", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a4c86444", + "metadata": {}, + "source": [ + "### Exercise 5\n", + "\n", + "Please read the following QuantEcon lecture before starting:\n", + "- https://python-programming.quantecon.org/pandas.html\n", + "\n", + "From reading we know that we can use [pandas-datareader](https://pandas-datareader.readthedocs.io/en/latest/) to access online data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e14a5243", + "metadata": {}, + "outputs": [], + "source": [ + "from pandas_datareader import wb" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ebcda398", + "metadata": {}, + "source": [ + "### Exercise 5.1\n", + "\n", + "Use [wb.search()](https://pandas-datareader.readthedocs.io/en/latest/readers/world-bank.html?highlight=search#pandas_datareader.wb.search) method to find the Gross Domestic Products per capita in constant 2015 US$.\n", + "\n", + "(Hint: use keywords, such as ``GDP`` or ``capita``.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd4af562", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ffcc0601", + "metadata": {}, + "source": [ + "### Exercise 5.2\n", + "Using the id you obtained from Exercise 2.1 to acquire GDP per capita data \n", + "- for countries US (``US``) and Australia (``AU``)\n", + "- from year 2000 to 2022,\n", + "\n", + "and store the data in a dataframe called ``dat``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf5da12b", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a72314cd", + "metadata": {}, + "source": [ + "### Exercise 5.3\n", + "\n", + "Calculate the average GDP per capita for these two countries, respectively, over the period.\n", + "\n", + "(HINT: Use ``.groupby`` from Exercise 4.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e335a0a2", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "444d20b1", + "metadata": {}, + "source": [ + "### Exercise 5.4\n", + "\n", + "Plot the GDP per capita from 2000 to 2022 as time series for the two countries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab68f01e", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "02f84f61", + "metadata": {}, + "source": [ + "## Exercise 6 (Climate change vs GDP growth)\n", + "\n", + "Next let's compare GDP per capita to the share of Droughts, floods and extreme temperatures around the world." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7f8a2756", + "metadata": {}, + "source": [ + "### Exercise 6.1\n", + "\n", + "Use [wb.search()](https://pandas-datareader.readthedocs.io/en/latest/readers/world-bank.html?highlight=search#pandas_datareader.wb.search) method to find the share of Droughts, floods, extreme temperatures." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1dd06bd1", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0b89ddba", + "metadata": {}, + "source": [ + "### Exercise 6.2 \n", + "\n", + "Acquire the GDP per capita and the share of extreme weather for **ALL** available countries in year 2009 using ``id``s from Exercises 5.1 and 6.1.\n", + "\n", + "Store the acquired data in a dataframe called ``df`` and name the columns by ``gdp`` and ``eweather``, respectively." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8f10496c", + "metadata": {}, + "source": [ + "Here a higher value in the column ``eweather`` means that the corresponding country experienced more extreme weather situations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c92bc58", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6fc0f8a1", + "metadata": {}, + "source": [ + "### Exercise 6.3 \n", + "\n", + "Use the [statsmodels](https://www.statsmodels.org/stable/regression.html) package to assess the relation between ``gdp`` and ``eweather`` using ordinary least squares regression." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "527b1a79", + "metadata": {}, + "outputs": [], + "source": [ + "import statsmodels.formula.api as sm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8f79134", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/exercises/day-09/exercise_set_9_with_solution.ipynb b/exercises/day-09/exercise_set_9_with_solution.ipynb new file mode 100644 index 0000000..fc61283 --- /dev/null +++ b/exercises/day-09/exercise_set_9_with_solution.ipynb @@ -0,0 +1,931 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "93e38185", + "metadata": {}, + "source": [ + "# Pandas fundamentals" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8a1c8e22", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4cd356b2", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)\n", + "#### Author: [Shu Hu](https://shu-hu.com/intro.html) and [Hengcheng Zhang](https://github.com/HengchengZhang)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "05920f6e", + "metadata": {}, + "source": [ + "First we install and import necessary packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2cc83f2c", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "! pip install --upgrade pandas-datareader\n", + "! pip install --upgrade statsmodels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ac3cb05", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6431cb83", + "metadata": {}, + "source": [ + "### Exercise 1 (View data)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "82d990c4", + "metadata": {}, + "source": [ + "Given the dataframe below you are required to do the following exercises." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3f05b7c", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv(\n", + " 'https://raw.githubusercontent.com/QuantEcon/lecture-python-programming/master/source/_static/lecture_specific/pandas/data/test_pwt.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8566b111", + "metadata": {}, + "outputs": [], + "source": [ + "df" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "bfe639a4", + "metadata": {}, + "source": [ + "### Exercise 1.1\n", + "\n", + "Show the top 5 rows of the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82404779", + "metadata": {}, + "outputs": [], + "source": [ + "df.head(5)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9e6118a5", + "metadata": {}, + "source": [ + "### Exercise 1.2\n", + "\n", + "Show the bottom 5 rows of the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93f6d669", + "metadata": {}, + "outputs": [], + "source": [ + "df.tail(5)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9ccf345a", + "metadata": {}, + "source": [ + "### Exercise 1.3\n", + "\n", + "Show a quick statistic summary of the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "706fb250", + "metadata": {}, + "outputs": [], + "source": [ + "df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7389bdb2", + "metadata": {}, + "outputs": [], + "source": [ + "# Alternative solution\n", + "df.describe()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "46c691a0", + "metadata": {}, + "source": [ + "### Exercise 1.4\n", + "\n", + "Transpose the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3b3b2ba", + "metadata": {}, + "outputs": [], + "source": [ + "df.T" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a9e76dc9", + "metadata": {}, + "source": [ + "### Exercise 1.5\n", + "\n", + "Sort the dataframe ``df`` by values in column ``tcgdp`` ascendingly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1605fb7d", + "metadata": {}, + "outputs": [], + "source": [ + "df.sort_values(by=\"tcgdp\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6fc52a2c", + "metadata": {}, + "source": [ + "### Exercise 2 (Select data)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c230f415", + "metadata": {}, + "source": [ + "### Exercise 2.1\n", + "\n", + "Select the column ``tcgdp`` from the dataframe ``df``, yielding a series." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a31e7945", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"tcgdp\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cd47727", + "metadata": {}, + "outputs": [], + "source": [ + "# Alternative solution\n", + "df.tcgdp" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "db206ace", + "metadata": {}, + "source": [ + "### Exercise 2.2\n", + "\n", + "Select the top 3 rows from the dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "978a7e93", + "metadata": {}, + "outputs": [], + "source": [ + "df[:3]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b141c3b0", + "metadata": {}, + "source": [ + "### Exercise 2.3\n", + "\n", + "\n", + "Get the first row of data across all the columns." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d24a4e1", + "metadata": {}, + "outputs": [], + "source": [ + "# Use df.iloc for integer index\n", + "df.iloc[0]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "3c43aa2e", + "metadata": {}, + "source": [ + "### Exercise 2.4\n", + "\n", + "Select all values on two columns ``country`` and ``POP``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aaaabcad", + "metadata": {}, + "outputs": [], + "source": [ + "df[[\"country\", \"POP\"]]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "defcdf25", + "metadata": {}, + "source": [ + "You can also use the ``loc`` method which gives you access to locators for both column and row selection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e42826de", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[:, [\"country\", \"POP\"]]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8efc6931", + "metadata": {}, + "source": [ + "### Exercise 2.5\n", + "\n", + "Select values in rows 2-4 on two columns ``country`` and ``POP``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a16f2e55", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[2:4, [\"country\", \"POP\"]]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "45257c92", + "metadata": {}, + "source": [ + "### Exercise 2.6\n", + "\n", + "Get a scalar value for the 2nd row in the column ``POP`` which should be ``1006300.297``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30461e8c", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[2, \"POP\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b17e73c", + "metadata": {}, + "outputs": [], + "source": [ + "# The .at property acts only on single value pairs for columns and rows, \n", + "# while .loc can include ranges and more advanced filters\n", + "df.at[2, \"POP\"]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "df59f094", + "metadata": {}, + "source": [ + "### Exercise 3 (Boolean indexing)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8b27f547", + "metadata": {}, + "source": [ + "### Exercise 3.1 \n", + "\n", + "Select data with column ``POP``'s values greater than ``30_000``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3914a393", + "metadata": {}, + "outputs": [], + "source": [ + "df[df['POP'] > 30_000]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "34e703ec", + "metadata": {}, + "source": [ + "### Exercise 3.2\n", + "\n", + "We see" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c04858cd", + "metadata": {}, + "outputs": [], + "source": [ + "df1 = df.copy()\n", + "df1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da845220", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"X\"] = [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\",\"H\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b05c4c5f", + "metadata": {}, + "outputs": [], + "source": [ + "df1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f803f63e", + "metadata": {}, + "source": [ + "Filter rows containing ``A``, ``C``, ``G`` in column ``X`` using method [isin()](https://pandas.pydata.org/docs/reference/api/pandas.Series.isin.html#pandas.Series.isin)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d5b4f10", + "metadata": {}, + "outputs": [], + "source": [ + "df1[df1[\"X\"].isin([\"A\", \"C\", \"G\"])]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ab9b50a6", + "metadata": {}, + "source": [ + "### Exercise 4" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4c0f7d73", + "metadata": {}, + "source": [ + "Let's consider the following dataframe ``df``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6737b1a", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://datascience.quantecon.org/assets/data/bball.csv\"\n", + "df = pd.read_csv(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f495d87", + "metadata": {}, + "outputs": [], + "source": [ + "df" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "34d85843", + "metadata": {}, + "source": [ + "### Exercise 4.1 (Merge vs Group)\n", + "\n", + "Given two dataframes ``df1`` and ``df2``, concatenate them together." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5630ea25", + "metadata": {}, + "outputs": [], + "source": [ + "df1 = df[0:3]\n", + "df2 = df[3:]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1c4218b", + "metadata": {}, + "outputs": [], + "source": [ + "dfs = [df1, df2]\n", + "pd.concat(dfs)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "05cf339d", + "metadata": {}, + "source": [ + "### Exercise 4.2 (Group)\n", + "\n", + "Group the dataframe ``df`` by column ``Player`` and apply the ``sum()`` method to the resulting groups." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c9f87cd", + "metadata": {}, + "outputs": [], + "source": [ + "df.groupby(\"Player\").sum(numeric_only=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "19e99c17", + "metadata": {}, + "source": [ + "### Exercise 4.3 (Group)\n", + "\n", + "Group the dataframe ``df`` by column ``Player`` and apply ``mean()`` method to the resulting groups." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca14399f", + "metadata": {}, + "outputs": [], + "source": [ + "df.groupby(\"Player\").mean(numeric_only=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a4c86444", + "metadata": {}, + "source": [ + "### Exercise 5\n", + "\n", + "Please read the following QuantEcon lecture before starting:\n", + "- https://python-programming.quantecon.org/pandas.html\n", + "\n", + "From reading we know that we can use [pandas-datareader](https://pandas-datareader.readthedocs.io/en/latest/) to access online data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e14a5243", + "metadata": {}, + "outputs": [], + "source": [ + "from pandas_datareader import wb" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ebcda398", + "metadata": {}, + "source": [ + "### Exercise 5.1\n", + "\n", + "Use [wb.search()](https://pandas-datareader.readthedocs.io/en/latest/readers/world-bank.html?highlight=search#pandas_datareader.wb.search) method to find the Gross Domestic Products per capita in constant 2015 US$.\n", + "\n", + "(Hint: use keywords, such as ``GDP`` or ``capita``.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd4af562", + "metadata": {}, + "outputs": [], + "source": [ + "matches = wb.search('gdp.*capita.*const.*2015')\n", + "matches" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4444f782", + "metadata": {}, + "source": [ + "The series has ``id``: ``NY.GDP.PCAP.KD``." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ffcc0601", + "metadata": {}, + "source": [ + "### Exercise 5.2\n", + "Using the id you obtained from Exercise 2.1 to acquire GDP per capita data \n", + "- for countries US (``US``) and Australia (``AU``)\n", + "- from year 2000 to 2022,\n", + "\n", + "and store the data in a dataframe called ``dat``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf5da12b", + "metadata": {}, + "outputs": [], + "source": [ + "dat = wb.download(indicator='NY.GDP.PCAP.KD', country=['US', 'AU'], start=2000, end=2022)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae137ecd", + "metadata": {}, + "outputs": [], + "source": [ + "dat" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a72314cd", + "metadata": {}, + "source": [ + "### Exercise 5.3\n", + "\n", + "Calculate the average GDP per capita for these two countries, respectively, over the period.\n", + "\n", + "(HINT: Use ``.groupby`` from Exercise 4.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e335a0a2", + "metadata": {}, + "outputs": [], + "source": [ + "dat['NY.GDP.PCAP.KD'].groupby(level=0).mean()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "444d20b1", + "metadata": {}, + "source": [ + "### Exercise 5.4\n", + "\n", + "Plot the GDP per capita from 2000 to 2022 as time series for the two countries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab68f01e", + "metadata": {}, + "outputs": [], + "source": [ + "dat_n = dat.reset_index()\n", + "dat_n = dat_n.sort_values(by=\"year\", ascending=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61b06ee0", + "metadata": {}, + "outputs": [], + "source": [ + "dat_n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8e106b1", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "\n", + "countries = [\"Australia\", \"United States\"]\n", + "year = \"year\"\n", + "ID = \"NY.GDP.PCAP.KD\"\n", + "\n", + "for i in range(len(countries)):\n", + " ax.plot(year, ID, data=dat_n[dat_n[\"country\"] == countries[i]], label=countries[i])\n", + "\n", + "\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "02f84f61", + "metadata": {}, + "source": [ + "## Exercise 6 (Climate change vs GDP growth)\n", + "\n", + "Next let's compare GDP per capita to the share of Droughts, floods and extreme temperatures around the world." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7f8a2756", + "metadata": {}, + "source": [ + "### Exercise 6.1\n", + "\n", + "Use [wb.search()](https://pandas-datareader.readthedocs.io/en/latest/readers/world-bank.html?highlight=search#pandas_datareader.wb.search) method to find the share of Droughts, floods, extreme temperatures." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1dd06bd1", + "metadata": {}, + "outputs": [], + "source": [ + "d = wb.search('temperature.*%')\n", + "d" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed4b8109", + "metadata": {}, + "outputs": [], + "source": [ + "d.iloc[:, 4]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0b89ddba", + "metadata": {}, + "source": [ + "### Exercise 6.2 \n", + "\n", + "Acquire the GDP per capita and the share of extreme weather for **ALL** available countries in year 2009 using ``id``s from Exercises 5.1 and 6.1.\n", + "\n", + "Store the acquired data in a dataframe called ``df`` and name the columns by ``gdp`` and ``eweather``, respectively." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8f10496c", + "metadata": {}, + "source": [ + "Here a higher value in the column ``eweather`` means that the corresponding country experienced more extreme weather situations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c92bc58", + "metadata": {}, + "outputs": [], + "source": [ + "ind = ['NY.GDP.PCAP.KD', 'EN.CLC.MDAT.ZS']\n", + "df = wb.download(indicator=ind, country='all', start=2009, end=2009).dropna()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "887f1059", + "metadata": {}, + "outputs": [], + "source": [ + "df.columns = ['gdp', 'eweather']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e90c6c87", + "metadata": {}, + "outputs": [], + "source": [ + "df" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6fc0f8a1", + "metadata": {}, + "source": [ + "### Exercise 6.3 \n", + "\n", + "Use the [statsmodels](https://www.statsmodels.org/stable/regression.html) package to assess the relation between ``gdp`` and ``eweather`` using ordinary least squares regression." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "527b1a79", + "metadata": {}, + "outputs": [], + "source": [ + "import statsmodels.formula.api as sm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8f79134", + "metadata": {}, + "outputs": [], + "source": [ + "wog = sm.ols('eweather ~ np.log(gdp)', df).fit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5de48f9d", + "metadata": {}, + "outputs": [], + "source": [ + "print(wog.summary())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/exercises/day-10/exercise_set_10.ipynb b/exercises/day-10/exercise_set_10.ipynb new file mode 100644 index 0000000..df9de43 --- /dev/null +++ b/exercises/day-10/exercise_set_10.ipynb @@ -0,0 +1,421 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "93e38185", + "metadata": {}, + "source": [ + "# Extension Exercises\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8a1c8e22", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4cd356b2", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e003466c", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.stats import expon" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d0cdb9de", + "metadata": {}, + "source": [ + "## Exercise 1\n", + "\n", + "***Exercise 1.1*** Consider the following setup:\n", + "\n", + "Given we have no prior knowledge about whether a coin is fair or unfair (that is we do not know whether the coin has a probability of head (p) equals to 0.5 or other values). In light of this prior belief, we assign a uniform prior to the probability of heads, $\\theta$. \n", + "\n", + "Your task is to write a function that takes a sequence of observations of coin flips, update belief after each flip, and returns the posterior distribution of $\\theta$ on a grid of points between 0 and 1. Set the true value of $\\theta$ to 0.7 and the number of coin flips ($n$) to 10000.\n", + "\n", + "(Hint: think about what distribution does coin flip follow?)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d58da89", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9437c586", + "metadata": {}, + "source": [ + "***Exercise 1.2*** Now instead of assuming a uniform prior on $[0, 1]$, assume the grid is restricted to $[0.6, 0.8]$. What is the posterior distribution of $\\theta$ after 100, 200, ..., 10000 coin flips? Visualize the distribution if you can." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7ac5faa5", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d10c5de", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7165202d", + "metadata": {}, + "source": [ + "***Exercise 1.3*** [Beta-binomial model](https://en.wikipedia.org/wiki/Beta-binomial_distribution#Beta-binomial_in_Bayesian_statistics) is well studied due to their conjugacy. Please show that the update in Exercise 1.1 fit into the construct of beta-binomial model." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c9d2b85c", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9c09a2af", + "metadata": {}, + "source": [ + "TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c12f343f", + "metadata": {}, + "source": [ + "## Exercise 2\n", + "\n", + "In this exercise, please show the fact we noticed in Exercise 1.3 mathematically." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "15b864de", + "metadata": {}, + "source": [ + "***Exercise 2.1*** Please write down the likelihood function for $\\theta$ after observing one flip of our coin." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "bef39363", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7a8f7b15", + "metadata": {}, + "source": [ + "TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6ead46e3", + "metadata": {}, + "source": [ + "***Exercise 2.2*** Please write the prior distribution (in terms of $\\alpha$ and $\\beta$) for $\\theta$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "2faecc1d", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "46d9e8a2", + "metadata": {}, + "source": [ + "TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "de94a34c", + "metadata": {}, + "source": [ + "***Exercise 2.3*** Please write the posterior distribution for $\\theta$ after observing one flip of our coin." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "502c2f85", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "2572bc12", + "metadata": {}, + "source": [ + "TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "918615e6", + "metadata": {}, + "source": [ + "## Exercise 3\n", + "\n", + "[Inverse transform sampling](https://python.quantecon.org/prob_matrix.html#classic-trick-for-generating-random-numbers) is a classic method used to generate random numbers from a desired probability distribution. The basic idea behind inverse transform sampling is to transform uniform random numbers into random numbers that follow the desired distribution.\n", + "\n", + "\n", + "The core idea is that if we draw a random number $u$ from a uniform distribution on $[0, 1]$, then the random variable $F^{-1}(u)$ has the distribution $F$:\n", + "\n", + "$$\n", + "X=F^{-1}(U)\n", + "$$\n", + "\n", + "where X is a random variable with CDF $F$:\n", + "\n", + "$$\n", + "F_X(x)=F(x)=\\textrm{Prob}\\{X\\le x\\}\n", + "$$\n", + "\n", + "A general algorithm for inverse transform sampling is as follows:\n", + "\n", + "1. Draw a random number $u$ from a uniform distribution on $[0, 1]$.\n", + "\n", + "2. Compute $x=F^{-1}(u)$.\n", + "\n", + "3. $x$ is a random number from the distribution $F$.\n", + "\n", + "Implement the inverse transform sampling algorithm for the exponential distribution with parameter $\\lambda$ = 0.5" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "82f1cc33", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce992def", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f86e1f1d", + "metadata": {}, + "source": [ + "## Exercise 4\n", + "\n", + "Consider the stochastic second-order linear difference equation\n", + "\n", + "$$\n", + "y_{t} = \\alpha_{0} + \\alpha_{1} y_{y-1} + \\alpha_{2} y_{t-2} + u_{t}\n", + "$$\n", + "\n", + "where $u_{t} \\sim N \\left(0, \\sigma_{u}^{2}\\right)$ and\n", + "\n", + "$$\n", + "\\left[\\begin{array}{c}\n", + "y_{-1}\\\\\n", + "y_{0}\n", + "\\end{array}\\right]\\sim N\\left(\\mu_{\\tilde{y}},\\Sigma_{\\tilde{y}}\\right)\n", + "$$\n", + "\n", + "It can be written as a stacked system\n", + "\n", + "$$\n", + "\\underset{\\equiv A}{\\underbrace{\\left[\\begin{array}{cccccccc}\n", + "1 & 0 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "-\\alpha_{1} & 1 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "-\\alpha_{2} & -\\alpha_{1} & 1 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "0 & -\\alpha_{2} & -\\alpha_{1} & 1 & \\cdots & 0 & 0 & 0\\\\\n", + "\\vdots & \\vdots & \\vdots & \\vdots & \\cdots & \\vdots & \\vdots & \\vdots\\\\\n", + "0 & 0 & 0 & 0 & \\cdots & -\\alpha_{2} & -\\alpha_{1} & 1\n", + "\\end{array}\\right]}}\\left[\\begin{array}{c}\n", + "y_{1}\\\\\n", + "y_{2}\\\\\n", + "y_{3}\\\\\n", + "y_{4}\\\\\n", + "\\vdots\\\\\n", + "y_{T}\n", + "\\end{array}\\right]=\\underset{\\equiv b}{\\underbrace{\\left[\\begin{array}{c}\n", + "\\alpha_{0}+\\alpha_{1}y_{0}+\\alpha_{2}y_{-1}\\\\\n", + "\\alpha_{0}+\\alpha_{2}y_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\vdots\\\\\n", + "\\alpha_{0}\n", + "\\end{array}\\right]}}\n", + "$$\n", + "\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "3dff9f4e", + "metadata": {}, + "source": [ + "***Exercise 4.1*** Code the stacked system using the parameters below as $A$ and calculate the inverse of the system." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b41c5b24", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59a2bb88", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: Put your code here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "87e84f22", + "metadata": {}, + "source": [ + "***Exercise 4.2*** We can compute $y$ by solving the system\n", + "\n", + "$$\n", + "y = A^{-1} \\left(b + u\\right)\n", + "$$\n", + "\n", + "Please solve for $\\mu_{y}$ and $\\Sigma_{y}$.\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7915a67f", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "66366cbb", + "metadata": {}, + "source": [ + "TODO: Put your solution here" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "a3abe516", + "metadata": {}, + "source": [ + "## Exercise 5\n", + "\n", + "Congratulations for making it to the end of the workshop! We hope you have enjoyed the workshop and learned a lot.\n", + "\n", + "Please run through [more advanced QuantEcon lecture series](https://quantecon.org/projects/#filter=lecture) and see what you can do with the tools you have learned in this workshop.\n", + "\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/exercises/day-10/exercise_set_10_with_solution.ipynb b/exercises/day-10/exercise_set_10_with_solution.ipynb new file mode 100644 index 0000000..84ee2c4 --- /dev/null +++ b/exercises/day-10/exercise_set_10_with_solution.ipynb @@ -0,0 +1,634 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "93e38185", + "metadata": {}, + "source": [ + "# Extension Exercises\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8a1c8e22", + "metadata": {}, + "source": [ + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4cd356b2", + "metadata": {}, + "source": [ + "#### Written for the QuantEcon Africa Workshop (July 2024)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e003466c", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.stats import expon" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d0cdb9de", + "metadata": {}, + "source": [ + "## Exercise 1\n", + "\n", + "***Exercise 1.1*** Consider the following setup:\n", + "\n", + "Given we have no prior knowledge about whether a coin is fair or unfair (that is we do not know whether the coin has a probability of head (p) equals to 0.5 or other values). In light of this prior belief, we assign a uniform prior to the probability of heads, $\\theta$. \n", + "\n", + "Your task is to write a function that takes a sequence of observations of coin flips, update belief after each flip, and returns the posterior distribution of $\\theta$ on a grid of points between 0 and 1. Set the true value of $\\theta$ to 0.7 and the number of coin flips ($n$) to 10000.\n", + "\n", + "(Hint: think about what distribution does coin flip follow?)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e96a1385", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d58da89", + "metadata": {}, + "outputs": [], + "source": [ + "n = 50_000 # Number of coin flips\n", + "bias = 0.7 # The true bias\n", + "\n", + "xs = np.linspace(0, 1, 101) # The grid\n", + "θ = np.repeat(1/len(xs), len(xs)) # Uniform θ\n", + "\n", + "def coin_flips(n, bias):\n", + " # Simulate n coin flips with bias\n", + " return np.random.choice([0, 1], size=n, p=[1-bias, bias])\n", + "\n", + "flips = coin_flips(n, bias)\n", + "\n", + "posterior_list = []\n", + "for flip in flips:\n", + " likelihood = xs**flip * (1-xs)**(1-flip) # Bernoulli Likelihood\n", + " updated_beliefs = likelihood * θ\n", + " posterior = likelihood * θ / np.sum(updated_beliefs)\n", + " posterior_list.append(θ)\n", + " θ = posterior\n", + "posterior = posterior_list[-1]\n", + "\n", + "plt.plot(xs, posterior, color='black', alpha=0.4)\n", + "plt.vlines(bias, 0, np.max(posterior), color='black', linestyles='--')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9437c586", + "metadata": {}, + "source": [ + "***Exercise 1.2*** Now instead of assuming a uniform prior on $[0, 1]$, assume the grid is restricted to $[0.6, 0.8]$. What is the posterior distribution of $\\theta$ after 100, 200, ..., 10000 coin flips? Visualize the distribution if you can." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7ac5faa5", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d10c5de", + "metadata": {}, + "outputs": [], + "source": [ + "n = 10_000 # Number of coin flips\n", + "bias = 0.7 # The true bias\n", + "\n", + "def simulate(n, bias):\n", + " xs = np.linspace(0.6, 0.8, 101) # The grid\n", + " θ = np.repeat(1/len(xs), len(xs)) # Uniform θ\n", + "\n", + " def coin_flips(n, bias):\n", + " # Simulate n coin flips with bias\n", + " return np.random.choice([0, 1], size=n, p=[1-bias, bias])\n", + "\n", + " flips = coin_flips(n, bias)\n", + "\n", + " posterior_list = []\n", + " for flip in flips:\n", + " likelihood = xs**flip * (1-xs)**(1-flip) # Bernoulli Likelihood\n", + " updated_beliefs = likelihood * θ\n", + " θ = likelihood * θ / np.sum(updated_beliefs)\n", + " posterior_list.append(θ)\n", + "\n", + " posterior = posterior_list[-1]\n", + " plt.plot(xs, posterior, color='grey', alpha=0.2)\n", + "\n", + "for i in range(100, n+1, 100):\n", + " if i % 2000 == 0:\n", + " print(f\"Simulating {i} coin flips...\")\n", + " simulate(i, bias)\n", + "\n", + "plt.axvline(bias, color='black')\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7165202d", + "metadata": {}, + "source": [ + "***Exercise 1.3*** [Beta-binomial model](https://en.wikipedia.org/wiki/Beta-binomial_distribution#Beta-binomial_in_Bayesian_statistics) is well studied due to their conjugacy. Please show that the update in Exercise 1.1 fit into the construct of beta-binomial model." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c9d2b85c", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "9c09a2af", + "metadata": {}, + "source": [ + "$\\theta |_{\\alpha = \\beta = 1} \\sim Unif(0, 1)$ in Exercise 1.1." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "c12f343f", + "metadata": {}, + "source": [ + "## Exercise 2\n", + "\n", + "In this exercise, please show the fact we noticed in Exercise 1.3 mathematically." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "15b864de", + "metadata": {}, + "source": [ + "***Exercise 2.1*** Please write down the likelihood function for $\\theta$ after observing one flip of our coin." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "bef39363", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7a8f7b15", + "metadata": {}, + "source": [ + "Suppose the outcome is Y, then the likelihood function is\n", + "\n", + "$$\n", + "L(Y|\\theta)= \\textrm{Prob}(X = Y | \\theta) = \n", + "\\theta^Y (1-\\theta)^{1-Y}\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6ead46e3", + "metadata": {}, + "source": [ + "***Exercise 2.2*** Please write the prior distribution (in terms of $\\alpha$ and $\\beta$) for $\\theta$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "2faecc1d", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "46d9e8a2", + "metadata": {}, + "source": [ + "The prior distribution is\n", + "\n", + "$$\n", + "\\textrm{Prob}(\\theta) = \\frac{\\theta^{\\alpha - 1} (1 - \\theta)^{\\beta - 1}}{B(\\alpha, \\beta)}\n", + "$$" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "de94a34c", + "metadata": {}, + "source": [ + "***Exercise 2.3*** Please write the posterior distribution for $\\theta$ after observing one flip of our coin." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "502c2f85", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "2572bc12", + "metadata": {}, + "source": [ + "We can derive the posterior distribution for $\\theta$ via \n", + "\n", + "\\begin{align*}\n", + " \\textrm{Prob}(\\theta | Y) &= \\frac{\\textrm{Prob}(Y | \\theta) \\textrm{Prob}(\\theta)}{\\textrm{Prob}(Y)} \\\\\n", + " &=\\frac{\\textrm{Prob}(Y | \\theta) \\textrm{Prob}(\\theta)}{\\int_{0}^{1} \\textrm{Prob}(Y | \\theta) \\textrm{Prob}(\\theta) d \\theta }\\\\\n", + " &= \\frac{\\theta^Y (1-\\theta)^{1-Y}\\frac{\\theta^{\\alpha - 1} (1 - \\theta)^{\\beta - 1}}{B(\\alpha, \\beta)}}{\\int_{0}^{1}\\theta^Y (1-\\theta)^{1-Y}\\frac{\\theta^{\\alpha - 1} (1 - \\theta)^{\\beta - 1}}{B(\\alpha, \\beta)} d \\theta } \\\\\n", + " &= \\frac{ \\theta^{Y+\\alpha - 1} (1 - \\theta)^{1-Y+\\beta - 1}}{\\int_{0}^{1}\\theta^{Y+\\alpha - 1} (1 - \\theta)^{1-Y+\\beta - 1} d \\theta}\n", + "\\end{align*}\n", + "\n", + "which means that\n", + "\n", + "$$\n", + "\\textrm{Prob}(\\theta | Y) \\sim \\textrm{Beta}(\\alpha + Y, \\beta + (1-Y))\n", + "$$\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ac5b35c3", + "metadata": {}, + "source": [ + "## Exercise 3\n", + "\n", + "[Inverse transform sampling](https://python.quantecon.org/prob_matrix.html#classic-trick-for-generating-random-numbers) is a classic method used to generate random numbers from a desired probability distribution. The basic idea behind inverse transform sampling is to transform uniform random numbers into random numbers that follow the desired distribution.\n", + "\n", + "\n", + "The core idea is that if we draw a random number $u$ from a uniform distribution on $[0, 1]$, then the random variable $F^{-1}(u)$ has the distribution $F$:\n", + "\n", + "$$\n", + "X=F^{-1}(U)\n", + "$$\n", + "\n", + "where X is a random variable with CDF $F$:\n", + "\n", + "$$\n", + "F_X(x)=F(x)=\\textrm{Prob}\\{X\\le x\\}\n", + "$$\n", + "\n", + "A general algorithm for inverse transform sampling is as follows:\n", + "\n", + "1. Draw a random number $u$ from a uniform distribution on $[0, 1]$.\n", + "\n", + "2. Compute $x=F^{-1}(u)$.\n", + "\n", + "3. $x$ is a random number from the distribution $F$.\n", + "\n", + "Implement the inverse transform sampling algorithm for the exponential distribution with parameter $\\lambda$ = 0.5" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "5683f4b3", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7432e622", + "metadata": {}, + "outputs": [], + "source": [ + "λ = 0.5\n", + "\n", + "# Number of random samples to generate\n", + "num_samples = 1000\n", + "\n", + "# Inverse transform sampling\n", + "def inverse_transform_sampling(num_samples, λ):\n", + " u = np.random.uniform(0, 1, num_samples) # Generate uniform random numbers\n", + " x = -np.log(1 - u) / λ # Apply inverse transform to get exponential random numbers\n", + " return x\n", + "\n", + "# Generate random samples\n", + "samples = inverse_transform_sampling(num_samples, λ)\n", + "\n", + "# Plot the histogram of the generated samples\n", + "plt.hist(samples, bins=30, density=True, alpha=0.5, label='Generated samples')\n", + "\n", + "x = np.linspace(0, 10, 1000)\n", + "plt.plot(x, expon.pdf(x, scale=1/λ),\n", + " 'r-', lw=2, alpha=0.5, label='expon pdf')\n", + "\n", + "plt.xlabel('x')\n", + "plt.ylabel('Probability density')\n", + "plt.title('Inverse Transform Sampling')\n", + "plt.legend()\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f86e1f1d", + "metadata": {}, + "source": [ + "## Exercise 4\n", + "\n", + "Consider the stochastic second-order linear difference equation\n", + "\n", + "$$\n", + "y_{t} = \\alpha_{0} + \\alpha_{1} y_{y-1} + \\alpha_{2} y_{t-2} + u_{t}\n", + "$$\n", + "\n", + "where $u_{t} \\sim N \\left(0, \\sigma_{u}^{2}\\right)$ and\n", + "\n", + "$$\n", + "\\left[\\begin{array}{c}\n", + "y_{-1}\\\\\n", + "y_{0}\n", + "\\end{array}\\right]\\sim N\\left(\\mu_{\\tilde{y}},\\Sigma_{\\tilde{y}}\\right)\n", + "$$\n", + "\n", + "It can be written as a stacked system\n", + "\n", + "$$\n", + "\\underset{\\equiv A}{\\underbrace{\\left[\\begin{array}{cccccccc}\n", + "1 & 0 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "-\\alpha_{1} & 1 & 0 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "-\\alpha_{2} & -\\alpha_{1} & 1 & 0 & \\cdots & 0 & 0 & 0\\\\\n", + "0 & -\\alpha_{2} & -\\alpha_{1} & 1 & \\cdots & 0 & 0 & 0\\\\\n", + "\\vdots & \\vdots & \\vdots & \\vdots & \\cdots & \\vdots & \\vdots & \\vdots\\\\\n", + "0 & 0 & 0 & 0 & \\cdots & -\\alpha_{2} & -\\alpha_{1} & 1\n", + "\\end{array}\\right]}}\\left[\\begin{array}{c}\n", + "y_{1}\\\\\n", + "y_{2}\\\\\n", + "y_{3}\\\\\n", + "y_{4}\\\\\n", + "\\vdots\\\\\n", + "y_{T}\n", + "\\end{array}\\right]=\\underset{\\equiv b}{\\underbrace{\\left[\\begin{array}{c}\n", + "\\alpha_{0}+\\alpha_{1}y_{0}+\\alpha_{2}y_{-1}\\\\\n", + "\\alpha_{0}+\\alpha_{2}y_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\vdots\\\\\n", + "\\alpha_{0}\n", + "\\end{array}\\right]}}\n", + "$$\n", + "\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "3dff9f4e", + "metadata": {}, + "source": [ + "***Exercise 4.1*** Code the stacked system using the parameters below as $A$ and calculate the inverse of the system." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b41c5b24", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59a2bb88", + "metadata": {}, + "outputs": [], + "source": [ + "# set parameters\n", + "T = 160\n", + "\n", + "# coefficients of the second order difference equation\n", + "𝛼0 = 10\n", + "𝛼1 = 1.53\n", + "𝛼2 = -.9\n", + "\n", + "# variance of u (\\sigma_u^2)\n", + "σu = 10.\n", + "\n", + "# distribution of y_{-1} and y_{0}\n", + "μy_tilde = np.array([1., 0.5])\n", + "Σy_tilde = np.array([[2., 1.], [1., 0.5]])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5968f20b", + "metadata": {}, + "outputs": [], + "source": [ + "# construct A and A^{\\prime}\n", + "A = np.zeros((T, T))\n", + "\n", + "for i in range(T):\n", + " A[i, i] = 1\n", + "\n", + " if i-1 >= 0:\n", + " A[i, i-1] = -𝛼1\n", + "\n", + " if i-2 >= 0:\n", + " A[i, i-2] = -𝛼2\n", + "\n", + "A_inv = np.linalg.inv(A)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "87e84f22", + "metadata": {}, + "source": [ + "***Exercise 4.2*** We can compute $y$ by solving the system\n", + "\n", + "$$\n", + "y = A^{-1} \\left(b + u\\right)\n", + "$$\n", + "\n", + "Please solve for $\\mu_{y}$ and $\\Sigma_{y}$.\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7915a67f", + "metadata": {}, + "source": [ + "### Solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "66366cbb", + "metadata": {}, + "source": [ + "We have\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "\\mu_{y} &= A^{-1} \\mu_{b} \\\\\n", + "\\Sigma_{y} &= A^{-1} E \\left[\\left(b - \\mu_{b} + u \\right) \\left(b - \\mu_{b} + u \\right)^{\\prime}\\right] \\left(A^{-1}\\right)^{\\prime} \\\\\n", + " &= A^{-1} \\left(\\Sigma_{b} + \\Sigma_{u} \\right) \\left(A^{-1}\\right)^{\\prime}\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "where\n", + "\n", + "$$\n", + "\\mu_{b}=\\left[\\begin{array}{c}\n", + "\\alpha_{0}+\\alpha_{1}\\mu_{y_{0}}+\\alpha_{2}\\mu_{y_{-1}}\\\\\n", + "\\alpha_{0}+\\alpha_{2}\\mu_{y_{0}}\\\\\n", + "\\alpha_{0}\\\\\n", + "\\vdots\\\\\n", + "\\alpha_{0}\n", + "\\end{array}\\right]\n", + "$$\n", + "\n", + "$$\n", + "\\Sigma_{b}=\\left[\\begin{array}{cc}\n", + "C\\Sigma_{\\tilde{y}}C^{\\prime} & \\boldsymbol{0}_{N-2\\times N-2}\\\\\n", + "\\boldsymbol{0}_{N-2\\times2} & \\boldsymbol{0}_{N-2\\times N-2}\n", + "\\end{array}\\right],\\quad C=\\left[\\begin{array}{cc}\n", + "\\alpha_{2} & \\alpha_{1}\\\\\n", + "0 & \\alpha_{2}\n", + "\\end{array}\\right]\n", + "$$\n", + "\n", + "$$\n", + "\\Sigma_{u}=\\left[\\begin{array}{cccc}\n", + "\\sigma_{u}^{2} & 0 & \\cdots & 0\\\\\n", + "0 & \\sigma_{u}^{2} & \\cdots & 0\\\\\n", + "\\vdots & \\vdots & \\vdots & \\vdots\\\\\n", + "0 & 0 & \\cdots & \\sigma_{u}^{2}\n", + "\\end{array}\\right]\n", + "$$\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "515fbf07", + "metadata": {}, + "outputs": [], + "source": [ + "# compute the mean vectors of b and y\n", + "μb = np.full(T, 𝛼0)\n", + "μb[0] += 𝛼1 * μy_tilde[1] + 𝛼2 * μy_tilde[0]\n", + "μb[1] += 𝛼2 * μy_tilde[1]\n", + "\n", + "μy = A_inv @ μb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a153c21", + "metadata": {}, + "outputs": [], + "source": [ + "# compute the covariance matrices of b and y\n", + "Σu = np.eye(T) * σu ** 2\n", + "\n", + "Σb = np.zeros((T, T))\n", + "\n", + "C = np.array([[𝛼2, 𝛼1], [0, 𝛼2]])\n", + "Σb[:2, :2] = C @ Σy_tilde @ C.T\n", + "\n", + "Σy = A_inv @ (Σb + Σu) @ A_inv.T" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7bdd3490", + "metadata": {}, + "source": [ + "## Exercise 5\n", + "\n", + "Congratulations for making it to the end of the workshop! We hope you have enjoyed the workshop and learned a lot.\n", + "\n", + "Please run through [more advanced QuantEcon lecture series](https://quantecon.org/projects/#filter=lecture) and see what you can do with the tools you have learned in this workshop." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}