diff --git a/lectures/_config.yml b/lectures/_config.yml index bad2784e..a17b4c9c 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -91,9 +91,40 @@ sphinx: launch_buttons: colab_url : https://colab.research.google.com intersphinx_mapping: + intersphinx_mapping: + intermediate: + - https://python.quantecon.org/ + - null + pyprog: + - https://python-programming.quantecon.org/ + - null intro: - "https://quantecon.github.io/lecture-intro.zh-cn/" - null + dle: + - https://quantecon.github.io/lecture-dle/ + - null + dps: + - https://quantecon.github.io/lecture-dps/ + - null + eqm: + - https://quantecon.github.io/lecture-eqm/ + - null + stats: + - https://quantecon.github.io/lecture-stats/ + - null + tools: + - https://quantecon.github.io/lecture-tools-techniques/ + - null + dynam: + - https://quantecon.github.io/lecture-dynamics/ + - null + advanced: + - "https://python-advanced.quantecon.org" + - null + jax: + - "https://jax.quantecon.org/" + - null mathjax3_config: tex: macros: diff --git a/lectures/_static/quant-econ.bib b/lectures/_static/quant-econ.bib index b71c6437..0fd46856 100644 --- a/lectures/_static/quant-econ.bib +++ b/lectures/_static/quant-econ.bib @@ -3,6 +3,85 @@ Note: Extended Information (like abstracts, doi, url's etc.) can be found in quant-econ-extendedinfo.bib file in _static/ ### +@article{blume2018case, + title={A case for incomplete markets}, + author={Blume, Lawrence E and Cogley, Timothy and Easley, David A and Sargent, Thomas J and Tsyrennikov, Viktor}, + journal={Journal of Economic Theory}, + volume={178}, + pages={191--221}, + year={2018}, + publisher={Elsevier} +} + +@article{shannon1948mathematical, + title={A mathematical theory of communication}, + author={Shannon, Claude E}, + journal={The Bell system technical journal}, + volume={27}, + number={3}, + pages={379--423}, + year={1948}, + publisher={Nokia Bell Labs} +} + +@article{kullback1951information, + title={On Information and Sufficiency}, + author={Kullback, Solomon and Leibler, Richard A}, + journal={The Annals of Mathematical Statistics}, + volume={22}, + number={1}, + pages={79--86}, + year={1951}, + publisher={JSTOR} +} + +@book{kullback1997information, + title={Information theory and statistics}, + author={Kullback, Solomon}, + year={1997}, + publisher={Courier Corporation} +} + +@book{friedman1953essays, + title={Essays in positive economics}, + author={Friedman, Milton}, + year={1953}, + publisher={University of Chicago press} +} + +@article{alchian1950uncertainty, + title={Uncertainty, evolution, and economic theory}, + author={Alchian, Armen A}, + journal={Journal of political economy}, + volume={58}, + number={3}, + pages={211--221}, + year={1950}, + publisher={The University of Chicago Press} +} + + +@article{blume2006if, + title={If you're so smart, why aren't you rich? Belief selection in complete and incomplete markets}, + author={Blume, Lawrence and Easley, David}, + journal={Econometrica}, + volume={74}, + number={4}, + pages={929--966}, + year={2006}, + publisher={Wiley Online Library} +} + +@article{mendoza1998international, + title={The international ramifications of tax reforms: supply-side economics in a global economy}, + author={Mendoza, Enrique G and Tesar, Linda L}, + journal={American Economic Review}, + pages={226--245}, + year={1998}, + publisher={JSTOR} +} + + @book{intriligator2002mathematical, title={Mathematical optimization and economic theory}, author={Intriligator, Michael D}, @@ -1112,7 +1191,7 @@ @book{Kreps88 address = {Boulder, Colorado} } -@book{Bertekas75, +@book{Bertsekas75, author = {Dmitri Bertsekas}, title = {Dynamic Programming and Stochastic Control}, year = {1975}, @@ -2558,4 +2637,11 @@ @article{hall1971dynamic pages={229--244}, year={1971}, publisher={Wiley-Blackwell} -} \ No newline at end of file +} + +@article{fischer2024improving, + title={Improving the (approximate) sequential probability ratio test by avoiding overshoot}, + author={Fischer, Lasse and Ramdas, Aaditya}, + journal={arXiv preprint arXiv:2410.16076}, + year={2024} +} diff --git a/lectures/_toc.yml b/lectures/_toc.yml index ce85805d..694a32ba 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -1,7 +1,7 @@ format: jb-book root: intro parts: -- caption: 工具与技术 +- caption: 基础工具 numbered: true chapters: - file: sir_model @@ -15,6 +15,7 @@ parts: numbered: true chapters: - file: prob_matrix + - file: stats_examples - file: lln_clt - file: prob_meaning - file: multi_hyper @@ -23,6 +24,26 @@ parts: - file: back_prop - file: rand_resp - file: util_rand_resp +- caption: 贝叶斯定律 + numbered: true + chapters: + - file: bayes_nonconj + - file: ar1_bayes + - file: ar1_turningpts +- caption: 统计与信息论 + numbered: true + chapters: + - file: divergence_measures + - file: likelihood_ratio_process + - file: likelihood_ratio_process_2 + - file: likelihood_var + - file: imp_sample + - file: wald_friedman + - file: wald_friedman_2 + - file: exchangeable + - file: likelihood_bayes + - file: mix_model + - file: navy_captain - caption: 线性规划 numbered: true chapters: @@ -49,12 +70,14 @@ parts: - file: career - file: jv - file: mccall_q + - file: odu - caption: 消费、储蓄与资本 numbered: true chapters: - file: cass_koopmans_1 - file: cass_koopmans_2 - file: cass_fiscal + - file: cass_fiscal_2 - file: ak2 - file: cake_eating_problem - file: cake_eating_numerical @@ -64,23 +87,6 @@ parts: - file: egm_policy_iter - file: ifp - file: ifp_advanced -- caption: 贝叶斯定律 - numbered: true - chapters: - - file: bayes_nonconj - - file: ar1_bayes - - file: ar1_turningpts -- caption: 信息论 - numbered: true - chapters: - - file: odu - - file: likelihood_ratio_process - - file: imp_sample - - file: wald_friedman - - file: exchangeable - - file: likelihood_bayes - - file: mix_model - - file: navy_captain - caption: LQ控制 numbered: true chapters: @@ -99,6 +105,7 @@ parts: - file: markov_perf - file: uncertainty_traps - file: aiyagari + - file: ak_aiyagari - caption: 资产定价与金融 numbered: true chapters: diff --git a/lectures/ak_aiyagari.md b/lectures/ak_aiyagari.md new file mode 100644 index 00000000..bedb48d6 --- /dev/null +++ b/lectures/ak_aiyagari.md @@ -0,0 +1,1436 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.3 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + + +# 长寿、异质性个体、世代交叠模型 + +除了Anaconda中已有的库之外,本讲座还需要以下库 + +```{code-cell} ipython3 +:tags: [skip-execution] + +!pip install jax +``` + +## 概述 + +本讲座描述了一个具有以下特征的世代交叠模型: + +- 不完全市场的竞争均衡决定价格和数量 +- 如 {cite}`auerbach1987dynamic` 所述,个体存活多个时期 +- 如 {cite}`Aiyagari1994` 所述,个体受到无法完全投保的特殊劳动生产率冲击 +- 如 {cite}`auerbach1987dynamic` 第2章和 {doc}`Transitions in an Overlapping Generations Model` 所述,政府财政政策工具包括税率、债务和转移支付 +- 在其他均衡要素中,竞争均衡决定了异质性个体消费、劳动收入和储蓄的横截面密度序列 + + +我们使用该模型研究: + +- 财政政策如何影响不同世代 +- 市场不完全性如何促进预防性储蓄 +- 生命周期储蓄和缓冲储蓄动机如何相互作用 +- 财政政策如何在世代间和世代内重新分配资源 + + +作为本讲座的先决条件,我们推荐两个 quantecon 讲座: + +1. {doc}`advanced:discrete_dp` +2. {doc}`ak2` + +以及可选阅读材料 {doc}`aiyagari` + +像往常一样,让我们先导入一些 Python 模块 + +```{code-cell} ipython3 +from collections import namedtuple +import numpy as np +import matplotlib.pyplot as plt +import jax.numpy as jnp +import jax.scipy as jsp +import jax +``` + +## 经济环境 + +我们首先介绍我们所处的经济环境。 + +### 人口统计和时间 + +我们在离散时间中工作,用 $t = 0, 1, 2, ...$ 表示。 + +每个个体存活 $J = 50$ 个时期,不存在死亡风险。 + +我们用 $j = 0, 1, ..., 49$ 表示年龄,人口规模固定在 $1/J$。 + +### 个体状态变量 + +在时间 $t$ 时,年龄为 $j$ 的个体 $i$ 由两个状态变量表征:资产持有量 $a_{i,j,t}$ 和特质劳动生产率 $\gamma_{i,j,t}$。 + +特质劳动生产率过程遵循一个两状态马尔可夫链,取值为 $\gamma_l$ 和 $\gamma_h$,转移矩阵为 $\Pi$。 + +新生个体在这些生产率状态上的初始分布为 $\pi = [0.5, 0.5]$。 + +### 劳动供给 + +生产率为 $\gamma_{i,j,t}$ 的个体提供 $l(j)\gamma_{i,j,t}$ 单位的有效劳动。 + +$l(j)$ 是一个确定性的年龄特定劳动效率单位曲线。 + +个体的有效劳动供给取决于生命周期效率曲线和特质随机过程。 + +### 初始条件 + +新生个体的初始资产为零 $a_{i,0,t} = 0$。 + +初始特质生产率从分布 $\pi$ 中抽取。 + +个体不留遗产,终期价值函数为 $V_J(a) = 0$。 + +## 生产 + +代表性企业采用规模报酬不变的柯布-道格拉斯生产函数: + +$$Y_t = Z_t K_t^\alpha L_t^{1-\alpha}$$ + +其中: +- $K_t$ 是总资本 + +- $L_t$ 是总劳动效率单位 +- $Z_t$ 是全要素生产率 +- $\alpha$ 是资本份额 + +## 政府 + +政府实行包括债务、税收、转移支付和政府支出的财政政策。 + +政府发行一期债务 $D_t$ 来为其运营提供资金,并通过对劳动和资本收入征收统一税率 $\tau_t$ 来收取收入。 + +政府还实施针对不同年龄组的定额税收或转移支付 $\delta_{j,t}$,可以在不同年龄组之间重新分配资源。 + +此外,政府还进行公共物品和服务的政府采购 $G_t$。 + +政府在时间 $t$ 的预算约束是 + +$$ +D_{t+1} - D_t = r_t D_t + G_t - T_t +$$ + +其中总税收 $T_t$ 满足 + +$$ +T_t = \tau_t w_t L_t + \tau_t r_t(D_t + K_t) + \sum_j \delta_{j,t} +$$ + +## 要素市场活动 + +在每个时间 $t \geq 0$,个体供应劳动和资本。 + +### 特定年龄的劳动供给 + +年龄为 $j \in \{0,1,...,J-1\}$ 的个体根据以下因素供应劳动: +- 其确定性的年龄效率曲线 $l(j)$ +- 其当前特质生产率冲击 $\gamma_{i,j,t}$ + +每个个体供应 $l(j)\gamma_{i,j,t}$ 个有效劳动单位,并按每个有效单位获得竞争性工资 $w_t$,同时需缴纳统一税率 $\tau_t$ 的劳动收入税。 + +### 资产市场参与 + +总结资产市场活动,所有年龄为 $j \in \{0,1,...,J-1\}$ 的个体都可以: + +- 持有资产 $a_{i,j,t}$(受借贷约束) +- 在储蓄上获得无风险的单期回报率 $r_t$ +- 按统一税率 $\tau_t$ 缴纳资本所得税 +- 获得或支付与年龄相关的转移支付 $\delta_{j,t}$ + +### 主要特征 + +*生命周期模式*影响不同年龄的经济行为: + + - 劳动生产率根据年龄曲线 $l(j)$ 系统性变化,而资产持有量通常遵循工作年龄段积累、退休年龄段消耗的生命周期模式。 + + - 特定年龄的财政转移支付 $\delta_{j,t}$ 在代际间重新分配资源。 + +*同期群组内部异质性*导致同龄人之间的差异: + + - 同龄人因特异性生产率冲击的不同历史、当前生产率 $\gamma_{i,j,t}$,以及由此产生的劳动收入和金融财富的差异,而在资产持有量 $a_{i,j,t}$ 上存在差异。 + +*跨期群组互动*通过市场聚合决定均衡结果: + + - 所有群组共同参与要素市场,所有群组的资产供给决定总资本,所有群组的有效劳动供给决定总劳动。 + + - 均衡价格反映生命周期和再分配的双重力量。 + +## 代表性企业的问题 + +代表性企业选择资本和有效劳动以最大化利润 + +$$ +\max_{K,L} Z_t K_t^\alpha L_t^{1-\alpha} - r_t K_t - w_t L_t +$$ + +一阶必要条件意味着 + +$$ +w_t = (1-\alpha)Z_t(K_t/L_t)^\alpha +$$ + +和 + +$$ +r_t = \alpha Z_t(K_t/L_t)^{\alpha-1} +$$ + +## 家庭问题 + +家庭的价值函数满足贝尔曼方程 + +$$ +V_{j,t}(a, \gamma) = \max_{c,a'} \{u(c) + \beta\mathbb{E}[V_{j+1,t+1}(a', \gamma')]\} +$$ + +其中最大化受约束于 + +$$ +c + a' = (1 + r_t(1-\tau_t))a + (1-\tau_t)w_t l(j)\gamma - \delta_{j,t} +$$ +$$ +c \geq 0 +$$ + +以及终端条件 +$V_{J,t}(a, \gamma) = 0$ + +## 人口动态 + +资产持有量和特质劳动生产率的联合概率密度函数$\mu_{j,t}(a,\gamma)$按如下方式演化: + +- 对于新生人口$(j=0)$: + +$$ +\mu_{0,t+1}(a',\gamma') =\begin{cases} +\pi(\gamma') &\text{ 若 }a'=0\text{, }\\ + 0, & \text{其他情况} + \end{cases} +$$ + +- 对于其他群组: + + $$ + \mu_{j+1,t+1}(a',\gamma') = \int {\bf 1}_{\sigma_{j,t}(a,\gamma)=a'}\Pi(\gamma,\gamma')\mu_{j,t}(a,\gamma)d(a,\gamma) + $$ + +其中$\sigma_{j,t}(a,\gamma)$是最优储蓄策略函数。 + +## 均衡 + +均衡包括: +- 价值函数$V_{j,t}$ +- 策略函数$\sigma_{j,t}$ +- 联合概率分布$\mu_{j,t}$ +- 价格$r_t, w_t$ +- 政府政策$\tau_t, D_t, \delta_{j,t}, G_t$ + +满足以下条件: + +- 在给定价格和政府政策的情况下,价值函数和策略函数解决家庭问题 +- 在给定价格的情况下,代表性企业实现利润最大化 + +- 政府预算约束得到满足 +- 市场出清: + - 资产市场:$K_t = \sum_j \int a \mu_{j,t}(a,\gamma)d(a,\gamma) - D_t$ + - 劳动力市场:$L_t = \sum_j \int l(j)\gamma \mu_{j,t}(a,\gamma)d(a,\gamma)$ + +相对于{doc}`Transitions in an Overlapping Generations Model`中提出的模型,本模型增加了: +- 由生产率冲击导致的代内异质性 +- 预防性储蓄动机 +- 更多的再分配效应 +- 更复杂的转型动态 + +## 实现 + +使用{doc}`advanced:discrete_dp`中的工具,我们通过将值函数迭代与均衡价格确定相结合来求解我们的模型。 + +一个合理的方法是在寻找市场出清价格的外循环中嵌套一个离散动态规划求解器。 + +对于候选序列的利率$r_t$和工资$w_t$,我们可以使用值函数迭代或策略迭代来求解个体家庭的动态规划问题,从而获得最优策略函数。 + +然后我们推导出每个年龄群体的资产持有量和特质劳动效率单位的相关平稳联合概率分布。 + +这将给我们提供总资本供给(来自家庭储蓄)和劳动力供给(来自年龄效率曲线和生产率冲击)。 + +然后我们可以将这些与企业的资本和劳动力需求进行比较,计算要素市场供给和需求之间的偏差,然后更新价格猜测,直到找到市场出清价格。 + +为了构建转型动态,我们可以通过使用_向后归纳法_计算价值函数和政策函数,以及使用_向前迭代法_计算主体在各状态之间的分布,来计算时变价格序列: + +1. 外循环(市场出清) + * 猜测初始价格($r_t, w_t$) + * 迭代直到资产和劳动力市场出清 + * 使用企业的一阶必要条件来更新价格 + +2. 内循环(个体动态规划) + * 对每个年龄群组: + - 离散化资产和生产率状态空间 + - 使用价值函数迭代或政策迭代 + - 求解最优储蓄政策 + - 计算稳态分布 + +3. 聚合 + * 在每个群组内对个体状态求和 + * 跨群组求和得到 + - 总资本供给,和 + - 总有效劳动力供给 + * 考虑人口权重 $1/J$ + +4. 转型动态 + * 向后归纳: + - 从最终稳态开始 + - 求解价值函数序列 + * 向前迭代: + - 从初始分布开始 + - 追踪群组分布随时间变化 + * 每期市场出清: + - 求解价格序列 + - 更新直到所有市场在所有期都出清 + +我们通过定义描述偏好、企业和政府预算约束的辅助函数来开始编码。 + +```{code-cell} ipython3 +ϕ, k_bar = 0., 0. + +@jax.jit +def V_bar(a): + "根据资产持有量确定的终端价值函数。" + + return - ϕ * (a - k_bar) ** 2 +``` + +```{code-cell} ipython3 +ν = 0.5 + +@jax.jit +def u(c): + "消费带来的效用。" + + return c ** (1 - ν) / (1 - ν) + +l1, l2, l3 = 0.5, 0.05, -0.0008 + +@jax.jit +def l(j): + "年龄相关的工资曲线。" + + return l1 + l2 * j + l3 * j ** 2 +``` + +让我们定义一个包含控制生产技术参数的`Firm`命名元组。 + +```{code-cell} ipython3 +Firm = namedtuple("Firm", ("α", "Z")) + +def create_firm(α=0.3, Z=1): + + return Firm(α=α, Z=Z) +``` + +```{code-cell} ipython3 +firm = create_firm() +``` + +以下辅助函数将从代表性企业的一阶必要条件中得出的要素投入($K, L$)和要素价格($w, r$)联系起来。 + +```{code-cell} ipython3 +@jax.jit +def KL_to_r(K, L, firm): + + α, Z = firm + + return Z * α * (K / L) ** (α - 1) + +@jax.jit +def KL_to_w(K, L, firm): + + α, Z = firm + + return Z * (1 - α) * (K / L) ** α +``` + +我们使用函数`find_τ`来寻找能够平衡政府预算约束的统一税率,这个税率取决于其他政策变量,包括债务水平、政府支出和转移支付。 + +```{code-cell} ipython3 +@jax.jit +def find_τ(policy, price, aggs): + + D, D_next, G, δ = policy + r, w = price + K, L = aggs + + num = r * D + G - D_next + D - δ.sum(axis=-1) + denom = w * L + r * (D + K) + + return num / denom +``` + +我们使用命名元组`Household`来存储表征家庭问题的参数。 + +```{code-cell} ipython3 +Household = namedtuple("Household", ("j_grid", "a_grid", "γ_grid", + "Π", "β", "init_μ", "VJ")) + +def create_household( + a_min=0., a_max=10, a_size=200, + Π=[[0.9, 0.1], [0.1, 0.9]], + γ_grid=[0.5, 1.5], + β=0.96, J=50 + ): + + j_grid = jnp.arange(J) + + a_grid = jnp.linspace(a_min, a_max, a_size) + + γ_grid, Π = map(jnp.array, (γ_grid, Π)) + γ_size = len(γ_grid) + + # 新生人口的分布 + init_μ = jnp.zeros((a_size * γ_size)) + + # 新生者的初始资产为零 + # 且γ的概率相等 + init_μ = init_μ.at[:γ_size].set(1 / γ_size) + + # 终端值V_bar(a) + VJ = jnp.empty(a_size * γ_size) + for a_i in range(a_size): + a = a_grid[a_i] + VJ = VJ.at[a_i*γ_size:(a_i+1)*γ_size].set(V_bar(a)) + + return Household(j_grid=j_grid, a_grid=a_grid, γ_grid=γ_grid, + Π=Π, β=β, init_μ=init_μ, VJ=VJ) +``` + +```{code-cell} ipython3 +hh = create_household() +``` + +我们应用离散状态动态规划工具。 + +初始步骤包括为我们的离散化贝尔曼方程准备奖励矩阵 $R$ 和转移矩阵 $Q$。 + +```{code-cell} ipython3 +@jax.jit +def populate_Q(household): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + + num_state = a_grid.size * γ_grid.size + num_action = a_grid.size + + Q = jsp.linalg.block_diag(*[Π]*a_grid.size) + Q = Q.reshape((num_state, num_action, γ_grid.size)) + Q = jnp.tile(Q, a_grid.size).T + + return Q + +@jax.jit +def populate_R(j, r, w, τ, δ, household): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + + num_state = a_grid.size * γ_grid.size + num_action = a_grid.size + + a = jnp.reshape(a_grid, (a_grid.size, 1, 1)) + γ = jnp.reshape(γ_grid, (1, γ_grid.size, 1)) + ap = jnp.reshape(a_grid, (1, 1, a_grid.size)) + c = (1 + r*(1-τ)) * a + (1-τ) * w * l(j) * γ - δ[j] - ap + + return jnp.reshape(jnp.where(c > 0, u(c), -jnp.inf), + (num_state, num_action)) +``` + +## 计算稳态 + +我们首先计算一个稳态。 + +给定价格和税收的猜测值,我们可以使用反向归纳法来求解所有年龄段的价值函数以及最优消费和储蓄策略。 + +函数`backwards_opt`通过反向应用离散化的贝尔曼算子来求解最优值。 + +我们使用`jax.lax.scan`来高效地进行顺序和递归计算。 + +```{code-cell} ipython3 +@jax.jit +def backwards_opt(prices, taxes, household, Q): + + r, w = prices + τ, δ = taxes + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + J = j_grid.size + + num_state = a_grid.size * γ_grid.size + num_action = a_grid.size + + def bellman_operator_j(V_next, j): + "在给定Vj+1的情况下,求解年龄j时的家庭优化问题" + + Rj = populate_R(j, r, w, τ, δ, household) + vals = Rj + β * Q.dot(V_next) + σ_j = jnp.argmax(vals, axis=1) + V_j = vals[jnp.arange(num_state), σ_j] + + return V_j, (V_j, σ_j) + + js = jnp.arange(J-1, -1, -1) + init_V = VJ + + # 从年龄J迭代到1 + _, outputs = jax.lax.scan(bellman_operator_j, init_V, js) + V, σ = outputs + V = V[::-1] + σ = σ[::-1] + + return V, σ +``` + +```{code-cell} ipython3 +r, w = 0.05, 1 +τ, δ = 0.15, np.zeros(hh.j_grid.size) + +Q = populate_Q(hh) +``` + +```{code-cell} ipython3 +V, σ = backwards_opt([r, w], [τ, δ], hh, Q) +``` + +让我们用 `block_until_ready()` 来计时,以确保所有 JAX 运算都已完成 + +```{code-cell} ipython3 +%time backwards_opt([r, w], [τ, δ], hh, Q)[0].block_until_ready(); +``` + +从每个群组的最优消费和储蓄选择出发,我们可以计算出稳态下资产水平和特质生产率水平的联合概率分布。 + +```{code-cell} ipython3 +@jax.jit +def popu_dist(σ, household, Q): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + + J = hh.j_grid.size + num_state = hh.a_grid.size * hh.γ_grid.size + + def update_popu_j(μ_j, j): + "更新从年龄j到j+1的人口分布" + + Qσ = Q[jnp.arange(num_state), σ[j]] + μ_next = μ_j @ Qσ + + return μ_next, μ_next + + js = jnp.arange(J-1) + + # 从年龄1迭代到J + _, μ = jax.lax.scan(update_popu_j, init_μ, js) + μ = jnp.concatenate([init_μ[jnp.newaxis], μ], axis=0) + + return μ +``` + +```{code-cell} ipython3 +μ = popu_dist(σ, hh, Q) +``` + +让我们计时计算过程 + +```{code-cell} ipython3 +%time popu_dist(σ, hh, Q)[0].block_until_ready(); +``` + +下面我们绘制每个年龄组的储蓄边际分布。 + + +```{code-cell} ipython3 +for j in [0, 5, 20, 45, 49]: + plt.plot(hh.a_grid, jnp.sum(μ[j].reshape((hh.a_grid.size, hh.γ_grid.size)), axis=1), label=f'j={j}') + +plt.legend() +plt.xlabel('a') + +plt.title(r'marginal distribution over a, $\sum_\gamma \mu_j(a, \gamma)$') +plt.xlim([0, 8]) +plt.ylim([0, 0.1]) + +plt.show() +``` + +这些边际分布确认新进入经济体的个体没有任何资产持有。 + + * 蓝色的 $j=0$ 分布仅在 $a=0$ 处有质量。 + +随着个体年龄增长,他们最初会逐渐积累资产。 + + * 橙色的 $j=5$ 分布在正但较低的资产水平上有正质量 + * 绿色的 $j=20$ 分布在更广范围的资产水平上有正质量 + * 红色的 $j=45$ 分布范围更宽 + +在较晚年龄,他们会逐渐减少其资产持有。 + +* 紫色的 $j=49$ 分布说明了这一点 + +在生命末期,他们将耗尽所有资产。 + +让我们现在看看产生前述不同年龄资产边际分布的年龄特定最优储蓄政策。 + +我们将用以下Python代码绘制一些储蓄函数。 + +```{code-cell} ipython3 +σ_reshaped = σ.reshape(hh.j_grid.size, hh.a_grid.size, hh.γ_grid.size) +j_labels = [f'j={j}' for j in [0, 5, 20, 45, 49]] + +fig, axs = plt.subplots(1, 2, figsize=(14, 5)) + +axs[0].plot(hh.a_grid, hh.a_grid[σ_reshaped[[0, 5, 20, 45, 49], :, 0].T]) +axs[0].plot(hh.a_grid, hh.a_grid, '--') +axs[0].set_xlabel("$a_{j}$") +axs[0].set_ylabel("$a^*_{j+1}$") +axs[0].legend(j_labels+['45 degree line']) +axs[0].set_title(r"Optimal saving policy, low $\gamma$") + +axs[1].plot(hh.a_grid, hh.a_grid[σ_reshaped[[0, 5, 20, 45, 49], :, 1].T]) +axs[1].plot(hh.a_grid, hh.a_grid, '--') +axs[1].set_xlabel("$a_{j}$") +axs[1].set_ylabel("$a^*_{j+1}$") +axs[1].legend(j_labels+['45 degree line']) +axs[1].set_title(r"Optimal saving policy, high $\gamma$") + +plt.show() +``` + +从隐含的平稳人口分布中,我们可以计算总劳动供给 $L$ 和私人储蓄 $A$。 + +```{code-cell} ipython3 +@jax.jit +def compute_aggregates(μ, household): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + + J, a_size, γ_size = j_grid.size, a_grid.size, γ_grid.size + + μ = μ.reshape((J, hh.a_grid.size, hh.γ_grid.size)) + + # 计算私人储蓄 + a = a_grid.reshape((1, a_size, 1)) + A = (a * μ).sum() / J + + γ = γ_grid.reshape((1, 1, γ_size)) + lj = l(j_grid).reshape((J, 1, 1)) + L = (lj * γ * μ).sum() / J + + return A, L +``` + +```{code-cell} ipython3 +A, L = compute_aggregates(μ, hh) +A, L +``` + +该经济体中的资本存量等于$A-D$。 + +```{code-cell} ipython3 +D = 0 +K = A - D +``` + +企业的最优条件意味着利率 $r$ 和工资率 $w$。 + +```{code-cell} ipython3 +KL_to_r(K, L, firm), KL_to_w(K, L, firm) +``` + +隐含价格$(r,w)$与我们的猜测不同,所以我们必须更新猜测并迭代直到找到一个不动点。 + +这是我们的外层循环。 + +```{code-cell} ipython3 +@jax.jit +def find_ss(household, firm, pol_target, Q, tol=1e-6, verbose=False): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + J = j_grid.size + num_state = a_grid.size * γ_grid.size + + D, G, δ = pol_target + + # 价格的初始猜测 + r, w = 0.05, 1. + + # τ的初始猜测 + τ = 0.15 + + def cond_fn(state): + "收敛标准。" + + V, σ, μ, K, L, r, w, τ, D, G, δ, r_old, w_old = state + + error = (r - r_old) ** 2 + (w - w_old) ** 2 + + return error > tol + + def body_fn(state): + "迭代的主体部分。" + + V, σ, μ, K, L, r, w, τ, D, G, δ, r_old, w_old = state + r_old, w_old, τ_old = r, w, τ + + # 家庭最优决策和价值 + V, σ = backwards_opt([r, w], [τ, δ], hh, Q) + + # 计算稳态分布 + μ = popu_dist(σ, hh, Q) + + # 计算总量 + A, L = compute_aggregates(μ, hh) + K = A - D + + # 更新价格 + r, w = KL_to_r(K, L, firm), KL_to_w(K, L, firm) + + # 寻找τ + D_next = D + τ = find_τ([D, D_next, G, δ], + [r, w], + [K, L]) + + r = (r + r_old) / 2 + w = (w + w_old) / 2 + + return V, σ, μ, K, L, r, w, τ, D, G, δ, r_old, w_old + + # 初始状态 + V = jnp.empty((J, num_state), dtype=float) + σ = jnp.empty((J, num_state), dtype=int) + μ = jnp.empty((J, num_state), dtype=float) + + K, L = 1., 1. + initial_state = (V, σ, μ, K, L, r, w, τ, D, G, δ, r-1, w-1) + V, σ, μ, K, L, r, w, τ, D, G, δ, _, _ = jax.lax.while_loop( + cond_fn, body_fn, initial_state) + + return V, σ, μ, K, L, r, w, τ, D, G, δ +``` + +```{code-cell} ipython3 +ss1 = find_ss(hh, firm, [0, 0.1, np.zeros(hh.j_grid.size)], Q, verbose=True) +``` + +让我们计时计算过程 + +```{code-cell} ipython3 +%time find_ss(hh, firm, [0, 0.1, np.zeros(hh.j_grid.size)], Q)[0].block_until_ready(); +``` + +```{code-cell} ipython3 +hh_out_ss1 = ss1[:3] +quant_ss1 = ss1[3:5] +price_ss1 = ss1[5:7] +policy_ss1 = ss1[7:11] +``` + +```{code-cell} ipython3 +# V, σ, μ +V_ss1, σ_ss1, μ_ss1 = hh_out_ss1 +``` + +```{code-cell} ipython3 +# K, L +K_ss1, L_ss1 = quant_ss1 + +K_ss1, L_ss1 +``` + +```{code-cell} ipython3 +# 利率,工资 +r_ss1, w_ss1 = price_ss1 + +r_ss1, w_ss1 +``` + +```{code-cell} ipython3 +# τ, D, G, δ +τ_ss1, D_ss1, G_ss1, δ_ss1 = policy_ss1 + +τ_ss1, D_ss1, G_ss1, δ_ss1 +``` + +## 转换动态 + +我们使用`path_iteration`函数计算转换动态。 + +在外循环中,我们对价格和税收的猜测值进行迭代。 + +在内循环中,我们计算每个年龄组$j$在每个时间$t$的最优消费和储蓄选择,然后找出资产和生产力联合分布的隐含演变。 + +然后,我们根据经济中的总劳动供给和资本存量更新价格和税收的猜测值。 + +我们使用`solve_backwards`来求解给定价格和税收序列下的最优储蓄选择,并使用`simulate_forward`来计算联合分布的演变。 + +我们需要两个稳态作为输入:初始稳态为`simulate_forward`提供初始条件,最终稳态为`solve_backwards`提供延续值。 + +```{code-cell} ipython3 +@jax.jit +def bellman_operator(prices, taxes, V_next, household, Q): + + r, w = prices + τ, δ = taxes + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + J = j_grid.size + + num_state = a_grid.size * γ_grid.size + num_action = a_grid.size + + def bellman_operator_j(j): + Rj = populate_R(j, r, w, τ, δ, household) + vals = Rj + β * Q.dot(V_next[j+1]) + σ_j = jnp.argmax(vals, axis=1) + V_j = vals[jnp.arange(num_state), σ_j] + + return V_j, σ_j + + V, σ = jax.vmap(bellman_operator_j, (0,))(jnp.arange(J-1)) + + # 最后的生命阶段 + j = J-1 + Rj = populate_R(j, r, w, τ, δ, household) + vals = Rj + β * Q.dot(VJ) + σ = jnp.concatenate([σ, jnp.argmax(vals, axis=1)[jnp.newaxis]]) + V = jnp.concatenate([V, vals[jnp.arange(num_state), σ[j]][jnp.newaxis]]) + + return V, σ +``` + +```{code-cell} ipython3 +@jax.jit +def solve_backwards(V_ss2, σ_ss2, household, firm, price_seq, pol_seq, Q): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + J = j_grid.size + num_state = a_grid.size * γ_grid.size + + τ_seq, D_seq, G_seq, δ_seq = pol_seq + r_seq, w_seq = price_seq + + T = r_seq.size + + def solve_backwards_t(V_next, t): + + prices = (r_seq[t], w_seq[t]) + taxes = (τ_seq[t], δ_seq[t]) + V, σ = bellman_operator(prices, taxes, V_next, household, Q) + + return V, (V,σ) + + ts = jnp.arange(T-2, -1, -1) + init_V = V_ss2 + + _, outputs = jax.lax.scan(solve_backwards_t, init_V, ts) + V_seq, σ_seq = outputs + V_seq = V_seq[::-1] + σ_seq = σ_seq[::-1] + + V_seq = jnp.concatenate([V_seq, V_ss2[jnp.newaxis]]) + σ_seq = jnp.concatenate([σ_seq, σ_ss2[jnp.newaxis]]) + + return V_seq, σ_seq +``` + +```{code-cell} ipython3 +@jax.jit +def population_evolution(σt, μt, household, Q): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + + J = hh.j_grid.size + num_state = hh.a_grid.size * hh.γ_grid.size + + def population_evolution_j(j): + + Qσ = Q[jnp.arange(num_state), σt[j]] + μ_next = μt[j] @ Qσ + + return μ_next + + μ_next = jax.vmap(population_evolution_j, (0,))(jnp.arange(J-1)) + μ_next = jnp.concatenate([init_μ[jnp.newaxis], μ_next]) + + return μ_next +``` + +```{code-cell} ipython3 +@jax.jit +def simulate_forwards(σ_seq, D_seq, μ_ss1, K_ss1, L_ss1, household, Q): + + j_grid, a_grid, γ_grid, Π, β, init_μ, VJ = household + + J, num_state = μ_ss1.shape + + T = σ_seq.shape[0] + + def simulate_forwards_t(μ, t): + + μ_next = population_evolution(σ_seq[t], μ, household, Q) + + A, L = compute_aggregates(μ_next, household) + K = A - D_seq[t+1] + + return μ_next, (μ_next, K, L) + + ts = jnp.arange(T-1) + init_μ = μ_ss1 + + _, outputs = jax.lax.scan(simulate_forwards_t, init_μ, ts) + μ_seq, K_seq, L_seq = outputs + + μ_seq = jnp.concatenate([μ_ss1[jnp.newaxis], μ_seq]) + K_seq = jnp.concatenate([K_ss1[jnp.newaxis], K_seq]) + L_seq = jnp.concatenate([L_ss1[jnp.newaxis], L_seq]) + + return μ_seq, K_seq, L_seq +``` + +以下算法描述了路径迭代程序: + +```{prf:algorithm} AK-Aiyagari过渡路径算法 +:label: ak-aiyagari-algorithm + +**输入** 给定初始稳态$ss_1$,最终稳态$ss_2$,时间范围$T$,和政策序列$(D, G, \delta)$ + +**输出** 计算价值函数$V$、政策函数$\sigma$、分布$\mu$和价格$(r, w, \tau)$的均衡过渡路径 + +1. 从稳态初始化: + - $(V_1, \sigma_1, \mu_1) \leftarrow ss_1$ *(初始稳态)* + - $(V_2, \sigma_2, \mu_2) \leftarrow ss_2$ *(最终稳态)* + - $(r, w, \tau) \leftarrow initialize\_prices(T)$ *(线性插值)* + - $error \leftarrow \infty$, $i \leftarrow 0$ + +2. **当** $error > \varepsilon$ 或 $i \leq max\_iter$ 时: + + 1. $i \leftarrow i + 1$ + 2. $(r_{\text{old}}, w_{\text{old}}, \tau_{\text{old}}) \leftarrow (r, w, \tau)$ + + 3. **向后归纳:** 对于 $t \in [T, 1]$: + - 对于 $j \in [0, J-1]$ *(年龄组)*: + - $V[t,j] \leftarrow \max_{a'} \{u(c) + \beta\mathbb{E}[V[t+1,j+1]]\}$ + - $\sigma[t,j] \leftarrow \arg\max_{a'} \{u(c) + \beta\mathbb{E}[V[t+1,j+1]]\}$ + + 4. **向前模拟:** 对于 $t \in [1, T]$: + - $\mu[t] \leftarrow \Gamma(\sigma[t], \mu[t-1])$ *(分布演化)* + - $K[t] \leftarrow \int a \, d\mu[t] - D[t]$ *(总资本)* + - $L[t] \leftarrow \int l(j)\gamma \, d\mu[t]$ *(总劳动)* + +- $r[t] \leftarrow \alpha Z(K[t]/L[t])^{\alpha-1}$ *(利率)* + - $w[t] \leftarrow (1-\alpha)Z(K[t]/L[t])^{\alpha}$ *(工资率)* + - $\tau[t] \leftarrow solve\_budget(r[t],w[t],K[t],L[t],D[t],G[t])$ + + 5. 计算收敛指标: + - $error \leftarrow \|r - r_{\text{old}}\| + \|w - w_{\text{old}}\| + \|\tau - \tau_{\text{old}}\|$ + + 6. 使用阻尼更新价格: + - $r \leftarrow \lambda r + (1-\lambda)r_{\text{old}}$ + - $w \leftarrow \lambda w + (1-\lambda)w_{\text{old}}$ + - $\tau \leftarrow \lambda \tau + (1-\lambda)\tau_{\text{old}}$ + +3. **返回** $(V, \sigma, \mu, r, w, \tau)$ +``` + +```{code-cell} ipython3 +def path_iteration(ss1, ss2, pol_target, household, firm, Q, tol=1e-4, verbose=False): + + # 起点:初始稳态 + V_ss1, σ_ss1, μ_ss1 = ss1[:3] + K_ss1, L_ss1 = ss1[3:5] + r_ss1, w_ss1 = ss1[5:7] + τ_ss1, D_ss1, G_ss1, δ_ss1 = ss1[7:11] + + # 终点:收敛的新稳态 + V_ss2, σ_ss2, μ_ss2 = ss2[:3] + K_ss2, L_ss2 = ss2[3:5] + r_ss2, w_ss2 = ss2[5:7] + τ_ss2, D_ss2, G_ss2, δ_ss2 = ss2[7:11] + + # 给定的政策:D, G, δ + D_seq, G_seq, δ_seq = pol_target + T = G_seq.shape[0] + + # 价格的初始猜测 + r_seq = jnp.linspace(0, 1, T) * (r_ss2 - r_ss1) + r_ss1 + w_seq = jnp.linspace(0, 1, T) * (w_ss2 - w_ss1) + w_ss1 + + # 政策的初始猜测 + τ_seq = jnp.linspace(0, 1, T) * (τ_ss2 - τ_ss1) + τ_ss1 + + error = 1 + num_iter = 0 + + if verbose: + fig, axs = plt.subplots(1, 3, figsize=(14, 3)) + axs[0].plot(jnp.arange(T), r_seq) + axs[1].plot(jnp.arange(T), w_seq) + axs[2].plot(jnp.arange(T), τ_seq, label=f'iter {num_iter}') + + while error > tol: + # 重复直到找到不动点 + + r_old, w_old, τ_old = r_seq, w_seq, τ_seq + + pol_seq = (τ_seq, D_seq, G_seq, δ_seq) + price_seq = (r_seq, w_seq) + + # 向后求解最优政策 + V_seq, σ_seq = solve_backwards( + V_ss2, σ_ss2, hh, firm, price_seq, pol_seq, Q) + + # 向前计算人口演变 + μ_seq, K_seq, L_seq = simulate_forwards( + σ_seq, D_seq, μ_ss1, K_ss1, L_ss1, household, Q) + + # 根据总资本和劳动供给更新价格 + r_seq = KL_to_r(K_seq, L_seq, firm) + w_seq = KL_to_w(K_seq, L_seq, firm) + + # 找到平衡政府预算约束的税率 + τ_seq = find_τ([D_seq[:-1], D_seq[1:], G_seq, δ_seq], + [r_seq, w_seq], + [K_seq, L_seq]) + + # 新旧猜测之间的距离 + error = jnp.sum((r_old - r_seq) ** 2) + \ + jnp.sum((w_old - w_seq) ** 2) + \ + jnp.sum((τ_old - τ_seq) ** 2) + + num_iter += 1 + if verbose: + print(f"迭代 {num_iter:3d}: error = {error:.6e}") + axs[0].plot(jnp.arange(T), r_seq) + axs[1].plot(jnp.arange(T), w_seq) + axs[2].plot(jnp.arange(T), τ_seq, label=f'iter {num_iter}') + + r_seq = (r_seq + r_old) / 2 + w_seq = (w_seq + w_old) / 2 + τ_seq = (τ_seq + τ_old) / 2 + + if verbose: + axs[0].set_xlabel('t') + axs[1].set_xlabel('t') + axs[2].set_xlabel('t') + + axs[0].set_title('r') + axs[1].set_title('w') + axs[2].set_title('τ') + + axs[2].legend(loc='center left', bbox_to_anchor=(1, 0.5)) + + return V_seq, σ_seq, μ_seq, K_seq, L_seq, r_seq, w_seq, \ + τ_seq, D_seq, G_seq, δ_seq +``` + +现在我们可以计算由财政政策改革引发的均衡转换。 + +## 实验1:即时减税 + +假设政府降低税率,并通过发行债务立即平衡其预算。 + +在$t=0$时,政府出人意料地宣布立即减税。 + +从$t=0$到$19$,政府发行债务,因此债务$D_{t+1}$在20个周期内呈线性增长。 + +政府为其新债务水平设定目标$D_{20} =D_0 + 1 = \bar{D} + 1$。 + +政府支出$\bar{G}$和转移支付$\bar{\delta}_j$保持不变。 + +政府调整$\tau_t$以在转换过程中平衡预算。 + +我们要计算均衡转换路径。 + +我们的第一步是准备适当的政策变量数组`D_seq`、`G_seq`、`δ_seq` + +我们将计算一个能平衡政府预算的`τ_seq`。 + +```{code-cell} ipython3 +T = 150 + +D_seq = jnp.ones(T+1) * D_ss1 +D_seq = D_seq.at[:21].set(D_ss1 + jnp.linspace(0, 1, 21)) +D_seq = D_seq.at[21:].set(D_seq[20]) + +G_seq = jnp.ones(T) * G_ss1 + +δ_seq = jnp.repeat(δ_ss1, T).reshape((T, δ_ss1.size)) +``` + +为了迭代路径,我们首先需要找到其目标点,也就是在新财政政策下的新稳态。 + +```{code-cell} ipython3 +ss2 = find_ss(hh, firm, [D_seq[-1], G_seq[-1], δ_seq[-1]], Q) +``` + +我们可以使用`path_iteration`来寻找均衡转移动态。 + +通过设置关键参数`verbose=True`,可以让函数`path_iteration`显示收敛信息。 + +```{code-cell} ipython3 +paths = path_iteration(ss1, ss2, [D_seq, G_seq, δ_seq], hh, firm, Q, verbose=True) +``` + +在成功计算了转型动态后,让我们来研究它们。 + +```{code-cell} ipython3 +V_seq, σ_seq, μ_seq = paths[:3] +K_seq, L_seq = paths[3:5] +r_seq, w_seq = paths[5:7] +τ_seq, D_seq, G_seq, δ_seq = paths[7:11] +``` + +```{code-cell} ipython3 +ap = hh.a_grid[σ_seq[0]] +``` + +```{code-cell} ipython3 +j = jnp.reshape(hh.j_grid, (hh.j_grid.size, 1, 1)) +lj = l(j) +a = jnp.reshape(hh.a_grid, (1, hh.a_grid.size, 1)) +γ = jnp.reshape(hh.γ_grid, (1, 1, hh.γ_grid.size)) +``` + +```{code-cell} ipython3 +t = 0 + +ap = hh.a_grid[σ_seq[t]] +δ = δ_seq[t].reshape((hh.j_grid.size, 1, 1)) + +inc = (1 + r_seq[t]*(1-τ_seq[t])) * a \ + + (1-τ_seq[t]) * w_seq[t] * lj * γ - δ +inc = inc.reshape((hh.j_grid.size, hh.a_grid.size * hh.γ_grid.size)) + +c = inc - ap + +c_mean0 = (c * μ_seq[t]).sum(axis=1) +``` + +我们关注政策变化如何影响不同年龄群体和不同时期的消费。 + +我们可以研究特定年龄的平均消费水平。 + +```{code-cell} ipython3 +for t in [1, 10, 20, 50, 149]: + + ap = hh.a_grid[σ_seq[t]] + δ = δ_seq[t].reshape((hh.j_grid.size, 1, 1)) + + inc = (1 + r_seq[t]*(1-τ_seq[t])) * a + (1-τ_seq[t]) * w_seq[t] * lj * γ - δ + inc = inc.reshape((hh.j_grid.size, hh.a_grid.size * hh.γ_grid.size)) + + c = inc - ap + + c_mean = (c * μ_seq[t]).sum(axis=1) + + plt.plot(range(hh.j_grid.size), c_mean-c_mean0, label=f't={t}') + +plt.legend() +plt.xlabel(r'j') +plt.title(r'$\Delta mean(C(j))$') +plt.show() +``` + +为了总结这个转变过程,我们可以像在{doc}`ak2`中那样绘制路径。 + +但与那个两期生命的世代交叠模型设置不同,我们现在不再有具有代表性的老年和年轻主体。 + +* 现在我们在每个时间点都有50个不同年龄的群组 + +为了继续,我们构建两个规模相等的年龄组 -- 年轻组和老年组。 + +* 在25岁时,一个人从年轻组转变为老年组 + +```{code-cell} ipython3 +ap = hh.a_grid[σ_ss1] +J = hh.j_grid.size +δ = δ_ss1.reshape((hh.j_grid.size, 1, 1)) + +inc = (1 + r_ss1*(1-τ_ss1)) * a + (1-τ_ss1) * w_ss1 * lj * γ - δ +inc = inc.reshape((hh.j_grid.size, hh.a_grid.size * hh.γ_grid.size)) + +c = inc - ap + +Cy_ss1 = (c[:J//2] * μ_ss1[:J//2]).sum() / (J // 2) +Co_ss1 = (c[J//2:] * μ_ss1[J//2:]).sum() / (J // 2) +``` + +```{code-cell} ipython3 +T = σ_seq.shape[0] +J = σ_seq.shape[1] + +Cy_seq = np.empty(T) +Co_seq = np.empty(T) + +for t in range(T): + ap = hh.a_grid[σ_seq[t]] + δ = δ_seq[t].reshape((hh.j_grid.size, 1, 1)) + + inc = (1 + r_seq[t]*(1-τ_seq[t])) * a + (1-τ_seq[t]) * w_seq[t] * lj * γ - δ + inc = inc.reshape((hh.j_grid.size, hh.a_grid.size * hh.γ_grid.size)) + + c = inc - ap + + Cy_seq[t] = (c[:J//2] * μ_seq[t, :J//2]).sum() / (J // 2) + Co_seq[t] = (c[J//2:] * μ_seq[t, J//2:]).sum() / (J // 2) +``` + +```{code-cell} ipython3 +fig, axs = plt.subplots(3, 3, figsize=(14, 10)) + +# Cy (j=0-24) +axs[0, 0].plot(Cy_seq) +axs[0, 0].hlines(Cy_ss1, 0, T, color='r', linestyle='--') +axs[0, 0].set_title('Cy (j < 25)') + +# Cy (j=25-49) +axs[0, 1].plot(Co_seq) +axs[0, 1].hlines(Co_ss1, 0, T, color='r', linestyle='--') +axs[0, 1].set_title(r'Co (j $\geq$ 25)') + +names = ['K', 'L', 'r', 'w', 'τ', 'D', 'G'] +for i in range(len(names)): + i_var = i + 3 + i_axes = i + 2 + + row_i = i_axes // 3 + col_i = i_axes % 3 + + axs[row_i, col_i].plot(paths[i_var]) + axs[row_i, col_i].hlines(ss1[i_var], 0, T, color='r', linestyle='--') + axs[row_i, col_i].set_title(names[i]) + +# y轴范围 +axs[1, 0].set_ylim([ss1[4]-0.1, ss1[4]+0.1]) +axs[2, 2].set_ylim([ss1[9]-0.1, ss1[9]+0.1]) + +plt.show() +``` + +现在让我们计算每个时间点$t$下基于年龄的条件消费均值和方差。 + +```{code-cell} ipython3 +Cmean_seq = np.empty((T, J)) +Cvar_seq = np.empty((T, J)) + +for t in range(T): + ap = hh.a_grid[σ_seq[t]] + δ = δ_seq[t].reshape((hh.j_grid.size, 1, 1)) + + inc = (1 + r_seq[t]*(1-τ_seq[t])) * a + (1-τ_seq[t]) * w_seq[t] * lj * γ - δ + inc = inc.reshape((hh.j_grid.size, hh.a_grid.size * hh.γ_grid.size)) + + c = inc - ap + + Cmean_seq[t] = (c * μ_seq[t]).sum(axis=1) + Cvar_seq[t] = ((c - Cmean_seq[t].reshape((J, 1))) ** 2 * μ_seq[t]).sum(axis=1) +``` + +```{code-cell} ipython3 +J_seq, T_range = np.meshgrid(np.arange(J), np.arange(T)) + +fig = plt.figure(figsize=[20, 20]) + +# 绘制消费均值随年龄和时间的变化 +ax1 = fig.add_subplot(121, projection='3d') +ax1.plot_surface(T_range, J_seq, Cmean_seq, rstride=1, cstride=1, + cmap='viridis', edgecolor='none') +ax1.set_title(r"消费均值") +ax1.set_xlabel(r"t") +ax1.set_ylabel(r"j") + +# 绘制消费方差随年龄和时间的变化 +ax2 = fig.add_subplot(122, projection='3d') +ax2.plot_surface(T_range, J_seq, Cvar_seq, rstride=1, cstride=1, + cmap='viridis', edgecolor='none') +ax2.set_title(r"消费方差") +ax2.set_xlabel(r"t") +ax2.set_ylabel(r"j") + +plt.show() +``` + +## 实验2:预先宣布的减税 + +现在政府在时间$0$宣布永久性减税,但在20个周期后才实施。 + +我们将使用相同的关键工具`path_iteration`。 + +我们必须适当地指定`D_seq`。 + +```{code-cell} ipython3 +T = 150 + +D_t = 20 +D_seq = jnp.ones(T+1) * D_ss1 +D_seq = D_seq.at[D_t:D_t+21].set(D_ss1 + jnp.linspace(0, 1, 21)) +D_seq = D_seq.at[D_t+21:].set(D_seq[D_t+20]) + +G_seq = jnp.ones(T) * G_ss1 + +δ_seq = jnp.repeat(δ_ss1, T).reshape((T, δ_ss1.size)) +``` + +```{code-cell} ipython3 +ss2 = find_ss(hh, firm, [D_seq[-1], G_seq[-1], δ_seq[-1]], Q) +``` + +```{code-cell} ipython3 +paths = path_iteration(ss1, ss2, [D_seq, G_seq, δ_seq], + hh, firm, Q, verbose=True) +``` + +```{code-cell} ipython3 +V_seq, σ_seq, μ_seq = paths[:3] +K_seq, L_seq = paths[3:5] +r_seq, w_seq = paths[5:7] +τ_seq, D_seq, G_seq, δ_seq = paths[7:11] +``` + +```{code-cell} ipython3 +T = σ_seq.shape[0] +J = σ_seq.shape[1] + +Cy_seq = np.empty(T) +Co_seq = np.empty(T) + +for t in range(T): + ap = hh.a_grid[σ_seq[t]] + δ = δ_seq[t].reshape((hh.j_grid.size, 1, 1)) + + inc = (1 + r_seq[t]*(1-τ_seq[t])) * a + (1-τ_seq[t]) * w_seq[t] * lj * γ - δ + inc = inc.reshape((hh.j_grid.size, hh.a_grid.size * hh.γ_grid.size)) + + c = inc - ap + + Cy_seq[t] = (c[:J//2] * μ_seq[t, :J//2]).sum() / (J // 2) + Co_seq[t] = (c[J//2:] * μ_seq[t, J//2:]).sum() / (J // 2) +``` + +下面我们绘制经济的转换路径。 + + + +```{code-cell} ipython3 +fig, axs = plt.subplots(3, 3, figsize=(14, 10)) + +# Cy (j=0-24) +axs[0, 0].plot(Cy_seq) +axs[0, 0].hlines(Cy_ss1, 0, T, color='r', linestyle='--') +axs[0, 0].set_title('Cy (j < 25)') + +# Cy (j=25-49) +axs[0, 1].plot(Co_seq) +axs[0, 1].hlines(Co_ss1, 0, T, color='r', linestyle='--') +axs[0, 1].set_title(r'Co (j $\geq$ 25)') + +names = ['K', 'L', 'r', 'w', 'τ', 'D', 'G'] +for i in range(len(names)): + i_var = i + 3 + i_axes = i + 2 + + row_i = i_axes // 3 + col_i = i_axes % 3 + + axs[row_i, col_i].plot(paths[i_var]) + axs[row_i, col_i].hlines(ss1[i_var], 0, T, color='r', linestyle='--') + axs[row_i, col_i].set_title(names[i]) + +# ylims +axs[1, 0].set_ylim([ss1[4]-0.1, ss1[4]+0.1]) +axs[2, 2].set_ylim([ss1[9]-0.1, ss1[9]+0.1]) + +plt.show() +``` + +注意价格和数量是如何立即对预期的税率上调作出反应的。 + +让我们仔细观察资本存量是如何反应的。 + +```{code-cell} ipython3 +# K +i_var = 3 + +plt.plot(paths[i_var][:25]) +plt.hlines(ss1[i_var], 0, 25, color='r', linestyle='--') +plt.vlines(20, 6, 7, color='k', linestyle='--', linewidth=0.5) +plt.text(17, 6.56, r'tax cut') +plt.ylim([6.52, 6.65]) +plt.title("K") +plt.xlabel("t") +plt.show() +``` + +在t=20实施减税政策后,由于挤出效应,总资本将会减少。 + +个人在t=20之前几个时期就已预见到利率将会上升,因此开始增加储蓄。 + +由于储蓄的增加导致资本增加,随之而来的是利率的暂时下降。 + +对于生活在更早时期的个体来说,这种较低的利率使他们减少储蓄。 + +我们还可以沿着转换路径绘制不同群体消费的均值和方差的演变。 + +```{code-cell} ipython3 +Cmean_seq = np.empty((T, J)) +Cvar_seq = np.empty((T, J)) + +for t in range(T): + ap = hh.a_grid[σ_seq[t]] + δ = δ_seq[t].reshape((hh.j_grid.size, 1, 1)) + + inc = (1 + r_seq[t]*(1-τ_seq[t])) * a + (1-τ_seq[t]) * w_seq[t] * lj * γ - δ + inc = inc.reshape((hh.j_grid.size, hh.a_grid.size * hh.γ_grid.size)) + + c = inc - ap + + Cmean_seq[t] = (c * μ_seq[t]).sum(axis=1) + Cvar_seq[t] = ( + (c - Cmean_seq[t].reshape((J, 1))) ** 2 * μ_seq[t]).sum(axis=1) +``` + +```{code-cell} ipython3 +J_seq, T_range = np.meshgrid(np.arange(J), np.arange(T)) + +fig = plt.figure(figsize=[20, 20]) + +# 绘制消费均值随年龄和时间的变化 +ax1 = fig.add_subplot(121, projection='3d') +ax1.plot_surface(T_range, J_seq, Cmean_seq, rstride=1, cstride=1, + cmap='viridis', edgecolor='none') +ax1.set_title(r"消费均值") +ax1.set_xlabel(r"t") +ax1.set_ylabel(r"j") + +# 绘制消费方差随年龄和时间的变化 +ax2 = fig.add_subplot(122, projection='3d') +ax2.plot_surface(T_range, J_seq, Cvar_seq, rstride=1, cstride=1, + cmap='viridis', edgecolor='none') +ax2.set_title(r"消费方差") +ax2.set_xlabel(r"t") +ax2.set_ylabel(r"j") + +plt.show() +``` + diff --git a/lectures/cass_fiscal_2.md b/lectures/cass_fiscal_2.md new file mode 100644 index 00000000..b7e2c9cf --- /dev/null +++ b/lectures/cass_fiscal_2.md @@ -0,0 +1,584 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# 带扭曲性税收的双国模型 + +## 概述 + +本讲是 QuantEcon 讲座 {doc}`cass_fiscal` 的续篇。在那一讲中,我们研究了可预见的财政和技术冲击对 Cass-Koopmans 增长模型(如 QuantEcon 讲座 {doc}`cass_koopmans_2` 中所述)中竞争均衡价格和数量的影响。该模型是非随机版本。 + +这里我们研究该模型的双国版本。 + +我们通过将两个 {doc}`cass_koopmans_2` 经济体背靠背放在一起来构建它,然后开放某些商品的国际贸易,而不是所有商品。 + +这让我们能够关注 {cite:t}`mendoza1998international` 研究的一些问题。 + +让我们从一些导入开始: + +```{code-cell} ipython3 +import numpy as np +from scipy.optimize import root +import matplotlib.pyplot as plt +from collections import namedtuple +from mpmath import mp, mpf +from warnings import warn + +# 设置精度 +mp.dps = 40 +mp.pretty = True +``` + +## 两国Cass-Koopmans模型 + +本节描述{ref}`cs_fs_model`基本模型的两国版本。 + +该模型的结构类似于国际实际商业周期文献中使用的模型,其思路遵循{cite:t}`mendoza1998international`对扭曲性税收的分析。 + +我们允许两国之间进行商品贸易和未来商品债权交易,但不允许劳动力流动。 + +两国都拥有生产技术,每个国家的消费者都可以在任一国家持有资本,但需要接受不同的税收待遇。 + +我们用星号(*)表示第二个国家的变量。 + +两国的家庭都最大化终身效用: + +$$ +\sum_{t=0}^{\infty} \beta^t u(c_t) \quad \text{和} \quad \sum_{t=0}^{\infty} \beta^t u(c_t^*), +$$ + +其中$u(c) = \frac{c^{1-\gamma}}{1-\gamma}$,且$\gamma > 0$。 + +两国都采用具有相同技术参数的柯布-道格拉斯生产函数。 + +这个两国经济的世界资源约束是: + +$$ +(c_t+c_t^*)+(g_t+g_t^*)+(k_{t+1}-(1-\delta)k_t)+(k_{t+1}^*-(1-\delta)k_t^*) = f(k_t)+f(k_t^*) +$$ + +该约束结合了两国的可行性约束。 + +在后续计算中,我们将使用这个约束作为全球可行性约束。 + +为了连接两个国家,我们需要明确资本如何跨境流动以及在不同司法管辖区如何征税。 + +### 资本流动性和税收 + +第一国的消费者可以在任一国持有资本,但需要按照外国设定的税率对从外国资本持有中获得的租金缴税。 + +两国居民都可以在时间$t$以相同的Arrow-Debreu价格$q_t$购买消费品。我们假设资本市场是完整的。 + +让$B_t^f$表示本国代表性消费者通过向外国代表性消费者发行一期期票筹集的$t$期商品数量。 + +因此,$B_t^f > 0$表示本国消费者在$t$期从国外借款,而$B_t^f < 0$表示本国消费者在$t$期向国外贷款。 + +因此,第一国代表性消费者的预算约束为: + +$$ +\begin{aligned} +\sum_{t=0}^{\infty} q_t \left( c_t + (k_{t+1} - (1-\delta)k_t) + (\tilde{k}_{t+1} - (1-\delta)\tilde{k}_t) + R_{t-1,t}B_{t-1}^f \right) \leq \\ +\sum_{t=0}^{\infty} q_t \left( (\eta_t - \tau_{kt}(\eta_t - \delta))k_t + (\eta_t^* - \tau_{kt}^*(\eta_t^* - \delta))\tilde{k}_t + (1 - \tau_{nt})w_t n_t - \tau_{ht} + B_t^f \right). +\end{aligned} +$$ + +对于$t \geq 1$,$k_t$和$\tilde{k}_t$的无套利条件意味着 + +$$ +\begin{aligned} +q_{t-1} &= [(1 - \tau_{kt})(\eta_t - \delta) + 1] q_t, \\ +q_{t-1} &= [(1 - \tau^*_{kt})(\eta^*_t - \delta) + 1] q_t, +\end{aligned} +$$ + +这两个等式共同表明,两国的税后资本租金率是相等的: + +$$ +(1 - \tau^*_{kt})(\eta^*_t - \delta) = (1 - \tau_{kt})(\eta_t - \delta). +$$ + +$B_t^f$ 的无套利条件对于 $t \geq 0$ 是 $q_t = q_{t+1} R_{t+1,t}$,这意味着 + +$$ +q_{t-1} = q_t R_{t-1,t} +$$ + +对于 $t \geq 1$。 + +由于国内资本、国外资本和消费贷款具有相同的回报率,投资组合是不确定的。 + +如果我们允许 $B_t^f$ 为非零,我们可以将每个国家的国外资本持有量设为零。 + +这种解决投资组合不确定性的方法很方便,因为它减少了我们需要指定的初始条件数量。 + +因此,我们在允许国际借贷的同时,将两国的国外资本持有量都设为零。 + +给定从国内到国外的初始债务水平 $B_{-1}^f$,且 $R_{t-1,t} = \frac{q_{t-1}}{q_t}$,国际债务动态满足 + +$$ +B^f_t = R_{t-1,t} B^f_{t-1} + c_t + (k_{t+1} - (1 - \delta)k_t) + g_t - f(k_t) +$$ + +```{code-cell} ipython3 +def Bf_path(k, c, g, model): + """ + 计算 B^{f}_t: + Bf_t = R_{t-1} Bf_{t-1} + c_t + (k_{t+1}-(1-δ)k_t) + g_t - f(k_t) + 其中 Bf_0 = 0. + """ + S = len(c) - 1 + R = c[:-1]**(-model.γ) / (model.β * c[1:]**(-model.γ)) + + Bf = np.zeros(S + 1) + for t in range(1, S + 1): + inv = k[t] - (1 - model.δ) * k[t-1] + Bf[t] = ( + R[t-1] * Bf[t-1] + c[t] + inv + g[t-1] + - f(k[t-1], model)) + return Bf + +def Bf_ss(c_ss, k_ss, g_ss, model): + """ + 计算稳态 B^f + """ + R_ss = 1.0 / model.β + inv_ss = model.δ * k_ss + num = c_ss + inv_ss + g_ss - f(k_ss, model) + den = 1.0 - R_ss + return num / den +``` + +且 + +$$ +c^*_t + (k^*_{t+1} - (1 - \delta)k^*_t) + g^*_t - R_{t-1,t} B^f_{t-1} = f(k^*_t) - B^f_t. +$$ + +两国企业的一阶条件为: + +$$ +\begin{aligned} +\eta_t &= f'(k_t), \quad w_t = f(k_t) - k_t f'(k_t) \\ +\eta^*_t &= f'(k^*_t), \quad w^*_t = f(k^*_t) - k^*_t f'(k^*_t). +\end{aligned} +$$ + +国际商品贸易建立了: + +$$ +\frac{q_t}{\beta^t} = \frac{u'(c_t)}{1 + \tau_{ct}} = \mu^* \frac{u'(c^*_t)}{1 + \tau^*_{ct}}, +$$ + +其中$\mu^*$是一个非负数,是国家$*$中消费者预算约束的拉格朗日乘数的函数。 + +我们已将国内国家预算约束的拉格朗日乘数标准化,将相应的国内国家$\mu$设为1。 + +```{code-cell} ipython3 +def compute_rs(c_t, c_tp1, c_s_t, c_s_tp1, τc_t, + τc_tp1, τc_s_t, τc_s_tp1, model): + """ + 计算贸易开始后的国际风险分担。 + """ + + return (c_t**(-model.γ)/(1+τc_t)) * ((1+τc_s_t)/c_s_t**(-model.γ)) - ( + c_tp1**(-model.γ)/(1+τc_tp1)) * ((1+τc_s_tp1)/c_s_tp1**(-model.γ)) +``` + +均衡要求以下两个国家欧拉方程在 $t \geq 0$ 时满足: + +$$ +\begin{aligned} +u'(c_t) &= \beta u'(c_{t+1}) \left[ (1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] \left[ \frac{1 + \tau_{ct+1}}{1 + \tau_{ct}} \right], \\ +u'(c^*_t) &= \beta u'(c^*_{t+1}) \left[ (1 - \tau^*_{kt+1})(f'(k^*_{t+1}) - \delta) + 1 \right] \left[ \frac{1 + \tau^*_{ct+1}}{1 + \tau^*_{ct}} \right]. +\end{aligned} +$$ + +以下代码计算国内和国外的欧拉方程。 + +由于它们具有相同的形式但使用不同的变量,我们可以编写一个函数来处理这两种情况。 + +```{code-cell} ipython3 +def compute_euler(c_t, c_tp1, τc_t, + τc_tp1, τk_tp1, k_tp1, model): + """ + 计算欧拉方程。 + """ + Rbar = (1 - τk_tp1)*(f_prime(k_tp1, model) - model.δ) + 1 + return model.β * (c_tp1/c_t)**(-model.γ) * (1+τc_t)/(1+τc_tp1) * Rbar - 1 +``` + +### 初始条件和稳态 + +对于初始条件,我们选择贸易前的资本配置($k_0, k_0^*$)和本国(未标星国家)欠外国(标星国家)的初始国际债务水平$B_{-1}^f$。 + +### 均衡稳态值 + +两国模型的稳态由两组方程来表征。 + +首先,以下方程确定每个国家的稳态资本-劳动比率$\bar k$和$\bar k^*$: + +$$ +f'(\bar{k}) = \delta + \frac{\rho}{1 - \tau_k} +$$ (eq:steady_k_bar) + +$$ +f'(\bar{k}^*) = \delta + \frac{\rho}{1 - \tau_k^*} +$$ (eq:steady_k_star) + +给定这些稳态资本-劳动比率,本国和外国的消费值$\bar c$和$\bar c^*$由以下方程确定: + +$$ +(\bar{c} + \bar{c}^*) = f(\bar{k}) + f(\bar{k}^*) - \delta(\bar{k} + \bar{k}^*) - (\bar{g} + \bar{g}^*) +$$ (eq:steady_c_k_bar) + +$$ +\bar{c} = f(\bar{k}) - \delta\bar{k} - \bar{g} - \rho\bar{B}^f +$$ (eq:steady_c_kB) + +方程{eq}`eq:steady_c_k_bar`表示稳态下的可行性,而方程{eq}`eq:steady_c_kB`表示稳态下的贸易平衡,包括利息支付。 + +本国对外国的稳态债务水平$\bar{B}^f$影响两国之间的消费分配,但不影响世界总资本存量。 + +我们假设在稳态下$\bar{B}^f = 0$,这使我们得到以下函数来计算资本和消费的稳态值 + +```{code-cell} ipython3 +def compute_steady_state_global(model, g_ss=0.2): + """ + 计算资本、消费和投资的稳态值。 + """ + k_ss = ((1/model.β - (1-model.δ)) / (model.A * model.α)) ** (1/(model.α-1)) + c_ss = f(k_ss, model) - model.δ * k_ss - g_ss + return k_ss, c_ss +``` + +现在,我们可以应用残差最小化方法来计算资本和消费的稳态值。 + +我们再次对欧拉方程、全局资源约束和无套利条件的残差进行最小化。 + +```{code-cell} ipython3 +def compute_residuals_global(z, model, shocks, T, k0_ss, k_star, Bf_star): + """ + 计算两国模型的残差。 + """ + k, c, k_s, c_s = z.reshape(T+1, 4).T + g, gs = shocks['g'], shocks['g_s'] + τc, τk = shocks['τ_c'], shocks['τ_k'] + τc_s, τk_s = shocks['τ_c_s'], shocks['τ_k_s'] + + res = [k[0] - k0_ss, k_s[0] - k0_ss] + + for t in range(T): + e_d = compute_euler( + c[t], c[t+1], + τc[t], τc[t+1], τk[t+1], + k[t+1], model) + + e_f = compute_euler( + c_s[t], c_s[t+1], + τc_s[t], τc_s[t+1], τk_s[t+1], + k_s[t+1], model) + + rs = compute_rs( + c[t], c[t+1], c_s[t], c_s[t+1], + τc[t], τc[t+1], τc_s[t], τc_s[t+1], + model) + + # 全局资源约束 + grc = k[t+1] + k_s[t+1] - ( + f(k[t], model) + f(k_s[t], model) + + (1-model.δ)*(k[t] + k_s[t]) - + c[t] - c_s[t] - g[t] - gs[t] + ) + + res.extend([e_d, e_f, rs, grc]) + + Bf_term = Bf_path(k, c, shocks['g'], model)[-1] + res.append(k[T] - k_star) + res.append(Bf_term - Bf_star) + return np.array(res) +``` + +现在我们绘制结果 + +```{code-cell} ipython3 +# 绘制全球双国模型结果的函数 +def plot_global_results(k, k_s, c, c_s, shocks, model, + k0_ss, c0_ss, g_ss, S, T=40, shock='g', + # 存储左下面板序列的字典 + ll_series='None'): + """ + 绘制双国模型的结果。 + """ + fig, axes = plt.subplots(2, 3, figsize=(10, 8)) + x = np.arange(T) + τc, τk = shocks['τ_c'], shocks['τ_k'] + Bf = Bf_path(k, c, shocks['g'], model) + + # 计算衍生序列 + R_ratio = c[:-1]**(-model.γ) / (model.β * c[1:]**(-model.γ)) \ + *(1+τc[:-1])/(1+τc[1:]) + inv = k[1:] - (1-model.δ)*k[:-1] + inv_s = k_s[1:] - (1-model.δ)*k_s[:-1] + + # 将初始条件添加到序列中 + R_ratio = np.append(1/model.β, R_ratio) + c = np.append(c0_ss, c) + c_s = np.append(c0_ss, c_s) + k = np.append(k0_ss, k) + k_s = np.append(k0_ss, k_s) + + # 资本 + axes[0,0].plot(x, k[:T], '-', lw=1.5) + axes[0,0].plot(x, np.full(T, k0_ss), 'k-.', lw=1.5) + axes[0,0].plot(x, k_s[:T], '--', lw=1.5) + axes[0,0].set_title('k') + axes[0,0].set_xlim(0, T-1) + + # 消费 + axes[0,1].plot(x, c[:T], '-', lw=1.5) + axes[0,1].plot(x, np.full(T, c0_ss), 'k-.', lw=1.5) + axes[0,1].plot(x, c_s[:T], '--', lw=1.5) + axes[0,1].set_title('c') + axes[0,1].set_xlim(0, T-1) + + # 利率 + axes[0,2].plot(x, R_ratio[:T], '-', lw=1.5) + axes[0,2].plot(x, np.full(T, 1/model.β), 'k-.', lw=1.5) + axes[0,2].set_title(r'$\bar{R}$') + axes[0,2].set_xlim(0, T-1) + + # 投资 + axes[1,0].plot(x, np.full(T, model.δ * k0_ss), + 'k-.', lw=1.5) + axes[1,0].plot(x, np.append(model.δ*k0_ss, inv[:T-1]), + '-', lw=1.5) + axes[1,0].plot(x, np.append(model.δ*k0_ss, inv_s[:T-1]), + '--', lw=1.5) + axes[1,0].set_title('x') + axes[1,0].set_xlim(0, T-1) + + # 冲击 + axes[1,1].plot(x, shocks[shock][:T], '-', lw=1.5) + axes[1,1].plot(x, np.full(T, shocks[shock][0]), 'k-.', lw=1.5) + axes[1,1].set_title(f'${shock}$') + axes[1,1].set_ylim(-0.1, 0.5) + axes[1,1].set_xlim(0, T-1) + + # 资本流动 + axes[1,2].plot(x, np.append(0, Bf[1:T]), lw=1.5) + axes[1,2].plot(x, np.zeros(T), 'k-.', lw=1.5) + axes[1,2].set_title(r'$B^{f}$') + axes[1,2].set_xlim(0, T-1) + + plt.tight_layout() + return fig, axes +``` + +如同我们在{doc}`cass_fiscal`中的单一国家模型,我们假设一个柯布-道格拉斯生产函数: + +$$ +F(k, 1) = A k^\alpha +$$ + +```{code-cell} ipython3 +def f(k, model, A=1): + """ + 生产函数:f(k) = A * k^{α} + """ + return A * k ** model.α + +def f_prime(k, model, A=1): + """ + 资本的边际产出:f'(k) = α * A * k^{α - 1} + """ + return model.α * A * k ** (model.α - 1) +``` + +类似地,我们定义资本租赁率 + +$$ +\eta_t = f'(k_t) +$$ + +```{code-cell} ipython3 +def compute_η_path(k_path, model, S=100, A_path=None): + """ + 计算η路径:η_t = f'(k_t) + 对于增长模型可选择性地包含A_path。 + """ + A = np.ones_like(k_path) if A_path is None else np.asarray(A_path) + η_path = np.zeros_like(k_path) + for t in range(S): + η_path[t] = f_prime(k_path[t], model, A[t]) + return η_path +``` + +#### 实验1:在t=10时预见到g从0.2增加到0.4 + +下图展示了国内经济中g从0.2增加到0.4(提前十个周期宣布)后的转换动态。 + +我们从两个经济体的稳态开始,初始条件为$B_0^f = 0$。 + +在下图中,蓝线代表国内经济,橙色虚线代表国外经济。 + +```{code-cell} ipython3 +Model = namedtuple("Model", ["β", "γ", "δ", "α", "A"]) +model = Model(β=0.95, γ=2.0, δ=0.2, α=0.33, A=1.0) +S = 100 + +shocks_global = { + 'g': np.concatenate((np.full(10, 0.2), np.full(S-9, 0.4))), + 'g_s': np.full(S+1, 0.2), + 'τ_c': np.zeros(S+1), + 'τ_k': np.zeros(S+1), + 'τ_c_s': np.zeros(S+1), + 'τ_k_s': np.zeros(S+1) +} +g_ss = 0.2 +k0_ss, c0_ss = compute_steady_state_global(model, g_ss) + +k_star = k0_ss +Bf_star = Bf_ss(c0_ss, k_star, g_ss, model) + +init_glob = np.tile([k0_ss, c0_ss, k0_ss, c0_ss], S+1) +sol_glob = root( + lambda z: compute_residuals_global(z, model, shocks_global, + S, k0_ss, k_star, Bf_star), + init_glob, tol=1e-12 +) +k, c, k_s, c_s = sol_glob.x.reshape(S+1, 4).T + +# Plot global results via function +plot_global_results(k, k_s, c, c_s, + shocks_global, model, + k0_ss, c0_ss, g_ss, + S) +plt.show() +``` + +在时间1时,政府宣布国内政府支出$g$将在十个周期后上升,这将侵占未来的私人资源。 + +为了平滑消费,国内家庭立即增加储蓄,以抵消预期中对其未来财富的冲击。 + +在封闭经济中,他们只能通过积累额外的国内资本来储蓄;而在开放的资本市场中,他们还可以向外国人贷款。 + +一旦资本流动在时间$1$开放,无套利条件将连接这两种储蓄方式的调整:国内家庭储蓄的增加将降低外国经济中债券和资本的均衡回报率,以防止套利机会。 + +由于无套利使边际效用比率相等,两个经济体的消费和资本路径将同步变化。 + +在更高的$g$生效之前,两个国家都继续增加其资本存量。 + +当政府支出在10个周期后最终上升时,国内家庭开始动用部分资本来缓冲消费。 + +同样根据无套利条件,当$g$实际增加时,两个国家都降低了其投资率。 + +国内经济随之开始出现经常账户赤字,部分用于资助$g$的增加。 + +这意味着外国家庭通过减少其资本存量来开始偿还部分外部债务。 + + +#### 实验2:在t=10时$g$从0.2可预见地增加到0.4 + +我们现在探讨在t = 1时宣布的国内资本税上调政策在10个周期后的影响。 + +由于这一变化是可预期的,尽管税收直到第11期才开始生效,两国家庭都会立即做出调整。 + +```{code-cell} ipython3 +shocks_global = { + 'g': np.full(S+1, g_ss), + 'g_s': np.full(S+1, g_ss), + 'τ_c': np.zeros(S+1), + 'τ_k': np.concatenate((np.zeros(10), np.full(S-9, 0.2))), + 'τ_c_s': np.zeros(S+1), + 'τ_k_s': np.zeros(S+1), +} + +k0_ss, c0_ss = compute_steady_state_global(model, g_ss) +k_star = k0_ss +Bf_star = Bf_ss(c0_ss, k_star, g_ss, model) + +init_glob = np.tile([k0_ss, c0_ss, k0_ss, c0_ss], S+1) + +sol_glob = root( + lambda z: compute_residuals_global(z, model, + shocks_global, S, k0_ss, k_star, Bf_star), + init_glob, tol=1e-12) + +k, c, k_s, c_s = sol_glob.x.reshape(S+1, 4).T + +# plot +fig, axes = plot_global_results(k, k_s, c, c_s, shocks_global, model, + k0_ss, c0_ss, g_ss, S, shock='τ_k') +plt.tight_layout() +plt.show() +``` + +在宣布增税后,国内家庭预见到资本的税后回报率降低,因此转向更高的当前消费,并允许国内资本存量下降。 + +这种世界资本供应的萎缩推动全球实际利率上升,促使外国家庭也提高当前消费。 + +在实际加税之前,国内经济通过进口资本为部分消费提供资金,产生经常账户赤字。 + +当$\tau_k$最终上升时,国际套利导致投资者迅速将资本重新配置到未征税的国外市场,压缩了各地的债券收益率。 + +债券利率下跌反映了国内资本的税后回报率降低,以及国外资本存量增加导致其边际产出下降。 + +外国家庭通过对外借款为其资本购买提供资金,造成显著的经常账户赤字和外部债务的积累。 + +政策变更后,两国平稳地向新的稳态过渡,其特点是: + + * 各经济体的消费水平稳定在其宣布前路径之下。 + * 资本存量的差异恰好足以使跨境税后回报率趋于相等。 + +尽管承担着正的净负债,由于较大的资本存量带来更高的产出,外国能够享有更高的稳态消费。 + +该案例展示了开放资本市场如何在国际间传递国内税收冲击:资本流动和利率变动共同分担负担,随着时间推移平滑了征税和未征税经济体的消费调整。 + ++++ + +```{exercise} +:label: cass_fiscal_ex4 + +在本练习中,用 $\eta_t$ 替换 ${x_t}$ 的图表,以复制 {cite}`Ljungqvist2012` 中的图形。 + +比较 ${k_t}$ 和 $\eta_t$ 的图形并讨论其经济含义。 +``` +```{solution-start} cass_fiscal_ex4 +:class: dropdown +``` + +这是一个解决方案。 + +```{code-cell} ipython3 +fig, axes = plot_global_results(k, k_s, c, c_s, shocks_global, model, + k0_ss, c0_ss, g_ss, S, shock='τ_k') + +# Clear the plot for x_t +axes[1,0].cla() + +# Plot η_t +axes[1,0].plot(compute_η_path(k, model)[:40]) +axes[1,0].plot(compute_η_path(k_s, model)[:40], '--') +axes[1,0].plot(np.full(40, f_prime(k_s, model)[0]), 'k-.', lw=1.5) +axes[1,0].set_title(r'$\eta$') + +plt.tight_layout() +plt.show() +``` + +当税收冲击后国内资本 ${k_t}$ 减少时,该国的租金率 $\eta_t$ 上升。 + +这是因为当资本变得稀缺时,其边际产出会上升。 + +```{solution-end} +``` + diff --git a/lectures/divergence_measures.md b/lectures/divergence_measures.md new file mode 100644 index 00000000..8f52fde1 --- /dev/null +++ b/lectures/divergence_measures.md @@ -0,0 +1,543 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.6 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +(divergence_measures)= +```{raw} jupyter + +``` + +# 统计散度度量 + +```{contents} 目录 +:depth: 2 +``` + +## 概述 + +统计散度用于量化两个不同概率分布之间的差异,这些分布可能难以区分,原因如下: + + * 在一个分布下具有正概率的每个事件在另一个分布下也具有正概率 + + * 这意味着没有"确凿证据"事件的发生能让统计学家确定数据一定服从其中某一个概率分布 + +统计散度是一个将两个概率分布映射到非负实数的**函数**。 + +统计散度函数在统计学、信息论和现在许多人称之为"机器学习"的领域中发挥着重要作用。 + +本讲座描述了三种散度度量: + +* **库尔贝克-莱布勒(KL)散度** + +* **Jensen-Shannon (JS) 散度** +* **切尔诺夫熵** + +这些概念将在多个 quantecon 课程中出现。 + +让我们首先导入必要的 Python 工具。 + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +from numba import vectorize, jit +from math import gamma +from scipy.integrate import quad +from scipy.optimize import minimize_scalar +import pandas as pd +from IPython.display import display, Math +``` + +## 熵、交叉熵、KL散度入门 + +在深入之前,我们先介绍一些有用的基本概念。 + +我们暂时假设 $f$ 和 $g$ 是离散随机变量在状态空间 $I = \{1, 2, \ldots, n\}$ 上的两个概率质量函数,满足 $f_i \geq 0, \sum_{i} f_i =1, g_i \geq 0, \sum_{i} g_i =1$。 + +我们遵循一些统计学家和信息论学家的做法,将从分布 $f$ 中观察到单次抽样 $x = i$ 所关联的**惊奇度**或**惊奇量**定义为 + +$$ +\log\left(\frac{1}{f_i}\right) +$$ + +他们进一步将从单次实现中预期获得的**信息量**定义为期望惊奇度 + +$$ +H(f) = \sum_i f_i \log\left(\frac{1}{f_i}\right). +$$ + +Claude Shannon {cite}`shannon1948mathematical` 将 $H(f)$ 称为分布 $f$ 的**熵**。 + +```{note} +通过对 $\{f_1, f_2, \ldots, f_n\}$ 在约束 $\sum_i f_i = 1$ 下最大化 $H(f)$,我们可以验证使熵最大化的分布是均匀分布 +$ +f_i = \frac{1}{n} . +$ +均匀分布的熵 $H(f)$ 显然等于 $- \log(n)$。 +``` + +Kullback 和 Leibler {cite}`kullback1951information` 将单次抽样 $x$ 用于区分 $f$ 和 $g$ 所提供的信息量定义为对数似然比 + +$$ +\log \frac{f(x)}{g(x)} +$$ + +以下两个概念被广泛用于比较两个分布 $f$ 和 $g$。 + +**交叉熵:** + +\begin{equation} +H(f,g) = -\sum_{i} f_i \log g_i +\end{equation} + + + +**Kullback-Leibler (KL) 散度:** +\begin{equation} +D_{KL}(f \parallel g) = \sum_{i} f_i \log\left[\frac{f_i}{g_i}\right] +\end{equation} + +这些概念通过以下等式相关联。 + +$$ +D_{KL}(f \parallel g) = H(f,g) - H(f) +$$ (eq:KLcross) + +要证明{eq}`eq:KLcross`,注意到 + + +\begin{align} +D_{KL}(f \parallel g) &= \sum_{i} f_i \log\left[\frac{f_i}{g_i}\right] \\ +&= \sum_{i} f_i \left[\log f_i - \log g_i\right] \\ +&= \sum_{i} f_i \log f_i - \sum_{i} f_i \log g_i \\ +&= -H(f) + H(f,g) \\ +&= H(f,g) - H(f) +\end{align} + +记住$H(f)$是从$f$中抽取$x$时的预期惊异度。 + +那么上述等式告诉我们,KL散度是当预期$x$是从$f$中抽取而实际上是从$g$中抽取时产生的预期"额外惊异度"。 + + +## 两个Beta分布:运行示例 + +我们将广泛使用Beta分布来说明概念。 + +Beta分布特别方便,因为它定义在$[0,1]$上,并且通过适当选择其两个参数可以呈现多样的形状。 + +具有参数$a$和$b$的Beta分布的密度函数为 + +$$ +f(z; a, b) = \frac{\Gamma(a+b) z^{a-1} (1-z)^{b-1}}{\Gamma(a) \Gamma(b)} +\quad \text{其中} \quad +\Gamma(p) := \int_{0}^{\infty} x^{p-1} e^{-x} dx +$$ + +我们引入两个Beta分布$f(x)$和$g(x)$,我们将用它们来说明不同的散度度量。 + +让我们在Python中定义参数和密度函数 + +```{code-cell} ipython3 +# 两个Beta分布中的参数 +F_a, F_b = 1, 1 +G_a, G_b = 3, 1.2 + +@vectorize +def p(x, a, b): + r = gamma(a + b) / (gamma(a) * gamma(b)) + return r * x** (a-1) * (1 - x) ** (b-1) + +# 两个密度函数 +f = jit(lambda x: p(x, F_a, F_b)) +g = jit(lambda x: p(x, G_a, G_b)) + +# 绘制分布图 +x_range = np.linspace(0.001, 0.999, 1000) +f_vals = [f(x) for x in x_range] +g_vals = [g(x) for x in x_range] + +plt.figure(figsize=(10, 6)) +plt.plot(x_range, f_vals, 'b-', linewidth=2, label=r'$f(x) \sim \text{Beta}(1,1)$') +plt.plot(x_range, g_vals, 'r-', linewidth=2, label=r'$g(x) \sim \text{Beta}(3,1.2)$') + +# 填充重叠区域 +overlap = np.minimum(f_vals, g_vals) +plt.fill_between(x_range, 0, overlap, alpha=0.3, color='purple', label='overlap') + +plt.xlabel('x') +plt.ylabel('密度') +plt.legend() +plt.show() +``` + +(rel_entropy)= +## Kullback–Leibler散度 + +我们的第一个散度函数是**Kullback–Leibler (KL)散度**。 + +对于概率密度(或概率质量函数)$f$和$g$,它的定义为 + +$$ +D_{KL}(f\|g) = KL(f, g) = \int f(x) \log \frac{f(x)}{g(x)} \, dx. +$$ + +我们可以将$D_{KL}(f\|g)$解释为当数据由$f$生成而我们使用$g$时产生的预期超额对数损失(预期超额意外性)。 + +它有几个重要的性质: + +- 非负性(Gibbs不等式):$D_{KL}(f\|g) \ge 0$,当且仅当$f$几乎处处等于$g$时取等号 +- 不对称性:$D_{KL}(f\|g) \neq D_{KL}(g\|f)$(因此它不是度量) +- 信息分解: + $D_{KL}(f\|g) = H(f,g) - H(f)$,其中$H(f,g)$是交叉熵,$H(f)$是$f$的Shannon熵 +- 链式法则:对于联合分布$f(x, y)$和$g(x, y)$, + $D_{KL}(f(x,y)\|g(x,y)) = D_{KL}(f(x)\|g(x)) + E_{f}\left[D_{KL}(f(y|x)\|g(y|x))\right]$ + +KL散度在统计推断中扮演着核心角色,包括模型选择和假设检验。 + +{doc}`likelihood_ratio_process`描述了KL散度与预期对数似然比之间的联系, +而讲座{doc}`wald_friedman`将其与序贯概率比检验的测试性能联系起来。 + +让我们计算示例分布$f$和$g$之间的KL散度。 + +```{code-cell} ipython3 +def compute_KL(f, g): + """ + 通过数值积分计算KL散度KL(f, g) + """ + def integrand(w): + fw = f(w) + gw = g(w) + return fw * np.log(fw / gw) + val, _ = quad(integrand, 1e-5, 1-1e-5) + return val + +# 计算我们示例分布之间的KL散度 +kl_fg = compute_KL(f, g) +kl_gf = compute_KL(g, f) + +print(f"KL(f, g) = {kl_fg:.4f}") +print(f"KL(g, f) = {kl_gf:.4f}") +``` + +KL散度的不对称性具有重要的实际意义。 + +$D_{KL}(f\|g)$ 惩罚那些 $f > 0$ 但 $g$ 接近零的区域,反映了使用 $g$ 来建模 $f$ 的代价,反之亦然。 + +## Jensen-Shannon散度 + +有时我们需要一个对称的散度度量,用来衡量两个分布之间的差异,而不偏向任何一方。 + +这种情况经常出现在聚类等应用中,我们想要比较分布,但不假设其中一个是真实模型。 + +**Jensen-Shannon (JS) 散度**通过将两个分布与它们的混合分布进行比较来使KL散度对称化: + +$$ +JS(f,g) = \frac{1}{2} D_{KL}(f\|m) + \frac{1}{2} D_{KL}(g\|m), \quad m = \frac{1}{2}(f+g). +$$ + +其中 $m$ 是对 $f$ 和 $g$ 取平均的混合分布 + +让我们也可视化混合分布 $m$: + +```{code-cell} ipython3 +def m(x): + return 0.5 * (f(x) + g(x)) + +m_vals = [m(x) for x in x_range] + +plt.figure(figsize=(10, 6)) +plt.plot(x_range, f_vals, 'b-', linewidth=2, label=r'$f(x)$') +plt.plot(x_range, g_vals, 'r-', linewidth=2, label=r'$g(x)$') +plt.plot(x_range, m_vals, 'g--', linewidth=2, label=r'$m(x) = \frac{1}{2}(f(x) + g(x))$') + +plt.xlabel('x') +plt.ylabel('density') +plt.legend() +plt.show() +``` + +JS散度具有以下几个有用的性质: + +- 对称性:$JS(f,g)=JS(g,f)$。 +- 有界性:$0 \le JS(f,g) \le \log 2$。 +- 其平方根$\sqrt{JS}$在概率分布空间上是一个度量(Jensen-Shannon距离)。 +- JS散度等于二元随机变量$Z \sim \text{Bernoulli}(1/2)$(用于指示源)与样本$X$之间的互信息,其中当$Z=0$时$X$从$f$抽样,当$Z=1$时从$g$抽样。 + +Jensen-Shannon散度在某些生成模型的优化中起着关键作用,因为它是有界的、对称的,且比KL散度更平滑,通常能为训练提供更稳定的梯度。 + +让我们计算示例分布$f$和$g$之间的JS散度 + +```{code-cell} ipython3 +def compute_JS(f, g): + """计算Jensen-Shannon散度。""" + def m(w): + return 0.5 * (f(w) + g(w)) + js_div = 0.5 * compute_KL(f, m) + 0.5 * compute_KL(g, m) + return js_div + +js_div = compute_JS(f, g) +print(f"Jensen-Shannon散度 JS(f,g) = {js_div:.4f}") +``` + +我们可以使用带权重 $\alpha = (\alpha_i)_{i=1}^{n}$ 的广义 Jensen-Shannon 散度轻松推广到两个以上的分布: + +$$ +JS_\alpha(f_1, \ldots, f_n) = +H\left(\sum_{i=1}^n \alpha_i f_i\right) - \sum_{i=1}^n \alpha_i H(f_i) +$$ + +其中: +- $\alpha_i \geq 0$ 且 $\sum_{i=1}^n \alpha_i = 1$,以及 +- $H(f) = -\int f(x) \log f(x) dx$ 是分布 $f$ 的**香农熵** + +## Chernoff 熵 + +Chernoff 熵源自[大偏差理论](https://en.wikipedia.org/wiki/Large_deviations_theory)的早期应用,该理论通过提供罕见事件的指数衰减率来改进中心极限近似。 + +对于密度函数 $f$ 和 $g$,Chernoff 熵为 + +$$ +C(f,g) = - \log \min_{\phi \in (0,1)} \int f^{\phi}(x) g^{1-\phi}(x) \, dx. +$$ + +注释: + +- 内部积分是 **Chernoff 系数**。 +- 当 $\phi=1/2$ 时,它变成 **Bhattacharyya 系数** $\int \sqrt{f g}$。 +- 在具有 $T$ 个独立同分布观测的二元假设检验中,最优错误概率以 $e^{-C(f,g) T}$ 的速率衰减。 + +我们将在 {doc}`likelihood_ratio_process` 讲座中看到第三点的一个例子, +我们将在模型选择的背景下研究 Chernoff 熵。 + +让我们计算示例分布 $f$ 和 $g$ 之间的 Chernoff 熵。 + +```{code-cell} ipython3 +def chernoff_integrand(ϕ, f, g): + """计算给定 ϕ 的 Chernoff 熵中的积分。""" + def integrand(w): + return f(w)**ϕ * g(w)**(1-ϕ) + result, _ = quad(integrand, 1e-5, 1-1e-5) + return result + +def compute_chernoff_entropy(f, g): + """计算 Chernoff 熵 C(f,g)。""" + def objective(ϕ): + return chernoff_integrand(ϕ, f, g) + result = minimize_scalar(objective, bounds=(1e-5, 1-1e-5), method='bounded') + min_value = result.fun + ϕ_optimal = result.x + chernoff_entropy = -np.log(min_value) + return chernoff_entropy, ϕ_optimal + +C_fg, ϕ_optimal = compute_chernoff_entropy(f, g) +print(f"Chernoff 熵 C(f,g) = {C_fg:.4f}") +print(f"最优 ϕ = {ϕ_optimal:.4f}") +``` + +## 比较散度度量 + +我们现在比较几对Beta分布之间的这些度量 + +```{code-cell} ipython3 +:tags: [hide-input] + +distribution_pairs = [ + # (f_params, g_params) + ((1, 1), (0.1, 0.2)), + ((1, 1), (0.3, 0.3)), + ((1, 1), (0.3, 0.4)), + ((1, 1), (0.5, 0.5)), + ((1, 1), (0.7, 0.6)), + ((1, 1), (0.9, 0.8)), + ((1, 1), (1.1, 1.05)), + ((1, 1), (1.2, 1.1)), + ((1, 1), (1.5, 1.2)), + ((1, 1), (2, 1.5)), + ((1, 1), (2.5, 1.8)), + ((1, 1), (3, 1.2)), + ((1, 1), (4, 1)), + ((1, 1), (5, 1)) +] + +# 创建比较表 +results = [] +for i, ((f_a, f_b), (g_a, g_b)) in enumerate(distribution_pairs): + f = jit(lambda x, a=f_a, b=f_b: p(x, a, b)) + g = jit(lambda x, a=g_a, b=g_b: p(x, a, b)) + kl_fg = compute_KL(f, g) + kl_gf = compute_KL(g, f) + js_div = compute_JS(f, g) + chernoff_ent, _ = compute_chernoff_entropy(f, g) + results.append({ + 'Pair (f, g)': f"\\text{{Beta}}({f_a},{f_b}), \\text{{Beta}}({g_a},{g_b})", + 'KL(f, g)': f"{kl_fg:.4f}", + 'KL(g, f)': f"{kl_gf:.4f}", + 'JS': f"{js_div:.4f}", + 'C': f"{chernoff_ent:.4f}" + }) + +df = pd.DataFrame(results) +# 按JS散度排序 +df['JS_numeric'] = df['JS'].astype(float) +df = df.sort_values('JS_numeric').drop('JS_numeric', axis=1) + +columns = ' & '.join([f'\\text{{{col}}}' for col in df.columns]) +rows = ' \\\\\n'.join( + [' & '.join([f'{val}' for val in row]) + for row in df.values]) + +latex_code = rf""" +\begin{{array}}{{lcccc}} +{columns} \\ +\hline +{rows} +\end{{array}} +""" + +display(Math(latex_code)) +``` + +当我们改变Beta分布的参数时,我们可以清楚地看到各种散度测度之间的协同变化。 + +接下来我们可视化KL散度、JS散度和切尔诺夫熵之间的关系。 + +```{code-cell} ipython3 +kl_fg_values = [float(result['KL(f, g)']) for result in results] +js_values = [float(result['JS']) for result in results] +chernoff_values = [float(result['C']) for result in results] + +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +axes[0].scatter(kl_fg_values, js_values, alpha=0.7, s=60) +axes[0].set_xlabel('KL散度 KL(f, g)') +axes[0].set_ylabel('JS散度') +axes[0].set_title('JS散度与KL散度的关系') + +axes[1].scatter(js_values, chernoff_values, alpha=0.7, s=60) +axes[1].set_xlabel('JS散度') +axes[1].set_ylabel('切尔诺夫熵') +axes[1].set_title('切尔诺夫熵与JS散度的关系') + +plt.tight_layout() +plt.show() +``` + +现在我们生成图表来直观展示随着差异度量的增加,重叠程度如何减少。 + +```{code-cell} ipython3 +param_grid = [ + ((1, 1), (1, 1)), + ((1, 1), (1.5, 1.2)), + ((1, 1), (2, 1.5)), + ((1, 1), (3, 1.2)), + ((1, 1), (0.3, 0.3)), + ((1, 1), (5, 1)) +] +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +def plot_dist_diff(para_grid): + """绘制选定Beta分布对的重叠图。""" + + fig, axes = plt.subplots(3, 2, figsize=(15, 12)) + divergence_data = [] + for i, ((f_a, f_b), (g_a, g_b)) in enumerate(param_grid): + row, col = divmod(i, 2) + f = jit(lambda x, a=f_a, b=f_b: p(x, a, b)) + g = jit(lambda x, a=g_a, b=g_b: p(x, a, b)) + kl_fg = compute_KL(f, g) + js_div = compute_JS(f, g) + chernoff_ent, _ = compute_chernoff_entropy(f, g) + divergence_data.append({ + 'f_params': (f_a, f_b), + 'g_params': (g_a, g_b), + 'kl_fg': kl_fg, + 'js_div': js_div, + 'chernoff': chernoff_ent + }) + x_range = np.linspace(0, 1, 200) + f_vals = [f(x) for x in x_range] + g_vals = [g(x) for x in x_range] + axes[row, col].plot(x_range, f_vals, 'b-', + linewidth=2, label=f'f ~ Beta({f_a},{f_b})') + axes[row, col].plot(x_range, g_vals, 'r-', + linewidth=2, label=f'g ~ Beta({g_a},{g_b})') + overlap = np.minimum(f_vals, g_vals) + axes[row, col].fill_between(x_range, 0, + overlap, alpha=0.3, color='purple', label='重叠') + axes[row, col].set_title( + f'KL(f,g)={kl_fg:.3f}, JS={js_div:.3f}, C={chernoff_ent:.3f}', + fontsize=12) + axes[row, col].legend(fontsize=12) + plt.tight_layout() + plt.show() + return divergence_data + +divergence_data = plot_dist_diff(param_grid) +``` + +## KL散度和最大似然估计 + +给定n个观测样本 $X = \{x_1, x_2, \ldots, x_n\}$,**经验分布**为 + +$$p_e(x) = \frac{1}{n} \sum_{i=1}^n \delta(x - x_i)$$ + +其中 $\delta(x - x_i)$ 是中心在 $x_i$ 的狄拉克德尔塔函数: + +$$ +\delta(x - x_i) = \begin{cases} ++\infty & \text{如果 } x = x_i \\ +0 & \text{如果 } x \neq x_i +\end{cases} +$$ + +- **离散概率测度**:对每个观测数据点赋予概率 $\frac{1}{n}$ +- **经验期望**:$\langle X \rangle_{p_e} = \frac{1}{n} \sum_{i=1}^n x_i = \bar{\mu}$ +- **支撑集**:仅在观测数据点 $\{x_1, x_2, \ldots, x_n\}$ 上 + +从经验分布 $p_e$ 到参数模型 $p_\theta(x)$ 的KL散度为: + +$$D_{KL}(p_e \parallel p_\theta) = \int p_e(x) \log \frac{p_e(x)}{p_\theta(x)} dx$$ + +利用狄拉克德尔塔函数的数学性质,可得 + +$$D_{KL}(p_e \parallel p_\theta) = \sum_{i=1}^n \frac{1}{n} \log \frac{\left(\frac{1}{n}\right)}{p_\theta(x_i)}$$ + +$$= \frac{1}{n} \sum_{i=1}^n \log \frac{1}{n} - \frac{1}{n} \sum_{i=1}^n \log p_\theta(x_i)$$ + +$$= -\log n - \frac{1}{n} \sum_{i=1}^n \log p_\theta(x_i)$$ + +由于参数 $\theta$ 的对数似然函数为: + +$$ +\ell(\theta; X) = \sum_{i=1}^n \log p_\theta(x_i) , +$$ + +因此最大似然选择参数以最小化 + +$$ D_{KL}(p_e \parallel p_\theta) $$ + +因此,MLE等价于最小化从经验分布到统计模型$p_\theta$的KL散度。 + +## 相关讲座 + +本讲座介绍了我们将在其他地方遇到的工具。 + +- 其他应用散度度量与统计推断之间联系的quantecon讲座包括{doc}`likelihood_ratio_process`、{doc}`wald_friedman`和{doc}`mix_model`。 + +- 在研究Lawrence Blume和David Easley的异质信念和金融市场模型的{doc}`likelihood_ratio_process_2`中,统计散度函数也占据核心地位。 + diff --git a/lectures/imp_sample.md b/lectures/imp_sample.md index b1356c88..70b79a85 100644 --- a/lectures/imp_sample.md +++ b/lectures/imp_sample.md @@ -11,7 +11,7 @@ kernelspec: name: python3 --- -# 计算似然比过程的均值 +# 似然比过程的均值 ```{contents} 目录 :depth: 2 @@ -21,9 +21,9 @@ kernelspec: 在{doc}`这篇讲座 `中,我们描述了似然比过程的一个特殊性质,即尽管它几乎必然收敛于零,但对于所有 $t \geq 0$,其均值都等于1。 -虽然在理论上(即在总体中)很容易验证这个特殊性质,但通过计算机模拟来验证它却具有挑战性,这需要应用大数定律,研究重复模拟的样本平均值。 +虽然在理论上(即在总体中)很容易验证这个特殊性质,但要通过计算机模拟来验证它却很具有挑战性,因为这需要应用大数定律来研究重复模拟的样本平均值。 -为了应对这个挑战,本讲座运用__重要性抽样__来加速样本平均值向总体均值的收敛。 +为了应对这个挑战,本讲座使用__重要性抽样__来加速样本平均值向总体均值的收敛。 我们使用重要性抽样来估计累积似然比 $L\left(\omega^t\right) = \prod_{i=1}^t \ell \left(\omega_i\right)$ 的均值。 @@ -33,7 +33,6 @@ kernelspec: import numpy as np from numba import jit, vectorize, prange 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'] @@ -43,13 +42,13 @@ from math import gamma ## 似然比的数学期望 -在{doc}`本讲座 `中,我们研究了似然比 $\ell \left(\omega_t\right)$ +在{doc}`这节课 `中,我们研究了似然比 $\ell \left(\omega_t\right)$ $$ \ell \left( \omega_t \right) = \frac{f\left(\omega_t\right)}{g\left(\omega_t\right)} $$ -其中 $f$ 和 $g$ 是具有参数 $F_a$、$F_b$、$G_a$、$G_b$ 的 Beta 分布的密度函数。 +其中 $f$ 和 $g$ 是参数为 $F_a$、$F_b$、$G_a$、$G_b$ 的Beta分布的密度函数。 假设独立同分布的随机变量 $\omega_t \in \Omega$ 由 $g$ 生成。 @@ -61,21 +60,20 @@ $$ 我们的目标是很好地近似数学期望 $E \left[ L\left(\omega^t\right) \right]$。 -在{doc}`本讲座 `中,我们证明了对所有 $t$ 来说,$E \left[ L\left(\omega^t\right) \right]$ 等于 1。 -我们想要检验当用模拟的样本平均值替代 $E$ 时,这个结论的准确程度如何。 +在{doc}`这节课 `中,我们证明了对所有 $t$,$E \left[ L\left(\omega^t\right) \right]$ 等于1。 -这比说起来要难做到,因为对于 +我们想要检验当用模拟的样本均值替代 $E$ 时,这个结论的准确程度如何。 -假设上述为Beta分布,当$t \rightarrow \infty$时,$L\left(\omega^t\right)$具有非常偏斜的分布,并且有很长的尾部。 +事实证明这比说起来要难,因为对于上述假设的Beta分布,当 $t \rightarrow \infty$ 时,$L\left(\omega^t\right)$ 具有非常偏斜的分布,且有很长的尾部。 -这个特性使得通过标准蒙特卡洛模拟方法来有效且准确地估计均值变得困难。 +这个特性使得用标准蒙特卡洛模拟方法来有效且准确地估计均值变得困难。 -在本讲中,我们将探讨标准蒙特卡洛方法为何会失效,以及**重要性抽样**如何提供一种计算上更高效的方法来近似累积似然比的均值。 +在本课中,我们将探讨标准蒙特卡洛方法为何会失效,以及**重要性抽样**如何提供一种计算上更有效的方法来近似累积似然比的均值。 -我们首先来看看密度函数`f`和`g`。 +我们首先来看一下密度函数`f`和`g`。 ```{code-cell} ipython3 -# 两个beta分布中的参数 +# 两个贝塔分布中的参数 F_a, F_b = 1, 1 G_a, G_b = 3, 1.2 @@ -90,17 +88,17 @@ g = jit(lambda w: p(w, G_a, G_b)) ``` ```{code-cell} ipython3 -w_range = np.linspace(1e-5, 1-1e-5, 1000) +w_range = np.linspace(1e-2, 1-1e-5, 1000) plt.plot(w_range, g(w_range), label='g') plt.plot(w_range, f(w_range), label='f') -plt.xlabel('$\omega$') +plt.xlabel(r'$\omega$') plt.legend() plt.title('密度函数 $f$ 和 $g$') plt.show() ``` -似然比为 `l(w)=f(w)/g(w)`。 +似然比是 `l(w)=f(w)/g(w)`。 ```{code-cell} ipython3 l = jit(lambda w: f(w) / g(w)) @@ -108,8 +106,8 @@ l = jit(lambda w: f(w) / g(w)) ```{code-cell} ipython3 plt.plot(w_range, l(w_range)) -plt.title('$\ell(\omega)$') -plt.xlabel('$\omega$') +plt.title(r'$\ell(\omega)$') +plt.xlabel(r'$\omega$') plt.show() ``` @@ -117,23 +115,23 @@ plt.show() 对 $\hat{E} \left[L\left(\omega^t\right)\right] = \hat{E} \left[\prod_{i=1}^t \ell \left(\omega_i\right)\right]$ 的蒙特卡洛近似会重复从 $g$ 中抽取 $\omega$,对每次抽取计算似然比 $ \ell(\omega) = \frac{f(\omega)}{g(\omega)}$,然后对所有抽取结果取平均值。 -由于当 $\omega \rightarrow 0$ 时 $g(\omega) \rightarrow 0$,这种模拟程序对样本空间 $[0,1]$ 中的某些重要部分采样不足,而这些部分在准确近似似然比 $\ell(\omega)$ 的数学期望时需要经常访问。 +由于当 $\omega \rightarrow 0$ 时 $g(\omega) \rightarrow 0$,这种模拟程序对样本空间 [0,1] 中的某些部分采样不足,而这些部分对于很好地近似似然比 $\ell(\omega)$ 的数学期望来说是需要经常访问的重要区域。 -我们将在下面通过数值方法说明这一点。 +我们在下面通过数值方法说明这一点。 ## 重要性采样 -我们通过使用称为**重要性采样**的_分布变换_来解决这个问题。 +我们通过使用一种称为**重要性采样**的_分布变换_来解决这个问题。 -在模拟过程中,我们不从$g$中抽样生成数据,而是使用另一个分布$h$来生成$\omega$的抽样。 +在模拟过程中,我们不从 $g$ 中抽取数据,而是使用另一个分布 $h$ 来生成 $\omega$ 的抽样。 -这个想法是设计$h$,使其在$\ell \left(\omega_t\right)$取值较大但在$g$下密度较低的$\Omega$区域进行过采样。 +这个想法是设计 $h$ 使其对 $\Omega$ 中那些 $\ell \left(\omega_t\right)$ 取值较大但在 $g$ 下密度较低的区域进行过采样。 -用这种方式构建样本后,在计算似然比的经验均值时,我们必须用$g$和$h$的似然比对每个实现进行加权。 +用这种方式构造样本后,当我们计算似然比的经验均值时,必须用 $g$ 和 $h$ 的似然比对每个实现值进行加权。 -通过这样做,我们恰当地考虑了使用$h$而不是$g$来模拟数据的事实。 +通过这样做,我们恰当地考虑到了我们使用$h$而不是$g$来模拟数据的事实。 -为了说明这一点,假设我们对${E}\left[\ell\left(\omega\right)\right]$感兴趣。 +为了说明,假设我们对${E}\left[\ell\left(\omega\right)\right]$感兴趣。 我们可以简单地计算: @@ -143,26 +141,25 @@ $$ 其中$\omega_i^g$表示$\omega_i$是从$g$中抽取的。 -但是利用重要性采样的见解,我们可以改为计算以下对象: +但是利用重要性抽样的见解,我们可以改为计算这个对象: $$ - \hat{E}^h \left[\ell\left(\omega\right) \frac{g(w)}{h(w)} \right] = \frac{1}{N} \sum_{i=1}^{N} \ell(w_i^h) \frac{g(w_i^h)}{h(w_i^h)} $$ -其中 $w_i$ 现在从重要性分布 $h$ 中抽取。 +其中$w_i$现在是从重要性分布$h$中抽取的。 -注意上述两个是完全相同的总体对象: +注意上述两个在总体上是完全相同的对象: $$ E^g\left[\ell\left(\omega\right)\right] = \int_\Omega \ell(\omega) g(\omega) d\omega = \int_\Omega \ell(\omega) \frac{g(\omega)}{h(\omega)} h(\omega) d\omega = E^h\left[\ell\left(\omega\right) \frac{g(\omega)}{h(\omega)}\right] $$ -## 选择采样分布 +## 选择抽样分布 -由于我们必须使用一个在原分布 $g$ 赋予低概率质量的区域具有较大概率质量的分布 $h$,我们使用 $h=Beta(0.5, 0.5)$ 作为我们的重要性分布。 +由于我们必须使用一个$h$,它在$g$赋予低概率的分布部分具有更大的质量,我们使用$h=Beta(0.5, 0.5)$作为我们的重要性分布。 -这些图比较了 $g$ 和 $h$。 +这些图比较了$g$和$h$。 ```{code-cell} ipython3 g_a, g_b = G_a, G_b @@ -182,21 +179,21 @@ plt.show() ## 近似累积似然比 -我们现在研究如何使用重要性采样来近似 +我们现在研究如何使用重要性抽样来近似 ${E} \left[L(\omega^t)\right] = \left[\prod_{i=1}^T \ell \left(\omega_i\right)\right]$。 -如上所述,我们的计划是从$q$中抽取序列$\omega^t$,然后对似然比进行适当的重新加权: +如上所述,我们的计划是从 $q$ 中抽取序列 $\omega^t$,然后对似然比进行适当的重新加权: $$ \hat{E}^p \left[L\left(\omega^t\right)\right] = \hat{E}^p \left[\prod_{t=1}^T \ell \left(\omega_t\right)\right] = \hat{E}^q \left[\prod_{t=1}^T \ell \left(\omega_t\right) \frac{p\left(\omega_{t}\right)}{q\left(\omega_{t}\right)}\right] = \frac{1}{N} \sum_{i=1}^{N}\left( \prod_{t=1}^{T} \ell(\omega_{i,t}^h)\frac{p\left(\omega_{i,t}^h\right)}{q\left(\omega_{i,t}^h\right)}\right) $$ -其中最后一个等式使用从重要性分布$q$中抽取的$\omega_{i,t}^h$。 +其中最后一个等式使用从重要性分布 $q$ 中抽取的 $\omega_{i,t}^h$。 -这里$\frac{p\left(\omega_{i,t}^q\right)}{q\left(\omega_{i,t}^q\right)}$是我们分配给每个数据点$\omega_{i,t}^q$的权重。 +这里 $\frac{p\left(\omega_{i,t}^q\right)}{q\left(\omega_{i,t}^q\right)}$ 是我们分配给每个数据点 $\omega_{i,t}^q$ 的权重。 -下面我们准备一个Python函数,用于计算任意beta分布$p$、$q$的重要性采样估计。 +下面我们准备一个Python函数,用于计算给定任何beta分布 $p$、$q$ 的重要性抽样估计。 ```{code-cell} ipython3 @jit(parallel=True) @@ -235,11 +232,11 @@ estimate(g_a, g_b, g_a, g_b, T=1, N=10000) estimate(g_a, g_b, h_a, h_b, T=1, N=10000) ``` -显然,即使在T=1时,我们的重要性采样估计也比蒙特卡洛估计更接近$1$。 +显然,即使在 $T=1$ 时,我们的重要性采样估计比蒙特卡洛估计更接近 $1$。 -在计算更长序列的期望值$E_0\left[L\left(\omega^t\right)\right]$时,差异会更大。 +在计算更长序列的期望值 $E_0\left[L\left(\omega^t\right)\right]$ 时,差异会更大。 -当设置$T=10$时,我们发现蒙特卡洛方法严重低估了均值,而重要性采样仍然产生接近其理论值1的估计。 +当设置 $T=10$ 时,我们发现蒙特卡洛方法严重低估了均值,而重要性采样仍然产生接近其理论值1的估计。 ```{code-cell} ipython3 estimate(g_a, g_b, g_a, g_b, T=10, N=10000) @@ -249,11 +246,21 @@ estimate(g_a, g_b, g_a, g_b, T=10, N=10000) estimate(g_a, g_b, h_a, h_b, T=10, N=10000) ``` +蒙特卡洛方法会低估是因为在分布$g$下,似然比$L(\omega^T) = \prod_{t=1}^T \frac{f(\omega_t)}{g(\omega_t)}$具有高度偏斜的分布。 + +从$g$中抽取的大多数样本产生较小的似然比,而真实均值需要偶尔出现的非常大的值,这些值很少被采样到。 + +在我们的情况下,由于当$\omega \to 0$时$g(\omega) \to 0$而$f(\omega)$保持不变,蒙特卡洛过程恰恰在似然比$\frac{f(\omega)}{g(\omega)}$最大的地方采样不足。 + +随着$T$的增加,这个问题呈指数级恶化,使标准蒙特卡洛方法变得越来越不可靠。 + +使用$q = h$的重要性采样通过更均匀地从对$f$和$g$都重要的区域采样来解决这个问题。 + ## 样本均值的分布 -接下来我们研究蒙特卡洛方法和重要性抽样方法的偏差和效率。 +接下来我们研究蒙特卡洛和重要性采样方法的偏差和效率。 -下面的代码生成使用蒙特卡洛和重要性抽样两种方法的估计值分布。 +下面的代码使用蒙特卡洛和重要性采样方法生成估计值的分布。 ```{code-cell} ipython3 @jit(parallel=True) @@ -288,9 +295,9 @@ np.nanmean(μ_L_p), np.nanvar(μ_L_p) np.nanmean(μ_L_q), np.nanvar(μ_L_q) ``` -虽然两种方法都倾向于给出接近1的${E} \left[\ell\left(\omega\right)\right]$均值估计,但重要性采样估计的方差更小。 +虽然两种方法都倾向于给出接近1的${E} \left[\ell\left(\omega\right)\right]$均值估计,但重要性抽样估计的方差更小。 -接下来,我们展示$\hat{E} \left[L\left(\omega^t\right)\right]$的估计分布,分别针对$T=1, 5, 10, 20$的情况。 +接下来,我们展示$\hat{E} \left[L\left(\omega^t\right)\right]$在$T=1, 5, 10, 20$这些情况下的估计值分布。 ```{code-cell} ipython3 fig, axs = plt.subplots(2, 2, figsize=(14, 10)) @@ -315,7 +322,7 @@ for i, t in enumerate([1, 5, 10, 20]): for n, bins, μ_hat, σ_hat in [[n_p, bins_p, μ_hat_p, σ_hat_p], [n_q, bins_q, μ_hat_q, σ_hat_q]]: idx = np.argmax(n) - axs[row, col].text(bins[idx], n[idx], '$\hat{μ}$='+f'{μ_hat:.4g}'+', $\hat{σ}=$'+f'{σ_hat:.4g}') + axs[row, col].text(bins[idx], n[idx], r'$\hat{μ}$='+f'{μ_hat:.4g}'+r', $\hat{σ}=$'+f'{σ_hat:.4g}') plt.show() ``` @@ -324,17 +331,15 @@ plt.show() 显然,随着$T$的增加,偏差也在增加。 -## 关于抽样分布选择的更多思考 +## 选择抽样分布 +++ -在上面,我们随意选择了$h = Beta(0.5,0.5)$作为重要性分布。 +在上面,我们任意选择了$h = Beta(0.5,0.5)$作为重要性分布。 -是否存在最优的重要性分布呢? +是否存在最优的重要性分布? -在我们这个特定的情况下,由于我们事先知道$E_0 \left[ L\left(\omega^t\right) \right] = 1$。 - -我们可以利用这个知识。 +在我们这个特定情况下,由于我们事先知道$E_0 \left[ L\left(\omega^t\right) \right] = 1$,我们可以利用这个知识。 因此,假设我们直接使用$h = f$。 @@ -365,10 +370,10 @@ b_list = [0.5, 1.2, 5.] ```{code-cell} ipython3 w_range = np.linspace(1e-5, 1-1e-5, 1000) -plt.plot(w_range, g(w_range), label=f'p=Beta({g_a}, {g_b})') -plt.plot(w_range, p(w_range, a_list[0], b_list[0]), label=f'g=Beta({a_list[0]}, {b_list[0]})') -plt.plot(w_range, p(w_range, a_list[1], b_list[1]), label=f'g=Beta({a_list[1]}, {b_list[1]})') -plt.plot(w_range, p(w_range, a_list[2], b_list[2]), label=f'g=Beta({a_list[2]}, {b_list[2]})') +plt.plot(w_range, g(w_range), label=f'g=Beta({g_a}, {g_b})') +plt.plot(w_range, p(w_range, a_list[0], b_list[0]), label=f'$h_1$=Beta({a_list[0]},{b_list[0]})') +plt.plot(w_range, p(w_range, a_list[1], b_list[1]), label=f'$h_2$=Beta({a_list[1]},{b_list[1]})') +plt.plot(w_range, p(w_range, a_list[2], b_list[2]), label=f'$h_3$=Beta({a_list[2]},{b_list[2]})') plt.title('真实数据生成过程 $g$ 和重要性分布 $h$') plt.legend() plt.ylim([0., 3.]) @@ -377,7 +382,7 @@ plt.show() 我们考虑两个额外的分布。 -作为提醒,$h_1$是我们上面使用的原始$Beta(0.5,0.5)$分布。 +提醒一下,$h_1$是我们上面使用的原始$Beta(0.5,0.5)$分布。 $h_2$是$Beta(1,1.2)$分布。 @@ -418,7 +423,7 @@ for i, t in enumerate([1, 20]): for n, bins, μ_hat, σ_hat in [[n_p, bins_p, μ_hat_p, σ_hat_p], [n_q, bins_q, μ_hat_q, σ_hat_q]]: idx = np.argmax(n) - axs[i].text(bins[idx], n[idx], '$\hat{μ}$='+f'{μ_hat:.4g}'+', $\hat{σ}=$'+f'{σ_hat:.4g}') + axs[i].text(bins[idx], n[idx], r'$\hat{μ}$='+f'{μ_hat:.4g}'+r', $\hat{σ}=$'+f'{σ_hat:.4g}') plt.show() ``` @@ -452,15 +457,15 @@ for i, t in enumerate([1, 20]): for n, bins, μ_hat, σ_hat in [[n_p, bins_p, μ_hat_p, σ_hat_p], [n_q, bins_q, μ_hat_q, σ_hat_q]]: idx = np.argmax(n) - axs[i].text(bins[idx], n[idx], '$\hat{μ}$='+f'{μ_hat:.4g}'+', $\hat{σ}=$'+f'{σ_hat:.4g}') + axs[i].text(bins[idx], n[idx], r'$\hat{μ}$='+f'{μ_hat:.4g}'+r', $\hat{σ}=$'+f'{σ_hat:.4g}') plt.show() ``` -然而,$h_3$显然是一个不适合我们问题的重要性抽样分布,在$T = 20$时,其均值估计与$1$相差甚远。 +然而,$h_3$显然是我们这个问题的一个不理想的重要性抽样分布,在$T = 20$时,其均值估计与1相差甚远。 注意,即使在$T = 1$时,使用重要性抽样的均值估计比直接用$g$进行抽样的偏差更大。 -因此,我们的模拟表明,相比于使用$h_3$作为重要性抽样分布,直接使用$g$进行蒙特卡洛近似会更好。 +因此,我们的模拟表明,对于我们的问题,直接使用$g$进行蒙特卡洛近似会比使用$h_3$作为重要性抽样分布更好。 diff --git a/lectures/likelihood_bayes.md b/lectures/likelihood_bayes.md index 7b53125d..fd8007b2 100644 --- a/lectures/likelihood_bayes.md +++ b/lectures/likelihood_bayes.md @@ -3,8 +3,10 @@ jupytext: text_representation: extension: .md format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -22,38 +24,39 @@ kernelspec: ## 概述 -本讲座描述了**似然比过程**在**贝叶斯学习**中所扮演的角色。 +本讲解描述了**似然比过程**在**贝叶斯学习**中所扮演的角色。 -如同{doc}`本讲座 `中所述,我们将使用{doc}`本讲座 `中的一个简单统计设定。 +如同{doc}`本讲 `中所述,我们将使用{doc}`本讲 `中的一个简单统计设置。 我们将重点关注似然比过程和**先验**概率如何决定**后验**概率。 -我们将推导出今天的后验概率作为昨天后验概率和今天似然过程乘法增量的函数的一个便捷递归公式。 +我们将推导出一个便利的递归公式,表示今天的后验概率是昨天后验概率和今天似然过程乘法增量的函数。 -我们还将介绍该公式的一个有用推广,该推广将今天的后验概率表示为初始先验概率和今天似然比过程实现值的函数。 +我们还将介绍该公式的一个有用推广,该推广将今天的后验概率表示为初始先验和今天似然比过程实现值的函数。 -我们将研究在我们的设定下,贝叶斯学习者如何最终学习到生成数据的概率分布,这一结果基于在{doc}`本讲座 `中研究的似然比过程的渐近行为。 +我们将研究在我们的设置中,贝叶斯学习者如何最终学习到生成数据的概率分布,这个结果 -我们还将深入研究贝叶斯学习者的心理,研究其主观信念下的动态过程。 +这建立在{doc}`本讲座 `中研究的似然比过程的渐近行为之上。 -本讲座提供的技术结果是{doc}`本讲座 `、{doc}`本讲座 `和{doc}`本讲座 `中将要研究的结果的基础。 +我们还将深入探讨贝叶斯学习者的心理,研究其主观信念下的动态变化。 -我们首先加载一些Python模块。 +本讲座提供了技术性结果,这些结果是{doc}`本讲座 `、{doc}`本讲座 `和{doc}`本讲座 `中将要研究的结果的基础。 + +我们先加载一些Python模块。 ```{code-cell} ipython3 :hide-output: false -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) #set default figure size import numpy as np from numba import vectorize, jit, prange from math import gamma import pandas as pd +from scipy.integrate import quad + import seaborn as sns colors = sns.color_palette() @@ -66,17 +69,17 @@ set_seed() ## 背景设置 -我们首先回顾{doc}`本讲座 `中的背景设置,这里我们也将采用相同的设置。 +我们首先回顾{doc}`本讲座 `中的设置,这也是我们在这里采用的设置。 一个非负随机变量 $W$ 具有两个概率密度函数之一,要么是 $f$,要么是 $g$。 -在时间开始之前,自然界就一劳永逸地决定了是从 $f$ 还是从 $g$ 中进行一系列独立同分布的抽样。 +在时间开始之前,自然界一劳永逸地决定是从 $f$ 还是从 $g$ 中进行一系列独立同分布的抽样。 -我们有时会用 $q$ 表示自然界一劳永逸选择的密度函数,所以 $q$ 要么是 $f$ 要么是 $g$,且是永久性的。 +我们有时会用 $q$ 表示自然界一劳永逸选择的密度,所以 $q$ 要么是 $f$ 要么是 $g$,且是永久性的。 -自然界知道它永久性地从哪个密度函数中抽样,但我们这些观察者并不知道。 +自然界知道它永久从哪个密度中抽样,但我们这些观察者并不知道。 -我们知道 $f$ 和 $g$ 这两个密度函数,但我们不知道自然界选择了哪一个。 +我们知道 $f$ 和 $g$ 这两个密度,但不知道自然界选择了哪一个。 但我们想要知道。 @@ -84,33 +87,40 @@ set_seed() 我们观察到一个序列 $\{w_t\}_{t=1}^T$,它包含 $T$ 个从 $f$ 或 $g$ 中独立同分布抽取的样本。 -我们想要利用这些观测数据来推断自然界选择了 $f$ 还是 $g$。 +我们想要利用这些观测来推断自然界选择了 $f$ 还是 $g$。 **似然比过程**是完成这项任务的有用工具。 -首先,我们定义似然比过程的关键组成部分,即时间$t$的似然比,作为随机变量 +首先,我们定义似然比过程的关键组成部分,即时间 $t$ 的似然比,它是一个随机变量: $$ \ell (w_t)=\frac{f\left(w_t\right)}{g\left(w_t\right)},\quad t\geq1. $$ -我们假设$f$和$g$在随机变量$W$的可能实现值的相同区间上都具有正概率。 +我们假设 $f$ 和 $g$ 在随机变量 $W$ 可能实现值的相同区间上都赋予正概率。 + +这意味着在 $g$ 密度下,$\ell (w_t)= \frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}$ 显然是一个均值为1的非负随机变量。 -这意味着在$g$密度下,$\ell (w_t)= -\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}$ -显然是一个均值为1的非负随机变量。 +序列的**似然比过程** -对序列$\left\{ w_{t}\right\} _{t=1}^{\infty}$的**似然比过程**定义为 +$\left\{ w_{t}\right\} _{t=1}^{\infty}$ 定义如下: $$ L\left(w^{t}\right)=\prod_{i=1}^{t} \ell (w_i), $$ -其中$w^t=\{ w_1,\dots,w_t\}$是直到时间$t$(包括$t$)的观测历史。 +其中 $w^t=\{ w_1,\dots,w_t\}$ 是直到时间 $t$ (包括 $t$)的观测历史。 -有时为简便起见,我们会写作$L_t = L(w^t)$。 +有时为简便起见,我们会写作 + +$$ +L_t = L(w^t) = \frac{f(w^t)}{g(w^t)} +$$ -注意,似然比过程满足以下*递归*或*乘法分解* +这里我们使用如下约定: +$f(w^t) = f(w_1) f(w_2) \ldots f(w_t)$ 且 $g(w^t) = g(w_1) g(w_2) \ldots g(w_t)$。 + +注意,似然过程满足以下*递归*或*乘法分解*: $$ L(w^t) = \ell (w_t) L (w^{t-1}) . @@ -118,10 +128,10 @@ $$ 似然比及其对数是使用 Neyman 和 Pearson 经典频率派方法进行推断的关键工具 {cite}`Neyman_Pearson`。 -我们将再次使用 {doc}`这篇讲座 ` 中的 Python 代码,该代码将 $f$ 和 $g$ 评估为两个不同的贝塔分布,然后通过从*某个*概率分布(例如,从 $g$ 中进行 IID 抽样)生成序列 $w^t$ 来计算和模拟相关的似然比过程。 +我们将再次使用来自{doc}`本讲座 `的以下 Python 代码,该代码将 $f$ 和 $g$ 评估为两个不同的贝塔分布,然后通过从*某个*概率分布(例如,从 $g$ 生成的 IID 序列)生成序列 $w^t$ 来计算和模拟相关的似然比过程。 ```{code-cell} ipython3 -# 两个贝塔分布的参数 +# Parameters in the two beta distributions. F_a, F_b = 1, 1 G_a, G_b = 3, 1.2 @@ -130,7 +140,7 @@ def p(x, a, b): r = gamma(a + b) / (gamma(a) * gamma(b)) return r * x** (a-1) * (1 - x) ** (b-1) -# 两个密度函数 +# The two density functions. f = jit(lambda x: p(x, F_a, F_b)) g = jit(lambda x: p(x, G_a, G_b)) ``` @@ -169,100 +179,135 @@ l_seq_f = np.cumprod(l_arr_f, axis=1) ## 似然比过程和贝叶斯定律 -设$\pi_t$为贝叶斯后验概率,定义为 +设 $\pi_0 \in [0,1]$ 是贝叶斯统计学家对自然生成的 $w^t$ 序列是来自分布 $f$ 的独立同分布抽样的先验概率。 + +* 这里的"概率"应被理解为总结或表达主观观点的一种方式 +* 它**不**意味着样本量无限增长时的预期相对频率 + +设 $\pi_{t+1}$ 是定义如下的贝叶斯后验概率: $$ -\pi_t = {\rm Prob}(q=f|w^t) -$$ +\pi_{t+1} = {\rm Prob}(q=f|w^{t+1}) +$$ (eq:defbayesposterior) -似然比过程是控制后验概率$\pi_t$演化公式中的主要因素,这是**贝叶斯定律**的一个实例。 +似然比过程是后验概率 $\pi_t$ 演化公式中的主要角色,这是**贝叶斯定律**的一个实例。 -贝叶斯定律表明$\{\pi_t\}$遵循以下递归式 +让我们推导 $\pi_{t+1}$ 的两个公式,一个用似然比 $l(w_t)$ 表示,另一个用 $L(w^t)$ 表示。 -```{math} -:label: eq_recur1 +首先,我们使用以下符号约定: -\pi_t=\frac{\pi_{t-1} l_t(w_t)}{\pi_{t-1} l_t(w_t)+1-\pi_{t-1}} -``` +* $f(w^{t+1}) \equiv f(w_1) f(w_2) \cdots f(w_{t+1})$ +* $g(w^{t+1}) \equiv g(w_1) g(w_2) \cdots g(w_{t+1})$ +* $\pi_0 ={\rm Prob}(q=f |\emptyset)$ +* $\pi_t = {\rm Prob}(q=f |w^t)$ -其中$\pi_{0}$是$q = f$的贝叶斯先验概率,即在未观察到任何数据时,基于个人或主观判断对$q$的信念。 +这里符号 $\emptyset$ 表示"空集"或"无数据"。 -下面我们定义一个Python函数,该函数根据递归式{eq}`eq_recur1`使用似然比$\ell$来更新信念$\pi$ +在没有数据的情况下,我们的贝叶斯统计学家认为序列 $w^{t+1}$ 的概率密度是: -```{code-cell} ipython3 -@jit -def update(π, l): - "使用似然l更新π" +$$ +{\rm Prob}(w^{t+1} |\emptyset) = \pi_0 f(w^{t+1})+ (1 - \pi_0) g(w^{t+1}) +$$ - # 更新信念 - π = π * l / (π * l + 1 - π) +概率定律表明,事件 $A$ 和 $B$ 的联合分布 ${\rm Prob}(AB)$ 与条件分布 ${\rm Prob}(A |B)$ 和 ${\rm Prob}(B |A)$ 之间的关系是: - return π -``` +$$ -公式 {eq}`eq_recur1` 可以通过迭代推广,从而得到时间 $t$ 的后验概率 $\pi_{t+1}$ 作为时间 $0$ 的先验概率 $\pi_0$ 和似然比过程 $L(w^{t+1})$ 的函数表达式。 +{\rm Prob}(AB) = {\rm Prob}(A |B) {\rm Prob}(B) = {\rm Prob}(B |A) {\rm Prob}(A) . +$$ (eq:problawAB) -首先,注意更新规则 +我们关注的事件是 $$ -\pi_{t+1} -=\frac{\pi_{t}\ell \left(w_{t+1}\right)} -{\pi_{t}\ell \left(w_{t+1}\right)+\left(1-\pi_{t}\right)} +A = \{q=f\}, \quad B = \{w^{t+1}\}, \quad $$ -意味着 +其中大括号$\{\cdot\}$是我们用来表示"事件"的简写。 + +因此在我们的设定中,概率法则{eq}`eq:problawAB`意味着 $$ -\begin{aligned} -\frac{1}{\pi_{t+1}} - &=\frac{\pi_{t}\ell \left(w_{t+1}\right) - +\left(1-\pi_{t}\right)}{\pi_{t}\ell \left(w_{t+1}\right)} \\ - &=1-\frac{1}{\ell \left(w_{t+1}\right)} - +\frac{1}{\ell \left(w_{t+1}\right)}\frac{1}{\pi_{t}}. -\end{aligned} +{\rm Prob}(q=f |w^{t+1}) {\rm Prob}(w^{t+1} |\emptyset) = {\rm Prob}(w^{t+1} |q=f) {\rm Prob}(q=f | \emptyset) $$ +或者 + $$ -\Rightarrow -\frac{1}{\pi_{t+1}}-1 -=\frac{1}{\ell \left(w_{t+1}\right)}\left(\frac{1}{\pi_{t}}-1\right). +\pi_{t+1} \left[\pi_0 f(w^{t+1}) + (1- \pi_0) g(w^{t+1})\right] = f(w^{t+1}) \pi_0 $$ -因此 +或者 $$ -\begin{aligned} - \frac{1}{\pi_{t+1}}-1 - =\frac{1}{\prod_{i=1}^{t+1}\ell \left(w_{i}\right)} - \left(\frac{1}{\pi_{0}}-1\right) +\pi_{t+1} = \frac{ f(w^{t+1}) \pi_0 }{\pi_0 f(w^{t+1}) + (1- \pi_0) g(w^{t+1})} +$$ -=\frac{1}{L\left(w^{t+1}\right)}\left(\frac{1}{\pi_{0}}-1\right). -\end{aligned} +将上述等式右边的分子和分母都除以$g(w^{t+1})$得到 + +```{math} +:label: eq_Bayeslaw1033 + +\pi_{t+1}=\frac{\pi_{0}L\left(w^{t+1}\right)}{\pi_{0}L\left(w^{t+1}\right)+1-\pi_{0}} . +``` + +公式{eq}`eq_Bayeslaw1033`可以被视为在看到数据批次$\left\{ w_{i}\right\} _{i=1}^{t+1}$后对先验概率$\pi_0$的一步修正。 + +公式{eq}`eq_Bayeslaw1033`显示了似然比过程$L\left(w^{t+1}\right)$在确定后验概率$\pi_{t+1}$中起到的关键作用。 + +公式{eq}`eq_Bayeslaw1033`是理解以下观点的基础:由于似然比过程在$t \rightarrow + \infty$时的行为特征,似然比过程在决定$\pi_t$的极限行为时会主导初始先验$\pi_0$的影响。 + +### 递归公式 + +我们可以使用类似的推理方法得到公式{eq}`eq_Bayeslaw1033`的递归版本。 + +概率法则表明 + +$$ +{\rm Prob}(q=f|w^{t+1}) = \frac { {\rm Prob}(q=f|w^{t} ) f(w_{t+1})}{ {\rm Prob}(q=f|w^{t} ) f(w_{t+1}) + (1 - {\rm Prob}(q=f|w^{t} )) g(w_{t+1})} $$ -由于 $\pi_{0}\in\left(0,1\right)$ 且 -$L\left(w^{t+1}\right)>0$,我们可以验证 -$\pi_{t+1}\in\left(0,1\right)$。 +或 + +$$ +\pi_{t+1} = \frac { \pi_t f(w_{t+1})}{ \pi_t f(w_{t+1}) + (1 - \pi_t) g(w_{t+1})} +$$ (eq:bayes150) + +显然,上述方程表明 + +$$ +{\rm Prob}(q=f|w^{t+1}) = \frac{{\rm Prob}(q=f|w^{t}) f(w_{t+1} )} {{\rm Prob}(w_{t+1})} +$$ -通过重新整理前面的方程,我们可以将 $\pi_{t+1}$ 表示为 -$L\left(w^{t+1}\right)$(即 $t+1$ 时的似然比过程) -和初始先验 $\pi_{0}$ 的函数 +将方程{eq}`eq:bayes150`右侧的分子和分母都除以$g(w_{t+1})$得到递归式 ```{math} -:label: eq_Bayeslaw103 +:label: eq_recur1 -\pi_{t+1}=\frac{\pi_{0}L\left(w^{t+1}\right)}{\pi_{0}L\left(w^{t+1}\right)+1-\pi_{0}} . +\pi_{t+1}=\frac{\pi_{t} l_t(w_{t+1})}{\pi_{t} l_t(w_{t+1})+1-\pi_{t}} ``` -公式 {eq}`eq_Bayeslaw103` 是公式 {eq}`eq_recur1` 的推广。 +其中$\pi_{0}$是$q = f$的贝叶斯先验概率,即在我们尚未看到任何数据时基于个人或主观判断的关于$q$的信念。 + +通过迭代方程{eq}`eq_recur1`可以推导出公式{eq}`eq_Bayeslaw1033`。 + +下面我们定义一个Python函数,该函数根据递归式{eq}`eq_recur1`使用似然比$\ell$更新信念$\pi$ + +```{code-cell} ipython3 +@jit +def update(π, l): + "Update π using likelihood l" + + # Update belief + π = π * l / (π * l + 1 - π) -公式 {eq}`eq_Bayeslaw103` 可以被视为在观察到数据批次 $\left\{ w_{i}\right\} _{i=1}^{t+1}$ 后对先验概率 $\pi_0$ 的一步修正。 + return π +``` -公式 {eq}`eq_Bayeslaw103` 显示了似然比过程 $L\left(w^{t+1}\right)$ 在确定后验概率 $\pi_{t+1}$ 中所起的关键作用。 +如上所述,公式 {eq}`eq_Bayeslaw1033` 显示了似然比过程 $L\left(w^{t+1}\right)$ 在确定后验概率 $\pi_{t+1}$ 中发挥的关键作用。 -公式 {eq}`eq_Bayeslaw103` 是一个基础,它揭示了由于似然比过程在 $t \rightarrow + \infty$ 时的行为特征,似然比过程在决定 $\pi_t$ 的极限行为时比初始先验 $\pi_0$ 起着更主导的作用。 +当 $t \rightarrow + \infty$ 时,似然比过程在决定 $\pi_t$ 的极限行为中占主导地位,超过了初始先验 $\pi_0$ 的影响。 -为了说明这一见解,我们将绘制图表,展示似然比过程 $L_t$ 的**一条**模拟路径,以及与**相同**似然比过程实现但**不同**初始先验概率 $\pi_{0}$ 相关联的两条 $\pi_t$ 路径。 +为了说明这一见解,我们将绘制图表,展示似然比过程 $L_t$ 的**一条**模拟路径,以及与*相同*似然比过程实现但*不同*初始先验概率 $\pi_{0}$ 相关联的两条 $\pi_t$ 路径。 首先,我们在Python中设定两个 $\pi_0$ 的值。 @@ -286,9 +331,9 @@ for t in range(T): fig, ax1 = plt.subplots() for i in range(2): - ax1.plot(range(T+1), π_seq_f[i, :], label=f"$\pi_0$={π_seq_f[i, 0]}") + ax1.plot(range(T+1), π_seq_f[i, :], label=fr"$\pi_0$={π_seq_f[i, 0]}") -ax1.set_ylabel("$\pi_t$") +ax1.set_ylabel(r"$\pi_t$") ax1.set_xlabel("t") ax1.legend() ax1.set_title("当f支配数据时") @@ -320,9 +365,9 @@ for t in range(T): fig, ax1 = plt.subplots() for i in range(2): - ax1.plot(range(T+1), π_seq_g[i, :], label=f"$\pi_0$={π_seq_g[i, 0]}") + ax1.plot(range(T+1), π_seq_g[i, :], label=fr"$\pi_0$={π_seq_g[i, 0]}") -ax1.set_ylabel("$\pi_t$") +ax1.set_ylabel(r"$\pi_t$") ax1.set_xlabel("t") ax1.legend() ax1.set_title("当g支配数据时") @@ -334,7 +379,7 @@ ax2.set_ylabel("$log(L(w^{t}))$") plt.show() ``` -以下我们提供Python代码,验证自然永久地选择从密度$f$中抽取。 +以下我们提供Python代码,验证自然界永久选择从密度$f$中抽取。 ```{code-cell} ipython3 π_seq = np.empty((2, T+1)) @@ -349,78 +394,233 @@ for i in range(2): np.abs(π_seq - π_seq_f).max() < 1e-10 ``` -因此我们得出结论,似然比过程是公式{eq}`eq_Bayeslaw103`中的一个关键组成部分,该公式用于计算贝叶斯学习者对自然界从密度$g$中重复抽取得到历史$w^t$的后验概率。 +因此,我们得出结论,似然比过程是公式{eq}`eq_Bayeslaw1033`中贝叶斯后验概率的关键组成部分,该后验概率表示自然界从密度$f$中重复抽样得到历史$w^t$的概率。 + +## 另一种时序协议 + +让我们研究当自然界在不同的时序协议下生成历史$w^t = \{w_1, w_2, \dots, w_t\}$时,后验概率$\pi_t = {\rm Prob}(q=f|w^{t})$的表现。 +到目前为止,我们假设在时间1之前,自然界以某种方式选择从**要么**$f$**要么**$g$中进行iid序列抽样来得到$w^t$。 +自然界关于是从$f$还是从$g$中抽样的决定因此是**永久性的**。 +现在我们假设一个不同的时序协议,在**每个**时期$t =1, 2, \ldots$之前,自然界: -## 后验概率$\{\pi_t\}$在主观概率分布下的行为 +* 抛一个权重为$x$的硬币,然后 +* 如果抛出"正面"就从$f$中抽样 +* 如果抛出"反面"就从$g$中抽样 +在这个时序协议下,自然界**既不**永久地从$f$抽样**也不**永久地从$g$抽样,所以认为自然界在**永久地**从其中之一进行i.i.d.抽样的统计学家是错误的。 -我们将通过简要研究贝叶斯学习者在贝叶斯法则产生的主观信念$\pi_t$下期望学到什么来结束本讲。 +* 事实上,自然界实际上是**永久地**从$f$和$g$的$x$-混合分布中抽样——当$x \in (0,1)$时,这个分布既不是$f$也不是$g$ + +因此,贝叶斯先验 $\pi_0$ 和方程 {eq}`eq_Bayeslaw1033` 描述的后验概率序列**不应该**被解释为统计学家对于另一种时序协议(即自然从 $f$ 和 $g$ 的 $x$ 混合分布中抽样)下混合参数 $x$ 的观点。 + +当我们回顾方程 {eq}`eq:defbayesposterior` 中 $\pi_t$ 的定义时,这一点就很清楚了。为方便起见,我们在这里重复该方程: + +$$ +\pi_{t+1} = {\rm Prob}(q=f|w^{t+1}) +$$ + +让我们编写一些 Python 代码来研究当自然实际上既不是从 $f$ 也不是从 $g$ 生成数据,而是从两个 beta 分布的 $x$ 混合分布中进行 i.i.d. 抽样时,$\pi_t$ 的行为。 + +```{note} +这是一个统计学家的模型被错误指定的情况,因此我们应该预期相对于 $x$ 混合分布的 Kullback-Liebler 散度将影响结果。 +``` + +我们可以研究对于自然混合概率 $x$ 的不同值,$\pi_t$ 会如何表现。 + +首先,让我们创建一个函数来模拟混合时序协议下的数据: + +```{code-cell} ipython3 +@jit +def simulate_mixture_path(x_true, T): + """ + 模拟混合时序协议下的 T 个观测值。 + """ + w = np.empty(T) + for t in range(T): + if np.random.rand() < x_true: + w[t] = np.random.beta(F_a, F_b) + else: + w[t] = np.random.beta(G_a, G_b) + return w +``` + +让我们从这个混合模型生成一系列观测值,其真实混合概率为$x=0.5$。 + +我们首先用这个序列来研究$\pi_t$的行为。 + +```{note} +之后,我们可以用它来研究一个统计学家如何在知道数据是由$f$和$g$的$x$混合生成的情况下,构建$x$的最大似然估计或贝叶斯估计,以及$f$和$g$的自由参数。 +``` + +```{code-cell} ipython3 +x_true = 0.5 +T_mix = 200 + +# 三个不同的先验,均值分别为0.25, 0.5, 0.75 +prior_params = [(1, 3), (1, 1), (3, 1)] +prior_means = [a/(a+b) for a, b in prior_params] + +# 从混合模型生成一条观测路径 +set_seed() +w_mix = simulate_mixture_path(x_true, T_mix) +``` + +### 在错误模型下 $\pi_t$ 的行为 + +让我们研究当数据实际上是由 $f$ 和 $g$ 的 $x$-混合生成时,从 $f$ 永久抽取的后验概率 $\pi_t$ 的表现。 + +```{code-cell} ipython3 +fig, ax = plt.subplots(figsize=(10, 6)) +T_plot = 200 + +for i, mean0 in enumerate(prior_means): + π_wrong = np.empty(T_plot + 1) + π_wrong[0] = mean0 + + # 计算混合数据的似然比 + for t in range(T_plot): + l_t = f(w_mix[t]) / g(w_mix[t]) + π_wrong[t + 1] = update(π_wrong[t], l_t) + + ax.plot(range(T_plot + 1), π_wrong, + label=fr'$\pi_0 = ${mean0:.2f}', + color=colors[i], linewidth=2) + +ax.axhline(y=x_true, color='black', linestyle='--', + label=f'True x = {x_true}', linewidth=2) +ax.set_xlabel('t') +ax.set_ylabel(r'$\pi_t$') +ax.legend() +plt.show() +``` + +显然,$\pi_t$ 收敛到1。 + +这表明模型得出结论认为数据是由 $f$ 生成的。 + +为什么会这样呢? + +给定 $x = 0.5$,数据生成过程是 $f$ 和 $g$ 的混合:$m(w) = \frac{1}{2}f(w) + \frac{1}{2}g(w)$。 + +让我们检查一下混合分布 $m$ 与 $f$ 和 $g$ 之间的 [KL散度](rel_entropy)。 + +```{code-cell} ipython3 +def compute_KL(f, g): + """ + 计算KL散度 KL(f, g) + """ + integrand = lambda w: f(w) * np.log(f(w) / g(w)) + val, _ = quad(integrand, 1e-5, 1-1e-5) + return val + + +def compute_div_m(f, g): + """ + 计算Jensen-Shannon散度 + """ + def m(w): + return 0.5 * (f(w) + g(w)) + + return compute_KL(m, f), compute_KL(m, g) + + +KL_f, KL_g = compute_div_m(f, g) + +print(f'KL(m, f) = {KL_f:.3f}\nKL(m, g) = {KL_g:.3f}') +``` + +由于 $KL(m, f) < KL(m, g)$,$f$ 相对于混合分布 $m$ 来说"更接近"。 + +因此根据我们在{doc}`likelihood_ratio_process`中关于 KL 散度和似然比过程的讨论,当 $t \to \infty$ 时,$\log(L_t) \to \infty$。 + +现在回看关键方程{eq}`eq_Bayeslaw1033`。 + +考虑函数 + +$$ +h(z) = \frac{\pi_0 z}{\pi_0 z + 1 - \pi_0}. +$$ + +极限 $\lim_{z \to \infty} h(z)$ 等于1。 + +因此对任意 $\pi_0 \in (0,1)$,当 $t \to \infty$ 时,$\pi_t \to 1$。 + +这解释了我们在上图中观察到的现象。 + +但我们如何学习真实的混合参数 $x$? + +这个主题将在{doc}`mix_model`中讨论。 + +我们将在{doc}`mix_model`的练习中探讨如何学习真实的混合参数 $x$。 + +## 后验概率 $\{\pi_t\}$ 在主观概率分布下的行为 + +我们将通过简要研究贝叶斯学习者在贝叶斯法则产生的主观信念 $\pi_t$ 下期望学到什么来结束本讲。 这将为我们应用贝叶斯法则作为学习理论提供一些视角。 -正如我们将看到的,在每个时间$t$,贝叶斯学习者知道他将会感到惊讶。 +我们将看到,在每个时刻 $t$,贝叶斯学习者知道他将会感到惊讶。 但他预期新信息不会导致他改变信念。 而且在他的主观信念下,平均来说确实不会改变。 -我们将继续在这样一个设定下讨论:McCall劳动者知道他的工资连续抽样要么来自分布$F$要么来自分布$G$,但他不知道是这两个分布中的哪一个 +我们将继续在这样的设定下讨论:McCall工人知道他的工资连续抽样要么来自 $F$ 要么来自 $G$,但不知道是这两个分布中的哪一个。 -自然在时间$0$之前就已经一劳永逸地做出了选择。 +自然在时间 $0$ 之前已经一次性地做出了选择。 -我们将回顾、重申并重新整理我们在上文和相关讲座中遇到的一些公式。 +让我们回顾、重申并重新整理我们在上文和相关讲座中遇到的一些公式。 -劳动者的初始信念导致了一个可能无限序列的抽取$w_0, w_1, \ldots $的联合概率分布。 +工人的初始信念导致了一个关于潜在无限序列抽样 $w_0, w_1, \ldots $ 的联合概率分布。 -贝叶斯定律只是概率定律的一个应用,用于计算第$t$次抽取$w_t$在已知$[w_0, \ldots, w_{t-1}]$条件下的条件分布。 +贝叶斯定律仅仅是概率法则的应用,用于计算第 $t$ 次抽样 $w_t$ 在已知 $[w_0, \ldots, w_{t-1}]$ 条件下的条件分布。 -在我们的劳动者对自然选择分布$F$赋予主观概率$\pi_{-1}$之后,我们实际上从一开始就假设决策者**知道**过程$\{w_t\}_{t=0}$的联合分布。 +在我们的工人对自然选择分布 $F$ 赋予主观概率 $\pi_{-1}$ 后,我们实际上从一开始就假设决策者**知道**过程 $\{w_t\}_{t=0}$ 的联合分布。 -我们假设劳动者也知道概率论的定律。 +我们假设工人也知道概率论的法则。 -一种值得尊重的观点认为,贝叶斯定律与其说是一种学习理论,不如说是一种关于信息流入对决策者的影响的陈述,这个决策者认为他从一开始就知道真相(即联合概率分布)。 +一个值得尊重的观点是,贝叶斯定律与其说是一个学习理论,不如说是一个关于信息流入对决策者(他认为从一开始就知道真相,即联合概率分布)的影响的陈述。 -### 技术细节再述 +### 再谈机械细节 -在时间$0$**之前**获得工资报价时,劳动者认为分布为$F$的概率为$\pi_{-1} \in (0,1)$。 +在时间 $0$ **之前**抽取工资报价时,工人将概率 $\pi_{-1} \in (0,1)$ 赋予分布 $F$。 -在时间$0$获得工资之前,劳动者认为$w_0$的密度函数为: +在时间 $0$ 抽取工资之前,工人因此认为 $w_0$ 的密度是 $$ h(w_0;\pi_{-1}) = \pi_{-1} f(w_0) + (1-\pi_{-1}) g(w_0). $$ -令$a \in \{ f, g\} $为一个指标,表示自然是永久地从分布$f$还是从分布$g$中抽取。 +令 $a \in \{ f, g\} $ 为一个指标,表示自然是永久地从分布 $f$ 还是从分布 $g$ 中抽样。 -在获得$w_0$后,劳动者使用贝叶斯定律推导出密度为$f(w)$的后验概率$\pi_0 = {\rm Prob}{a = f | w_0} $为: +在绘制$w_0$后,工人使用贝叶斯定理推导出后验概率$\pi_0 = {\rm Prob}({a = f | w_0})$(即密度为$f(w)$的概率)为: $$ \pi_0 = { \pi_{-1} f(w_0) \over \pi_{-1} f(w_0) + (1-\pi_{-1}) g(w_0)} . $$ -一般来说,在进行第$t$次抽取并观察到$w_t, w_{t-1}, \ldots, w_0$后,劳动者认为 -$w_{t+1}$是从分布$F$中抽取的概率为 +更一般地,在进行第$t$次抽取并观察到$w_t, w_{t-1}, \ldots, w_0$后,工人认为$w_{t+1}$是从分布$F$中抽取的概率为: $$ \pi_t = \pi_t(w_t | \pi_{t-1}) \equiv { \pi_{t-1} f(w_t)/g(w_t) \over \pi_{t-1} f(w_t)/g(w_t) + (1-\pi_{t-1})} $$ (eq:like44) -或者 +或 $$ \pi_t=\frac{\pi_{t-1} l_t(w_t)}{\pi_{t-1} l_t(w_t)+1-\pi_{t-1}} $$ -而在给定$w_t, w_{t-1}, \ldots, w_0$条件下$w_{t+1}$的密度为 +而在给定$w_t, w_{t-1}, \ldots, w_0$条件下$w_{t+1}$的密度为: $$ h(w_{t+1};\pi_{t}) = \pi_{t} f(w_{t+1}) + (1-\pi_{t}) g(w_{t+1}) . $$ -注意到 +注意到: $$ \begin{aligned} @@ -433,31 +633,33 @@ $$ 因此过程$\pi_t$是一个**鞅**。 -事实上,它是一个**有界鞅**,因为每个$\pi_t$作为一个概率,都在0和1之间。 +事实上,它是一个**有界鞅**,因为每个$\pi_t$作为概率都在0和1之间。 -在上述等式的第一行中,第一个括号中的项仅仅是作为$w_{t}$的函数的$\pi_t$,而第二个括号中的项是在给定$w_{t-1}, \ldots , w_0$条件下$w_{t}$的密度,或等价地说,是在给定$w_{t-1}, \ldots , w_0$的*充分统计量*$\pi_{t-1}$条件下的密度。 +在上述等式串的第一行中,第一个方括号中的项就是作为$w_{t}$函数的$\pi_t$,而第二个方括号中的项是在给定条件下$w_{t}$的密度。 -注意,这里我们是在第二个括号项中描述的**主观**密度下计算$E(\pi_t | \pi_{t-1})$。 +在 $w_{t-1}, \ldots , w_0$ 上,或等价地在 $w_{t-1}, \ldots , w_0$ 的*充分统计量* $\pi_{t-1}$ 上的条件。 -因为$\{\pi_t\}$是一个有界鞅序列,根据**鞅收敛定理**,$\pi_t$几乎必然收敛到$[0,1]$区间内的一个随机变量。 +注意这里我们是在括号中第二项所描述的**主观**密度下计算 $E(\pi_t | \pi_{t-1})$。 -实际上,这意味着概率为1的样本路径$\{\pi_t\}_{t=0}^\infty$是收敛的。 +因为 $\{\pi_t\}$ 是一个有界鞅序列,根据**鞅收敛定理**,$\pi_t$ 几乎必然收敛到 $[0,1]$ 中的一个随机变量。 -根据该定理,不同的样本路径可以收敛到不同的极限值。 +实际上,这意味着概率为1的样本路径 $\{\pi_t\}_{t=0}^\infty$ 是收敛的。 -因此,让$\{\pi_t(\omega)\}_{t=0}^\infty$表示由特定$\omega \in \Omega$索引的特定样本路径。 +根据定理,不同的样本路径可以收敛到不同的极限值。 -我们可以把自然看作是从概率分布 ${\textrm{Prob}} \Omega$ 中抽取一个 $\omega \in \Omega$,然后生成过程的单个实现(或称_模拟_)$\{\pi_t(\omega)\}_{t=0}^\infty$。 +因此,让 $\{\pi_t(\omega)\}_{t=0}^\infty$ 表示由特定 $\omega \in \Omega$ 索引的特定样本路径。 -当 $t \rightarrow +\infty$ 时,$\{\pi_t(\omega)\}_{t=0}^\infty$ 的极限点是一个随机变量的实现,这个随机变量是通过从 $\Omega$ 中采样 $\omega$ 并重复构造 $\{\pi_t(\omega)\}_{t=0}^\infty$ 得到的。 +我们可以认为自然从概率分布 ${\textrm{Prob}} \Omega$ 中抽取一个 $\omega \in \Omega$,然后生成该过程的单个实现(或_模拟_)$\{\pi_t(\omega)\}_{t=0}^\infty$。 -通过观察运动方程 {eq}`eq_recur1` 或 {eq}`eq:like44`,我们可以了解到一些关于极限点概率分布的信息。 +当 $t \rightarrow +\infty$ 时,$\{\pi_t(\omega)\}_{t=0}^\infty$ 的极限点是一个随机变量的实现,这个随机变量是当我们从 $\Omega$ 中采样 $\omega$ 并构造 $\{\pi_t(\omega)\}_{t=0}^\infty$ 的重复抽样时产生的。 + +通过观察运动方程 {eq}`eq_recur1` 或 {eq}`eq:like44`,我们可以推断出一些关于极限点概率分布的信息 $$ \pi_\infty(\omega) = \lim_{t \rightarrow + \infty} \pi_t(\omega). $$ -显然,由于当 $f \neq g$ 时似然比 $\ell(w_t)$ 与 1 不同(这是我们的假设),{eq}`eq:like44` 的唯一可能的固定点是 +显然,由于我们假设 $f \neq g$ 时似然比 $\ell(w_t)$ 与 1 不同,{eq}`eq:like44` 的唯一可能的固定点是 $$ \pi_\infty(\omega) =1 @@ -469,9 +671,7 @@ $$ \pi_\infty(\omega) =0 $$ -因此,对于某些实现,$\lim_{\rightarrow + \infty} \pi_t(\omega) =1$ - -而对于其他实现, $\lim_{\rightarrow + \infty} \pi_t(\omega) =0$。 +因此,对某些实现来说,$\lim_{\rightarrow + \infty} \pi_t(\omega) =1$,而对其他实现来说,$\lim_{\rightarrow + \infty} \pi_t(\omega) =0$。 现在让我们记住 $\{\pi_t\}_{t=0}^\infty$ 是一个鞅,并应用迭代期望法则。 @@ -484,7 +684,7 @@ $$ 特别是 $$ -E_{-1} \pi_{t+j} = \pi_{-1}. +E_{-1} \pi_{t+j} = \pi_{-1} $$ 将上述公式应用于 $\pi_\infty$,我们得到 @@ -495,7 +695,7 @@ $$ 这里的数学期望 $E_{-1}$ 是相对于概率测度 ${\textrm{Prob}(\Omega)}$ 计算的。 -由于 $\pi_\infty(\omega)$ 只能取 1 和 0 两个值,我们知道对于某个 $\lambda \in [0,1]$ +由于 $\pi_\infty(\omega)$ 只能取 1 和 0 两个值,我们知道对某个 $\lambda \in [0,1]$ $$ {\textrm{Prob}}\Bigl(\pi_\infty(\omega) = 1\Bigr) = \lambda, \quad {\textrm{Prob}}\Bigl(\pi_\infty(\omega) = 0\Bigr) = 1- \lambda @@ -507,17 +707,17 @@ $$ E_{-1} \pi_\infty(\omega) = \lambda \cdot 1 + (1-\lambda) \cdot 0 = \lambda $$ -将此方程与方程(20)结合,我们推导出 +将此方程与方程(20)结合,我们推断出 ${\textrm{Prob}(\Omega)}$ 赋予 $\pi_\infty(\omega)$ 为 1 的概率必须是 $\pi_{-1}$。 -在劳动者的主观分布下,${\textrm{Prob}(\Omega)}$ 赋予 $\pi_\infty(\omega)$ 为 $1$ 的概率必须是 $\pi_{-1}$。 +因此,在工人的主观分布下,$\pi_{-1}$ 的样本路径 -因此,在劳动者的主观分布下,$\{\pi_t\}$ 的 $\pi_{-1}$ 比例的样本路径将逐点收敛到 $1$,而 $1 - \pi_{-1}$ 比例的样本路径将逐点收敛到 $0$。 +$\{\pi_t\}$将有$\pi_{-1}$的样本路径逐点收敛到$1$,有$1 - \pi_{-1}$的样本路径逐点收敛到$0$。 ### 一些模拟 -让我们通过一些在劳动者主观分布下的学习模型模拟来观察鞅收敛定理的作用。 +让我们通过一些模拟来观察鞅收敛定理在工人主观分布下的学习模型中的表现。 -让我们模拟 $\left\{ \pi_{t}\right\} _{t=0}^{T}$, $\left\{ w_{t}\right\} _{t=0}^{T}$ 路径,其中对于每个 $t\geq0$,$w_t$ 从主观分布中抽取 +让我们模拟$\left\{ \pi_{t}\right\} _{t=0}^{T}$和$\left\{ w_{t}\right\} _{t=0}^{T}$的路径,其中对于每个$t\geq0$,$w_t$从主观分布中抽取: $$ \pi_{t-1}f\left(w_{t}\right)+\left(1-\pi_{t-1}\right)g\left(w_{t}\right) @@ -564,8 +764,6 @@ def create_table(π0s, N=10000, T=500, decimals=2): table.index = π0s return table - - # simulate T = 200 π0 = .5 @@ -579,7 +777,7 @@ for i in range(100): ax.plot(range(T+1), π_path[i, :]) ax.set_xlabel('$t$') -ax.set_ylabel('$\pi_t$') +ax.set_ylabel(r'$\pi_t$') plt.show() ``` @@ -593,7 +791,7 @@ plt.show() * 没有路径收敛到不等于 $0$ 或 $1$ 的极限点 -实际上收敛发生得相当快,从下图所示的不同小 $t$ 值时 $\pi_t$ 的跨集合分布可以看出。 +如下图所示,通过观察不同小 $t$ 值时 $\pi_t$ 的跨集合分布,可以看出收敛实际上发生得相当快。 ```{code-cell} ipython3 fig, ax = plt.subplots() @@ -601,7 +799,7 @@ for t in [1, 10, T-1]: ax.hist(π_path[:,t], bins=20, alpha=0.4, label=f'T={t}') ax.set_ylabel('count') -ax.set_xlabel('$\pi_T$') +ax.set_xlabel(r'$\pi_T$') ax.legend(loc='lower right') plt.show() ``` @@ -616,7 +814,7 @@ plt.show() 是的:它等于我们用来生成整个集合中每个序列的初始值 $\pi_0 = .5$。 -所以让我们把 $\pi_0$ 改为 $.3$,观察在不同 $t$ 值下,$\pi_t$ 集合的分布会发生什么变化。 +那么让我们把 $\pi_0$ 改为 $.3$,看看对于不同的 $t$ 值,$\pi_t$ 集合的分布会发生什么变化。 ```{code-cell} ipython3 # 模拟 @@ -632,7 +830,7 @@ for t in [1, 10, T-1]: ax.hist(π_path3[:,t], bins=20, alpha=0.4, label=f'T={t}') ax.set_ylabel('计数') -ax.set_xlabel('$\pi_T$') +ax.set_xlabel(r'$\pi_T$') ax.legend(loc='upper right') plt.show() ``` @@ -641,17 +839,17 @@ plt.show() 注意其中一条路径涉及系统性更高的 $w_t$ 值,这些结果将 $\pi_t$ 向上推动。 -在模拟早期的随机抽样使主观分布更频繁地从 $F$ 中抽取样本,这将 $\pi_t$ 推向 $0$。 +在模拟早期的随机抽样会将主观分布推向更频繁地从 $F$ 中抽样的方向,这会将 $\pi_t$ 推向 $0$。 ```{code-cell} ipython3 fig, ax = plt.subplots() for i, j in enumerate([10, 100]): - ax.plot(range(T+1), π_path[j,:], color=colors[i], label=f'$\pi$_path, {j}-th simulation') - ax.plot(range(1,T+1), w_path[j,:], color=colors[i], label=f'$w$_path, {j}-th simulation', alpha=0.3) + ax.plot(range(T+1), π_path[j,:], color=colors[i], label=fr'$\pi$_path, {j}-th simulation') + ax.plot(range(1,T+1), w_path[j,:], color=colors[i], label=fr'$w$_path, {j}-th simulation', alpha=0.3) ax.legend(loc='upper right') ax.set_xlabel('$t$') -ax.set_ylabel('$\pi_t$') +ax.set_ylabel(r'$\pi_t$') ax2 = ax.twinx() ax2.set_ylabel("$w_t$") plt.show() @@ -665,9 +863,9 @@ plt.show() 在下表中,粗体显示的左列报告了$\pi_{-1}$的假设值。 -第二列报告了在$N = 10000$次模拟中,$\pi_{t}$在每次模拟的终止日期$T=500$时收敛到$0$的比例。 +第二列报告了在$N = 10000$次模拟中,对于每次模拟在终止日期$T=500$时$\pi_{t}$收敛到$0$的比例。 -第三列报告了在$N = 10000$次模拟中,$\pi_{t}$在每次模拟的终止日期$T=500$时收敛到$1$的比例。 +第三列报告了在$N = 10000$次模拟中,对于每次模拟在终止日期$T=500$时$\pi_{t}$收敛到$1$的比例。 ```{code-cell} ipython3 # create table @@ -717,18 +915,18 @@ for pi in pi_array: fig, ax = plt.subplots() ax.plot(pi_array, cond_var_array) -ax.set_xlabel('$\pi_{t-1}$') -ax.set_ylabel('$\sigma^{2}(\pi_{t}\\vert \pi_{t-1})$') +ax.set_xlabel(r'$\pi_{t-1}$') +ax.set_ylabel(r'$\sigma^{2}(\pi_{t}\vert \pi_{t-1})$') plt.show() ``` -条件方差作为 $\pi_{t-1}$ 的函数的形状能够揭示 $\{\pi_t\}$ 样本路径的行为特征。 +条件方差作为 $\pi_{t-1}$ 的函数的形状,能够告诉我们 $\{\pi_t\}$ 样本路径的行为特征。 注意当 $\pi_{t-1}$ 接近 0 或 1 时,条件方差趋近于 0。 只有当代理几乎确定 $w_t$ 是从 $F$ 分布中抽取的,或者几乎确定是从 $G$ 分布中抽取的时候,条件方差才接近于零。 -## 后续内容 +## 相关讲座 -本讲主要致力于建立一些有用的基础设施,这将有助于我们理解在{doc}`这篇讲座 `、{doc}`这篇讲座 ` 和{doc}`这篇讲座 ` 中描述的结果的推理基础。 +本讲座致力于建立一些有用的基础设施,这将有助于我们理解在{doc}`这个讲座 `、{doc}`这个讲座 ` 和{doc}`这个讲座 ` 中描述的结果的推理基础。 diff --git a/lectures/likelihood_ratio_process.md b/lectures/likelihood_ratio_process.md index 014e820b..c3f3f3bb 100644 --- a/lectures/likelihood_ratio_process.md +++ b/lectures/likelihood_ratio_process.md @@ -3,8 +3,10 @@ jupytext: text_representation: extension: .md format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -24,157 +26,196 @@ kernelspec: :depth: 2 ``` +除了Anaconda中已有的库外,本讲座还需要以下库: + +```{code-cell} ipython3 +:tags: [hide-output] +!pip install --upgrade quantecon +``` + ## 概述 本讲座介绍似然比过程及其一些用途。 -我们将使用{doc}`本讲座 `中描述的设置。 +我们将研究与{doc}`可交换性讲座 `中相同的设定。 我们将学习的内容包括: +* 似然比过程如何成为频率派假设检验的关键要素 +* **接收者操作特征曲线**如何总结频率派假设检验中的虚警概率和检验效能的信息 +* 统计学家如何将第一类和第二类错误的频率派概率结合起来,形成模型选择或个体分类问题中的错误后验概率 +* 如何使用Kullback-Leibler散度来量化具有相同支撑的两个概率分布之间的差异 +* 二战期间美国海军如何设计一个决策规则来对弹药批次进行质量控制,这个话题为{doc}`这个讲座 `做铺垫 * 似然比过程的一个特殊性质 -* 似然比过程如何成为频率派假设检验中的关键要素 - -* **接收者操作特征曲线**如何总结频率论假设检验中的虚警概率和检验效能的信息 -* 在第二次世界大战期间,美国海军制定了一个决策规则,Garret L. Schyler上尉对此提出质疑,并要求Milton Friedman向他解释其合理性,这个话题将在{doc}`本讲座中 `进行研究 让我们先导入一些Python工具。 -```{code-cell} ipython +```{code-cell} ipython3 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 vectorize, jit from math import gamma from scipy.integrate import quad +from scipy.optimize import brentq, minimize_scalar +from scipy.stats import beta as beta_dist +import pandas as pd +from IPython.display import display, Math +import quantecon as qe ``` ## 似然比过程 一个非负随机变量 $W$ 具有两个概率密度函数之一,要么是 $f$,要么是 $g$。 -在时间开始之前,自然界一劳永逸地决定是从 $f$ 还是 $g$ 中抽取一系列独立同分布的样本。 +在时间开始之前,自然界一次性地决定是从 $f$ 还是 $g$ 中进行一系列独立同分布的抽样。 -我们有时会用 $q$ 表示自然界一劳永逸选择的密度函数,所以 $q$ 要么是 $f$ 要么是 $g$,且是永久性的。 +我们有时用 $q$ 表示自然界一次性选择的密度,所以 $q$ 要么是 $f$ 要么是 $g$,且是永久性的。 -自然界知道它永久性地从哪个密度函数中抽样,但我们这些观察者并不知道。 +自然界知道它永久性地从哪个密度中抽样,但我们这些观察者并不知道。 -我们知道 $f$ 和 $g$ 这两个密度函数,但不知道自然界选择了哪一个。 +我们知道 $f$ 和 $g$ 两个密度,但不知道自然界选择了哪一个。 但我们想要知道。 为此,我们使用观测值。 -我们观察到一个序列 $\{w_t\}_{t=1}^T$,它包含 $T$ 个从 $f$ 或 $g$ 中抽取的独立同分布样本。 +我们观察到一个序列 $\{w_t\}_{t=1}^T$,包含 $T$ 个独立同分布的抽样,我们知道这些抽样要么来自 $f$ 要么来自 $g$。 我们想要利用这些观测值来推断自然界选择了 $f$ 还是 $g$。 **似然比过程**是完成这项任务的有用工具。 -首先,我们定义似然比过程的一个关键组成部分,即时间 $t$ 的似然比,它是如下随机变量 +首先,我们定义似然比过程的一个关键组成部分,即时间 $t$ 的似然比,作为随机变量: $$ - \ell (w_t)=\frac{f\left(w_t\right)}{g\left(w_t\right)},\quad t\geq1. $$ 我们假设 $f$ 和 $g$ 在随机变量 $W$ 的相同可能实现区间上都具有正概率。 -这意味着在 $g$ 密度下,$\ell (w_t)= -\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}$ -显然是一个均值为1的非负随机变量。 +这意味着在 $g$ 密度下,$\ell (w_t)=\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}$ 是一个均值为1的非负随机变量。 -对序列 $\left\{ w_{t}\right\} _{t=1}^{\infty}$ 的**似然比过程**定义为 +序列 $\left\{ w_{t}\right\} _{t=1}^{\infty}$ 的**似然比过程**定义为: $$ L\left(w^{t}\right)=\prod_{i=1}^{t} \ell (w_i), $$ -其中 $w^t=\{ w_1,\dots,w_t\}$ 是直到时间 $t$ (包括 $t$)的观测历史。 +其中 $w^t=\{ w_1,\dots,w_t\}$ 是直到时间 $t$ (包括 $t$) 的观测历史。 -有时为简便起见,我们会写作 $L_t = L(w^t)$。 +为简便起见,我们有时会写作 $L_t = L(w^t)$。 -注意,似然比过程满足以下*递归*或*乘法分解* +注意似然过程满足以下*递归*关系 $$ L(w^t) = \ell (w_t) L (w^{t-1}) . $$ -似然比及其对数是使用 Neyman 和 Pearson {cite}`Neyman_Pearson` 的经典频率派方法进行推断的关键工具。 +似然比及其对数是 Neyman 和 Pearson {cite}`Neyman_Pearson` 经典频率派推断方法中的关键工具。 -为了帮助我们理解其工作原理,以下Python代码将$f$和$g$评估为两个不同的beta分布,然后通过从两个概率分布之一生成序列$w^t$(例如,从$g$生成的IID序列)来计算和模拟相关的似然比过程。 +为了帮助我们理解其工作原理,以下 Python 代码将 $f$ 和 $g$ 定义为两个不同的 Beta 分布,然后通过从两个概率分布之一(例如,从 $g$ 生成 IID 序列)生成序列 $w^t$ 来计算和模拟相关的似然比过程。 ```{code-cell} ipython3 -# 两个beta分布中的参数 +# Parameters for the two Beta distributions F_a, F_b = 1, 1 G_a, G_b = 3, 1.2 @vectorize def p(x, a, b): + """Beta distribution density function.""" r = gamma(a + b) / (gamma(a) * gamma(b)) return r * x** (a-1) * (1 - x) ** (b-1) -# 两个密度函数 f = jit(lambda x: p(x, F_a, F_b)) g = jit(lambda x: p(x, G_a, G_b)) -``` -```{code-cell} ipython3 -@jit -def simulate(a, b, T=50, N=500): - ''' - 生成N组T个似然比观测值, - 以N x T矩阵形式返回。 +def create_beta_density(a, b): + """Create a beta density function with specified parameters.""" + return jit(lambda x: p(x, a, b)) - ''' +def likelihood_ratio(w, f_func, g_func): + """Compute likelihood ratio for observation(s) w.""" + return f_func(w) / g_func(w) +@jit +def simulate_likelihood_ratios(a, b, f_func, g_func, T=50, N=500): + """ + Generate N sets of T observations of the likelihood ratio. + """ l_arr = np.empty((N, T)) - for i in range(N): - for j in range(T): w = np.random.beta(a, b) - l_arr[i, j] = f(w) / g(w) - + l_arr[i, j] = f_func(w) / g_func(w) return l_arr -``` - -## 自然永久地从密度 g 中抽取 - -我们首先模拟当自然永久地从 $g$ 中抽取时的似然比过程。 -```{code-cell} ipython3 -l_arr_g = simulate(G_a, G_b) -l_seq_g = np.cumprod(l_arr_g, axis=1) +def simulate_sequences(distribution, f_func, g_func, + F_params=(1, 1), G_params=(3, 1.2), T=50, N=500): + """ + Generate N sequences of T observations from specified distribution. + """ + if distribution == 'f': + a, b = F_params + elif distribution == 'g': + a, b = G_params + else: + raise ValueError("distribution must be 'f' or 'g'") + + l_arr = simulate_likelihood_ratios(a, b, f_func, g_func, T, N) + l_seq = np.cumprod(l_arr, axis=1) + return l_arr, l_seq + +def plot_likelihood_paths(l_seq, title="Likelihood ratio paths", + ylim=None, n_paths=None): + """Plot likelihood ratio paths.""" + N, T = l_seq.shape + n_show = n_paths or min(N, 100) + + plt.figure(figsize=(10, 6)) + for i in range(n_show): + plt.plot(range(T), l_seq[i, :], color='b', lw=0.8, alpha=0.5) + + if ylim: + plt.ylim(ylim) + plt.title(title) + plt.xlabel('t') + plt.ylabel('$L(w^t)$') + plt.show() ``` -```{code-cell} ipython3 -N, T = l_arr_g.shape +(nature_likeli)= +## 当自然永久从密度g中抽取时 -for i in range(N): +我们首先模拟当自然永久从$g$中抽取时的似然比过程。 - plt.plot(range(T), l_seq_g[i, :], color='b', lw=0.8, alpha=0.5) - -plt.ylim([0, 3]) -plt.title("$L(w^{t})$ 路径"); +```{code-cell} ipython3 +# 模拟当自然从g中抽取时的情况 +l_arr_g, l_seq_g = simulate_sequences('g', f, g, (F_a, F_b), (G_a, G_b)) +plot_likelihood_paths(l_seq_g, + title="当自然从g中抽取时的$L(w^{t})$路径", + ylim=[0, 3]) ``` -显然,随着样本长度 $T$ 的增长,大部分概率质量向零偏移 +显然,随着样本长度 $T$ 的增长,大部分概率质量 +向零靠近 -为了更清楚地看到这一点,我们绘制了随时间变化的路径分数 $L\left(w^{t}\right)$ 落在区间 $\left[0, 0.01\right]$ 内的比例。 +为了更清楚地看到这一点,我们绘制了随时间变化的 +路径 $L\left(w^{t}\right)$ 落在区间 +$\left[0, 0.01\right]$ 内的比例。 ```{code-cell} ipython3 +N, T = l_arr_g.shape plt.plot(range(T), np.sum(l_seq_g <= 0.01, axis=0) / N) +plt.show() ``` 尽管大部分概率质量明显收敛到接近$0$的一个很小区间内,但在概率密度$g$下,$L\left(w^t\right)$的无条件均值对所有$t$恒等于$1$。 -为了验证这个断言,首先注意到如前所述,对所有$t$,无条件均值$E\left[\ell \left(w_{t}\right)\bigm|q=g\right]$等于$1$: +为了验证这个论断,首先注意到如前所述,对所有$t$,无条件均值$E\left[\ell \left(w_{t}\right)\bigm|q=g\right]$等于$1$: $$ \begin{aligned} @@ -193,156 +234,166 @@ E\left[L\left(w^{1}\right)\bigm|q=g\right] &=E\left[\ell \left(w_{1}\right)\big \end{aligned} $$ -因为$L(w^t) = \ell(w_t) L(w^{t-1})$且$\{w_t\}_{t=1}^t$是IID序列,我们有 +因为$L(w^t) = \ell(w_t) L(w^{t-1})$且$\{w_t\}_{t=1}^t$是独立同分布序列,我们有 $$ \begin{aligned} E\left[L\left(w^{t}\right)\bigm|q=g\right] &=E\left[L\left(w^{t-1}\right)\ell \left(w_{t}\right)\bigm|q=g\right] \\ - -&=E\left[L\left(w^{t-1}\right)E\left[\ell \left(w_{t}\right)\bigm|q=g,w^{t-1}\right]\bigm|q=g\right] \\ - &=E\left[L\left(w^{t-1}\right)E\left[\ell \left(w_{t}\right)\bigm|q=g\right]\bigm|q=g\right] \\ + &=E\left[L\left(w^{t-1}\right)E\left[\ell \left(w_{t}\right)\bigm|q=g,w^{t-1}\right]\bigm|q=g\right] \\ + &=E\left[L\left(w^{t-1}\right)E\left[\ell \left(w_{t}\right)\bigm|q=g\right]\bigm|q=g\right] \\ &=E\left[L\left(w^{t-1}\right)\bigm|q=g\right] \\ \end{aligned} $$ -对任意 $t \geq 1$。 +对任意$t \geq 1$成立。 -数学归纳法表明 -$E\left[L\left(w^{t}\right)\bigm|q=g\right]=1$ 对所有 -$t \geq 1$ 成立。 +数学归纳法表明对所有$t \geq 1$,$E\left[L\left(w^{t}\right)\bigm|q=g\right]=1$。 ## 特殊性质 -当似然比过程的大部分概率质量在 -$t \rightarrow + \infty$ 时堆积在0附近时, -$E\left[L\left(w^{t}\right)\bigm|q=g\right]=1$ 怎么可能成立? +当似然比过程的大部分概率质量在 $t \rightarrow + \infty$ 时堆积在 $0$ 附近时,$E\left[L\left(w^{t}\right)\bigm|q=g\right]=1$ 怎么可能成立? -答案必须是当 $t \rightarrow + \infty$ 时, -$L_t$ 的分布变得越来越重尾: -足够多的质量转移到越来越大的 $L_t$ 值上,使得 -尽管大部分概率质量堆积在0附近,$L_t$ 的均值仍然保持为1。 +答案是,当 $t \rightarrow + \infty$ 时,$L_t$ 的分布变得越来越厚尾:足够多的质量向 $L_t$ 的更大值移动,使得尽管大部分概率质量堆积在 $0$ 附近,$L_t$ 的均值仍然保持为1。 -为了说明这个特殊性质,我们模拟了多条路径并且 - -通过在每个时刻$t$对这些路径取平均值来计算$L\left(w^t\right)$的无条件均值。 +为了说明这个特殊性质,我们模拟多条路径,并通过在每个时刻 $t$ 对这些路径取平均来计算 $L\left(w^t\right)$ 的无条件均值。 ```{code-cell} ipython3 -l_arr_g = simulate(G_a, G_b, N=50000) -l_seq_g = np.cumprod(l_arr_g, axis=1) +l_arr_g, l_seq_g = simulate_sequences('g', + f, g, (F_a, F_b), (G_a, G_b), N=50000) ``` 使用模拟来验证无条件期望值$E\left[L\left(w^{t}\right)\right]$等于1(通过对样本路径取平均)会很有用。 -但是在这里仅仅使用标准蒙特卡洛模拟方法会消耗太多计算时间,因此我们不会这样做。 +但是在这里使用标准蒙特卡洛模拟方法会消耗太多计算时间,因此我们不会这样做。 -原因是对于较大的$t$值,$L\left(w^{t}\right)$的分布极度偏斜。 +原因是对于较大的$t$值,$L\left(w^{t}\right)$的分布极度偏斜。 -因为右尾部的概率密度接近于0,从右尾部采样足够多的点需要太多计算时间。 +因为右尾部的概率密度接近于0,从右尾部采样足够多的点需要太多计算时间。 -我们在{doc}`这篇讲座 `中更详细地解释了这个问题。 +我们在{doc}`这篇讲座 `中详细解释了这个问题。 -在那里我们描述了一种替代方法来计算似然比的均值,即通过从一个_不同的_概率分布中采样来计算一个_不同的_随机变量的均值。 +在那里我们描述了一种通过从不同的概率分布中采样来计算不同随机变量的均值,从而计算似然比均值的替代方法。 -## 自然永久地从密度f中抽样 +## 自然永久从密度f中抽样 -现在假设在时间0之前,自然界永久地决定反复从密度f中抽样。 +现在假设在时间0之前,自然界永久决定反复从密度f中抽样。 -虽然似然比 $\ell \left(w_{t}\right)$ 在密度 $g$ 下的均值为 $1$,但在密度 $f$ 下的均值大于 1。 +虽然似然比$\ell \left(w_{t}\right)$在密度$g$下的均值是1,但在密度$f$下的均值超过1。 -为了证明这一点,我们计算: +为了说明这一点,我们计算: $$ \begin{aligned} E\left[\ell \left(w_{t}\right)\bigm|q=f\right] &=\int\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}f\left(w_{t}\right)dw_{t} \\ - &=\int\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}g\left(w_{t}\right)dw_{t} \\ - &=\int \ell \left(w_{t}\right)^{2}g\left(w_{t}\right)dw_{t} \\ - &=E\left[\ell \left(w_{t}\right)^{2}\mid q=g\right] \\ - &=E\left[\ell \left(w_{t}\right)\mid q=g\right]^{2}+Var\left(\ell \left(w_{t}\right)\mid q=g\right) \\ - &>E\left[\ell \left(w_{t}\right)\mid q=g\right]^{2} = 1 \\ + &=\int\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}\frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}g\left(w_{t}\right)dw_{t} \\ + &=\int \ell \left(w_{t}\right)^{2}g\left(w_{t}\right)dw_{t} \\ + +&=E\left[\ell \left(w_{t}\right)^{2}\mid q=g\right] \\ + &=E\left[\ell \left(w_{t}\right)\mid q=g\right]^{2}+Var\left(\ell \left(w_{t}\right)\mid q=g\right) \\ + &>E\left[\ell \left(w_{t}\right)\mid q=g\right]^{2} = 1 \\ \end{aligned} $$ -这反过来意味着似然比过程 $L(w^t)$ 的无条件均值趋向于 $+ \infty$。 +这反过来意味着似然比过程$L(w^t)$的无条件均值将趋向于$+ \infty$。 下面的模拟验证了这个结论。 -请注意 $y$ 轴的刻度。 +请注意$y$轴的刻度。 ```{code-cell} ipython3 -l_arr_f = simulate(F_a, F_b, N=50000) -l_seq_f = np.cumprod(l_arr_f, axis=1) +# 模拟当自然从f中抽取时 +l_arr_f, l_seq_f = simulate_sequences('f', f, g, + (F_a, F_b), (G_a, G_b), N=50000) ``` ```{code-cell} ipython3 N, T = l_arr_f.shape plt.plot(range(T), np.mean(l_seq_f, axis=0)) +plt.show() ``` 我们还绘制了 $L\left(w^t\right)$ 落入区间 $[10000, \infty)$ 的概率随时间的变化图,观察概率质量向 $+\infty$ 发散的速度。 ```{code-cell} ipython3 plt.plot(range(T), np.sum(l_seq_f > 10000, axis=0) / N) +plt.show() ``` ## 似然比检验 -我们现在描述如何运用Neyman和Pearson {cite}`Neyman_Pearson`的方法来检验历史数据$w^t$是否由密度函数$g$的重复独立同分布抽样生成。 +我们现在描述如何运用 Neyman 和 Pearson {cite}`Neyman_Pearson` 的方法来检验历史数据 $w^t$ 是否由密度函数 $f$ 的独立同分布重复抽样生成。 -设$q$为数据生成过程,即$q=f \text{ 或 } g$。 +令 $q$ 表示数据生成过程,因此 $q=f \text{ 或 } g$。 -在观察到样本$\{W_i\}_{i=1}^t$后,我们想通过执行(频率学派的)假设检验来判断自然是从$g$还是从$f$中抽样。 +在观察到样本 $\{W_i\}_{i=1}^t$ 后,我们想通过执行(频率学派的)假设检验来判断自然是从 $g$ 还是从 $f$ 中抽样。 我们指定: -- 原假设$H_0$:$q=f$ -- 备择假设$H_1$:$q=g$ +- 零假设 $H_0$:$q=f$ +- 备择假设 $H_1$:$q=g$ + +Neyman 和 Pearson 证明了检验这个假设的最佳方法是使用**似然比检验**,形式如下: -Neyman和Pearson证明,检验这个假设的最佳方法是使用**似然比检验**,其形式为: +- 当 $L(W^t) > c$ 时接受 $H_0$ +- 当 $L(W^t) < c$ 时拒绝 $H_0$ -- 当$L(W^t) < c$时拒绝$H_0$ -- 否则接受$H_0$ +其中 $c$ 是给定的判别阈值。 -其中$c$是一个给定的判别阈值,我们稍后将描述如何选择它。 +设置 $c=1$ 是一个常见的选择。 -这个检验是*最佳的*,因为它是一个**一致最优**检验。 +我们将在下面讨论其他 $c$ 值选择的影响。 -为了理解这意味着什么,我们需要定义两个重要事件的概率: +这个检验是*最佳的*,因为它是**一致最优检验**。 -让我们描述与给定阈值 $c$ 相关的检验特征。 +为了理解这一点,我们需要定义两个重要事件的概率,这些概率可以帮助我们描述与给定阈值 $c$ 相关的检验。 这两个概率是: -- 检测概率(= 检验效力 = 1减去第II类错误概率): +- 第一类错误的概率(当 $H_0$ 为真时拒绝它): $$ - 1-\beta \equiv \Pr\left\{ L\left(w^{t}\right)c\mid q=g\right\} + $$ + +这两个概率是以下两个概念的基础: + +- 虚警概率(=显著性水平=第一类错误概率): $$ \alpha \equiv \Pr\left\{ L\left(w^{t}\right) np.log(c) - axs[nr, nc].fill_between(x[1:][ind], hist[ind], alpha=0.5, label=label) - - axs[nr, nc].legend() - axs[nr, nc].set_title(f"t={t}") - -plt.show() +def plot_log_histograms(l_seq_f, l_seq_g, c=1, time_points=[1, 7, 14, 21]): + """绘制对数似然比直方图。""" + fig, axs = plt.subplots(2, 2, figsize=(12, 8)) + + for i, t in enumerate(time_points): + nr, nc = i // 2, i % 2 + + axs[nr, nc].axvline(np.log(c), color="k", ls="--") + + hist_f, x_f = np.histogram(np.log(l_seq_f[:, t]), 200, density=True) + hist_g, x_g = np.histogram(np.log(l_seq_g[:, t]), 200, density=True) + + axs[nr, nc].plot(x_f[1:], hist_f, label="f下的分布") + axs[nr, nc].plot(x_g[1:], hist_g, label="g下的分布") + + # 填充错误区域 + for j, (x, hist, label) in enumerate( + zip([x_f, x_g], [hist_f, hist_g], + ["第一类错误", "第二类错误"])): + ind = x[1:] <= np.log(c) if j == 0 else x[1:] > np.log(c) + axs[nr, nc].fill_between(x[1:][ind], hist[ind], + alpha=0.5, label=label) + + axs[nr, nc].legend() + axs[nr, nc].set_title(f"t={t}") + + plt.show() + +plot_log_histograms(l_seq_f, l_seq_g, c=c) ``` -下图更清楚地显示,当我们固定阈值$c$时,检测概率随着$t$的增加而单调增加,而虚警概率则单调减少。 +在上述图表中, + * 蓝色区域与第一类错误的概率 $\alpha$ 相关但不相等,因为 +它们是在拒绝域 $L_t < 1$ 上 $\log L_t$ 的积分,而不是 $L_t$ 的积分 +* 橙色区域与第二类错误的概率 $\beta$ 相关但不相等,因为 +它们是在接受域 $L_t > 1$ 上 $\log L_t$ 的积分,而不是 $L_t$ 的积分 -```{code-cell} ipython3 -PD = np.empty(T) -PFA = np.empty(T) +当我们将 $c$ 固定在 $c=1$ 时,下图显示: + * 检测概率随着 $t$ 的增加单调增加 + * 虚警概率随着 $t$ 的增加单调减少 -for t in range(T): - PD[t] = np.sum(l_seq_g[:, t] < c) / N - PFA[t] = np.sum(l_seq_f[:, t] < c) / N +```{code-cell} ipython3 -plt.plot(range(T), PD, label="Probability of detection") -plt.plot(range(T), PFA, label="Probability of false alarm") -plt.xlabel("t") -plt.title("$c=1$") -plt.legend() -plt.show() +def compute_error_probabilities(l_seq_f, l_seq_g, c=1): + """ + 计算第一类和第二类错误概率。 + """ + N, T = l_seq_f.shape + + # 第一类错误(虚警)- 在H0为真时拒绝H0 + PFA = np.array([np.sum(l_seq_f[:, t] < c) / N for t in range(T)]) + + # 第二类错误 - 在H0为假时接受H0 + beta = np.array([np.sum(l_seq_g[:, t] >= c) / N for t in range(T)]) + + # 检测概率(检验效能) + PD = np.array([np.sum(l_seq_g[:, t] < c) / N for t in range(T)]) + + return { + 'alpha': PFA, + 'beta': beta, + 'PD': PD, + 'PFA': PFA + } + +def plot_error_probabilities(error_dict, T, c=1, title_suffix=""): + """绘制随时间变化的错误概率。""" + plt.figure(figsize=(10, 6)) + plt.plot(range(T), error_dict['PD'], label="检测概率") + plt.plot(range(T), error_dict['PFA'], label="虚警概率") + plt.xlabel("t") + plt.ylabel("概率") + plt.title(f"错误概率 (c={c}){title_suffix}") + plt.legend() + plt.show() + +error_probs = compute_error_probabilities(l_seq_f, l_seq_g, c=c) +N, T = l_seq_f.shape +plot_error_probabilities(error_probs, T, c) ``` 对于给定的样本量 $t$,阈值 $c$ 唯一确定了两种类型错误的概率。 -如果对于固定的 $t$,我们现在释放并移动 $c$,我们将得到检测概率作为虚警概率的函数。 +如果在固定 $t$ 的情况下,我们释放并移动 $c$,我们将得到检测概率作为虚警概率的函数。 -这就产生了所谓的[接收者操作特征曲线](https://en.wikipedia.org/wiki/Receiver_operating_characteristic)。 +这就产生了[接收者操作特征曲线(ROC曲线)](https://en.wikipedia.org/wiki/Receiver_operating_characteristic)。 -下面,我们绘制不同样本量 $t$ 的接收者操作特征曲线。 +下面,我们为不同的样本量 $t$ 绘制接收者操作特征曲线。 ```{code-cell} ipython3 -PFA = np.arange(0, 100, 1) +def plot_roc_curves(l_seq_f, l_seq_g, t_values=[1, 5, 9, 13], N=None): + """绘制不同样本量的ROC曲线。""" + if N is None: + N = l_seq_f.shape[0] + + PFA = np.arange(0, 100, 1) + + plt.figure(figsize=(10, 6)) + for t in t_values: + percentile = np.percentile(l_seq_f[:, t], PFA) + PD = [np.sum(l_seq_g[:, t] < p) / N for p in percentile] + plt.plot(PFA / 100, PD, label=f"t={t}") + + plt.scatter(0, 1, label="完美检测") + plt.plot([0, 1], [0, 1], color='k', ls='--', label="随机检测") + + plt.arrow(0.5, 0.5, -0.15, 0.15, head_width=0.03) + plt.text(0.35, 0.7, "更好") + plt.xlabel("虚警概率") + plt.ylabel("检测概率") + plt.legend() + plt.title("ROC曲线") + plt.show() + + +plot_roc_curves(l_seq_f, l_seq_g, t_values=range(1, 15, 4), N=N) +``` -for t in range(1, 15, 4): - percentile = np.percentile(l_seq_f[:, t], PFA) - PD = [np.sum(l_seq_g[:, t] < p) / N for p in percentile] +注意到随着 $t$ 的增加,对于给定的判别阈值 $c$,我们可以确保更高的检测概率和更低的虚警概率。 - plt.plot(PFA / 100, PD, label=f"t={t}") +对于给定的样本量 $t$,当我们改变 $c$ 时,$\alpha$ 和 $\beta$ 都会发生变化。 -plt.scatter(0, 1, label="perfect detection") -plt.plot([0, 1], [0, 1], color='k', ls='--', label="random detection") +当我们增加 $c$ 时 -plt.arrow(0.5, 0.5, -0.15, 0.15, head_width=0.03) -plt.text(0.35, 0.7, "better") -plt.xlabel("虚警概率") -plt.ylabel("检测概率") -plt.legend() -plt.title("接收者操作特征曲线") -plt.show() -``` - -注意随着 $t$ 的增加,对于给定的判别阈值 $c$,我们可以确保获得更高的检测概率和更低的虚警概率。 +* $\alpha \equiv \Pr\left\{ L\left(w^{t}\right)c\mid q=g\right\}$ 减少 当 $t \rightarrow + \infty$ 时,我们接近完美检测曲线,该曲线在蓝点处呈直角。 对于给定的样本量 $t$,判别阈值 $c$ 决定了接收者操作特征曲线上的一个点。 -权衡两种类型错误的概率是由测试设计者决定的。 +测试设计者需要权衡这两种类型错误的概率。 但我们知道如何选择最小样本量来达到给定的概率目标。 -通常,频率学派的目标是在虚警概率有上限的情况下获得高检测概率。 +通常,频率学派的目标是在虚警概率有上限的情况下实现高检测概率。 下面我们展示一个例子,其中我们将虚警概率固定在 $0.05$。 -做出决策所需的样本量由一个 - -目标检测概率,例如 $0.9$,如下图所示。 +做出决定所需的样本量则由目标检测概率决定,例如 $0.9$,如下图所示。 ```{code-cell} ipython3 PFA = 0.05 @@ -469,143 +571,1188 @@ plt.show() 美国海军显然在第二次世界大战期间使用类似这样的程序来选择质量控制测试的样本大小 $t$。 -一位被命令执行此类测试的海军上尉对此产生了疑虑,他向米尔顿·弗里德曼提出了这些疑虑,我们在{doc}`这篇讲座 `中对此进行了描述。 +一位被命令执行此类测试的海军上校对此产生了疑虑,他向米尔顿·弗里德曼提出了这些疑虑,我们在{doc}`这篇讲座 `中对此进行了描述。 -## Kullback–Leibler 散度 +(llr_h)= +### 第三个分布 $h$ 现在让我们考虑一种既不是 $g$ 也不是 $f$ 生成数据的情况。 而是由第三个分布 $h$ 生成。 -让我们观察当 $h$ 支配数据时,累积似然比 $f/g$ 的表现。 - -这里的一个关键工具被称为 **Kullback–Leibler 散度**。 - -它也被称为**相对熵**。 +让我们研究当 $h$ 支配数据时,累积似然比 $L$ 的表现。 -它用来衡量一个概率分布与另一个概率分布的差异程度。 +这里的一个关键工具被称为**库尔贝克-莱布勒散度**,我们在{doc}`divergence_measures`中已经研究过。 -在我们的应用中,我们想要衡量 $f$ 或 $g$ 与 $h$ 的差异。 +在我们的应用中,我们想要度量 $f$ 或 $g$ 与 $h$ 的偏离程度。 -与我们相关的两个 Kullback–Leibler 散度是 $K_f$ 和 $K_g$,定义如下: +与我们相关的两个库尔贝克-莱布勒散度是 $K_f$ 和 $K_g$,定义如下: $$ \begin{aligned} +K_{f} = D_{KL}\bigl(h\|f\bigr) = KL(h, f) + &= E_{h}\left[\log\frac{h(w)}{f(w)}\right] \\ + &= \int \log\left(\frac{h(w)}{f(w)}\right)h(w)dw . +\end{aligned} +$$ $$ \begin{aligned} -K_{f} &=E_{h}\left[\log\left(\frac{f\left(w\right)}{h\left(w\right)}\right)\frac{f\left(w\right)}{h\left(w\right)}\right] \\ - &=\int\log\left(\frac{f\left(w\right)}{h\left(w\right)}\right)\frac{f\left(w\right)}{h\left(w\right)}h\left(w\right)dw \\ - &=\int\log\left(\frac{f\left(w\right)}{h\left(w\right)}\right)f\left(w\right)dw +K_{g} = D_{KL}\bigl(h\|g\bigr) = KL(h, g) + &= E_{h}\left[\log\frac{h(w)}{g(w)}\right] \\ + &= \int \log\left(\frac{h(w)}{g(w)}\right)h(w)dw . \end{aligned} $$ +让我们使用{doc}`divergence_measures`中的相同代码来计算库尔贝克-莱布勒差异。 + +```{code-cell} ipython3 +def compute_KL(f, g): + """ + 计算KL散度 KL(f, g) + """ + integrand = lambda w: f(w) * np.log(f(w) / g(w)) + val, _ = quad(integrand, 1e-5, 1-1e-5) + return val + +def compute_KL_h(h, f, g): + """ + 计算相对于参考分布h的KL散度 + """ + Kf = compute_KL(h, f) + Kg = compute_KL(h, g) + return Kf, Kg +``` + +(KL_link)= +### 一个有用的公式 + +似然比和KL散度之间存在一个数学关系。 + +当数据由分布$h$生成时,期望对数似然比为: + +$$ +\frac{1}{t} E_{h}\!\bigl[\log L_t\bigr] = K_g - K_f +$$ (eq:kl_likelihood_link) + +其中$L_t=\prod_{j=1}^{t}\frac{f(w_j)}{g(w_j)}$是似然比过程。 + +方程{eq}`eq:kl_likelihood_link`告诉我们: +- 当$K_g < K_f$(即$g$比$f$更接近$h$)时,期望对数似然比为负,所以$L\left(w^t\right) \rightarrow 0$。 +- 当$K_g > K_f$(即$f$比$g$更接近$h$)时,期望对数似然比为正,所以$L\left(w^t\right) \rightarrow + \infty$。 + +让我们通过模拟来验证这一点。 + +在模拟中,我们使用Beta分布$f$、$g$和$h$生成多条路径,并计算$\log(L(w^t))$的路径。 + +首先,我们编写一个函数来计算似然比过程 + +```{code-cell} ipython3 +def compute_likelihood_ratios(sequences, f, g): + """计算似然比和累积乘积。""" + l_ratios = f(sequences) / g(sequences) + L_cumulative = np.cumprod(l_ratios, axis=1) + return l_ratios, L_cumulative +``` + +我们考虑三种情况:(1) $h$ 更接近 $f$,(2) $f$ 和 $g$ 与 $h$ 的距离大致相等,以及 (3) $h$ 更接近 $g$。 + +```{code-cell} ipython3 +:tags: [hide-input] + +# Define test scenarios +scenarios = [ + { + "name": "KL(h,g) > KL(h,f)", + "h_params": (1.2, 1.1), + "expected": r"$L_t \to \infty$" + }, + { + "name": "KL(h,g) ≈ KL(h,f)", + "h_params": (2, 1.35), + "expected": "$L_t$ fluctuates" + }, + { + "name": "KL(h,g) < KL(h,f)", + "h_params": (3.5, 1.5), + "expected": r"$L_t \to 0$" + } +] + +fig, axes = plt.subplots(2, 3, figsize=(15, 12)) + +for i, scenario in enumerate(scenarios): + # Define h + h = lambda x: p(x, scenario["h_params"][0], + scenario["h_params"][1]) + + # Compute KL divergences + Kf, Kg = compute_KL_h(h, f, g) + kl_diff = Kg - Kf + + # Simulate paths + N_paths = 100 + T = 150 + + # Generate data from h + h_data = np.random.beta(scenario["h_params"][0], + scenario["h_params"][1], (N_paths, T)) + l_ratios, l_cumulative = compute_likelihood_ratios(h_data, f, g) + log_l_cumulative = np.log(l_cumulative) + + # Plot distributions + ax = axes[0, i] + x_range = np.linspace(0.001, 0.999, 200) + ax.plot(x_range, [f(x) for x in x_range], + 'b-', label='f', linewidth=2) + ax.plot(x_range, [g(x) for x in x_range], + 'r-', label='g', linewidth=2) + ax.plot(x_range, [h(x) for x in x_range], + 'g--', label='h (data)', linewidth=2) + ax.set_xlabel('w') + ax.set_ylabel('density') + ax.set_title(scenario["name"], fontsize=16) + ax.legend() + + # Plot log likelihood ratio paths + ax = axes[1, i] + for j in range(min(20, N_paths)): + ax.plot(log_l_cumulative[j, :], alpha=0.3, color='purple') + + # Plot theoretical expectation + theory_line = kl_diff * np.arange(1, T+1) + ax.plot(theory_line, 'k--', linewidth=2, label=r'$t \times (K_g - K_f)$') + + ax.set_xlabel('t') + ax.set_ylabel('$log L_t$') + ax.set_title(f'KL(h,f)={Kf:.3f}, KL(h,g)={Kg:.3f}\n{scenario["expected"]}', + fontsize=16) + ax.legend(fontsize=16) + +plt.tight_layout() +plt.show() +``` + +请注意 + +- 在第一张图中,由于 $K_g > K_f$,$\log L(w^t)$ 发散到 $\infty$。 +- 在第二张图中,虽然仍然有 $K_g > K_f$,但差值较小,所以 $L(w^t)$ 发散到无穷的速度较慢。 +- 在最后一张图中,由于 $K_g < K_f$,$\log L(w^t)$ 发散到 $-\infty$。 +- 黑色虚线 $t \left(D_{KL}(h\|g) - D_{KL}(h\|f)\right)$ 与验证 {eq}`eq:kl_likelihood_link` 的路径紧密吻合。 + +这些观察结果与理论相符。 + +在 {doc}`likelihood_ratio_process_2` 中,我们将看到这些思想的一个应用。 + +## 假设检验和分类 + +本节讨论似然比过程的另一个应用。 + +我们描述统计学家如何结合第一类和第二类错误的频率主义概率来 + +* 计算基于样本长度 $T$ 选择错误模型的预期频率 +* 计算分类问题中的预期错误率 + +我们考虑这样一种情况:自然界用已知的混合参数 $\pi_{-1} \in (0,1)$ 混合已知密度 $f$ 和 $g$ 来生成数据,使得随机变量 $w$ 从以下密度中抽取 + +$$ +h (w) = \pi_{-1} f(w) + (1-\pi_{-1}) g(w) +$$ + +我们假设统计学家知道密度 $f$ 和 $g$ 以及混合参数 $\pi_{-1}$。 + +下面,我们将设定 $\pi_{-1} = .5$,尽管使用其他 $\pi_{-1} \in (0,1)$ 的值进行分析也是可行的。 + +我们假设 $f$ 和 $g$ 在随机变量 $W$ 的相同可能实现区间上都赋予正概率。 + +在下面的模拟中,我们指定 $f$ 是 $\text{Beta}(1, 1)$ 分布,$g$ 是 $\text{Beta}(3, 1.2)$ 分布。 + +我们考虑两种替代的时序协议。 + +* 时序协议1用于模型选择问题 +* 时序协议2用于个体分类问题 + +**时序协议1:** 自然只在 $t=-1$ 时刻**一次性**掷硬币,以概率 $\pi_{-1}$ 从 $f$ 生成一个 IID 序列 $\{w_t\}_{t=1}^T$,以概率 $1-\pi_{-1}$ 从 $g$ 生成一个 IID 序列 $\{w_t\}_{t=1}^T$。 + +**时序协议2:** 自然**频繁**掷硬币。在每个时刻 $t \geq 0$,自然掷一次硬币,以概率 $\pi_{-1}$ 从 $f$ 中抽取 $w_t$,以概率 $1-\pi_{-1}$ 从 $g$ 中抽取 $w_t$。 + +以下是我们用来实现时序协议1和2的Python代码 + +```{code-cell} ipython3 +def protocol_1(π_minus_1, T, N=1000, F_params=(1, 1), G_params=(3, 1.2)): + """ + Simulate Protocol 1: Nature decides once at t=-1 which model to use. + """ + F_a, F_b = F_params + G_a, G_b = G_params + + # Single coin flip for the true model + true_models_F = np.random.rand(N) < π_minus_1 + sequences = np.empty((N, T)) + + n_f = np.sum(true_models_F) + n_g = N - n_f + + if n_f > 0: + sequences[true_models_F, :] = np.random.beta(F_a, F_b, (n_f, T)) + if n_g > 0: + sequences[~true_models_F, :] = np.random.beta(G_a, G_b, (n_g, T)) + + return sequences, true_models_F + +def protocol_2(π_minus_1, T, N=1000, F_params=(1, 1), G_params=(3, 1.2)): + """ + Simulate Protocol 2: Nature decides at each time step which model to use. + """ + F_a, F_b = F_params + G_a, G_b = G_params + + # Coin flips for each time step + true_models_F = np.random.rand(N, T) < π_minus_1 + sequences = np.empty((N, T)) + + n_f = np.sum(true_models_F) + n_g = N * T - n_f + + if n_f > 0: + sequences[true_models_F] = np.random.beta(F_a, F_b, n_f) + if n_g > 0: + sequences[~true_models_F] = np.random.beta(G_a, G_b, n_g) + + return sequences, true_models_F +``` + +**注释:** 在时序协议2下,$\{w_t\}_{t=1}^T$ 是从 $h(w)$ 中独立同分布(IID)抽取的序列。在时序协议1下,$\{w_t\}_{t=1}^T$ 不是独立同分布的。它是**条件独立同分布**的 -- 意味着以概率 $\pi_{-1}$ 它是从 $f(w)$ 中独立同分布抽取的序列,以概率 $1-\pi_{-1}$ 它是从 $g(w)$ 中独立同分布抽取的序列。关于这一点的更多信息,请参见{doc}`这篇关于可交换性的讲座 `。 + +我们再次部署一个**似然比过程**,其时间 $t$ 分量是似然比 + +$$ +\ell (w_t)=\frac{f\left(w_t\right)}{g\left(w_t\right)},\quad t\geq1. +$$ + +序列 $\left\{ w_{t}\right\} _{t=1}^{\infty}$ 的**似然比过程**是 + +$$ +L\left(w^{t}\right)=\prod_{i=1}^{t} \ell (w_i), +$$ + +为简便起见,我们将写作 $L_t = L(w^t)$。 + +### 模型选择错误概率 + +我们首先研究假设时序协议1的问题。 + +考虑一个决策者想要知道是模型 $f$ 还是模型 $g$ 支配着长度为 $T$ 观测值的数据集。 + +决策者已经观察到序列 $\{w_t\}_{t=1}^T$。 + +基于观察到的序列,似然比检验在 $L_T \geq 1$ 时选择模型 $f$,在 $L_T < 1$ 时选择模型 $g$。 + +当模型 $f$ 生成数据时,似然比检验选择错误模型的概率是 + +$$ +p_f = {\rm Prob}\left(L_T < 1\Big| f\right) = \alpha_T . +$$ + +当模型 $g$ 生成数据时,似然比检验选择错误模型的概率是 + +$$ +p_g = {\rm Prob}\left(L_T \geq 1 \Big|g \right) = \beta_T. +$$ + +我们可以通过赋予自然选择模型 $f$ 的贝叶斯先验概率 $\pi_{-1} = .5$,然后对 $p_f$ 和 $p_g$ 取平均值来构造似然比选择错误模型的概率,从而得到检测错误的贝叶斯后验概率等于 + +$$ +p(\textrm{wrong decision}) = {1 \over 2} (\alpha_T + \beta_T) . +$$ (eq:detectionerrorprob) + +现在让我们模拟时序协议1并计算错误概率 + +```{code-cell} ipython3 + +def compute_protocol_1_errors(π_minus_1, T_max, N_simulations, f_func, g_func, + F_params=(1, 1), G_params=(3, 1.2)): + """ + 计算协议1的错误概率。 + """ + sequences, true_models = protocol_1( + π_minus_1, T_max, N_simulations, F_params, G_params) + l_ratios, L_cumulative = compute_likelihood_ratios(sequences, + f_func, g_func) + + T_range = np.arange(1, T_max + 1) + + mask_f = true_models + mask_g = ~true_models + + L_f = L_cumulative[mask_f, :] + L_g = L_cumulative[mask_g, :] + + α_T = np.mean(L_f < 1, axis=0) + β_T = np.mean(L_g >= 1, axis=0) + error_prob = 0.5 * (α_T + β_T) + + return { + 'T_range': T_range, + 'alpha': α_T, + 'beta': β_T, + 'error_prob': error_prob, + 'L_cumulative': L_cumulative, + 'true_models': true_models + } +``` + +以下代码可视化了时序协议1的错误概率 + +```{code-cell} ipython3 +:tags: [hide-input] + +def analyze_protocol_1(π_minus_1, T_max, N_simulations, f_func, g_func, + F_params=(1, 1), G_params=(3, 1.2)): + """分析协议1""" + result = compute_protocol_1_errors(π_minus_1, T_max, N_simulations, + f_func, g_func, F_params, G_params) + + # 绘制结果 + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) + + ax1.plot(result['T_range'], result['alpha'], 'b-', + label=r'$\alpha_T$', linewidth=2) + ax1.plot(result['T_range'], result['beta'], 'r-', + label=r'$\beta_T$', linewidth=2) + ax1.set_xlabel('$T$') + ax1.set_ylabel('错误概率') + ax1.legend() + + ax2.plot(result['T_range'], result['error_prob'], 'g-', + label=r'$\frac{1}{2}(\alpha_T+\beta_T)$', linewidth=2) + ax2.set_xlabel('$T$') + ax2.set_ylabel('错误概率') + ax2.legend() + + plt.tight_layout() + plt.show() + + # 打印总结 + print(f"在T={T_max}时:") + print(f"α_{T_max} = {result['alpha'][-1]:.4f}") + print(f"β_{T_max} = {result['beta'][-1]:.4f}") + print(f"模型选择错误概率 = {result['error_prob'][-1]:.4f}") + + return result + +# 分析协议1 +π_minus_1 = 0.5 +T_max = 30 +N_simulations = 10_000 + +result_p1 = analyze_protocol_1(π_minus_1, T_max, N_simulations, + f, g, (F_a, F_b), (G_a, G_b)) +``` + +注意随着$T$的增长,模型选择的错误概率趋近于零。 + +### 分类 + +我们现在考虑一个假设采用时序协议2的问题。 + +决策者想要将观察序列$\{w_t\}_{t=1}^T$的组成部分分类为来自$f$或$g$。 + +决策者使用以下分类规则: + $$ \begin{aligned} -K_{g} &=E_{h}\left[\log\left(\frac{g\left(w\right)}{h\left(w\right)}\right)\frac{g\left(w\right)}{h\left(w\right)}\right] \\ - &=\int\log\left(\frac{g\left(w\right)}{h\left(w\right)}\right)\frac{g\left(w\right)}{h\left(w\right)}h\left(w\right)dw \\ - &=\int\log\left(\frac{g\left(w\right)}{h\left(w\right)}\right)g\left(w\right)dw +w_t & \ {\rm 来自 \ } f \ {\rm 如果 \ } l_t > 1 \\ +w_t & \ {\rm 来自 \ } g \ {\rm 如果 \ } l_t \leq 1 . \end{aligned} $$ -当 $K_g < K_f$ 时,$g$ 比 $f$ 更接近 $h$。 +在这个规则下,预期的错误分类率为 -- 在这种情况下,我们会发现 $L\left(w^t\right) \rightarrow 0$。 +$$ +p(\textrm{misclassification}) = {1 \over 2} (\tilde \alpha_t + \tilde \beta_t) +$$ (eq:classerrorprob) -当 $K_g > K_f$ 时,$f$ 比 $g$ 更接近 $h$。 +其中$\tilde \alpha_t = {\rm Prob}(l_t < 1 \mid f)$且$\tilde \beta_t = {\rm Prob}(l_t \geq 1 \mid g)$。 -- 在这种情况下,我们会发现 $L\left(w^t\right) \rightarrow + \infty$ +现在让我们编写一些代码来模拟它 -我们现在将尝试一个$h$也是贝塔分布的情况 +```{code-cell} ipython3 +def compute_protocol_2_errors(π_minus_1, T_max, N_simulations, f_func, g_func, + F_params=(1, 1), G_params=(3, 1.2)): + """ + 计算协议2的错误概率。 + """ + sequences, true_models = protocol_2(π_minus_1, + T_max, N_simulations, F_params, G_params) + l_ratios, _ = compute_likelihood_ratios(sequences, f_func, g_func) + + T_range = np.arange(1, T_max + 1) + + accuracy = np.empty(T_max) + for t in range(T_max): + predictions = (l_ratios[:, t] >= 1) + actual = true_models[:, t] + accuracy[t] = np.mean(predictions == actual) + + return { + 'T_range': T_range, + 'accuracy': accuracy, + 'l_ratios': l_ratios, + 'true_models': true_models + } -我们首先设置参数$G_a$和$G_b$,使得 -$h$更接近$g$ +``` -```{code-cell} ipython3 -H_a, H_b = 3.5, 1.8 +由于对于每个 $t$,决策边界都是相同的,因此可以通过以下方式计算决策边界 -h = jit(lambda x: p(x, H_a, H_b)) +```{code-cell} ipython3 +root = brentq(lambda w: f(w) / g(w) - 1, 0.001, 0.999) ``` +我们可以绘制$f$和$g$的分布以及决策边界 + ```{code-cell} ipython3 -x_range = np.linspace(0, 1, 100) -plt.plot(x_range, f(x_range), label='f') -plt.plot(x_range, g(x_range), label='g') -plt.plot(x_range, h(x_range), label='h') +:tags: [hide-input] + +fig, ax = plt.subplots(figsize=(7, 6)) + +w_range = np.linspace(1e-5, 1-1e-5, 1000) +f_values = [f(w) for w in w_range] +g_values = [g(w) for w in w_range] +ratio_values = [f(w)/g(w) for w in w_range] -plt.legend() +ax.plot(w_range, f_values, 'b-', + label=r'$f(w) \sim Beta(1,1)$', linewidth=2) +ax.plot(w_range, g_values, 'r-', + label=r'$g(w) \sim Beta(3,1.2)$', linewidth=2) + +type1_prob = 1 - beta_dist.cdf(root, F_a, F_b) +type2_prob = beta_dist.cdf(root, G_a, G_b) + +w_type1 = w_range[w_range >= root] +f_type1 = [f(w) for w in w_type1] +ax.fill_between(w_type1, 0, f_type1, alpha=0.3, color='blue', + label=fr'$\tilde \alpha_t = {type1_prob:.2f}$') + +w_type2 = w_range[w_range <= root] +g_type2 = [g(w) for w in w_type2] +ax.fill_between(w_type2, 0, g_type2, alpha=0.3, color='red', + label=fr'$\tilde \beta_t = {type2_prob:.2f}$') + +ax.axvline(root, color='green', linestyle='--', alpha=0.7, + label=f'决策边界: $w=${root:.3f}') + +ax.set_xlabel('w') +ax.set_ylabel('概率密度') +ax.legend() + +plt.tight_layout() plt.show() ``` -让我们通过求积分计算Kullback-Leibler差异。 +在绿色垂直线的左侧,$g < f$,所以 $l_t > 1$;因此,落在绿线左侧的 $w_t$ 被归类为 $f$ 类型个体。 + + * 红色阴影区域等于 $\beta$ -- 将实际为 $f$ 类型的个体错误分类为 $g$ 类型的概率。 + +在绿色垂直线的右侧,$g > f$,所以 $l_t < 1$;因此,落在绿线右侧的 $w_t$ 被归类为 $g$ 类型个体。 + + * 蓝色阴影区域等于 $\alpha$ -- 将实际为 $g$ 类型的个体错误分类为 $f$ 类型的概率。 + +这给了我们计算理论分类错误概率的线索 ```{code-cell} ipython3 -def KL_integrand(w, q, h): +# 计算理论 tilde α_t 和 tilde β_t +def α_integrand(w): + """用于计算 tilde α_t = P(l_t < 1 | f) 的积分""" + return f(w) if f(w) / g(w) < 1 else 0 - m = q(w) / h(w) +def β_integrand(w): + """用于计算 tilde β_t = P(l_t >= 1 | g) 的积分""" + return g(w) if f(w) / g(w) >= 1 else 0 - return np.log(m) * q(w) +# 计算积分 +α_theory, _ = quad(α_integrand, 0, 1, limit=100) +β_theory, _ = quad(β_integrand, 0, 1, limit=100) + +theory_error = 0.5 * (α_theory + β_theory) + +print(f"理论 tilde α_t = {α_theory:.4f}") +print(f"理论 tilde β_t = {β_theory:.4f}") +print(f"理论分类错误概率 = {theory_error:.4f}") ``` +现在我们模拟时序协议2并计算分类错误概率。 + +在下一个单元格中,我们还将理论分类准确率与实验分类准确率进行比较 + ```{code-cell} ipython3 -def compute_KL(h, f, g): +def analyze_protocol_2(π_minus_1, T_max, N_simulations, f_func, g_func, + theory_error=None, F_params=(1, 1), G_params=(3, 1.2)): + """分析协议2。""" + result = compute_protocol_2_errors(π_minus_1, T_max, N_simulations, + f_func, g_func, F_params, G_params) + + # 绘制结果 + plt.figure(figsize=(10, 6)) + plt.plot(result['T_range'], result['accuracy'], + 'b-', linewidth=2, label='实验准确率') + + if theory_error is not None: + plt.axhline(1 - theory_error, color='r', linestyle='--', + label=f'理论准确率 = {1 - theory_error:.4f}') + + plt.xlabel('$t$') + plt.ylabel('准确率') + plt.legend() + plt.ylim(0.5, 1.0) + plt.show() + + return result + +# 分析协议2 +result_p2 = analyze_protocol_2(π_minus_1, T_max, N_simulations, f, g, + theory_error, (F_a, F_b), (G_a, G_b)) +``` - Kf, _ = quad(KL_integrand, 0, 1, args=(f, h)) - Kg, _ = quad(KL_integrand, 0, 1, args=(g, h)) +让我们观察随着观测数据的不断累积,两种时序协议所做出的决策变化。 - return Kf, Kg +```{code-cell} ipython3 +def compare_protocols(result1, result2): + """比较两种协议的结果。""" + plt.figure(figsize=(10, 6)) + + plt.plot(result1['T_range'], result1['error_prob'], linewidth=2, + label='协议1(模型选择)') + plt.plot(result2['T_range'], 1 - result2['accuracy'], + linestyle='--', linewidth=2, + label='协议2(分类)') + + plt.xlabel('$T$') + plt.ylabel('错误概率') + plt.legend() + plt.show() + +compare_protocols(result_p1, result_p2) ``` +从上图可以看出: + +- 对于两种时序协议,误差概率都从相同的水平开始,只是受到一些随机性的影响。 + +- 对于时序协议1,随着样本量的增加,误差概率会降低,因为我们只做**一个**决定 -- 即选择是$f$还是$g$支配**所有**个体。更多的数据提供了更好的证据。 + +- 对于时序协议2,误差概率保持不变,因为我们在做**多个**决定 -- 对每个观测都要做一个分类决定。 + +**注意:**思考一下大数定律是如何应用于计算模型选择问题和分类问题的误差概率的。 + +### 误差概率和散度度量 + +一个合理的猜测是,似然比区分分布$f$和$g$的能力取决于它们有多"不同"。 + +我们在{doc}`divergence_measures`中已经学习了一些衡量分布之间"差异"的度量。 + +现在让我们研究两个在模型选择和分类背景下有用的分布之间"差异"的度量。 + +回顾一下,概率密度$f$和$g$之间的Chernoff熵定义为: + +$$ +C(f,g) = - \log \min_{\phi \in (0,1)} \int f^\phi(x) g^{1-\phi}(x) dx +$$ + +模型选择误差概率的上界是 + +$$ +e^{-C(f,g)T} . +$$ + +让我们用Python代码来数值计算Chernoff熵 + ```{code-cell} ipython3 -Kf, Kg = compute_KL(h, f, g) -Kf, Kg +def chernoff_integrand(ϕ, f, g): + """ + 计算Chernoff熵的被积函数 + """ + def integrand(w): + return f(w)**ϕ * g(w)**(1-ϕ) + + result, _ = quad(integrand, 1e-5, 1-1e-5) + return result + +def compute_chernoff_entropy(f, g): + """ + 计算Chernoff熵C(f,g) + """ + def objective(ϕ): + return chernoff_integrand(ϕ, f, g) + + # 在(0,1)区间内找到最小值 + result = minimize_scalar(objective, + bounds=(1e-5, 1-1e-5), + method='bounded') + min_value = result.fun + ϕ_optimal = result.x + + chernoff_entropy = -np.log(min_value) + return chernoff_entropy, ϕ_optimal +C_fg, ϕ_optimal = compute_chernoff_entropy(f, g) +print(f"Chernoff熵C(f,g) = {C_fg:.4f}") +print(f"最优ϕ = {ϕ_optimal:.4f}") +``` + +现在让我们来研究 $e^{-C(f,g)T}$ 作为 $T$ 的函数时的表现,并将其与模型选择错误概率进行比较 + +```{code-cell} ipython3 +T_range = np.arange(1, T_max+1) +chernoff_bound = np.exp(-C_fg * T_range) + +# 绘制比较图 +fig, ax = plt.subplots(figsize=(10, 6)) + +ax.semilogy(T_range, chernoff_bound, 'r-', linewidth=2, + label=f'$e^{{-C(f,g)T}}$') +ax.semilogy(T_range, result_p1['error_prob'], 'b-', linewidth=2, + label='模型选择错误概率') + +ax.set_xlabel('T') +ax.set_ylabel('错误概率(对数刻度)') +ax.legend() +plt.tight_layout() +plt.show() ``` -我们有 $K_g < K_f$。 +显然,$e^{-C(f,g)T}$是误差率的上界。 -接下来,我们可以通过模拟来验证我们关于 $L\left(w^t\right)$ 的猜想。 +在`{doc}`divergence_measures`中,我们还研究了**Jensen-Shannon散度**作为分布之间的对称距离度量。 + +我们可以使用Jensen-Shannon散度来测量分布$f$和$g$之间的距离,并计算它与模型选择错误概率的协方差。 + +我们还可以通过一些Python代码来数值计算Jensen-Shannon散度 ```{code-cell} ipython3 -l_arr_h = simulate(H_a, H_b) -l_seq_h = np.cumprod(l_arr_h, axis=1) +def compute_JS(f, g): + """ + 计算Jensen-Shannon散度 + """ + def m(w): + return 0.5 * (f(w) + g(w)) + + js_div = 0.5 * compute_KL(f, m) + 0.5 * compute_KL(g, m) + return js_div ``` -下图绘制了随时间变化的路径分数$L\left(w^t\right)$在区间$[0,0.01]$内的比例。 +现在让我们回到我们的猜想,即在大样本量情况下的错误概率与两个分布之间的Chernoff熵有关。 + +我们通过计算时序协议1下$T=50$时错误概率的对数与散度度量之间的相关性来验证这一点。 + +在下面的模拟中,自然界从$g$中抽取$N/2$个序列,从$f$中抽取$N/2$个序列。 + +```{note} +自然界采用这种方式,而不是在每次长度为$T$的模拟之前抛一次公平硬币来决定是从$g$还是$f$中抽取。 +``` -注意当$g$比$f$更接近$h$时,该比例如预期般收敛到1。 +我们使用以下Beta分布对作为$f$和$g$的测试用例 ```{code-cell} ipython3 -N, T = l_arr_h.shape -plt.plot(range(T), np.sum(l_seq_h <= 0.01, axis=0) / N) +distribution_pairs = [ + # (f_params, g_params) + ((1, 1), (0.1, 0.2)), + ((1, 1), (0.3, 0.3)), + ((1, 1), (0.3, 0.4)), + ((1, 1), (0.5, 0.5)), + ((1, 1), (0.7, 0.6)), + ((1, 1), (0.9, 0.8)), + ((1, 1), (1.1, 1.05)), + ((1, 1), (1.2, 1.1)), + ((1, 1), (1.5, 1.2)), + ((1, 1), (2, 1.5)), + ((1, 1), (2.5, 1.8)), + ((1, 1), (3, 1.2)), + ((1, 1), (4, 1)), + ((1, 1), (5, 1)) +] ``` -我们也可以尝试一个比$g$更接近$f$的$h$,这样$K_g$就会大于$K_f$。 +现在让我们运行模拟 ```{code-cell} ipython3 -H_a, H_b = 1.2, 1.2 -h = jit(lambda x: p(x, H_a, H_b)) +# 模拟参数 +T_large = 50 +N_sims = 5000 +N_half = N_sims // 2 + +# 初始化数组 +n_pairs = len(distribution_pairs) +kl_fg_vals = np.zeros(n_pairs) +kl_gf_vals = np.zeros(n_pairs) +js_vals = np.zeros(n_pairs) +chernoff_vals = np.zeros(n_pairs) +error_probs = np.zeros(n_pairs) +pair_names = [] + +for i, ((f_a, f_b), (g_a, g_b)) in enumerate(distribution_pairs): + # 创建密度函数 + f = jit(lambda x, a=f_a, b=f_b: p(x, a, b)) + g = jit(lambda x, a=g_a, b=g_b: p(x, a, b)) + + # 计算散度度量 + kl_fg_vals[i] = compute_KL(f, g) + kl_gf_vals[i] = compute_KL(g, f) + js_vals[i] = compute_JS(f, g) + chernoff_vals[i], _ = compute_chernoff_entropy(f, g) + + # 生成样本 + sequences_f = np.random.beta(f_a, f_b, (N_half, T_large)) + sequences_g = np.random.beta(g_a, g_b, (N_half, T_large)) + + # 计算似然比和累积乘积 + _, L_cumulative_f = compute_likelihood_ratios(sequences_f, f, g) + _, L_cumulative_g = compute_likelihood_ratios(sequences_g, f, g) + + # 获取最终值 + L_cumulative_f = L_cumulative_f[:, -1] + L_cumulative_g = L_cumulative_g[:, -1] + + # 计算错误概率 + error_probs[i] = 0.5 * (np.mean(L_cumulative_f < 1) + + np.mean(L_cumulative_g >= 1)) + pair_names.append(f"Beta({f_a},{f_b}) and Beta({g_a},{g_b})") + +cor_data = { + 'kl_fg': kl_fg_vals, + 'kl_gf': kl_gf_vals, + 'js': js_vals, + 'chernoff': chernoff_vals, + 'error_prob': error_probs, + 'names': pair_names, + 'T': T_large} ``` +现在让我们来可视化这些相关性 + ```{code-cell} ipython3 -Kf, Kg = compute_KL(h, f, g) -Kf, Kg +:tags: [hide-input] + +def plot_error_divergence(data): + """ + 绘制误差概率和散度测量之间的相关性。 + """ + # 过滤掉接近零的误差概率以适应对数刻度 + nonzero_mask = data['error_prob'] > 1e-6 + log_error = np.log(data['error_prob'][nonzero_mask]) + js_vals = data['js'][nonzero_mask] + chernoff_vals = data['chernoff'][nonzero_mask] + + # 创建图形和坐标轴 + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5)) + + # 绘制相关性的函数 + def plot_correlation(ax, x_vals, x_label, color): + ax.scatter(x_vals, log_error, alpha=0.7, s=60, color=color) + ax.set_xlabel(x_label) + ax.set_ylabel(f'T={data["T"]}时的对数误差概率') + + # 计算相关性和趋势线 + corr = np.corrcoef(x_vals, log_error)[0, 1] + z = np.polyfit(x_vals, log_error, 2) + x_trend = np.linspace(x_vals.min(), x_vals.max(), 100) + ax.plot(x_trend, np.poly1d(z)(x_trend), + "r--", alpha=0.8, linewidth=2) + ax.set_title(f'对数误差概率与{x_label}的关系\n' + f'相关性 = {corr:.3f}') + + # 绘制两个相关性图 + plot_correlation(ax1, js_vals, 'JS散度', 'C0') + plot_correlation(ax2, chernoff_vals, 'Chernoff熵', 'C1') + + plt.tight_layout() + plt.show() + +plot_error_divergence(cor_data) ``` +显然,Chernoff熵和Jensen-Shannon熵都与模型选择错误概率密切相关。 + +我们很快将在{doc}`wald_friedman`中遇到相关概念。 + +(lrp_markov)= +## 马尔可夫链 + +现在让我们来看看一个非独立同分布随机变量序列的似然比过程。 + +这里我们假设该序列是由有限状态空间上的马尔可夫链生成的。 + +我们考虑在相同状态空间{1, 2, ..., n}上的两个n状态不可约非周期马尔可夫链模型,它们具有正转移矩阵$P^{(f)}$、$P^{(g)}$和初始分布$\pi_0^{(f)}$、$\pi_0^{(g)}$。 + +我们假设自然从链f中采样。 + +对于样本路径$(x_0, x_1, \ldots, x_T)$,让$N_{ij}$计算从状态i到j的转移次数。 + +模型$m \in \{f, g\}$下的似然过程为 + +$$ +L_T^{(m)} = \pi_{0,x_0}^{(m)} \prod_{i=1}^n \prod_{j=1}^n \left(P_{ij}^{(m)}\right)^{N_{ij}} +$$ + +因此, + +$$ +\log L_T^{(m)} =\log\pi_{0,x_0}^{(m)} +\sum_{i,j}N_{ij}\log P_{ij}^{(m)} +$$ + +对数似然比为 + +$$ +\log \frac{L_T^{(f)}}{L_T^{(g)}} = \log \frac{\pi_{0,x_0}^{(f)}}{\pi_{0,x_0}^{(g)}} + \sum_{i,j}N_{ij}\log \frac{P_{ij}^{(f)}}{P_{ij}^{(g)}} +$$ (eq:llr_markov) + +### KL散度率 + +根据不可约非周期马尔可夫链的遍历定理,我们有 + +$$ +\frac{N_{ij}}{T} \xrightarrow{a.s.} \pi_i^{(f)}P_{ij}^{(f)} \quad \text{当 } T \to \infty +$$ + +其中 $\boldsymbol{\pi}^{(f)}$ 是满足 $\boldsymbol{\pi}^{(f)} = \boldsymbol{\pi}^{(f)} P^{(f)}$ 的平稳分布。 + +因此, + +$$ +\frac{1}{T}\log \frac{L_T^{(f)}}{L_T^{(g)}} = \frac{1}{T}\log \frac{\pi_{0,x_0}^{(f)}}{\pi_{0,x_0}^{(g)}} + \frac{1}{T}\sum_{i,j}N_{ij}\log \frac{P_{ij}^{(f)}}{P_{ij}^{(g)}} +$$ + +当 $T \to \infty$ 时,我们有: +- 第一项:$\frac{1}{T}\log \frac{\pi_{0,x_0}^{(f)}}{\pi_{0,x_0}^{(g)}} \to 0$ +- 第二项:$\frac{1}{T}\sum_{i,j}N_{ij}\log \frac{P_{ij}^{(f)}}{P_{ij}^{(g)}} \xrightarrow{a.s.} \sum_{i,j}\pi_i^{(f)}P_{ij}^{(f)}\log \frac{P_{ij}^{(f)}}{P_{ij}^{(g)}}$ + +定义**KL散度率**为 + +$$ +h_{KL}(f, g) = \sum_{i=1}^n \pi_i^{(f)} \underbrace{\sum_{j=1}^n P_{ij}^{(f)} \log \frac{P_{ij}^{(f)}}{P_{ij}^{(g)}}}_{=: KL(P_{i\cdot}^{(f)}, P_{i\cdot}^{(g)})} +$$ + +其中 $KL(P_{i\cdot}^{(f)}, P_{i\cdot}^{(g)})$ 是按行计算的KL散度。 + +根据遍历定理,我们有 + +$$ +\frac{1}{T}\log \frac{L_T^{(f)}}{L_T^{(g)}} \xrightarrow{a.s.} h_{KL}(f, g) \quad \text{当 } T \to \infty +$$ + +取期望并使用控制收敛定理,我们得到 + +$$ +\frac{1}{T}E_f\left[\log \frac{L_T^{(f)}}{L_T^{(g)}}\right] \to h_{KL}(f, g) \quad \text{当 } T \to \infty +$$ + +在这里我们邀请读者停下来比较这个结果与{eq}`eq:kl_likelihood_link`。 + +让我们在下面的模拟中验证这一点。 + +### 模拟 + +让我们通过三状态马尔可夫链的模拟来说明这些概念。 + +首先编写函数来计算马尔可夫链模型的平稳分布和KL散度率。 + ```{code-cell} ipython3 -l_arr_h = simulate(H_a, H_b) -l_seq_h = np.cumprod(l_arr_h, axis=1) +:tags: [hide-input] + +def compute_stationary_dist(P): + """ + 计算转移矩阵P的平稳分布 + """ + eigenvalues, eigenvectors = np.linalg.eig(P.T) + idx = np.argmax(np.abs(eigenvalues)) + stationary = np.real(eigenvectors[:, idx]) + return stationary / stationary.sum() + +def markov_kl_divergence(P_f, P_g, pi_f): + """ + 计算两个马尔可夫链之间的KL散度率 + """ + if np.any((P_f > 0) & (P_g == 0)): + return np.inf + + valid_mask = (P_f > 0) & (P_g > 0) + log_ratios = np.zeros_like(P_f) + log_ratios[valid_mask] = np.log(P_f[valid_mask] / P_g[valid_mask]) + + # 用平稳概率加权并求和 + kl_rate = np.sum(pi_f[:, np.newaxis] * P_f * log_ratios) + return kl_rate + +def simulate_markov_chain(P, pi_0, T, N_paths=1000): + """ + 模拟马尔可夫链的N_paths条样本路径 + """ + mc = qe.MarkovChain(P, state_values=None) + initial_states = np.random.choice(len(P), size=N_paths, p=pi_0) + paths = np.zeros((N_paths, T+1), dtype=int) + + for i in range(N_paths): + path = mc.simulate(T+1, init=initial_states[i]) + paths[i, :] = path + + return paths + +def compute_likelihood_ratio_markov(paths, P_f, P_g, π_0_f, π_0_g): + """ + 计算马尔可夫链路径的似然比过程 + """ + N_paths, T_plus_1 = paths.shape + T = T_plus_1 - 1 + L_ratios = np.ones((N_paths, T+1)) + + # 初始似然比 + L_ratios[:, 0] = π_0_f[paths[:, 0]] / π_0_g[paths[:, 0]] + + # 计算序列似然比 + for t in range(1, T+1): + prev_states = paths[:, t-1] + curr_states = paths[:, t] + + transition_ratios = (P_f[prev_states, curr_states] / + P_g[prev_states, curr_states]) + L_ratios[:, t] = L_ratios[:, t-1] * transition_ratios + + return L_ratios + +def analyze_markov_chains(P_f, P_g, + T=500, N_paths=1000, plot_paths=True, n_show=50): + """ + 两个马尔可夫链的完整分析 + """ + # 计算平稳分布 + π_f = compute_stationary_dist(P_f) + π_g = compute_stationary_dist(P_g) + + print(f"平稳分布 (f): {π_f}") + print(f"平稳分布 (g): {π_g}") + + # 计算KL散度率 + kl_rate_fg = markov_kl_divergence(P_f, P_g, π_f) + kl_rate_gf = markov_kl_divergence(P_g, P_f, π_g) + + print(f"\nKL散度率 h(f, g): {kl_rate_fg:.4f}") + print(f"KL散度率 h(g, f): {kl_rate_gf:.4f}") + + if plot_paths: + # 模拟并绘制路径 + paths_from_f = simulate_markov_chain(P_f, π_f, T, N_paths) + L_ratios_f = compute_likelihood_ratio_markov( + paths_from_f, P_f, P_g, π_f, π_g) + + plt.figure(figsize=(10, 6)) + + # 绘制个别路径 + for i in range(min(n_show, N_paths)): + plt.plot(np.log(L_ratios_f[i, :]), alpha=0.3, color='blue', lw=0.8) + + # 绘制理论期望 + theory_line = kl_rate_fg * np.arange(T+1) + plt.plot(theory_line, 'k--', linewidth=2.5, + label=r'$T \times h_{KL}(f,g)$') + + # 绘制经验平均值 + avg_log_L = np.mean(np.log(L_ratios_f), axis=0) + plt.plot(avg_log_L, 'r-', linewidth=2.5, + label='经验平均值', alpha=0.7) + + plt.axhline(y=0, color='gray', linestyle='--', alpha=0.5) + plt.xlabel(r'$T$') + plt.ylabel(r'$\log L_T$') + plt.title('马尔可夫链似然比(本质 = f)') + plt.legend() + plt.show() + + return { + 'stationary_f': π_f, + 'stationary_g': π_g, + 'kl_rate_fg': kl_rate_fg, + 'kl_rate_gf': kl_rate_gf + } + +def compute_markov_selection_error(T_values, P_f, P_g, π_0_f, π_0_g, N_sim=1000): + """ + 计算马尔可夫链的模型选择错误概率 + """ + errors = [] + + for T in T_values: + # 从两个模型中模拟 + paths_f = simulate_markov_chain(P_f, π_0_f, T, N_sim//2) + paths_g = simulate_markov_chain(P_g, π_0_g, T, N_sim//2) + + # 计算似然比 + L_f = compute_likelihood_ratio_markov(paths_f, P_f, P_g, π_0_f, π_0_g) + L_g = compute_likelihood_ratio_markov(paths_g, P_f, P_g, π_0_f, π_0_g) + + # 决策规则:如果L_T >= 1则选择f + error_f = np.mean(L_f[:, -1] < 1) # 第一类错误 + error_g = np.mean(L_g[:, -1] >= 1) # 第二类错误 + + total_error = 0.5 * (error_f + error_g) + errors.append(total_error) + + return np.array(errors) ``` -现在$L\left(w^t\right)$的概率质量在10000以上的部分趋向于$+\infty$。 +现在让我们创建一个包含两个不同的3状态马尔可夫链的示例。 + +我们现在准备模拟路径并可视化似然比是如何演变的。 + +我们通过绘制经验平均值和理论预测线来验证从平稳分布开始的 $\frac{1}{T}E_f\left[\log \frac{L_T^{(f)}}{L_T^{(g)}}\right] = h_{KL}(f, g)$ ```{code-cell} ipython3 -N, T = l_arr_h.shape -plt.plot(range(T), np.sum(l_seq_h > 10000, axis=0) / N) +# 定义示例马尔可夫链转移矩阵 +P_f = np.array([[0.7, 0.2, 0.1], + [0.3, 0.5, 0.2], + [0.1, 0.3, 0.6]]) + +P_g = np.array([[0.5, 0.3, 0.2], + [0.2, 0.6, 0.2], + [0.2, 0.2, 0.6]]) + +markov_results = analyze_markov_chains(P_f, P_g) ``` -## 后续内容 +## 相关讲座 + +似然过程在贝叶斯学习中扮演重要角色,正如在{doc}`likelihood_bayes`中所描述的,并在{doc}`odu`中得到应用。 + +似然比过程是Lawrence Blume和David Easley回答他们提出的问题"如果你那么聪明,为什么不富有?" {cite}`blume2006if`的核心,这是讲座{doc}`likelihood_ratio_process_2`的主题。 + +似然比过程也出现在{doc}`advanced:additive_functionals`中,其中包含了另一个关于上述似然比过程**特殊性质**的说明。 + +## 练习 -似然过程在贝叶斯学习中扮演着重要角色,正如在{doc}`这篇讲座`中所描述的,并在{doc}`这篇讲座`中得到应用。 +```{exercise} +:label: lr_ex1 + +考虑自然从第三个密度函数$h$生成数据的情况。 + +设$\{w_t\}_{t=1}^T$是从$h$中独立同分布抽取的样本,且$L_t = L(w^t)$是如讲座中定义的似然比过程。 + +证明: + +$$ +\frac{1}{t} E_h[\log L_t] = K_g - K_f +$$ + +其中$K_g, K_f$有限,$E_h |\log f(W)| < \infty$且$E_h |\log g(W)| < \infty$。 + +*提示:* 首先将$\log L_t$表示为$\log \ell(w_i)$项的和,并与$K_f$和$K_g$的定义进行比较。 +``` + +```{solution-start} lr_ex1 +:class: dropdown +``` -似然比过程在[这篇讲座](https://python-advanced.quantecon.org/additive_functionals.html)中再次出现,其中包含了另一个关于上述似然比过程**特殊性质**的说明。 +由于$w_1, \ldots, w_t$是从$h$中独立同分布抽取的样本,我们可以写成 + +$$ +\log L_t = \log \prod_{i=1}^t \ell(w_i) = \sum_{i=1}^t \log \ell(w_i) = \sum_{i=1}^t \log \frac{f(w_i)}{g(w_i)} +$$ + +在$h$下取期望 + +$$ +E_h[\log L_t] += E_h\left[\sum_{i=1}^t \log \frac{f(w_i)}{g(w_i)}\right] + += \sum_{i=1}^t E_h\left[\log \frac{f(w_i)}{g(w_i)}\right] +$$ + +由于 $w_i$ 是同分布的 + +$$ +E_h[\log L_t] = t \cdot E_h\left[\log \frac{f(w)}{g(w)}\right] +$$ + +其中 $w \sim h$。 + +因此 + +$$ +\frac{1}{t} E_h[\log L_t] = E_h\left[\log \frac{f(w)}{g(w)}\right] = E_h[\log f(w)] - E_h[\log g(w)] +$$ + +根据 Kullback-Leibler 散度的定义 + +$$ +K_f = \int h(w) \log \frac{h(w)}{f(w)} dw = E_h[\log h(w)] - E_h[\log f(w)] +$$ + +这给出 + +$$ +E_h[\log f(w)] = E_h[\log h(w)] - K_f +$$ + +类似地 + +$$ +E_h[\log g(w)] = E_h[\log h(w)] - K_g +$$ + +代回得到 + +$$ +\begin{aligned} +\frac{1}{t} E_h[\log L_t] &= E_h[\log f(w)] - E_h[\log g(w)] \\ +&= [E_h[\log h(w)] - K_f] - [E_h[\log h(w)] - K_g] \\ +&= K_g - K_f +\end{aligned} +$$ + +```{solution-end} +``` + +```{exercise} +:label: lr_ex2 + +基于{ref}`lr_ex1`的结果,解释当 $t \to \infty$ 时在以下情况下 $L_t$ 会发生什么: + +1. 当 $K_g > K_f$ 时(即 $f$ 比 $g$ 更"接近" $h$) +2. 当 $K_g < K_f$ 时(即 $g$ 比 $f$ 更"接近" $h$) + +将你的答案与{ref}`本节`中显示的模拟结果联系起来。 +``` + +```{solution-start} lr_ex2 +:class: dropdown +``` + +从{ref}`lr_ex1`中,我们知道: + +$$ +\frac{1}{t} E_h[\log L_t] = K_g - K_f +$$ + +**情况1:** 当 $K_g > K_f$ 时 + +这里, $f$ 比 $g$ 更"接近" $h$。由于 $K_g - K_f > 0$ + +$$ +E_h[\log L_t] = t \cdot (K_g - K_f) \to +\infty \text{ 当 } t \to \infty +$$ + +根据大数定律,$\frac{1}{t} \log L_t \to K_g - K_f > 0$ 几乎必然成立。 + +因此 $L_t \to +\infty$ 几乎必然成立。 + +**情况2:** 当 $K_g < K_f$ 时 + +这里,$g$ 比 $f$ "更接近" $h$。由于 $K_g - K_f < 0$ + +$$ +E_h[\log L_t] = t \cdot (K_g - K_f) \to -\infty \text{ 当 } t \to \infty +$$ + +因此通过类似的推理 $L_t \to 0$ 几乎必然成立。 + +```{solution-end} +``` diff --git a/lectures/likelihood_ratio_process_2.md b/lectures/likelihood_ratio_process_2.md new file mode 100644 index 00000000..872a93ed --- /dev/null +++ b/lectures/likelihood_ratio_process_2.md @@ -0,0 +1,1708 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.6 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +(likelihood_ratio_process_2)= +```{raw} jupyter + +``` + +# 异质信念与金融市场 + +```{contents} 目录 +:depth: 2 +``` + +## 概述 + +似然比过程是Lawrence Blume和David Easley回答他们提出的问题"如果你那么聪明,为什么不富有?"的基础 {cite}`blume2006if`。 + +Blume和Easley构建了正式模型,研究关于风险收入过程概率的不同观点如何影响结果,以及如何反映在个人用来分享和对冲风险的股票、债券和保险政策的价格中。 + +```{note} +{cite}`alchian1950uncertainty`和{cite}`friedman1953essays`推测,通过奖励具有更现实概率模型的交易者,金融证券的竞争市场将财富置于信息更充分的交易者手中,并有助于使风险资产的价格反映现实的概率评估。 +``` + +在这里,我们将提供一个示例来说明Blume和Easley分析的基本组成部分。 + +我们将只关注他们对完全市场环境的分析,在这种环境中可以进行所有可想象的风险证券交易。 + +我们将研究两种替代安排: + +* 完全的社会主义制度,在这种制度下,个人每期都将消费品的禀赋交给中央计划者,然后由计划者独裁式地分配这些商品 +* 分散的竞争市场体系,在这种体系中,自私的价格接受者在竞争市场中自愿相互交易 + +福利经济学的基本定理将适用,并向我们保证这两种安排最终会产生完全相同的消费品分配结果,**前提是**社会计划者分配了一组适当的**帕累托权重**。 + +```{note} +你可以在{doc}`这篇关于规划问题的讲座 `和{doc}`这篇关于相关竞争均衡的讲座 `中了解现代宏观经济模型如何应用这两个福利定理。{doc}`这篇quantecon讲座 `介绍了具有同质信念的完全市场模型的递归表述。 +``` + +让我们首先导入一些Python工具。 + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" +mpl.font_manager.fontManager.addfont(FONTPATH) +plt.rcParams['font.family'] = ['Source Han Serif SC'] + +import numpy as np +from numba import vectorize, jit, prange +from math import gamma +from scipy.integrate import quad +``` + +## 回顾:似然比过程 + +让我们首先回顾似然比过程的定义和性质。 + +一个非负随机变量 $W$ 具有两个概率密度函数之一,要么是 $f$,要么是 $g$。 + +在时间开始之前,自然界一劳永逸地决定是从 $f$ 还是 $g$ 中进行一系列独立同分布的抽样。 + +我们有时用 $q$ 表示自然界永久选择的密度,所以 $q$ 要么是 $f$,要么是 $g$,且是永久性的。 + +自然界知道它永久从哪个密度中抽样,但我们这些观察者并不知道。 + +我们知道 $f$ 和 $g$ 两个密度,但不知道自然界选择了哪个。 + +但我们想要知道。 + +为此,我们使用观测值。 + +我们观察到一个序列 $\{w_t\}_{t=1}^T$,包含 $T$ 个独立同分布的抽样,我们知道这些抽样要么来自 $f$,要么来自 $g$。 + +我们想要利用这些观测值来推断自然界选择了 $f$ 还是 $g$。 + +**似然比过程**是完成这项任务的有用工具。 + +首先,我们定义似然比过程的一个关键组成部分,即时间 $t$ 的似然比,它是一个随机变量: + +$$ +\ell (w_t)=\frac{f\left(w_t\right)}{g\left(w_t\right)},\quad t\geq1. +$$ + +我们假设 $f$ 和 $g$ 在随机变量 $W$ 的相同可能实现区间上都赋予正概率。 + +这意味着在 $g$ 密度下,$\ell (w_t)= \frac{f\left(w_{t}\right)}{g\left(w_{t}\right)}$ 是一个均值为1的非负随机变量。 + +序列的**似然比过程**为 + +$\left\{ w_{t}\right\} _{t=1}^{\infty}$ 定义为 + +$$ +L\left(w^{t}\right)=\prod_{i=1}^{t} \ell (w_i), +$$ + +其中 $w^t=\{ w_1,\dots,w_t\}$ 是直到时间 $t$ (包括 $t$) 的观测历史。 + +有时为简便起见,我们会写 $L_t = L(w^t)$。 + +注意,似然过程满足以下*递归*关系 + +$$ +L(w^t) = \ell (w_t) L (w^{t-1}) . +$$ + +似然比及其对数是使用 Neyman 和 Pearson 经典频率派方法进行推断的关键工具 {cite}`Neyman_Pearson`。 + +为了帮助我们理解其工作原理,以下 Python 代码将 $f$ 和 $g$ 评估为两个不同的 Beta 分布,然后通过从两个概率分布中的一个生成序列 $w^t$(例如,从 $g$ 生成的 IID 抽样序列)来计算和模拟相关的似然比过程。 + +```{code-cell} ipython3 +# 两个 Beta 分布的参数 +F_a, F_b = 1, 1 +G_a, G_b = 3, 1.2 + +@vectorize +def p(x, a, b): + r = gamma(a + b) / (gamma(a) * gamma(b)) + return r * x** (a-1) * (1 - x) ** (b-1) + +# 两个密度函数 +f = jit(lambda x: p(x, F_a, F_b)) +g = jit(lambda x: p(x, G_a, G_b)) +``` + +```{code-cell} ipython3 +@jit +def simulate(a, b, T=50, N=500): + ''' + 生成N组T个似然比观测值, + 以N x T矩阵形式返回。 + ''' + + l_arr = np.empty((N, T)) + + for i in range(N): + for j in range(T): + w = np.random.beta(a, b) + l_arr[i, j] = f(w) / g(w) + + return l_arr +``` + +## Blume和Easley的设定 + +令随机变量 $s_t \in (0,1)$ 在时间 $t =0, 1, 2, \ldots$ 按照具有参数 $\theta = \{\theta_1, \theta_2\}$ 的相同Beta分布分布。 + +我们将这个概率密度表示为 + +$$ +\pi(s_t|\theta) +$$ + +为了节省空间,下面我们通常会直接写 $\pi(s_t)$ 而不是 $\pi(s_t|\theta)$。 + +令 $s_t \equiv y_t^1$ 为我们称为"个体1"在时间 $t$ 获得的不可储存消费品的禀赋。 + +令历史 $s^t = [s_t, s_{t-1}, \ldots, s_0]$ 为具有联合分布的独立同分布随机变量序列 + +$$ +\pi_t(s^t) = \pi(s_t) \pi(s_{t-1}) \cdots \pi(s_0) +$$ + +因此在我们的例子中,历史 $s^t$ 是从时间 $0$ 到时间 $t$ 个体 $1$ 的消费品禀赋的完整记录。 + +如果个体 $1$ 独自生活在一个岛上,个体 $1$ 在时间 $t$ 的消费 $c^1(s_t)$ 是 + +$$c^1(s_t) = y_t^1 = s_t. $$ + +但在我们的模型中,个体1并不是孤独的。 + +## 自然和个体的信念 + +自然从 $\pi_t(s^t)$ 中抽取独立同分布序列 $\{s_t\}_{t=0}^\infty$。 + +* 所以没有上标的 $\pi$ 是自然的模型 +* 但除了自然之外,我们的模型中还有其他实体——我们称之为"个体"的人工个体 +* 每个个体对 $t=0, \ldots$ 时的 $s^t$ 都有一个概率分布序列 +* 个体 $i$ 认为自然从 $\{\pi_t^i(s^t)\}_{t=0}^\infty$ 中抽取独立同分布序列 $\{s_t\}_{t=0}^\infty$ + +* 除非 $\pi_t^i(s^t) = \pi_t(s^t)$,否则个体 $i$ 是错误的 + +```{note} +**理性预期**模型会对所有个体 $i$ 设定 $\pi_t^i(s^t) = \pi_t(s^t)$。 +``` + +有两个个体,分别标记为 $i=1$ 和 $i=2$。 + +在时间 $t$,个体 $1$ 获得一个不可储存的消费品的禀赋 + +$$ +y_t^1 = s_t +$$ + +而个体 $2$ 获得禀赋 + +$$ +y_t^2 = 1 - s_t +$$ + +消费品的总禀赋为 + +$$ +y_t^1 + y_t^2 = 1 +$$ + +这在每个时间点 $t \geq 0$ 都成立。 + +在时间 $t$,个体 $i$ 消费 $c_t^i(s^t)$ 单位的商品。 + +每期总禀赋为1的(无浪费的)可行分配满足 + +$$ +c_t^1 + c_t^2 = 1 . +$$ + +## 社会主义风险分担安排 + +为了分担风险,一个仁慈的社会规划者制定了一个依赖于历史的消费分配,它采用一系列函数的形式 + +$$ +c_t^i = c_t^i(s^t) +$$ + +这些函数满足 + +$$ +c_t^1(s^t) + c_t^2(s^t) = 1 +$$ (eq:feasibility) + +对所有 $s^t$ 和所有 $t \geq 0$ 成立。 + +为了设计一个社会最优分配,社会规划者需要知道个体1对禀赋序列的信念以及他们对承担风险的态度。 + +关于禀赋序列,个体 $i$ 认为自然从联合密度中独立同分布地抽取序列 + +$$ +\pi_t^i(s^t) = \pi^i(s_t) \pi^i(s_{t-1}) \cdots \pi^i(s_0) +$$ + +关于承担风险的态度,个体 $i$ 有一个单期效用函数 + +$$ +u(c_t^i) = \ln (c_t^i) +$$ + +在第$t$期的消费边际效用为 + +$$ +u'(c_t^i) = \frac{1}{c_t^i} +$$ + +将其对随机禀赋序列的信念和对承担风险的态度结合起来,个体$i$的跨期效用函数为 + +$$ +V^i = \sum_{t=0}^{\infty} \sum_{s^t} \delta^t u(c_t^i(s^t)) \pi_t^i(s^t) , +$$ (eq:objectiveagenti) + +其中$\delta \in (0,1)$是跨期贴现因子,$u(\cdot)$是严格递增、凹的单期效用函数。 + +## 社会规划者的分配问题 + +仁慈的独裁者拥有所需的全部信息来选择一个消费分配,以最大化社会福利标准 + +$$ +W = \lambda V^1 + (1-\lambda) V^2 +$$ (eq:welfareW) + +其中$\lambda \in [0,1]$是帕累托权重,表示规划者对个体$1$的偏好程度,而$1 - \lambda$是帕累托权重,表示社会规划者对个体$2$的偏好程度。 + +设定$\lambda = .5$表示"平等主义"的社会偏好。 + +注意社会福利标准{eq}`eq:welfareW`如何通过公式{eq}`eq:objectiveagenti`考虑了两个个体的偏好。 + +这意味着社会规划者知道并尊重: + +* 每个个体的单期效用函数$u(\cdot) = \ln(\cdot)$ +* 每个个体$i$的概率模型$\{\pi_t^i(s^t)\}_{t=0}^\infty$ + +因此,我们预期这些对象将出现在社会规划者分配每期总禀赋的规则中。 + +对福利标准{eq}`eq:welfareW`在可行性约束{eq}`eq:feasibility`下最大化的一阶必要条件是 + +$$\frac{\pi_t^2(s^t)}{\pi_t^1(s^t)} \frac{(1/c_t^2(s^t))}{(1/c_t^1(s^t))} = \frac{\lambda}{1-\lambda}$$ + +可以重新整理为 + +$$ +\frac{c_t^1(s^t)}{c_t^2(s^t)} = \frac{\lambda}{1-\lambda} l_t(s^t) +$$ (eq:allocationrule0) + +其中 + +$$ l_t(s^t) = \frac{\pi_t^1(s^t)}{\pi_t^2(s^t)} $$ + +是个体1的联合密度与个体2的联合密度的似然比。 + +使用 + +$$c_t^1(s^t) + c_t^2(s^t) = 1$$ + +我们可以将分配规则{eq}`eq:allocationrule0`重写为 + +$$\frac{c_t^1(s^t)}{1 - c_t^1(s^t)} = \frac{\lambda}{1-\lambda} l_t(s^t)$$ + +或 + +$$c_t^1(s^t) = \frac{\lambda}{1-\lambda} l_t(s^t)(1 - c_t^1(s^t))$$ + +这意味着社会规划者的分配规则是 + +$$ +c_t^1(s^t) = \frac{\lambda l_t(s^t)}{1-\lambda + \lambda l_t(s^t)} +$$ (eq:allocationrule1) + +如果我们定义一个临时或**延续帕累托权重**过程为 + +$$ +\lambda_t(s^t) = \frac{\lambda l_t(s^t)}{1-\lambda + \lambda l_t(s^t)}, +$$ + +那么我们可以将社会规划者的分配规则表示为 + +$$ +c_t^1(s^t) = \lambda_t(s^t) . +$$ + +## 如果你这么聪明,$\ldots$ + +让我们计算一下对于一些有趣的似然比过程$l_t(s^t)$的极限值,其极限分配{eq}`eq:allocationrule1`的值: + +$$l_\infty (s^\infty)= 1; \quad c_\infty^1 = \lambda$$ + +* 在上述情况下,两个个体同样聪明(或同样不聪明),消费分配在两个个体之间保持在 $\lambda, 1 - \lambda$ 的分配比例。 + +$$l_\infty (s^\infty) = 0; \quad c_\infty^1 = 0$$ + +* 在上述情况下,个体2比个体1"更聪明",个体1在总禀赋中的份额趋近于零。 + +$$l_\infty (s^\infty)= \infty; \quad c_\infty^1 = 1$$ + +* 在上述情况下,个体1比个体2更聪明,个体1在总禀赋中的份额趋近于1。 + +```{note} +这三种情况某种程度上告诉我们随着时间推移个体的相对**财富**是如何演变的。 +* 当两个个体同样聪明且 $\lambda \in (0,1)$ 时,个体1的财富份额永远保持在 $\lambda$。 +* 当个体1更聪明且 $\lambda \in (0,1)$ 时,个体1最终"拥有"全部的延续禀赋,而个体2最终"一无所有"。 +* 当个体2更聪明且 $\lambda \in (0,1)$ 时,个体2最终"拥有"全部的延续禀赋,而个体1最终"一无所有"。 +延续财富可以在我们引入竞争均衡**价格**体系后被精确定义。 +``` + +很快我们将进行一些模拟,这将进一步阐明可能的结果。 + +但在此之前,让我们先转向研究社会规划问题的一些"影子价格",这些价格可以很容易地转换为竞争均衡的"均衡价格"。 + +这样做将使我们能够将分析与{cite}`alchian1950uncertainty`和{cite}`friedman1953essays`的论点联系起来,即竞争市场过程可以使风险资产的价格更好地反映现实的概率评估。 + +## 竞争均衡价格 + +一般均衡模型的两个基本福利定理使我们预期,在我们一直研究的社会规划问题的解决方案与具有完整历史或有商品市场的**竞争均衡**配置之间存在联系。 + +```{note} +关于两个福利定理及其历史,请参见 。 +另外,关于经典宏观经济增长模型的应用,请参见{doc}`这篇关于规划问题的讲座 `和{doc}`这篇关于相关竞争均衡的讲座 ` +``` + +这种联系在我们的模型中也存在。 + +我们现在来简要说明。 + +在竞争均衡中,不存在独裁式地收集每个人的禀赋然后重新分配的社会规划者。 + +相反,存在一个在某个时间点举行的全面的集中市场。 + +有**价格**,价格接受者可以按这些价格买卖他们想要的任何商品。 + +贸易是多边的,因为存在一个生活在模型之外的"瓦尔拉斯拍卖师",其工作是验证 + +每个个体的预算约束都得到满足。 + +这个预算约束涉及个体的禀赋流总值和消费流总值。 + +这些价值是根据个体视为既定的价格向量计算的——他们是"价格接受者",假定他们可以按这些价格买入或卖出任何数量。 + +假设在时间$-1$(即时间$0$开始之前),个体$i$可以以价格$p_t(s^t)$购买一单位在历史$s^t$后时间$t$的消费$c_t(s^t)$。 + +注意这是一个(很长的)价格**向量**。 + +* 对每个历史$s^t$和每个日期$t = 0, 1, \ldots, $都有一个价格$p_t(s^t)$。 +* 所以价格的数量与历史和日期的数量一样多。 + +这些价格在经济开始前的时间$-1$确定。 + +市场在时间$-1$只开放一次。 + +在时间$t =0, 1, 2, \ldots$执行在时间$-1$达成的交易。 + +* 在背景中,有一个"执行"程序强制个体履行他们在时间$-1$同意的交换或"交付"。 + +我们想研究个体的信念如何影响均衡价格。 + +个体$i$面临**单一**的跨期预算约束 + +$$ +\sum_{t=0}^\infty\sum_{s^t} p_t(s^t) c_t^i (s^t) \leq \sum_{t=0}^\infty\sum_{s^t} p_t(s^t) y_t^i (s^t) +$$ (eq:budgetI) + +根据预算约束{eq}`eq:budgetI`,交易在以下意义上是**多边的** + +* 我们可以想象个体 $i$ 首先出售他的随机禀赋流 $\{y_t^i (s^t)\}$,然后用所得收益(即他的"财富")购买随机消费流 $\{c_t^i (s^t)\}$。 + +个体 $i$ 在 {eq}`eq:budgetI` 上设置拉格朗日乘数 $\mu_i$,并一次性选择消费计划 $\{c^i_t(s^t)\}_{t=0}^\infty$ 以最大化目标函数 {eq}`eq:objectiveagenti`,同时受预算约束 {eq}`eq:budgetI` 的限制。 + +这意味着个体 $i$ 需要选择多个对象,即对于 $t = 0, 1, 2, \ldots$ 的所有 $s^t$ 的 $c_t^i(s^t)$。 + +为方便起见,让我们回顾一下在 {eq}`eq:objectiveagenti` 中定义的目标函数 $V^i$: + +$$ +V^i = \sum_{t=0}^{\infty} \sum_{s^t} \delta^t u(c_t^i(s^t)) \pi_t^i(s^t) +$$ + +最大化目标函数 $V^i$(在 {eq}`eq:objectiveagenti` 中定义)关于 $c_t^i(s^t)$ 的一阶必要条件是: + +$$ +\delta^t u'(c^i_t(s^t)) \pi_t^i(s^t) = \mu_i p_t(s^t) , +$$ + +我们可以重新整理得到: + +$$ +p_t(s^t) = \frac{ \delta^t \pi_t^i(s^t)}{\mu_i c^i_t(s^t)} +$$ (eq:priceequation1) + +对于 $i=1,2$。 + +如果我们将个体1的方程 {eq}`eq:priceequation1` 除以个体2的相应方程,使用 $c^2_t(s^t) = 1 - c^1_t(s^t)$,并进行一些代数运算,我们将得到: + +$$ +c_t^1(s^t) = \frac{\mu_1 l_t(s^t)}{\mu_2 + \mu_1 l_t(s^t)} . +$$ (eq:allocationce) + +我们现在进行一个扩展的"猜测和验证"练习,涉及将我们的竞争均衡中的对象与社会规划问题中的对象进行匹配。 + +* 我们将规划问题中的消费分配与竞争均衡中的均衡消费分配相匹配 +* 我们将规划问题中的"影子"价格与竞争均衡价格相匹配 + +注意,如果我们设定$\mu_1 = 1-\lambda$且$\mu_2 = \lambda$,那么公式{eq}`eq:allocationce`就与公式{eq}`eq:allocationrule1`一致。 + + * 这相当于为价格系统$\{p_t(s^t)\}_{t=0}^\infty$选择一个**计价单位**或标准化 + +```{note} +关于在像我们这样只决定相对价格的模型中,如何选择计价单位来确定绝对价格水平的信息,请参见。 +``` + +如果我们将公式{eq}`eq:allocationce`代入公式{eq}`eq:priceequation1`中的$c_t^1(s^t)$并重新整理,我们得到 + +$$ +p_t(s^t) = \frac{\delta^t}{\lambda(1-\lambda)} \pi_t^2(s^t) \bigl[1 - \lambda + \lambda l_t(s^t)\bigr] +$$ + +或 + +$$ +p_t(s^t) = \frac{\delta^t}{\lambda(1-\lambda)} \bigl[(1 - \lambda) \pi_t^2(s^t) + \lambda \pi_t^1(s^t)\bigr] +$$ (eq:pformulafinal) + +根据公式{eq}`eq:pformulafinal`,我们有以下可能的极限情况: + +* 当 $l_\infty = 0$ 时,$c_\infty^1 = 0$,竞争均衡价格的尾部反映了个体 $2$ 的概率模型 $\pi_t^2(s^t)$,即 $p_t(s^t) \propto \delta^t \pi_t^2(s^t)$ +* 当 $l_\infty = \infty$ 时,$c_\infty^1 = 1$,竞争均衡价格的尾部反映了个体 $1$ 的概率模型 $\pi_t^1(s^t)$,即 $p_t(s^t) \propto \delta^t \pi_t^1(s^t)$ +* 对于较小的 $t$,竞争均衡价格反映了两个个体的概率模型。 + +我们将影子价格的验证留给读者,因为它遵循相同的推理过程。 + +## 模拟 + +现在让我们实现一些模拟,其中个体 $1$ 相信边际密度 + +$$\pi^1(s_t) = f(s_t)$$ + +而个体 $2$ 相信边际密度 + +$$\pi^2(s_t) = g(s_t)$$ + +这里 $f$ 和 $g$ 是 Beta 分布,类似于我们在本讲座前面章节中使用的分布。 + +同时,我们假设自然界相信边际密度 + +$$ +\pi(s_t) = h(s_t) +$$ + +其中 $h(s_t)$ 可能是 $f$ 和 $g$ 的混合。 + +首先,我们编写一个函数来计算似然比过程 + +```{code-cell} ipython3 +def compute_likelihood_ratios(sequences, f, g): + """计算似然比和累积乘积。""" + l_ratios = f(sequences) / g(sequences) + L_cumulative = np.cumprod(l_ratios, axis=1) + return l_ratios, L_cumulative +``` + +让我们通过求积分计算Kullback-Leibler差异。 + +```{code-cell} ipython3 +def compute_KL(f, g): + """ + 计算KL散度 KL(f, g) + """ + integrand = lambda w: f(w) * np.log(f(w) / g(w)) + val, _ = quad(integrand, 1e-5, 1-1e-5) + return val +``` + +我们还创建一个辅助函数来计算相对于参考分布$h$的KL散度 + +```{code-cell} ipython3 +def compute_KL_h(h, f, g): + """ + 计算相对于参考分布h的KL散度 + """ + + Kf = compute_KL(h, f) + Kg = compute_KL(h, g) + + return Kf, Kg +``` + +让我们编写一个Python函数来计算个体1的消费份额 + +```{code-cell} ipython3 +def simulate_blume_easley(sequences, f_belief=f, g_belief=g, λ=0.5): + """模拟Blume-Easley模型的消费份额。""" + l_ratios, l_cumulative = compute_likelihood_ratios(sequences, f_belief, g_belief) + c1_share = λ * l_cumulative / (1 - λ + λ * l_cumulative) + return l_cumulative, c1_share +``` + +现在让我们使用这个函数来生成以下序列: + +* 每期自然从 $f$ 中抽取,或者 +* 每期自然从 $g$ 中抽取,或者 +* 每期自然抛一枚公平硬币来决定是从 $f$ 还是从 $g$ 中抽取 + +```{code-cell} ipython3 +λ = 0.5 +T = 100 +N = 10000 + +# 自然遵循 f、g 或混合 +s_seq_f = np.random.beta(F_a, F_b, (N, T)) +s_seq_g = np.random.beta(G_a, G_b, (N, T)) + +h = jit(lambda x: 0.5 * f(x) + 0.5 * g(x)) +model_choices = np.random.rand(N, T) < 0.5 +s_seq_h = np.empty((N, T)) +s_seq_h[model_choices] = np.random.beta(F_a, F_b, size=model_choices.sum()) +s_seq_h[~model_choices] = np.random.beta(G_a, G_b, size=(~model_choices).sum()) + +l_cum_f, c1_f = simulate_blume_easley(s_seq_f) +l_cum_g, c1_g = simulate_blume_easley(s_seq_g) +l_cum_h, c1_h = simulate_blume_easley(s_seq_h) +``` + +在查看下图之前,让我们先来猜一猜,随着时间推移,在我们的三种情况下,个体1或个体2的消费份额会变得越来越大。 + +为了做出更好的猜测,让我们来可视化这三种情况下的似然比过程的实例。 + +```{code-cell} ipython3 +fig, axes = plt.subplots(2, 3, figsize=(15, 10)) + +titles = ["Nature = f", "Nature = g", "Nature = mixture"] +data_pairs = [(l_cum_f, c1_f), (l_cum_g, c1_g), (l_cum_h, c1_h)] + +for i, ((l_cum, c1), title) in enumerate(zip(data_pairs, titles)): + # 似然比 + ax = axes[0, i] + for j in range(min(50, l_cum.shape[0])): + ax.plot(l_cum[j, :], alpha=0.3, color='blue') + ax.set_yscale('log') + ax.set_xlabel('时间') + ax.set_ylabel('似然比 $l_t$') + ax.set_title(title) + ax.axhline(y=1, color='red', linestyle='--', alpha=0.5) + + # 消费份额 + ax = axes[1, i] + for j in range(min(50, c1.shape[0])): + ax.plot(c1[j, :], alpha=0.3, color='green') + ax.set_xlabel('时间') + ax.set_ylabel("个体1的消费份额") + ax.set_ylim([0, 1]) + ax.axhline(y=λ, color='red', linestyle='--', alpha=0.5) + +plt.tight_layout() +plt.show() +``` + +在左侧面板中,自然选择$f$。个体1的消费很快达到$1$。 + +在中间面板中,自然选择$g$。个体1的消费比率趋向于$0$,但速度不如第一种情况快。 + +在右侧面板中,自然每期抛硬币。我们看到与左侧面板中的过程非常相似的模式。 + +顶部面板的图形让我们想起[本节](KL_link)中的讨论。 + +我们邀请读者重新访问[该节](llr_h)并尝试推断$D_{KL}(f\|g)$、$D_{KL}(g\|f)$、$D_{KL}(h\|f)$和$D_{KL}(h\|g)$之间的关系。 + +让我们计算KL散度的值 + +```{code-cell} ipython3 +shares = [np.mean(c1_f[:, -1]), np.mean(c1_g[:, -1]), np.mean(c1_h[:, -1])] +Kf_g, Kg_f = compute_KL(f, g), compute_KL(g, f) +Kf_h, Kg_h = compute_KL_h(h, f, g) + +print(f"Final shares: f={shares[0]:.3f}, g={shares[1]:.3f}, mix={shares[2]:.3f}") +print(f"KL divergences: \nKL(f,g)={Kf_g:.3f}, KL(g,f)={Kg_f:.3f}") +print(f"KL(h,f)={Kf_h:.3f}, KL(h,g)={Kg_h:.3f}") +``` + +我们发现 $KL(f,g) > KL(g,f)$ 且 $KL(h,g) > KL(h,f)$。 + +第一个不等式告诉我们,当自然选择 $f$ 而信念为 $g$ 时的平均"惊讶度"大于当自然选择 $g$ 而信念为 $f$ 时的"惊讶度"。 + +这解释了我们在上面注意到的前两个面板之间的差异。 + +第二个不等式告诉我们,个体1的信念分布 $f$ 比个体2的信念 $g$ 更接近自然的选择。 + ++++ + +为了使这个想法更具体,让我们比较两种情况: + +- 个体1的信念分布 $f$ 接近个体2的信念分布 $g$; +- 个体1的信念分布 $f$ 远离个体2的信念分布 $g$。 + +我们使用下面可视化的两个分布 + +```{code-cell} ipython3 +def plot_distribution_overlap(ax, x_range, f_vals, g_vals, + f_label='f', g_label='g', + f_color='blue', g_color='red'): + """Plot two distributions with their overlap region.""" + ax.plot(x_range, f_vals, color=f_color, linewidth=2, label=f_label) + ax.plot(x_range, g_vals, color=g_color, linewidth=2, label=g_label) + + overlap = np.minimum(f_vals, g_vals) + ax.fill_between(x_range, 0, overlap, alpha=0.3, color='purple', label='Overlap') + ax.set_xlabel('x') + ax.set_ylabel('Density') + ax.legend() + +# Define close and far belief distributions +f_close = jit(lambda x: p(x, 1, 1)) +g_close = jit(lambda x: p(x, 1.1, 1.05)) + +f_far = jit(lambda x: p(x, 1, 1)) +g_far = jit(lambda x: p(x, 3, 1.2)) + +# Visualize the belief distributions +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) + +x_range = np.linspace(0.001, 0.999, 200) + +# Close beliefs +f_close_vals = [f_close(x) for x in x_range] +g_close_vals = [g_close(x) for x in x_range] +plot_distribution_overlap(ax1, x_range, f_close_vals, g_close_vals, + f_label='f (Beta(1, 1))', g_label='g (Beta(1.1, 1.05))') +ax1.set_title(f'Close Beliefs') + +# Far beliefs +f_far_vals = [f_far(x) for x in x_range] +g_far_vals = [g_far(x) for x in x_range] +plot_distribution_overlap(ax2, x_range, f_far_vals, g_far_vals, + f_label='f (Beta(1, 1))', g_label='g (Beta(3, 1.2))') +ax2.set_title(f'Far Beliefs') + +plt.tight_layout() +plt.show() +``` + +让我们绘制与上面相同的代理1的消费比例图。 + +我们用中位数和百分位数替代模拟路径,使图形更清晰。 + +观察下面的图形,我们能推断出$KL(f,g)$和$KL(g,f)$之间的关系吗? + +从右侧面板,我们能推断出$KL(h,g)$和$KL(h,f)$之间的关系吗? + +```{code-cell} ipython3 +fig, axes = plt.subplots(2, 3, figsize=(15, 10)) +nature_params = {'close': [(1, 1), (1.1, 1.05), (2, 1.5)], + 'far': [(1, 1), (3, 1.2), (2, 1.5)]} +nature_labels = ["Nature = f", "Nature = g", "Nature = h"] +colors = {'close': 'blue', 'far': 'red'} + +threshold = 1e-5 # "接近零"的截断值 + +for row, (f_belief, g_belief, label) in enumerate([ + (f_close, g_close, 'close'), + (f_far, g_far, 'far')]): + + for col, nature_label in enumerate(nature_labels): + params = nature_params[label][col] + s_seq = np.random.beta(params[0], params[1], (1000, 200)) + _, c1 = simulate_blume_easley(s_seq, f_belief, g_belief, λ) + + median_c1 = np.median(c1, axis=0) + p10, p90 = np.percentile(c1, [10, 90], axis=0) + + ax = axes[row, col] + color = colors[label] + ax.plot(median_c1, color=color, linewidth=2, label='中位数') + ax.fill_between(range(len(median_c1)), p10, p90, alpha=0.3, color=color, label='10-90%') + ax.set_xlabel('时间') + ax.set_ylabel("代理1的份额") + ax.set_ylim([0, 1]) + ax.set_title(nature_label) + ax.axhline(y=λ, color='gray', linestyle='--', alpha=0.5) + below = np.where(median_c1 < threshold)[0] + above = np.where(median_c1 > 1-threshold)[0] + if below.size > 0: first_zero = (below[0], True) + elif above.size > 0: first_zero = (above[0], False) + else: first_zero = None + if first_zero is not None: + ax.axvline(x=first_zero[0], color='black', linestyle='--', + alpha=0.7, + label=fr'中位数 $\leq$ {threshold}' if first_zero[1] + else fr'中位数 $\geq$ 1-{threshold}') + ax.legend() + +plt.tight_layout() +plt.show() +``` + +让我们按照我们的猜测来计算这四个值 + +```{code-cell} ipython3 +# 近距离情况 +Kf_g, Kg_f = compute_KL(f_close, g_close), compute_KL(g_close, f_close) +Kf_h, Kg_h = compute_KL_h(h, f_close, g_close) + +print(f"KL散度(近距离):\nKL(f,g)={Kf_g:.3f}, KL(g,f)={Kg_f:.3f}") +print(f"KL(h,f)={Kf_h:.3f}, KL(h,g)={Kg_h:.3f}") + +# 远距离情况 +Kf_g, Kg_f = compute_KL(f_far, g_far), compute_KL(g_far, f_far) +Kf_h, Kg_h = compute_KL_h(h, f_far, g_far) + +print(f"KL散度(远距离):\nKL(f,g)={Kf_g:.3f}, KL(g,f)={Kg_f:.3f}") +print(f"KL(h,f)={Kf_h:.3f}, KL(h,g)={Kg_h:.3f}") +``` + +我们发现在第一种情况下,$KL(f,g) \approx KL(g,f)$ 且两者都相对较小,所以尽管个体1或个体2最终会消耗所有资源,但在顶部前两个面板中显示的收敛是相当缓慢的。 + +在底部的前两个面板中,我们看到收敛发生得更快(如黑色虚线所示),这是因为差异度 $KL(f, g)$ 和 $KL(g, f)$ 更大。 + +由于 $KL(f,g) > KL(g,f)$,我们看到当自然选择 $f$ 时,底部第一个面板的收敛比自然选择 $g$ 时的第二个面板更快。 + +这与{eq}`eq:kl_likelihood_link`很好地联系在一起。 + + + +## 相关讲座 + +具有同质信念的完全市场模型,这种模型在宏观经济学和金融学中经常使用,在这个quantecon讲座{doc}`ge_arrow`中有研究。 + +{cite}`blume2018case`讨论了反对完全市场的家长式论点。他们的分析假设社会规划者应该忽视个人偏好,即应该忽视其偏好中的主观信念成分。 + +似然过程在贝叶斯学习中扮演重要角色,这在{doc}`likelihood_bayes`中有描述,并在{doc}`odu`中有应用。 + +似然比过程在{doc}`advanced:additive_functionals`中再次出现。 + + + +## 练习 + +```{exercise} +:label: lr_ex3 + +从{eq}`eq:priceequation1`开始,证明竞争均衡价格可以表示为 + +$$ + +p_t(s^t) = \frac{\delta^t}{\lambda(1-\lambda)} \pi_t^2(s^t) \bigl[1 - \lambda + \lambda l_t(s^t)\bigr] +$$ + +``` + +```{solution-start} lr_ex3 +:class: dropdown +``` + +从以下式子开始 + +$$ +p_t(s^t) = \frac{\delta^t \pi_t^i(s^t)}{\mu_i c_t^i(s^t)}, \qquad i=1,2. +$$ + +由于两个表达式等于相同的价格,我们可以令它们相等 + +$$ +\frac{\pi_t^1(s^t)}{\mu_1 c_t^1(s^t)} = \frac{\pi_t^2(s^t)}{\mu_2 c_t^2(s^t)} +$$ + +重新整理得到 + +$$ +\frac{c_t^1(s^t)}{c_t^2(s^t)} = \frac{\mu_2}{\mu_1} l_t(s^t) +$$ + +其中 $l_t(s^t) \equiv \pi_t^1(s^t)/\pi_t^2(s^t)$ 是似然比过程。 + +使用 $c_t^2(s^t) = 1 - c_t^1(s^t)$: + +$$ +\frac{c_t^1(s^t)}{1 - c_t^1(s^t)} = \frac{\mu_2}{\mu_1} l_t(s^t) +$$ + +求解 $c_t^1(s^t)$ + +$$ +c_t^1(s^t) = \frac{\mu_2 l_t(s^t)}{\mu_1 + \mu_2 l_t(s^t)} +$$ + +规划者的解给出 + +$$ +c_t^1(s^t) = \frac{\lambda l_t(s^t)}{1 - \lambda + \lambda l_t(s^t)} +$$ + +为了使个体1在竞争均衡中的选择与规划者为个体1做出的选择相匹配,必须满足以下等式 + +$$ +\frac{\mu_2}{\mu_1} = \frac{\lambda}{1 - \lambda} +$$ + +因此我们有 + +$$ +\mu_1 = 1 - \lambda, \qquad \mu_2 = \lambda +$$ + +当 $\mu_1 = 1-\lambda$ 且 $c_t^1(s^t) = \frac{\lambda l_t(s^t)}{1-\lambda+\lambda l_t(s^t)}$ 时, +我们有 + +$$ +\begin{aligned} +p_t(s^t) &= \frac{\delta^t \pi_t^1(s^t)}{(1-\lambda) c_t^1(s^t)} \\ +&= \frac{\delta^t \pi_t^1(s^t)}{(1-\lambda)} \cdot \frac{1 - \lambda + \lambda l_t(s^t)}{\lambda l_t(s^t)} \\ + +&= \frac{\delta^t \pi_t^1(s^t)}{(1-\lambda)\lambda l_t(s^t)} \bigl[1 - \lambda + \lambda l_t(s^t)\bigr]. +\end{aligned} +$$ + +由于 $\pi_t^1(s^t) = l_t(s^t) \pi_t^2(s^t)$,我们有 + +$$ +\begin{aligned} +p_t(s^t) &= \frac{\delta^t l_t(s^t) \pi_t^2(s^t)}{(1-\lambda)\lambda l_t(s^t)} \bigl[1 - \lambda + \lambda l_t(s^t)\bigr] \\ +&= \frac{\delta^t \pi_t^2(s^t)}{(1-\lambda)\lambda} \bigl[1 - \lambda + \lambda l_t(s^t)\bigr] \\ +&= \frac{\delta^t}{\lambda(1-\lambda)} \pi_t^2(s^t) \bigl[1 - \lambda + \lambda l_t(s^t)\bigr]. +\end{aligned} +$$ + +```{solution-end} +``` + +```{exercise} +:label: lr_ex4 + +在这个练习中,我们将研究两个主体,每个主体在数据到达时都会更新其后验概率。 + +* 每个主体都按照{doc}`likelihood_bayes`中研究的方式应用贝叶斯法则。 + +以下是两个待考虑的模型 + +$$ +f(s^t) = f(s_1) f(s_2) \cdots f(s_t) +$$ + +和 + +$$ +g(s^t) = g(s_1) g(s_2) \cdots g(s_t) +$$ + +以及相关的似然比过程 + +$$ +L(s^t) = \frac{f(s^t)}{g(s^t)} . +$$ + +令 $\pi_0 \in (0,1)$ 为先验概率,且 + +$$ +\pi_t = \frac{ \pi_0 L(s^t)}{ \pi_0 L(s^t) + (1-\pi_0) } . +$$ + +我们的两个主体各自使用混合模型的自己的版本 + +$$ +m(s^t) = \pi_t f(s^t) + (1- \pi_t) g(s^t) +$$ (eq:be_mix_model) + +我们将为每种类型的消费者配备模型{eq}`eq:be_mix_model`。 + +* 两个主体共享相同的 $f$ 和 $g$,但是 +* 他们有不同的初始先验概率,即 $\pi_0^1$ 和 $\pi_0^2$ + +因此,消费者 $i$ 的概率模型是 + +$$ + +m^i(s^t) = \pi^i_t f(s^t) + (1- \pi^i_t) g(s^t) +$$ (eq:prob_model) + +现在我们将概率模型{eq}`eq:prob_model`(其中i=1,2)交给社会规划者。 + +我们想要推导分配$c^i(s^t), i = 1,2$,并观察当以下情况发生时会发生什么: + + * 自然的模型是$f$ + * 自然的模型是$g$ + +我们预期消费者最终会学习到"真相",但其中一个人会学习得更快。 + +为了探索这些问题,请设定$f \sim \text{Beta}(1.5, 1)$和$g \sim \text{Beta}(1, 1.5)$。 + +请编写Python代码回答以下问题: + + * 消费份额如何演变? + * 当自然遵循$f$时,哪个代理学习得更快? + * 当自然遵循$g$时,哪个代理学习得更快? + * 初始先验$\pi_0^1$和$\pi_0^2$的差异如何影响收敛速度? +``` + +```{solution-start} lr_ex4 +:class: dropdown +``` + +首先,让我们编写辅助函数来计算模型组件,包括每个代理的主观信念函数。 + +```{code-cell} ipython3 +def bayesian_update(π_0, L_t): + """ + 给定似然比的贝叶斯信念概率更新。 + """ + return (π_0 * L_t) / (π_0 * L_t + (1 - π_0)) + +def mixture_density_belief(s_seq, f_func, g_func, π_seq): + """ + 计算代理i的混合密度信念m^i(s^t)。 + """ + f_vals = f_func(s_seq) + g_vals = g_func(s_seq) + return π_seq * f_vals + (1 - π_seq) * g_vals +``` + +现在让我们编写代码来模拟包含两个个体的Blume-Easley模型。 + +```{code-cell} ipython3 +def simulate_learning_blume_easley(sequences, f_belief, g_belief, + π_0_1, π_0_2, λ=0.5): + """ + 模拟包含学习个体的Blume-Easley模型。 + """ + N, T = sequences.shape + + # 初始化存储结果的数组 + π_1_seq = np.full((N, T), np.nan) + π_2_seq = np.full((N, T), np.nan) + c1_share = np.full((N, T), np.nan) + l_agents_seq = np.full((N, T), np.nan) + + π_1_seq[:, 0] = π_0_1 + π_2_seq[:, 0] = π_0_2 + + for n in range(N): + # 初始化信念的累积似然比 + L_cumul = 1.0 + + # 初始化个体密度之间的似然比 + l_agents_cumul = 1.0 + + for t in range(1, T): + s_t = sequences[n, t] + + # 计算此观测的似然比 + l_t = f_belief(s_t) / g_belief(s_t) + + # 更新累积似然比 + L_cumul *= l_t + + # 贝叶斯更新信念 + π_1_t = bayesian_update(π_0_1, L_cumul) + π_2_t = bayesian_update(π_0_2, L_cumul) + + # 存储信念 + π_1_seq[n, t] = π_1_t + π_2_seq[n, t] = π_2_t + + # 计算每个个体的混合密度 + m1_t = π_1_t * f_belief(s_t) + (1 - π_1_t) * g_belief(s_t) + m2_t = π_2_t * f_belief(s_t) + (1 - π_2_t) * g_belief(s_t) + + # 更新个体之间的累积似然比 + l_agents_cumul *= (m1_t / m2_t) + l_agents_seq[n, t] = l_agents_cumul + + # c_t^1(s^t) = λ * l_t(s^t) / (1 - λ + λ * l_t(s^t)) + # 其中l_t(s^t)是个体之间的累积似然比 + c1_share[n, t] = λ * l_agents_cumul / (1 - λ + λ * l_agents_cumul) + + return { + 'π_1': π_1_seq, + 'π_2': π_2_seq, + 'c1_share': c1_share, + 'l_agents': l_agents_seq + } +``` + +让我们运行不同场景的模拟。 + +我们使用 $\lambda = 0.5$,$T=40$,以及 $N=1000$。 + +```{code-cell} ipython3 +λ = 0.5 +T = 40 +N = 1000 + +F_a, F_b = 1.5, 1 +G_a, G_b = 1, 1.5 + +f = jit(lambda x: p(x, F_a, F_b)) +g = jit(lambda x: p(x, G_a, G_b)) +``` + +我们将从不同的初始先验概率 $\pi^i_0 \in (0, 1)$ 开始,并扩大它们之间的差距。 + +```{code-cell} ipython3 +# 不同的初始先验概率 +π_0_scenarios = [ + (0.3, 0.7), + (0.7, 0.3), + (0.1, 0.9), +] +``` + +现在我们可以为不同场景运行模拟 + +```{code-cell} ipython3 +# 自然遵循 f +s_seq_f = np.random.beta(F_a, F_b, (N, T)) + +# 自然遵循 g +s_seq_g = np.random.beta(G_a, G_b, (N, T)) + +results_f = {} +results_g = {} + +for i, (π_0_1, π_0_2) in enumerate(π_0_scenarios): + # 当自然遵循 f 时 + results_f[i] = simulate_learning_blume_easley( + s_seq_f, f, g, π_0_1, π_0_2, λ) + # 当自然遵循 g 时 + results_g[i] = simulate_learning_blume_easley( + s_seq_g, f, g, π_0_1, π_0_2, λ) +``` + +让我们可视化结果 + +```{code-cell} ipython3 +def plot_learning_results(results, π_0_scenarios, nature_type, truth_value): + """ + 绘制学习智能体的信念和消费份额。 + """ + + fig, axes = plt.subplots(3, 2, figsize=(10, 15)) + + scenario_labels = [ + rf'$\pi_0^1 = {π_0_1}, \pi_0^2 = {π_0_2}$' + for π_0_1, π_0_2 in π_0_scenarios + ] + + for row, (scenario_idx, scenario_label) in enumerate( + zip(range(3), scenario_labels)): + + res = results[scenario_idx] + + # 绘制信念 + ax = axes[row, 0] + π_1_med = np.median(res['π_1'], axis=0) + π_2_med = np.median(res['π_2'], axis=0) + ax.plot(π_1_med, 'C0', label=r'智能体1', linewidth=2) + ax.plot(π_2_med, 'C1', label=r'智能体2', linewidth=2) + ax.axhline(y=truth_value, color='gray', linestyle='--', + alpha=0.5, label=f'真值({nature_type})') + ax.set_title(f'当自然状态 = {nature_type}时的信念\n{scenario_label}') + ax.set_ylabel(r'中位数 $\pi_i^t$') + ax.set_ylim([-0.05, 1.05]) + ax.legend() + + # 绘制消费份额 + ax = axes[row, 1] + c1_med = np.median(res['c1_share'], axis=0) + ax.plot(c1_med, 'g-', linewidth=2, label='中位数') + ax.axhline(y=0.5, color='gray', linestyle='--', + alpha=0.5) + ax.set_title(f'智能体1的消费份额(自然状态 = {nature_type})') + ax.set_ylabel('消费份额') + ax.set_ylim([0, 1]) + ax.legend() + + # 添加x轴标签 + for col in range(2): + axes[row, col].set_xlabel('$t$') + + plt.tight_layout() + return fig, axes +``` + +现在我们将绘制当自然遵循 f 时的结果: + +```{code-cell} ipython3 +fig_f, axes_f = plot_learning_results( + results_f, π_0_scenarios, 'f', 1.0) +plt.show() +``` + +我们可以看到,具有更准确信念的个体获得更高的消费份额。 + +此外,初始信念差异越大,消费比率收敛所需的时间就越长。 + +"不太准确"的个体学习时间越长,其最终消费份额就越低。 + +现在让我们绘制当自然遵循g时的结果: + +```{code-cell} ipython3 +fig_g, axes_g = plot_learning_results(results_g, π_0_scenarios, 'g', 0.0) +plt.show() +``` + +我们观察到对称的结果。 + +```{solution-end} +``` + +```{exercise} +:label: lr_ex5 + +在前面的练习中,我们故意将两个 beta 分布设置得相对接近。 + +这使得区分这些分布变得具有挑战性。 + +现在让我们研究当这些分布相距更远时的结果。 + +让我们设置 $f \sim \text{Beta}(2, 5)$ 和 $g \sim \text{Beta}(5, 2)$。 + +请使用你已经编写的 Python 代码来研究结果。 +``` + +```{solution-start} lr_ex5 +:class: dropdown +``` + +这是一个解决方案 + +```{code-cell} ipython3 +λ = 0.5 +T = 40 +N = 1000 + +F_a, F_b = 2, 5 +G_a, G_b = 5, 2 + +f = jit(lambda x: p(x, F_a, F_b)) +g = jit(lambda x: p(x, G_a, G_b)) + +π_0_scenarios = [ + (0.3, 0.7), + (0.7, 0.3), + (0.1, 0.9), +] + +s_seq_f = np.random.beta(F_a, F_b, (N, T)) +s_seq_g = np.random.beta(G_a, G_b, (N, T)) + +results_f = {} +results_g = {} + +for i, (π_0_1, π_0_2) in enumerate(π_0_scenarios): + # 当自然遵循 f 时 + results_f[i] = simulate_learning_blume_easley( + s_seq_f, f, g, π_0_1, π_0_2, λ) + # 当自然遵循 g 时 + results_g[i] = simulate_learning_blume_easley( + s_seq_g, f, g, π_0_1, π_0_2, λ) +``` + +现在让我们将结果可视化 + +```{code-cell} ipython3 +fig_f, axes_f = plot_learning_results(results_f, π_0_scenarios, 'f', 1.0) +plt.show() +``` + +```{code-cell} ipython3 +fig_g, axes_g = plot_learning_results(results_g, π_0_scenarios, 'g', 0.0) +plt.show() +``` + +显然,由于两个分布之间的距离更远,更容易区分它们。 + +因此学习发生得更快。 + +消费份额也是如此。 + +```{solution-end} +``` + +```{exercise} +:label: lr_ex6 + +两个代理对三个可能的模型有不同的信念。 + +假设对于 $x \in X$,$f(x) \geq 0$,$g(x) \geq 0$,且 $h(x) \geq 0$,并且: +- $\int_X f(x) dx = 1$ +- $\int_X g(x) dx = 1$ +- $\int_X h(x) dx = 1$ + +我们将考虑两个代理: +* 代理1:$\pi^g_0 = 1 - \pi^f_0$,$\pi^f_0 \in (0,1)$,$\pi^h_0 = 0$ +(仅对模型 $f$ 和 $g$ 赋予正概率) +* 代理2:$\pi^g_0 = \pi^f_0 = 1/3$,$\pi^h_0 = 1/3$ +(对所有三个模型赋予相等权重) + +令 $f$ 和 $g$ 为两个贝塔分布,其中 $f \sim \text{Beta}(3, 2)$ 且 +$g \sim \text{Beta}(2, 3)$,并且 +设 $h = \pi^f_0 f + (1-\pi^f_0) g$,其中 $\pi^f_0 = 0.5$。 + +贝叶斯法则告诉我们,模型 $f$ 和 $g$ 的后验概率按如下方式演变: + +$$ +\pi^f(s^t) := \frac{\pi^f_0 f(s^t)}{\pi^f_0 f(s^t) ++ \pi^g_0 g(s^t) + (1 - \pi^f_0 - \pi^g_0) h(s^t)} +$$ + +和 + +$$ +\pi^g(s^t) := \frac{\pi^g_0 g(s^t)}{\pi^f_0 f(s^t) ++ \pi^g_0 g(s^t) + (1 - \pi^f_0 - \pi^g_0) h(s^t)} +$$ + +请模拟并可视化以下情况下的后验概率和消费分配的演变: + +* 自然永久从 $f$ 中抽取 +* 自然永久从 $g$ 中抽取 +``` + +```{solution-start} lr_ex6 +:class: dropdown +``` + +让我们实现这个具有两个代理的三模型案例。 + +让我们定义相距较远的函数$f$和$g$,并让$h$作为$f$和$g$的混合。 + +```{code-cell} ipython3 +F_a, F_b = 3, 2 +G_a, G_b = 2, 3 +λ = 0.5 +π_f_0 = 0.5 + +f = jit(lambda x: p(x, F_a, F_b)) +g = jit(lambda x: p(x, G_a, G_b)) +h = jit(lambda x: π_f_0 * f(x) + (1 - π_f_0) * g(x)) +``` + +现在我们可以为模型定义信念更新 + +```{code-cell} ipython3 +@jit(parallel=True) +def compute_posterior_three_models( + s_seq, f_func, g_func, h_func, π_f_0, π_g_0): + """ + 计算三个模型的后验概率。 + """ + N, T = s_seq.shape + π_h_0 = 1 - π_f_0 - π_g_0 + + π_f = np.zeros((N, T)) + π_g = np.zeros((N, T)) + π_h = np.zeros((N, T)) + + for n in prange(N): + # 用先验概率初始化 + π_f[n, 0] = π_f_0 + π_g[n, 0] = π_g_0 + π_h[n, 0] = π_h_0 + + # 计算累积似然 + f_cumul = 1.0 + g_cumul = 1.0 + h_cumul = 1.0 + + for t in range(1, T): + s_t = s_seq[n, t] + + # 更新累积似然 + f_cumul *= f_func(s_t) + g_cumul *= g_func(s_t) + h_cumul *= h_func(s_t) + + # 使用贝叶斯法则计算后验概率 + denominator = π_f_0 * f_cumul + π_g_0 * g_cumul + π_h_0 * h_cumul + + π_f[n, t] = π_f_0 * f_cumul / denominator + π_g[n, t] = π_g_0 * g_cumul / denominator + π_h[n, t] = π_h_0 * h_cumul / denominator + + return π_f, π_g, π_h +``` + +让我们也写一些类似之前练习的模拟代码 + +```{code-cell} ipython3 +@jit +def bayesian_update_three_models(π_f_0, π_g_0, L_f, L_g, L_h): + """三个模型的贝叶斯更新。""" + π_h_0 = 1 - π_f_0 - π_g_0 + denom = π_f_0 * L_f + π_g_0 * L_g + π_h_0 * L_h + return π_f_0 * L_f / denom, π_g_0 * L_g / denom, π_h_0 * L_h / denom + +@jit +def compute_mixture_density(π_f, π_g, π_h, f_val, g_val, h_val): + """计算代理的混合密度。""" + return π_f * f_val + π_g * g_val + π_h * h_val + +@jit(parallel=True) +def simulate_three_model_allocation(sequences, f_func, g_func, h_func, + π_f_0_1, π_g_0_1, π_f_0_2, π_g_0_2, λ=0.5): + """ + 模拟具有学习代理和三个模型的Blume-Easley模型。 + """ + N, T = sequences.shape + + # 初始化数组以存储结果 + beliefs_1 = {k: np.full((N, T), np.nan) for k in ['π_f', 'π_g', 'π_h']} + beliefs_2 = {k: np.full((N, T), np.nan) for k in ['π_f', 'π_g', 'π_h']} + c1_share = np.full((N, T), np.nan) + l_agents_seq = np.full((N, T), np.nan) + + # 设置初始信念 + beliefs_1['π_f'][:, 0] = π_f_0_1 + beliefs_1['π_g'][:, 0] = π_g_0_1 + beliefs_1['π_h'][:, 0] = 1 - π_f_0_1 - π_g_0_1 + beliefs_2['π_f'][:, 0] = π_f_0_2 + beliefs_2['π_g'][:, 0] = π_g_0_2 + beliefs_2['π_h'][:, 0] = 1 - π_f_0_2 - π_g_0_2 + + for n in range(N): + # 初始化累积似然 + L_cumul = {'f': 1.0, 'g': 1.0, 'h': 1.0} + l_agents_cumul = 1.0 + + # 计算t=0时的初始消费份额 + l_agents_seq[n, 0] = 1.0 + c1_share[n, 0] = λ * 1.0 / (1 - λ + λ * 1.0) # 等于λ + + for t in range(1, T): + s_t = sequences[n, t] + + # 计算当前观察的密度 + densities = { + 'f': f_func(s_t), + 'g': g_func(s_t), + 'h': h_func(s_t) + } + + # 更新累积似然 + for model in L_cumul: + L_cumul[model] *= densities[model] + + # 两个代理的贝叶斯更新 + π_f_1, π_g_1, π_h_1 = bayesian_update_three_models( + π_f_0_1, π_g_0_1, L_cumul['f'], L_cumul['g'], L_cumul['h']) + π_f_2, π_g_2, π_h_2 = bayesian_update_three_models( + π_f_0_2, π_g_0_2, L_cumul['f'], L_cumul['g'], L_cumul['h']) + + # 存储信念 + beliefs_1['π_f'][n, t] = π_f_1 + beliefs_1['π_g'][n, t] = π_g_1 + beliefs_1['π_h'][n, t] = π_h_1 + beliefs_2['π_f'][n, t] = π_f_2 + beliefs_2['π_g'][n, t] = π_g_2 + beliefs_2['π_h'][n, t] = π_h_2 + + # 计算混合密度 + m1_t = compute_mixture_density( + π_f_1, π_g_1, π_h_1, densities['f'], + densities['g'], densities['h']) + m2_t = compute_mixture_density( + π_f_2, π_g_2, π_h_2, densities['f'], + densities['g'], densities['h']) + + # 更新代理之间的累积似然比 + l_agents_cumul *= (m1_t / m2_t) + l_agents_seq[n, t] = l_agents_cumul + + # 代理1的消费份额 + c1_share[n, t] = λ * l_agents_cumul / (1 - λ + λ * l_agents_cumul) + + return { + 'π_f_1': beliefs_1['π_f'], + 'π_g_1': beliefs_1['π_g'], + 'π_h_1': beliefs_1['π_h'], + 'π_f_2': beliefs_2['π_f'], + 'π_g_2': beliefs_2['π_g'], + 'π_h_2': beliefs_2['π_h'], + 'c1_share': c1_share, + 'l_agents': l_agents_seq + } +``` + +以下代码单元定义了一个绘图函数,用于显示信念和消费比例的演变 + +```{code-cell} ipython3 +:tags: [hide-input] + +def plot_belief_evolution(results, nature='f', figsize=(15, 5)): + """ + 创建显示三个模型(f, g, h)信念演变的图表。 + """ + fig, axes = plt.subplots(1, 3, figsize=figsize) + + model_names = ['f', 'g', 'h'] + belief_keys = [('π_f_1', 'π_f_2'), + ('π_g_1', 'π_g_2'), + ('π_h_1', 'π_h_2')] + + for j, (model_name, (key1, key2)) in enumerate( + zip(model_names, belief_keys)): + ax = axes[j] + + # 绘制个体信念 + ax.plot(np.median(results[key1], axis=0), 'C0-', + linewidth=2, label='个体1') + ax.plot(np.median(results[key2], axis=0), 'C1-', + linewidth=2, label='个体2') + + # 真实值指示器 + if model_name == nature: + ax.axhline(y=1.0, color='grey', linestyle='-.', + alpha=0.7, label='真实值') + else: + ax.axhline(y=0.0, color='grey', linestyle='-.', + alpha=0.7, label='真实值') + + ax.set_title(f'π({model_name}) 当自然状态 = {nature}') + ax.set_xlabel('$t$') + ax.set_ylabel(f'中位数 π({model_name})') + ax.set_ylim([-0.01, 1.01]) + ax.legend(loc='best') + + plt.tight_layout() + return fig, axes + + +def plot_consumption_dynamics(results_f, results_g, λ=0.5, figsize=(14, 5)): + """ + 创建显示个体1消费份额动态的图表。 + """ + fig, axes = plt.subplots(1, 2, figsize=figsize) + + results_list = [results_f, results_g] + nature_labels = ['f', 'g'] + colors = ['blue', 'green'] + + for i, (results, nature_label, color) in enumerate( + zip(results_list, nature_labels, colors)): + ax = axes[i] + c1 = results['c1_share'] + c1_med = np.median(c1, axis=0) + + # 绘制中位数和百分位数 + ax.plot(c1_med, color=color, linewidth=2, label="中位数") + + # 添加百分位区间带 + c1_25 = np.percentile(c1, 25, axis=0) + c1_75 = np.percentile(c1, 75, axis=0) + ax.fill_between(range(len(c1_med)), c1_25, c1_75, + color=color, alpha=0.2, label="25-75百分位") + + ax.axhline(y=0.5, color='grey', linestyle='--', + alpha=0.5, label='等份') + + ax.set_title(f'个体1消费份额(自然状态 = {nature_label})') + ax.set_xlabel('$t$') + ax.set_ylabel("消费份额") + ax.set_ylim([-0.02, 1.02]) + ax.legend(loc='best') + + plt.tight_layout() + return fig, axes +``` + +现在让我们运行模拟。 + +在下面的模拟中,个体1只对$f$和$g$分配正概率,而个体2对所有三个模型赋予相等的权重。 + +```{code-cell} ipython3 +T = 100 +N = 1000 + +# 为自然状态f和g生成序列 +s_seq_f = np.random.beta(F_a, F_b, (N, T)) +s_seq_g = np.random.beta(G_a, G_b, (N, T)) + +# 运行模拟 +results_f = simulate_three_model_allocation(s_seq_f, + f, g, h, π_f_0, 1-π_f_0, + 1/3, 1/3, λ) +results_g = simulate_three_model_allocation(s_seq_g, + f, g, h, π_f_0, 1-π_f_0, + 1/3, 1/3, λ) +``` + +下面的图表分别展示了每个模型(f、g、h)的信念演变。 + +首先我们展示当自然选择$f$时的图表 + +```{code-cell} ipython3 +plot_belief_evolution(results_f, nature='f', figsize=(15, 5)) +plt.show() +``` + +智能体1的后验信念用蓝色表示,智能体2的后验信念用橙色表示。 + +显然,当自然选择$f$时,智能体1比智能体2学习得更快,这是因为智能体2(与智能体1不同)对模型$h$赋予了正的先验概率: + +- 在最左边的面板中,两个智能体对$\pi(f)$的信念都逐渐收敛到1(真实值) +- 智能体2对模型$h$的信念(最右边的面板)在初期上升后逐渐收敛到0 + +现在让我们绘制当自然选择$g$时的信念演化: + +```{code-cell} ipython3 +plot_belief_evolution(results_g, nature='g', figsize=(15, 5)) +plt.show() +``` + +再次可以看到,智能体1比智能体2学习得更快。 + +在查看下一张图之前,请猜测消费份额是如何变化的。 + +请记住,智能体1比智能体2更快地达到正确的模型。 + +```{code-cell} ipython3 +plot_consumption_dynamics(results_f, results_g, λ=0.5, figsize=(14, 5)) +plt.show() +``` + +正如我们所预期的,个体1比个体2有更高的消费份额。 + +在这个练习中,"真实情况"是两个个体模型中可能的结果之一。 + +个体2的模型"更一般化",因为它允许一种个体1的模型中不包含的可能性——即自然从$h$中抽取。 + +个体1学习得更快是因为他使用了一个更简单的模型。 + +```{solution-end} +``` + +```{exercise} +:label: lr_ex7 + +现在考虑两个对三个模型有极端先验的个体。 + +考虑与前一个练习相同的设置,但现在: +* 个体1:$\pi^g_0 = \pi^f_0 = \frac{\epsilon}{2} > 0$,其中$\epsilon$接近$0$(例如,$\epsilon = 0.01$) +* 个体2:$\pi^g_0 = \pi^f_0 = 0$(对模型$h$的刚性信念) + +选择$h$使其在KL散度度量下接近但不等于$f$或$g$。 +例如,设置$h \sim \text{Beta}(1.2, 1.1)$且$f \sim \text{Beta}(1, 1)$。 + +请模拟并可视化以下情况下的后验概率和消费分配的演变: + +* 自然永久从$f$中抽取 +* 自然永久从$g$中抽取 +``` + +```{solution-start} lr_ex7 +:class: dropdown +``` + +为了探索这个练习,我们将$T$增加到1000。 + +让我们指定$f$、$g$和$h$,并验证$h$和$f$比$h$和$g$更接近 + +```{code-cell} ipython3 +F_a, F_b = 1, 1 +G_a, G_b = 3, 1.2 +H_a, H_b = 1.2, 1.1 + +f = jit(lambda x: p(x, F_a, F_b)) +g = jit(lambda x: p(x, G_a, G_b)) +h = jit(lambda x: p(x, H_a, H_b)) + +Kh_f = compute_KL(h, f) +Kh_g = compute_KL(h, g) +Kf_h = compute_KL(f, h) +Kg_h = compute_KL(g, h) + +print(f"KL散度:") +print(f"KL(h,f) = {Kh_f:.4f}, KL(h,g) = {Kh_g:.4f}") +print(f"KL(f,h) = {Kf_h:.4f}, KL(g,h) = {Kg_h:.4f}") +``` + +现在我们可以为两个智能体设置信念模型 + +```{code-cell} ipython3 +ε = 0.01 +λ = 0.5 + +# 智能体1: π_f = ε/2, π_g = ε/2, π_h = 1-ε +# (对h几乎完全坚信) +π_f_1 = ε/2 +π_g_1 = ε/2 + +# 智能体2: π_f = 0, π_g = 0, π_h = 1 +# (对h完全坚信) +π_f_2 = 1e-10 +π_g_2 = 1e-10 +``` + +现在我们可以运行模拟 + +```{code-cell} ipython3 +T = 1000 +N = 1000 + +# 为不同的自然情景生成序列 +s_seq_f = np.random.beta(F_a, F_b, (N, T)) +s_seq_g = np.random.beta(G_a, G_b, (N, T)) + +# 为两种情景运行模拟 +results_f = simulate_three_model_allocation( + s_seq_f, + f, g, h, + π_f_1, π_g_1, π_f_2, π_g_2, λ) +results_g = simulate_three_model_allocation( + s_seq_g, + f, g, h, + π_f_1, π_g_1, π_f_2, π_g_2, λ) +``` + +让我们绘制当自然选择$f$时的信念演变 + +```{code-cell} ipython3 +plot_belief_evolution(results_f, nature='f', figsize=(15, 5)) +plt.show() +``` + +观察最左侧面板中$\pi(f)$显示的个体1如何缓慢地学习真相。 + +还要注意个体2没有更新。 + +这是因为我们已经指定$f$很难与$h$区分,这是通过$KL(f, h)$来衡量的。 + +对$h$的刚性阻止了个体2在观察到非常相似的模型$f$时更新其信念。 + +现在让我们绘制当自然选择$g$时的信念演变 + +```{code-cell} ipython3 +plot_belief_evolution(results_g, nature='g', figsize=(15, 5)) +plt.show() +``` + +当自然从$g$中抽取时,它与$h$的距离更远,这是通过KL散度来衡量的。 + +这有助于两个个体更快地学习真相。 + +```{code-cell} ipython3 +plot_consumption_dynamics(results_f, results_g, + λ=0.5, figsize=(14, 5)) +plt.show() +``` + +在消费动态图中,注意到无论自然是永久从$f$中抽取还是永久从$g$中抽取,个体1的消费份额都收敛到1。 + +```{solution-end} +``` + diff --git a/lectures/likelihood_var.md b/lectures/likelihood_var.md new file mode 100644 index 00000000..5550aa63 --- /dev/null +++ b/lectures/likelihood_var.md @@ -0,0 +1,789 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +(var_likelihood)= +```{raw} jupyter + +``` + +# VAR模型的似然过程 + +```{contents} 目录 +:depth: 2 +``` + +## 概述 + +本讲座将我们对似然比过程的分析扩展到向量自回归(VAR)模型。 + +我们将: + +* 构建VAR模型的似然函数 +* 形成用于比较两个VAR模型的似然比过程 +* 可视化似然比随时间的演变 +* 将VAR似然比与萨缪尔森乘数-加速器模型联系起来 + +我们的分析建立在以下概念之上: +- {doc}`likelihood_ratio_process` +- {doc}`linear_models` +- {doc}`samuelson` + +让我们首先导入有用的库: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" +mpl.font_manager.fontManager.addfont(FONTPATH) +plt.rcParams['font.family'] = ['Source Han Serif SC'] + +from scipy import linalg +from scipy.stats import multivariate_normal as mvn +from quantecon import LinearStateSpace +import quantecon as qe +from numba import jit +from typing import NamedTuple, Optional, Tuple +from collections import namedtuple +``` + +## VAR模型设置 + +考虑以下形式的VAR模型: + +$$ +\begin{aligned} +x_{t+1} & = A x_t + C w_{t+1} \\ +x_0 & \sim \mathcal{N}(\mu_0, \Sigma_0) +\end{aligned} +$$ + +其中: +- $x_t$ 是一个 $n \times 1$ 状态向量 +- $w_{t+1} \sim \mathcal{N}(0, I)$ 是一个 $m \times 1$ 的冲击向量 +- $A$ 是一个 $n \times n$ 转移矩阵 +- $C$ 是一个 $n \times m$ 波动率矩阵 + +让我们为VAR模型定义必要的数据结构 + +```{code-cell} ipython3 +VARModel = namedtuple('VARModel', ['A', 'C', 'μ_0', 'Σ_0', + 'CC', 'CC_inv', 'log_det_CC', + 'Σ_0_inv', 'log_det_Σ_0']) +def compute_stationary_var(A, C): + """ + 计算VAR模型的平稳均值和协方差 + """ + n = A.shape[0] + + # 检查稳定性 + eigenvalues = np.linalg.eigvals(A) + if np.max(np.abs(eigenvalues)) >= 1: + raise ValueError("VAR不是平稳的") + + μ_0 = np.zeros(n) + + # 平稳协方差:求解离散Lyapunov方程 + # Σ_0 = A @ Σ_0 @ A.T + C @ C.T + CC = C @ C.T + Σ_0 = linalg.solve_discrete_lyapunov(A, CC) + + return μ_0, Σ_0 + +def create_var_model(A, C, μ_0=None, Σ_0=None, stationary=True): + """ + 创建带有参数和预计算矩阵的VAR模型 + """ + A = np.asarray(A) + C = np.asarray(C) + n = A.shape[0] + CC = C @ C.T + + if stationary: + μ_0_comp, Σ_0_comp = compute_stationary_var(A, C) + else: + μ_0_comp = μ_0 if μ_0 is not None else np.zeros(n) + Σ_0_comp = Σ_0 if Σ_0 is not None else np.eye(n) + + # 检查CC是否奇异 + det_CC = np.linalg.det(CC) + if np.abs(det_CC) < 1e-10: + # 对奇异情况使用伪逆 + CC_inv = np.linalg.pinv(CC) + CC_reg = CC + 1e-10 * np.eye(CC.shape[0]) + log_det_CC = np.log(np.linalg.det(CC_reg)) + else: + CC_inv = np.linalg.inv(CC) + log_det_CC = np.log(det_CC) + + # 对Σ_0进行相同的检查 + det_Σ_0 = np.linalg.det(Σ_0_comp) + if np.abs(det_Σ_0) < 1e-10: + Σ_0_inv = np.linalg.pinv(Σ_0_comp) + Σ_0_reg = Σ_0_comp + 1e-10 * np.eye(Σ_0_comp.shape[0]) + log_det_Σ_0 = np.log(np.linalg.det(Σ_0_reg)) + else: + Σ_0_inv = np.linalg.inv(Σ_0_comp) + log_det_Σ_0 = np.log(det_Σ_0) + + return VARModel(A=A, C=C, μ_0=μ_0_comp, Σ_0=Σ_0_comp, + CC=CC, CC_inv=CC_inv, log_det_CC=log_det_CC, + Σ_0_inv=Σ_0_inv, log_det_Σ_0=log_det_Σ_0) +``` + +### 联合分布 + +联合概率分布 $f(x_T, x_{T-1}, \ldots, x_0)$ 可以分解为: + +$$ +f(x_T, \ldots, x_0) = f(x_T | x_{T-1}) f(x_{T-1} | x_{T-2}) \cdots f(x_1 | x_0) f(x_0) +$$ + +由于VAR是马尔可夫的,$f(x_{t+1} | x_t, \ldots, x_0) = f(x_{t+1} | x_t)$。 + +### 条件密度 + +基于高斯结构,条件分布 $f(x_{t+1} | x_t)$ 是高斯分布,其: +- 均值:$A x_t$ +- 协方差:$CC'$ + +对数条件密度为 + +$$ +\log f(x_{t+1} | x_t) = -\frac{n}{2} \log(2\pi) - \frac{1}{2} \log \det(CC') - \frac{1}{2} (x_{t+1} - A x_t)' (CC')^{-1} (x_{t+1} - A x_t) +$$ (eq:cond_den) + +```{code-cell} ipython3 +def log_likelihood_transition(x_next, x_curr, model): + """ + 计算从x_curr到x_next的转移对数似然 + """ + x_next = np.atleast_1d(x_next) + x_curr = np.atleast_1d(x_curr) + n = len(x_next) + diff = x_next - model.A @ x_curr + return -0.5 * (n * np.log(2 * np.pi) + model.log_det_CC + + diff @ model.CC_inv @ diff) +``` + +初始状态的对数密度为: + +$$ +\log f(x_0) = -\frac{n}{2} \log(2\pi) - \frac{1}{2} \log \det(\Sigma_0) - \frac{1}{2} (x_0 - \mu_0)' \Sigma_0^{-1} (x_0 - \mu_0) +$$ + +```{code-cell} ipython3 +def log_likelihood_initial(x_0, model): + """ + 计算初始状态的对数似然 + """ + x_0 = np.atleast_1d(x_0) + n = len(x_0) + diff = x_0 - model.μ_0 + return -0.5 * (n * np.log(2 * np.pi) + model.log_det_Σ_0 + + diff @ model.Σ_0_inv @ diff) +``` + +现在让我们把似然计算组合成一个函数,用于计算整个路径的对数似然 + +```{code-cell} ipython3 +def log_likelihood_path(X, model): + """ + 计算整个路径的对数似然 + """ + + T = X.shape[0] - 1 + log_L = log_likelihood_initial(X[0], model) + + for t in range(T): + log_L += log_likelihood_transition(X[t+1], X[t], model) + + return log_L + +def simulate_var(model, T, N_paths=1): + """ + 从VAR模型中模拟路径 + """ + n = model.A.shape[0] + m = model.C.shape[1] + paths = np.zeros((N_paths, T+1, n)) + + for i in range(N_paths): + # 生成初始状态 + x = mvn.rvs(mean=model.μ_0, cov=model.Σ_0) + x = np.atleast_1d(x) + paths[i, 0] = x + + # 向前模拟 + for t in range(T): + w = np.random.randn(m) + x = model.A @ x + model.C @ w + paths[i, t+1] = x + + return paths if N_paths > 1 else paths[0] +``` + +## 似然比过程 + +现在让我们计算两个VAR模型的似然比过程。 + +对于具有状态向量$x_t$的VAR模型,在时间$t$的对数似然比为 + +$$ +\ell_t = \log \frac{p_f(x_t | x_{t-1})}{p_g(x_t | x_{t-1})} +$$ + +其中$p_f$和$p_g$分别是模型$f$和$g$下的条件密度。 + +累积对数似然比过程为 + +$$ +L_t = \sum_{s=1}^{t} \ell_s = \sum_{s=1}^{t} \log \frac{p_f(x_s | x_{s-1})}{p_g(x_s | x_{s-1})} +$$ + +其中$p_f(x_t | x_{t-1})$和$p_g(x_t | x_{t-1})$由{eq}`eq:cond_den`中定义的各自条件密度给出。 + +让我们用Python编写这些方程 + +```{code-cell} ipython3 +def compute_likelihood_ratio_var(paths, model_f, model_g): + """ + 计算VAR模型的似然比过程 + """ + if paths.ndim == 2: + paths = paths[np.newaxis, :] + + N_paths, T_plus_1, n = paths.shape + T = T_plus_1 - 1 + log_L_ratios = np.zeros((N_paths, T+1)) + + for i in range(N_paths): + X = paths[i] + + # 初始对数似然比 + log_L_f_0 = log_likelihood_initial(X[0], model_f) + log_L_g_0 = log_likelihood_initial(X[0], model_g) + log_L_ratios[i, 0] = log_L_f_0 - log_L_g_0 + + # 递归计算 + for t in range(1, T+1): + log_L_f_t = log_likelihood_transition(X[t], X[t-1], model_f) + log_L_g_t = log_likelihood_transition(X[t], X[t-1], model_g) + + # 更新对数似然比 + log_diff = log_L_f_t - log_L_g_t + + log_L_prev = log_L_ratios[i, t-1] + log_L_new = log_L_prev + log_diff + log_L_ratios[i, t] = log_L_new + + return log_L_ratios if N_paths > 1 else log_L_ratios[0] +``` + +## 示例1:两个AR(1)过程 + +让我们从一个简单的例子开始,比较两个单变量AR(1)过程,其中$A_f = 0.8$,$A_g = 0.5$,以及$C_f = 0.3$,$C_g = 0.4$ + +```{code-cell} ipython3 +# 模型f:AR(1),持续性系数 ρ = 0.8 +A_f = np.array([[0.8]]) +C_f = np.array([[0.3]]) + +# 模型g:AR(1),持续性系数 ρ = 0.5 +A_g = np.array([[0.5]]) +C_g = np.array([[0.4]]) + +# 创建VAR模型 +model_f = create_var_model(A_f, C_f) +model_g = create_var_model(A_g, C_g) +``` + +让我们从模型 $f$ 生成100条长度为200的路径,并计算似然比过程 + +```{code-cell} ipython3 +# 从模型f进行模拟 +T = 200 +N_paths = 100 +paths_from_f = simulate_var(model_f, T, N_paths) + +L_ratios_f = compute_likelihood_ratio_var(paths_from_f, model_f, model_g) + +fig, ax = plt.subplots() + +for i in range(min(20, N_paths)): + ax.plot(L_ratios_f[i], alpha=0.3, color='C0', lw=2) + +ax.axhline(y=0, color='gray', linestyle='--', alpha=0.5) +ax.set_ylabel(r'$\log L_t$') +ax.set_title('对数似然比过程(本质 = f)') + +plt.tight_layout() +plt.show() +``` + +正如我们预期的那样,似然比过程随着T的增加趋向于$+\infty$,表明我们的算法正确选择了模型$f$。 + +## 示例2:二元VAR模型 + +现在让我们考虑一个二元VAR模型的例子,其中 + +$$ +A_f & = \begin{bmatrix} 0.7 & 0.2 \\ 0.1 & 0.6 \end{bmatrix}, \quad C_f = \begin{bmatrix} 0.3 & 0.1 \\ 0.1 & 0.3 \end{bmatrix} +$$ + +和 + +$$ +A_g & = \begin{bmatrix} 0.5 & 0.3 \\ 0.2 & 0.5 \end{bmatrix}, \quad C_g = \begin{bmatrix} 0.4 & 0.0 \\ 0.0 & 0.4 \end{bmatrix} +$$ + +```{code-cell} ipython3 +A_f = np.array([[0.7, 0.2], + [0.1, 0.6]]) + +C_f = np.array([[0.3, 0.1], + [0.1, 0.3]]) + +A_g = np.array([[0.5, 0.3], + [0.2, 0.5]]) + +C_g = np.array([[0.4, 0.0], + [0.0, 0.4]]) + +# 创建VAR模型 +model2_f = create_var_model(A_f, C_f) +model2_g = create_var_model(A_g, C_g) + +# 检查平稳性 +print("模型f的特征值:", np.linalg.eigvals(A_f)) +print("模型g的特征值:", np.linalg.eigvals(A_g)) +``` + +让我们从两个模型中各生成50条长度为50的路径,并计算似然比过程 + +```{code-cell} ipython3 +# 从两个模型中模拟 +T = 50 +N_paths = 50 + +paths_from_f = simulate_var(model2_f, T, N_paths) +paths_from_g = simulate_var(model2_g, T, N_paths) + +# 计算似然比 +L_ratios_ff = compute_likelihood_ratio_var(paths_from_f, model2_f, model2_g) +L_ratios_gf = compute_likelihood_ratio_var(paths_from_g, model2_f, model2_g) +``` + +我们可以看到,对于从模型 $f$ 生成的路径,似然比过程趋向于 $+\infty$,而对于从模型 $g$ 生成的路径,则趋向于 $-\infty$。 + +```{code-cell} ipython3 +# 可视化结果 +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +ax = axes[0] +for i in range(min(20, N_paths)): + ax.plot(L_ratios_ff[i], alpha=0.5, color='C0', lw=2) +ax.axhline(y=0, color='gray', linestyle='--', alpha=0.5, lw=2) +ax.set_title(r'$\log L_t$ (nature = f)') +ax.set_ylabel(r'$\log L_t$') + +ax = axes[1] +for i in range(min(20, N_paths)): + ax.plot(L_ratios_gf[i], alpha=0.5, color='C1', lw=2) +ax.axhline(y=0, color='gray', linestyle='--', alpha=0.5, lw=2) +ax.set_title(r'$\log L_t$ (nature = g)') +plt.tight_layout() +plt.show() +``` + +让我们应用{doc}`likelihood_ratio_process`中描述的Neyman-Pearson频率主义决策规则,当$\log L_T \geq 0$时选择模型$f$,当$\log L_T < 0$时选择模型$g$ + +```{code-cell} ipython3 +fig, ax = plt.subplots() +T_values = np.arange(0, T+1) +accuracy_f = np.zeros(len(T_values)) +accuracy_g = np.zeros(len(T_values)) + +for i, t in enumerate(T_values): + # 当数据来自f时的正确选择 + accuracy_f[i] = np.mean(L_ratios_ff[:, t] > 0) + # 当数据来自g时的正确选择 + accuracy_g[i] = np.mean(L_ratios_gf[:, t] < 0) + +ax.plot(T_values, accuracy_f, 'C0', linewidth=2, label='accuracy (nature = f)') +ax.plot(T_values, accuracy_g, 'C1', linewidth=2, label='accuracy (nature = g)') +ax.axhline(y=0.5, color='gray', linestyle='--', alpha=0.5) +ax.set_xlabel('T') +ax.set_ylabel('accuracy') +ax.legend() + +plt.tight_layout() +plt.show() +``` + +显然,随着 $T$ 的增加,准确率趋近于 $1$,而且这个过程非常快。 + +让我们也检查一下类型 I 和类型 II 错误作为 $T$ 的函数的变化 + +```{code-cell} ipython3 +def model_selection_analysis(T_values, model_f, model_g, N_sim=500): + """ + 分析不同样本大小的模型选择性能 + """ + errors_f = [] # 类型 I 错误 + errors_g = [] # 类型 II 错误 + + for T in T_values: + # 从模型 f 模拟 + paths_f = simulate_var(model_f, T, N_sim//2) + L_ratios_f = compute_likelihood_ratio_var(paths_f, model_f, model_g) + + # 从模型 g 模拟 + paths_g = simulate_var(model_g, T, N_sim//2) + L_ratios_g = compute_likelihood_ratio_var(paths_g, model_f, model_g) + + # 决策规则:如果 log L_T >= 0 则选择 f + errors_f.append(np.mean(L_ratios_f[:, -1] < 0)) + errors_g.append(np.mean(L_ratios_g[:, -1] >= 0)) + + return np.array(errors_f), np.array(errors_g) + +T_values = np.arange(1, 50, 1) +errors_f, errors_g = model_selection_analysis(T_values, model2_f, model2_g, N_sim=400) + +fig, ax = plt.subplots() + +ax.plot(T_values, errors_f, 'C0', linewidth=2, label='类型 I 错误') +ax.plot(T_values, errors_g, 'C1', linewidth=2, label='类型 II 错误') +ax.plot(T_values, 0.5 * (errors_f + errors_g), 'g--', +linewidth=2, label='平均错误') +ax.set_xlabel('$T$') +ax.set_ylabel('错误概率') +ax.set_title('模型选择错误') +plt.tight_layout() +plt.show() +``` + +## 应用:萨缪尔森乘数-加速器模型 + +现在让我们来看萨缪尔森乘数-加速器模型。 + +该模型包括: + +- 消费:$C_t = \gamma + a Y_{t-1}$ 其中 $a \in (0,1)$ 是边际消费倾向 +- 投资:$I_t = b(Y_{t-1} - Y_{t-2})$ 其中 $b > 0$ 是加速系数 +- 政府支出:$G_t = G$ (常数) + +我们有国民收入恒等式 + +$$ +Y_t = C_t + I_t + G_t +$$ + +这些方程得出二阶差分方程: + +$$ +Y_t = (\gamma + G) + (a + b)Y_{t-1} - b Y_{t-2} + \sigma \epsilon_t +$$ + +令 $\rho_1 = a + b$ 且 $\rho_2 = -b$,我们得到: + +$$ +Y_t = (\gamma + G) + \rho_1 Y_{t-1} + \rho_2 Y_{t-2} + \sigma \epsilon_t +$$ + +为了符合我们的讨论,我们将其写成状态空间表示。 + +为了正确处理常数项,我们使用增广状态向量 $\mathbf{x}_t = [1, Y_t, Y_{t-1}]'$: + +$$ +\mathbf{x}_{t+1} = \begin{bmatrix} +1 \\ +Y_{t+1} \\ +Y_t +\end{bmatrix} = \begin{bmatrix} +1 & 0 & 0 \\ +\gamma + G & \rho_1 & \rho_2 \\ +0 & 1 & 0 +\end{bmatrix} \begin{bmatrix} +1 \\ +Y_t \\ +Y_{t-1} +\end{bmatrix} + \begin{bmatrix} +0 \\ +\sigma \\ +0 +\end{bmatrix} \epsilon_{t+1} +$$ + +观测方程提取经济变量: + +$$ +\mathbf{y}_t = \begin{bmatrix} +Y_t \\ +C_t \\ +I_t +\end{bmatrix} = \begin{bmatrix} +\gamma + G & \rho_1 & \rho_2 \\ +\gamma & a & 0 \\ +0 & b & -b +\end{bmatrix} \begin{bmatrix} +1 \\ +Y_t \\ +Y_{t-1} +\end{bmatrix} +$$ + +这给出了: + +- $Y_t = (\gamma + G) \cdot 1 + \rho_1 Y_{t-1} + \rho_2 Y_{t-2}$ (总产出) +- $C_t = \gamma \cdot 1 + a Y_{t-1}$ (消费) +- $I_t = b(Y_{t-1} - Y_{t-2})$ (投资) + +```{code-cell} ipython3 +def samuelson_to_var(a, b, γ, G, σ): + """ + 将萨缪尔森模型参数转换为带扩展状态的VAR形式 + + 萨缪尔森模型: + - Y_t = C_t + I_t + G + - C_t = γ + a*Y_{t-1} + - I_t = b*(Y_{t-1} - Y_{t-2}) + + 简化形式: Y_t = (γ+G) + (a+b)*Y_{t-1} - b*Y_{t-2} + σ*ε_t + + 状态向量为 [1, Y_t, Y_{t-1}]' + """ + ρ_1 = a + b + ρ_2 = -b + + # 扩展状态的状态转移矩阵 + A = np.array([[1, 0, 0], + [γ + G, ρ_1, ρ_2], + [0, 1, 0]]) + + # 冲击载荷矩阵 + C = np.array([[0], + [σ], + [0]]) + + # 观测矩阵(提取Y_t, C_t, I_t) + G_obs = np.array([[γ + G, ρ_1, ρ_2], # Y_t + [γ, a, 0], # C_t + [0, b, -b]]) # I_t + + return A, C, G_obs +``` + +我们在下面的代码单元中定义函数来获取初始条件并检查稳定性 + +```{code-cell} ipython3 +:tags: [hide-input] + +def get_samuelson_initial_conditions(a, b, γ, G, y_0=None, y_m1=None, + stationary_init=False): + """ + 获取萨缪尔森模型的初始条件 + """ + # 计算稳态 + y_ss = (γ + G) / (1 - a - b) + + if y_0 is None: + y_0 = y_ss + if y_m1 is None: + y_m1 = y_ss if stationary_init else y_0 * 0.95 + + # 初始均值 + μ_0 = np.array([1.0, y_0, y_m1]) + + if stationary_init: + Σ_0 = np.array([[0, 0, 0], + [0, 1, 0.5], + [0, 0.5, 1]]) + else: + Σ_0 = np.array([[0, 0, 0], + [0, 25, 15], + [0, 15, 25]]) + + return μ_0, Σ_0 + +def check_samuelson_stability(a, b): + """ + 检查萨缪尔森模型的稳定性并返回特征根 + """ + ρ_1 = a + b + ρ_2 = -b + + roots = np.roots([1, -ρ_1, -ρ_2]) + max_abs_root = np.max(np.abs(roots)) + is_stable = max_abs_root < 1 + + # 确定动态类型 + if np.iscomplex(roots[0]): + if max_abs_root < 1: + dynamics = "阻尼振荡" + else: + dynamics = "爆炸性振荡" + else: + if max_abs_root < 1: + dynamics = "平滑收敛" + else: + if np.max(roots) > 1: + dynamics = "爆炸性增长" + else: + dynamics = "爆炸性振荡(实根)" + + return is_stable, roots, max_abs_root, dynamics +``` + +让我们实现并检查由两个具有不同参数的萨缪尔森模型产生的似然比过程。 + +```{code-cell} ipython3 +def create_samuelson_var_model(a, b, γ, G, σ, stationary_init=False, + y_0=None, y_m1=None): + """ + 从萨缪尔森参数创建VAR模型 + """ + A, C, G_obs = samuelson_to_var(a, b, γ, G, σ) + + μ_0, Σ_0 = get_samuelson_initial_conditions( + a, b, γ, G, y_0, y_m1, stationary_init + ) + + # 创建VAR模型 + model = create_var_model(A, C, μ_0, Σ_0, stationary=False) + is_stable, roots, max_root, dynamics = check_samuelson_stability(a, b) + info = { + 'a': a, 'b': b, 'γ': γ, 'G': G, 'σ': σ, + 'ρ_1': a + b, 'ρ_2': -b, + 'steady_state': (γ + G) / (1 - a - b), + 'is_stable': is_stable, + 'roots': roots, + 'max_abs_root': max_root, + 'dynamics': dynamics + } + + return model, G_obs, info + +def simulate_samuelson(model, G_obs, T, N_paths=1): + """ + 模拟萨缪尔森模型 + """ + # 模拟状态路径 + states = simulate_var(model, T, N_paths) + + # 使用G矩阵提取可观测值 + if N_paths == 1: + # 单一路径: states是(T+1, 3) + observables = (G_obs @ states.T).T + else: + # 多个路径: states是(N_paths, T+1, 3) + observables = np.zeros((N_paths, T+1, 3)) + for i in range(N_paths): + observables[i] = (G_obs @ states[i].T).T + + return states, observables +``` + +现在让我们模拟两个具有不同加速系数的萨缪尔森模型并绘制它们的样本路径 + +```{code-cell} ipython3 +# 模型 f: 较高的加速系数 +a_f, b_f = 0.98, 0.9 +γ_f, G_f, σ_f = 10, 10, 0.5 + +# 模型 g: 较低的加速系数 +a_g, b_g = 0.98, 0.85 +γ_g, G_g, σ_g = 10, 10, 0.5 + + +model_sam_f, G_obs_f, info_f = create_samuelson_var_model( + a_f, b_f, γ_f, G_f, σ_f, + stationary_init=False, + y_0=100, y_m1=95 +) + +model_sam_g, G_obs_g, info_g = create_samuelson_var_model( + a_g, b_g, γ_g, G_g, σ_g, + stationary_init=False, + y_0=100, y_m1=95 +) + +T = 50 +N_paths = 50 + +# 获取状态和观测值 +states_f, obs_f = simulate_samuelson(model_sam_f, G_obs_f, T, N_paths) +states_g, obs_g = simulate_samuelson(model_sam_g, G_obs_g, T, N_paths) + +output_paths_f = obs_f[:, :, 0] +output_paths_g = obs_g[:, :, 0] + +print("模型 f:") +print(f" ρ_1 = a + b = {info_f['ρ_1']:.2f}") +print(f" ρ_2 = -b = {info_f['ρ_2']:.2f}") +print(f" 特征根: {info_f['roots']}") +print(f" 动态特征: {info_f['dynamics']}") + +print("\n模型 g:") +print(f" ρ_1 = a + b = {info_g['ρ_1']:.2f}") +print(f" ρ_2 = -b = {info_g['ρ_2']:.2f}") +print(f" 特征根: {info_g['roots']}") +print(f" 动态特征: {info_g['dynamics']}") + + +fig, ax = plt.subplots(1, 1) + +for i in range(min(20, N_paths)): + ax.plot(output_paths_f[i], alpha=0.6, color='C0', linewidth=0.8) + ax.plot(output_paths_g[i], alpha=0.6, color='C1', linewidth=0.8) +ax.set_xlabel('$t$') +ax.set_ylabel('$Y_t$') +ax.legend(['模型 f', '模型 g'], loc='upper left') +plt.tight_layout() +plt.show() +``` + +```{code-cell} ipython3 +# 计算似然比 +L_ratios_ff = compute_likelihood_ratio_var(states_f, model_sam_f, model_sam_g) +L_ratios_gf = compute_likelihood_ratio_var(states_g, model_sam_f, model_sam_g) + +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +ax = axes[0] +for i in range(min(20, N_paths)): + ax.plot(L_ratios_ff[i], alpha=0.5, color='C0', lw=0.8) +ax.axhline(y=0, color='gray', linestyle='--', alpha=0.5) +ax.set_title(r'$\log L_t$ (真实模型 = f)') +ax.set_ylabel(r'$\log L_t$') + +ax = axes[1] +for i in range(min(20, N_paths)): + ax.plot(L_ratios_gf[i], alpha=0.5, color='C1', lw=0.8) +ax.axhline(y=0, color='gray', linestyle='--', alpha=0.5) +ax.set_title(r'$\log L_t$ (真实模型 = g)') +plt.show() +``` + +在左图中,数据由$f$生成,似然比趋向正无穷。 + +在右图中,数据由$g$生成,似然比趋向负无穷。 + +在这两种情况下,为了数值稳定性,我们对对数似然比过程设置了上下限阈值,因为它们会很快增长到无界。 + +在这两种情况下,似然比过程最终都能帮助我们选择正确的模型。 + diff --git a/lectures/mix_model.md b/lectures/mix_model.md index f87f01d0..feeb623e 100644 --- a/lectures/mix_model.md +++ b/lectures/mix_model.md @@ -1,10 +1,10 @@ --- jupytext: text_representation: - extension: .myst + extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.13.8 + jupytext_version: 1.17.2 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -14,11 +14,12 @@ kernelspec: (likelihood-ratio-process)= # 错误模型 -除了Anaconda中包含的库之外,本讲座还需要以下库: -```{code-cell} ipython ---- -tags: [hide-output] ---- +```{include} _admonition/gpu.md +``` + +```{code-cell} ipython3 +:tags: [no-execute, hide-output] + !pip install numpyro jax ``` @@ -38,73 +39,76 @@ tags: [hide-output] 这个统计设定与那个 quantecon 讲座中研究的问题相近但不完全相同。 -在那个讲座中,有两个独立同分布的过程可能支配着一个非负随机变量 $W$ 的连续抽取。 +在那个讲座中,有两个可能支配非负随机变量 $W$ 连续抽取的独立同分布过程。 -自然界一劳永逸地决定是从分布 $f$ 还是从分布 $g$ 中进行一系列独立同分布的抽取。 +自然界一劳永逸地决定是从分布 $f$ 还是从分布 $g$ 中进行一系列独立同分布抽取。 -该讲座研究了一个同时知道$f$和$g$但不知道自然在$-1$时刻选择了哪个分布的个体。 +那个讲座研究了一个同时知道 $f$ 和 $g$ 但不知道自然界在时间 $-1$ 选择了哪个分布的代理人。 -个体通过假设自然以概率$\pi_{-1}$选择概率分布$f$的方式来表示这种无知,就像抛一枚不公平的硬币。 +该代理人通过假设自然界抛一个不公平的硬币来选择 $f$ 或 $g$,其中选择概率分布 $f$ 的概率为 $\pi_{-1}$,来表示这种无知状态。 -这个假设使得个体能够构建一个关于随机序列$\{W_t\}_{t=0}^\infty$的主观联合概率分布。 +这个假设使得代理人能够构建一个关于随机序列 $\{W_t\}_{t=0}^\infty$ 的主观联合概率分布。 -我们研究了个体如何使用条件概率法则和观察到的历史数据$w^t =\{w_s\}_{t=0}^t$来形成 +我们研究了代理人如何使用条件概率法则和观察到的历史 $w^t =\{w_s\}_{s=0}^t$ 来形成 $$ -\pi_t = E [ \textrm{自然选择分布} f | w^t] , \quad t = 0, 1, 2, \ldots + +\pi_t = E [ \textrm{自然选择分布} f | w^t] , \quad t = 0, 1, 2, \ldots $$ -然而,在本讲座的设定中,这个规则赋予了个体一个错误的模型。 +然而,在本讲座的设定中,该规则为智能体赋予了一个错误的模型。 原因是现在工资序列实际上是由一个不同的统计模型描述的。 -因此,我们需要对{doc}`quantecon讲座`的规范进行如下修改。 +因此,我们需要以下列方式改变{doc}`quantecon讲座`的规范。 -现在,在**每个时期** $t \geq 0$,自然界抛出一个可能不公平的硬币,其正面($f$)概率为 $\alpha$,反面($g$)概率为 $1-\alpha$。 +现在,在**每个时期**$t \geq 0$,自然投掷一个可能不公平的硬币,以概率$\alpha$出现$f$,以概率$1-\alpha$出现$g$。 -因此,自然界持续地从具有以下c.d.f.的**混合分布**中抽取: +因此,自然持续地从具有以下累积分布函数的**混合分布**中抽取: $$ -H(w ) = \alpha F(w) + (1-\alpha) G(w), \quad \alpha \in (0,1) +H(w) = \alpha F(w) + (1-\alpha) G(w), \quad \alpha \in (0,1) $$ -我们将研究两个试图了解工资过程的个体,他们使用不同的统计模型。 +我们将研究两种试图学习工资过程的智能体,他们使用不同的统计模型。 + +两种类型的智能体都知道$f$和$g$,但都不知道$\alpha$。 -两种类型的个体都知道 $f$ 和 $g$,但都不知道 $\alpha$。 +我们的第一类智能体错误地认为在时间$-1$时,自然一次性选择了$f$或$g$,此后永久地从该分布中抽取。 -我们的第一类个体错误地认为在时间 $-1$ 时,自然界一次性选择了 $f$ 或 $g$,此后永久地从该分布中抽取。 +我们的第二类智能体正确地知道,自然在每个时期以混合概率$\alpha \in (0,1)$混合$f$和$g$,尽管智能体不知道混合参数。 -我们的第二类个体正确地知道,自然界在每个时期都以混合概率 $\alpha \in (0,1)$ 混合 $f$ 和 $g$,尽管个体不知道混合参数。 +我们的第一类智能体应用{doc}`这个quantecon讲座`中描述的学习算法。 -我们的第一类个体应用了在{doc}`这个quantecon讲座 `中描述的学习算法。 +在该讲座中所涉及的统计模型的背景下,这是一个好的学习算法,它使贝叶斯学习者能够 -在那节课中统计模型的背景下,这是一个很好的学习算法,它使贝叶斯学习者最终能够学习到自然在时间$-1$时所抽取的分布。 +最终学习自然在时间 $-1$ 时所选择的分布。 -这是因为该代理的统计模型在与数据生成过程一致的意义上是*正确的*。 +这是因为该智能体的统计模型在与数据生成过程一致的意义上是*正确的*。 -但在当前情况下,我们的第一类决策者的模型是错误的,因为实际生成数据的模型$h$既不是$f$也不是$g$,因此超出了代理认为可能的模型支持范围。 +但在当前情况下,我们的第一类决策者的模型是错误的,因为实际生成数据的模型 $h$ 既不是 $f$ 也不是 $g$,因此超出了该智能体认为可能的模型支持范围。 -尽管如此,我们将看到我们的第一类代理仍然能够摸索前进,并最终学到一些有趣且有用的东西,即使这些并不是*真实的*。 +尽管如此,我们将看到我们的第一类智能体仍然能够摸索前进,并最终学到一些有趣且有用的东西,即使这些并不是*真实的*。 -相反,事实证明我们这个配备了错误统计模型的第一类代理,最终会学习到$f$或$g$中在特定意义上与实际生成数据的$h$*最接近*的那个概率分布。 +相反,事实证明我们这个配备了错误统计模型的第一类智能体,最终会学习到 $f$ 或 $g$ 中在特定意义上与实际生成数据的 $h$ *最接近*的那个概率分布。 -我们将说明它在什么意义上最接近。 +我们将说明它在什么意义上是最接近的。 -我们的第二类代理理解自然在每个时期以固定的混合概率 $\alpha$ 在 $f$ 和 $g$ 之间进行混合。 +我们的第二类智能体理解自然在每个时期以固定的混合概率 $\alpha$ 在 $f$ 和 $g$ 之间进行混合。 -但是代理不知道 $\alpha$。 +但该智能体不知道 $\alpha$ 的值。 -代理决定使用贝叶斯定律应用于他的模型来学习 $\alpha$。 +该智能体着手使用贝叶斯法则应用于其模型来学习 $\alpha$。 他的模型是正确的,因为它包含了实际的数据生成过程 $h$ 作为一个可能的分布。 在本讲中,我们将学习 -* 自然如何在两个分布 $f$ 和 $g$ 之间*混合*来创建一个新的分布 $h$。 +* 自然如何在两个分布 $f$ 和 $g$ 之间进行*混合*以创建一个新的分布 $h$。 -* Kullback-Leibler统计散度 ,它在不正确的统计模型下控制统计学习 +* Kullback-Leibler统计散度 用于控制在不正确统计模型下的统计学习 -* 一个有用的Python函数 `numpy.searchsorted`,它与均匀随机数生成器一起使用可以从任意分布中进行采样 +* 一个有用的Python函数`numpy.searchsorted`,它与均匀随机数生成器结合使用时,可以用来从任意分布中进行采样 像往常一样,我们先导入一些Python工具。 @@ -112,12 +116,10 @@ $$ :hide-output: false 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) #set default figure size import numpy as np from numba import vectorize, jit from math import gamma @@ -135,11 +137,11 @@ from numpyro.infer import MCMC, NUTS import jax.numpy as jnp from jax import random -np.random.seed(142857) +np.random.seed(0) @jit def set_seed(): - np.random.seed(142857) + np.random.seed(0) set_seed() ``` @@ -210,7 +212,7 @@ l_seq_f = np.cumprod(l_arr_f, axis=1) * 第一步: - * 使用 numpy.random.choice 函数抛一个不公平的硬币,以概率 $\alpha$ 选择分布 $F$,以概率 $1-\alpha$ 选择分布 $G$ + * 使用 numpy.random.choice 函数抛一个不公平的硬币,以概率 $\alpha$ 选择分布 $F$,以概率 $1-\alpha$ 选择 $G$ * 第二步: @@ -220,19 +222,20 @@ l_seq_f = np.cumprod(l_arr_f, axis=1) * 将前两步放在一个大循环中,对 $w$ 的每个实现都执行这些步骤 + 我们的第二种方法使用均匀分布和以下在 quantecon 讲座 中描述和使用的事实: -* 如果随机变量 $X$ 的累积分布函数为 $F(X)$,那么随机变量 $F^{-1}(U)$ 也具有累积分布函数 $F(x)$,其中 $U$ 是 $[0,1]$ 上的均匀随机变量。 + * 如果随机变量 $X$ 的累积分布函数为 $F$,那么随机变量 $F^{-1}(U)$ 也具有累积分布函数 $F$,其中 $U$ 是 $[0,1]$ 上的均匀随机变量。 -换句话说,如果 $X \sim F(x)$,我们可以通过从区间 $[0,1]$ 上的均匀分布中抽取随机样本,并计算 $F^{-1}(U)$ 来从 $F$ 中生成随机样本。 +换句话说,如果 $X \sim F(x)$,我们可以通过从 $[0,1]$ 上的均匀分布中抽取随机样本并计算 $F^{-1}(U)$ 来生成来自 $F$ 的随机样本。 -我们将结合 `numpy.searchsorted` 命令使用这个事实来直接从 $H$ 中采样。 +我们将结合 `numpy.searchsorted` 命令使用这个事实来直接从 $H$ 中抽样。 -参见 了解 `searchsorted` 函数。 +关于 `searchsorted` 函数的说明,请参见 。 -查看[Mr. P Solver关于蒙特卡洛模拟的视频](https://www.google.com/search?q=Mr.+P+Solver+video+on+Monte+Carlo+simulation&oq=Mr.+P+Solver+video+on+Monte+Carlo+simulation),了解这个强大技巧的其他应用。 +观看[Mr. P Solver关于蒙特卡洛模拟的视频](https://www.google.com/search?q=Mr.+P+Solver+video+on+Monte+Carlo+simulation&oq=Mr.+P+Solver+video+on+Monte+Carlo+simulation),了解这个强大技巧的其他应用。 -在下面的Python代码中,我们将使用这两种方法,并确认它们都能很好地从我们的目标混合分布中进行采样。 +在下面的Python代码中,我们将使用两种方法,并确认它们都能很好地从我们的目标混合分布中进行采样。 ```{code-cell} ipython3 @jit @@ -245,7 +248,6 @@ def draw_lottery(p, N): draws.append(np.random.beta(F_a, F_b)) else: draws.append(np.random.beta(G_a, G_b)) - return np.array(draws) def draw_lottery_MC(p, N): @@ -278,25 +280,13 @@ plt.legend() plt.show() ``` -```{code-cell} ipython3 -# %%timeit # 比较速度 -# sample1 = draw_lottery(α, N=int(1e6)) -``` - -```{code-cell} ipython3 -# %%timeit -# sample2 = draw_lottery_MC(α, N=int(1e6)) -``` - -**注意:** 使用numba加速后,当我们生成1,000,000个样本时,第一种方法实际上只比第二种方法稍慢一点。 - -## 类型1代理 +## 类型1智能体 -我们现在来研究类型1代理学到了什么 +现在我们来研究类型1智能体学到了什么 -请记住,我们的类型1代理使用了错误的统计模型,认为自然在时间-1时就一次性地在$f$和$g$之间做出了选择。 +请记住,我们的类型1智能体使用了错误的统计模型,认为自然在时间-1时就一次性地在$f$和$g$之间做出了选择。 -因此,类型1代理使用了在{doc}`这个quantecon讲座`中研究的学习算法。 +因此,类型1智能体使用了在{doc}`这个quantecon讲座`中研究的学习算法。 我们现在简要回顾一下该学习算法。 @@ -312,30 +302,28 @@ $$ $$ \pi_t=\frac{\pi_{t-1} l_t(w_t)}{\pi_{t-1} l_t(w_t)+1-\pi_{t-1}} -$$ (equation-eq-recur1) - -其中$\pi_{0}$是$q = f$的贝叶斯先验概率, +$$ (eq:recur1) -即,基于我们尚未看到任何数据而对 $ q $ 的个人或主观信念。 +其中$\pi_{0}$是关于$q = f$的贝叶斯先验概率,即在我们尚未看到任何数据时基于主观判断的个人信念。 -下面我们定义一个Python函数,使用似然比 $ \ell $ 根据递归公式 {eq}`equation-eq-recur1` 来更新信念 $ \pi $ +下面我们定义一个Python函数,该函数根据递归式{eq}`eq:recur1`使用似然比$\ell$来更新信念$\pi$ ```{code-cell} ipython3 :hide-output: false @jit def update(π, l): - "使用似然l更新π" + "Update π using likelihood l" - # 更新信念 + # Update belief π = π * l / (π * l + 1 - π) return π ``` -公式 {eq}`equation-eq-recur1` 可以通过迭代推广,从而得到时间 $ t $ 的后验概率 $ \pi_{t+1} $ 作为时间 $ 0 $ 的先验概率 $ \pi_0 $ 和时间 $ t $ 的似然比过程 $ L(w^{t+1}) $ 的函数表达式。 +通过对公式 {eq}`eq:recur1` 进行迭代,我们可以推导出时间 $ t $ 的后验概率 $ \pi_{t+1} $ 与时间 $ 0 $ 的先验概率 $ \pi_0 $ 和似然比过程 $ L(w^{t+1}) $ 之间的关系。 -首先,注意更新规则 +首先,注意更新规则 $$ \pi_{t+1} @@ -343,7 +331,7 @@ $$ {\pi_{t}\ell \left(w_{t+1}\right)+\left(1-\pi_{t}\right)} $$ -意味着 +可推导出 $$ \begin{aligned} @@ -368,40 +356,33 @@ $$ \frac{1}{\pi_{t+1}}-1 =\frac{1}{\prod_{i=1}^{t+1}\ell \left(w_{i}\right)} \left(\frac{1}{\pi_{0}}-1\right) - -=\frac{1}{L\left(w^{t+1}\right)}\left(\frac{1}{\pi_{0}}-1\right). + =\frac{1}{L\left(w^{t+1}\right)}\left(\frac{1}{\pi_{0}}-1\right). \end{aligned} $$ -由于 $ \pi_{0}\in\left(0,1\right) $ 且 -$ L\left(w^{t+1}\right)>0 $,我们可以验证 -$ \pi_{t+1}\in\left(0,1\right) $。 +由于 $ \pi_{0}\in\left(0,1\right) $ 且 $ L\left(w^{t+1}\right)>0 $,我们可以验证 $ \pi_{t+1}\in\left(0,1\right) $。 -通过重新整理前面的方程,我们可以将 $ \pi_{t+1} $ 表示为 -$ L\left(w^{t+1}\right) $(即t+1时刻的似然比过程) -和初始先验 $ \pi_{0} $ 的函数 +通过重新整理上述方程,我们可以将 $ \pi_{t+1} $ 表示为 $ t+1 $ 时刻的似然比过程 $ L\left(w^{t+1}\right) $ 和初始先验概率 $ \pi_{0} $ 的函数 $$ \pi_{t+1}=\frac{\pi_{0}L\left(w^{t+1}\right)}{\pi_{0}L\left(w^{t+1}\right)+1-\pi_{0}}. -$$ (equation-eq-bayeslaw103) +$$ (eq:bayeslaw103) -公式{eq}`equation-eq-bayeslaw103`是公式{eq}`equation-eq-recur1`的推广。 +公式{eq}`eq:bayeslaw103`是公式{eq}`eq:recur1`的推广。 -公式{eq}`equation-eq-bayeslaw103`可以被视为在观察到数据批次$ \left\{ w_{i}\right\} _{i=1}^{t+1} $后,对先验概率$ \pi_0 $的一步修正。 +公式{eq}`eq:bayeslaw103`可以被视为在观察到一批数据$ \left\{ w_{i}\right\} _{i=1}^{t+1} $后对先验概率$ \pi_0 $的一步修正。 ## 当混合分布$H$生成数据时,类型1代理学到什么 -我们现在研究当混合分布$h;\alpha$真实地每期生成数据时会发生什么。 - -次鞅或上鞅继续描述 $\pi_t$ +我们现在研究当混合分布$h;\alpha$在每个时期真实生成数据时会发生什么。 -它显露出其丑陋的一面,导致 $\pi_t$ 要么收敛到 $0$,要么收敛到 $1$。 +尽管代理的模型有误设定,序列$\pi_t$仍然会收敛,且极限要么是$0$要么是$1$。 -即使在实际中自然总是在 $f$ 和 $g$ 之间混合,这一点仍然成立。 +即使在实际上自然总是在$f$和$g$之间混合,这一点依然成立。 -在验证了关于 $\pi_t$ 序列可能极限点的这一说法之后,我们将深入研究决定 $\pi_t$ 极限值的基本力量。 +在验证了关于$\pi_t$序列可能极限点的这一说法之后,我们将深入研究决定$\pi_t$极限值的根本力量。 -让我们设定一个 $\alpha$ 值,然后观察 $\pi_t$ 如何演变。 +让我们设定一个$\alpha$值,然后观察$\pi_t$如何演变。 ```{code-cell} ipython3 def simulate_mixed(α, T=50, N=500): @@ -437,10 +418,10 @@ def plot_π_seq(α, π1=0.2, π2=0.8, T=200): ax1.plot(range(T+1), π_seq_mixed[i, :], label=rf"$\pi_0$={π_seq_mixed[i, 0]}") ax1.plot(np.nan, np.nan, '--', color='b', label='对数似然比过程') - ax1.set_ylabel("$\pi_t$") + ax1.set_ylabel(r"$\pi_t$") ax1.set_xlabel("t") ax1.legend() - ax1.set_title("当 $\\alpha G + (1-\\alpha)$ F 支配数据时") + ax1.set_title("当$\\alpha F + (1-\\alpha)G$支配数据时") ax2 = ax1.twinx() ax2.plot(range(1, T+1), np.log(l_seq_mixed[0, :]), '--', color='b') @@ -472,16 +453,16 @@ $$ h(w) \equiv h(w | \alpha) = \alpha f(w) + (1-\alpha) g(w) $$ 我们将计算以下两个 Kullback-Leibler 散度: $$ -KL_g (\alpha) = \int \log\left(\frac{g(w)}{h(w)}\right) h(w) d w +KL_g (\alpha) = \int \log\left(\frac{h(w)}{g(w)}\right) h(w) d w $$ 和 $$ -KL_f (\alpha) = \int \log\left(\frac{f(w)}{h(w)}\right) h(w) d w +KL_f (\alpha) = \int \log\left(\frac{h(w)}{f(w)}\right) h(w) d w $$ -我们将绘制这两个函数关于 $\alpha$ 的图像,同时用 $\alpha$ 来改变 $h(w) = h(w|\alpha)$。 +我们将在使用 $\alpha$ 改变 $h(w) = h(w|\alpha)$ 时,绘制这两个函数关于 $\alpha$ 的图像。 $\pi_t$ 的极限由下式决定: @@ -489,38 +470,38 @@ $$ \min_{f,g} \{KL_g, KL_f\} $$ 唯一可能的极限是 $0$ 和 $1$。 -当 $t \rightarrow +\infty$ 时,$\pi_t$ 趋向于 1 当且仅当 $KL_f < KL_g$ +当且仅当 $KL_f < KL_g$ 时,$\pi_t$ 在 $t \rightarrow +\infty$ 时趋向于 1。 ```{code-cell} ipython3 @vectorize def KL_g(α): - "Compute the KL divergence between g and h." + "Compute the KL divergence KL(h, g)." err = 1e-8 # to avoid 0 at end points ws = np.linspace(err, 1-err, 10000) gs, fs = g(ws), f(ws) hs = α*fs + (1-α)*gs - return np.sum(np.log(gs/hs)*hs)/10000 + return np.sum(np.log(hs/gs)*hs)/10000 @vectorize def KL_f(α): - "Compute the KL divergence between f and h." + "Compute the KL divergence KL(h, f)." err = 1e-8 # to avoid 0 at end points ws = np.linspace(err, 1-err, 10000) gs, fs = g(ws), f(ws) hs = α*fs + (1-α)*gs - return np.sum(np.log(fs/hs)*hs)/10000 + return np.sum(np.log(hs/fs)*hs)/10000 # compute KL using quad in Scipy def KL_g_quad(α): - "Compute the KL divergence between g and h using scipy.integrate." + "Compute the KL divergence KL(h, g) using scipy.integrate." h = lambda x: α*f(x) + (1-α)*g(x) - return quad(lambda x: np.log(g(x)/h(x))*h(x), 0, 1)[0] + return quad(lambda x: h(x) * np.log(h(x)/g(x)), 0, 1)[0] def KL_f_quad(α): - "Compute the KL divergence between f and h using scipy.integrate." + "Compute the KL divergence KL(h, f) using scipy.integrate." h = lambda x: α*f(x) + (1-α)*g(x) - return quad(lambda x: np.log(f(x)/h(x))*h(x), 0, 1)[0] + return quad(lambda x: h(x) * np.log(h(x)/f(x)), 0, 1)[0] # vectorize KL_g_quad_v = np.vectorize(KL_g_quad) @@ -550,61 +531,47 @@ KL_f_arr = KL_f(α_arr) fig, ax = plt.subplots(1, figsize=[10, 6]) -ax.plot(α_arr, KL_g_arr, label='KL(g, h)') -ax.plot(α_arr, KL_f_arr, label='KL(f, h)') -ax.set_ylabel('K-L散度') +ax.plot(α_arr, KL_g_arr, label='KL(h, g)') +ax.plot(α_arr, KL_f_arr, label='KL(h, f)') +ax.set_ylabel('KL散度') ax.set_xlabel(r'$\alpha$') ax.legend(loc='upper right') plt.show() ``` -```{code-cell} ipython3 -# # 使用Scipy计算KL散度 - -# α_arr = np.linspace(0, 1, 100) -# KL_g_arr = KL_g_quad_v(α_arr) -# KL_f_arr = KL_f_quad_v(α_arr) - -# fig, ax = plt.subplots(1, figsize=[10, 6]) - -# ax.plot(α_arr, KL_g_arr, label='KL(g, h)') -# ax.plot(α_arr, KL_f_arr, label='KL(f, h)') -# ax.set_ylabel('K-L散度') - -# ax.legend(loc='upper right') -# plt.show() -``` - 让我们计算一个 $\alpha$ 值,使得 $h$ 和 $g$ 之间的 KL 散度等于 $h$ 和 $f$ 之间的 KL 散度。 ```{code-cell} ipython3 # 当 KL_f = KL_g 时 -α_arr[np.argmin(np.abs(KL_g_arr-KL_f_arr))] +discretion = α_arr[np.argmin(np.abs(KL_g_arr-KL_f_arr))] ``` -我们可以计算并绘制每个 $\alpha$ 的收敛点 $\pi_{\infty}$ 来验证收敛确实受KL散度支配。 +我们可以计算并绘制每个$\alpha$的收敛点$\pi_{\infty}$,以验证收敛确实是由KL散度决定的。 -蓝色圆圈显示了模拟发现的不同 $\alpha$ 值(记录在 $x$ 轴上)对应的 $\pi_t$ 的极限值。 +蓝色圆圈显示了模拟发现的不同$\alpha$值(记录在$x$轴上)对应的$\pi_t$的极限值。 -因此,下图证实了最小KL散度如何支配我们的类型1代理最终学到的内容。 +因此,下图证实了KL散度的最小值如何决定了我们的类型1代理最终学到的内容。 ```{code-cell} ipython3 -α_arr_x = α_arr[(α_arr<0.28)|(α_arr>0.38)] +α_arr_x = α_arr[(α_arrdiscretion)] π_lim_arr = π_lim_v(α_arr_x) # plot fig, ax = plt.subplots(1, figsize=[10, 6]) -ax.plot(α_arr, KL_g_arr, label='KL(g, h)') -ax.plot(α_arr, KL_f_arr, label='KL(f, h)') -ax.set_ylabel('K-L散度') +ax.plot(α_arr, KL_g_arr, label='KL(h, g)') +ax.plot(α_arr, KL_f_arr, label='KL(h, f)') +ax.set_ylabel('KL散度') ax.set_xlabel(r'$\alpha$') # plot KL ax2 = ax.twinx() # plot limit point -ax2.scatter(α_arr_x, π_lim_arr, facecolors='none', edgecolors='tab:blue', label=r'$\pi$ lim') +ax2.scatter(α_arr_x, π_lim_arr, + facecolors='none', + edgecolors='tab:blue', + label=r'$\pi$ lim') ax2.set_ylabel('π lim') ax.legend(loc=[0.85, 0.8]) @@ -612,15 +579,19 @@ ax2.legend(loc=[0.85, 0.73]) plt.show() ``` -显然,我们的类型1学习者在对其错误设定的统计模型集应用贝叶斯法则时,最终会学习到一个尽可能接近真实模型的近似模型,这种接近程度是通过Kullback-Leibler散度来衡量的。 +显然,我们的类型1学习者将贝叶斯定律应用于其错误设定的统计模型集合,最终学习到一个尽可能接近真实模型的近似模型,这种接近程度是通过Kullback-Leibler散度来衡量的: + +- 当$\alpha$较小时,$KL_g < KL_f$意味着$g$与$h$的散度小于$f$的散度,因此$\pi_t$的极限点接近0。 + +- 当$\alpha$较大时,$KL_f < KL_g$意味着$f$与$h$的散度小于$g$的散度,因此$\pi_t$的极限点接近1。 ## 类型2代理 现在我们来描述类型2代理如何构建他的学习问题以及他最终学到什么。 -我们的类型2代理理解正确的统计模型,但承认他不知道$\alpha$。 +我们的类型2代理理解正确的统计模型但不知道$\alpha$。 -我们应用贝叶斯法则来推导学习$\alpha$的算法,假设代理知道 +我们应用贝叶斯定律来推导学习$\alpha$的算法,假设代理知道 $$ h(w) = h(w| \alpha) @@ -628,32 +599,33 @@ $$ 但不知道$\alpha$。 -我们假设此人以先验概率$\pi_0(\alpha)$开始,其中$\alpha \in (0,1)$,这个先验具有我们在{doc}`这个quantecon讲座`中使用的形式之一。 +我们假设此人从$\alpha \in (0,1)$上的先验概率$\pi_0(\alpha)$开始,这个先验具有我们在{doc}`这个quantecon讲座`中使用的形式之一。 我们将启动`numpyro`并将其应用于当前情况。 -贝叶斯法则现在采取以下形式: +贝叶斯定律现在采取以下形式: $$ \pi_{t+1}(\alpha) = \frac {h(w_{t+1} | \alpha) \pi_t(\alpha)} - -{ \int h(w_{t+1} | \hat \alpha) \pi_t(\hat \alpha) d \hat \alpha } + { \int h(w_{t+1} | \hat \alpha) \pi_t(\hat \alpha) d \hat \alpha } $$ 我们将使用numpyro来近似这个方程。 -我们将创建后验分布$\pi_t(\alpha)$的图形,展示当$t \rightarrow +\infty$时的变化,这与quantecon讲座中展示的图形相对应。 +我们将创建后验$\pi_t(\alpha)$的图形,随着 -我们预计,当$t \rightarrow + \infty$时,后验分布将会收敛到真实的$\alpha$值周围。 +当 $t \rightarrow +\infty$ 时,对应于 quantecon 讲座中展示的内容 。 -让我们先尝试使用均匀先验分布。 +我们预计后验分布将在 $t \rightarrow + \infty$ 时收敛于真实的 $\alpha$ 值周围。 -我们使用Numpyro中的`Mixture`类来构建似然函数。 +让我们先尝试一个均匀先验分布。 + +我们使用 numpyro 中的 `Mixture` 类来构建似然函数。 ```{code-cell} ipython3 α = 0.8 -# 使用真实α值模拟数据 +# 用真实的 α 模拟数据 data = draw_lottery(α, 1000) sizes = [5, 20, 50, 200, 1000, 25000] @@ -664,12 +636,12 @@ def model(w): dist.Mixture(dist.Categorical(jnp.array([α, 1-α])), [dist.Beta(F_a, F_b), dist.Beta(G_a, G_b)]), obs=w) def MCMC_run(ws): - "使用MCMC计算观测到ws时的后验分布" + "使用 MCMC 计算观测到的 ws 的后验分布" - kernal = NUTS(model) - mcmc = MCMC(kernal, num_samples=5000, num_warmup=1000, progress_bar=False) + kernel = NUTS(model) + mcmc = MCMC(kernel, num_samples=5000, num_warmup=1000, progress_bar=False) - mcmc.run(rng_key=random.PRNGKey(142857), w=jnp.array(ws)) + mcmc.run(rng_key=random.PRNGKey(0), w=jnp.array(ws)) sample = mcmc.get_samples() return sample['α'] ``` @@ -692,36 +664,173 @@ ax.set_xlabel(r'$\alpha$') plt.show() ``` -显然,随着观测历史长度的增加,贝叶斯后验会逐渐收敛到混合参数的真实值 $\alpha = .8$。 +显然,随着观测历史长度的增长,贝叶斯后验分布逐渐收敛于混合参数的真实值 $\alpha = .8$。 -## 总结说明 +## 总结性评论 -我们的类型1个体使用了一个错误的统计模型。 +我们的第1类人使用了一个错误的统计模型。 他认为要么是 $f$ 要么是 $g$ 生成了 $w$ 过程,只是不知道具体是哪一个。 -这是错误的,因为实际上自然在每个周期都以混合概率 $\alpha$ 进行混合。 +这是错误的,因为实际上自然在每个时期都以混合概率 $\alpha$ 进行混合。 -我们的类型1个体最终会相信要么是 $f$ 要么是 $g$ 生成了 $w$ 序列,具体结果取决于相对于 $h$ 具有较小KL散度的模型($f$ 或 $g$)。 +我们的第1类主体最终会相信要么是 $f$ 要么是 $g$ 生成了 $w$ 序列,结果取决于相对于 $h$ 具有较小 KL 散度的模型($f$ 或 $g$)。 -我们的类型2个体有一个不同的统计模型,这个模型是正确设定的。 +我们的第2类主体有一个不同的统计模型,这个模型是正确设定的。 他知道统计模型的参数形式,但不知道混合参数 $\alpha$。 他知道自己不知道这个参数。 -但通过结合贝叶斯定律、统计模型和历史数据,他最终能够对$\alpha$做出越来越准确的推断。 +但是通过结合其统计模型和数据历史使用贝叶斯法则,他最终能够对 $\alpha$ 做出越来越准确的推断。 -这个小实验展示了一些重要的普遍原理,这些原理支配着贝叶斯学习错误设定模型的结果。 +这个小实验展示了一些重要的一般原则,这些原则支配着贝叶斯学习错误设定模型的结果。 因此,在实证研究中普遍存在以下情况。 -科学家用统计模型流形$S$来处理数据,其中$s(X|\theta)$是随机向量$X$上的概率分布,$\theta \in \Theta$是参数向量,而$\Theta$索引了模型流形。 +一个科学家用统计模型流形 $S$ 来处理数据,其中 $ s (X | \theta)$ 是随机向量 $X$ 上的概率分布,$\theta \in \Theta$ 是参数向量,而 $\Theta$ 标记了模型流形。 + +科学家通过观察得到随机向量$X$的实现值$x$,想要解决一个**逆问题**,即通过某种方式_求逆_ +$s(x | \theta)$来从$x$推断$\theta$。 + +但科学家的模型是错误设定的,只是自然界用来生成$X$的未知模型$h$的一个近似。 + +如果科学家使用贝叶斯定律或相关的基于似然的方法来推断$\theta$,通常在大样本情况下,逆问题会推断出一个使科学家模型$s$相对于自然模型$h$的KL散度最小化的$\theta$。 + +## 练习 + +```{exercise} +:label: mix_model_ex1 + +在{doc}`likelihood_bayes`中,我们研究了将似然比和贝叶斯定律应用于错误设定统计模型的后果。 + +在那节课中,我们使用模型选择算法来研究真实数据生成过程是混合分布的情况。 + +在本节课中,我们研究了如何使用贝叶斯方法正确地"学习"由混合过程生成的模型。 + +为了修正我们在{doc}`likelihood_bayes`中使用的算法,正确的贝叶斯方法应该直接对$x$的不确定性建模,并随着新数据的到来更新对它的信念。 + +这是算法: + +首先我们指定$x$的先验分布为$x \sim \text{Beta}(\alpha_0, \beta_0)$,其期望值为$\mathbb{E}[x] = \frac{\alpha_0}{\alpha_0 + \beta_0}$。 + +单个观测值 $w_t$ 的似然函数为 $p(w_t|x) = x f(w_t) + (1-x) g(w_t)$。 + +对于序列 $w^t = (w_1, \dots, w_t)$,似然函数为 $p(w^t|x) = \prod_{i=1}^t p(w_i|x)$。 + +后验分布使用 $p(x|w^t) \propto p(w^t|x) p(x)$ 进行更新。 + +递归地,$w_t$ 之后的后验分布为 $p(x|w^t) \propto p(w_t|x) p(x|w^{t-1})$。 + +如果没有共轭先验,我们可以通过将 $x$ 离散化为网格来近似后验分布。 -科学家将观测数据解释为随机向量$X$的实现值$x$,想要解决一个**逆问题**,即某种方式_求逆_$s(x|\theta)$以从$x$推断$\theta$。 +你的任务是用Python实现这个算法。 -但科学家的模型是错误设定的,它只是自然用来生成$X$的未知模型$h$的一个近似。 +你可以通过检查后验均值是否随着 $t$ 的增加而收敛到 $x$ 的真实值来验证你的实现,详见 {doc}`likelihood_bayes`。 +``` + +```{solution-start} mix_model_ex1 +:class: dropdown +``` + +这是一个解决方案: + +首先我们定义混合概率 +和先验分布的参数 + +```{code-cell} ipython3 +x_true = 0.5 +T_mix = 200 + +# 三个不同的先验,均值分别为0.25、0.5、0.75 +prior_params = [(1, 3), (1, 1), (3, 1)] +prior_means = [a/(a+b) for a, b in prior_params] + +w_mix = draw_lottery(x_true, T_mix) +``` + +```{code-cell} ipython3 +@jit +def learn_x_bayesian(observations, α0, β0, grid_size=2000): + """ + 使用网格近似对混合概率x进行顺序贝叶斯学习。 + """ + w = np.asarray(observations) + T = w.size + + x_grid = np.linspace(1e-3, 1 - 1e-3, grid_size) + + # 对数先验 + log_prior = (α0 - 1) * np.log(x_grid) + (β0 - 1) * np.log1p(-x_grid) + + μ_path = np.empty(T + 1) + μ_path[0] = α0 / (α0 + β0) + log_post = log_prior.copy() -如果科学家使用贝叶斯定律或相关的基于似然的方法来推断$\theta$,通常在大样本量的情况下,这个逆问题会推断出一个使科学家模型$s$相对于自然模型$h$的KL散度最小化的$\theta$值。 + for t in range(T): + wt = w[t] + # P(w_t | x) = x f(w_t) + (1 - x) g(w_t) + like = x_grid * f(wt) + (1 - x_grid) * g(wt) + log_post += np.log(like) + + # 归一化 + log_post -= log_post.max() + post = np.exp(log_post) + post /= post.sum() + + μ_path[t + 1] = x_grid @ post + + return μ_path + +x_posterior_means = [learn_x_bayesian(w_mix, α0, β0) for α0, β0 in prior_params] +``` + +让我们可视化 $x$ 的后验均值如何随时间演变,从三个不同的先验信念开始。 + +```{code-cell} ipython3 +fig, ax = plt.subplots(figsize=(10, 6)) + +for i, (x_means, mean0) in enumerate(zip(x_posterior_means, prior_means)): + ax.plot(range(T_mix + 1), x_means, + label=fr'Prior mean = ${mean0:.2f}$', + color=colors[i], linewidth=2) + +ax.axhline(y=x_true, color='black', linestyle='--', + label=f'True x = {x_true}', linewidth=2) +ax.set_xlabel('$t$') +ax.set_ylabel('Posterior mean of $x$') +ax.legend() +plt.show() +``` + +图表显示,无论初始先验信念如何,所有三个后验均值最终都会收敛到 $x=0.5$ 的真实值。 + +接下来,让我们看看更长时间范围内的多次模拟,所有模拟都从均匀先验开始。 + +```{code-cell} ipython3 +set_seed() +n_paths = 20 +T_long = 10_000 + +fig, ax = plt.subplots(figsize=(10, 5)) + +for j in range(n_paths): + w_path = draw_lottery(x_true, T_long) + x_means = learn_x_bayesian(w_path, 1, 1) # 均匀先验 + ax.plot(range(T_long + 1), x_means, alpha=0.5, linewidth=1) + +ax.axhline(y=x_true, color='red', linestyle='--', + label=f'True x = {x_true}', linewidth=2) +ax.set_ylabel('Posterior mean of $x$') +ax.set_xlabel('$t$') +ax.legend() +plt.tight_layout() +plt.show() +``` + +我们可以看到 $x$ 的后验均值收敛到真实值 $x=0.5$。 + +```{solution-end} +``` diff --git a/lectures/prob_matrix.md b/lectures/prob_matrix.md index 692c8722..593d18f6 100644 --- a/lectures/prob_matrix.md +++ b/lectures/prob_matrix.md @@ -43,7 +43,7 @@ tags: [hide-output] !pip install prettytable ``` -像往常一样,我们先导入一些库 +和平常一样,我们先导入一些库 ```{code-cell} ipython3 import numpy as np @@ -89,8 +89,7 @@ $$ (eq:CDFfromdensity) 我们称这为随机变量 $X$ 的诱导概率分布。 -在实际工作中,应用统计学家往往不从底层的概率空间 $\Omega,\mathcal{F}$ 和概率测度 $\mu$ -出发进行显式推导,而是直接为某个随机变量给定其诱导分布的函数形式。 +在实际工作中,应用统计学家往往不从底层的概率空间 $\Omega,\mathcal{F}$ 和概率测度 $\mu$ 出发进行显式推导,而是直接为某个随机变量给定其诱导分布的函数形式。 本讲以及此后的多篇讲座都将采用这种做法。 @@ -100,35 +99,32 @@ $$ (eq:CDFfromdensity) 我们在 quantecon 讲座 中也涉及了这些主题。 -在本讲座的大部分内容中,我们讨论的都是固定的“总体”概率分布。 +在本讲座的大部分内容中,我们讨论的都是固定的"总体"概率分布。 这些概率分布是纯粹的数学对象。 要理解统计学家如何将概率与数据联系起来,关键是理解以下概念: * 从概率分布中进行单次抽样 -* 从同一概率分布中重复地进行独立同分布(i.i.d.)抽样,得到“样本”或“观测值” +* 从同一概率分布中重复地进行独立同分布(i.i.d.)抽样,得到"样本"或"观测值" * **统计量**,定义为样本序列的函数 * **经验分布**或**直方图**(将观测数据分箱后的经验分布),用于记录观察到的**相对频率** -* 总体概率分布可以看作是一长串 i.i.d. 抽样试验中**相对频率**的期望值。以下数学工具格定义 -了何为**期望的相对频率**: +* 总体概率分布可以看作是一长串 i.i.d. 抽样试验中**相对频率**的期望值。以下数学工具定义了何为**期望的相对频率**: - **大数定律(LLN)** - **中心极限定理(CLT)** - **标量示例** -设$X$是一个标量随机变量,它可以取$I$个可能的值 -$0, 1, 2, \ldots, I-1$,其概率为 +设$X$是一个标量随机变量,它可以取$I$个可能的值$0, 1, 2, \ldots, I-1$,其概率为 $$ - {\rm Prob}(X = i) = f_i, \quad $$ + 其中 $$ - f_i \geqslant 0, \quad \sum_i f_i = 1 . +f_i \geqslant 0, \quad \sum_i f_i = 1 . $$ 我们有时写作 @@ -141,7 +137,7 @@ $$ 考虑从$X$中抽取$N$个独立同分布的样本$x_0, x_1, \dots , x_{N-1}$。 -“独立同分布”(i.i.d.)这个术语中,“同分布”和“独立”各自意味着什么? +"独立同分布"(i.i.d.)这个术语中,"同分布"和"独立"各自意味着什么? - "同分布"意味着每次抽样都来自相同的分布。 - "独立"意味着联合分布等于边缘分布的乘积,即: @@ -180,7 +176,7 @@ $$ - 对于"频率学派"统计学家来说,**预期相对频率**就是概率分布的**全部**含义。 - 但对贝叶斯学派来说,概率的含义有所不同——在一定程度上是主观且带有个人色彩的。 - - 之所以说“在一定程度上”,是因为贝叶斯学派同样会关注相对频率。 + - 之所以说"在一定程度上",是因为贝叶斯学派同样会关注相对频率。 ## 表示概率分布 @@ -226,7 +222,7 @@ $$ 设 $X$ 是一个离散随机变量,其可能取值为:$i=0,1,\ldots,I-1 = \bar{X}$。 -这里,我们将最大索引设定为 $I-1$, 是因为这与Python的索引约定(从0开始)很好地对应。 +这里,我们将最大索引设定为 $I-1$,是因为这与Python的索引约定(从0开始)很好地对应。 定义 $f_i \equiv \textrm{Prob}\{X=i\}$ 并构造非负向量 @@ -315,7 +311,6 @@ X\in\{0,\ldots,I-1\} $$ $$ - Y\in\{0,\ldots,J-1\} $$ @@ -406,7 +401,7 @@ $$ =\frac{ \sum_{i}f_{ij} }{ \sum_{i}f_{ij}}=1 $$ -**注:** 条件概率的定义实际上蕴含了**贝叶斯定律**: +**注:** 条件概率的定义实际上蕴含了**贝叶斯定理**: $$ @@ -469,8 +464,8 @@ $$ 假设只有两个时期: -* $t=0$ 表示“今天” -* $t=1$ 表示“明天” +* $t=0$ 表示"今天" +* $t=1$ 表示"明天" 令 $X(0)$ 为在 $t=0$ 时实现的随机变量,$X(1)$ 为在 $t=1$ 时实现的随机变量。 @@ -498,6 +493,7 @@ $$ 如果随机变量 X 和 Y 满足以下条件,则称它们是统计**独立**的: $$ + \textrm{Prob}\{X=i,Y=j\}={f_ig_j} $$ @@ -543,9 +539,9 @@ $$ 让我们用一个小故事来说明这个例子。 -假设你去参加一个工作面试,你要么通过要么失败。 +假设你去参加一个工作面试,你要么通过要么失败。 -你有5%的机会通过面试,而且你知道如果通过的话,你的日薪会在300~400之间均匀分布。 +你有5%的机会通过面试,而且你知道如果通过的话,你的日薪会在300~400之间均匀分布。 我们可以用以下概率来描述你的日薪这个离散-连续变量: @@ -622,7 +618,7 @@ $$ \textrm{Prob}(Y=j)=\sum_i{f_{ij}}=v_j $$ 让我们写一段 Python 代码,用来生成大样本并计算相对频率。 -这段代码将帮助我们检验“抽样”分布是否与“总体”分布一致——从而确认总体分布确实给出了在大样本中应当期望 +这段代码将帮助我们检验"抽样"分布是否与"总体"分布一致——从而确认总体分布确实给出了在大样本中应当期望 的相对频率。 ```{code-cell} ipython3 @@ -734,7 +730,6 @@ $$ \cdots\cdots\cdots & \vdots & \cdots\cdots\cdots & \cdots\cdots\cdots \\ y=y_1 & \vdots & \frac{0.3}{0.4}=0.75 & \frac{0.1}{0.4}=0.25 \\ \cdots\cdots\cdots & \vdots & \cdots\cdots\cdots & \cdots\cdots\cdots \\ - y=y_2 & \vdots & \frac{0.2}{0.6}\approx 0.33 & \frac{0.4}{0.6}\approx0.67 \\ \end{array}\right] $$ @@ -751,8 +746,7 @@ $$ 可以看出,总体的计算结果与我们上面得到的样本结果非常接近。 -接下来,我们将把之前用到的一些功能封装到一个 Python 类中,以便对任意给定的离散二元联合分布进行 -类似的分析。 +接下来,我们将把之前用到的一些功能封装到一个Python类中,以便对任意给定的离散二元联合分布进行类似的分析。 ```{code-cell} ipython3 class discrete_bijoint: @@ -878,7 +872,7 @@ d.joint_tb() ``` ```{code-cell} ipython3 -# 样本边缘分布 +# 样本边际分布 d.draw(1_000_000) d.marg_dist() ``` @@ -983,7 +977,7 @@ ax.set_xticks([]) plt.show() ``` -接下来我们可以使用内置的`numpy`函数进行模拟,并从样本均值和方差计算**样本**边缘分布。 +然后我们可以使用内置的`numpy`函数来进行模拟,并从样本均值和方差计算**样本**边际分布。 ```{code-cell} ipython3 μ= np.array([0, 5]) @@ -1052,7 +1046,7 @@ $$ \end{aligned} $$ -让我们从具有上述均值和方差的正态分布中抽样,检验我们的近似值有多准确。 +让我们从具有上述均值和方差的正态分布中采样,检验我们的近似值有多准确。 ```{code-cell} ipython3 # 离散化均值 @@ -1061,7 +1055,7 @@ $$ # 离散化标准差 σx = np.sqrt(np.dot((x - μx)**2, z)) -# 抽样 +# 采样 zz = np.random.normal(μx, σx, 1_000_000) plt.hist(zz, bins=300, density=True, alpha=0.3, range=[-10, 10]) plt.show() @@ -1182,6 +1176,7 @@ $$ 第二行是在 $X=1$ 条件下 $Y=j, j=0,1$ 的概率。 注意 + - $\sum_{j}\rho_{ij}= \frac{ \sum_{j}\rho_{ij}}{ \sum_{j}\rho_{ij}}=1$,所以 $\rho$ 的每一行都是一个概率分布(每一列则不是)。 ## 耦合 @@ -1258,7 +1253,6 @@ $$ 为了验证这是一个耦合,我们检查 $$ - \begin{aligned} (1-q)(1-r)+(1-q)r+q(1-r)+qr &=1\\ \mu_{0}= (1-q)(1-r)+(1-q)r & =1-q\\ @@ -1285,6 +1279,7 @@ $$ $$ \begin{aligned} 1-r+r-q+q &=1\\ + \mu_{0}& = 1-q\\ \mu_{1}& = q\\ \nu_{0}& = 1-r\\ @@ -1292,11 +1287,11 @@ $$ \end{aligned} $$ -因此,我们提出的两个联合分布具有相同的边缘分布。 +因此,我们提出的两个联合分布具有相同的边际分布。 但是联合分布本身不同。 -因此,多个联合分布 $[f_{ij}]$ 可以具有相同的边缘分布。 +因此,多个联合分布 $[f_{ij}]$ 可以具有相同的边际分布。 **注释:** - 耦合在最优传输问题和马尔可夫过程中很重要。 @@ -1305,7 +1300,7 @@ $$ 假设 $X_1, X_2, \dots, X_n$ 是 $N$ 个随机变量,并且 -* 它们的边缘分布是 $F_1(x_1), F_2(x_2),\dots, F_N(x_N)$,并且 +* 它们的边际分布是 $F_1(x_1), F_2(x_2),\dots, F_N(x_N)$,并且 * 它们的联合分布是$H(x_1,x_2,\dots,x_N)$ @@ -1321,15 +1316,15 @@ $$ C(u_1,u_2,\dots,u_n) = H[F^{-1}_1(u_1),F^{-1}_2(u_2),\dots,F^{-1}_N(u_N)] $$ -反过来,给定单变量**边缘分布**$F_1(x_1), F_2(x_2),\dots,F_N(x_N)$和一个Copula函数$C(\cdot)$,函数$H(x_1,x_2,\dots,x_N) = C(F_1(x_1), F_2(x_2),\dots,F_N(x_N))$是$F_1(x_1), F_2(x_2),\dots,F_N(x_N)$的一个**耦合**。 +反过来,给定单变量**边际分布**$F_1(x_1), F_2(x_2),\dots,F_N(x_N)$和一个Copula函数$C(\cdot)$,函数$H(x_1,x_2,\dots,x_N) = C(F_1(x_1), F_2(x_2),\dots,F_N(x_N))$是$F_1(x_1), F_2(x_2),\dots,F_N(x_N)$的一个**耦合**。 -因此,对于给定的边缘分布,当相关的单变量随机变量不独立时,我们可以使用Copula函数来确定联合分布。 +因此,对于给定的边际分布,当相关的单变量随机变量不独立时,我们可以使用Copula函数来确定联合分布。 -Copula 函数常被用来描述随机变量之间的**相依性**。 +Copula函数常被用来描述随机变量之间的**相依性**。 -**离散边缘分布** +**离散边际分布** -如上所述,对于两个给定的边缘分布,可能存在多个耦合。 +如上所述,对于两个给定的边际分布,可能存在多个耦合。 例如,考虑两个随机变量 $X, Y$ 的分布为 @@ -1387,7 +1382,7 @@ ymtb.add_row([1, r_hat]) print(ymtb) ``` -现在让我们用两个边缘分布,一个是$X$的,另一个是$Y$的,来构造两个不同的耦合。 +现在让我们用两个边际分布,一个是$X$的,另一个是$Y$的,来构造两个不同的耦合。 对于第一个联合分布: @@ -1404,7 +1399,7 @@ $$ \end{array}\right] $$ -让我们使用Python来构造这个联合分布,然后验证其边缘分布是否符合要求。 +让我们使用Python来构造这个联合分布,然后验证其边际分布是否符合要求。 ```{code-cell} ipython3 # 定义参数 @@ -1459,7 +1454,7 @@ c1_r_hat = sum(c1[1, :] == 1)/draws1 # 打印输出 print("x的边缘分布") c1_x_mtb = pt.PrettyTable() -c1_x_mtb.field_names = ['c1_x_值', 'c1_x_概率'] +c1_x_mtb.field_names = ['c1_x_值', 'c1_x_概率'] c1_x_mtb.add_row([0, 1-c1_q_hat]) c1_x_mtb.add_row([1, c1_q_hat]) print(c1_x_mtb) @@ -1547,7 +1542,7 @@ c2_ymtb.add_row([1, c2_r_hat]) print(c2_ymtb) ``` - -经过验证,联合分布 $c_1$ 和 $c_2$ 具有相同的 $X$ 和 $Y$ 的边缘分布。 +经过验证,联合分布 $c_1$ 和 $c_2$ 具有相同的 $X$ 和 $Y$ 的边际分布。 因此它们都是 $X$ 和 $Y$ 的耦合。 + diff --git a/lectures/stats_examples.md b/lectures/stats_examples.md new file mode 100644 index 00000000..682a6f37 --- /dev/null +++ b/lectures/stats_examples.md @@ -0,0 +1,534 @@ +--- +jupytext: + text_representation: + extension: .myst + format_name: myst + format_version: 0.13 + jupytext_version: 1.13.8 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# 一些概率分布 + +本讲座是{doc}`这个关于矩阵统计的讲座 `的补充内容。 + +它描述了一些常见的分布,并使用Python从这些分布中进行采样。 + +它还描述了一种通过转换均匀概率分布的样本来从你自己设计的任意概率分布中采样的方法。 + +除了Anaconda中已有的库外,本讲座还需要以下库: + +```{code-cell} ipython3 +--- +tags: [hide-output] +--- +!pip install prettytable +``` + +像往常一样,我们先导入一些库 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +import prettytable as pt +from mpl_toolkits.mplot3d import Axes3D +from matplotlib_inline.backend_inline import set_matplotlib_formats +set_matplotlib_formats('retina') +``` + +## 一些离散概率分布 + +让我们编写一些Python代码来计算单变量随机变量的均值和方差。 + +我们将使用代码来 + +- 从概率分布计算总体均值和方差 +- 生成N个独立同分布的样本并计算样本均值和方差 +- 比较总体和样本的均值和方差 + +## 几何分布 + +离散几何分布的概率质量函数为 + +$$ +\textrm{Prob}(X=k)=(1-p)^{k-1}p,k=1,2, \ldots, \quad p \in (0,1) +$$ + +其中$k = 1, 2, \ldots$是第一次成功之前的试验次数。 + +这个单参数概率分布的均值和方差为 + +$$ +\begin{aligned} +\mathbb{E}(X) & =\frac{1}{p}\\\mathbb{Var}(X) & =\frac{1-p}{p^2} +\end{aligned} +$$ + +让我们使用Python从该分布中抽取观测值,并将样本均值和方差与理论结果进行比较。 + +```{code-cell} ipython3 +# 指定参数 +p, n = 0.3, 1_000_000 + +# 从分布中抽取观测值 +x = np.random.geometric(p, n) + +# 计算样本均值和方差 +μ_hat = np.mean(x) +σ2_hat = np.var(x) + +print("样本均值为:", μ_hat, "\n样本方差为:", σ2_hat) + +# 与理论结果比较 +print("\n总体均值为:", 1/p) +print("总体方差为:", (1-p)/(p**2)) +``` + +## 帕斯卡(负二项)分布 + +考虑一个独立伯努利试验序列。 + +设 $p$ 为成功的概率。 + +设 $X$ 为在获得 $r$ 次成功之前失败的次数的随机变量。 + +其分布为 + +$$ +\begin{aligned} +X & \sim NB(r,p) \\ +\textrm{Prob}(X=k;r,p) & = \begin{bmatrix}k+r-1 \\ r-1 \end{bmatrix}p^r(1-p)^{k} +\end{aligned} +$$ + +这里,我们从 $k+r-1$ 个可能的结果中选择,因为最后一次抽取根据定义必须是成功的。 + +我们计算得到均值和方差为 + +$$ +\begin{aligned} +\mathbb{E}(X) & = \frac{k(1-p)}{p} \\ +\mathbb{V}(X) & = \frac{k(1-p)}{p^2} +\end{aligned} +$$ + +```{code-cell} ipython3 +# specify parameters +r, p, n = 10, 0.3, 1_000_000 + +# draw observations from the distribution +x = np.random.negative_binomial(r, p, n) + +# compute sample mean and variance +μ_hat = np.mean(x) +σ2_hat = np.var(x) + +print("The sample mean is: ", μ_hat, "\nThe sample variance is: ", σ2_hat) +print("\nThe population mean is: ", r*(1-p)/p) +print("The population variance is: ", r*(1-p)/p**2) +``` + +## 纽科姆-本福特分布 + +**纽科姆-本福特定律**适用于许多数据集,例如向税务机关报告的收入,其中首位数字更可能是小数而不是大数。 + +参见 + +本福特概率分布为 + +$$ +\textrm{Prob}\{X=d\}=\log _{10}(d+1)-\log _{10}(d)=\log _{10}\left(1+\frac{1}{d}\right) +$$ + +其中 $d\in\{1,2,\cdots,9\}$ 可以被视为数字序列中的**首位数字**。 + +这是一个定义明确的离散分布,因为我们可以验证概率是非负的且和为 $1$。 + +$$ +\log_{10}\left(1+\frac{1}{d}\right)\geq0,\quad\sum_{d=1}^{9}\log_{10}\left(1+\frac{1}{d}\right)=1 +$$ + +本福特分布的均值和方差为 + +$$ +\begin{aligned} +\mathbb{E}\left[X\right] &=\sum_{d=1}^{9}d\log_{10}\left(1+\frac{1}{d}\right)\simeq3.4402 \\ +\mathbb{V}\left[X\right] & =\sum_{d=1}^{9}\left(d-\mathbb{E}\left[X\right]\right)^{2}\log_{10}\left(1+\frac{1}{d}\right)\simeq6.0565 +\end{aligned} +$$ + +我们使用`numpy`来验证上述结果并计算均值和方差。 + +```{code-cell} ipython3 +Benford_pmf = np.array([np.log10(1+1/d) for d in range(1,10)]) +k = np.arange(1, 10) + +# mean +mean = k @ Benford_pmf + +# variance +var = ((k - mean) ** 2) @ Benford_pmf + +# verify sum to 1 +print(np.sum(Benford_pmf)) +print(mean) +print(var) +``` + +```{code-cell} ipython3 +# 绘制分布图 +plt.plot(range(1,10), Benford_pmf, 'o') +plt.title('本福特分布') +plt.show() +``` + +现在让我们来看看一些连续型随机变量。 + +## 一元高斯分布 + +我们用 + +$$ +X \sim N(\mu,\sigma^2) +$$ + +来表示概率分布 + +$$f(x|u,\sigma^2)=\frac{1}{\sqrt{2\pi \sigma^2}}e^{[-\frac{1}{2\sigma^2}(x-u)^2]} $$ + +在下面的例子中,我们设定 $\mu = 0, \sigma = 0.1$。 + +```{code-cell} ipython3 +# 指定参数 +μ, σ = 0, 0.1 + +# 指定抽样次数 +n = 1_000_000 + +# 从分布中抽取观测值 +x = np.random.normal(μ, σ, n) + +# 计算样本均值和方差 +μ_hat = np.mean(x) +σ_hat = np.std(x) + +print("样本均值为:", μ_hat) +print("样本标准差为:", σ_hat) +``` + +```{code-cell} ipython3 +# 比较 +print(μ-μ_hat < 1e-3) +print(σ-σ_hat < 1e-3) +``` + +## 均匀分布 + +$$ +\begin{aligned} +X & \sim U[a,b] \\ +f(x)& = \begin{cases} \frac{1}{b-a}, & a \leq x \leq b \\ \quad0, & \text{其他} \end{cases} +\end{aligned} +$$ + +总体均值和方差为 + +$$ +\begin{aligned} +\mathbb{E}(X) & = \frac{a+b}{2} \\ +\mathbb{V}(X) & = \frac{(b-a)^2}{12} +\end{aligned} +$$ + +```{code-cell} ipython3 +# 指定参数 +a, b = 10, 20 + +# 指定抽样次数 +n = 1_000_000 + +# 从分布中抽取观测值 +x = a + (b-a)*np.random.rand(n) + +# 计算样本均值和方差 +μ_hat = np.mean(x) +σ2_hat = np.var(x) + +print("样本均值为:", μ_hat, "\n样本方差为:", σ2_hat) +print("\n总体均值为:", (a+b)/2) +print("总体方差为:", (b-a)**2/12) +``` + +## 混合离散-连续分布 + +让我们用一个小故事来说明这个例子。 + +假设你去参加一个工作面试,你要么通过要么失败。 + +你有5%的机会通过面试,而且你知道如果通过的话,你的日薪会在300~400之间均匀分布。 + +我们可以用以下概率来描述你的日薪这个离散-连续变量: + +$$ +P(X=0)=0.95 +$$ + +$$ +P(300\le X \le 400)=\int_{300}^{400} f(x)\, dx=0.05 +$$ + +$$ +f(x) = 0.0005 +$$ + +让我们先生成一个随机样本并计算样本矩。 + +```{code-cell} ipython3 +x = np.random.rand(1_000_000) +# x[x > 0.95] = 100*x[x > 0.95]+300 +x[x > 0.95] = 100*np.random.rand(len(x[x > 0.95]))+300 +x[x <= 0.95] = 0 + +μ_hat = np.mean(x) +σ2_hat = np.var(x) + +print("样本均值是: ", μ_hat, "\n样本方差是: ", σ2_hat) +``` + +可以计算解析均值和方差: + +$$ +\begin{aligned} +\mu &= \int_{300}^{400}xf(x)dx \\ +&= 0.0005\int_{300}^{400}xdx \\ +&= 0.0005 \times \frac{1}{2}x^2\bigg|_{300}^{400} +\end{aligned} +$$ + +$$ +\begin{aligned} +\sigma^2 &= 0.95\times(0-17.5)^2+\int_{300}^{400}(x-17.5)^2f(x)dx \\ +&= 0.95\times17.5^2+0.0005\int_{300}^{400}(x-17.5)^2dx \\ +&= 0.95\times17.5^2+0.0005 \times \frac{1}{3}(x-17.5)^3 \bigg|_{300}^{400} +\end{aligned} +$$ + +```{code-cell} ipython3 +mean = 0.0005*0.5*(400**2 - 300**2) +var = 0.95*17.5**2+0.0005/3*((400-17.5)**3-(300-17.5)**3) +print("mean: ", mean) +print("variance: ", var) +``` + +## 从特定分布中抽取随机数 + +假设我们有一个可以生成均匀随机变量的伪随机数,即具有如下概率分布: + +$$ +\textrm{Prob}\{\tilde{X}=i\}=\frac{1}{I},\quad i=0,\ldots,I-1 +$$ + +我们如何将$\tilde{X}$转换为随机变量$X$,使得$\textrm{Prob}\{X=i\}=f_i,\quad i=0,\ldots,I-1$, +其中$f_i$是在$i=0,1,\dots,I-1$上的任意离散概率分布? + +关键工具是累积分布函数(CDF)的逆函数。 + +注意,分布的CDF是单调且非递减的,取值在$0$和$1$之间。 + +我们可以按以下方式抽取具有已知CDF的随机变量$X$的样本: + +- 从$[0,1]$上的均匀分布中抽取随机变量$u$ +- 将$u$的样本值代入目标CDF的**"逆函数"**得到$X$ +- $X$具有目标CDF + +因此,知道分布的**"逆"**CDF就足以从这个分布中进行模拟。 + +```{note} +这个方法要求"逆"CDF必须存在。 +``` + +逆CDF定义为: + +$$ +F^{-1}(u)\equiv\inf \{x\in \mathbb{R}: F(x) \geq u\} \quad(00$。 + +其密度函数为 + +$$ +\quad f(x)=\lambda e^{-\lambda x} +$$ + +其累积分布函数为 + +$$ +F(x)=\int_{0}^{\infty}\lambda e^{-\lambda x}=1-e^{-\lambda x} +$$ + +设$U$服从$[0,1]$上的均匀分布。 + +$X$是一个随机变量,满足$U=F(X)$。 + +可以从以下推导得出$X$的分布: + +$$ +\begin{aligned} +U& =F(X)=1-e^{-\lambda X}\qquad\\ +\implies & \quad -U=e^{-\lambda X}\\ +\implies& \quad \log(1-U)=-\lambda X\\ +\implies & \quad X=\frac{(1-U)}{-\lambda} +\end{aligned} +$$ + +让我们从$U[0,1]$中抽取$u$并计算$x=\frac{log(1-U)}{-\lambda}$。 + +我们将检验$X$是否似乎服从**连续几何**(指数)分布。 + +让我们用`numpy`来检验。 + +```{code-cell} ipython3 +n, λ = 1_000_000, 0.3 + +# 生成均匀分布随机数 +u = np.random.rand(n) + +# 转换 +x = -np.log(1-u)/λ + +# 生成指数分布 +x_g = np.random.exponential(1 / λ, n) + +# 绘图并比较 +plt.hist(x, bins=100, density=True) +plt.show() +``` + +```{code-cell} ipython3 +plt.hist(x_g, bins=100, density=True, alpha=0.6) +plt.show() +``` + +**几何分布** + +设 $X$ 服从几何分布,即 + +$$ +\begin{aligned} +\textrm{Prob}(X=i) & =(1-\lambda)\lambda^i,\quad\lambda\in(0,1), \quad i=0,1,\dots \\ + & \sum_{i=0}^{\infty}\textrm{Prob}(X=i)=1\longleftrightarrow(1- \lambda)\sum_{i=0}^{\infty}\lambda^i=\frac{1-\lambda}{1-\lambda}=1 +\end{aligned} +$$ + +其累积分布函数为 + +$$ +\begin{aligned} +\textrm{Prob}(X\le i)& =(1-\lambda)\sum_{j=0}^{i}\lambda^i\\ +& =(1-\lambda)[\frac{1-\lambda^{i+1}}{1-\lambda}]\\ +& =1-\lambda^{i+1}\\ +& =F(X)=F_i \quad +\end{aligned} +$$ + +再次,设 $\tilde{U}$ 服从均匀分布,我们要找到满足 $F(X)=\tilde{U}$ 的 $X$。 + +让我们从以下推导 $X$ 的分布: + +$$ +\begin{aligned} +\tilde{U} & =F(X)=1-\lambda^{x+1}\\ +1-\tilde{U} & =\lambda^{x+1}\\ +\log(1-\tilde{U})& =(x+1)\log\lambda\\ +\frac{\log(1-\tilde{U})}{\log\lambda}& =x+1\\ +\frac{\log(1-\tilde{U})}{\log\lambda}-1 &=x +\end{aligned} +$$ + +然而,对于任何 $x\geq0$,$\tilde{U}=F^{-1}(X)$ 可能不是整数。 + +所以令 + +$$ +x=\lceil\frac{\log(1-\tilde{U})}{\log\lambda}-1\rceil +$$ + +其中 $\lceil . \rceil$ 是向上取整函数。 + +因此 $x$ 是使离散几何累积分布函数大于或等于 $\tilde{U}$ 的最小整数。 + +我们可以通过以下 `numpy` 程序验证 $x$ 确实服从几何分布。 + +```{note} +指数分布是几何分布的连续模拟。 +``` + +```{code-cell} ipython3 +n, λ = 1_000_000, 0.8 + +# 生成均匀分布随机数 +u = np.random.rand(n) + +# 转换 +x = np.ceil(np.log(1-u)/np.log(λ) - 1) + +# 生成几何分布 +x_g = np.random.geometric(1-λ, n) + +# 绘图并比较 +plt.hist(x, bins=150, density=True) +plt.show() +``` + + +```{code-cell} ipython3 +np.random.geometric(1-λ, n).max() +``` + +```{code-cell} ipython3 +np.log(0.4)/np.log(0.3) +``` + +```{code-cell} ipython3 +plt.hist(x_g, bins=150, density=True, alpha=0.6) +plt.show() +``` + diff --git a/lectures/two_auctions.md b/lectures/two_auctions.md index 000733f6..9a46e029 100644 --- a/lectures/two_auctions.md +++ b/lectures/two_auctions.md @@ -189,17 +189,17 @@ $$ import numpy as np 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'] import seaborn as sns import scipy.stats as stats import scipy.interpolate as interp # 用于绘图 -plt.rcParams.update({"text.usetex": True, 'font.size': 14}) -colors = plt. rcParams['axes.prop_cycle'].by_key()['color'] +colors = plt.rcParams['axes.prop_cycle'].by_key()['color'] + +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" +mpl.font_manager.fontManager.addfont(FONTPATH) +plt.rcParams['font.family'] = ['Source Han Serif SC'] # 确保笔记本生成相同的随机数 np.random.seed(1337) diff --git a/lectures/wald_friedman.md b/lectures/wald_friedman.md index c88f40f4..6811af3f 100644 --- a/lectures/wald_friedman.md +++ b/lectures/wald_friedman.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.11.5 + jupytext_version: 1.17.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -33,26 +33,30 @@ kernelspec: ## 概述 -本讲座描述了二战期间提交给弥尔顿·弗里德曼和W·艾伦·沃利斯的一个统计决策问题,当时他们是分析师在 +这是关于一个统计决策问题的两个讲座中的第一个。这个问题是二战期间,当弥尔顿·弗里德曼和W·艾伦·沃利斯在哥伦比亚大学的美国政府统计研究组担任分析师时,一位美国海军上尉向他们提出的。 -美国哥伦比亚大学政府统计研究组。 +这个问题促使亚伯拉罕·瓦尔德{cite}`Wald47`提出了**序贯分析**,这是一种与动态规划密切相关的统计决策问题处理方法。 -这个问题促使Abraham Wald {cite}`Wald47` 提出了**序贯分析**, -这是一种与动态规划密切相关的统计决策问题方法。 +本讲座及其{doc}`续篇 `延续了{doc}`之前讲座 `的精神,从频率主义和贝叶斯两个不同的角度来处理这个问题。 -在本讲中,我们将动态规划算法应用于Friedman、Wallis和Wald的问题。 +在本讲中,我们从一位统计学家的角度描述Wald的问题表述,这位统计学家遵循Neyman-Pearson的频率派统计学传统,关注假设检验,并因此使用大数定律来研究在给定**假设**下特定统计量的极限性质,即,一个**参数**向量确定了统计学家感兴趣的统计模型簇中的某个特定成员。 -主要涉及的概念包括: + * 从{doc}`这节关于频率派和贝叶斯统计的讲座`中,请记住频率派统计学家经常计算随机变量序列的函数,以参数向量为条件。 + +在{doc}`这个相关讲座`中,我们将讨论另一种表述方法,它采用**贝叶斯统计学家**的视角,将参数视为与他所关心的可观测变量共同分布的随机变量。 + +因为我们采用的是关注在不同参数值(即不同**假设**)条件下相对频率的频率派视角,本讲的关键概念包括: -- 贝叶斯定理 -- 动态规划 - 第一类和第二类统计错误 - 第一类错误是指在原假设为真时拒绝原假设 - 第二类错误是指在原假设为假时接受原假设 -- Abraham Wald的**序贯概率比检验** -- 统计检验的**功效** +- 频率派统计检验的**检验效能** +- 频率派统计检验的**显著性水平** + - 统计检验的**临界区域** - **一致最优检验** +- 大数定律(LLN)在解释频率统计检验的**功效**和**规模**中的作用 +- 亚伯拉罕·瓦尔德的**序贯概率比检验** 我们先导入一些包: @@ -64,786 +68,1196 @@ FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" mpl.font_manager.fontManager.addfont(FONTPATH) plt.rcParams['font.family'] = ['Source Han Serif SC'] -from numba import jit, prange, float64, int64 +from numba import njit, prange, vectorize, jit from numba.experimental import jitclass from math import gamma +from scipy.integrate import quad +from scipy.stats import beta +from collections import namedtuple +import pandas as pd +import scipy as sp ``` -本讲座使用了{doc}`本讲座 `、{doc}`本讲座 `和{doc}`本讲座 `中研究的概念。 +本讲座运用了{doc}`似然比过程讲座`和{doc}`贝叶斯学习讲座`中研究的概念。 -## 问题的起源 +## 问题的来源 -在米尔顿·弗里德曼与罗斯·弗里德曼1998年合著的《两个幸运儿》一书第137-139页{cite}`Friedman98`中,米尔顿·弗里德曼描述了二战期间他和艾伦·沃利斯在哥伦比亚大学美国政府统计研究组工作时遇到的一个问题。 +在米尔顿·弗里德曼与罗斯·弗里德曼1998年合著的《两个幸运儿》一书的137-139页{cite}`Friedman98`中,米尔顿·弗里德曼描述了二战期间他和艾伦·沃利斯在哥伦比亚大学美国政府统计研究组工作时遇到的一个问题。 ```{note} -参见艾伦·沃利斯1980年发表的文章{cite}`wallis1980statistical`第25和26页,其中讲述了二战期间在哥伦比亚大学统计研究组的这段经历,以及哈罗德·霍特林对问题形成所做的重要贡献。另见珍妮弗·伯恩斯关于米尔顿·弗里德曼的著作{cite}`Burns_2023`第5章。 +参见艾伦·沃利斯1980年发表的文章{cite}`wallis1980statistical`第25和26页,其中讲述了二战期间在哥伦比亚大学统计研究组的这段经历,以及哈罗德·霍特林对问题形成所作出的重要贡献。另见珍妮弗·伯恩斯关于米尔顿·弗里德曼的著作{cite}`Burns_2023`第5章。 ``` -让我们听听米尔顿·弗里德曼是如何讲述这件事的 +让我们听听米尔顿·弗里德曼是如何讲述这件事的: -> 为了理解这个故事,有必要先了解一个 +> 要理解这个故事,需要先了解一个简单的统计问题及其标准处理程序。序贯分析由此产生的实际问题就很合适。海军有两种备选的炮弹设计(比如说A和B),想要确定哪一个更好。为此,海军进行了一系列成对的试射。每一轮中,如果A的表现优于B,则给A记1分,B记0分;反之,如果A的表现不如B,则给A记0分,B记1分。海军请统计学家 -> 这是一个简单的统计问题,以及处理它的标准程序。让我们以顺序分析发展的实际问题为例。海军有两种备选的炮弹设计(比如说A和B)。他们想要确定哪一种更好。为此,他们进行了一系列成对的发射试验。在每一轮中,如果A的性能优于B,则给A赋值1,B赋值0;反之,如果A的性能劣于B,则给A赋值0,B赋值1。海军请统计学家告诉他们如何进行测试并分析结果。 +> 如何进行测试以及如何分析结果。 -> 标准的统计学答案是指定发射次数(比如1,000次)和一对百分比(例如,53%和47%),并告诉客户:如果A在超过53%的发射中获得1,则可以认为A更优;如果A在少于47%的发射中获得1,则可以认为B更优;如果百分比在47%和53%之间,则无法得出任何一方更优的结论。 +> 标准的统计答案是指定发射次数(比如1,000次)和一对百分比(例如53%和47%),并告诉客户如果A在超过53%的发射中获得1分,就可以认为A更优;如果在少于47%的发射中获得1分,则可以认为B更优;如果百分比在47%到53%之间,则两者都不能被认为更优。 -> 当艾伦·沃利斯与(海军)加勒特·L·施莱尔上尉讨论这样一个问题时, -> 上尉提出反对意见,引用艾伦的说法,这样的测试可能会造成浪费。如果 -> 像施莱尔这样明智且经验丰富的军需官在现场,他在看到前几千发甚至 -> 前几百发[弹药]后就会发现实验不需要完成,要么是因为新方法明显 -> 较差,要么是因为它明显优于预期$\ldots$。 +> 当Allen Wallis与(海军)Garret L. Schuyler上尉讨论这个问题时,上尉反对这样的测试,引用Allen的说法,这可能会造成浪费。如果像Schuyler这样明智且经验丰富的军需官在现场,他在前几千发甚至前几百发[弹药]后就会发现实验不需要完成,要么是因为新方法明显较差,要么是因为它明显优于预期$\ldots$。 -弗里德曼和沃利斯为这个问题苦苦挣扎,但在意识到他们无法解决后, -向亚伯拉罕·瓦尔德描述了这个问题。 +Friedman和Wallis研究了这个问题一段时间但没有完全解决它。 -这让瓦尔德开始了通往*序贯分析*{cite}`Wald47`的道路。 +意识到这一点后,他们把这个问题告诉了Abraham Wald。 -我们将使用动态规划来阐述这个问题。 +这让Wald走上了一条创造*序贯分析*{cite}`Wald47`的道路。 -## 动态规划方法 +## Neyman-Pearson公式 -以下对问题的介绍紧密遵循德米特里·伯斯克卡斯在**动态规划与随机控制**{cite}`Bertekas75`中的处理方式。 +从描述美国海军告诉G. S. Schuyler上尉使用的测试背后的理论开始会很有帮助。 -决策者可以观察一个随机变量$z$的一系列抽样。 +Schuyler上尉的疑虑促使他向Milton Friedman和Allen Wallis表达了他的推测,即存在更好的实践程序。 -他(或她)想要知道是概率分布$f_0$还是$f_1$支配着$z$。 +显然,海军当时要求Schuyler上校使用当时最先进的Neyman-Pearson假设检验。 -在已知连续观测值是从分布$f_0$中抽取的条件下,这个随机变量序列是独立同分布的(IID)。 +我们将依据Abraham Wald的{cite}`Wald47`对Neyman-Pearson理论的优雅总结。 -在已知连续观测值是从分布$f_1$中抽取的条件下,这个随机变量序列也是独立同分布的(IID)。 +请注意以下设置特点: -但观察者并不知道是哪一个分布生成了这个序列。 +- 假定*固定*样本量$n$ +- 应用大数定律(在不同概率模型条件下)来解释Neyman-Pearson理论中定义的第一类错误和第二类错误的概率$\alpha$和$\beta$ -由[可交换性和贝叶斯更新](https://python.quantecon.org/exchangeable.html)中解释的原因,这意味着该序列不是独立同分布的。 +在**序贯分析**{cite}`Wald47`第一章中,Abraham Wald总结了Neyman-Pearson的假设检验方法。 -观察者有需要学习的东西,即观测值是从$f_0$还是从$f_1$中抽取的。 +Wald将问题框定为对部分已知的概率分布做出决策。 -决策者想要决定是哪一个分布在生成这些结果。 +(你必须假设*某些*内容是已知的,才能提出一个明确的问题 -- 通常,*某些*意味着*很多*) -我们采用贝叶斯公式。 +通过限制未知部分,Wald使用以下简单结构来说明主要思想: -决策者从先验概率开始 +- 决策者想要决定两个分布$f_0$、$f_1$中哪一个支配独立同分布随机变量$z$。 +- 原假设$H_0$是指$f_0$支配数据的陈述。 +- 备择假设$H_1$是指$f_1$支配数据的陈述。 +- 问题是基于固定数量$n$个独立观测值$z_1, z_2, \ldots, z_n$设计并分析一个检验原假设$H_0$对备择假设$H_1$的检验。 -$$ -\pi_{-1} = -\mathbb P \{ f = f_0 \mid \textrm{ no observations} \} \in (0, 1) -$$ - -在观察到$k+1$个观测值$z_k, z_{k-1}, \ldots, z_0$后,他更新其个人对观测值由分布$f_0$描述的概率为 - -$$ -\pi_k = \mathbb P \{ f = f_0 \mid z_k, z_{k-1}, \ldots, z_0 \} -$$ +引用Abraham Wald的话: -这是通过递归应用贝叶斯法则计算得出: +> 导致接受或拒绝[零]假设的检验程序,简单来说就是一个规则,它为每个可能的样本量 +> $n$规定是否应该基于该样本接受或拒绝[零]假设。这也可以表述如下:检验程序 +> 就是将所有可能的样本量$n$的总体划分为两个互斥的部分,比如说第1部分和第2部分, +> 同时应用这样的规则:如果观察到的样本包含在第2部分中,则接受[零]假设。第1部分 +> 也被称为临界区域。由于第2部分是所有不包含在第1部分中的样本量$n$的总体, +> 第2部分由第1部分唯一确定。因此,选择检验程序等同于确定临界区域。 -$$ -\pi_{k+1} = \frac{ \pi_k f_0(z_{k+1})}{ \pi_k f_0(z_{k+1}) + (1-\pi_k) f_1 (z_{k+1}) }, -\quad k = -1, 0, 1, \ldots -$$ +让我们继续听Wald的话: -在观察到$z_k, z_{k-1}, \ldots, z_0$后,决策者认为$z_{k+1}$具有概率分布 +> Neyman和Pearson提出了以下选择临界区域的考虑因素:在接受或拒绝$H_0$时, +> 我们可能犯两种错误。当$H_0$为真而我们拒绝它时,我们犯第一类错误;当 +> $H_1$为真而我们接受$H_0$时,我们犯第二类错误。在选定特定的临界区域 +> $W$之后,犯第一类错误的概率以及犯第二类错误的概率 -$$ -f_{{\pi}_k} (v) = \pi_k f_0(v) + (1-\pi_k) f_1 (v) , -$$ +> 第一类错误是唯一确定的。第一类错误的概率等于在假设$H_0$为真的条件下,观察到的样本落入临界区域$W$的概率。第二类错误的概率等于在假设$H_1$为真的条件下,概率落在临界区域$W$之外的概率。对于任何给定的临界区域$W$,我们用$\alpha$表示第一类错误的概率,用$\beta$表示第二类错误的概率。 -这是分布$f_0$和$f_1$的混合,其中$f_0$的权重是$f = f_0$的后验概率[^f1]。 +让我们仔细听听Wald如何运用大数定律来解释$\alpha$和$\beta$: -为了说明这样的分布,让我们检查一些beta分布的混合。 +> 概率$\alpha$和$\beta$有以下重要的实际解释:假设我们抽取大量规模为$n$的样本。设$M$为抽取的样本数。假设对于这$M$个样本中的每一个,如果样本落入$W$则拒绝$H_0$,如果样本落在$W$之外则接受$H_0$。通过这种方式,我们做出$M$个拒绝或接受的判断。这些判断中的一些通常会是错误的。如果$H_0$为真且$M$很大,则错误判断的比例(即错误判断数除以$M$)约为$\alpha$的概率接近于$1$(即几乎可以确定)。如果$H_1$为真,则错误判断的比例约为 -具有参数 $a$ 和 $b$ 的贝塔概率分布的密度函数为 +> 错误陈述的比例将大约为$\beta$。 +> 因此,我们可以说从长远来看[这里Wald应用大数定律,让$M \rightarrow \infty$(这是我们的注释,不是Wald的)],如果$H_0$为真,错误陈述的比例将是$\alpha$,如果$H_1$为真,则为$\beta$。 -$$ -f(z; a, b) = \frac{\Gamma(a+b) z^{a-1} (1-z)^{b-1}}{\Gamma(a) \Gamma(b)} -\quad \text{其中} \quad -\Gamma(t) := \int_{0}^{\infty} x^{t-1} e^{-x} dx -$$ +量$\alpha$被称为临界区域的*大小*,而量$1-\beta$被称为临界区域的*检验力*。 -上图的上半部分显示了两个贝塔分布。 +Wald指出 -下半部分展示了这些分布的混合,其中使用了不同的混合概率 $\pi_k$ +> 如果一个临界区域$W$具有较小的$\alpha$和$\beta$值,那么它比另一个更可取。虽然通过适当选择临界区域$W$,可以使$\alpha$或$\beta$任意小,但对于固定的$n$值(即固定的样本量),不可能同时使$\alpha$和$\beta$都任意小。 -```{code-cell} ipython3 -@jit -def p(x, a, b): - r = gamma(a + b) / (gamma(a) * gamma(b)) - return r * x**(a-1) * (1 - x)**(b-1) +Wald总结了Neyman和Pearson的设置如下: -f0 = lambda x: p(x, 1, 1) -f1 = lambda x: p(x, 9, 9) -grid = np.linspace(0, 1, 50) +> Neyman和Pearson表明,由满足以下不等式的所有样本$(z_1, z_2, \ldots, z_n)$组成的区域 +> +> $$ + \frac{ f_1(z_1) \cdots f_1(z_n)}{f_0(z_1) \cdots f_0(z_n)} \geq k + $$ +> +> 是检验假设$H_0$对抗备择假设$H_1$的最优势检验区域。右边的项$k$是一个常数,选择它使得该区域具有所需的大小$\alpha$。 -fig, axes = plt.subplots(2, figsize=(10, 8)) +Wald继续讨论了Neyman和Pearson的*一致最优势*检验的概念。 -axes[0].set_title("原始分布") -axes[0].plot(grid, f0(grid), lw=2, label="$f_0$") -axes[0].plot(grid, f1(grid), lw=2, label="$f_1$") +以下是Wald如何引入序贯检验的概念 -axes[1].set_title("混合分布") -for π in 0.25, 0.5, 0.75: - y = π * f0(grid) + (1 - π) * f1(grid) - axes[1].plot(y, lw=2, label=rf"$\pi_k$ = {π}") +> 在实验的任何阶段(对于每个整数值$m$的第$m$次试验),都给出一个规则来做出以下三个决定之一: +> (1)接受假设$H$,(2)拒绝假设$H$,(3)通过进行额外的观察来继续实验。因此, +> 这样的检验程序是按顺序进行的。基于第一次观察,做出上述决定之一。如果做出 +> 第一个或第二个决定,过程就终止。如果做出第三个决定,就进行第二次试验。 +> 同样,基于前两次观察,做出三个决定之一。如果做出第三个决定,就进行第三次 +> 试验,依此类推。这个过程持续进行,直到做出第一个或第二个决定为止。这种 +> 检验程序所需的观察次数$n$是一个随机变量,因为$n$的值取决于观察的结果。 -for ax in axes: - ax.legend() - ax.set(xlabel="$z$ 值", ylabel="$z_k$ 的概率") +## 瓦尔德的序贯表述 -plt.tight_layout() -plt.show() -``` +与奈曼-皮尔逊问题表述的对比,在瓦尔德的表述中: -### 损失和成本 +- 样本量$n$不是固定的,而是一个随机变量。 +- 两个参数$A$和$B$与奈曼-皮尔逊的$\alpha$和$\beta$相关但不同; +$A$和$B$表征了瓦尔德用来确定随机变量$n$作为随机结果函数的截止规则。 -在观察到 $z_k, z_{k-1}, \ldots, z_0$ 后,决策者可以在三种不同的行动中选择: +以下是瓦尔德如何设置这个问题。 -- 他确定 $f = f_0$ 并停止获取更多 $z$ 值 -- 他确定 $f = f_1$ 并停止获取更多 $z$ 值 -- 他推迟现在做决定,转而选择获取一个新的 $z_{k+1}$ +决策者可以观察一个随机变量 $z$ 的一系列抽样。 -与这三种行动相关联,决策者可能遭受三种损失: +他(或她)想要知道是哪一个概率分布 $f_0$ 或 $f_1$ 支配着 $z$。 -- 当实际上 $f=f_1$ 时,他决定 $f = f_0$ 会遭受损失 $L_0$ -- 当实际上 $f=f_0$ 时,他决定 $f = f_1$ 会遭受损失 $L_1$ -- 如果他推迟决定并选择获取另一个 $z$ 值,会产生成本 $c$ +我们使用贝塔分布作为例子。 -### 关于第一类和第二类错误的补充说明 +我们还将使用在 {doc}`divergence_measures` 中介绍的 Jensen-Shannon 散度。 -如果我们将 $f=f_0$ 视为原假设,将 $f=f_1$ 视为备择假设,那么 $L_1$ 和 $L_0$ 是与两类统计错误相关的损失 +```{code-cell} ipython3 +@vectorize +def p(x, a, b): + """贝塔分布密度函数。""" + r = gamma(a + b) / (gamma(a) * gamma(b)) + return r * x** (a-1) * (1 - x) ** (b-1) + +def create_beta_density(a, b): + """创建具有指定参数的贝塔密度函数。""" + return jit(lambda x: p(x, a, b)) + +def compute_KL(f, g): + """计算KL散度 KL(f, g)""" + integrand = lambda w: f(w) * np.log(f(w) / g(w)) + val, _ = quad(integrand, 1e-5, 1-1e-5) + return val + +def compute_JS(f, g): + """计算Jensen-Shannon散度""" + def m(w): + return 0.5 * (f(w) + g(w)) + + js_div = 0.5 * compute_KL(f, m) + 0.5 * compute_KL(g, m) + return js_div +``` -- 第一类错误是错误地拒绝了真实的原假设("假阳性") -- 第二类错误是未能拒绝错误的原假设("假阴性") +下图显示了两个贝塔分布 -当我们将 $f=f_0$ 作为零假设时 +```{code-cell} ipython3 +f0 = create_beta_density(1, 1) +f1 = create_beta_density(9, 9) +grid = np.linspace(0, 1, 50) -- 我们可以将 $L_1$ 视为第一类错误相关的损失。 -- 我们可以将 $L_0$ 视为第二类错误相关的损失。 +fig, ax = plt.subplots() +ax.plot(grid, f0(grid), lw=2, label="$f_0$") +ax.plot(grid, f1(grid), lw=2, label="$f_1$") +ax.legend() +ax.set(xlabel="$z$ 值", ylabel="$z_k$ 的概率") +plt.tight_layout() +plt.show() +``` -### 直观理解 +在已知连续观测值来自分布$f_0$的条件下,这个随机变量序列是独立同分布的(IID)。 -在继续之前,让我们试着猜测一个最优决策规则可能是什么样的。 +在已知连续观测值来自分布$f_1$的条件下,这个随机变量序列也是独立同分布的(IID)。 -假设在某个特定时间点,$\pi$ 接近1。 +但是观察者并不知道序列是由这两个分布中的哪一个生成的。 -那么我们的先验信念和目前的证据都强烈指向 $f = f_0$。 +由[可交换性和贝叶斯更新](https://python.quantecon.org/exchangeable.html)中解释的原因,这意味着观察者认为该序列不是IID的。 -另一方面,如果 $\pi$ 接近0,那么 $f = f_1$ 就更有可能。 +因此,观察者有需要学习的内容,即观测值是来自$f_0$还是来自$f_1$。 -最后,如果 $\pi$ 在区间 $[0, 1]$ 的中间位置,那么我们就面临更多的不确定性。 +决策者想要确定是哪一个分布在生成结果。 -这种推理表明决策规则可能如图所示 +### 第一类错误和第二类错误 -```{figure} /_static/lecture_specific/wald_friedman/wald_dec_rule.png +如果我们将$f=f_0$视为零假设,将$f=f_1$视为备择假设,那么: -``` +- 第一类错误是错误地拒绝了真的零假设("假阳性") +- 第二类错误是未能拒绝假的零假设("假阴性") -正如我们将看到的,这确实是决策规则的正确形式。 +重申一下: -我们的问题是确定阈值 $\alpha, \beta$,这些阈值以某种方式依赖于上述参数。 +- $\alpha$是第一类错误的概率 +- $\beta$是第二类错误的概率 -在这一点上,你可能想要暂停并尝试预测参数如$c$或$L_0$对$\alpha$或$\beta$的影响。 +### 选择 -### 贝尔曼方程 +在观察到$z_k, z_{k-1}, \ldots, z_1$后,决策者可以在三个不同的行动中选择: -设$J(\pi)$为当前信念为$\pi$且做出最优选择的决策者的总损失。 +- 他决定$f = f_0$并停止获取更多的$z$值 +- 他决定$f = f_1$并停止获取更多的$z$值 -经过思考,你会同意$J$应该满足贝尔曼方程 +- 他推迟做决定,转而选择抽取 + $z_{k+1}$ -```{math} -:label: new1 +Wald定义 -J(\pi) = - \min - \left\{ - (1-\pi) L_0, \; \pi L_1, \; - c + \mathbb E [ J (\pi') ] - \right\} -``` +- $p_{0m} = f_0(z_1) \cdots f_0(z_m)$ +- $p_{1m} = f_1(z_1) \cdots f_1(z_m)$ +- $L_{m} = \frac{p_{1m}}{p_{0m}}$ -其中$\pi'$是由贝叶斯法则定义的随机变量 +这里$\{L_m\}_{m=0}^\infty$是一个**似然比过程**。 -$$ -\pi' = \kappa(z', \pi) = \frac{ \pi f_0(z')}{ \pi f_0(z') + (1-\pi) f_1 (z') } -$$ +Wald的序贯决策规则由实数$B < A$参数化。 -当$\pi$固定且$z'$从当前最佳猜测分布中抽取时,该分布$f$定义为 +对于给定的一对$A, B$,决策规则是 $$ -f_{\pi}(v) = \pi f_0(v) + (1-\pi) f_1 (v) +\begin{aligned} +\textrm { 接受 } f=f_1 \textrm{ 如果 } L_m \geq A \\ +\textrm { 接受 } f=f_0 \textrm{ 如果 } L_m \leq B \\ +\textrm { 再抽取一个 } z \textrm{ 如果 } B < L_m < A +\end{aligned} $$ -在贝尔曼方程中,最小化是针对三个行动: - -1. 接受假设$f = f_0$ -1. 接受假设$f = f_1$ -1. 推迟决定并再次抽样 +下图说明了Wald程序的各个方面。 -我们可以将贝尔曼方程表示为 - -```{math} -:label: optdec +```{figure} /_static/lecture_specific/wald_friedman/wald_dec_rule.png -J(\pi) = -\min \left\{ (1-\pi) L_0, \; \pi L_1, \; h(\pi) \right\} ``` -其中 $\pi \in [0,1]$ 且 - -- $(1-\pi) L_0$ 是接受 $f_0$ 相关的预期损失(即犯II类错误的成本)。 -- $\pi L_1$ 是接受 $f_1$ 相关的预期损失(即犯I类错误的成本)。 -- $h(\pi) := c + \mathbb E [J(\pi')]$;这是继续值;即与再抽取一个 $z$ 相关的预期成本。 +## $A,B$与$\alpha, \beta$之间的联系 -最优决策规则由两个数 $\alpha, \beta \in (0,1) \times (0,1)$ 来表征,这两个数满足 +在**序贯分析**{cite}`Wald47`第3章中,Wald建立了以下不等式 -$$ -(1- \pi) L_0 < \min \{ \pi L_1, c + \mathbb E [J(\pi')] \} \textrm { if } \pi \geq \alpha -$$ - -且 - -$$ -\pi L_1 < \min \{ (1-\pi) L_0, c + \mathbb E [J(\pi')] \} \textrm { if } \pi \leq \beta +$$ +\begin{aligned} + \frac{\alpha}{1 -\beta} & \leq \frac{1}{A} \\ + \frac{\beta}{1 - \alpha} & \leq B +\end{aligned} $$ -最优决策规则则为 +他对这些不等式的分析导致Wald推荐以下近似作为设置$A$和$B$的规则,这些规则接近于达到决策者对第I类错误概率$\alpha$和第II类错误概率$\beta$的目标值: $$ \begin{aligned} -\textrm { 接受 } f=f_0 \textrm{ 如果 } \pi \geq \alpha \\ +A \approx a(\alpha,\beta) & \equiv \frac{1-\beta}{\alpha} \\ +B \approx b(\alpha,\beta) & \equiv \frac{\beta}{1-\alpha} +\end{aligned} +$$ (eq:Waldrule) -\textrm { 接受 } f=f_1 \textrm{ 如果 } \pi \leq \beta \\ -\textrm { 再抽取一个 } z \textrm{ 如果 } \beta \leq \pi \leq \alpha -\end{aligned} -$$ +对于较小的 $\alpha$ 和 $\beta$ 值,Wald表明近似式 {eq}`eq:Waldrule` 提供了一个设定 $A$ 和 $B$ 的良好方法。 -我们的目标是计算成本函数 $J$,并由此得出相关的临界值 $\alpha$ 和 $\beta$。 +特别地,Wald构建了一个数学论证,使他得出结论:使用近似式 {eq}`eq:Waldrule` 而不是真实函数 $A (\alpha, \beta), B(\alpha,\beta)$ 来设定 $A$ 和 $B$ -为了使计算更易于管理,使用{eq}`optdec`,我们可以将延续成本 $h(\pi)$ 写作 +> $\ldots$ 不会导致 $\alpha$ 或 $\beta$ 的值有任何显著增加。换句话说, +> 就实际目的而言,对应于 $A = a(\alpha, \beta), B = b(\alpha,\beta)$ 的检验 +> 至少提供了与对应于 $A = A(\alpha, \beta)$ 和 +> $B = b(\alpha, \beta)$ 的检验相同的防错决策保护。 -```{math} -:label: optdec2 +> 因此,使用 $ a(\alpha, \beta), b(\alpha,\beta)$ 而不是 +> $ A(\alpha, \beta), B(\alpha,\beta)$ 可能产生的唯一缺点是, +> 这可能会导致检验所需的观测数量显著增加。 -\begin{aligned} -h(\pi) &= c + \mathbb E [J(\pi')] \\ -&= c + \mathbb E_{\pi'} \min \{ (1 - \pi') L_0, \pi' L_1, h(\pi') \} \\ -&= c + \int \min \{ (1 - \kappa(z', \pi) ) L_0, \kappa(z', \pi) L_1, h(\kappa(z', \pi) ) \} f_\pi (z') dz' -\end{aligned} -``` +我们将编写一些Python代码来帮助我们说明Wald关于 $\alpha$ 和 $\beta$ 如何与表征其序贯概率比检验的参数 $A$ 和 $B$ 相关的论断。 -等式 +## 模拟 -```{math} -:label: funceq +我们尝试不同的分布 $f_0$ 和 $f_1$ 来研究Wald检验在各种条件下的表现。 -h(\pi) = -c + \int \min \{ (1 - \kappa(z', \pi) ) L_0, \kappa(z', \pi) L_1, h(\kappa(z', \pi) ) \} f_\pi (z') dz' -``` - -是一个未知函数 $h$ 的**泛函方程**。 +进行这些模拟的目的是为了理解Wald的**序贯概率比检验**在决策速度和准确性之间的权衡。 -使用延续成本的泛函方程{eq}`funceq`,我们可以通过{eq}`optdec`的右侧推导出最优选择。 +具体来说,我们将观察: -这个函数方程可以通过取一个初始猜测值并迭代来找到不动点来求解。 +- 决策阈值 $A$ 和 $B$ (或等效的目标错误率 $\alpha$ 和 $\beta$) 如何影响平均停止时间 +- 分布 $f_0$ 和 $f_1$ 之间的差异如何影响平均停止时间 -因此,我们用算子$Q$进行迭代,其中 - -$$ -Q h(\pi) = -c + \int \min \{ (1 - \kappa(z', \pi) ) L_0, \kappa(z', \pi) L_1, h(\kappa(z', \pi) ) \} f_\pi (z') dz' -$$ +我们将重点关注 $f_0$ 和 $f_1$ 为贝塔分布的情况,因为通过调整其形状参数可以轻松控制两个密度的重叠区域。 -## 实现 +首先,我们定义一个命名元组来存储我们进行模拟研究所需的所有参数。 -首先,我们将构造一个`jitclass`来存储模型的参数 +我们还根据目标第一类和第二类错误 $\alpha$ 和 $\beta$ 计算Wald推荐的阈值 $A$ 和 $B$ ```{code-cell} ipython3 -wf_data = [('a0', float64), # beta分布的参数 - ('b0', float64), - ('a1', float64), - ('b1', float64), - ('c', float64), # 再次抽样的成本 - ('π_grid_size', int64), - ('L0', float64), # 当f1为真时选择f0的成本 - ('L1', float64), # 当f0为真时选择f1的成本 - ('π_grid', float64[:]), - ('mc_size', int64), - ('z0', float64[:]), - ('z1', float64[:])] +SPRTParams = namedtuple('SPRTParams', + ['α', 'β', # 目标第一类和第二类错误 + 'a0', 'b0', # f_0的形状参数 + 'a1', 'b1', # f_1的形状参数 + 'N', # 模拟次数 + 'seed']) + +@njit +def compute_wald_thresholds(α, β): + """计算Wald推荐的阈值。""" + A = (1 - β) / α + B = β / (1 - α) + return A, B, np.log(A), np.log(B) ``` -```{code-cell} ipython3 -@jitclass(wf_data) -class WaldFriedman: +现在我们可以按照Wald的建议运行模拟。 - def __init__(self, - c=1.25, - a0=1, - b0=1, - a1=3, - b1=1.2, - L0=25, - L1=25, - π_grid_size=200, - mc_size=1000): +我们将对数似然比与阈值的对数 $\log(A)$ 和 $\log(B)$ 进行比较。 - self.a0, self.b0 = a0, b0 - self.a1, self.b1 = a1, b1 - self.c, self.π_grid_size = c, π_grid_size - self.L0, self.L1 = L0, L1 - self.π_grid = np.linspace(0, 1, π_grid_size) - self.mc_size = mc_size +以下算法是我们模拟的基础。 - self.z0 = np.random.beta(a0, b0, mc_size) - self.z1 = np.random.beta(a1, b1, mc_size) +1. 计算阈值 $A = \frac{1-\beta}{\alpha}$, $B = \frac{\beta}{1-\alpha}$ 并使用 $\log A$, $\log B$。 - def f0(self, x): +2. 给定真实分布(要么是 $f_0$ 或 $f_1$): + - 初始化对数似然比 $\log L_0 = 0$ + - 重复: + - 从真实分布中抽取观测值 $z$ + - 更新: $\log L_{n+1} \leftarrow \log L_n + (\log f_1(z) - \log f_0(z))$ + - 如果 $\log L_{n+1} \geq \log A$: 停止,拒绝 $H_0$ + - 如果 $\log L_{n+1} \leq \log B$: 停止,接受 $H_0$ - return p(x, self.a0, self.b0) +3. 对每个分布重复步骤2进行 $N/2$ 次重复,总共 $N$ 次重复,计算经验第一类错误 $\hat{\alpha}$ 和第二类错误 $\hat{\beta}$: - def f1(self, x): +$$ +\hat{\alpha} = \frac{\text{当 } f_0 \text{ 为真时拒绝 } H_0 \text{ 的次数}}{\text{以 } f_0 \text{ 为真的重复次数}} +$$ - return p(x, self.a1, self.b1) +$$ +\hat{\beta} = \frac{\text{当 } f_1 \text{ 为真时接受 } H_0 \text{ 的次数}}{\text{以 } f_1 \text{ 为真的重复次数}} +$$ - def f0_rvs(self): - return np.random.beta(self.a0, self.b0) +```{code-cell} ipython3 +@njit +def sprt_single_run(a0, b0, a1, b1, logA, logB, true_f0, seed): + """运行单次SPRT直到达到决策。""" + log_L = 0.0 + n = 0 + np.random.seed(seed) + + while True: + z = np.random.beta(a0, b0) if true_f0 else np.random.beta(a1, b1) + n += 1 + + # 更新对数似然比 + log_L += np.log(p(z, a1, b1)) - np.log(p(z, a0, b0)) + + # 检查停止条件 + if log_L >= logA: + return n, False # 拒绝H0 + elif log_L <= logB: + return n, True # 接受H0 + +@njit(parallel=True) +def run_sprt_simulation(a0, b0, a1, b1, α, β, N, seed): + """SPRT模拟。""" + A, B, logA, logB = compute_wald_thresholds(α, β) + + stopping_times = np.zeros(N, dtype=np.int64) + decisions_h0 = np.zeros(N, dtype=np.bool_) + truth_h0 = np.zeros(N, dtype=np.bool_) + + for i in prange(N): + true_f0 = (i % 2 == 0) + truth_h0[i] = true_f0 + + n, accept_f0 = sprt_single_run( + a0, b0, a1, b1, + logA, logB, + true_f0, seed + i) + stopping_times[i] = n + decisions_h0[i] = accept_f0 + + return stopping_times, decisions_h0, truth_h0 + +def run_sprt(params): + """使用给定参数运行SPRT模拟。""" + stopping_times, decisions_h0, truth_h0 = run_sprt_simulation( + params.a0, params.b0, params.a1, params.b1, + params.α, params.β, params.N, params.seed + ) + + # 计算错误率 + truth_h0_bool = truth_h0.astype(bool) + decisions_h0_bool = decisions_h0.astype(bool) + + type_I = np.sum(truth_h0_bool & ~decisions_h0_bool) \ + / np.sum(truth_h0_bool) + type_II = np.sum(~truth_h0_bool & decisions_h0_bool) \ + / np.sum(~truth_h0_bool) + + return { + 'stopping_times': stopping_times, + 'decisions_h0': decisions_h0_bool, + 'truth_h0': truth_h0_bool, + 'type_I': type_I, + 'type_II': type_II + } + +# 运行模拟 +params = SPRTParams(α=0.05, β=0.10, a0=2, b0=5, a1=5, b1=2, N=20000, seed=1) +results = run_sprt(params) + +print(f"平均停止时间: {results['stopping_times'].mean():.2f}") +print(f"经验第一类错误: {results['type_I']:.3f} (目标 = {params.α})") +print(f"经验第二类错误: {results['type_II']:.3f} (目标 = {params.β})") +``` - def f1_rvs(self): - return np.random.beta(self.a1, self.b1) +正如在上文中 Wald 讨论近似式 {eq}`eq:Waldrule` 中给出的 $a(\alpha, \beta), b(\alpha, \beta)$ 的质量时所预期的那样,我们发现该算法实际上给出了比目标值**更低**的第一类和第二类错误率。 - def κ(self, z, π): - """ - 使用贝叶斯法则和当前观测值z更新π - """ +```{note} +关于近似式 {eq}`eq:Waldrule` 质量的最新研究,请参见 {cite}`fischer2024improving`。 +``` - f0, f1 = self.f0, self.f1 +以下代码创建了几个图表来展示我们的模拟结果。 - π_f0, π_f1 = π * f0(z), (1 - π) * f1(z) - π_new = π_f0 / (π_f0 + π_f1) +```{code-cell} ipython3 +:tags: [hide-input] + +@njit +def compute_wald_thresholds(α, β): + """计算 Wald 推荐的阈值。""" + A = (1 - β) / α + B = β / (1 - α) + return A, B, np.log(A), np.log(B) + +def plot_sprt_results(results, params, title=""): + """绘制 SPRT 结果。""" + fig, axes = plt.subplots(1, 3, figsize=(20, 6)) + + # 分布图 + z_grid = np.linspace(0, 1, 200) + f0 = create_beta_density(params.a0, params.b0) + f1 = create_beta_density(params.a1, params.b1) + + axes[0].plot(z_grid, f0(z_grid), 'b-', lw=2, + label=f'$f_0 = \\text{{Beta}}({params.a0},{params.b0})$') + axes[0].plot(z_grid, f1(z_grid), 'r-', lw=2, + label=f'$f_1 = \\text{{Beta}}({params.a1},{params.b1})$') + axes[0].fill_between(z_grid, 0, + np.minimum(f0(z_grid), f1(z_grid)), + alpha=0.3, color='purple', label='overlap') + if title: + axes[0].set_title(title, fontsize=20) + axes[0].set_xlabel('z', fontsize=16) + axes[0].set_ylabel('density', fontsize=16) + axes[0].legend(fontsize=14) + + # 停止时间 + max_n = min(results['stopping_times'].max(), 101) + bins = np.arange(1, max_n) - 0.5 + axes[1].hist(results['stopping_times'], bins=bins, + color="steelblue", alpha=0.8, edgecolor="black") + axes[1].set_title(f'stopping times (μ={results["stopping_times"].mean():.1f})', + fontsize=16) + axes[1].set_xlabel('n', fontsize=16) + axes[1].set_ylabel('frequency', fontsize=16) + axes[1].set_xlim(0, 100) + + # 混淆矩阵 + plot_confusion_matrix(results, axes[2]) + + plt.tight_layout() + plt.show() - return π_new +def plot_confusion_matrix(results, ax): + """绘制 SPRT 结果的混淆矩阵。""" + f0_correct = np.sum(results['truth_h0'] & results['decisions_h0']) + f0_incorrect = np.sum(results['truth_h0'] & (~results['decisions_h0'])) + f1_correct = np.sum((~results['truth_h0']) & (~results['decisions_h0'])) + f1_incorrect = np.sum((~results['truth_h0']) & results['decisions_h0']) + + confusion_data = np.array([[f0_correct, f0_incorrect], + [f1_incorrect, f1_correct]]) + row_totals = confusion_data.sum(axis=1, keepdims=True) + + im = ax.imshow(confusion_data, cmap='Blues', aspect='equal') + ax.set_title(f'errors: I={results["type_I"]:.3f} II={results["type_II"]:.3f}', + fontsize=16) + ax.set_xticks([0, 1]) + ax.set_xticklabels(['accept $H_0$', 'reject $H_0$'], fontsize=14) + ax.set_yticks([0, 1]) + ax.set_yticklabels(['true $f_0$', 'true $f_1$'], fontsize=14) + + for i in range(2): + for j in range(2): + percent = confusion_data[i, j] / row_totals[i, 0] \ + if row_totals[i, 0] > 0 else 0 + color = 'white' if confusion_data[i, j] > confusion_data.max() * 0.5 \ + else 'black' + ax.text(j, i, f'{confusion_data[i, j]}\n({percent:.1%})', + ha="center", va="center", color=color, fontweight='bold', + fontsize=14) ``` -如同{doc}`最优增长讲座 `中所述,为了近似连续的值函数 - -* 我们在有限的 $\pi$ 值网格上进行迭代。 -* 当我们在网格点之间评估 $\mathbb E[J(\pi')]$ 时,我们使用线性插值。 - -我们在下面定义算子函数 `Q`。 +让我们绘制模拟的结果 ```{code-cell} ipython3 -@jit(nopython=True, parallel=True) -def Q(h, wf): +plot_sprt_results(results, params) +``` - c, π_grid = wf.c, wf.π_grid - L0, L1 = wf.L0, wf.L1 - z0, z1 = wf.z0, wf.z1 - mc_size = wf.mc_size +在这个例子中,停止时间保持在10以下。 - κ = wf.κ +我们可以构建一个$2 \times 2$的"混淆矩阵",其对角线元素统计了Wald决策规则正确接受和正确拒绝原假设的次数。 - h_new = np.empty_like(π_grid) - h_func = lambda p: np.interp(p, π_grid, h) +```{code-cell} ipython3 +print("混淆矩阵数据:") +print(f"第一类错误:{results['type_I']:.3f}") +print(f"第二类错误:{results['type_II']:.3f}") +``` - for i in prange(len(π_grid)): - π = π_grid[i] +接下来我们使用代码研究三对不同的 $f_0, f_1$ 分布,它们之间有不同程度的差异。 - # Find the expected value of J by integrating over z - integral_f0, integral_f1 = 0, 0 - for m in range(mc_size): - π_0 = κ(z0[m], π) # Draw z from f0 and update π - integral_f0 += min((1 - π_0) * L0, π_0 * L1, h_func(π_0)) +我们为每对分布绘制与上面相同的三种图表 - π_1 = κ(z1[m], π) # Draw z from f1 and update π - integral_f1 += min((1 - π_1) * L0, π_1 * L1, h_func(π_1)) +```{code-cell} ipython3 +params_1 = SPRTParams(α=0.05, β=0.10, a0=2, b0=8, a1=8, b1=2, N=5000, seed=42) +results_1 = run_sprt(params_1) - integral = (π * integral_f0 + (1 - π) * integral_f1) / mc_size +params_2 = SPRTParams(α=0.05, β=0.10, a0=4, b0=5, a1=5, b1=4, N=5000, seed=42) +results_2 = run_sprt(params_2) - h_new[i] = c + integral +params_3 = SPRTParams(α=0.05, β=0.10, a0=0.5, b0=0.4, a1=0.4, + b1=0.5, N=5000, seed=42) +results_3 = run_sprt(params_3) +``` - return h_new +```{code-cell} ipython3 +plot_sprt_results(results_1, params_1) ``` -为了求解关键的函数方程,我们将使用`Q`进行迭代以找到不动点 +```{code-cell} ipython3 +plot_sprt_results(results_2, params_2) +``` ```{code-cell} ipython3 -@jit -def solve_model(wf, tol=1e-4, max_iter=1000): - """ - 计算延续成本函数 +plot_sprt_results(results_3, params_3) +``` - * wf 是 WaldFriedman 的一个实例 - """ +请注意,当两个分布相距较远时,停止时间会更短。 - # 设置循环 - h = np.zeros(len(wf.π_grid)) - i = 0 - error = tol + 1 +这是很合理的。 - while i < max_iter and error > tol: - h_new = Q(h, wf) - error = np.max(np.abs(h - h_new)) - i += 1 - h = h_new +当两个分布"相距较远"时,判断哪个分布在产生数据不应该需要太长时间。 - if error > tol: - print("未能收敛!") +当两个分布"相近"时,判断哪个分布在产生数据应该需要更长时间。 - return h_new -``` +我们很容易想到将这种模式与我们在{doc}`likelihood_ratio_process`中讨论的[Kullback–Leibler散度](rel_entropy)联系起来。 -## 分析 +虽然当两个分布差异更大时KL散度更大,但KL散度并不是对称的,这意味着分布$f$相对于分布$g$的KL散度不一定等于$g$相对于$f$的KL散度。 -让我们检查结果。 +如果我们想要一个真正具有度量性质的对称散度,我们可以使用[Jensen-Shannon距离](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.jensenshannon.html)。 -我们将使用默认参数化的分布,如下所示 +这就是我们现在要做的。 -```{code-cell} ipython3 -wf = WaldFriedman() +我们将计算Jensen-Shannon距离,并绘制它与平均停止时间的关系图。 -fig, ax = plt.subplots(figsize=(10, 6)) -ax.plot(wf.f0(wf.π_grid), label="$f_0$") -ax.plot(wf.f1(wf.π_grid), label="$f_1$") -ax.set(ylabel="$z_k$ 的概率", xlabel="$z_k$", title="分布") -ax.legend() +```{code-cell} ipython3 +def js_dist(a0, b0, a1, b1): + """Jensen–Shannon距离""" + f0 = create_beta_density(a0, b0) + f1 = create_beta_density(a1, b1) + + # 混合 + m = lambda w: 0.5*(f0(w) + f1(w)) + return np.sqrt(0.5*compute_KL(m, f0) + 0.5*compute_KL(m, f1)) + +def generate_β_pairs(N=100, T=10.0, d_min=0.5, d_max=9.5): + ds = np.linspace(d_min, d_max, N) + a0 = (T - ds) / 2 + b0 = (T + ds) / 2 + return list(zip(a0, b0, b0, a0)) + +param_comb = generate_β_pairs() + +# 为每个参数组合运行模拟 +js_dists = [] +mean_stopping_times = [] +param_list = [] + +for a0, b0, a1, b1 in param_comb: + # 计算KL散度 + js_div = js_dist(a1, b1, a0, b0) + + # 用固定参数集运行SPRT模拟 + params = SPRTParams(α=0.05, β=0.10, a0=a0, b0=b0, + a1=a1, b1=b1, N=5000, seed=42) + results = run_sprt(params) + + js_dists.append(js_div) + mean_stopping_times.append(results['stopping_times'].mean()) + param_list.append((a0, b0, a1, b1)) + +# 创建图表 +fig, ax = plt.subplots() + +scatter = ax.scatter(js_dists, mean_stopping_times, + s=80, alpha=0.7, linewidth=0.5) + +ax.set_xlabel('Jensen–Shannon距离', fontsize=14) +ax.set_ylabel('平均停止时间', fontsize=14) +plt.tight_layout() plt.show() ``` -### 值函数 +该图显示了相对熵与平均停止时间之间存在明显的负相关关系。 -为了求解模型,我们将调用`solve_model`函数 +随着Jensen-Shannon散度的增加(分布之间的差异增大),平均停止时间呈指数下降。 -```{code-cell} ipython3 -h_star = solve_model(wf) # 求解模型 -``` - -我们还将设置一个函数来计算截断值 $\alpha$ 和 $\beta$,并在成本函数图上绘制这些值 +以下是我们上述实验的采样示例 ```{code-cell} ipython3 -@jit -def find_cutoff_rule(wf, h): - - """ - 该函数接收一个延续成本函数,并返回在继续采样和选择特定模型之间 - 转换的对应截断点 - """ - - π_grid = wf.π_grid - L0, L1 = wf.L0, wf.L1 - - # 在网格上计算选择模型的所有点的成本 - payoff_f0 = (1 - π_grid) * L0 - payoff_f1 = π_grid * L1 - - # 通过将这些成本与贝尔曼方程的差值可以找到截断点 - # (J 总是小于或等于 p_c_i) - β = π_grid[np.searchsorted( - payoff_f1 - np.minimum(h, payoff_f0), - 1e-10) - - 1] - α = π_grid[np.searchsorted( - np.minimum(h, payoff_f1) - payoff_f0, - 1e-10) - - 1] +def plot_beta_distributions_grid(param_list, js_dists, mean_stopping_times, + selected_indices=None): + """绘制贝塔分布网格,包含JS距离和停止时间。""" + if selected_indices is None: + selected_indices = [0, len(param_list)//6, len(param_list)//3, + len(param_list)//2, 2*len(param_list)//3, -1] + + fig, axes = plt.subplots(2, 3, figsize=(15, 8)) + z_grid = np.linspace(0, 1, 200) + + for i, idx in enumerate(selected_indices): + row, col = i // 3, i % 3 + a0, b0, a1, b1 = param_list[idx] + + f0 = create_beta_density(a0, b0) + f1 = create_beta_density(a1, b1) + + axes[row, col].plot(z_grid, f0(z_grid), 'b-', lw=2, label='$f_0$') + axes[row, col].plot(z_grid, f1(z_grid), 'r-', lw=2, label='$f_1$') + axes[row, col].fill_between(z_grid, 0, + np.minimum(f0(z_grid), f1(z_grid)), + alpha=0.3, color='purple') + + axes[row, col].set_title(f'JS距离: {js_dists[idx]:.3f}' + f'\n平均时间: {mean_stopping_times[idx]:.1f}', + fontsize=12) + axes[row, col].set_xlabel('z', fontsize=10) + if i == 0: + axes[row, col].set_ylabel('密度', fontsize=10) + axes[row, col].legend(fontsize=10) + + plt.tight_layout() + plt.show() - return (β, α) +plot_beta_distributions_grid(param_list, js_dists, mean_stopping_times) +``` -β, α = find_cutoff_rule(wf, h_star) -cost_L0 = (1 - wf.π_grid) * wf.L0 -cost_L1 = wf.π_grid * wf.L1 +再次发现,当分布之间的差异越大(用Jensen-Shannon距离衡量),停止时间就越短。 -fig, ax = plt.subplots(figsize=(10, 6)) +让我们可视化单个似然比过程,看看它们是如何向决策边界演变的。 -ax.plot(wf.π_grid, h_star, label='再次采样') -ax.plot(wf.π_grid, cost_L1, label='选择 f1') -ax.plot(wf.π_grid, cost_L0, label='选择 f0') -ax.plot(wf.π_grid, - np.amin(np.column_stack([h_star, cost_L0, cost_L1]),axis=1), - lw=15, alpha=0.1, color='b', label=r'$J(\pi)$') +```{code-cell} ipython3 +def plot_likelihood_paths(params, n_highlight=10, n_background=200): + """可视化似然比路径。""" + A, B, logA, logB = compute_wald_thresholds(params.α, params.β) + f0, f1 = map(lambda ab: create_beta_density(*ab), + [(params.a0, params.b0), + (params.a1, params.b1)]) + + fig, axes = plt.subplots(1, 2, figsize=(14, 7)) + + for dist_idx, (true_f0, ax, title) in enumerate([ + (True, axes[0], '真实分布: $f_0$'), + (False, axes[1], '真实分布: $f_1$') + ]): + rng = np.random.default_rng(seed=42 + dist_idx) + paths_data = [] + + # 生成路径 + for path in range(n_background + n_highlight): + log_L_path, log_L, n = [0.0], 0.0, 0 + + while True: + z = rng.beta(params.a0, params.b0) if true_f0 \ + else rng.beta(params.a1, params.b1) + n += 1 + log_L += np.log(f1(z)) - np.log(f0(z)) + log_L_path.append(log_L) + + if log_L >= logA or log_L <= logB: + paths_data.append((log_L_path, n, log_L >= logA)) + break + + # 绘制背景路径 + for path, _, decision in paths_data[:n_background]: + ax.plot(range(len(path)), path, color='C1' if decision else 'C0', + alpha=0.2, linewidth=0.5) + + # 绘制高亮路径及标签 + for i, (path, _, decision) in enumerate(paths_data[n_background:]): + ax.plot(range(len(path)), path, color='C1' if decision else 'C0', + alpha=0.8, linewidth=1.5, + label='拒绝 $H_0$' if decision and i == 0 else ( + '接受 $H_0$' if not decision and i == 0 else '')) + + # 添加阈值线和格式化 + ax.axhline(y=logA, color='C1', linestyle='--', linewidth=2, + label=f'$\\log A = {logA:.2f}$') + ax.axhline(y=logB, color='C0', linestyle='--', linewidth=2, + label=f'$\\log B = {logB:.2f}$') + ax.axhline(y=0, color='black', linestyle='-', alpha=0.5, linewidth=1) + + ax.set_xlabel(r'$n$') + ax.set_ylabel(r'$\log(L_n)$') + ax.set_title(title, fontsize=20) + ax.legend(fontsize=18, loc='center right') + + y_margin = max(abs(logA), abs(logB)) * 0.2 + ax.set_ylim(logB - y_margin, logA + y_margin) + + plt.tight_layout() + plt.show() -ax.annotate(r"$\beta$", xy=(β + 0.01, 0.5), fontsize=14) -ax.annotate(r"$\alpha$", xy=(α + 0.01, 0.5), fontsize=14) +plot_likelihood_paths(params_3, n_highlight=10, n_background=100) +``` -plt.vlines(β, 0, β * wf.L0, linestyle="--") -plt.vlines(α, 0, (1 - α) * wf.L1, linestyle="--") +接下来,让我们调整决策阈值 $A$ 和 $B$,并观察平均停止时间以及第一类和第二类错误率的变化。 -ax.set(xlim=(0, 1), ylim=(0, 0.5 * max(wf.L0, wf.L1)), ylabel="成本", - xlabel=r"$\pi$", title="成本函数 $J(\pi)$") +在下面的代码中,我们通过调整因子 $A_f$ 和 $B_f$ 来调整 Wald 规则的阈值。 -plt.legend(borderpad=1.1) -plt.show() +```{code-cell} ipython3 +@njit(parallel=True) +def run_adjusted_thresholds(a0, b0, a1, b1, α, β, N, seed, A_f, B_f): + """带有调整阈值的 SPRT 模拟。""" + + # 计算原始阈值 + A_original = (1 - β) / α + B_original = β / (1 - α) + + # 应用调整因子 + A_adj = A_original * A_f + B_adj = B_original * B_f + logA = np.log(A_adj) + logB = np.log(B_adj) + + # 预分配数组 + stopping_times = np.zeros(N, dtype=np.int64) + decisions_h0 = np.zeros(N, dtype=np.bool_) + truth_h0 = np.zeros(N, dtype=np.bool_) + + # 并行运行模拟 + for i in prange(N): + true_f0 = (i % 2 == 0) + truth_h0[i] = true_f0 + + n, accept_f0 = sprt_single_run(a0, b0, a1, b1, + logA, logB, true_f0, seed + i) + stopping_times[i] = n + decisions_h0[i] = accept_f0 + + return stopping_times, decisions_h0, truth_h0, A_adj, B_adj + +def run_adjusted(params, A_f=1.0, B_f=1.0): + """运行带有调整 A 和 B 阈值的 SPRT 的包装函数。""" + + stopping_times, decisions_h0, truth_h0, A_adj, B_adj = run_adjusted_thresholds( + params.a0, params.b0, params.a1, params.b1, + params.α, params.β, params.N, params.seed, A_f, B_f + ) + truth_h0_bool = truth_h0.astype(bool) + decisions_h0_bool = decisions_h0.astype(bool) + + # 计算错误率 + type_I = np.sum(truth_h0_bool + & ~decisions_h0_bool) / np.sum(truth_h0_bool) + type_II = np.sum(~truth_h0_bool + & decisions_h0_bool) / np.sum(~truth_h0_bool) + + return { + 'stopping_times': stopping_times, + 'type_I': type_I, + 'type_II': type_II, + 'A_used': A_adj, + 'B_used': B_adj + } + +adjustments = [ + (5.0, 0.5), + (1.0, 1.0), + (0.3, 3.0), + (0.2, 5.0), + (0.15, 7.0), +] + +results_table = [] +for A_f, B_f in adjustments: + result = run_adjusted(params_2, A_f, B_f) + results_table.append([ + A_f, B_f, + f"{result['stopping_times'].mean():.1f}", + f"{result['type_I']:.3f}", + f"{result['type_II']:.3f}" + ]) + +df = pd.DataFrame(results_table, + columns=["A_f", "B_f", "平均停止时间", + "第一类错误", "第二类错误"]) +df = df.set_index(["A_f", "B_f"]) +df ``` -成本函数$J$在$\pi \leq \beta$时等于$\pi L_1$,在$\pi \geq \alpha$时等于$(1-\pi )L_0$。 +让我们通过回顾{eq}`eq:Waldrule`来更仔细地思考这个表格。 -成本函数$J(\pi)$两个线性部分的斜率由$L_1$和$-L_0$决定。 +回想一下$A = \frac{1-\beta}{\alpha}$和$B = \frac{\beta}{1-\alpha}$。 -在内部区域,当后验概率分配给$f_0$处于不确定区域$\pi \in (\beta, \alpha)$时,成本函数$J$是平滑的。 +当我们用小于1的因子乘以$A$(使$A$变小)时,我们实际上是在使拒绝原假设$H_0$变得更容易。 -决策者继续采样,直到他对模型$f_0$的概率低于$\beta$或高于$\alpha$。 +这增加了第一类错误的概率。 -### 模拟 +当我们用大于1的因子乘以$B$(使$B$变大)时,我们是在使接受原假设$H_0$变得更容易。 -下图显示了决策过程的500次模拟结果。 +这增加了第二类错误的概率。 -左图是**停止时间**的直方图,即做出决策所需的$z_k$抽样次数。 +表格证实了这种直觉:当$A$减小且$B$增加超出其最优Wald值时,第一类和第二类错误率都会增加,而平均停止时间会减少。 -平均抽样次数约为6.6。 +## 相关讲座 -右图是在停止时间点做出正确决策的比例。 +我们将在以下早期和后续讲座中深入探讨这里使用的一些概念: -在这种情况下,决策者80%的时间做出了正确的决策。 +* 在{doc}`这个续篇`中,我们从**贝叶斯统计学家**的角度重新阐述了这个问题,他们将参数视为与他们关心的可观察量共同分布的随机变量向量。 +* **可交换性**的概念是统计学习的基础,在我们的{doc}`可交换随机变量讲座`中有深入探讨。 +* 要深入理解似然比过程及其在频率派和贝叶斯统计理论中的作用,请参见{doc}`likelihood_ratio_process`。 -```{code-cell} ipython3 -def simulate(wf, true_dist, h_star, π_0=0.5): - - """ - This function takes an initial condition and simulates until it - stops (when a decision is made) - """ - - f0, f1 = wf.f0, wf.f1 - f0_rvs, f1_rvs = wf.f0_rvs, wf.f1_rvs - π_grid = wf.π_grid - κ = wf.κ - - if true_dist == "f0": - f, f_rvs = wf.f0, wf.f0_rvs - elif true_dist == "f1": - f, f_rvs = wf.f1, wf.f1_rvs - - # Find cutoffs - β, α = find_cutoff_rule(wf, h_star) - - # Initialize a couple of useful variables - decision_made = False - π = π_0 - t = 0 - - while decision_made is False: - # Maybe should specify which distribution is correct one so that - # the draws come from the "right" distribution - z = f_rvs() - t = t + 1 - π = κ(z, π) - if π < β: - decision_made = True - decision = 1 - elif π > α: - decision_made = True - decision = 0 - - if true_dist == "f0": - if decision == 0: - correct = True - else: - correct = False - - elif true_dist == "f1": - if decision == 1: - correct = True - else: - correct = False - - return correct, π, t - -def stopping_dist(wf, h_star, ndraws=250, true_dist="f0"): - - """ - Simulates repeatedly to get distributions of time needed to make a - decision and how often they are correct - """ - - tdist = np.empty(ndraws, int) - cdist = np.empty(ndraws, bool) - - for i in range(ndraws): - correct, π, t = simulate(wf, true_dist, h_star) - tdist[i] = t - cdist[i] = correct - - return cdist, tdist - -def simulation_plot(wf): - h_star = solve_model(wf) - ndraws = 500 - cdist, tdist = stopping_dist(wf, h_star, ndraws) - - fig, ax = plt.subplots(1, 2, figsize=(16, 5)) - - ax[0].hist(tdist, bins=np.max(tdist)) - ax[0].set_title(f"Stopping times over {ndraws} replications") - ax[0].set(xlabel="time", ylabel="number of stops") - ax[0].annotate(f"mean = {np.mean(tdist)}", xy=(max(tdist) / 2, - max(np.histogram(tdist, bins=max(tdist))[0]) / 2)) - - ax[1].hist(cdist.astype(int), bins=2) - ax[1].set_title(f"Correct decisions over {ndraws} replications") - ax[1].annotate(f"% correct = {np.mean(cdist)}", - xy=(0.05, ndraws / 2)) +* 在此基础上,{doc}`likelihood_bayes`探讨了似然比过程在**贝叶斯学习**中的作用。 +* 最后,{doc}`这个后续讲座 `重新审视了这里讨论的主题,并探讨了海军命令船长使用的频率主义决策规则是否会比Abraham Wald的序贯决策规则表现得更好或更差。 - plt.show() +## 练习 -simulation_plot(wf) -``` +在下面的两个练习中,请尝试重写本讲座中的整个SPRT套件。 -### 比较静态分析 +```{exercise} +:label: wald_friedman_ex1 -现在让我们来看下面的练习。 +在第一个练习中,我们将序贯概率比检验应用于区分由3状态马尔可夫链生成的两个模型 -我们将获取额外观测值的成本提高一倍。 +(关于马尔可夫链似然比过程的回顾,请参见[本节](lrp_markov)。) -在查看结果之前,请思考会发生什么: +考虑使用Wald的序贯概率比检验来区分两个3状态马尔可夫链模型。 -- 决策者的判断正确率会提高还是降低? -- 他会更早还是更晚做出决定? +你有关于转移概率的竞争假设: -```{code-cell} ipython3 -wf = WaldFriedman(c=2.5) -simulation_plot(wf) -``` +- $H_0$:链遵循转移矩阵 $P^{(0)}$ +- $H_1$:链遵循转移矩阵 $P^{(1)}$ -每次抽样成本的增加导致决策者在做出决定前减少抽样次数。 +给定转移矩阵: -由于他用更少的抽样做决定,正确判断的比例下降。 +$$ +P^{(0)} = \begin{bmatrix} +0.7 & 0.2 & 0.1 \\ +0.3 & 0.5 & 0.2 \\ +0.1 & 0.3 & 0.6 +\end{bmatrix}, \quad +P^{(1)} = \begin{bmatrix} +0.5 & 0.3 & 0.2 \\ +0.2 & 0.6 & 0.2 \\ +0.2 & 0.2 & 0.6 +\end{bmatrix} +$$ -这导致他在对两个模型赋予相同权重时产生更高的预期损失。 +对于观测序列$(x_0, x_1, \ldots, x_t)$,似然比为: -### 笔记本实现 +$$ +\Lambda_t = \frac{\pi_{x_0}^{(1)}}{\pi_{x_0}^{(0)}} \prod_{s=1}^t \frac{P_{x_{s-1},x_s}^{(1)}}{P_{x_{s-1},x_s}^{(0)}} +$$ -为了便于比较静态分析,我们提供了一个[Jupyter笔记本](https://nbviewer.org/github/QuantEcon/lecture-python.notebooks/blob/main/wald_friedman.ipynb),它可以生成相同的图表,但带有滑块控件。 +其中$\pi^{(i)}$是假设$i$下的平稳分布。 -使用这些滑块,你可以调整参数并立即观察 +任务: +1. 实现马尔可夫链的似然比计算 +2. 实现Wald序贯检验,I类错误$\alpha = 0.05$和II类错误$\beta = 0.10$ +3. 在每个假设下运行1000次模拟并计算经验错误率 +4. 分析停止时间的分布 -* 当我们增加分段线性近似中的网格点数时,对犹豫不决的中间范围内价值函数平滑度的影响。 -* 不同成本参数$L_0, L_1, c$、两个beta分布$f_0$和$f_1$的参数,以及在价值函数分段连续近似中使用的点数和线性函数$m$的设置对结果的影响。 +检验在以下情况停止: +- $\Lambda_t \geq A = \frac{1-\beta}{\alpha} = 18$: 拒绝$H_0$ +- $\Lambda_t \leq B = \frac{\beta}{1-\alpha} = 0.105$: 接受$H_0$ +``` -* 从 $f_0$ 进行的各种模拟以及相关的决策等待时间分布。 -* 正确和错误决策的相关直方图。 -## 与奈曼-皮尔逊公式的比较 +```{solution-start} wald_friedman_ex1 +:class: dropdown +``` -出于几个原因,有必要描述海军上尉G. S. Schuyler被要求使用的测试背后的理论,这也是他向Milton Friedman和Allan Wallis提出他的推测,认为存在更好的实用程序的原因。 +以下是该练习的一个解决方案。 -显然,海军告诉Schuyler上尉使用他们所知的最先进的奈曼-皮尔逊检验。 +在讲座中,我们更详细地编写代码以清晰地说明概念。 -我们将依据Abraham Wald的{cite}`Wald47`对奈曼-皮尔逊理论的优雅总结。 +在下面的代码中,我们简化了一些代码结构以便更简短地呈现。 -就我们的目的而言,需要注意设置中的以下特征: +首先我们定义马尔可夫链SPRT的参数 -- 假设*固定*样本量 $n$ -- 应用大数定律,在备择概率模型的条件下,解释奈曼-皮尔逊理论中定义的概率 $\alpha$ 和 $\beta$ +```{code-cell} ipython3 +MarkovSPRTParams = namedtuple('MarkovSPRTParams', + ['α', 'β', 'P_0', 'P_1', 'N', 'seed']) + +def compute_stationary_distribution(P): + """计算转移矩阵P的平稳分布。""" + eigenvalues, eigenvectors = np.linalg.eig(P.T) + idx = np.argmin(np.abs(eigenvalues - 1)) + pi = np.real(eigenvectors[:, idx]) + return pi / pi.sum() + +@njit +def simulate_markov_chain(P, pi_0, T, seed): + """模拟马尔可夫链路径。""" + np.random.seed(seed) + path = np.zeros(T, dtype=np.int32) + + cumsum_pi = np.cumsum(pi_0) + path[0] = np.searchsorted(cumsum_pi, np.random.uniform()) + + for t in range(1, T): + cumsum_row = np.cumsum(P[path[t-1]]) + path[t] = np.searchsorted(cumsum_row, np.random.uniform()) + + return path +``` -回顾上述顺序分析公式中, +这里我们定义了用于马尔可夫链的 SPRT 运行函数 -- 样本量 $n$ 不是固定的,而是一个待选择的对象;从技术上讲,$n$ 是一个随机变量。 -- 参数 $\beta$ 和 $\alpha$ 表征用于确定随机变量 $n$ 的截止规则。 -- 大数定律在顺序构造中并未出现。 +```{code-cell} ipython3 +@njit +def markov_sprt_single_run(P_0, P_1, π_0, π_1, + logA, logB, true_P, true_π, seed): + """运行单次马尔可夫链 SPRT。""" + max_n = 10000 + path = simulate_markov_chain(true_P, true_π, max_n, seed) + + log_L = np.log(π_1[path[0]] / π_0[path[0]]) + if log_L >= logA: return 1, False + if log_L <= logB: return 1, True + + for t in range(1, max_n): + prev_state, curr_state = path[t-1], path[t] + p_1, p_0 = P_1[prev_state, curr_state], P_0[prev_state, curr_state] + + if p_0 > 0: + log_L += np.log(p_1 / p_0) + elif p_1 > 0: + log_L = np.inf + + if log_L >= logA: return t+1, False + if log_L <= logB: return t+1, True + + return max_n, log_L < 0 + +def run_markov_sprt(params): + """运行马尔可夫链 SPRT。""" + π_0 = compute_stationary_distribution(params.P_0) + π_1 = compute_stationary_distribution(params.P_1) + A, B, logA, logB = compute_wald_thresholds(params.α, params.β) + + stopping_times = np.zeros(params.N, dtype=np.int64) + decisions_h0 = np.zeros(params.N, dtype=bool) + truth_h0 = np.zeros(params.N, dtype=bool) + + for i in range(params.N): + true_P, true_π = (params.P_0, π_0) if i % 2 == 0 else (params.P_1, π_1) + truth_h0[i] = i % 2 == 0 + + n, accept_h0 = markov_sprt_single_run( + params.P_0, params.P_1, π_0, π_1, logA, logB, + true_P, true_π, params.seed + i) + + stopping_times[i] = n + decisions_h0[i] = accept_h0 + + type_I = np.sum(truth_h0 & ~decisions_h0) / np.sum(truth_h0) + type_II = np.sum(~truth_h0 & decisions_h0) / np.sum(~truth_h0) + + return { + 'stopping_times': stopping_times, 'decisions_h0': decisions_h0, + 'truth_h0': truth_h0, 'type_I': type_I, 'type_II': type_II + } +``` -在**顺序分析**{cite}`Wald47`第一章中,Abraham Wald总结了Neyman-Pearson的假设检验方法。 +现在我们可以运行马尔可夫链的SPRT并可视化结果 -Wald将问题描述为对部分已知的概率分布做出决策。 +```{code-cell} ipython3 +# 运行马尔可夫链SPRT +P_0 = np.array([[0.7, 0.2, 0.1], + [0.3, 0.5, 0.2], + [0.1, 0.3, 0.6]]) -(为了提出一个明确的问题,你必须假设*某些东西*是已知的 -- 通常,*某些东西*意味着*很多东西*) +P_1 = np.array([[0.5, 0.3, 0.2], + [0.2, 0.6, 0.2], + [0.2, 0.2, 0.6]]) -通过限制未知的内容,Wald使用以下简单结构来说明主要思想: +params_markov = MarkovSPRTParams(α=0.05, β=0.10, + P_0=P_0, P_1=P_1, N=1000, seed=42) +results_markov = run_markov_sprt(params_markov) -- 决策者想要决定两个分布 $f_0$、$f_1$ 中的哪一个支配着独立同分布随机变量 $z$。 -- 零假设 $H_0$ 是指 $f_0$ 支配数据的陈述。 -- 备择假设 $H_1$ 是指 $f_1$ 支配数据的陈述。 -- 问题在于基于固定数量 $n$ 个独立观测值 $z_1, z_2, \ldots, z_n$(来自随机变量 $z$)的样本,设计并分析一个针对零假设 $H_0$ 和备择假设 $H_1$ 的假设检验。 +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5)) -引用 Abraham Wald 的话: +ax1.hist(results_markov['stopping_times'], + bins=50, color="steelblue", alpha=0.8) +ax1.set_title("停止时间") +ax1.set_xlabel("n") +ax1.set_ylabel("频率") -> 导致接受或拒绝[零]假设的检验程序,简单来说就是一个规则,它为每个可能的大小为 $n$ 的样本指定是否应该基于该样本接受或拒绝[零]假设。这也可以表述如下:检验程序就是将所有可能的大小为 $n$ 的样本总体划分为两个互斥的部分,比如说第1部分和第2部分,同时应用规则,如果观察到的样本属于 +plot_confusion_matrix(results_markov, ax2) -> 包含在第2部分中。第1部分也被称为临界区域。由于 -> 第2部分是所有大小为$n$的样本中不包含在第1部分的 -> 总体,第2部分由第1部分唯一确定。因此, -> 选择检验程序等同于确定临界区域。 +plt.tight_layout() +plt.show() +``` -让我们继续听瓦尔德的说法: +```{solution-end} +``` -> 关于选择临界区域的依据,奈曼和皮尔逊提出了以下 -> 考虑:在接受或拒绝$H_0$时,我们可能会犯两种 -> 错误。当$H_0$为真而我们拒绝它时,我们犯第一类 -> 错误;当$H_1$为真而我们接受$H_0$时,我们犯 -> 第二类错误。在选定特定的临界区域$W$后, -> 犯第一类错误的概率和犯第二类错误的概率就 -> 被唯一确定了。犯第一类错误的概率等于由 -> 假设 $H_0$ 为真,观察到的样本将落在临界区域 $W$ 内。 -> 犯第二类错误的概率等于在假设 $H_1$ 为真的情况下, -> 概率落在临界区域 $W$ 之外的概率。对于任何给定的 -> 临界区域 $W$,我们用 $\alpha$ 表示第一类错误的概率, -> 用 $\beta$ 表示第二类错误的概率。 +```{exercise} +:label: wald_friedman_ex2 -让我们仔细听听Wald如何运用大数定律来解释 $\alpha$ 和 $\beta$: +在本练习中,将Wald的序贯检验应用于区分具有不同动态和噪声结构的两个VAR(1)模型。 -> 概率 $\alpha$ 和 $\beta$ 有以下重要的实际解释: -> 假设我们抽取大量规模为 $n$ 的样本。设 $M$ 为 -> 抽取的样本总数。假设对于这 $M$ 个样本中的每一个, -> 如果样本落在 $W$ 内则拒绝 $H_0$,如果样本落在 -> $W$ 外则接受 $H_0$。通过这种方式,我们做出了 $M$ 个 -> 拒绝或 +关于VAR模型的似然比过程的回顾,请参见{doc}`likelihood_var`。 -> 接受。这些陈述中的一些通常是错误的。如果 -> $H_0$为真且$M$很大,那么错误陈述的比例(即错误陈述的数量 -> 除以$M$)约为$\alpha$的概率接近于$1$(即几乎是确定的)。如果 -> $H_1$为真,错误陈述的比例约为$\beta$的概率接近于$1$。 -> 因此,我们可以说从长远来看[这里Wald通过令$M \rightarrow \infty$应用了大数定律(这是我们的注释, -> 不是Wald的)],如果$H_0$为真,错误陈述的比例将是 -> $\alpha$,如果$H_1$为真,则为$\beta$。 +给定每个假设下的VAR模型: +- $H_0$: $x_{t+1} = A^{(0)} x_t + C^{(0)} w_{t+1}$ +- $H_1$: $x_{t+1} = A^{(1)} x_t + C^{(1)} w_{t+1}$ -量$\alpha$被称为临界区域的*大小*, -而量$1-\beta$被称为临界区域的*检验力*。 +其中 $w_t \sim \mathcal{N}(0, I)$ 且: -Wald指出 +$$ +A^{(0)} = \begin{bmatrix} 0.8 & 0.1 \\ 0.2 & 0.7 \end{bmatrix}, \quad +C^{(0)} = \begin{bmatrix} 0.3 & 0.1 \\ 0.1 & 0.3 \end{bmatrix} +$$ -> 如果一个临界区域$W$具有更小的$\alpha$和$\beta$值, -> 那么它比另一个更可取。虽然 +$$ +A^{(1)} = \begin{bmatrix} 0.6 & 0.2 \\ 0.3 & 0.5 \end{bmatrix}, \quad +C^{(1)} = \begin{bmatrix} 0.4 & 0 \\ 0 & 0.4 \end{bmatrix} +$$ -> 通过适当选择临界区域 $W$,$\alpha$ 或 $\beta$ 中的任一个都可以被任意缩小, -> 但在固定样本量 $n$ 的情况下,不可能同时使 $\alpha$ 和 $\beta$ 都任意小。 +任务: +1. 使用VAR讲座中的函数实现VAR似然比 +2. 实现Wald的序贯检验,其中 $\alpha = 0.05$ 且 $\beta = 0.10$ +3. 分析在两个假设下以及模型错误设定情况下的表现 +4. 在停止时间和准确性方面与马尔可夫链情况进行比较 -Wald 总结了 Neyman 和 Pearson 的设置如下: +``` -> Neyman 和 Pearson 证明,由满足以下不等式的所有样本 -> $(z_1, z_2, \ldots, z_n)$ 构成的区域 -> -> $$ - \frac{ f_1(z_1) \cdots f_1(z_n)}{f_0(z_1) \cdots f_0(z_n)} \geq k - $$ -> -> 是检验假设 $H_0$ 对立假设 $H_1$ 的最优势临界区域。 -> 右侧的常数项 $k$ 的选择使得该区域具有所需的显著性水平 $\alpha$。 +```{solution-start} wald_friedman_ex2 +:class: dropdown +``` -Wald 接着讨论了 Neyman 和 Pearson 的*一致最优势*检验的概念。 +以下是该练习的一个解决方案。 -以下是 Wald 引入序贯检验概念的方式: +首先我们定义VAR模型和模拟器的参数 -> 在任何阶段都给出一个规则来做出以下三个决定中的一个: +```{code-cell} ipython3 +VARSPRTParams = namedtuple('VARSPRTParams', + ['α', 'β', 'A_0', 'C_0', 'A_1', 'C_1', 'N', 'seed']) + +def create_var_model(A, C): + """创建VAR模型。""" + μ_0 = np.zeros(A.shape[0]) + CC = C @ C.T + Σ_0 = sp.linalg.solve_discrete_lyapunov(A, CC) + + CC_inv = np.linalg.inv(CC + 1e-10 * np.eye(CC.shape[0])) + Σ_0_inv = np.linalg.inv(Σ_0 + 1e-10 * np.eye(Σ_0.shape[0])) + + return { + 'A': A, 'C': C, 'μ_0': μ_0, 'Σ_0': Σ_0, + 'CC_inv': CC_inv, 'Σ_0_inv': Σ_0_inv, + 'log_det_CC': np.log( + np.linalg.det(CC + 1e-10 * np.eye(CC.shape[0]))), + 'log_det_Σ_0': np.log( + np.linalg.det(Σ_0 + 1e-10 * np.eye(Σ_0.shape[0]))) + } +``` -> 实验(在第m次试验中,m为整数值):(1)接受假设H,(2)拒绝假设H,(3) -> 通过进行额外观察来继续实验。因此,这样的检验程序是按顺序进行的。基于第一次 -> 观察,做出上述决策之一。如果做出第一个或第二个决策,过程就终止。如果做出第 -> 三个决策,则进行第二次试验。同样,基于前两次观察,做出三个决策中的一个。如 -> 果做出第三个决策,则进行第三次试验,依此类推。这个过程持续进行,直到做出第 -> 一个或第二个决策为止。这种检验程序所需的观察次数n是一个随机变量,因为n的值 -> 取决于观察的结果。 +现在我们为VAR模型定义似然比和SPRT函数,类似于马尔可夫链的情况 -[^f1]: 决策者的行为就像他相信随机变量序列 +```{code-cell} ipython3 +def var_log_likelihood(x_curr, x_prev, model, initial=False): + """计算VAR对数似然。""" + n = len(x_curr) + if initial: + diff = x_curr - model['μ_0'] + return -0.5 * (n * np.log(2 * np.pi) + model['log_det_Σ_0'] + + diff @ model['Σ_0_inv'] @ diff) + else: + diff = x_curr - model['A'] @ x_prev + return -0.5 * (n * np.log(2 * np.pi) + model['log_det_CC'] + + diff @ model['CC_inv'] @ diff) + +def var_sprt_single_run(model_0, model_1, model_true, + logA, logB, seed): + """单次VAR SPRT运行。""" + np.random.seed(seed) + max_T = 500 + + # 生成VAR路径 + Σ_chol = np.linalg.cholesky(model_true['Σ_0']) + x = model_true['μ_0'] + Σ_chol @ np.random.randn( + len(model_true['μ_0'])) + + # 初始似然比 + log_L = (var_log_likelihood(x, None, model_1, True) - + var_log_likelihood(x, None, model_0, True)) + + if log_L >= logA: return 1, False + if log_L <= logB: return 1, True + + # 序贯更新 + for t in range(1, max_T): + x_prev = x.copy() + w = np.random.randn(model_true['C'].shape[1]) + x = model_true['A'] @ x + model_true['C'] @ w + + log_L += (var_log_likelihood(x, x_prev, model_1) - + var_log_likelihood(x, x_prev, model_0)) + + if log_L >= logA: return t+1, False + if log_L <= logB: return t+1, True + + return max_T, log_L < 0 + +def run_var_sprt(params): + """运行VAR SPRT。""" + + model_0 = create_var_model(params.A_0, params.C_0) + model_1 = create_var_model(params.A_1, params.C_1) + A, B, logA, logB = compute_wald_thresholds(params.α, params.β) + + stopping_times = np.zeros(params.N) + decisions_h0 = np.zeros(params.N, dtype=bool) + truth_h0 = np.zeros(params.N, dtype=bool) + + for i in range(params.N): + model_true = model_0 if i % 2 == 0 else model_1 + truth_h0[i] = i % 2 == 0 + + n, accept_h0 = var_sprt_single_run(model_0, model_1, model_true, + logA, logB, params.seed + i) + stopping_times[i] = n + decisions_h0[i] = accept_h0 + + type_I = np.sum(truth_h0 & ~decisions_h0) / np.sum(truth_h0) + type_II = np.sum(~truth_h0 & decisions_h0) / np.sum(~truth_h0) + + return {'stopping_times': stopping_times, + 'decisions_h0': decisions_h0, + 'truth_h0': truth_h0, + 'type_I': type_I, 'type_II': type_II} +``` -$[z_{0}, z_{1}, \ldots]$ 是*可交换的*。参见[可交换性和贝叶斯更新](https://python.quantecon.org/exchangeable.html)和 -{cite}`Kreps88`第11章对可交换性的讨论。 -## 后续内容 +让我们运行SPRT并可视化结果 -我们将在以下讲座中深入探讨这里使用的一些概念: +```{code-cell} ipython3 +# 运行 VAR SPRT +A_0 = np.array([[0.8, 0.1], + [0.2, 0.7]]) +C_0 = np.array([[0.3, 0.1], + [0.1, 0.3]]) +A_1 = np.array([[0.6, 0.2], + [0.3, 0.5]]) +C_1 = np.array([[0.4, 0.0], + [0.0, 0.4]]) + +params_var = VARSPRTParams(α=0.05, β=0.10, + A_0=A_0, C_0=C_0, A_1=A_1, C_1=C_1, + N=1000, seed=42) +results_var = run_var_sprt(params_var) + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) + +ax1.boxplot([results_markov['stopping_times'], + results_var['stopping_times']], + tick_labels=['马尔可夫链', 'VAR(1)']) +ax1.set_ylabel('停止时间') + +x = np.arange(2) +ax2.bar(x - 0.2, [results_markov['type_I'], results_var['type_I']], + 0.4, label='第一类错误', alpha=0.7) +ax2.bar(x + 0.2, [results_markov['type_II'], results_var['type_II']], + 0.4, label='第二类错误', alpha=0.7) +ax2.axhline(y=0.05, linestyle='--', alpha=0.5, color='C0') +ax2.axhline(y=0.10, linestyle='--', alpha=0.5, color='C1') +ax2.set_xticks(x), ax2.set_xticklabels(['马尔可夫', 'VAR']) +ax2.legend() +plt.tight_layout() +plt.show() +``` -* {doc}`本讲座 ` 讨论了合理化统计学习的关键概念**可交换性** -* {doc}`本讲座 ` 描述了**似然比过程**及其在频率派和贝叶斯统计理论中的作用 -* {doc}`本讲座 ` 讨论了似然比过程在**贝叶斯学习**中的作用 -* {doc}`本讲座 ` 回到本讲座的主题,研究海军命令舰长使用的(频率派)决策规则是否可以预期会比Abraham Wald设计的序贯规则更好或更差 +```{solution-end} +``` diff --git a/lectures/wald_friedman_2.md b/lectures/wald_friedman_2.md new file mode 100644 index 00000000..067f8066 --- /dev/null +++ b/lectures/wald_friedman_2.md @@ -0,0 +1,732 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +(wald_friedman_2)= +```{raw} jupyter + +``` + +# {index}`用贝叶斯方法解决弗里德曼和瓦尔德问题 ` + +```{index} single: Models; Sequential analysis +``` + +```{contents} 目录 +:depth: 2 +``` + +## 概述 + +本讲座重新审视了二战期间弗里德曼和W·艾伦·瓦利斯在哥伦比亚大学美国政府统计研究组担任分析师时面临的统计决策问题。 + +在{doc}`之前的讲座`中,我们描述了亚伯拉罕·瓦尔德{cite}`Wald47`如何通过扩展频率论假设检验技术并将问题顺序化来解决这个问题。 + +```{note} +瓦尔德将问题顺序化的想法与理查德·贝尔曼在1950年代发展的**动态规划**建立了联系。 +``` + +正如我们在{doc}`prob_matrix`和{doc}`prob_meaning`中所学到的,频率学派统计学家将概率分布视为从已知概率分布中进行大量独立同分布抽样时所构建的统计量的相对频率的度量。 + +这个已知的概率分布就是他的"假设"。 + +频率学派统计学家研究在该已知概率分布下统计量的分布 + +* 当分布是参数化概率分布集合中的一个成员时,他的假设表现为特定的参数向量形式。 +* 这就是我们所说的频率学派统计学家"以参数为条件"的含义 +* 他将参数视为自然界已知但他本人未知的固定数值。 +* 统计学家通过构建与频率学派假设检验相关的第一类和第二类错误来应对他对这些参数的无知。 + +在本讲中,我们通过将视角从{doc}`关于沃尔德序贯分析的讲座`中的"客观"频率学派观点转变为贝叶斯决策者的明确"主观"观点来重新构建弗里德曼和沃尔德的问题。贝叶斯决策者将参数视为不是固定数值,而是与他通过从联合分布中抽样可以观察到的随机变量共同分布的(隐藏)随机变量。 + +为了形成联合分布,贝叶斯统计学家在频率派统计学家使用的条件分布基础上,补充了一个表示其个人主观意见的参数先验概率分布。 + +这让贝叶斯统计学家能够计算出他需要的联合分布,从而计算他想要的条件分布。 + +要按这种方式进行,我们需要赋予决策者以下条件: + +- 一个初始先验主观概率 $\pi_{-1} \in (0,1)$,表示自然界使用 $f_1$ 而不是 $f_0$ 生成 i.i.d. 序列 $\{z_k\}$ 的概率 +- 相信贝叶斯定律作为在观察到 $\{z_k\}$ 序列时修正其主观信念的方法 +- 一个损失函数,用于衡量决策者如何评估第一类和第二类错误 + +在我们的{doc}`之前的频率派版本`中,主要涉及的概念有: + +- 第一类和第二类统计错误 + - 第一类错误是指在原假设为真时拒绝它 + - 第二类错误是指在原假设为假时接受它 +- Abraham Wald的**序贯概率比检验** +- 统计检验的**检验力** +- 统计检验的**临界区域** +- **一致最优检验** + +在这个问题的贝叶斯重构讲座中,还包含以下额外概念: +- 模型 $f_1$ 生成数据的初始先验概率 $\pi_{-1}$ +- 贝叶斯定律 + +- 模型 $f_1$ 生成数据的后验概率序列 +- 动态规划 + + +本讲座使用了在 {doc}`似然比过程`、{doc}`它们在贝叶斯学习中的作用` 和 {doc}`这个关于可交换性的讲座` 中研究的概念。 + + +让我们从一些导入开始: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" +mpl.font_manager.fontManager.addfont(FONTPATH) +plt.rcParams['font.family'] = ['Source Han Serif SC'] + +from numba import jit, prange, float64, int64 +from numba.experimental import jitclass +from math import gamma +``` + +## 动态规划方法 + +以下对问题的介绍主要遵循Dmitri Bertsekas在**动态规划与随机控制**{cite}`Bertsekas75`中的处理方式。 + +决策者可以观察到一个随机变量$z$的一系列抽样。 + +他(或她)想要知道是概率分布$f_0$还是$f_1$支配着$z$。 + +在已知连续观察值是从分布$f_0$中抽取的条件下,这个随机变量序列是独立同分布的(IID)。 + +在已知连续观察值是从分布$f_1$中抽取的条件下,这个随机变量序列也是独立同分布的(IID)。 + +但观察者并不知道是哪个分布生成了这个序列。 + +由[可交换性和贝叶斯更新](https://python.quantecon.org/exchangeable.html)中解释的原因,这意味着该序列不是IID的。 + +观察者有需要学习的东西,即观察值是从$f_0$还是从$f_1$中抽取的。 + +决策者想要确定是哪个分布在生成结果。 + +我们采用贝叶斯方法。 + +决策者从先验概率开始 + +$$ +\pi_{-1} = +\mathbb P \{ f = f_1 \mid \textrm{ 无观察值} \} \in (0, 1) +$$ + +```{note} +在{cite:t}`Bertsekas75`中,信念是与分布$f_0$相关联的,但在这里 + +我们将信念与分布 $f_1$ 关联起来,以匹配{doc}`关于Wald序贯分析的讲座`中的讨论。 +``` + +在观察到 $k+1$ 个观测值 $z_k, z_{k-1}, \ldots, z_0$ 后,他将观测值由分布 $f_1$ 描述的个人概率更新为 + +$$ +\pi_k = \mathbb P \{ f = f_1 \mid z_k, z_{k-1}, \ldots, z_0 \} +$$ + +这是通过应用贝叶斯定律递归计算的: + +$$ +\pi_{k+1} = \frac{ \pi_k f_1(z_{k+1})}{ (1-\pi_k) f_0(z_{k+1}) + \pi_k f_1 (z_{k+1}) }, +\quad k = -1, 0, 1, \ldots +$$ + +在观察到 $z_k, z_{k-1}, \ldots, z_0$ 后,决策者认为 $z_{k+1}$ 的概率分布为 + +$$ +f_{{\pi}_k} (v) = (1-\pi_k) f_0(v) + \pi_k f_1 (v) , +$$ + +这是分布 $f_0$ 和 $f_1$ 的混合,其中 $f_1$ 的权重是 $f = f_1$ 的后验概率[^f1]。 + +为了说明这样的分布,让我们检查一些beta分布的混合。 + +参数为 $a$ 和 $b$ 的beta概率分布的密度函数是 + +$$ +f(z; a, b) = \frac{\Gamma(a+b) z^{a-1} (1-z)^{b-1}}{\Gamma(a) \Gamma(b)} +\quad \text{where} \quad +\Gamma(t) := \int_{0}^{\infty} x^{t-1} e^{-x} dx +$$ + +下图的上面板显示了两个beta分布。 + +下面板展示了这些分布的混合,使用了不同的混合概率 $\pi_k$ + +```{code-cell} ipython3 +@jit +def p(x, a, b): + r = gamma(a + b) / (gamma(a) * gamma(b)) + return r * x**(a-1) * (1 - x)**(b-1) + +f0 = lambda x: p(x, 1, 1) +f1 = lambda x: p(x, 9, 9) +grid = np.linspace(0, 1, 50) + +fig, axes = plt.subplots(2, figsize=(10, 8)) + +axes[0].set_title("Original Distributions") +axes[0].plot(grid, f0(grid), lw=2, label="$f_0$") +axes[0].plot(grid, f1(grid), lw=2, label="$f_1$") + +axes[1].set_title("Mixtures") +for π in 0.25, 0.5, 0.75: + y = (1 - π) * f0(grid) + π * f1(grid) + axes[1].plot(grid, y, lw=2, label=fr"$\pi_k$ = {π}") + +for ax in axes: + ax.legend() + ax.set(xlabel="$z$ values", ylabel="probability of $z_k$") + +plt.tight_layout() +plt.show() +``` + +### 损失和成本 + +在观察到 $z_k, z_{k-1}, \ldots, z_0$ 后,决策者可以在三种不同的行动中选择: + +- 他确定 $f = f_0$ 并不再抽取 $z$ 值 +- 他确定 $f = f_1$ 并不再抽取 $z$ 值 +- 他推迟现在做决定,转而选择抽取一个 $z_{k+1}$ + +与这三种行动相关,决策者可能遭受三种损失: + +- 当实际上 $f=f_1$ 时,他决定 $f = f_0$ 会遭受损失 $L_0$ +- 当实际上 $f=f_0$ 时,他决定 $f = f_1$ 会遭受损失 $L_1$ +- 如果他推迟决定并选择再抽取一个 $z$,会产生成本 $c$ + +### 关于第一类和第二类错误的说明 + +如果我们将 $f=f_0$ 视为零假设,将 $f=f_1$ 视为备择假设,那么 $L_1$ 和 $L_0$ 是与两类统计错误相关的损失 + +- 第一类错误是错误地拒绝了真实的零假设("假阳性") +- 第二类错误是未能拒绝错误的零假设("假阴性") + +因此当我们将 $f=f_0$ 作为零假设时 + +- 我们可以将 $L_1$ 视为与第一类错误相关的损失 +- 我们可以将 $L_0$ 视为与第二类错误相关的损失 + +### 直观理解 + +在继续之前,让我们试着猜测最优决策规则可能是什么样的。 + +假设在某个时间点 $\pi$ 接近于1。 + +那么我们的先验信念和到目前为止的证据都强烈指向 $f = f_1$。 + +另一方面,如果 $\pi$ 接近于0,那么 $f = f_0$ 的可能性更大。 + +最后,如果$\pi$位于区间$[0, 1]$的中间,我们就会面临更多的不确定性。 + +这种推理建议采用一个顺序决策规则,我们在下图中说明: + +```{figure} /_static/lecture_specific/wald_friedman_2/wald_dec_rule.png + +``` + +正如我们将看到的,这确实是决策规则的正确形式。 + +我们的问题是确定阈值$A, B$,这些阈值以某种方式依赖于上述参数。 + +在这一点上,你可能想暂停一下,试着预测像$c$或$L_0$这样的参数对$A$或$B$的影响。 + +### 贝尔曼方程 + +让$J(\pi)$表示当前信念为$\pi$的决策者在最优选择下的总损失。 + +**动态规划**原理告诉我们,最优损失函数$J$满足以下贝尔曼函数方程 + +```{math} +:label: new1 + +J(\pi) = + \min + \left\{ + \underbrace{\pi L_0}_{ \text{接受 } f_0 } \; , \; \underbrace{(1-\pi) L_1}_{ \text{接受 } f_1 } \; , \; + \underbrace{c + \mathbb E [ J (\pi') ]}_{ \text{再次抽样} } + \right\} +``` + +其中$\pi'$是由贝叶斯法则定义的随机变量 + +$$ +\pi' = \kappa(z', \pi) = \frac{ \pi f_1(z')}{ (1-\pi) f_0(z') + \pi f_1 (z') } +$$ + +当$\pi$固定且$z'$从当前最佳猜测分布$f$中抽取时,该分布定义为 + +$$ +f_{\pi}(v) = (1-\pi) f_0(v) + \pi f_1 (v) +$$ + +在贝尔曼方程中,最小化是针对三个行动: + +1. 接受假设 $f = f_0$ +1. 接受假设 $f = f_1$ +1. 推迟决定并再次抽样 + +我们可以将贝尔曼方程表示为 + +```{math} +:label: optdec + +J(\pi) = +\min \left\{ \pi L_0, \; (1-\pi) L_1, \; h(\pi) \right\} +``` + +其中 $\pi \in [0,1]$ 且 + +- $\pi L_0$ 是接受 $f_0$ 的预期损失(即犯第II类错误的成本)。 +- $(1-\pi) L_1$ 是接受 $f_1$ 的预期损失(即犯第I类错误的成本)。 +- $h(\pi) := c + \mathbb E [J(\pi')]$;这是继续值;即与再抽取一个 $z$ 相关的预期成本。 + +最优决策规则由两个数 $A, B \in (0,1) \times (0,1)$ 来表征,满足 + +$$ +\pi L_0 < \min \{ (1-\pi) L_1, c + \mathbb E [J(\pi')] \} \textrm { if } \pi \leq B +$$ + +和 + +$$ +(1- \pi) L_1 < \min \{ \pi L_0, c + \mathbb E [J(\pi')] \} \textrm { if } \pi \geq A +$$ + +则最优决策规则为 + +$$ +\begin{aligned} +\textrm { 接受 } f=f_1 \textrm{ 如果 } \pi \geq A \\ +\textrm { 接受 } f=f_0 \textrm{ 如果 } \pi \leq B \\ +\textrm { 再抽取一个 } z \textrm{ 如果 } B < \pi < A +\end{aligned} +$$ + +我们的目标是计算成本函数 $J$ 以及相关的临界值 $A$ 和 $B$。 + +为了使我们的计算更易于管理,我们可以使用 {eq}`optdec` 将继续成本 $h(\pi)$ 写为 + +```{math} +:label: optdec2 + +\begin{aligned} +h(\pi) &= c + \mathbb E [J(\pi')] \\ + +&= c + \mathbb E_{\pi'} \min \{ \pi' L_0, (1 - \pi') L_1, h(\pi') \} \\ +&= c + \int \min \{ \kappa(z', \pi) L_0, (1 - \kappa(z', \pi) ) L_1, h(\kappa(z', \pi) ) \} f_\pi (z') dz' +\end{aligned} +``` + +等式 + +```{math} +:label: funceq + +h(\pi) = +c + \int \min \{ \kappa(z', \pi) L_0, (1 - \kappa(z', \pi) ) L_1, h(\kappa(z', \pi) ) \} f_\pi (z') dz' +``` + +是一个未知函数 $h$ 的方程。 + +```{note} +这种方程被称为**泛函方程**。 +``` + +使用延续成本的泛函方程 {eq}`funceq`,我们可以通过 {eq}`optdec` 的右侧推导出最优选择。 + +这个泛函方程可以通过取一个初始猜测并迭代来找到不动点来求解。 + +因此,我们用算子 $Q$ 进行迭代,其中 + +$$ +Q h(\pi) = +c + \int \min \{ \kappa(z', \pi) L_0, (1 - \kappa(z', \pi) ) L_1, h(\kappa(z', \pi) ) \} f_\pi (z') dz' +$$ + +## 实现 + +首先,我们将构造一个 `jitclass` 来存储模型的参数 + +```{code-cell} ipython3 +wf_data = [('a0', float64), # beta分布的参数 + ('b0', float64), + ('a1', float64), + ('b1', float64), + ('c', float64), # 另一次抽样的成本 + ('π_grid_size', int64), + ('L0', float64), # 当f1为真时选择f0的成本 + ('L1', float64), # 当f0为真时选择f1的成本 + ('π_grid', float64[:]), + ('mc_size', int64), + ('z0', float64[:]), + ('z1', float64[:])] +``` + +```{code-cell} ipython3 +@jitclass(wf_data) +class WaldFriedman: + + def __init__(self, + c=1.25, + a0=1, + b0=1, + a1=3, + b1=1.2, + L0=25, + L1=25, + π_grid_size=200, + mc_size=1000): + + self.a0, self.b0 = a0, b0 + self.a1, self.b1 = a1, b1 + self.c, self.π_grid_size = c, π_grid_size + self.L0, self.L1 = L0, L1 + self.π_grid = np.linspace(0, 1, π_grid_size) + self.mc_size = mc_size + + self.z0 = np.random.beta(a0, b0, mc_size) + self.z1 = np.random.beta(a1, b1, mc_size) + + def f0(self, x): + + return p(x, self.a0, self.b0) + + def f1(self, x): + + return p(x, self.a1, self.b1) + + def f0_rvs(self): + return np.random.beta(self.a0, self.b0) + + def f1_rvs(self): + return np.random.beta(self.a1, self.b1) + + def κ(self, z, π): + """ + 使用贝叶斯法则和当前观测值z更新π + """ + + f0, f1 = self.f0, self.f1 + + π_f0, π_f1 = (1 - π) * f0(z), π * f1(z) + π_new = π_f1 / (π_f0 + π_f1) + + return π_new +``` + +如同{doc}`最优增长讲座 `中所述,为了近似连续的值函数 + +* 我们在有限的 $\pi$ 值网格上进行迭代。 +* 当我们在网格点之间评估 $\mathbb E[J(\pi')]$ 时,我们使用线性插值。 + +我们在下面定义算子函数 `Q`。 + +```{code-cell} ipython3 +@jit(nopython=True, parallel=True) +def Q(h, wf): + + c, π_grid = wf.c, wf.π_grid + L0, L1 = wf.L0, wf.L1 + z0, z1 = wf.z0, wf.z1 + mc_size = wf.mc_size + + κ = wf.κ + + h_new = np.empty_like(π_grid) + h_func = lambda p: np.interp(p, π_grid, h) + + for i in prange(len(π_grid)): + π = π_grid[i] + + # Find the expected value of J by integrating over z + integral_f0, integral_f1 = 0, 0 + for m in range(mc_size): + π_0 = κ(z0[m], π) # Draw z from f0 and update π + integral_f0 += min(π_0 * L0, (1 - π_0) * L1, h_func(π_0)) + + π_1 = κ(z1[m], π) # Draw z from f1 and update π + integral_f1 += min(π_1 * L0, (1 - π_1) * L1, h_func(π_1)) + + integral = ((1 - π) * integral_f0 + π * integral_f1) / mc_size + + h_new[i] = c + integral + + return h_new +``` + +为了求解关键的函数方程,我们将使用`Q`进行迭代以找到不动点 + +```{code-cell} ipython3 +@jit +def solve_model(wf, tol=1e-4, max_iter=1000): + """ + 计算延续成本函数 + + * wf 是 WaldFriedman 的一个实例 + """ + + # 设置循环 + h = np.zeros(len(wf.π_grid)) + i = 0 + error = tol + 1 + + while i < max_iter and error > tol: + h_new = Q(h, wf) + error = np.max(np.abs(h - h_new)) + i += 1 + h = h_new + + if error > tol: + print("未能收敛!") + + return h_new +``` + +## 分析 + +让我们检查结果。 + +我们将使用默认参数化的分布,如下所示 + +```{code-cell} ipython3 +wf = WaldFriedman() + +fig, ax = plt.subplots(figsize=(10, 6)) +ax.plot(wf.f0(wf.π_grid), label="$f_0$") +ax.plot(wf.f1(wf.π_grid), label="$f_1$") +ax.set(ylabel="$z_k$的概率", xlabel="$z_k$", title="分布") +ax.legend() + +plt.show() +``` + +### 成本函数 + +为了求解模型,我们将调用我们的`solve_model`函数 + +```{code-cell} ipython3 +h_star = solve_model(wf) # 求解模型 +``` + +我们还将设置一个函数来计算截断值 $A$ 和 $B$,并在成本函数图上绘制这些值 + +```{code-cell} ipython3 +@jit +def find_cutoff_rule(wf, h): + + """ + 该函数接收一个延续成本函数,并返回在继续采样和选择特定模型之间 + 转换的对应截断点 + """ + + π_grid = wf.π_grid + L0, L1 = wf.L0, wf.L1 + + # 在网格上所有点计算选择模型的成本 + cost_f0 = π_grid * L0 + cost_f1 = (1 - π_grid) * L1 + + # 找到B: cost_f0 <= min(cost_f1, h)时最大的π + optimal_cost = np.minimum(np.minimum(cost_f0, cost_f1), h) + choose_f0 = (cost_f0 <= cost_f1) & (cost_f0 <= h) + + if np.any(choose_f0): + B = π_grid[choose_f0][-1] # 我们选择f0的最后一点 + else: + assert False, "没有选择f0的点" + + # 找到A: cost_f1 <= min(cost_f0, h)时最小的π + choose_f1 = (cost_f1 <= cost_f0) & (cost_f1 <= h) + + if np.any(choose_f1): + A = π_grid[choose_f1][0] # 我们选择f1的第一点 + else: + assert False, "没有选择f1的点" + + return (B, A) + +B, A = find_cutoff_rule(wf, h_star) +cost_L0 = wf.π_grid * wf.L0 +cost_L1 = (1 - wf.π_grid) * wf.L1 + +fig, ax = plt.subplots(figsize=(10, 6)) + +ax.plot(wf.π_grid, h_star, label='再次采样') +ax.plot(wf.π_grid, cost_L1, label='选择f1') +ax.plot(wf.π_grid, cost_L0, label='选择f0') +ax.plot(wf.π_grid, + np.amin(np.column_stack([h_star, cost_L0, cost_L1]),axis=1), + lw=15, alpha=0.1, color='b', label=r'$J(\pi)$') + +ax.annotate(r"$B$", xy=(B + 0.01, 0.5), fontsize=14) +ax.annotate(r"$A$", xy=(A + 0.01, 0.5), fontsize=14) + +plt.vlines(B, 0, (1 - B) * wf.L1, linestyle="--") +plt.vlines(A, 0, A * wf.L0, linestyle="--") + +ax.set(xlim=(0, 1), ylim=(0, 0.5 * max(wf.L0, wf.L1)), ylabel="成本", + xlabel=r"$\pi$", title=r"成本函数 $J(\pi)$") + +plt.legend(borderpad=1.1) +plt.show() +``` + +成本函数$J$在$\pi \leq B$时等于$\pi L_0$,在$\pi \geq A$时等于$(1-\pi) L_1$。 + +成本函数$J(\pi)$两个线性部分的斜率由$L_0$和$-L_1$决定。 + +在内部区域,当分配给$f_1$的后验概率处于犹豫区间$\pi \in (B, A)$时,成本函数$J$是平滑的。 + +决策者继续采样,直到他对模型$f_1$的概率低于$B$或高于$A$。 + +### 模拟 + +下图显示了决策过程的500次模拟结果。 + +左图是**停止时间**的直方图,即做出决策所需的$z_k$抽样次数。 + +平均抽样次数约为6.6。 + +右图是在停止时间时正确决策的比例。 + +在这种情况下,决策者80%的时间做出正确决策。 + +```{code-cell} ipython3 +def simulate(wf, true_dist, h_star, π_0=0.5): + + """ + 该函数接受一个初始条件并进行模拟,直到停止(当做出决策时) + """ + + f0, f1 = wf.f0, wf.f1 + f0_rvs, f1_rvs = wf.f0_rvs, wf.f1_rvs + π_grid = wf.π_grid + κ = wf.κ + + if true_dist == "f0": + f, f_rvs = wf.f0, wf.f0_rvs + elif true_dist == "f1": + f, f_rvs = wf.f1, wf.f1_rvs + + # 找到截断点 + B, A = find_cutoff_rule(wf, h_star) + + # 初始化几个有用的变量 + decision_made = False + π = π_0 + t = 0 + + while decision_made is False: + z = f_rvs() + t = t + 1 + π = κ(z, π) + if π < B: + decision_made = True + decision = 0 + elif π > A: + decision_made = True + decision = 1 + + if true_dist == "f0": + if decision == 0: + correct = True + else: + correct = False + + elif true_dist == "f1": + if decision == 1: + correct = True + else: + correct = False + + return correct, π, t + +def stopping_dist(wf, h_star, ndraws=250, true_dist="f0"): + + """ + 重复模拟以获得做出决策所需时间的分布以及正确决策的频率 + """ + + tdist = np.empty(ndraws, int) + cdist = np.empty(ndraws, bool) + + for i in range(ndraws): + correct, π, t = simulate(wf, true_dist, h_star) + tdist[i] = t + cdist[i] = correct + + return cdist, tdist + +def simulation_plot(wf): + h_star = solve_model(wf) + ndraws = 500 + cdist, tdist = stopping_dist(wf, h_star, ndraws) + + fig, ax = plt.subplots(1, 2, figsize=(16, 5)) + + ax[0].hist(tdist, bins=np.max(tdist)) + ax[0].set_title(f"在{ndraws}次重复中的停止时间") + ax[0].set(xlabel="时间", ylabel="停止次数") + ax[0].annotate(f"平均值 = {np.mean(tdist)}", xy=(max(tdist) / 2, + max(np.histogram(tdist, bins=max(tdist))[0]) / 2)) + + ax[1].hist(cdist.astype(int), bins=2) + ax[1].set_title(f"在{ndraws}次重复中的正确决策") + ax[1].annotate(f"正确率 = {np.mean(cdist)}", + xy=(0.05, ndraws / 2)) + + plt.show() + +simulation_plot(wf) +``` + +### 比较静态分析 + +现在让我们来看下面这个练习。 + +我们将获取额外观测值的成本提高一倍。 + +在查看结果之前,请思考会发生什么: + +- 决策者的判断正确率会提高还是降低? +- 他会更早还是更晚做出决定? + +```{code-cell} ipython3 +wf = WaldFriedman(c=2.5) +simulation_plot(wf) +``` + + +由于每次抽样成本的增加,决策者在做出决定前会减少抽样次数。 + +因为他用更少的抽样来做决定,他的正确判断比例下降。 + +当他对两个模型赋予相同权重时,这导致他的预期损失更高。 + +为了便于比较静态分析,我们邀请您调整模型参数并研究: + +* 当我们增加分段线性近似中的网格点数量时,对不确定中间范围内价值函数平滑性的影响。 +* 不同成本参数 $L_0, L_1, c$、两个贝塔分布 $f_0$ 和 $f_1$ 的参数,以及用于价值函数分段连续近似的点数和线性函数数量 $m$ 的设置效果。 +* 从 $f_0$ 进行的各种模拟以及做出决定前等待时间的分布。 +* 相关的正确和错误决定的直方图。 + + +[^f1]: 决策者的行为就像他相信随机变量序列 $[z_{0}, z_{1}, \ldots]$ 是*可交换的*。关于可交换性的讨论,请参见[可交换性和贝叶斯更新](https://python.quantecon.org/exchangeable.html)和 +{cite}`Kreps88`第11章。 + diff --git a/tools/lectures/prob_meaning.md b/tools/lectures/prob_meaning.md deleted file mode 100644 index dfde2187..00000000 --- a/tools/lectures/prob_meaning.md +++ /dev/null @@ -1,722 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.10.3 -kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 ---- - -# Two Meanings of Probability - - -## Overview - - -This lecture illustrates two distinct interpretations of a **probability distribution** - - * A frequentist interpretation as **relative frequencies** anticipated to occur in a large i.i.d. sample - - * A Bayesian interpretation as a **personal opinion** (about a parameter or list of parameters) after seeing a collection of observations - -We recommend watching this video about **hypothesis testing** within the frequentist approach - -```{youtube} 8JIe_cz6qGA -``` - -After you watch that video, please watch the following video on the Bayesian approach to constructing **coverage intervals** - -```{youtube} Pahyv9i_X2k -``` - -After you are familiar with the material in these videos, this lecture uses the Socratic method to to help consolidate your understanding of the different questions that are answered by - - * a frequentist confidence interval - - * a Bayesian coverage interval - -We do this by inviting you to write some Python code. - -It would be especially useful if you tried doing this after each question that we pose for you, before -proceeding to read the rest of the lecture. - -We provide our own answers as the lecture unfolds, but you'll learn more if you try writing your own code before reading and running ours. - -**Code for answering questions:** - - -In addition to what’s in Anaconda, this lecture will deploy the following library: - -```{code-cell} ipython3 -:tags: [hide-output] -pip install prettytable -``` - -To answer our coding questions, we'll start with some imports - -```{code-cell} ipython3 -import numpy as np -import pandas as pd -import prettytable as pt -import matplotlib.pyplot as plt -from scipy.stats import binom -import scipy.stats as st -``` - -Empowered with these Python tools, we'll now explore the two meanings described above. - -## Frequentist Interpretation - -Consider the following classic example. - -The random variable $X $ takes on possible values $k = 0, 1, 2, \ldots, n$ with probabilties - -$$ -\textrm{Prob}(X = k | \theta) = -\left(\frac{n!}{k! (n-k)!} \right) \theta^k (1-\theta)^{n-k} -$$ - -where the fixed parameter $\theta \in (0,1)$. - -This is called the __binomial distribution__. - -Here - -* $\theta$ is the probability that one toss of a coin will be a head, an outcome that we encode as $Y = 1$. - -* $1 -\theta$ is the probability that one toss of the coin will be a tail, an outcome that we denote $Y = 0$. - -* $X$ is the total number of heads that came up after flipping the coin $n$ times. - -Consider the following experiment: - -Take $I$ **independent** sequences of $n$ **independent** flips of the coin - -Notice the repeated use of the adjective **independent**: - -* we use it once to describe that we are drawing $n$ independent times from a **Bernoulli** distribution with parameter $\theta$ to arrive at one draw from a **Binomial** distribution with parameters -$\theta,n$. - -* we use it again to describe that we are then drawing $I$ sequences of $n$ coin draws. - -Let $y_h^i \in \{0, 1\}$ be the realized value of $Y$ on the $h$th flip during the $i$th sequence of flips. - -Let $\sum_{h=1}^n y_h^i$ denote the total number of times heads come up during the $i$th sequence of $n$ independent coin flips. - -Let $f_k$ record the fraction of samples of length $n$ for which $\sum_{h=1}^n y_h^i = k$: - -$$ -f_k^I = \frac{\textrm{number of samples of length n for which } \sum_{h=1}^n y_h^i = k}{ - I} -$$ - -The probability $\textrm{Prob}(X = k | \theta)$ answers the following question: - -* As $I$ becomes large, in what fraction of $I$ independent draws of $n$ coin flips should we anticipate $k$ heads to occur? - -As usual, a law of large numbers justifies this answer. - -```{exercise} -:label: pm_ex1 - -1. Please write a Python class to compute $f_k^I$ - -2. Please use your code to compute $f_k^I, k = 0, \ldots , n$ and compare them to - $\textrm{Prob}(X = k | \theta)$ for various values of $\theta, n$ and $I$ - -3. With the Law of Large numbers in mind, use your code to say something -``` - -```{solution-start} pm_ex1 -:class: dropdown -``` - -Here is one solution: - -```{code-cell} ipython3 -class frequentist: - - def __init__(self, θ, n, I): - - ''' - initialization - ----------------- - parameters: - θ : probability that one toss of a coin will be a head with Y = 1 - n : number of independent flips in each independent sequence of draws - I : number of independent sequence of draws - - ''' - - self.θ, self.n, self.I = θ, n, I - - def binomial(self, k): - - '''compute the theoretical probability for specific input k''' - - θ, n = self.θ, self.n - self.k = k - self.P = binom.pmf(k, n, θ) - - def draw(self): - - '''draw n independent flips for I independent sequences''' - - θ, n, I = self.θ, self.n, self.I - sample = np.random.rand(I, n) - Y = (sample <= θ) * 1 - self.Y = Y - - def compute_fk(self, kk): - - '''compute f_{k}^I for specific input k''' - - Y, I = self.Y, self.I - K = np.sum(Y, 1) - f_kI = np.sum(K == kk) / I - self.f_kI = f_kI - self.kk = kk - - def compare(self): - - '''compute and print the comparison''' - - n = self.n - comp = pt.PrettyTable() - comp.field_names = ['k', 'Theoretical', 'Frequentist'] - self.draw() - for i in range(n): - self.binomial(i+1) - self.compute_fk(i+1) - comp.add_row([i+1, self.P, self.f_kI]) - print(comp) -``` - -```{code-cell} ipython3 -θ, n, k, I = 0.7, 20, 10, 1_000_000 - -freq = frequentist(θ, n, I) - -freq.compare() -``` - -From the table above, can you see the law of large numbers at work? - -```{solution-end} -``` - -Let's do some more calculations. - -**Comparison with different $\theta$** - -Now we fix - -$$ -n=20, k=10, I=1,000,000 -$$ - -We'll vary $\theta$ from $0.01$ to $0.99$ and plot outcomes against $\theta$. - -```{code-cell} ipython3 -θ_low, θ_high, npt = 0.01, 0.99, 50 -thetas = np.linspace(θ_low, θ_high, npt) -P = [] -f_kI = [] -for i in range(npt): - freq = frequentist(thetas[i], n, I) - freq.binomial(k) - freq.draw() - freq.compute_fk(k) - P.append(freq.P) - f_kI.append(freq.f_kI) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(8, 6)) -ax.grid() -ax.plot(thetas, P, 'k-.', label='Theoretical') -ax.plot(thetas, f_kI, 'r--', label='Fraction') -plt.title(r'Comparison with different $\theta$', fontsize=16) -plt.xlabel(r'$\theta$', fontsize=15) -plt.ylabel('Fraction', fontsize=15) -plt.tick_params(labelsize=13) -plt.legend() -plt.show() -``` - -**Comparison with different $n$** - -Now we fix $\theta=0.7, k=10, I=1,000,000$ and vary $n$ from $1$ to $100$. - -Then we'll plot outcomes. - -```{code-cell} ipython3 -n_low, n_high, nn = 1, 100, 50 -ns = np.linspace(n_low, n_high, nn, dtype='int') -P = [] -f_kI = [] -for i in range(nn): - freq = frequentist(θ, ns[i], I) - freq.binomial(k) - freq.draw() - freq.compute_fk(k) - P.append(freq.P) - f_kI.append(freq.f_kI) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(8, 6)) -ax.grid() -ax.plot(ns, P, 'k-.', label='Theoretical') -ax.plot(ns, f_kI, 'r--', label='Frequentist') -plt.title(r'Comparison with different $n$', fontsize=16) -plt.xlabel(r'$n$', fontsize=15) -plt.ylabel('Fraction', fontsize=15) -plt.tick_params(labelsize=13) -plt.legend() -plt.show() -``` - -**Comparison with different $I$** - -Now we fix $\theta=0.7, n=20, k=10$ and vary $\log(I)$ from $2$ to $7$. - -```{code-cell} ipython3 -I_log_low, I_log_high, nI = 2, 6, 200 -log_Is = np.linspace(I_log_low, I_log_high, nI) -Is = np.power(10, log_Is).astype(int) -P = [] -f_kI = [] -for i in range(nI): - freq = frequentist(θ, n, Is[i]) - freq.binomial(k) - freq.draw() - freq.compute_fk(k) - P.append(freq.P) - f_kI.append(freq.f_kI) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(8, 6)) -ax.grid() -ax.plot(Is, P, 'k-.', label='Theoretical') -ax.plot(Is, f_kI, 'r--', label='Fraction') -plt.title(r'Comparison with different $I$', fontsize=16) -plt.xlabel(r'$I$', fontsize=15) -plt.ylabel('Fraction', fontsize=15) -plt.tick_params(labelsize=13) -plt.legend() -plt.show() -``` - -From the above graphs, we can see that **$I$, the number of independent sequences,** plays an important role. - -When $I$ becomes larger, the difference between theoretical probability and frequentist estimate becomes smaller. - -Also, as long as $I$ is large enough, changing $\theta$ or $n$ does not substantially change the accuracy of the observed fraction -as an approximation of $\theta$. - -The Law of Large Numbers is at work here. - -For each draw of an independent sequence, $\textrm{Prob}(X_i = k | \theta)$ is the same, so aggregating all draws forms an i.i.d sequence of a binary random variable $\rho_{k,i},i=1,2,...I$, with a mean of $\textrm{Prob}(X = k | \theta)$ and a variance of - -$$ -n \cdot \textrm{Prob}(X = k | \theta) \cdot (1-\textrm{Prob}(X = k | \theta)). -$$ - -So, by the LLN, the average of $P_{k,i}$ converges to: - -$$ -E[\rho_{k,i}] = \textrm{Prob}(X = k | \theta) = \left(\frac{n!}{k! (n-k)!} \right) \theta^k (1-\theta)^{n-k} -$$ - -as $I$ goes to infinity. - - -## Bayesian Interpretation - -We again use a binomial distribution. - -But now we don't regard $\theta$ as being a fixed number. - -Instead, we think of it as a **random variable**. - -$\theta$ is described by a probability distribution. - -But now this probability distribution means something different than a relative frequency that we can anticipate to occur in a large i.i.d. sample. - -Instead, the probability distribution of $\theta$ is now a summary of our views about likely values of $\theta$ either - - * **before** we have seen **any** data at all, or - * **before** we have seen **more** data, after we have seen **some** data - -Thus, suppose that, before seeing any data, you have a personal prior probability distribution saying that - -$$ -P(\theta) = \frac{\theta^{\alpha-1}(1-\theta)^{\beta -1}}{B(\alpha, \beta)} -$$ - -where $B(\alpha, \beta)$ is a **beta function** , so that $P(\theta)$ is -a **beta distribution** with parameters $\alpha, \beta$. - -```{exercise} -:label: pm_ex2 - -**a)** Please write down the **likelihood function** for a sample of length $n$ from a binomial distribution with parameter $\theta$. - -**b)** Please write down the **posterior** distribution for $\theta$ after observing one flip of the coin. - -**c)** Now pretend that the true value of $\theta = .4$ and that someone who doesn't know this has a beta prior distribution with parameters with $\beta = \alpha = .5$. Please write a Python class to simulate this person's personal posterior distribution for $\theta$ for a _single_ sequence of $n$ draws. - -**d)** Please plot the posterior distribution for $\theta$ as a function of $\theta$ as $n$ grows as $1, 2, \ldots$. - -**e)** For various $n$'s, please describe and compute a Bayesian coverage interval for the interval $[.45, .55]$. - -**f)** Please tell what question a Bayesian coverage interval answers. - -**g)** Please compute the Posterior probabililty that $\theta \in [.45, .55]$ for various values of sample size $n$. - -**h)** Please use your Python class to study what happens to the posterior distribution as $n \rightarrow + \infty$, again assuming that the true value of $\theta = .4$, though it is unknown to the person doing the updating via Bayes' Law. -``` - - -```{solution-start} pm_ex2 -:class: dropdown -``` - -**a)** Please write down the **likelihood function** and the **posterior** distribution for $\theta$ after observing one flip of our coin. - -Suppose the outcome is __Y__. - -The likelihood function is: - -$$ -L(Y|\theta)= \textrm{Prob}(X = Y | \theta) = -\theta^Y (1-\theta)^{1-Y} -$$ - -**b)** Please write the **posterior** distribution for $\theta$ after observing one flip of our coin. - -The prior distribution is - -$$ -\textrm{Prob}(\theta) = \frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)} -$$ - -We can derive the posterior distribution for $\theta$ via - -\begin{align*} - \textrm{Prob}(\theta | Y) &= \frac{\textrm{Prob}(Y | \theta) \textrm{Prob}(\theta)}{\textrm{Prob}(Y)} \\ - &=\frac{\textrm{Prob}(Y | \theta) \textrm{Prob}(\theta)}{\int_{0}^{1} \textrm{Prob}(Y | \theta) \textrm{Prob}(\theta) d \theta }\\ - &= \frac{\theta^Y (1-\theta)^{1-Y}\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)}}{\int_{0}^{1}\theta^Y (1-\theta)^{1-Y}\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)} d \theta } \\ - &= \frac{ \theta^{Y+\alpha - 1} (1 - \theta)^{1-Y+\beta - 1}}{\int_{0}^{1}\theta^{Y+\alpha - 1} (1 - \theta)^{1-Y+\beta - 1} d \theta} -\end{align*} - -which means that - -$$ -\textrm{Prob}(\theta | Y) \sim \textrm{Beta}(\alpha + Y, \beta + (1-Y)) -$$ - -Now please pretend that the true value of $\theta = .4$ and that someone who doesn't know this has a beta prior with $\beta = \alpha = .5$. - -**c)** Now pretend that the true value of $\theta = .4$ and that someone who doesn't know this has a beta prior distribution with parameters with $\beta = \alpha = .5$. Please write a Python class to simulate this person's personal posterior distribution for $\theta$ for a _single_ sequence of $n$ draws. - -```{code-cell} ipython3 -class Bayesian: - - def __init__(self, θ=0.4, n=1_000_000, α=0.5, β=0.5): - """ - Parameters: - ---------- - θ : float, ranging from [0,1]. - probability that one toss of a coin will be a head with Y = 1 - - n : int. - number of independent flips in an independent sequence of draws - - α&β : int or float. - parameters of the prior distribution on θ - - """ - self.θ, self.n, self.α, self.β = θ, n, α, β - self.prior = st.beta(α, β) - - def draw(self): - """ - simulate a single sequence of draws of length n, given probability θ - - """ - array = np.random.rand(self.n) - self.draws = (array < self.θ).astype(int) - - def form_single_posterior(self, step_num): - """ - form a posterior distribution after observing the first step_num elements of the draws - - Parameters - ---------- - step_num: int. - number of steps observed to form a posterior distribution - - Returns - ------ - the posterior distribution for sake of plotting in the subsequent steps - - """ - heads_num = self.draws[:step_num].sum() - tails_num = step_num - heads_num - - return st.beta(self.α+heads_num, self.β+tails_num) - - def form_posterior_series(self,num_obs_list): - """ - form a series of posterior distributions that form after observing different number of draws. - - Parameters - ---------- - num_obs_list: a list of int. - a list of the number of observations used to form a series of posterior distributions. - - """ - self.posterior_list = [] - for num in num_obs_list: - self.posterior_list.append(self.form_single_posterior(num)) -``` - -**d)** Please plot the posterior distribution for $\theta$ as a function of $\theta$ as $n$ grows from $1, 2, \ldots$. - -```{code-cell} ipython3 -Bay_stat = Bayesian() -Bay_stat.draw() - -num_list = [1, 2, 3, 4, 5, 10, 20, 30, 50, 70, 100, 300, 500, 1000, # this line for finite n - 5000, 10_000, 50_000, 100_000, 200_000, 300_000] # this line for approximately infinite n - -Bay_stat.form_posterior_series(num_list) - -θ_values = np.linspace(0.01, 1, 100) - -fig, ax = plt.subplots(figsize=(10, 6)) - -ax.plot(θ_values, Bay_stat.prior.pdf(θ_values), label='Prior Distribution', color='k', linestyle='--') - -for ii, num in enumerate(num_list[:14]): - ax.plot(θ_values, Bay_stat.posterior_list[ii].pdf(θ_values), label='Posterior with n = %d' % num) - -ax.set_title('P.D.F of Posterior Distributions', fontsize=15) -ax.set_xlabel(r"$\theta$", fontsize=15) - -ax.legend(fontsize=11) -plt.show() -``` - -**e)** For various $n$'s, please describe and compute $.05$ and $.95$ quantiles for posterior probabilities. - -```{code-cell} ipython3 -upper_bound = [ii.ppf(0.05) for ii in Bay_stat.posterior_list[:14]] -lower_bound = [ii.ppf(0.95) for ii in Bay_stat.posterior_list[:14]] - -interval_df = pd.DataFrame() -interval_df['upper'] = upper_bound -interval_df['lower'] = lower_bound -interval_df.index = num_list[:14] -interval_df = interval_df.T -interval_df -``` - -As $n$ increases, we can see that Bayesian coverage intervals narrow and move toward $0.4$. - -**f)** Please tell what question a Bayesian coverage interval answers. - -The Bayesian coverage interval tells the range of $\theta$ that corresponds to the [$p_1$, $p_2$] quantiles of the cumulative probability distribution (CDF) of the posterior distribution. - -To construct the coverage interval we first compute a posterior distribution of the unknown parameter $\theta$. - -If the CDF is $F(\theta)$, then the Bayesian coverage interval $[a,b]$ for the interval $[p_1,p_2]$ is described by - -$$ -F(a)=p_1,F(b)=p_2 -$$ - -**g)** Please compute the Posterior probabililty that $\theta \in [.45, .55]$ for various values of sample size $n$. - -```{code-cell} ipython3 -left_value, right_value = 0.45, 0.55 - -posterior_prob_list=[ii.cdf(right_value)-ii.cdf(left_value) for ii in Bay_stat.posterior_list] - -fig, ax = plt.subplots(figsize=(8, 5)) -ax.plot(posterior_prob_list) -ax.set_title('Posterior Probabililty that '+ r"$\theta$" +' Ranges from %.2f to %.2f'%(left_value, right_value), - fontsize=13) -ax.set_xticks(np.arange(0, len(posterior_prob_list), 3)) -ax.set_xticklabels(num_list[::3]) -ax.set_xlabel('Number of Observations', fontsize=11) - -plt.show() -``` - -Notice that in the graph above the posterior probabililty that $\theta \in [.45, .55]$ typically exhibits a hump shape as $n$ increases. - -Two opposing forces are at work. - -The first force is that the individual adjusts his belief as he observes new outcomes, so his posterior probability distribution becomes more and more realistic, which explains the rise of the posterior probabililty. - -However, $[.45, .55]$ actually excludes the true $\theta =.4 $ that generates the data. - -As a result, the posterior probabililty drops as larger and larger samples refine his posterior probability distribution of $\theta$. - -The descent seems precipitous only because of the scale of the graph that has the number of observations increasing disproportionately. - -When the number of observations becomes large enough, our Bayesian becomes so confident about $\theta$ that he considers $\theta \in [.45, .55]$ very unlikely. - -That is why we see a nearly horizontal line when the number of observations exceeds 500. - -**h)** Please use your Python class to study what happens to the posterior distribution as $n \rightarrow + \infty$, again assuming that the true value of $\theta = .4$, though it is unknown to the person doing the updating via Bayes' Law. - -Using the Python class we made above, we can see the evolution of posterior distributions as $n$ approaches infinity. - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(10, 6)) - -for ii, num in enumerate(num_list[14:]): - ii += 14 - ax.plot(θ_values, Bay_stat.posterior_list[ii].pdf(θ_values), - label='Posterior with n=%d thousand' % (num/1000)) - -ax.set_title('P.D.F of Posterior Distributions', fontsize=15) -ax.set_xlabel(r"$\theta$", fontsize=15) -ax.set_xlim(0.3, 0.5) - -ax.legend(fontsize=11) -plt.show() -``` - -As $n$ increases, we can see that the probability density functions _concentrate_ on $0.4$, the true value of $\theta$. - -Here the posterior means converges to $0.4$ while the posterior standard deviations converges to $0$ from above. - -To show this, we compute the means and variances statistics of the posterior distributions. - -```{code-cell} ipython3 -mean_list = [ii.mean() for ii in Bay_stat.posterior_list] -std_list = [ii.std() for ii in Bay_stat.posterior_list] - -fig, ax = plt.subplots(1, 2, figsize=(14, 5)) - -ax[0].plot(mean_list) -ax[0].set_title('Mean Values of Posterior Distribution', fontsize=13) -ax[0].set_xticks(np.arange(0, len(mean_list), 3)) -ax[0].set_xticklabels(num_list[::3]) -ax[0].set_xlabel('Number of Observations', fontsize=11) - -ax[1].plot(std_list) -ax[1].set_title('Standard Deviations of Posterior Distribution', fontsize=13) -ax[1].set_xticks(np.arange(0, len(std_list), 3)) -ax[1].set_xticklabels(num_list[::3]) -ax[1].set_xlabel('Number of Observations', fontsize=11) - -plt.show() -``` - -```{solution-end} -``` - -How shall we interpret the patterns above? - -The answer is encoded in the Bayesian updating formulas. - -It is natural to extend the one-step Bayesian update to an $n$-step Bayesian update. - - -$$ -\textrm{Prob}(\theta|k) = \frac{\textrm{Prob}(\theta,k)}{\textrm{Prob}(k)}=\frac{\textrm{Prob}(k|\theta)*\textrm{Prob}(\theta)}{\textrm{Prob}(k)}=\frac{\textrm{Prob}(k|\theta)*\textrm{Prob}(\theta)}{\int_0^1 \textrm{Prob}(k|\theta)*\textrm{Prob}(\theta) d\theta} -$$ - -$$ -=\frac{{N \choose k} (1 - \theta)^{N-k} \theta^k*\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)}}{\int_0^1 {N \choose k} (1 - \theta)^{N-k} \theta^k*\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)} d\theta} -$$ - -$$ -=\frac{(1 -\theta)^{\beta+N-k-1}* \theta^{\alpha+k-1}}{\int_0^1 (1 - \theta)^{\beta+N-k-1}* \theta^{\alpha+k-1} d\theta} -$$ - -$$ -={Beta}(\alpha + k, \beta+N-k) -$$ - -A beta distribution with $\alpha$ and $\beta$ has the following mean and variance. - -The mean is $\frac{\alpha}{\alpha + \beta}$ - -The variance is $\frac{\alpha \beta}{(\alpha + \beta)^2 (\alpha + \beta + 1)}$ - -* $\alpha$ can be viewed as the number of successes - -* $\beta$ can be viewed as the number of failures - -The random variables $k$ and $N-k$ are governed by Binomial Distribution with $\theta=0.4$. - -Call this the true data generating process. - -According to the Law of Large Numbers, for a large number of observations, observed frequencies of $k$ and $N-k$ will be described by the true data generating process, i.e., the population probability distribution that we assumed when generating the observations on the computer. (See {ref}`pm_ex1`). - -Consequently, the mean of the posterior distribution converges to $0.4$ and the variance withers to zero. - -```{code-cell} ipython3 -upper_bound = [ii.ppf(0.95) for ii in Bay_stat.posterior_list] -lower_bound = [ii.ppf(0.05) for ii in Bay_stat.posterior_list] - -fig, ax = plt.subplots(figsize=(10, 6)) -ax.scatter(np.arange(len(upper_bound)), upper_bound, label='95 th Quantile') -ax.scatter(np.arange(len(lower_bound)), lower_bound, label='05 th Quantile') - -ax.set_xticks(np.arange(0, len(upper_bound), 2)) -ax.set_xticklabels(num_list[::2]) -ax.set_xlabel('Number of Observations', fontsize=12) -ax.set_title('Bayesian Coverage Intervals of Posterior Distributions', fontsize=15) - -ax.legend(fontsize=11) -plt.show() -``` - -After observing a large number of outcomes, the posterior distribution collapses around $0.4$. - -Thus, the Bayesian statististian comes to believe that $\theta$ is near $.4$. - -As shown in the figure above, as the number of observations grows, the Bayesian coverage intervals (BCIs) become narrower and narrower around $0.4$. - -However, if you take a closer look, you will find that the centers of the BCIs are not exactly $0.4$, due to the persistent influence of the prior distribution and the randomness of the simulation path. - - -## Role of a Conjugate Prior - -We have made assumptions that link functional forms of our likelihood function and our prior in a way that has eased our calculations considerably. - -In particular, our assumptions that the likelihood function is **binomial** and that the prior distribution is a **beta distribution** have the consequence that the posterior distribution implied by Bayes' Law is also a **beta distribution**. - -So posterior and prior are both beta distributions, albeit ones with different parameters. - -When a likelihood function and prior fit together like hand and glove in this way, we can say that the prior and posterior are **conjugate distributions**. - -In this situation, we also sometimes say that we have **conjugate prior** for the likelihood function $\textrm{Prob}(X | \theta)$. - -Typically, the functional form of the likelihood function determines the functional form of a **conjugate prior**. - -A natural question to ask is why should a person's personal prior about a parameter $\theta$ be restricted to be described by a conjugate prior? - -Why not some other functional form that more sincerely describes the person's beliefs? - -To be argumentative, one could ask, why should the form of the likelihood function have *anything* to say about my personal beliefs about $\theta$? - -A dignified response to that question is, well, it shouldn't, but if you want to compute a posterior easily you'll just be happier if your prior is conjugate to your likelihood. - -Otherwise, your posterior won't have a convenient analytical form and you'll be in the situation of wanting to apply the Markov chain Monte Carlo techniques deployed in {doc}`this quantecon lecture `. - -We also apply these powerful methods to approximating Bayesian posteriors for non-conjugate priors in -{doc}`this quantecon lecture ` and {doc}`this quantecon lecture ` diff --git a/tools/lectures/prob_meaning_cn.md b/tools/lectures/prob_meaning_cn.md deleted file mode 100644 index d22df66c..00000000 --- a/tools/lectures/prob_meaning_cn.md +++ /dev/null @@ -1,713 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.10.3 -kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 ---- - -# 概率的两种含义 - -## 概述 - -本讲座说明了**概率分布**的两种不同解释 - -* 频率主义解释:预期在大规模独立同分布样本中出现的**相对频率** - -* 贝叶斯解释:在观察一系列数据后对参数或参数列表的**个人观点** - -我们建议观看这个关于频率主义方法中**假设检验**的视频 - -```{youtube} 8JIe_cz6qGA -``` - -观看完该视频后,请观看以下关于贝叶斯方法构建**覆盖区间**的视频 - -```{youtube} Pahyv9i_X2k -``` - -在您熟悉这些视频中的内容后,本讲座将使用苏格拉底方法来帮助巩固您对以下两种方法所回答的不同问题的理解: - -* 频率主义置信区间 - -* 贝叶斯覆盖区间 - -我们通过邀请您编写一些Python代码来实现这一点。 - -在继续阅读讲座的其余部分之前,建议您在我们提出的每个问题后尝试编写代码。 - -随着讲座的展开,我们会提供我们自己的答案,但如果您在阅读和运行我们的代码之前尝试编写自己的代码,您会学到更多。 - -**回答问题的代码:** - -除了Anaconda中包含的内容外,本讲座还将使用以下库: - -```{code-cell} ipython3 -:tags: [hide-output] -pip install prettytable -``` - -为了回答我们的编程问题,我们先导入一些库 - -```{code-cell} ipython3 -import numpy as np -import pandas as pd -import prettytable as pt -import matplotlib.pyplot as plt -from scipy.stats import binom -import scipy.stats as st -``` - -有了这些Python工具,我们现在来探索上述两种含义。 - -## 频率主义解释 - -考虑以下经典例子。 - -随机变量 $X$ 可能取值为 $k = 0, 1, 2, \ldots, n$,其概率为 - -$$ -\textrm{Prob}(X = k | \theta) = -\left(\frac{n!}{k! (n-k)!} \right) \theta^k (1-\theta)^{n-k} -$$ - -其中固定参数 $\theta \in (0,1)$。 - -这被称为__二项分布__。 - -这里 - -* $\theta$ 是一次硬币投掷出现正面的概率,我们将这个结果编码为 $Y = 1$。 - -* $1 -\theta$ 是一次硬币投掷出现反面的概率,我们将这个结果表示为 $Y = 0$。 - -* $X$ 是投掷硬币 $n$ 次后出现正面的总次数。 - -考虑以下实验: - -进行 $I$ 次**独立**的硬币投掷序列,每次序列包含 $n$ 次**独立**的投掷 - -注意这里重复使用了**独立**这个形容词: - -* 我们用它来描述从参数为 $\theta$ 的**伯努利**分布中进行 $n$ 次独立抽样,从而得到一个参数为 $\theta,n$ 的**二项**分布的一次抽样。 - -* 我们再次使用它来描述我们进行 $I$ 次这样的 $n$ 次投币序列。 - -令 $y_h^i \in \{0, 1\}$ 表示第 $i$ 次序列中第 $h$ 次投掷的 $Y$ 的实际值。 - -令 $\sum_{h=1}^n y_h^i$ 表示第 $i$ 次 $n$ 次独立投币序列中出现正面的总次数。 - -令 $f_k$ 记录长度为 $n$ 的样本中满足 $\sum_{h=1}^n y_h^i = k$ 的比例: - -$$ -f_k^I = \frac{\textrm{满足} \sum_{h=1}^n y_h^i = k \textrm{的长度为n的样本数}}{ - I} -$$ - -概率 $\textrm{Prob}(X = k | \theta)$ 回答了以下问题: - -* 当 $I$ 变大时,在 $I$ 次独立的 $n$ 次硬币投掷中,我们应该预期有多大比例会出现 $k$ 次正面? - -像往常一样,大数定律证明了这个答案。 - -```{exercise} -:label: pm_ex1 - -1. 请编写一个Python类来计算 $f_k^I$ - -2. 请使用你的代码计算 $f_k^I, k = 0, \ldots , n$ 并将其与不同 $\theta, n$ 和 $I$ 值下的 - $\textrm{Prob}(X = k | \theta)$ 进行比较 - -3. 结合大数定律,用你的代码说明一些现象 -``` - -```{solution-start} pm_ex1 -:class: dropdown -``` - -这是一个解决方案: - -```{code-cell} ipython3 -class frequentist: - - def __init__(self, θ, n, I): - - ''' - 初始化 - ----------------- - 参数: - θ : 一次硬币投掷出现正面(Y = 1)的概率 - n : 每个独立序列中的独立投掷次数 - I : 独立序列的数量 - - ''' - - self.θ, self.n, self.I = θ, n, I - - def binomial(self, k): - - '''计算特定输入k的理论概率''' - - θ, n = self.θ, self.n - self.k = k - self.P = binom.pmf(k, n, θ) - - def draw(self): - - '''为I个独立序列进行n次独立投掷''' - - θ, n, I = self.θ, self.n, self.I - sample = np.random.rand(I, n) - Y = (sample <= θ) * 1 - self.Y = Y - - def compute_fk(self, kk): - - '''计算特定输入k的f_{k}^I''' - - Y, I = self.Y, self.I - K = np.sum(Y, 1) - f_kI = np.sum(K == kk) / I - self.f_kI = f_kI - self.kk = kk - - def compare(self): - - '''计算并打印比较结果''' - - n = self.n - comp = pt.PrettyTable() - comp.field_names = ['k', '理论值', '频率值'] - self.draw() - for i in range(n): - self.binomial(i+1) - self.compute_fk(i+1) - comp.add_row([i+1, self.P, self.f_kI]) - print(comp) -``` - -```{code-cell} ipython3 -θ, n, k, I = 0.7, 20, 10, 1_000_000 - -freq = frequentist(θ, n, I) - -freq.compare() -``` - -从上表中,你能看出大数定律在起作用吗? - -```{solution-end} -``` - -让我们进行更多计算。 - -**不同$\theta$值的比较** - -现在我们固定 - -$$ -n=20, k=10, I=1,000,000 -$$ - -我们将$\theta$从$0.01$变化到$0.99$,并绘制结果与$\theta$的关系图。 - -```{code-cell} ipython3 -θ_low, θ_high, npt = 0.01, 0.99, 50 -thetas = np.linspace(θ_low, θ_high, npt) -P = [] -f_kI = [] -for i in range(npt): - freq = frequentist(thetas[i], n, I) - freq.binomial(k) - freq.draw() - freq.compute_fk(k) - P.append(freq.P) - f_kI.append(freq.f_kI) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(8, 6)) -ax.grid() -ax.plot(thetas, P, 'k-.', label='理论值') -ax.plot(thetas, f_kI, 'r--', label='分数') -plt.title(r'不同$\theta$值的比较', fontsize=16) -plt.xlabel(r'$\theta$', fontsize=15) -plt.ylabel('分数', fontsize=15) -plt.tick_params(labelsize=13) -plt.legend() -plt.show() -``` - -**不同 $n$ 值的比较** - -现在我们固定 $\theta=0.7, k=10, I=1,000,000$ 并将 $n$ 从 $1$ 变化到 $100$。 - -然后我们将绘制结果。 - -```{code-cell} ipython3 -n_low, n_high, nn = 1, 100, 50 -ns = np.linspace(n_low, n_high, nn, dtype='int') -P = [] -f_kI = [] -for i in range(nn): - freq = frequentist(θ, ns[i], I) - freq.binomial(k) - freq.draw() - freq.compute_fk(k) - P.append(freq.P) - f_kI.append(freq.f_kI) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(8, 6)) -ax.grid() -ax.plot(ns, P, 'k-.', label='理论值') -ax.plot(ns, f_kI, 'r--', label='频率派') -plt.title(r'不同$n$值的比较', fontsize=16) -plt.xlabel(r'$n$', fontsize=15) -plt.ylabel('比例', fontsize=15) -plt.tick_params(labelsize=13) -plt.legend() -plt.show() -``` - -**不同 $I$ 值的比较** - -现在我们固定 $\theta=0.7, n=20, k=10$,并将 $\log(I)$ 从 $2$ 变化到 $7$。 - -```{code-cell} ipython3 -I_log_low, I_log_high, nI = 2, 6, 200 -log_Is = np.linspace(I_log_low, I_log_high, nI) -Is = np.power(10, log_Is).astype(int) -P = [] -f_kI = [] -for i in range(nI): - freq = frequentist(θ, n, Is[i]) - freq.binomial(k) - freq.draw() - freq.compute_fk(k) - P.append(freq.P) - f_kI.append(freq.f_kI) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(8, 6)) -ax.grid() -ax.plot(Is, P, 'k-.', label='理论值') -ax.plot(Is, f_kI, 'r--', label='分数') -plt.title(r'不同 $I$ 值的比较', fontsize=16) -plt.xlabel(r'$I$', fontsize=15) -plt.ylabel('分数', fontsize=15) -plt.tick_params(labelsize=13) -plt.legend() -plt.show() -``` - -从上面的图表中,我们可以看到**$I$,即独立序列的数量,**起着重要作用。 - -当$I$变大时,理论概率和频率估计之间的差异变小。 - -而且,只要$I$足够大,改变$\theta$或$n$都不会实质性地改变观察到的分数作为$\theta$的近似值的准确性。 - -这里体现了大数定律。 - -对于每个独立序列的抽取,$\textrm{Prob}(X_i = k | \theta)$都是相同的,所以所有抽取的聚合形成了一个二元随机变量$\rho_{k,i},i=1,2,...I$的独立同分布序列,其均值为$\textrm{Prob}(X = k | \theta)$,方差为 - -$$ -n \cdot \textrm{Prob}(X = k | \theta) \cdot (1-\textrm{Prob}(X = k | \theta)). -$$ - -因此,根据大数定律,$P_{k,i}$的平均值收敛于: - -$$ -E[\rho_{k,i}] = \textrm{Prob}(X = k | \theta) = \left(\frac{n!}{k! (n-k)!} \right) \theta^k (1-\theta)^{n-k} -$$ - -当$I$趋向于无穷时。 - -## 贝叶斯解释 - -我们再次使用二项分布。 - -但现在我们不把$\theta$看作是一个固定的数。 - -相反,我们把它看作是一个**随机变量**。 - -$\theta$由一个概率分布来描述。 - -但现在这个概率分布的含义与我们在大规模独立同分布样本中能预期出现的相对频率不同。 - -相反,$\theta$的概率分布现在是我们对$\theta$可能值的看法的总结,这些看法要么是 - -* 在我们**完全没有看到**任何数据之前,或者 -* 在我们已经看到**一些**数据之后,但在看到**更多**数据之前 - -因此,假设在看到任何数据之前,你有一个个人先验概率分布,表示为 - -$$ -P(\theta) = \frac{\theta^{\alpha-1}(1-\theta)^{\beta -1}}{B(\alpha, \beta)} -$$ - -其中$B(\alpha, \beta)$是一个**贝塔函数**,所以$P(\theta)$是一个带参数$\alpha, \beta$的**贝塔分布**。 - -```{exercise} -:label: pm_ex2 - -**a)** 请写出从参数为$\theta$的二项分布中抽取长度为$n$的样本的**似然函数**。 - -**b)** 请写出观察到一次硬币翻转后$\theta$的**后验**分布。 - -**c)** 现在假设$\theta$的真实值为$.4$,而某个不知道这一点的人有一个参数为$\beta = \alpha = .5$的贝塔先验分布。请编写一个Python类来模拟这个人对于一个长度为$n$的_单个_序列的$\theta$的个人后验分布。 - -**d)** 请绘制当$n$增长为$1, 2, \ldots$时,$\theta$的后验分布关于$\theta$的函数图。 - -**e)** 对于不同的$n$值,请描述并计算区间$[.45, .55]$的贝叶斯覆盖区间。 - -**f)** 请说明贝叶斯覆盖区间回答了什么问题。 - -**g)** 请计算对于不同的样本大小$n$,后验概率$P(\theta \in [.45, .55])$的值。 - -**h)** 请使用您的Python类来研究当 $n \rightarrow + \infty$ 时后验分布会发生什么变化,同样假设 $\theta$ 的真实值为 $.4$,尽管对于通过贝叶斯定律进行更新的人来说这是未知的。 -``` - - -```{solution-start} pm_ex2 -:class: dropdown -``` - -**a)** 请写出观察到一次硬币翻转后 $\theta$ 的**似然函数**和**后验**分布。 - -假设结果为 __Y__。 - -似然函数为: - -$$ -L(Y|\theta)= \textrm{Prob}(X = Y | \theta) = -\theta^Y (1-\theta)^{1-Y} -$$ - -**b)** 请写出观察到一次硬币翻转后 $\theta$ 的**后验**分布。 - -先验分布为: - -$$ -\textrm{Prob}(\theta) = \frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)} -$$ - -我们可以通过以下方式推导 $\theta$ 的后验分布: - -\begin{align*} - \textrm{Prob}(\theta | Y) &= \frac{\textrm{Prob}(Y | \theta) \textrm{Prob}(\theta)}{\textrm{Prob}(Y)} \\ - &=\frac{\textrm{Prob}(Y | \theta) \textrm{Prob}(\theta)}{\int_{0}^{1} \textrm{Prob}(Y | \theta) \textrm{Prob}(\theta) d \theta }\\ - &= \frac{\theta^Y (1-\theta)^{1-Y}\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)}}{\int_{0}^{1}\theta^Y (1-\theta)^{1-Y}\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)} d \theta } \\ - &= \frac{ \theta^{Y+\alpha - 1} (1 - \theta)^{1-Y+\beta - 1}}{\int_{0}^{1}\theta^{Y+\alpha - 1} (1 - \theta)^{1-Y+\beta - 1} d \theta} -\end{align*} - -这意味着 - -$$ -\textrm{Prob}(\theta | Y) \sim \textrm{Beta}(\alpha + Y, \beta + (1-Y)) -$$ - -现在假设 $\theta$ 的真实值为 $.4$,并且有一个不知道这一点的人,他有一个 $\beta = \alpha = .5$ 的beta先验分布。 - -**c)** 现在假设 $\theta$ 的真实值为 $.4$,并且有一个不知道这一点的人,他有一个参数为 $\beta = \alpha = .5$ 的beta先验分布。请编写一个Python类来模拟这个人对于_单个_长度为 $n$ 的序列的 $\theta$ 的个人后验分布。 - -```{code-cell} ipython3 -class Bayesian: - - def __init__(self, θ=0.4, n=1_000_000, α=0.5, β=0.5): - """ - 参数: - ---------- - θ : float, 范围在 [0,1] 之间。 - 一次硬币投掷得到正面(Y = 1)的概率 - - n : int. - 独立序列中独立投掷的次数 - - α&β : int 或 float. - θ 的先验分布的参数 - - """ - self.θ, self.n, self.α, self.β = θ, n, α, β - self.prior = st.beta(α, β) - - def draw(self): - """ - 模拟一个长度为 n 的单个序列,给定概率 θ - - """ - array = np.random.rand(self.n) - self.draws = (array < self.θ).astype(int) - - def form_single_posterior(self, step_num): - """ - 在观察到序列的前 step_num 个元素后形成后验分布 - - 参数 - ---------- - step_num: int. - 用于形成后验分布的观察步数 - - 返回 - ------ - 后验分布,用于后续步骤的绘图 - - """ - heads_num = self.draws[:step_num].sum() - tails_num = step_num - heads_num - - return st.beta(self.α+heads_num, self.β+tails_num) - - def form_posterior_series(self,num_obs_list): - """ - 形成一系列后验分布,这些分布是在观察不同数量的抽样后形成的。 - - 参数 - ---------- - num_obs_list: int 列表。 - 用于形成一系列后验分布的观察数量列表。 - - """ - self.posterior_list = [] - for num in num_obs_list: - self.posterior_list.append(self.form_single_posterior(num)) -``` - -**d)** 请绘制$\theta$的后验分布随着$n$从$1, 2, \ldots$增长时的函数图。 - -```{code-cell} ipython3 -Bay_stat = Bayesian() -Bay_stat.draw() - -num_list = [1, 2, 3, 4, 5, 10, 20, 30, 50, 70, 100, 300, 500, 1000, # 此行用于有限n - 5000, 10_000, 50_000, 100_000, 200_000, 300_000] # 此行用于近似无穷n - -Bay_stat.form_posterior_series(num_list) - -θ_values = np.linspace(0.01, 1, 100) - -fig, ax = plt.subplots(figsize=(10, 6)) - -ax.plot(θ_values, Bay_stat.prior.pdf(θ_values), label='先验分布', color='k', linestyle='--') - -for ii, num in enumerate(num_list[:14]): - ax.plot(θ_values, Bay_stat.posterior_list[ii].pdf(θ_values), label='n = %d 时的后验分布' % num) - -ax.set_title('后验分布的概率密度函数', fontsize=15) -ax.set_xlabel(r"$\theta$", fontsize=15) - -ax.legend(fontsize=11) -plt.show() -``` - -**e)** 对于不同的 $n$ 值,请描述并计算后验概率的 $.05$ 和 $.95$ 分位数。 - -```{code-cell} ipython3 -upper_bound = [ii.ppf(0.05) for ii in Bay_stat.posterior_list[:14]] -lower_bound = [ii.ppf(0.95) for ii in Bay_stat.posterior_list[:14]] - -interval_df = pd.DataFrame() -interval_df['upper'] = upper_bound -interval_df['lower'] = lower_bound -interval_df.index = num_list[:14] -interval_df = interval_df.T -interval_df -``` - -随着$n$的增加,我们可以看到贝叶斯覆盖区间变窄并趋向于$0.4$。 - -**f)** 请说明贝叶斯覆盖区间回答了什么问题。 - -贝叶斯覆盖区间表示后验分布的累积概率分布(CDF)中[$p_1$, $p_2$]分位数对应的$\theta$的范围。 - -要构建覆盖区间,我们首先计算未知参数$\theta$的后验分布。 - -如果CDF为$F(\theta)$,那么区间$[p_1,p_2]$的贝叶斯覆盖区间$[a,b]$由以下等式描述: - -$$ -F(a)=p_1,F(b)=p_2 -$$ - -**g)** 请计算不同样本量$n$下$\theta \in [.45, .55]$的后验概率。 - -```{code-cell} ipython3 -left_value, right_value = 0.45, 0.55 - -posterior_prob_list=[ii.cdf(right_value)-ii.cdf(left_value) for ii in Bay_stat.posterior_list] - -fig, ax = plt.subplots(figsize=(8, 5)) -ax.plot(posterior_prob_list) -ax.set_title('后验概率:'+ r"$\theta$" +'的范围从%.2f到%.2f'%(left_value, right_value), - fontsize=13) -ax.set_xticks(np.arange(0, len(posterior_prob_list), 3)) -ax.set_xticklabels(num_list[::3]) -ax.set_xlabel('观测数量', fontsize=11) - -plt.show() -``` - -注意在上图中,当 $n$ 增加时,$\theta \in [.45, .55]$ 的后验概率通常呈现出驼峰形状。 - -这里有两种相互对立的力量在起作用。 - -第一种力量是,个体在观察到新的结果时会调整他的信念,使他的后验概率分布变得越来越符合实际,这解释了后验概率的上升。 - -然而,$[.45, .55]$ 实际上排除了生成数据的真实 $\theta =.4$。 - -因此,随着更大的样本量使他的 $\theta$ 后验概率分布变得更加精确,后验概率开始下降。 - -下降看起来如此陡峭,仅仅是因为图表的尺度使得观测数量增加不成比例。 - -当观测数量变得足够大时,我们的贝叶斯学习者对 $\theta$ 变得如此确信,以至于他认为 $\theta \in [.45, .55]$ 的可能性非常小。 - -这就是为什么当观测数量超过500时,我们看到一条几乎水平的线。 - -**h)** 请使用你的Python类来研究当 $n \rightarrow + \infty$ 时后验分布会发生什么,同样假设 $\theta = .4$ 是真实值,尽管对于通过贝叶斯法则进行更新的人来说这是未知的。 - -使用我们上面创建的Python类,我们可以看到后验分布随着 $n$ 趋向于无穷大时的演变。 - -```{code-cell} ipython3 -fig, ax = plt.subplots(figsize=(10, 6)) - -for ii, num in enumerate(num_list[14:]): - ii += 14 - ax.plot(θ_values, Bay_stat.posterior_list[ii].pdf(θ_values), - label='Posterior with n=%d thousand' % (num/1000)) - -ax.set_title('P.D.F of Posterior Distributions', fontsize=15) -ax.set_xlabel(r"$\theta$", fontsize=15) -ax.set_xlim(0.3, 0.5) - -ax.legend(fontsize=11) -plt.show() -``` - -随着 $n$ 的增加,我们可以看到概率密度函数在 $0.4$(即 $\theta$ 的真实值)处_集中_。 - -这里后验均值收敛于 $0.4$,而后验标准差从上方收敛于 $0$。 - -为了展示这一点,我们计算后验分布的均值和方差统计量。 - -```{code-cell} ipython3 -mean_list = [ii.mean() for ii in Bay_stat.posterior_list] -std_list = [ii.std() for ii in Bay_stat.posterior_list] - -fig, ax = plt.subplots(1, 2, figsize=(14, 5)) - -ax[0].plot(mean_list) -ax[0].set_title('后验分布的均值', fontsize=13) -ax[0].set_xticks(np.arange(0, len(mean_list), 3)) -ax[0].set_xticklabels(num_list[::3]) -ax[0].set_xlabel('观测数量', fontsize=11) - -ax[1].plot(std_list) -ax[1].set_title('后验分布的标准差', fontsize=13) -ax[1].set_xticks(np.arange(0, len(std_list), 3)) -ax[1].set_xticklabels(num_list[::3]) -ax[1].set_xlabel('观测数量', fontsize=11) - -plt.show() -``` - -```{solution-end} -``` - -我们应该如何解读上述模式? - -答案就在贝叶斯更新公式中。 - -将单步贝叶斯更新自然延伸到 n 步贝叶斯更新是很合理的。 - -$$ -\textrm{Prob}(\theta|k) = \frac{\textrm{Prob}(\theta,k)}{\textrm{Prob}(k)}=\frac{\textrm{Prob}(k|\theta)*\textrm{Prob}(\theta)}{\textrm{Prob}(k)}=\frac{\textrm{Prob}(k|\theta)*\textrm{Prob}(\theta)}{\int_0^1 \textrm{Prob}(k|\theta)*\textrm{Prob}(\theta) d\theta} -$$ - -$$ -=\frac{{N \choose k} (1 - \theta)^{N-k} \theta^k*\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)}}{\int_0^1 {N \choose k} (1 - \theta)^{N-k} \theta^k*\frac{\theta^{\alpha - 1} (1 - \theta)^{\beta - 1}}{B(\alpha, \beta)} d\theta} -$$ - -$$ -=\frac{(1 -\theta)^{\beta+N-k-1}* \theta^{\alpha+k-1}}{\int_0^1 (1 - \theta)^{\beta+N-k-1}* \theta^{\alpha+k-1} d\theta} -$$ - -$$ -={Beta}(\alpha + k, \beta+N-k) -$$ - -具有 $\alpha$ 和 $\beta$ 参数的贝塔分布有以下均值和方差。 - -均值是 $\frac{\alpha}{\alpha + \beta}$ - -方差是 $\frac{\alpha \beta}{(\alpha + \beta)^2 (\alpha + \beta + 1)}$ - -* $\alpha$ 可以视为成功次数 - -* $\beta$ 可以视为失败次数 - -随机变量 $k$ 和 $N-k$ 服从参数为 $\theta=0.4$ 的二项分布。 - -这就是真实的数据生成过程。 - -根据大数定律,对于大量观测值,观测到的频率 $k$ 和 $N-k$ 将由真实的数据生成过程来描述,即我们在计算机上生成观测值时假设的总体概率分布。(参见 {ref}`pm_ex1`)。 - -因此,后验分布的均值收敛于 $0.4$,且方差趋近于零。 - -```{code-cell} ipython3 -upper_bound = [ii.ppf(0.95) for ii in Bay_stat.posterior_list] -lower_bound = [ii.ppf(0.05) for ii in Bay_stat.posterior_list] - -fig, ax = plt.subplots(figsize=(10, 6)) -ax.scatter(np.arange(len(upper_bound)), upper_bound, label='95 分位数') -ax.scatter(np.arange(len(lower_bound)), lower_bound, label='05 分位数') - -ax.set_xticks(np.arange(0, len(upper_bound), 2)) -ax.set_xticklabels(num_list[::2]) -ax.set_xlabel('观测值数量', fontsize=12) -ax.set_title('后验分布的贝叶斯覆盖区间', fontsize=15) - -ax.legend(fontsize=11) -plt.show() -``` - -在观察了大量结果后,后验分布收敛在$0.4$周围。 - -因此,贝叶斯统计学家认为$\theta$接近$.4$。 - -如上图所示,随着观测数量的增加,贝叶斯置信区间(BCIs)在$0.4$周围变得越来越窄。 - -然而,如果仔细观察,你会发现BCIs的中心并不完全是$0.4$,这是由于先验分布的持续影响和模拟路径的随机性造成的。 - -## 共轭先验的作用 - -我们做出了一些假设,将似然函数和先验的函数形式联系起来,这大大简化了我们的计算。 - -特别是,我们假设似然函数是**二项分布**,而先验分布是**beta分布**,这导致贝叶斯定律推导出的后验分布也是**beta分布**。 - -所以后验和先验都是beta分布,只是它们的参数不同。 - -当似然函数和先验像手和手套一样完美匹配时,我们可以说先验和后验是**共轭分布**。 - -在这种情况下,我们有时也说我们有似然函数$\textrm{Prob}(X | \theta)$的**共轭先验**。 - -通常,似然函数的函数形式决定了**共轭先验**的函数形式。 - - -一个自然的问题是,为什么一个人对参数$\theta$的个人先验必须局限于共轭先验的形式? - -为什么不能是其他更真实地描述个人信念的函数形式? - -从争辩的角度来说,人们可以问,为什么似然函数的形式应该对我关于$\theta$的个人信念有*任何*影响? - -对这个问题的一个得体回答是,确实不应该有影响,但如果你想要轻松地计算后验分布,使用与似然函数共轭的先验会让你更愉快。 - -否则,你的后验分布将不会有一个方便的解析形式,你就会需要使用{doc}`这个 quantecon 讲座 `中部署的马尔可夫链蒙特卡洛技术。 - -我们也在{doc}`这个 quantecon 讲座 `和{doc}`这个 quantecon 讲座 `中应用这些强大的方法来近似非共轭先验的贝叶斯后验分布。 - diff --git a/tools/translation.py b/tools/translation.py index cb3095a5..6333a50e 100644 --- a/tools/translation.py +++ b/tools/translation.py @@ -185,7 +185,7 @@ def translate_cn(input_file): logging.info(f"All chunks translated and saved to {output_file}") if __name__ == "__main__": - directory = "lectures" + directory = "../lectures" max_workers = 2 # Adjust this based on your API rate limits and system capabilities # Load translation history diff --git a/tools/translation_history.json b/tools/translation_history.json index 98a797d0..4f0e9f0a 100644 --- a/tools/translation_history.json +++ b/tools/translation_history.json @@ -1,297 +1,22 @@ { - "lectures/perm_income.md": { - "hash": "8027e12b0d1a509907cf469ee574341d", - "last_modified": 1742193379.0191963, - "last_translated": 1742195625.260733 - }, - "lectures/troubleshooting.md": { - "hash": "2c84670ef7e7723c08b6906e5b72fb27", - "last_modified": 1742193379.0697775, - "last_translated": 1742195639.494167 - }, - "lectures/ge_arrow.md": { - "hash": "5c1af49891e38f2d26aeaf8fe7e5bf8b", - "last_modified": 1742193378.837432, - "last_translated": 1742195713.635284 - }, - "lectures/wealth_dynamics.md": { - "hash": "759f0e7adb0e82e62b7b41eec57c80d8", - "last_modified": 1742193379.101374, - "last_translated": 1742195763.19976 - }, - "lectures/mix_model.md": { - "hash": "884a2c9dac28974be201e2e5f7bd6481", - "last_modified": 1742193378.9612448, - "last_translated": 1742195875.9428968 - }, - "lectures/re_with_feedback.md": { - "hash": "80762c68f36d7a3eca6256df085c8661", - "last_modified": 1742193379.045698, - "last_translated": 1742195997.016331 - }, - "lectures/inventory_dynamics.md": { - "hash": "7fde683e1116b79773ed882b5df2e5f9", - "last_modified": 1742193378.876982, - "last_translated": 1742196065.7237408 - }, - "lectures/intro.md": { - "hash": "a01cc0acbf3d97c9a82d8f3f018d4219", - "last_modified": 1742193378.871891, - "last_translated": 1742196068.084739 - }, - "lectures/status.md": { - "hash": "ccf79b1f0f147e0e44607e07c8eaa5fc", - "last_modified": 1742193379.0599775, - "last_translated": 1742196071.0216908 - }, - "lectures/wald_friedman.md": { - "hash": "c8d683dc458776645ba188326ec11ea5", - "last_modified": 1742193379.0955558, - "last_translated": 1742196088.6650162 - }, - "lectures/sir_model.md": { - "hash": "e05399a3b0caa38b8c9553ff4b3d365f", - "last_modified": 1742193379.0544574, - "last_translated": 1742196158.392222 - }, - "lectures/opt_transport.md": { - "hash": "393a5dad449f553cb6ba07df145686ee", - "last_modified": 1742193378.9963984, - "last_translated": 1742196255.114292 - }, - "lectures/mccall_model.md": { - "hash": "cc395ec5222ba30f1d81540555e82286", - "last_modified": 1742193378.9537675, - "last_translated": 1742196305.3139808 - }, - "lectures/multi_hyper.md": { - "hash": "c85e2ae2df4ff99ac3414ee9efc90c95", - "last_modified": 1742193378.9702873, - "last_translated": 1742196401.9877381 - }, - "lectures/mle.md": { - "hash": "8c30dadee541133b4c05d5efcd3c1cf9", - "last_modified": 1742193378.9635065, - "last_translated": 1742196440.125151 - }, - "lectures/mccall_q.md": { - "hash": "c5036eb7510b4f32dd80e61bced7c200", - "last_modified": 1742193378.9558287, - "last_translated": 1742196582.39528 - }, - "lectures/lln_clt.md": { - "hash": "23b66956f1b1f6c25ff67776461cafb1", - "last_modified": 1742193378.914302, - "last_translated": 1742196640.484413 - }, - "lectures/hoist_failure.md": { - "hash": "60e67e5ab745dc0c255075a41d47674e", - "last_modified": 1742193378.8519914, - "last_translated": 1742196740.1205518 - }, - "lectures/newton_method.md": { - "hash": "90acc29bed46418ef80cd25614d7e48d", - "last_modified": 1742193378.9850743, - "last_translated": 1742196841.399981 - }, - "lectures/perm_income_cons.md": { - "hash": "76b90a427ce9569af557007a559ff832", - "last_modified": 1742193379.0140722, - "last_translated": 1742196915.739697 - }, - "lectures/imp_sample.md": { - "hash": "e17acfbbe72f108c14f4fd8b9a0017f5", - "last_modified": 1742193378.8693507, - "last_translated": 1742196961.0119739 - }, - "lectures/optgrowth_fast.md": { - "hash": "ce84215df06b2f0cd1e4482f34364018", - "last_modified": 1742193379.0014524, - "last_translated": 1742196984.558659 - }, - "lectures/harrison_kreps.md": { - "hash": "9926045884f3baf3b7f31b5c92aea79d", - "last_modified": 1742193378.846141, - "last_translated": 1742197100.608493 - }, - "lectures/lq_inventories.md": { - "hash": "77dcb75b14f4783569107f7e1024a8d4", - "last_modified": 1742193378.9191923, - "last_translated": 1742197149.3313339 - }, - "lectures/markov_asset.md": { - "hash": "1a7bd355889513557ed03796c0ce51d8", - "last_modified": 1742193378.9297526, - "last_translated": 1742197306.7671838 - }, - "lectures/rational_expectations.md": { - "hash": "a257b6faf4f11a9a7772f9699869df71", - "last_modified": 1742193379.0426712, - "last_translated": 1742197343.752576 - }, - "lectures/markov_perf.md": { - "hash": "506269428d3fd62e248173bbe5a419b2", - "last_modified": 1742193378.9348679, - "last_translated": 1742197511.658255 - }, - "lectures/lqcontrol.md": { - "hash": "bb464e1c4d95d4e38ec5faeb008d56d1", - "last_modified": 1742193378.9212067, - "last_translated": 1742197617.224051 - }, - "lectures/kalman.md": { - "hash": "fb7f5dc140a6f1c4307cb47e063131e9", - "last_modified": 1742193378.8878865, - "last_translated": 1742197682.1539981 - }, - "lectures/ifp.md": { - "hash": "1d4e20d4123f2cb8a94e6a9889982654", - "last_modified": 1742193378.863815, - "last_translated": 1742197752.9636989 - }, - "lectures/two_auctions.md": { - "hash": "38d9f21e41d4dc5b39e93fd47bb8d57f", - "last_modified": 1742193379.0723503, - "last_translated": 1742197921.121033 - }, - "lectures/multivariate_normal.md": { - "hash": "bd97f06b8faf790607480fc51e65cda6", - "last_modified": 1742193378.9759977, - "last_translated": 1742198117.018036 - }, - "lectures/von_neumann_model.md": { - "hash": "62daa80d47eff134a750ca5fe17f168a", - "last_modified": 1742193379.08927, - "last_translated": 1742198145.139241 - }, - "lectures/optgrowth.md": { - "hash": "00b9207d2e3e93ce09b7c317d3a96e41", - "last_modified": 1742193379.004255, - "last_translated": 1742198267.2342458 - }, - "lectures/exchangeable.md": { - "hash": "0ad6e8dde08608a5bd94104b7f8e196b", - "last_modified": 1742193378.8295267, - "last_translated": 1742198429.900707 - }, - "lectures/house_auction.md": { - "hash": "3fc55cbb73d9b5e6945647b87c763815", - "last_modified": 1742193378.8548117, - "last_translated": 1742198437.5134678 - }, - "lectures/qr_decomp.md": { - "hash": "2fca6392c1b7f75445fa9df4cabd12ef", - "last_modified": 1742193379.0342953, - "last_translated": 1742198528.4649339 - }, - "lectures/linear_algebra.md": { - "hash": "57bd335602a5958cffbe7fa10a0a2953", - "last_modified": 1742193378.9092934, - "last_translated": 1742198689.9288461 - }, - "lectures/linear_models.md": { - "hash": "156209c657fd72a3ea8c65502005eb79", - "last_modified": 1742193378.9121091, - "last_translated": 1742198780.757025 - }, - "lectures/zreferences.md": { - "hash": "956de42c96df5c0e7c70590014dc0e31", - "last_modified": 1742193379.11044, - "last_translated": 1742198782.231174 - }, - "lectures/kalman_2.md": { - "hash": "b9fc1572a88d78ddc8f42126bc58b92f", - "last_modified": 1742193378.88552, - "last_translated": 1742198810.754369 - }, - "lectures/mccall_fitted_vfi.md": { - "hash": "e67afeb5fc464a1d2644ef690f101a02", - "last_modified": 1742193378.9436839, - "last_translated": 1742198853.689048 - }, - "lectures/svd_intro.md": { - "hash": "c8a003f6357cf33f21f8ae324312d4d7", - "last_modified": 1742193379.0668964, - "last_translated": 1742199013.526934 - }, - "lectures/navy_captain.md": { - "hash": "27066ce06854d454a2a20c274a71bf8b", - "last_modified": 1742193378.9789858, - "last_translated": 1742199085.416687 - }, - "lectures/likelihood_ratio_process.md": { - "hash": "7c60c77d7c212e5346d4ba3832ef16c5", - "last_modified": 1742193378.9042053, - "last_translated": 1742199156.0807118 - }, - "lectures/samuelson.md": { - "hash": "fba9a962771f0e5fcd7a355151c50e54", - "last_modified": 1742193379.0515208, - "last_translated": 1742199337.5519428 - }, - "lectures/rand_resp.md": { - "hash": "09ecaee3eb9fc39a3cd2aaa72e39cd02", - "last_modified": 1742193379.0371559, - "last_translated": 1742199404.1484952 - }, - "lectures/prob_matrix.md": { - "hash": "f15664657964d61f02d20ff649b379a7", - "last_modified": 1742193379.021947, - "last_translated": 1742199522.715189 - }, - "lectures/prob_meaning.md": { - "hash": "2ad3ae151b17ce1f1b070554571e3523", - "last_modified": 1742465863.4871967, - "last_translated": 1742466049.2771358 - }, - "lectures/jv.md": { - "hash": "68670074d3605d458cf3e1e0b8c89e1a", - "last_modified": 1742193378.8791728, - "last_translated": 1742199620.436908 - }, - "lectures/uncertainty_traps.md": { - "hash": "8eecdf545e0c5371d8f2a253457ee92e", - "last_modified": 1742193379.0778549, - "last_translated": 1742199674.7539442 - }, - "lectures/var_dmd.md": { - "hash": "e8ff98e60b4b72b993128c70641aa3a0", - "last_modified": 1742193379.0861392, - "last_translated": 1742199786.197601 - }, - "lectures/pandas_panel.md": { - "hash": "5d2afad65271a27e26903127e1016295", - "last_modified": 1742193379.011166, - "last_translated": 1742199905.266813 - }, - "lectures/finite_markov.md": { - "hash": "f65f1d7fd99a2094306235a113f01a75", - "last_modified": 1742193378.8350585, - "last_translated": 1742199944.471071 - }, - "lectures/ols.md": { - "hash": "6f7a2389184c055974972f7151422cc5", - "last_modified": 1742193378.9938638, - "last_translated": 1742200074.232906 - }, - "lectures/odu.md": { - "hash": "31ce9e27af6645da6de53ba4f3ab78c8", - "last_modified": 1742193378.9884832, - "last_translated": 1742200102.301013 - }, - "lectures/lagrangian_lqdp.md": { - "hash": "342c4b7eb715bd072c347a1028dd7acb", - "last_modified": 1742203569.55142, - "last_translated": 1742203760.230793 - }, "lectures/likelihood_bayes.md": { - "hash": "63eccc98317151b4bc0c83af31b395bc", - "last_modified": 1742203837.8098228, - "last_translated": 1742204007.591847 + "hash": "b6558dc1d8da30c7d0243d39849894f4", + "last_modified": 1757642355.350762, + "last_translated": 1757644222.9616024 }, - "lectures/util_rand_resp.md": { - "hash": "8b7e183efc2092e438dc5a6cc6a1ab03", - "last_modified": 1742786858.046247, - "last_translated": 1742787114.4174118 + "lectures/wald_friedman.md": { + "hash": "e2a33cd4e5b01b470d22c09640cdde9c", + "last_modified": 1757644091.1972508, + "last_translated": 1757644502.7967446 + }, + "../lectures/wald_friedman_2.md": { + "hash": "9183cc1436d8a30c902a6d37539c72cb", + "last_modified": 1757726776.0700061, + "last_translated": 1757728691.896269 + }, + "../lectures/mix_model.md": { + "hash": "4736e4eabe4c811e5fd864b604503597", + "last_modified": 1757726815.7993617, + "last_translated": 1757730283.8648303 } } \ No newline at end of file