43. 工作搜寻 II:搜寻与离职#

除了Anaconda中包含的内容外,本讲座还需要以下库:

!pip install quantecon

Hide code cell output

Requirement already satisfied: quantecon in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (0.10.1)
Requirement already satisfied: numba>=0.49.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from quantecon) (0.61.0)
Requirement already satisfied: numpy>=1.17.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from quantecon) (2.1.3)
Requirement already satisfied: requests in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from quantecon) (2.32.3)
Requirement already satisfied: scipy>=1.5.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from quantecon) (1.15.3)
Requirement already satisfied: sympy in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from quantecon) (1.13.3)
Requirement already satisfied: llvmlite<0.45,>=0.44.0dev0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from numba>=0.49.0->quantecon) (0.44.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->quantecon) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->quantecon) (3.7)
Requirement already satisfied: urllib3<3,>=1.21.1 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->quantecon) (2.3.0)
Requirement already satisfied: certifi>=2017.4.17 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->quantecon) (2025.4.26)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from sympy->quantecon) (1.3.0)

43.1. 概述#

之前的讲座中,我们研究了McCall工作搜寻模型 [McCall, 1970]作为理解失业和劳动者决策的一种方式。

在之前的模型中,我们假设工作是永久性的,这不太符合现实。

本讲座将通过引入离职的可能性来使McCall模型更加贴近现实。

一旦引入离职,个体会有不同的考虑:

  • 失业不仅仅是一个暂时状态,而是随时可能发生的资本损失

  • 失业期间的工作搜寻成为寻找下一份工作的投资

我们还将引入效用函数来更好地刻画劳动者的偏好。

让我们首先导入所需的包:

import matplotlib.pyplot as plt
import matplotlib as mpl
FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf"
mpl.font_manager.fontManager.addfont(FONTPATH)
plt.rcParams['font.family'] = ['Source Han Serif SC']

plt.rcParams["figure.figsize"] = (11, 5)  #设置默认图形大小
import numpy as np
from numba import jit, float64
from numba.experimental import jitclass
from quantecon.distributions import BetaBinomial

43.2. 模型#

该模型与基础McCall工作搜寻模型类似。

它关注一个无限期生存的劳动者的生活,以及:

  • 他或她(为节省一个字符,我们称”他”)在不同工资水平工作的机会

  • 摧毁他当前工作的外生事件

  • 他在失业期间的决策过程

劳动者可以处于两种状态之一:就业或失业。

他希望最大化:

(43.1)#\[{\mathbb E} \sum_{t=0}^\infty \beta^t u(y_t)\]

在这个阶段,与基础模型的唯一区别是我们通过引入效用函数\(u\)增加了偏好的灵活性。

