From 90382fbb354ab4a262c7810f5b324387460479ce Mon Sep 17 00:00:00 2001 From: John Stachurski Date: Wed, 19 Sep 2018 16:04:03 -0400 Subject: [PATCH] misc --- .../job_search_finite.ipynb | 396 ++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 finite_life_job_search/job_search_finite.ipynb diff --git a/finite_life_job_search/job_search_finite.ipynb b/finite_life_job_search/job_search_finite.ipynb new file mode 100644 index 0000000..4d04cb7 --- /dev/null +++ b/finite_life_job_search/job_search_finite.ipynb @@ -0,0 +1,396 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem Set 2: Job Search" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A Python solution to the finite life Job Search problem.\n", + "\n", + "We start with some imports" + ] + }, + { + "cell_type": "code", + "execution_count": 151, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import quantecon as qe\n", + "\n", + "from numba import njit, prange\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To keep the code simple, some variables will be global." + ] + }, + { + "cell_type": "code", + "execution_count": 152, + "metadata": {}, + "outputs": [], + "source": [ + "T = 65\n", + "w_vals = (7, 10, 11)\n", + "p = (0.25, 0.5, 0.25)\n", + "p_cdf = np.cumsum(p)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's a little function to draw from $p$" + ] + }, + { + "cell_type": "code", + "execution_count": 153, + "metadata": {}, + "outputs": [], + "source": [ + "@njit\n", + "def draw_from_offer_distribution():\n", + " return qe.random.draw(p_cdf)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "The next function computes values and policies.\n", + "\n", + "The possible wage values are $w_0, w_1, w_2$\n", + "\n", + "The value functions $v_t(w)$ are returned as a matrix $V$ of the form\n", + "\n", + "$$\n", + "V = \n", + "\\begin{pmatrix}\n", + " v_0(w_0) & v_0(w_1) & v_0(w_2) \\\\\n", + " v_1(w_0) & v_1(w_1) & v_1(w_2) \\\\\n", + " & \\vdots & \\\\\n", + " v_t(w_0) & v_t(w_1) & v_t(w_2) \\\\\n", + " & \\vdots & \n", + "\\end{pmatrix}\n", + "$$\n", + "\n", + "The policy functions, which give the optimal choice at each state and time, have the interpretation\n", + "\n", + "$$ \\sigma_t(w) =\n", + "\\begin{cases}\n", + " 1 & \\text{if accept $w$ at time $t$} \\\\\n", + " 0 & \\text{otherwise}\n", + "\\end{cases}\n", + "$$\n", + "\n", + "The policy functions are returned as a matrix $\\sigma$ of the form\n", + "\n", + "$$\n", + "\\sigma = \n", + "\\begin{pmatrix}\n", + " \\sigma_0(w_0) & \\sigma_0(w_1) & \\sigma_0(w_2) \\\\\n", + " \\sigma_1(w_0) & \\sigma_1(w_1) & \\sigma_1(w_2) \\\\\n", + " & \\vdots & \\\\\n", + " \\sigma_t(w_0) & \\sigma_t(w_1) & \\sigma_t(w_2) \\\\\n", + " & \\vdots & \n", + "\\end{pmatrix}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": 154, + "metadata": {}, + "outputs": [], + "source": [ + "@njit\n", + "def compute_values_and_policies(β=0.96, c=8):\n", + "\n", + " n = len(w_vals) \n", + " V = np.empty((T, n))\n", + " σ = np.zeros((T, n), dtype=np.int64)\n", + "\n", + " t = T-1\n", + " for i, w in enumerate(w_vals):\n", + " V[t, i] = max(c, w) \n", + " σ[t, i] = (w > c)\n", + "\n", + " while t > 0:\n", + " for i, w in enumerate(w_vals):\n", + " \n", + " accept_val = w * (1 - β**(T-t+1)) / (1 - β)\n", + " EV = 0.0\n", + " for j in range(n):\n", + " EV += V[t, j] * p[j]\n", + " continue_val = c + β * EV\n", + " \n", + " if accept_val > continue_val:\n", + " σ[t-1, i] = 1\n", + " V[t-1, i] = accept_val\n", + " else:\n", + " V[t-1, i] = continue_val\n", + " \n", + " t -= 1\n", + "\n", + " return V, σ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's jitted code that simulates the life of one agent, recording the wage that they accept at and their age when they accept." + ] + }, + { + "cell_type": "code", + "execution_count": 166, + "metadata": {}, + "outputs": [], + "source": [ + "@njit\n", + "def sim_life(σ):\n", + " for t in range(T):\n", + " i = draw_from_offer_distribution()\n", + " if σ[t, i] == 1:\n", + " accepted_wage = w_vals[i]\n", + " start_work_age = t\n", + " return accepted_wage, start_work_age+1\n", + " \n", + " start_work_age = T\n", + " accepted_wage = 0\n", + " return accepted_wage, start_work_age" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's a function that simulates the lives of many agents and takes an average over their statistics.\n", + "\n", + "Parallelization is not implemented because the individual calculations are so short." + ] + }, + { + "cell_type": "code", + "execution_count": 167, + "metadata": {}, + "outputs": [], + "source": [ + "@njit\n", + "def sim_stats(σ, m=1_000_000):\n", + " wage_mean = 0\n", + " age_mean = 0\n", + " for i in range(m):\n", + " accepted_wage, start_work_age = sim_life(σ)\n", + " age_mean += start_work_age\n", + " wage_mean += accepted_wage\n", + " return wage_mean / m, age_mean / m\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's actually compute the optimal policies and simulate some agents to calculate statistics." + ] + }, + { + "cell_type": "code", + "execution_count": 178, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "V, σ = compute_values_and_policies()" + ] + }, + { + "cell_type": "code", + "execution_count": 179, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 153 ms, sys: 0 ns, total: 153 ms\n", + "Wall time: 151 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "\n", + "wage_mean, age_mean = sim_stats(σ)" + ] + }, + { + "cell_type": "code", + "execution_count": 180, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "11.0" + ] + }, + "execution_count": 180, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wage_mean" + ] + }, + { + "cell_type": "code", + "execution_count": 181, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.999721" + ] + }, + "execution_count": 181, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "age_mean" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total time to simulate for 1,000,000 agents is a few hundred ms on my machine." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What happens when we change $c$?" + ] + }, + { + "cell_type": "code", + "execution_count": 182, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "V, σ = compute_values_and_policies(c=4.5)" + ] + }, + { + "cell_type": "code", + "execution_count": 183, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 103 ms, sys: 0 ns, total: 103 ms\n", + "Wall time: 101 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "\n", + "wage_mean, age_mean = sim_stats(σ)" + ] + }, + { + "cell_type": "code", + "execution_count": 184, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10.71835" + ] + }, + "execution_count": 184, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wage_mean" + ] + }, + { + "cell_type": "code", + "execution_count": 185, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2.876221" + ] + }, + "execution_count": 185, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "age_mean" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}