From 4a6dd4eeabf272b4431852014cc443872c87c976 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Tue, 27 Feb 2024 11:07:20 +1100 Subject: [PATCH 1/2] update numpy code to remove vectorizations --- lectures/equalizing_difference.md | 156 +++++++++--------------------- 1 file changed, 45 insertions(+), 111 deletions(-) diff --git a/lectures/equalizing_difference.md b/lectures/equalizing_difference.md index 623367cc..f339b856 100644 --- a/lectures/equalizing_difference.md +++ b/lectures/equalizing_difference.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.4 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -29,7 +29,7 @@ To map Friedman's application into our model, think of our high school students Our presentation is "incomplete" in the sense that it is based on a single equation that would be part of set equilibrium conditions of a more fully articulated model. -This ''equalizing difference'' equation determines a college, high-school wage ratio that equalizes present values of a high school educated worker and a college educated worker. +This ''equalizing difference'' equation determines a college-high-school wage ratio that equalizes present values of a high school educated worker and a college educated worker. The idea is that lifetime earnings somehow adjust to make a new high school worker indifferent between going to college and not going to college but instead going to work immmediately. @@ -50,6 +50,8 @@ As usual, we'll start by importing some Python modules. ```{code-cell} ipython3 import numpy as np import matplotlib.pyplot as plt +from collections import namedtuple +from sympy import Symbol, Lambda, symbols ``` ## The indifference condition @@ -206,34 +208,34 @@ prominently including $\gamma_h, \gamma_c, R$. Now let's write some Python code to compute $\phi$ and plot it as a function of some of its determinants. - ```{code-cell} ipython3 -class equalizing_diff: - """ - A class of the equalizing difference model - """ +# Define the namedtuple for the equalizing difference model +EqDiffModel = namedtuple('EqDiffModel', 'R T γ_h γ_c w_h0 D π') + +def create_edm(R=1.05, # Gross rate of return + T=40, # Time horizon + γ_h=1.01, # High-school wage growth + γ_c=1.01, # College wage growth + w_h0=1, # Initial wage (high school) + D=10, # Cost for college + π=None): + + return EqDiffModel(R, T, γ_h, γ_c, w_h0, D, π) + +def compute_gap(model): + R, T, γ_h, γ_c, w_h0, D, π = model + + A_h = (1 - (γ_h/R)**(T+1)) / (1 - γ_h/R) + A_c = (1 - (γ_c/R)**(T-3)) / (1 - γ_c/R) * (γ_c/R)**4 - def __init__(self, R, T, γ_h, γ_c, w_h0, D=0, π=None): - # one switches to the weak model by setting π - self.R, self.γ_h, self.γ_c, self.w_h0, self.D = R, γ_h, γ_c, w_h0, D - self.T, self.π = T, π + # Tweaked model + if π is not None: + A_c = π * A_c - def compute_gap(self): - R, γ_h, γ_c, w_h0, D = self.R, self.γ_h, self.γ_c, self.w_h0, self.D - T, π = self.T, self.π - - A_h = (1 - (γ_h/R)**(T+1)) / (1 - γ_h/R) - A_c = (1 - (γ_c/R)**(T-3)) / (1 - γ_c/R) * (γ_c/R)**4 - - # tweaked model - if π!=None: - A_c = π*A_c - - ϕ = A_h/A_c + D/(w_h0*A_c) - return ϕ + ϕ = A_h / A_c + D / (w_h0 * A_c) + return ϕ ``` - Using vectorization instead of loops, we build some functions to help do comparative statics . @@ -242,75 +244,30 @@ For a given instance of the class, we want to recompute $\phi$ when one paramete Let's do an example. ```{code-cell} ipython3 -# ϕ_R -def ϕ_R(mc, R_new): - mc_new = equalizing_diff(R_new, mc.T, mc.γ_h, mc.γ_c, mc.w_h0, mc.D, mc.π) - return mc_new.compute_gap() - -ϕ_R = np.vectorize(ϕ_R) - -# ϕ_γh -def ϕ_γh(mc, γh_new): - mc_new = equalizing_diff(mc.R, mc.T, γh_new, mc.γ_c, mc.w_h0, mc.D, mc.π) - return mc_new.compute_gap() - -ϕ_γh = np.vectorize(ϕ_γh) - -# ϕ_γc -def ϕ_γc(mc, γc_new): - mc_new = equalizing_diff(mc.R, mc.T, mc.γ_h, γc_new, mc.w_h0, mc.D, mc.π) - return mc_new.compute_gap() +ex1 = create_edm() +gap1 = compute_gap(ex1) -ϕ_γc = np.vectorize(ϕ_γc) - -# ϕ_π -def ϕ_π(mc, π_new): - mc_new = equalizing_diff(mc.R, mc.T, mc.γ_h, mc.γ_c, mc.w_h0, mc.D, π_new) - return mc_new.compute_gap() - -ϕ_π = np.vectorize(ϕ_π) -``` - -```{code-cell} ipython3 -# set benchmark parameters -R = 1.05 -T = 40 -γ_h, γ_c = 1.01, 1.01 -w_h0 = 1 -D = 10 - -# create an instance -ex1 = equalizing_diff(R=R, T=T, γ_h=γ_h, γ_c=γ_c, w_h0=w_h0, D=D) -gap1 = ex1.compute_gap() - -print(gap1) +gap1 ``` Let's not charge for college and recompute $\phi$. The initial college wage premium should go down. - - - ```{code-cell} ipython3 # free college -ex2 = equalizing_diff(R, T, γ_h, γ_c, w_h0, D=0) -gap2 = ex2.compute_gap() -print(gap2) +ex2 = create_edm(D=0) +gap2 = compute_gap(ex2) +gap2 ``` - - Let us construct some graphs that show us how the initial college-high-school wage ratio $\phi$ would change if one of its determinants were to change. -Let's start with the gross interest rate $R$. - - +Let's start with the gross interest rate $R$. ```{code-cell} ipython3 R_arr = np.linspace(1, 1.2, 50) -plt.plot(R_arr, φ_R(ex1, R_arr)) +plt.plot(R_arr, compute_gap(create_edm(R=R_arr))) plt.xlabel(r'$R$') plt.ylabel(r'wage gap') plt.show() @@ -323,11 +280,12 @@ determinants of $\phi$. ```{code-cell} ipython3 γc_arr = np.linspace(1, 1.2, 50) -plt.plot(γc_arr, φ_γc(ex1, γc_arr)) +plt.plot(γc_arr, compute_gap(create_edm(γ_c=γc_arr))) plt.xlabel(r'$\gamma_c$') plt.ylabel(r'wage gap') plt.show() ``` + Notice how the intitial wage gap falls when the rate of growth $\gamma_c$ of college wages rises. The wage gap falls to "equalize" the present values of the two types of career, one as a high school worker, the other as a college worker. @@ -338,33 +296,31 @@ The following graph shows what happens. ```{code-cell} ipython3 γh_arr = np.linspace(1, 1.1, 50) -plt.plot(γh_arr, φ_γh(ex1, γh_arr)) +plt.plot(γh_arr, compute_gap(create_edm(γ_h=γh_arr))) plt.xlabel(r'$\gamma_h$') plt.ylabel(r'wage gap') plt.show() ``` - ## Entrepreneur-worker interpretation Now let's adopt the entrepreneur-worker interpretation of our model. -If the probability that a new business succeeds is $.2$, let's compute the initial wage premium for successful entrepreneurs. +If the probability that a new business succeeds is $0.2$, let's compute the initial wage premium for successful entrepreneurs. ```{code-cell} ipython3 # a model of enterpreneur -ex3 = equalizing_diff(R, T, γ_h, γ_c, w_h0, π=0.2) -gap3 = ex3.compute_gap() +ex3 = create_edm(π=0.2) +gap3 = compute_gap(ex3) -print(gap3) +gap3 ``` Now let's study how the initial wage premium for successful entrepreneurs depend on the success probability. - ```{code-cell} ipython3 π_arr = np.linspace(0.2, 1, 50) -plt.plot(π_arr, φ_π(ex3, π_arr)) +plt.plot(π_arr, compute_gap(create_edm(π=π_arr))) plt.ylabel(r'wage gap') plt.xlabel(r'$\pi$') plt.show() @@ -388,16 +344,10 @@ But for a reader interested in how we can get Python to do all the hard work inv We'll use the Python module 'sympy' to compute partial derivatives of $\phi$ with respect to the parameters that determine it. -Let's import key functions from sympy. - -```{code-cell} ipython3 -from sympy import Symbol, Lambda, symbols -``` - Define symbols ```{code-cell} ipython3 -γ_h, γ_c, w_h0, D = symbols('\gamma_h, \gamma_h_c, w_0^h, D', real=True) +γ_h, γ_c, w_h0, D = symbols('\gamma_h, \gamma_c, w_0^h, D', real=True) R, T = Symbol('R', real=True), Symbol('T', integer=True) ``` @@ -450,8 +400,6 @@ Now let's compute $\frac{\partial \phi}{\partial D}$ and then evaluate it at the Thus, as with our earlier graph, we find that raising $R$ increases the initial college wage premium $\phi$. -+++ - Compute $\frac{\partial \phi}{\partial T}$ and evaluate it a default parameters ```{code-cell} ipython3 @@ -469,8 +417,6 @@ We find that raising $T$ decreases the initial college wage premium $\phi$. This is because college graduates now have longer career lengths to "pay off" the time and other costs they paid to go to college -+++ - Let's compute $\frac{\partial \phi}{\partial γ_h}$ and evaluate it at default parameters. ```{code-cell} ipython3 @@ -486,8 +432,6 @@ Let's compute $\frac{\partial \phi}{\partial γ_h}$ and evaluate it at default p We find that raising $\gamma_h$ increases the initial college wage premium $\phi$, as we did with our earlier graphical analysis. -+++ - Compute $\frac{\partial \phi}{\partial γ_c}$ and evaluate it numerically at default parameter values ```{code-cell} ipython3 @@ -503,8 +447,6 @@ Compute $\frac{\partial \phi}{\partial γ_c}$ and evaluate it numerically at def We find that raising $\gamma_c$ decreases the initial college wage premium $\phi$, as we did with our graphical analysis earlier -+++ - Let's compute $\frac{\partial \phi}{\partial R}$ and evaluate it numerically at default parameter values ```{code-cell} ipython3 @@ -518,12 +460,4 @@ Let's compute $\frac{\partial \phi}{\partial R}$ and evaluate it numerically at ϕ_R_func(D_value, γ_h_value, γ_c_value, R_value, T_value, w_h0_value) ``` -+++ {"tags": []} - -We find that raising the gross interest rate $R$ increases the initial college wage premium $\phi$, as we did with our graphical analysis earlier - - - -```{code-cell} ipython3 - -``` \ No newline at end of file +We find that raising the gross interest rate $R$ increases the initial college wage premium $\phi$, as we did with our graphical analysis earlier \ No newline at end of file From 568dcd50aa13b79a15fb5e3976ac44f760fa8102 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 29 Feb 2024 13:37:10 +1100 Subject: [PATCH 2/2] use more explicit computation and move \pi to later part of the lecture --- lectures/equalizing_difference.md | 143 ++++++++++++++++++------------ 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/lectures/equalizing_difference.md b/lectures/equalizing_difference.md index f339b856..6a756af9 100644 --- a/lectures/equalizing_difference.md +++ b/lectures/equalizing_difference.md @@ -167,38 +167,7 @@ $$ \phi = \frac{A_h}{A_c} . $$ -Soon we'll write Python code to compute $\phi$ and plot it as a function of its determinants. - -But first we'll describe an alternative interpretation of our model that mostly just relabels variables. - - - -## Reinterpreting the model: workers and entrepreneurs - - -We can add a parameter and reinterpret variables to get a model of entrepreneurs versus workers. - -We now let $h$ be the present value of a "worker". - -We define the present value of an entrepreneur to be - -$$ -c_0 = \pi \sum_{t=4}^T R^{-t} w_t^c -$$ - -where $\pi \in (0,1) $ is the probability that an entrepreneur's "project" succeeds. - -For our model of workers and firms, we'll interpret $D$ as the cost of becoming an entrepreneur. - -This cost might include costs of hiring workers, office space, and lawyers. - - - -What we used to call the college, high school wage gap $\phi$ now becomes the ratio -of a successful entrepreneur's earnings to a worker's earnings. - -We'll find that as $\pi$ decreases, $\phi$ increases, indicating that the riskier it is to -be an entrepreuner, the higher must be the reward for a successful project. +In the next section we'll write Python code to compute $\phi$ and plot it as a function of its determinants. ## Computations @@ -210,29 +179,25 @@ Now let's write some Python code to compute $\phi$ and plot it as a function of ```{code-cell} ipython3 # Define the namedtuple for the equalizing difference model -EqDiffModel = namedtuple('EqDiffModel', 'R T γ_h γ_c w_h0 D π') - -def create_edm(R=1.05, # Gross rate of return - T=40, # Time horizon - γ_h=1.01, # High-school wage growth - γ_c=1.01, # College wage growth - w_h0=1, # Initial wage (high school) - D=10, # Cost for college - π=None): +EqDiffModel = namedtuple('EqDiffModel', 'R T γ_h γ_c w_h0 D') + +def create_edm(R=1.05, # gross rate of return + T=40, # time horizon + γ_h=1.01, # high-school wage growth + γ_c=1.01, # college wage growth + w_h0=1, # initial wage (high school) + D=10, # cost for college + ): - return EqDiffModel(R, T, γ_h, γ_c, w_h0, D, π) + return EqDiffModel(R, T, γ_h, γ_c, w_h0, D) def compute_gap(model): - R, T, γ_h, γ_c, w_h0, D, π = model + R, T, γ_h, γ_c, w_h0, D = model A_h = (1 - (γ_h/R)**(T+1)) / (1 - γ_h/R) A_c = (1 - (γ_c/R)**(T-3)) / (1 - γ_c/R) * (γ_c/R)**4 - - # Tweaked model - if π is not None: - A_c = π * A_c - ϕ = A_h / A_c + D / (w_h0 * A_c) + return ϕ ``` @@ -267,7 +232,10 @@ Let's start with the gross interest rate $R$. ```{code-cell} ipython3 R_arr = np.linspace(1, 1.2, 50) -plt.plot(R_arr, compute_gap(create_edm(R=R_arr))) +models = [create_edm(R=r) for r in R_arr] +gaps = [compute_gap(model) for model in models] + +plt.plot(R_arr, gaps) plt.xlabel(r'$R$') plt.ylabel(r'wage gap') plt.show() @@ -280,7 +248,10 @@ determinants of $\phi$. ```{code-cell} ipython3 γc_arr = np.linspace(1, 1.2, 50) -plt.plot(γc_arr, compute_gap(create_edm(γ_c=γc_arr))) +models = [create_edm(γ_c=γ_c) for γ_c in γc_arr] +gaps = [compute_gap(model) for model in models] + +plt.plot(γc_arr, gaps) plt.xlabel(r'$\gamma_c$') plt.ylabel(r'wage gap') plt.show() @@ -296,7 +267,10 @@ The following graph shows what happens. ```{code-cell} ipython3 γh_arr = np.linspace(1, 1.1, 50) -plt.plot(γh_arr, compute_gap(create_edm(γ_h=γh_arr))) +models = [create_edm(γ_h=γ_h) for γ_h in γh_arr] +gaps = [compute_gap(model) for model in models] + +plt.plot(γh_arr, gaps) plt.xlabel(r'$\gamma_h$') plt.ylabel(r'wage gap') plt.show() @@ -304,13 +278,63 @@ plt.show() ## Entrepreneur-worker interpretation -Now let's adopt the entrepreneur-worker interpretation of our model. +We can add a parameter and reinterpret variables to get a model of entrepreneurs versus workers. + +We now let $h$ be the present value of a "worker". + +We define the present value of an entrepreneur to be + +$$ +c_0 = \pi \sum_{t=4}^T R^{-t} w_t^c +$$ + +where $\pi \in (0,1) $ is the probability that an entrepreneur's "project" succeeds. + +For our model of workers and firms, we'll interpret $D$ as the cost of becoming an entrepreneur. + +This cost might include costs of hiring workers, office space, and lawyers. + +What we used to call the college, high school wage gap $\phi$ now becomes the ratio +of a successful entrepreneur's earnings to a worker's earnings. + +We'll find that as $\pi$ decreases, $\phi$ increases, indicating that the riskier it is to +be an entrepreuner, the higher must be the reward for a successful project. + +Now let's adopt the entrepreneur-worker interpretation of our model + +```{code-cell} ipython3 +# Define a model of entrepreneur-worker interpretation +EqDiffModel = namedtuple('EqDiffModel', 'R T γ_h γ_c w_h0 D π') + +def create_edm_π(R=1.05, # gross rate of return + T=40, # time horizon + γ_h=1.01, # high-school wage growth + γ_c=1.01, # college wage growth + w_h0=1, # initial wage (high school) + D=10, # cost for college + π=0 # chance of business success + ): + + return EqDiffModel(R, T, γ_h, γ_c, w_h0, D, π) + + +def compute_gap(model): + R, T, γ_h, γ_c, w_h0, D, π = model + + A_h = (1 - (γ_h/R)**(T+1)) / (1 - γ_h/R) + A_c = (1 - (γ_c/R)**(T-3)) / (1 - γ_c/R) * (γ_c/R)**4 + + # Incorprate chance of success + A_c = π * A_c + + ϕ = A_h / A_c + D / (w_h0 * A_c) + return ϕ +``` If the probability that a new business succeeds is $0.2$, let's compute the initial wage premium for successful entrepreneurs. ```{code-cell} ipython3 -# a model of enterpreneur -ex3 = create_edm(π=0.2) +ex3 = create_edm_π(π=0.2) gap3 = compute_gap(ex3) gap3 @@ -320,7 +344,10 @@ Now let's study how the initial wage premium for successful entrepreneurs depend ```{code-cell} ipython3 π_arr = np.linspace(0.2, 1, 50) -plt.plot(π_arr, compute_gap(create_edm(π=π_arr))) +models = [create_edm_π(π=π) for π in π_arr] +gaps = [compute_gap(model) for model in models] + +plt.plot(π_arr, gaps) plt.ylabel(r'wage gap') plt.xlabel(r'$\pi$') plt.show() @@ -430,7 +457,7 @@ Let's compute $\frac{\partial \phi}{\partial γ_h}$ and evaluate it at default p ϕ_γ_h_func(D_value, γ_h_value, γ_c_value, R_value, T_value, w_h0_value) ``` -We find that raising $\gamma_h$ increases the initial college wage premium $\phi$, as we did with our earlier graphical analysis. +We find that raising $\gamma_h$ increases the initial college wage premium $\phi$, in line with our earlier graphical analysis. Compute $\frac{\partial \phi}{\partial γ_c}$ and evaluate it numerically at default parameter values @@ -445,7 +472,7 @@ Compute $\frac{\partial \phi}{\partial γ_c}$ and evaluate it numerically at def ϕ_γ_c_func(D_value, γ_h_value, γ_c_value, R_value, T_value, w_h0_value) ``` -We find that raising $\gamma_c$ decreases the initial college wage premium $\phi$, as we did with our graphical analysis earlier +We find that raising $\gamma_c$ decreases the initial college wage premium $\phi$, in line with our earlier graphical analysis. Let's compute $\frac{\partial \phi}{\partial R}$ and evaluate it numerically at default parameter values @@ -460,4 +487,4 @@ Let's compute $\frac{\partial \phi}{\partial R}$ and evaluate it numerically at ϕ_R_func(D_value, γ_h_value, γ_c_value, R_value, T_value, w_h0_value) ``` -We find that raising the gross interest rate $R$ increases the initial college wage premium $\phi$, as we did with our graphical analysis earlier \ No newline at end of file +We find that raising the gross interest rate $R$ increases the initial college wage premium $\phi$, in line with our earlier graphical analysis.