Skip to content

[mccall_fitted_vfi] Translation Update #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lectures/cake_eating_numerical.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ v(x) = \max_{0\leq c \leq x} \{u(c) + \beta v(x-c)\}

我们将采用的第一种方法是**值函数迭代**。

这是一种**连续逼近**的方法,在我们的{doc}`求职搜索讲座 <mccall_model>`中已经讨论过。
这是一种**连续逼近**的方法,在我们的{doc}`工作搜寻讲座 <mccall_model>`中已经讨论过。

基本思路是:

Expand All @@ -93,7 +93,7 @@ $$
从$v$我们得到$Tv$,将$T$应用于此得到$T^2 v := T (Tv)$,依此类推。

这被称为从初始猜测值$v$开始**迭代贝尔曼算子**。
正如我们在后面的讲座中详细讨论的那样,可以使用Banach收缩映射定理来证明函数序列$T^n v$收敛到Bellman方程的解
正如我们在后面的讲座中详细讨论的那样,可以使用Banach收缩映射定理来证明函数序列$T^n v$收敛到贝尔曼方程的解

### 拟合值函数迭代

Expand All @@ -105,7 +105,7 @@ $$

但这意味着我们必须在无限多个$x$处存储$T^n v(x)$,这通常是不可能的。

为了解决这个问题,我们将使用拟合值函数迭代,这在之前关于{doc}`求职搜索的讲座 <mccall_fitted_vfi>`中已经讨论过。
为了解决这个问题,我们将使用拟合值函数迭代,这在之前关于{doc}`工作搜寻的讲座 <mccall_fitted_vfi>`中已经讨论过。

这个过程如下:

Expand Down
2 changes: 1 addition & 1 deletion lectures/career.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ kernelspec:
</div>
```

# 求职搜索 V:职业选择建模
# 工作搜寻 V:职业选择建模

```{index} single: Modeling; Career Choice
```
Expand Down
2 changes: 1 addition & 1 deletion lectures/jv.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ kernelspec:
</div>
```

# {index}`求职搜索 VI:在职搜索 <single: Job Search VI: On-the-Job Search>`
# {index}`工作搜寻 VI:在职搜索 <single: Job Search VI: On-the-Job Search>`

```{index} single: Models; On-the-Job Search
```
Expand Down
4 changes: 2 additions & 2 deletions lectures/mccall_correlated.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ kernelspec:
</div>
```

# 求职搜索 IV:相关工资报价
# 工作搜寻 IV:相关工资报价

```{contents} 目录
:depth: 2
Expand All @@ -34,7 +34,7 @@ tags: [hide-output]

## 概述

在本讲座中,我们求解一个工资报价由持续性和暂时性成分组成的{doc}`McCall求职搜索模型 <mccall_model>`。
在本讲座中,我们求解一个工资报价由持续性和暂时性成分组成的{doc}`McCall工作搜寻模型 <mccall_model>`。

换句话说,我们放宽了工资随机性在时间上独立的假设。

Expand Down
133 changes: 70 additions & 63 deletions lectures/mccall_fitted_vfi.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,27 @@ kernelspec:
</div>
```

# 求职搜索 III: 拟合值函数迭代
# 工作搜寻 III: 拟合值函数迭代

```{contents} 目录
:depth: 2
```

## 概述

在本讲座中,我们再次研究{doc}`带有离职的McCall求职搜索模型 <mccall_model_with_separation>`,但这次使用连续工资分布
在本讲座中,我们再次研究{doc}`带有离职情形的McCall工作搜寻模型 <mccall_model_with_separation>`,但这次会使用连续工资分布

虽然我们在{doc}`第一个求职搜索讲座 <mccall_model>`的练习中已经简要考虑过连续工资分布,但在那种情况下,这种改变相对来说是微不足道的。
虽然我们在{doc}`第一个工作搜寻讲座 <mccall_model>`的练习中已经简要讨论过连续工资分布,但在那个案例中,这种改变相对来说是微不足道的。

这是因为我们能够将问题简化为求解单个标量值(持续价值)
这是因为我们能够将问题简化为求解单个标量值,即延续价值

在这里,由于分离,变化不那么简单,因为连续的工资分布导致了不可数的无限状态空间
在这一讲座中,由于离职情形的存在,变化不再那么简单,因为连续工资分布会导致不可数的无限状态空间

无限状态空间带来了额外的挑战,特别是在应用值函数迭代(VFI)时。
无限状态空间带来了额外的问题,特别是在应用值函数迭代(VFI)时。

这些挑战将促使我们通过添加插值步骤来修改VFI
这些问题会促使我们通过添加插值这一步骤,来改进VFI方法

VFI和这个插值步骤的组合被称为**拟合值函数迭代**(fitted VFI)。
VFI和这个插值步骤的结合被称为**拟合值函数迭代**(拟合 VFI)。

拟合VFI在实践中非常常见,所以我们将花一些时间来详细研究。

Expand All @@ -57,19 +57,19 @@ from numba.experimental import jitclass

## 算法

该模型与我们{doc}`之前学习的 <mccall_model_with_separation>`带有工作分离的McCall模型相同,只是工资分布是连续的
该模型与我们{doc}`之前学习的 <mccall_model_with_separation>`带有离职情形的McCall模型相同,除了工资分布是连续的

我们将从{ref}`简化转换 <ast_mcm>`后得到的两个Bellman方程开始
我们将从{ref}经`简化变换 <ast_mcm>`后得到的两个贝尔曼方程入手

为了适应连续的工资分布,它们采用以下形式
为了适应连续工资抽样,这两个方程呈现以下形式

```{math}
:label: bell1mcmc