它满足\(u'> 0\)\(u'' < 0\)

43.2.1. 工资过程#

为了简化模型,我们不再像基础模型那样将状态过程和工资过程分开。

我们直接假设工资报价\(\{w_t\}\)是从一个共同分布\(q\)中独立抽取的。

我们用\(\mathbb W\)表示所有可能的工资值集合。

(在后面的章节中,我们会重新引入独立的状态过程\(\{s_t\}\)来驱动随机结果,因为这种方式在处理更复杂的模型时会更加方便。)

43.2.2. 时间安排和决策#

在每个时期开始时,个体可以是:

  • 失业,或

  • 在某个现有工资水平\(w_e\)就业。

在给定时期开始时,观察到当前工资报价\(w_t\)

如果当前就业,劳动者:

  1. 获得效用\(u(w_e)\),并且

  2. 以某个(小的)概率\(\alpha\)被解雇。

如果当前失业,劳动者可以接受或拒绝当前报价\(w_t\)

如果他接受,则立即以工资\(w_t\)开始工作。

如果他拒绝,则获得失业补偿\(c\)

然后过程重复。

备注

我们不允许在就业期间进行工作搜寻—这个主题将在后续讲座中讨论。

43.3. 求解模型#

我们在下文中省略时间下标,用撇号表示下一期的值。

令:

  • \(v(w_e)\)为进入当前时期就业且现有工资为\(w_e\)的劳动者的总终身价值

  • \(h(w)\)为进入当前时期失业且收到工资报价\(w\)的劳动者的总终身价值。

这里的价值是指当劳动者在所有未来时间点都做出最优决策时目标函数(43.1)的值。

我们的首要目标是获得这些函数。

43.3.1. 贝尔曼方程#

假设现在劳动者可以计算函数\(v\)\(h\)并在决策中使用它们。

那么\(v\)\(h\)应该满足:

(43.2)#\[v(w_e) = u(w_e) + \beta \left[ (1-\alpha)v(w_e) + \alpha \sum_{w' \in \mathbb W} h(w') q(w') \right]\]

(43.3)#\[h(w) = \max \left\{ v(w), \, u(c) + \beta \sum_{w' \in \mathbb W} h(w') q(w') \right\}\]

方程(43.2)表达了以工资\(w_e\)就业的价值,包括:

  • 当前报酬\(u(w_e)\)加上

  • 考虑到\(\alpha\)被解雇概率的贴现预期价值

方程(43.3)表达了失业且手中有报价\(w\)的价值,作为两个选项的最大值:接受或拒绝当前报价。

接受使劳动者转为就业,因此获得价值\(v(w)\)

拒绝导致失业补偿和明天的失业。

方程(43.2)(43.3)是该模型的贝尔曼方程。

它们提供了足够的信息来求解\(v\)\(h\)

43.3.2. 简化变换#

与其直接求解这些方程,让我们看看是否能简化它们。

(这个过程将类似于我们对普通McCall模型的第二次尝试,在那里我们简化了贝尔曼方程。)

首先,令:

(43.4)#\[d := \sum_{w' \in \mathbb W} h(w') q(w')\]

为明天失业的预期价值。

我们现在可以将(43.3)写为:

\[ h(w) = \max \left\{ v(w), \, u(c) + \beta d \right\} \]

或者,将时间向前移动一个时期:

\[ \sum_{w' \in \mathbb W} h(w') q(w') = \sum_{w' \in \mathbb W} \max \left\{ v(w'), \, u(c) + \beta d \right\} q(w') \]

再次使用(43.4)现在给出:

(43.5)#\[d = \sum_{w' \in \mathbb W} \max \left\{ v(w'), \, u(c) + \beta d \right\} q(w')\]

最后,(43.2)现在可以重写为:

(43.6)#\[v(w) = u(w) + \beta \left[ (1-\alpha)v(w) + \alpha d \right]\]

在最后一个表达式中,我们将\(w_e\)写为\(w\)以简化符号。

43.3.3. 保留工资#

假设我们可以使用(43.5)(43.6)来求解\(d\)\(v\)

(我们很快就会这样做。)

然后我们可以确定劳动者的最优行为。

(43.3)中,我们看到失业个体接受当前报价\(w\)如果\(v(w) \geq u(c) + \beta d\)。 这表明接受工作的价值超过了继续搜索的预期价值。

由于更高的工资报价不会让个体更差,\(v\)是关于\(w\)的(弱)递增函数。

这意味着个体的最优策略可以用一个保留工资来表示 - 当且仅当工资报价\(w\)超过某个临界值时接受工作:

\[ w \geq \bar w \quad \text{其中} \quad \bar w \text{ 满足 } v(\bar w) = u(c) + \beta d \]

43.3.4. 求解贝尔曼方程#

我们将采用与第一个工作搜寻讲座相同的迭代方法来求解贝尔曼方程。

具体步骤如下:

  1. 首先对\(d\)\(v\)的值进行初始猜测

  2. 将这些猜测值代入(43.5)(43.6)右侧的表达式

  3. 计算得到新的左侧值,并用这些新值更新猜测

  4. 重复以上步骤直到收敛

换句话说,我们使用以下规则进行迭代:

(43.7)#\[d_{n+1} = \sum_{w' \in \mathbb W} \max \left\{ v_n(w'), \, u(c) + \beta d_n \right\} q(w')\]
(43.8)#\[v_{n+1}(w) = u(w) + \beta \left[ (1-\alpha)v_n(w) + \alpha d_n \right]\]

从一些初始条件\(d_0, v_0\)开始。

如前所述,系统总是收敛到真实解—在这种情况下,是满足(43.5)(43.6)\(v\)\(d\)

(可以通过巴拿赫压缩映射定理获得证明。)

43.4. 实现#

让我们实现这个迭代过程。

在代码中,你会看到我们使用一个类来存储与给定模型相关的各种参数和其他对象。

这有助于整理代码并提供一个易于传递给函数的对象。

默认效用函数是CRRA效用函数:

@jit
def u(c, σ=2.0):
    return (c**(1 - σ) - 1) / (1 - σ)

另外,这是一个基于Beta-二项分布的默认工资分布:

n = 60                                  # w的n个可能结果
w_default = np.linspace(10, 20, n)      # 10到20之间的工资
a, b = 600, 400                         # 形状参数
dist = BetaBinomial(n-1, a, b)
q_default = dist.pdf()

这是我们的McCall模型与离职的即时编译类:

mccall_data = [
    ('α', float64),      # 工作离职率
    ('β', float64),      # 贴现因子
    ('c', float64),      # 失业补偿
    ('w', float64[:]),   # 工资值列表
    ('q', float64[:])    # 随机变量w的概率质量函数
]

@jitclass(mccall_data)
class McCallModel:
    """
    存储与给定模型相关的参数和函数。
    """

    def __init__(self, α=0.2, β=0.98, c=6.0, w=w_default, q=q_default):

        self.α, self.β, self.c, self.w, self.q = α, β, c, w, q


    def update(self, v, d):

        α, β, c, w, q = self.α, self.β, self.c, self.w, self.q

        v_new = np.empty_like(v)

        for i in range(len(w)):
            v_new[i] = u(w[i]) + β * ((1 - α) * v[i] + α * d)

        d_new = np.sum(np.maximum(v, u(c) + β * d) * q)

        return v_new, d_new

现在我们迭代直到连续实现之间的差异小于某个小的容差水平。

然后我们将当前迭代作为近似解返回。

@jit
def solve_model(mcm, tol=1e-5, max_iter=2000):
    """
    迭代求解贝尔曼方程直到收敛

    * mcm是McCallModel的实例
    """

    v = np.ones_like(mcm.w)    # v的初始猜测
    d = 1                      # d的初始猜测
    i = 0
    error = tol + 1

    while error > tol and i < max_iter:
        v_new, d_new = mcm.update(v, d)
        error_1 = np.max(np.abs(v_new - v))
        error_2 = np.abs(d_new - d)
        error = max(error_1, error_2)
        v = v_new
        d = d_new
        i += 1

    return v, d

43.4.1. 保留工资:第一次尝试#

个体的最优选择由保留工资总结。

如上所述,保留工资是满足\(v(\bar w) = h\)\(\bar w\),其中\(h := u(c) + \beta d\)是继续值。

让我们比较\(v\)\(h\)看看它们的样子。

我们将使用代码中的默认参数化。

mcm = McCallModel()
v, d = solve_model(mcm)
h = u(mcm.c) + mcm.β * d

fig, ax = plt.subplots()

ax.plot(mcm.w, v, 'b-', lw=2, alpha=0.7, label='$v$')
ax.plot(mcm.w, [h] * len(mcm.w),
        'g-', lw=2, alpha=0.7, label='$h$')
ax.set_xlim(min(mcm.w), max(mcm.w))
ax.legend()

plt.show()
_images/f73fa94c3136fd8a87ac8a322560b1629ce536a9dab0021ffc4a7392481cddf8.png

价值\(v\)是递增的,因为更高的\(w\)在保持就业的条件下产生更高的工资流。

43.4.2. 保留工资:计算#

这是一个函数compute_reservation_wage,它接受McCallModel的实例并返回相关的保留工资。

@jit
def compute_reservation_wage(mcm):
    """
    通过找到最小的w使得v(w) >= h来计算McCall模型的保留工资。

    如果不存在这样的w,则w_bar设置为np.inf。
    """

    v, d = solve_model(mcm)
    h = u(mcm.c) + mcm.β * d

    i = np.searchsorted(v, h, side='right')
    w_bar = mcm.w[i]

    return w_bar

接下来我们将研究保留工资如何随参数变化。

43.5. 参数的影响#

现在我们将研究保留工资如何随不同参数变化。

对于每个参数,我们会展示一副图,并在练习中让你动手来重现这些图形。

43.5.1. 保留工资和失业补偿#

首先,让我们看看\(\bar w\)如何随失业补偿变化。

在下面的图中,我们使用McCallModel类中的默认参数,除了c(它在水平轴上取给定值)

_images/mccall_resw_c.png

正如预期的那样,更高的失业补偿导致劳动者等待更高的工资。

实际上,继续工作搜寻的成本降低了。

43.5.2. 保留工资和贴现#

接下来,让我们研究\(\bar w\)如何随贴现因子变化。

下一个图绘制了与不同\(\beta\)值相关的保留工资

_images/mccall_resw_beta.png

同样,结果是直观的:更有耐心的劳动者会等待更高的工资。

43.5.3. 保留工资和工作破坏#

最后,让我们看看\(\bar w\)如何随工作离职率\(\alpha\)变化。

更高的\(\alpha\)意味着劳动者在就业后每个时期面临终止的可能性更大。

_images/mccall_resw_alpha.png

再次,结果符合我们的直觉。

如果离职率高,那么等待更高工资的收益就会下降。

因此保留工资较低。

43.6. 练习#

练习 43.1

重现上面显示的所有保留工资图。

关于水平轴上的值,使用:

grid_size = 25
c_vals = np.linspace(2, 12, grid_size)         # 失业补偿
beta_vals = np.linspace(0.8, 0.99, grid_size)  # 贴现因子
alpha_vals = np.linspace(0.05, 0.5, grid_size) # 离职率