{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "
\n", " \n", " \"QuantEcon\"\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# A Lake Model of Employment and Unemployment\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Contents\n", "\n", "- [A Lake Model of Employment and Unemployment](#A-Lake-Model-of-Employment-and-Unemployment) \n", " - [Overview](#Overview) \n", " - [The Model](#The-Model) \n", " - [Implementation](#Implementation) \n", " - [Dynamics of an Individual Worker](#Dynamics-of-an-Individual-Worker) \n", " - [Endogenous Job Finding Rate](#Endogenous-Job-Finding-Rate) \n", " - [Exercises](#Exercises) \n", " - [Solutions](#Solutions) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "\n", "This lecture describes what has come to be called a *lake model*\n", "\n", "The lake model is a basic tool for modeling unemployment\n", "\n", "It allows us to analyze\n", "\n", "- flows between unemployment and employment \n", "- how these flows influence steady state employment and unemployment rates \n", "\n", "\n", "It is a good model for interpreting monthly labor department reports on gross and net jobs created and jobs destroyed\n", "\n", "The “lakes” in the model are the pools of employed and unemployed\n", "\n", "The “flows” between the lakes are caused by\n", "\n", "- firing and hiring \n", "- entry and exit from the labor force \n", "\n", "\n", "For the first part of this lecture, the parameters governing transitions into\n", "and out of unemployment and employment are exogenous\n", "\n", "Later, we’ll determine some of these transition rates endogenously using the [McCall search model](dynamic_programming/mccall_model.ipynb)\n", "\n", "We’ll also use some nifty concepts like ergodicity, which provides a fundamental link between *cross-sectional* and *long run time series* distributions\n", "\n", "These concepts will help us build an equilibrium model of ex ante homogeneous workers whose different luck generates variations in their ex post experiences" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Prerequisites\n", "\n", "Before working through what follows, we recommend you read the [lecture\n", "on finite Markov chains](tools_and_techniques/finite_markov.ipynb)\n", "\n", "You will also need some basic [linear algebra](tools_and_techniques/linear_algebra.ipynb) and probability" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Model\n", "\n", "The economy is inhabited by a very large number of ex ante identical workers\n", "\n", "The workers live forever, spending their lives moving between unemployment and employment\n", "\n", "Their rates of transition between employment and unemployment are governed by the following parameters:\n", "\n", "- $ \\lambda $, the job finding rate for currently unemployed workers \n", "- $ \\alpha $, the dismissal rate for currently employed workers \n", "- $ b $, the entry rate into the labor force \n", "- $ d $, the exit rate from the labor force \n", "\n", "\n", "The growth rate of the labor force evidently equals $ g=b-d $" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Aggregate Variables\n", "\n", "We want to derive the dynamics of the following aggregates\n", "\n", "- $ E_t $, the total number of employed workers at date $ t $ \n", "- $ U_t $, the total number of unemployed workers at $ t $ \n", "- $ N_t $, the number of workers in the labor force at $ t $ \n", "\n", "\n", "We also want to know the values of the following objects\n", "\n", "- The employment rate $ e_t := E_t/N_t $ \n", "- The unemployment rate $ u_t := U_t/N_t $ \n", "\n", "\n", "(Here and below, capital letters represent stocks and lowercase letters represent flows)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Laws of Motion for Stock Variables\n", "\n", "We begin by constructing laws of motion for the aggregate variables $ E_t,U_t, N_t $\n", "\n", "Of the mass of workers $ E_t $ who are employed at date $ t $,\n", "\n", "- $ (1-d)E_t $ will remain in the labor force \n", "- of these, $ (1-\\alpha)(1-d)E_t $ will remain employed \n", "\n", "\n", "Of the mass of workers $ U_t $ workers who are currently unemployed,\n", "\n", "- $ (1-d)U_t $ will remain in the labor force \n", "- of these, $ (1-d) \\lambda U_t $ will become employed \n", "\n", "\n", "Therefore, the number of workers who will be employed at date $ t+1 $ will be\n", "\n", "$$\n", "E_{t+1} = (1-d)(1-\\alpha)E_t + (1-d)\\lambda U_t\n", "$$\n", "\n", "A similar analysis implies\n", "\n", "$$\n", "U_{t+1} = (1-d)\\alpha E_t + (1-d)(1-\\lambda)U_t + b (E_t+U_t)\n", "$$\n", "\n", "The value $ b(E_t+U_t) $ is the mass of new workers entering the labor force unemployed\n", "\n", "The total stock of workers $ N_t=E_t+U_t $ evolves as\n", "\n", "$$\n", "N_{t+1} = (1+b-d)N_t = (1+g)N_t\n", "$$\n", "\n", "Letting $ X_t := \\left(\\begin{matrix}U_t\\\\E_t\\end{matrix}\\right) $, the law of motion for $ X $ is\n", "\n", "$$\n", "X_{t+1} = A X_t\n", "\\quad \\text{where} \\quad\n", "A :=\n", "\\begin{pmatrix}\n", " (1-d)(1-\\lambda) + b & (1-d)\\alpha + b \\\\\n", " (1-d)\\lambda & (1-d)(1-\\alpha)\n", "\\end{pmatrix}\n", "$$\n", "\n", "This law tells us how total employment and unemployment evolve over time" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Laws of Motion for Rates\n", "\n", "Now let’s derive the law of motion for rates\n", "\n", "To get these we can divide both sides of $ X_{t+1} = A X_t $ by $ N_{t+1} $ to get\n", "\n", "$$\n", "\\begin{pmatrix}\n", " U_{t+1}/N_{t+1} \\\\\n", " E_{t+1}/N_{t+1}\n", "\\end{pmatrix}\n", "=\n", "\\frac1{1+g} A\n", "\\begin{pmatrix}\n", " U_{t}/N_{t}\n", " \\\\\n", " E_{t}/N_{t}\n", "\\end{pmatrix}\n", "$$\n", "\n", "Letting\n", "\n", "$$\n", "x_t :=\n", "\\left(\\begin{matrix}\n", " u_t\\\\ e_t\n", "\\end{matrix}\\right)\n", "= \\left(\\begin{matrix}\n", " U_t/N_t\\\\ E_t/N_t\n", "\\end{matrix}\\right)\n", "$$\n", "\n", "we can also write this as\n", "\n", "$$\n", "x_{t+1} = \\hat A x_t\n", "\\quad \\text{where} \\quad\n", "\\hat A := \\frac{1}{1 + g} A\n", "$$\n", "\n", "You can check that $ e_t + u_t = 1 $ implies that $ e_{t+1}+u_{t+1} = 1 $\n", "\n", "This follows from the fact that the columns of $ \\hat A $ sum to 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Implementation\n", "\n", "Let’s code up these equations\n", "\n", "Here’s the code:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setup" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": true }, "outputs": [], "source": [ "using InstantiateFromURL\n", "github_project(\"QuantEcon/quantecon-notebooks-julia\", version = \"0.2.0\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": true }, "outputs": [], "source": [ "using LinearAlgebra, Statistics, Compat\n", "using Distributions, Expectations, NLsolve, Parameters, Plots\n", "using QuantEcon, Roots, Random" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "gr(fmt = :png);" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "LakeModel = @with_kw (λ = 0.283, α = 0.013, b = 0.0124, d = 0.00822)\n", "\n", "function transition_matrices(lm)\n", " @unpack λ, α, b, d = lm\n", " g = b - d\n", " A = [(1 - λ) * (1 - d) + b (1 - d) * α + b\n", " (1 - d) * λ (1 - d) * (1 - α)]\n", "  = A ./ (1 + g)\n", " return (A = A,  = Â)\n", "end\n", "\n", "function rate_steady_state(lm)\n", " @unpack  = transition_matrices(lm)\n", " sol = fixedpoint(x ->  * x, fill(0.5, 2))\n", " converged(sol) || error(\"Failed to converge in $(result.iterations) iterations\")\n", " return sol.zero\n", "end\n", "\n", "function simulate_stock_path(lm, X0, T)\n", " @unpack A = transition_matrices(lm)\n", " X_path = zeros(eltype(X0), 2, T)\n", " X = copy(X0)\n", " for t in 1:T\n", " X_path[:, t] = X\n", " X = A * X\n", " end\n", " return X_path\n", "end\n", "\n", "function simulate_rate_path(lm, x0, T)\n", " @unpack  = transition_matrices(lm)\n", " x_path = zeros(eltype(x0), 2, T)\n", " x = copy(x0)\n", " for t in 1:T\n", " x_path[:, t] = x\n", " x =  * x\n", " end\n", " return x_path\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let’s observe these matrices for the baseline model" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel()\n", "A,  = transition_matrices(lm)\n", "A" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "Â" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And a revised model" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel(α = 2.0)\n", "A,  = transition_matrices(lm)\n", "A" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "Â" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Aggregate Dynamics\n", "\n", "Let’s run a simulation under the default parameters (see above) starting from $ X_0 = (12, 138) $" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel()\n", "N_0 = 150 # population\n", "e_0 = 0.92 # initial employment rate\n", "u_0 = 1 - e_0 # initial unemployment rate\n", "T = 50 # simulation length\n", "\n", "U_0 = u_0 * N_0\n", "E_0 = e_0 * N_0\n", "X_0 = [U_0; E_0]\n", "\n", "X_path = simulate_stock_path(lm, X_0, T)\n", "\n", "x1 = X_path[1, :]\n", "x2 = X_path[2, :]\n", "x3 = dropdims(sum(X_path, dims = 1), dims = 1)\n", "\n", "plt_unemp = plot(title = \"Unemployment\", 1:T, x1, color = :blue, lw = 2, grid = true, label = \"\")\n", "plt_emp = plot(title = \"Employment\", 1:T, x2, color = :blue, lw = 2, grid = true, label = \"\")\n", "plt_labor = plot(title = \"Labor force\", 1:T, x3, color = :blue, lw = 2, grid = true, label = \"\")\n", "\n", "plot(plt_unemp, plt_emp, plt_labor, layout = (3, 1), size = (800, 600))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The aggregates $ E_t $ and $ U_t $ don’t converge because their sum $ E_t + U_t $ grows at rate $ g $\n", "\n", "On the other hand, the vector of employment and unemployment rates $ x_t $ can be in a steady state $ \\bar x $ if\n", "there exists an $ \\bar x $ such that\n", "\n", "- $ \\bar x = \\hat A \\bar x $ \n", "- the components satisfy $ \\bar e + \\bar u = 1 $ \n", "\n", "\n", "This equation tells us that a steady state level $ \\bar x $ is an eigenvector of $ \\hat A $ associated with a unit eigenvalue\n", "\n", "We also have $ x_t \\to \\bar x $ as $ t \\to \\infty $ provided that the remaining eigenvalue of $ \\hat A $ has modulus less that 1\n", "\n", "This is the case for our default parameters:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel()\n", "A,  = transition_matrices(lm)\n", "e, f = eigvals(Â)\n", "abs(e), abs(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let’s look at the convergence of the unemployment and employment rate to steady state levels (dashed red line)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel()\n", "e_0 = 0.92 # initial employment rate\n", "u_0 = 1 - e_0 # initial unemployment rate\n", "T = 50 # simulation length\n", "\n", "xbar = rate_steady_state(lm)\n", "x_0 = [u_0; e_0]\n", "x_path = simulate_rate_path(lm, x_0, T)\n", "\n", "plt_unemp = plot(title =\"Unemployment rate\", 1:T, x_path[1, :],color = :blue, lw = 2,\n", " alpha = 0.5, grid = true, label = \"\")\n", "plot!(plt_unemp, [xbar[1]], color=:red, linetype = :hline, linestyle = :dash, lw = 2, label = \"\")\n", "plt_emp = plot(title = \"Employment rate\", 1:T, x_path[2, :],color = :blue, lw = 2, alpha = 0.5,\n", " grid = true, label = \"\")\n", "plot!(plt_emp, [xbar[2]], color=:red, linetype = :hline, linestyle = :dash, lw = 2, label = \"\")\n", "plot(plt_unemp, plt_emp, layout = (2, 1), size=(700,500))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dynamics of an Individual Worker\n", "\n", "An individual worker’s employment dynamics are governed by a [finite state Markov process](tools_and_techniques/finite_markov.ipynb)\n", "\n", "The worker can be in one of two states:\n", "\n", "- $ s_t=0 $ means unemployed \n", "- $ s_t=1 $ means employed \n", "\n", "\n", "Let’s start off under the assumption that $ b = d = 0 $\n", "\n", "The associated transition matrix is then\n", "\n", "$$\n", "P = \\left(\n", " \\begin{matrix}\n", " 1 - \\lambda & \\lambda \\\\\n", " \\alpha & 1 - \\alpha\n", " \\end{matrix}\n", " \\right)\n", "$$\n", "\n", "Let $ \\psi_t $ denote the [marginal distribution](tools_and_techniques/finite_markov.ipynb#mc-md) over employment / unemployment states for the worker at time $ t $\n", "\n", "As usual, we regard it as a row vector\n", "\n", "We know [from an earlier discussion](tools_and_techniques/finite_markov.ipynb#mc-md) that $ \\psi_t $ follows the law of motion\n", "\n", "$$\n", "\\psi_{t+1} = \\psi_t P\n", "$$\n", "\n", "We also know from the [lecture on finite Markov chains](tools_and_techniques/finite_markov.ipynb)\n", "that if $ \\alpha \\in (0, 1) $ and $ \\lambda \\in (0, 1) $, then\n", "$ P $ has a unique stationary distribution, denoted here by $ \\psi^* $\n", "\n", "The unique stationary distribution satisfies\n", "\n", "$$\n", "\\psi^*[0] = \\frac{\\alpha}{\\alpha + \\lambda}\n", "$$\n", "\n", "Not surprisingly, probability mass on the unemployment state increases with\n", "the dismissal rate and falls with the job finding rate rate" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ergodicity\n", "\n", "Let’s look at a typical lifetime of employment-unemployment spells\n", "\n", "We want to compute the average amounts of time an infinitely lived worker would spend employed and unemployed\n", "\n", "Let\n", "\n", "$$\n", "\\bar s_{u,T} := \\frac1{T} \\sum_{t=1}^T \\mathbb 1\\{s_t = 0\\}\n", "$$\n", "\n", "and\n", "\n", "$$\n", "\\bar s_{e,T} := \\frac1{T} \\sum_{t=1}^T \\mathbb 1\\{s_t = 1\\}\n", "$$\n", "\n", "(As usual, $ \\mathbb 1\\{Q\\} = 1 $ if statement $ Q $ is true and 0 otherwise)\n", "\n", "These are the fraction of time a worker spends unemployed and employed, respectively, up until period $ T $\n", "\n", "If $ \\alpha \\in (0, 1) $ and $ \\lambda \\in (0, 1) $, then $ P $ is [ergodic](tools_and_techniques/finite_markov.ipynb#ergodicity), and hence we have\n", "\n", "$$\n", "\\lim_{T \\to \\infty} \\bar s_{u, T} = \\psi^*[0]\n", "\\quad \\text{and} \\quad\n", "\\lim_{T \\to \\infty} \\bar s_{e, T} = \\psi^*[1]\n", "$$\n", "\n", "with probability one\n", "\n", "Inspection tells us that $ P $ is exactly the transpose of $ \\hat A $ under the assumption $ b=d=0 $\n", "\n", "Thus, the percentages of time that an infinitely lived worker spends employed and unemployed equal the fractions of workers employed and unemployed in the steady state distribution" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Convergence rate\n", "\n", "How long does it take for time series sample averages to converge to cross sectional averages?\n", "\n", "We can use [QuantEcon.jl’s](http://quantecon.org/julia_index.html)\n", "MarkovChain type to investigate this\n", "\n", "Let’s plot the path of the sample averages over 5,000 periods" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "using QuantEcon, Roots, Random" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel(d = 0, b = 0)\n", "T = 5000 # Simulation length\n", "\n", "@unpack α, λ = lm\n", "P = [(1 - λ) λ\n", " α (1 - α)]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "Random.seed!(42)\n", "mc = MarkovChain(P, [0; 1]) # 0=unemployed, 1=employed\n", "xbar = rate_steady_state(lm)\n", "\n", "s_path = simulate(mc, T; init=2)\n", "s̄_e = cumsum(s_path) ./ (1:T)\n", "s̄_u = 1 .- s̄_e\n", "s_bars = [s̄_u s̄_e]\n", "\n", "plt_unemp = plot(title = \"Percent of time unemployed\", 1:T, s_bars[:,1],color = :blue, lw = 2,\n", " alpha = 0.5, label = \"\", grid = true)\n", "plot!(plt_unemp, [xbar[1]], linetype = :hline, linestyle = :dash, color=:red, lw = 2, label = \"\")\n", "plt_emp = plot(title = \"Percent of time employed\", 1:T, s_bars[:,2],color = :blue, lw = 2,\n", " alpha = 0.5, label = \"\", grid = true)\n", "plot!(plt_emp, [xbar[2]], linetype = :hline, linestyle = :dash, color=:red, lw = 2, label = \"\")\n", "plot(plt_unemp, plt_emp, layout = (2, 1), size=(700,500))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The stationary probabilities are given by the dashed red line\n", "\n", "In this case it takes much of the sample for these two objects to converge\n", "\n", "This is largely due to the high persistence in the Markov chain" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Endogenous Job Finding Rate\n", "\n", "We now make the hiring rate endogenous\n", "\n", "The transition rate from unemployment to employment will be determined by the McCall search model [[McC70]](zreferences.ipynb#mccall1970)\n", "\n", "All details relevant to the following discussion can be found in [our treatment](dynamic_programming/mccall_model.ipynb) of that model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reservation Wage\n", "\n", "The most important thing to remember about the model is that optimal decisions\n", "are characterized by a reservation wage $ \\bar w $\n", "\n", "- If the wage offer $ w $ in hand is greater than or equal to $ \\bar w $, then the worker accepts \n", "- Otherwise, the worker rejects \n", "\n", "\n", "As we saw in [our discussion of the model](dynamic_programming/mccall_model.ipynb), the reservation wage depends on the wage offer distribution and the parameters\n", "\n", "- $ \\alpha $, the separation rate \n", "- $ \\beta $, the discount factor \n", "- $ \\gamma $, the offer arrival rate \n", "- $ c $, unemployment compensation " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Linking the McCall Search Model to the Lake Model\n", "\n", "Suppose that all workers inside a lake model behave according to the McCall search model\n", "\n", "The exogenous probability of leaving employment remains $ \\alpha $\n", "\n", "But their optimal decision rules determine the probability $ \\lambda $ of leaving unemployment\n", "\n", "This is now\n", "\n", "\n", "\n", "$$\n", "\\lambda\n", "= \\gamma \\mathbb P \\{ w_t \\geq \\bar w\\}\n", "= \\gamma \\sum_{w' \\geq \\bar w} p(w') \\tag{1}\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fiscal Policy\n", "\n", "We can use the McCall search version of the Lake Model to find an optimal level of unemployment insurance\n", "\n", "We assume that the government sets unemployment compensation $ c $\n", "\n", "The government imposes a lump sum tax $ \\tau $ sufficient to finance total unemployment payments\n", "\n", "To attain a balanced budget at a steady state, taxes, the steady state unemployment rate $ u $, and the unemployment compensation rate must satisfy\n", "\n", "$$\n", "\\tau = u c\n", "$$\n", "\n", "The lump sum tax applies to everyone, including unemployed workers\n", "\n", "Thus, the post-tax income of an employed worker with wage $ w $ is $ w - \\tau $\n", "\n", "The post-tax income of an unemployed worker is $ c - \\tau $\n", "\n", "For each specification $ (c, \\tau) $ of government policy, we can solve for the worker’s optimal reservation wage\n", "\n", "This determines $ \\lambda $ via [(1)](#equation-lake-lamda) evaluated at post tax wages, which in turn determines a steady state unemployment rate $ u(c, \\tau) $\n", "\n", "For a given level of unemployment benefit $ c $, we can solve for a tax that balances the budget in the steady state\n", "\n", "$$\n", "\\tau = u(c, \\tau) c\n", "$$\n", "\n", "To evaluate alternative government tax-unemployment compensation pairs, we require a welfare criterion\n", "\n", "We use a steady state welfare criterion\n", "\n", "$$\n", "W := e \\, {\\mathbb E} [V \\, | \\, \\text{employed}] + u \\, U\n", "$$\n", "\n", "where the notation $ V $ and $ U $ is as defined in the [McCall search model lecture](dynamic_programming/mccall_model.ipynb)\n", "\n", "The wage offer distribution will be a discretized version of the lognormal distribution $ LN(\\log(20),1) $, as shown in the next figure\n", "\n", "![_static/figures/lake_distribution_wages.png](_static/figures/lake_distribution_wages.png) \n", "We take a period to be a month\n", "\n", "We set $ b $ and $ d $ to match monthly [birth](http://www.cdc.gov/nchs/fastats/births.htm) and [death rates](http://www.cdc.gov/nchs/fastats/deaths.htm), respectively, in the U.S. population\n", "\n", "- $ b = 0.0124 $ \n", "- $ d = 0.00822 $ \n", "\n", "\n", "Following [[DFH06]](zreferences.ipynb#davis2006flow), we set $ \\alpha $, the hazard rate of leaving employment, to\n", "\n", "- $ \\alpha = 0.013 $ " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fiscal Policy Code\n", "\n", "We will make use of (with some tweaks) the code we wrote in the [McCall model lecture](dynamic_programming/mccall_model.ipynb), embedded below for convenience" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "function solve_mccall_model(mcm; U_iv = 1.0, V_iv = ones(length(mcm.w)), tol = 1e-5,\n", " iter = 2_000)\n", " @unpack α, β, σ, c, γ, w, E, u = mcm\n", "\n", " # necessary objects\n", " u_w = u.(w, σ)\n", " u_c = u(c, σ)\n", "\n", " # Bellman operator T. Fixed point is x* s.t. T(x*) = x*\n", " function T(x)\n", " V = x[1:end-1]\n", " U = x[end]\n", " [u_w + β * ((1 - α) * V .+ α * U); u_c + β * (1 - γ) * U + β * γ * E * max.(U, V)]\n", " end\n", "\n", " # value function iteration\n", " x_iv = [V_iv; U_iv] # initial x val\n", " xstar = fixedpoint(T, x_iv, iterations = iter, xtol = tol).zero\n", " V = xstar[1:end-1]\n", " U = xstar[end]\n", "\n", " # compute the reservation wage\n", " w_barindex = searchsortedfirst(V .- U, 0.0)\n", " if w_barindex >= length(w) # if this is true, you never want to accept\n", " w̄ = Inf\n", " else\n", " w̄ = w[w_barindex] # otherwise, return the number\n", " end\n", "\n", " # return a NamedTuple, so we can select values by name\n", " return (V = V, U = U, w̄ = w̄)\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And the McCall object" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "# a default utility function\n", "u(c, σ) = c > 0 ? (c^(1 - σ) - 1) / (1 - σ) : -10e-6\n", "\n", "# model constructor\n", "McCallModel = @with_kw (α = 0.2,\n", " β = 0.98, # discount rate\n", " γ = 0.7,\n", " c = 6.0, # unemployment compensation\n", " σ = 2.0,\n", " u = u, # utility function\n", " w = range(10, 20, length = 60), # wage values\n", " E = Expectation(BetaBinomial(59, 600, 400))) # distribution over wage values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let’s compute and plot welfare, employment, unemployment, and tax revenue as a\n", "function of the unemployment compensation rate" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "# some global variables that will stay constant\n", "α = 0.013\n", "α_q = (1 - (1 - α)^3)\n", "b_param = 0.0124\n", "d_param = 0.00822\n", "β = 0.98\n", "γ = 1.0\n", "σ = 2.0\n", "\n", "# the default wage distribution: a discretized log normal\n", "log_wage_mean, wage_grid_size, max_wage = 20, 200, 170\n", "w_vec = range(1e-3, max_wage, length = wage_grid_size + 1)\n", "\n", "logw_dist = Normal(log(log_wage_mean), 1)\n", "cdf_logw = cdf.(logw_dist, log.(w_vec))\n", "pdf_logw = cdf_logw[2:end] - cdf_logw[1:end-1]\n", "\n", "p_vec = pdf_logw ./ sum(pdf_logw)\n", "w_vec = (w_vec[1:end-1] + w_vec[2:end]) / 2\n", "\n", "E = expectation(Categorical(p_vec)) # expectation object\n", "\n", "function compute_optimal_quantities(c, τ)\n", " mcm = McCallModel(α = α_q,\n", " β = β,\n", " γ = γ,\n", " c = c - τ, # post-tax compensation\n", " σ = σ,\n", " w = w_vec .- τ, # post-tax wages\n", " E = E) # expectation operator\n", "\n", " @unpack V, U, w̄ = solve_mccall_model(mcm)\n", " indicator = wage -> wage > w̄\n", " λ = γ * E * indicator.(w_vec .- τ)\n", "\n", " return w̄, λ, V, U\n", "end\n", "\n", "function compute_steady_state_quantities(c, τ)\n", " w̄, λ_param, V, U = compute_optimal_quantities(c, τ)\n", "\n", " # compute steady state employment and unemployment rates\n", " lm = LakeModel(λ = λ_param, α = α_q, b = b_param, d = d_param)\n", " x = rate_steady_state(lm)\n", " u_rate, e_rate = x\n", "\n", " # compute steady state welfare\n", " indicator(wage) = wage > w̄\n", " indicator(wage) = wage > w̄\n", " decisions = indicator.(w_vec .- τ)\n", " w = (E * (V .* decisions)) / (E * decisions)\n", " welfare = e_rate .* w + u_rate .* U\n", "\n", " return u_rate, e_rate, welfare\n", "end\n", "\n", "function find_balanced_budget_tax(c)\n", " function steady_state_budget(t)\n", " u_rate, e_rate, w = compute_steady_state_quantities(c, t)\n", " return t - u_rate * c\n", " end\n", "\n", " τ = find_zero(steady_state_budget, (0.0, 0.9c))\n", " return τ\n", "end\n", "\n", "# levels of unemployment insurance we wish to study\n", "Nc = 60\n", "c_vec = range(5, 140, length = Nc)\n", "\n", "tax_vec = zeros(Nc)\n", "unempl_vec = similar(tax_vec)\n", "empl_vec = similar(tax_vec)\n", "welfare_vec = similar(tax_vec)\n", "\n", "for i in 1:Nc\n", " t = find_balanced_budget_tax(c_vec[i])\n", " u_rate, e_rate, welfare = compute_steady_state_quantities(c_vec[i], t)\n", " tax_vec[i] = t\n", " unempl_vec[i] = u_rate\n", " empl_vec[i] = e_rate\n", " welfare_vec[i] = welfare\n", "end\n", "\n", "plt_unemp = plot(title = \"Unemployment\", c_vec, unempl_vec, color = :blue, lw = 2, alpha=0.7,\n", " label = \"\",grid = true)\n", "plt_tax = plot(title = \"Tax\", c_vec, tax_vec, color = :blue, lw = 2, alpha=0.7, label = \"\",\n", " grid = true)\n", "plt_emp = plot(title = \"Employment\", c_vec, empl_vec, color = :blue, lw = 2, alpha=0.7, label = \"\",\n", " grid = true)\n", "plt_welf = plot(title = \"Welfare\", c_vec, welfare_vec, color = :blue, lw = 2, alpha=0.7, label = \"\",\n", " grid = true)\n", "\n", "plot(plt_unemp, plt_emp, plt_tax, plt_welf, layout = (2,2), size = (800, 700))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Welfare first increases and then decreases as unemployment benefits rise\n", "\n", "The level that maximizes steady state welfare is approximately 62" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercises" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 1\n", "\n", "Consider an economy with initial stock of workers $ N_0 = 100 $ at the\n", "steady state level of employment in the baseline parameterization\n", "\n", "- $ \\alpha = 0.013 $ \n", "- $ \\lambda = 0.283 $ \n", "- $ b = 0.0124 $ \n", "- $ d = 0.00822 $ \n", "\n", "\n", "(The values for $ \\alpha $ and $ \\lambda $ follow [[DFH06]](zreferences.ipynb#davis2006flow))\n", "\n", "Suppose that in response to new legislation the hiring rate reduces to $ \\lambda = 0.2 $\n", "\n", "Plot the transition dynamics of the unemployment and employment stocks for 50 periods\n", "\n", "Plot the transition dynamics for the rates\n", "\n", "How long does the economy take to converge to its new steady state?\n", "\n", "What is the new steady state level of employment?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 2\n", "\n", "Consider an economy with initial stock of workers $ N_0 = 100 $ at the\n", "steady state level of employment in the baseline parameterization\n", "\n", "Suppose that for 20 periods the birth rate was temporarily high ($ b = 0.0025 $) and then returned to its original level\n", "\n", "Plot the transition dynamics of the unemployment and employment stocks for 50 periods\n", "\n", "Plot the transition dynamics for the rates\n", "\n", "How long does the economy take to return to its original steady state?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Solutions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 1\n", "\n", "We begin by constructing an object containing the default parameters and assigning the\n", "steady state values to x0" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel()\n", "x0 = rate_steady_state(lm)\n", "println(\"Initial Steady State: $x0\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Initialize the simulation values" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "N0 = 100\n", "T = 50" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "New legislation changes $ \\lambda $ to $ 0.2 $" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel(λ = 0.2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "xbar = rate_steady_state(lm) # new steady state\n", "X_path = simulate_stock_path(lm, x0 * N0, T)\n", "x_path = simulate_rate_path(lm, x0, T)\n", "println(\"New Steady State: $xbar\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now plot stocks" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "x1 = X_path[1, :]\n", "x2 = X_path[2, :]\n", "x3 = dropdims(sum(X_path, dims = 1), dims = 1)\n", "\n", "plt_unemp = plot(title = \"Unemployment\", 1:T, x1, color = :blue, grid = true, label = \"\",\n", " bg_inside = :lightgrey)\n", "plt_emp = plot(title = \"Employment\", 1:T, x2, color = :blue, grid = true, label = \"\",\n", " bg_inside = :lightgrey)\n", "plt_labor = plot(title = \"Labor force\", 1:T, x3, color = :blue, grid = true, label = \"\",\n", " bg_inside = :lightgrey)\n", "\n", "plot(plt_unemp, plt_emp, plt_labor, layout = (3, 1), size = (800, 600))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And how the rates evolve" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "plt_unemp = plot(title = \"Unemployment rate\", 1:T, x_path[1,:], color = :blue, grid = true,\n", " label = \"\", bg_inside = :lightgrey)\n", "plot!(plt_unemp, [xbar[1]], linetype = :hline, linestyle = :dash, color =:red, label = \"\")\n", "\n", "plt_emp = plot(title = \"Employment rate\", 1:T, x_path[2,:], color = :blue, grid = true,\n", " label = \"\", bg_inside = :lightgrey)\n", "plot!(plt_emp, [xbar[2]], linetype = :hline, linestyle = :dash, color =:red, label = \"\")\n", "\n", "plot(plt_unemp, plt_emp, layout = (2, 1), size = (800, 600))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that it takes 20 periods for the economy to converge to it’s new\n", "steady state levels" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise 2\n", "\n", "This next exercise has the economy experiencing a boom in entrances to\n", "the labor market and then later returning to the original levels\n", "\n", "For 20 periods the economy has a new entry rate into the labor market\n", "\n", "Let’s start off at the baseline parameterization and record the steady\n", "state" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel()\n", "x0 = rate_steady_state(lm)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here are the other parameters:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "b̂ = 0.003\n", "T̂ = 20" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let’s increase $ b $ to the new value and simulate for 20 periods" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel(b=b̂)\n", "X_path1 = simulate_stock_path(lm, x0 * N0, T̂) # simulate stocks\n", "x_path1 = simulate_rate_path(lm, x0, T̂) # simulate rates" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we reset $ b $ to the original value and then, using the state\n", "after 20 periods for the new initial conditions, we simulate for the\n", "additional 30 periods" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "lm = LakeModel(b = 0.0124)\n", "X_path2 = simulate_stock_path(lm, X_path1[:, end-1], T-T̂+1) # simulate stocks\n", "x_path2 = simulate_rate_path(lm, x_path1[:, end-1], T-T̂+1) # simulate rates" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally we combine these two paths and plot" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "x_path = hcat(x_path1, x_path2[:, 2:end]) # note [2:] to avoid doubling period 20\n", "X_path = hcat(X_path1, X_path2[:, 2:end])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "x1 = X_path[1,:]\n", "x2 = X_path[2,:]\n", "x3 = dropdims(sum(X_path, dims = 1), dims = 1)\n", "\n", "plt_unemp = plot(title = \"Unemployment\", 1:T, x1, color = :blue, lw = 2, alpha = 0.7,\n", " grid = true, label = \"\", bg_inside = :lightgrey)\n", "plot!(plt_unemp, ylims = extrema(x1) .+ (-1, 1))\n", "\n", "plt_emp = plot(title = \"Employment\", 1:T, x2, color = :blue, lw = 2, alpha = 0.7, grid = true,\n", " label = \"\", bg_inside = :lightgrey)\n", "plot!(plt_emp, ylims = extrema(x2) .+ (-1, 1))\n", "\n", "plt_labor = plot(title = \"Labor force\", 1:T, x3, color = :blue, alpha = 0.7, grid = true,\n", " label = \"\", bg_inside = :lightgrey)\n", "plot!(plt_labor, ylims = extrema(x3) .+ (-1, 1))\n", "plot(plt_unemp, plt_emp, plt_labor, layout = (3, 1), size = (800, 600))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And the rates" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide-output": false }, "outputs": [], "source": [ "plt_unemp = plot(title = \"Unemployment Rate\", 1:T, x_path[1,:], color = :blue, grid = true,\n", " label = \"\", bg_inside = :lightgrey, lw = 2)\n", "plot!(plt_unemp, [x0[1]], linetype = :hline, linestyle = :dash, color =:red, label = \"\", lw = 2)\n", "\n", "plt_emp = plot(title = \"Employment Rate\", 1:T, x_path[2,:], color = :blue, grid = true,\n", " label = \"\", bg_inside = :lightgrey, lw = 2)\n", "plot!(plt_emp, [x0[2]], linetype = :hline, linestyle = :dash, color =:red, label = \"\", lw = 2)\n", "\n", "plot(plt_unemp, plt_emp, layout = (2, 1), size = (800, 600))" ] } ], "metadata": { "filename": "lake_model.rst", "kernelspec": { "display_name": "Julia 1.2", "language": "julia", "name": "julia-1.2" }, "title": "A Lake Model of Employment and Unemployment" }, "nbformat": 4, "nbformat_minor": 2 }