d = \int \max \left\{ v(w'), \, u(c) + \beta d \right\} q(w') d w'
```

以及

```{math}
:label: bell2mcmc
Expand All @@ -82,29 +82,29 @@ v(w) = u(w) + \beta

这里的未知量是函数$v$和标量$d$。

这些方程与我们之前处理的一对Bellman方程的区别在于
这些方程与我们之前处理的一对贝尔曼方程的区别在于

1. 在{eq}`bell1mcmc`中,原来对有限个工资值的求和变成了对无限集合的积分。
1. {eq}`bell2mcmc`中的函数$v$定义在所有$w \in \mathbb R_+$上。

函数 $q$ 在 {eq}`bell1mcmc` 中是工资分布的密度函数
函数 $q$ 在 {eq}`bell1mcmc` 中是工资分布的概率密度函数

其支撑集等于 $\mathbb R_+$。

### 值函数迭代

理论上,我们应该按以下步骤进行:

1. 从一个对 {eq}`bell1mcmc`--{eq}`bell2mcmc` 解的猜测值 $v, d$ 开始
1. 将 $v, d$ 代入 {eq}`bell1mcmc`--{eq}`bell2mcmc` 的右侧
计算左侧以获得更新值 $v', d'$
1. 除非满足某些停止条件,否则设置 $(v, d) = (v', d')$
1. {eq}`bell1mcmc`--{eq}`bell2mcmc` 的解设定初始猜测值 $v, d$ 。
1. 将 $v, d$ 代入 {eq}`bell1mcmc`--{eq}`bell2mcmc` 的右侧表达式
通过计算获得左侧更新值 $v', d'$
1. 若未满足某些终止条件,则令 $(v, d) = (v', d')$
并返回步骤2。

然而,在实施这个程序之前,我们必须面对一个问题:
值函数的迭代既不能被精确计算,也不能被存储在计算机中。
然而,在实施这个算法之前,我们必须面对一个问题:
值函数的迭代序列既不能被精确计算,也不能被存储在计算机中。

要理解这个问题,请考虑 {eq}`bell2mcmc`。
要理解这个问题,请考察 {eq}`bell2mcmc`。

即使 $v$ 是一个已知函数,存储其更新值 $v'$ 的唯一方法
是记录其在每个 $w \in \mathbb R_+$ 处的值 $v'(w)$。
Expand All @@ -113,36 +113,36 @@ v(w) = u(w) + \beta

### 拟合值函数迭代

我们将改用**拟合值函数迭代**。
我们将改用**拟合值函数迭代**的方法

具体步骤如下:

假设已有当前的猜测值 $v$。
假设当前给定猜测值函数 $v$。

我们只在有限个"网格"点 $w_1 < w_2 < \cdots < w_I$ 上记录函数 $v'$ 的值,然后在需要时根据这些信息重构 $v'$。

更具体地说,算法将是
更具体地说,这个算法是

(fvi_alg)=
1. 从一个数组 $\mathbf v$ 开始,该数组表示在某些网格点 $\{w_i\}$ 上的初始值函数猜测值
1. 基于 $\mathbf v$ 和 $\{w_i\}$,通过插值或近似在状态空间 $\mathbb R_+$ 上构建函数 $v$。
1. 从一个数组 $\mathbf v$ 开始,该数组表示值函数在某些网格点 $\{w_i\}$ 上的初始猜测值
1. 基于 $\mathbf v$ 和 $\{w_i\}$,通过插值法或近似法在状态空间 $\mathbb R_+$ 上构建函数 $v$。
1. 在每个网格点 $w_i$ 上获取并记录更新后的函数 $v'(w_i)$ 的样本。
1. 除非满足某些停止条件,否则将此作为新数组并返回步骤1
1. 若未满足某些停止条件,则将其作为新数组并返回步骤1

我们应该如何处理步骤2?

这是一个函数逼近问题,有很多种方法可以解决。
这是一个函数近似问题,有很多种方法可以解决。

这里重要的是函数近似方案不仅要对每个$v$产生良好的近似,而且还要能够很好地配合上述更广泛的迭代算法
对于函数近似方案,我们需要考虑两个关键点:一是要能够准确地近似每个$v$,二是要能够有效地融入到整个迭代算法中

从这两个方面来看,分段线性插值是一个不错的选择
从这两个方面来看,连续分段线性插值法是一个不错的选择

这种方法

1. 能够很好地配合值函数迭代(参见{cite}`gordon1995stable`或{cite}`stachurski2008continuous`)
1. 能保持有用的形状特性,如单调性和凹凸性。
1. 能够很好地配合值函数迭代(参见{cite}`gordon1995stable`或{cite}`stachurski2008continuous`)
1. 能保持关键的形状特性,如单调性和凹凸性。

线性插值将使用[numpy.interp](https://numpy.org/doc/stable/reference/generated/numpy.interp.html)来实现。
线性插值将通过[numpy.interp](https://numpy.org/doc/stable/reference/generated/numpy.interp.html)来实现。

下图展示了在网格点$0, 0.2, 0.4, 0.6, 0.8, 1$上对任意函数进行分段线性插值的情况。

Expand All @@ -159,8 +159,8 @@ def Af(x):

fig, ax = plt.subplots()

ax.plot(f_grid, f(f_grid), 'b-', label='true function')
ax.plot(f_grid, Af(f_grid), 'g-', label='linear approximation')
ax.plot(f_grid, f(f_grid), 'b-', label='真实函数')
ax.plot(f_grid, Af(f_grid), 'g-', label='线性近似')
ax.vlines(c_grid, c_grid * 0, f(c_grid), linestyle='dashed', alpha=0.5)

ax.legend(loc="upper center")
Expand All @@ -171,11 +171,11 @@ plt.show()

## 实现

第一步是为具有分离和连续工资分布的McCall模型构建一个即时编译类
第一步,是为具有离职情况和连续工资分布的McCall模型构建一个jit类

在本应用中,我们将效用函数设定为对数函数,即$u(c) = \ln c$。
在这个应用中,我们将效用函数设定为对数函数,即$u(c) = \ln c$。

我们将为工资采用对数正态分布,当$z$为标准正态分布且$\mu, \sigma$为参数时,$w = \exp(\mu + \sigma z)$。
我们将采用对数正态分布来描述工资水平,其具体形式为$w = \exp(\mu + \sigma z)$,其中$z$服从标准正态分布,$\mu, \sigma$为模型参数

```{code-cell} ipython3
@jit
Expand All @@ -186,15 +186,15 @@ def lognormal_draws(n=1000, μ=2.5, σ=0.5, seed=1234):
return w_draws
```

这是我们的类。
以下是类的定义:

```{code-cell} ipython3
mccall_data_continuous = [
('c', float64), # 失业补偿
('α', float64), # 工作分离率
('α', float64), # 离职率
('β', float64), # 折现因子
('w_grid', float64[:]), # 用于拟合VFI的网格点
('w_draws', float64[:]) # 用于蒙特卡洛的工资抽样
('w_draws', float64[:]) # 用于蒙特卡洛方法的工资抽样
]

@jitclass(mccall_data_continuous)
Expand All @@ -221,10 +221,10 @@ class McCallModelContinuous:
w = self.w_grid
u = lambda x: np.log(x)

# 对数组表示的值函数进行插值
# 对用数组表示的值函数进行插值
vf = lambda x: np.interp(x, w, v)

# 使用蒙特卡洛方法评估积分来更新d
# 使用蒙特卡洛方法进行积分估值来更新d
d_new = np.mean(np.maximum(vf(self.w_draws), u(c) + β * d))

# 更新v
Expand Down Expand Up @@ -261,9 +261,9 @@ def solve_model(mcm, tol=1e-5, max_iter=2000):
return v, d
```

这是一个函数`compute_reservation_wage`,它接收一个`McCallModelContinuous`实例并返回相应的保留工资。
以下是一个函数`compute_reservation_wage`,它接收一个`McCallModelContinuous`实例并返回相应的保留工资。

如果对所有的w都有$v(w) < h$,那么函数返回np.inf
如果对所有的$w$都有$v(w) < h$,那么函数返回`np.inf`。

```{code-cell} ipython3
@jit
Expand All @@ -272,7 +272,7 @@ def compute_reservation_wage(mcm):
通过寻找最小的满足v(w) >= h的w,
计算McCall模型实例的保留工资。

如果不存在这样的w,则w_bar被设为np.inf。
如果不存在这样的w,那么w_bar就被设为np.inf。
"""
u = lambda x: np.log(x)

Expand All @@ -288,25 +288,25 @@ def compute_reservation_wage(mcm):
return w_bar
```

这些练习要求你探索解决方案以及它如何随参数变化
下面的练习中我们探究保留工资随参数变化的情况

## 练习

```{exercise}
:label: mfv_ex1

使用上面的代码探索当工资参数 $\mu$ 发生变化时,保留工资会发生什么变化。
使用上面的代码来探究当工资参数 $\mu$ 发生变化时,保留工资会发生什么变化。

使用默认参数和 `mu_vals = np.linspace(0.0, 2.0, 15)` 中的 $\mu$
使用默认参数以及 `mu_vals = np.linspace(0.0, 2.0, 15)` $\mu$ 的值

保留工资的变化是否如你所预期
保留工资的变化是否符合你的预期
```

```{solution-start} mfv_ex1
:class: dropdown
```

这是一个解决方案
这是一种答案

```{code-cell} ipython3
mcm = McCallModelContinuous()
Expand All @@ -320,41 +320,48 @@ for i, m in enumerate(mu_vals):
w_bar = compute_reservation_wage(mcm)
w_bar_vals[i] = w_bar

ax.set(xlabel='mean', ylabel='reservation wage')
ax.plot(mu_vals, w_bar_vals, label=r'$\bar w$ as a function of $\mu$')
ax.set(xlabel='均值', ylabel='保留工资')
ax.plot(mu_vals, w_bar_vals, label=r'$\bar w$ $\mu$ 的变化')
ax.legend()

plt.show()
```

不出所料,当报价分布向右偏移时,求职者更倾向于等待。
不出所料,当工资报价分布向右偏移时,求职者更倾向于等待。

```{solution-end}
```

```{exercise}
:label: mfv_ex2

让我们现在来考虑求职者如何对波动性的增加做出反应
现在我们来考虑求职者在面对波动性增加时,会做出怎样的反应

为了理解这一点,请计算当工资报价分布在 $(m - s, m + s)$ 上均匀分布,且 $s$ 变化时的保留工资
为了理解这一点,请计算当工资报价在 $(m - s, m + s)$ 上均匀分布且 $s$ 会变化时的保留工资

这里的想法是我们保持均值不变,但扩大分布范围
这里的想法是我们保持均值不变,但扩大支撑集

(这是一种*均值保持扩散*。)
(这是一种*均值保留展开*。)

使用 `s_vals = np.linspace(1.0, 2.0, 15)` 和 `m = 2.0`。

说明你预期保留工资如何随 $s$ 变化。
在分析保留工资如何随 $s$ 变化之前,让我们先思考一下:

现在计算它。结果是否如你所预期?
当工资分布的波动性增加时,求职者面临两个相反的影响:

1. 更高的不确定性可能会让求职者倾向于接受当前工作机会,因为这提供了确定性收入
2. 但另一方面,更大的波动性也意味着出现高工资的机会增加了

你认为哪个影响会占主导地位?保留工资会随着 $s$ 的增加而上升还是下降?

现在,请计算它。结果是否符合你的预期?
```

```{solution-start} mfv_ex2
:class: dropdown
```

这是一个解决方案
这是其中一种解法

```{code-cell} ipython3
mcm = McCallModelContinuous()
Expand All @@ -371,7 +378,7 @@ for i, s in enumerate(s_vals):
w_bar_vals[i] = w_bar

ax.set(xlabel='波动性', ylabel='保留工资')
ax.plot(s_vals, w_bar_vals, label=r'工资波动性函数中的$\bar w$')
ax.plot(s_vals, w_bar_vals, label=r'将工资波动性作为自变量的$\bar w$')
ax.legend()

plt.show()
Expand All @@ -382,7 +389,7 @@ plt.show()

人们可能会认为,更高的波动性会使求职者更倾向于接受给定的工作机会,因为接受工作代表确定性,而等待则意味着风险。

但求职就像持有期权:劳动者只面临上行风险(因为在自由市场中,没有人可以强迫他们接受不好的工作机会)。
但求职就像持有期权:工人只面临上行风险(因为在自由市场中,没有人可以强迫他们接受不好的工作机会)。

更大的波动性意味着更高的上行潜力,这会鼓励求职者继续等待。

Expand Down
Loading
Loading