diff --git a/.translate/state/affine_risk_prices.md.yml b/.translate/state/affine_risk_prices.md.yml new file mode 100644 index 0000000..f6fe4bc --- /dev/null +++ b/.translate/state/affine_risk_prices.md.yml @@ -0,0 +1,6 @@ +source-sha: d1a3cccb8617e053108374fbf821325ffc8e7904 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 8 +tool-version: 0.20.0 diff --git a/.translate/state/aiyagari_egm.md.yml b/.translate/state/aiyagari_egm.md.yml new file mode 100644 index 0000000..a37353d --- /dev/null +++ b/.translate/state/aiyagari_egm.md.yml @@ -0,0 +1,6 @@ +source-sha: 8bfb28272ea5943355965d090cb600fbb4c3d041 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 8 +tool-version: 0.20.0 diff --git a/.translate/state/blackwell_kihlstrom.md.yml b/.translate/state/blackwell_kihlstrom.md.yml new file mode 100644 index 0000000..38cc121 --- /dev/null +++ b/.translate/state/blackwell_kihlstrom.md.yml @@ -0,0 +1,6 @@ +source-sha: fea6b58cd64d8502f8e09821f63ae7a6f890cc44 +synced-at: "2026-07-21" +model: claude-opus-4-8 +mode: NEW +section-count: 13 +tool-version: 0.20.0 diff --git a/.translate/state/chow_business_cycles.md.yml b/.translate/state/chow_business_cycles.md.yml new file mode 100644 index 0000000..a111e9e --- /dev/null +++ b/.translate/state/chow_business_cycles.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-21" +model: claude-opus-4-8 +mode: NEW +section-count: 10 +tool-version: 0.20.0 diff --git a/.translate/state/endogenous_lake.md.yml b/.translate/state/endogenous_lake.md.yml new file mode 100644 index 0000000..6982673 --- /dev/null +++ b/.translate/state/endogenous_lake.md.yml @@ -0,0 +1,6 @@ +source-sha: 0bfcac8105ac8c11f06797579a9f4d565db7b53d +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 4 +tool-version: 0.20.0 diff --git a/.translate/state/hansen_singleton_1982.md.yml b/.translate/state/hansen_singleton_1982.md.yml new file mode 100644 index 0000000..4d21de7 --- /dev/null +++ b/.translate/state/hansen_singleton_1982.md.yml @@ -0,0 +1,6 @@ +source-sha: 4ab3365729d5afd5f25c62d73c505034e090a75c +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 7 +tool-version: 0.20.0 diff --git a/.translate/state/hansen_singleton_1983.md.yml b/.translate/state/hansen_singleton_1983.md.yml new file mode 100644 index 0000000..e5a5c85 --- /dev/null +++ b/.translate/state/hansen_singleton_1983.md.yml @@ -0,0 +1,6 @@ +source-sha: 4ab3365729d5afd5f25c62d73c505034e090a75c +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 12 +tool-version: 0.20.0 diff --git a/.translate/state/ifp_discrete.md.yml b/.translate/state/ifp_discrete.md.yml new file mode 100644 index 0000000..6982673 --- /dev/null +++ b/.translate/state/ifp_discrete.md.yml @@ -0,0 +1,6 @@ +source-sha: 0bfcac8105ac8c11f06797579a9f4d565db7b53d +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 4 +tool-version: 0.20.0 diff --git a/.translate/state/ifp_egm_transient_shocks.md.yml b/.translate/state/ifp_egm_transient_shocks.md.yml new file mode 100644 index 0000000..fb9f8df --- /dev/null +++ b/.translate/state/ifp_egm_transient_shocks.md.yml @@ -0,0 +1,6 @@ +source-sha: b6245397ef7e794a81e502af4fa03f3a2e30047e +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 7 +tool-version: 0.20.0 diff --git a/.translate/state/ifp_opi.md.yml b/.translate/state/ifp_opi.md.yml new file mode 100644 index 0000000..10adb91 --- /dev/null +++ b/.translate/state/ifp_opi.md.yml @@ -0,0 +1,6 @@ +source-sha: 0bfcac8105ac8c11f06797579a9f4d565db7b53d +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 7 +tool-version: 0.20.0 diff --git a/.translate/state/information_market_equilibrium.md.yml b/.translate/state/information_market_equilibrium.md.yml new file mode 100644 index 0000000..1d84b5b --- /dev/null +++ b/.translate/state/information_market_equilibrium.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-21" +model: claude-opus-4-8 +mode: NEW +section-count: 7 +tool-version: 0.20.0 diff --git a/.translate/state/inventory_q.md.yml b/.translate/state/inventory_q.md.yml new file mode 100644 index 0000000..169e46a --- /dev/null +++ b/.translate/state/inventory_q.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 4 +tool-version: 0.20.0 diff --git a/.translate/state/kalman_filter_var.md.yml b/.translate/state/kalman_filter_var.md.yml new file mode 100644 index 0000000..539dc3c --- /dev/null +++ b/.translate/state/kalman_filter_var.md.yml @@ -0,0 +1,6 @@ +source-sha: 1abb15f5fc0273ea02b47850f447b3c224255123 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 12 +tool-version: 0.20.0 diff --git a/.translate/state/long_run_risk_operator.md.yml b/.translate/state/long_run_risk_operator.md.yml new file mode 100644 index 0000000..d98cfdb --- /dev/null +++ b/.translate/state/long_run_risk_operator.md.yml @@ -0,0 +1,6 @@ +source-sha: b8ed85c7e8b8c17f5f59c74b3cb829470363ca8b +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 11 +tool-version: 0.20.0 diff --git a/.translate/state/lq_bewley_complete_markets.md.yml b/.translate/state/lq_bewley_complete_markets.md.yml new file mode 100644 index 0000000..7771e15 --- /dev/null +++ b/.translate/state/lq_bewley_complete_markets.md.yml @@ -0,0 +1,6 @@ +source-sha: 94222f281872c1d42aad8eff12f32821041cbdef +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 6 +tool-version: 0.20.0 diff --git a/.translate/state/lq_permanent_income.md.yml b/.translate/state/lq_permanent_income.md.yml new file mode 100644 index 0000000..32c6a30 --- /dev/null +++ b/.translate/state/lq_permanent_income.md.yml @@ -0,0 +1,6 @@ +source-sha: 94222f281872c1d42aad8eff12f32821041cbdef +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 3 +tool-version: 0.20.0 diff --git a/.translate/state/lq_robust_smoothing.md.yml b/.translate/state/lq_robust_smoothing.md.yml new file mode 100644 index 0000000..5d1159f --- /dev/null +++ b/.translate/state/lq_robust_smoothing.md.yml @@ -0,0 +1,6 @@ +source-sha: cb3f056f8e966bd6fd43c8cccefa7a666d6a133c +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 4 +tool-version: 0.20.0 diff --git a/.translate/state/ls_learning.md.yml b/.translate/state/ls_learning.md.yml new file mode 100644 index 0000000..98e4436 --- /dev/null +++ b/.translate/state/ls_learning.md.yml @@ -0,0 +1,6 @@ +source-sha: b8ed85c7e8b8c17f5f59c74b3cb829470363ca8b +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 14 +tool-version: 0.20.0 diff --git a/.translate/state/mccall_model_with_sep_markov.md.yml b/.translate/state/mccall_model_with_sep_markov.md.yml new file mode 100644 index 0000000..a97b4fe --- /dev/null +++ b/.translate/state/mccall_model_with_sep_markov.md.yml @@ -0,0 +1,6 @@ +source-sha: 0bfcac8105ac8c11f06797579a9f4d565db7b53d +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 9 +tool-version: 0.20.0 diff --git a/.translate/state/measurement_models.md.yml b/.translate/state/measurement_models.md.yml new file mode 100644 index 0000000..b9ef0cf --- /dev/null +++ b/.translate/state/measurement_models.md.yml @@ -0,0 +1,6 @@ +source-sha: bb3310a3ed9e1346211f7daee56187883670b6f1 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 7 +tool-version: 0.20.0 diff --git a/.translate/state/merging_of_opinions.md.yml b/.translate/state/merging_of_opinions.md.yml new file mode 100644 index 0000000..0520e80 --- /dev/null +++ b/.translate/state/merging_of_opinions.md.yml @@ -0,0 +1,6 @@ +source-sha: a8966965b2649d470ea144150ca5fd5d520b5345 +synced-at: "2026-07-21" +model: claude-opus-4-8 +mode: NEW +section-count: 11 +tool-version: 0.20.0 diff --git a/.translate/state/misspecified_recovery.md.yml b/.translate/state/misspecified_recovery.md.yml new file mode 100644 index 0000000..6f22b0f --- /dev/null +++ b/.translate/state/misspecified_recovery.md.yml @@ -0,0 +1,6 @@ +source-sha: b8ed85c7e8b8c17f5f59c74b3cb829470363ca8b +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 9 +tool-version: 0.20.0 diff --git a/.translate/state/morris_learn.md.yml b/.translate/state/morris_learn.md.yml new file mode 100644 index 0000000..a14b297 --- /dev/null +++ b/.translate/state/morris_learn.md.yml @@ -0,0 +1,6 @@ +source-sha: 774202bff9a46fc56229fe2fb84f15f72772f667 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 9 +tool-version: 0.20.0 diff --git a/.translate/state/organization_capital.md.yml b/.translate/state/organization_capital.md.yml new file mode 100644 index 0000000..0281f02 --- /dev/null +++ b/.translate/state/organization_capital.md.yml @@ -0,0 +1,6 @@ +source-sha: a8966965b2649d470ea144150ca5fd5d520b5345 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 9 +tool-version: 0.20.0 diff --git a/.translate/state/os_egm.md.yml b/.translate/state/os_egm.md.yml new file mode 100644 index 0000000..2f1c4b1 --- /dev/null +++ b/.translate/state/os_egm.md.yml @@ -0,0 +1,6 @@ +source-sha: 1abb15f5fc0273ea02b47850f447b3c224255123 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 3 +tool-version: 0.20.0 diff --git a/.translate/state/os_egm_jax.md.yml b/.translate/state/os_egm_jax.md.yml new file mode 100644 index 0000000..2f1c4b1 --- /dev/null +++ b/.translate/state/os_egm_jax.md.yml @@ -0,0 +1,6 @@ +source-sha: 1abb15f5fc0273ea02b47850f447b3c224255123 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 3 +tool-version: 0.20.0 diff --git a/.translate/state/os_time_iter.md.yml b/.translate/state/os_time_iter.md.yml new file mode 100644 index 0000000..f5d5a54 --- /dev/null +++ b/.translate/state/os_time_iter.md.yml @@ -0,0 +1,6 @@ +source-sha: 5efda5424e302d1d87c0d361b123177b842e23bc +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 4 +tool-version: 0.20.0 diff --git a/.translate/state/rational_learning_re.md.yml b/.translate/state/rational_learning_re.md.yml new file mode 100644 index 0000000..5425276 --- /dev/null +++ b/.translate/state/rational_learning_re.md.yml @@ -0,0 +1,6 @@ +source-sha: b8ed85c7e8b8c17f5f59c74b3cb829470363ca8b +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 12 +tool-version: 0.20.0 diff --git a/.translate/state/robust_permanent_income.md.yml b/.translate/state/robust_permanent_income.md.yml new file mode 100644 index 0000000..27247b8 --- /dev/null +++ b/.translate/state/robust_permanent_income.md.yml @@ -0,0 +1,6 @@ +source-sha: 7c6396a0a24cd9b944750681b42519179e6bab58 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 10 +tool-version: 0.20.0 diff --git a/.translate/state/ross_recovery.md.yml b/.translate/state/ross_recovery.md.yml new file mode 100644 index 0000000..b04e56d --- /dev/null +++ b/.translate/state/ross_recovery.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 12 +tool-version: 0.20.0 diff --git a/.translate/state/rs_inventory_q.md.yml b/.translate/state/rs_inventory_q.md.yml new file mode 100644 index 0000000..1d80b99 --- /dev/null +++ b/.translate/state/rs_inventory_q.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 6 +tool-version: 0.20.0 diff --git a/.translate/state/survival_recursive_preferences.md.yml b/.translate/state/survival_recursive_preferences.md.yml new file mode 100644 index 0000000..144cda0 --- /dev/null +++ b/.translate/state/survival_recursive_preferences.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-21" +model: claude-opus-4-8 +mode: NEW +section-count: 14 +tool-version: 0.20.0 diff --git a/.translate/state/theil_1.md.yml b/.translate/state/theil_1.md.yml new file mode 100644 index 0000000..20a97aa --- /dev/null +++ b/.translate/state/theil_1.md.yml @@ -0,0 +1,6 @@ +source-sha: 7c6396a0a24cd9b944750681b42519179e6bab58 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 9 +tool-version: 0.20.0 diff --git a/.translate/state/theil_2.md.yml b/.translate/state/theil_2.md.yml new file mode 100644 index 0000000..71027c5 --- /dev/null +++ b/.translate/state/theil_2.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 8 +tool-version: 0.20.0 diff --git a/.translate/state/two_computation.md.yml b/.translate/state/two_computation.md.yml new file mode 100644 index 0000000..9ed747f --- /dev/null +++ b/.translate/state/two_computation.md.yml @@ -0,0 +1,6 @@ +source-sha: 78030a3a27f6527046675bcd8a8d27995ca25af6 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 10 +tool-version: 0.20.0 diff --git a/.translate/state/unemployment_linear.md.yml b/.translate/state/unemployment_linear.md.yml new file mode 100644 index 0000000..299cb75 --- /dev/null +++ b/.translate/state/unemployment_linear.md.yml @@ -0,0 +1,6 @@ +source-sha: 538a1f8c838a7311588f4b5c75708b1f77924914 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 8 +tool-version: 0.20.0 diff --git a/.translate/state/unemployment_shocks.md.yml b/.translate/state/unemployment_shocks.md.yml new file mode 100644 index 0000000..ec546f2 --- /dev/null +++ b/.translate/state/unemployment_shocks.md.yml @@ -0,0 +1,6 @@ +source-sha: 68e893d3439ab2628bc04324aad7a0f329ebdab9 +synced-at: "2026-07-22" +model: claude-opus-4-8 +mode: NEW +section-count: 6 +tool-version: 0.20.0 diff --git a/lectures/_static/lecture_specific/hansen_singleton_1982/hansen_singleton_1982_data.csv b/lectures/_static/lecture_specific/hansen_singleton_1982/hansen_singleton_1982_data.csv new file mode 100644 index 0000000..9b28375 --- /dev/null +++ b/lectures/_static/lecture_specific/hansen_singleton_1982/hansen_singleton_1982_data.csv @@ -0,0 +1,240 @@ +date,gross_real_return,gross_cons_growth +1959-02-28,1.0109579062397553,1.0006229224411516 +1959-03-31,1.00571436382525,1.0180902221035215 +1959-04-30,1.037975704918033,0.9817704517570749 +1959-05-31,1.0206154266958425,1.0184807553981456 +1959-06-30,0.997762130888052,0.9958074219092394 +1959-07-31,1.0332284787350057,0.993247983171137 +1959-08-31,0.9862179047619046,1.001525294171654 +1959-09-30,0.9525118058948054,1.00821529850278 +1959-10-31,1.0133797259977257,0.9992750451488477 +1959-11-30,1.02031276849642,0.9946087169562763 +1959-12-31,1.0277770065075922,1.004162246542396 +1960-01-31,0.9350211841390549,0.9964357385736891 +1960-02-29,1.0144448970724023,0.9893925342902301 +1960-03-31,0.9853802764976959,1.0163173699295078 +1960-04-30,0.9786453316092882,1.017764785481483 +1960-05-31,1.0343458146930415,0.9709179722539227 +1960-06-30,1.0234206480133703,1.0085616910776072 +1960-07-31,0.9760739799763161,1.0025345810761046 +1960-08-31,1.029428143294484,0.99079410331375 +1960-09-30,0.9410440365002685,0.996384087876349 +1960-10-31,0.9934469213868494,1.008487858402606 +1960-11-30,1.044505804453463,0.998696477646169 +1960-12-31,1.0473899061533538,0.9853033898833323 +1961-01-31,1.0641837217984962,1.0048685493734337 +1961-02-28,1.0366024043074953,1.0060859901137909 +1961-03-31,1.0330478230674713,1.011079709815748 +1961-04-30,1.0092366983309182,0.9981161184493256 +1961-05-31,1.0267367533304685,1.0027101407890602 +1961-06-30,0.9728199730965832,1.002476272282421 +1961-07-31,1.026840189873418,0.9909863637951827 +1961-08-31,1.0265493942318,1.0038014943010605 +1961-09-30,0.9809888298728473,1.0049599207987134 +1961-10-31,1.0289144491593705,1.0005889440900915 +1961-11-30,1.045943817810721,1.0078399370066953 +1961-12-31,1.0013294402322954,1.0046414973238167 +1962-01-31,0.9621478982122725,0.9998486478698215 +1962-02-28,1.0156832745349584,0.9968025400551506 +1962-03-31,0.9947746099593928,1.0099083657192807 +1962-04-30,0.9340541975374449,0.9959690580913071 +1962-05-31,0.9170709260741926,1.0038630150586507 +1962-06-30,0.9186180622393326,0.9888965939087042 +1962-07-31,1.0686570555108608,1.004257045558508 +1962-08-31,1.0208077663671373,1.0032008132019383 +1962-09-30,0.9390012372442236,1.008872742785775 +1962-10-31,1.0046497376093295,0.9902798033248339 +1962-11-30,1.1110766885802141,1.0035193294325306 +1962-12-31,1.0147671803592304,1.0014352218681717 +1963-01-31,1.0481125807476441,1.001428214563085 +1963-02-28,0.9775236125072746,0.9915834699129015 +1963-03-31,1.036389952762592,1.0078801105544286 +1963-04-30,1.0489919005102042,0.9956865775751438 +1963-05-31,1.0186465686534685,0.9989658846886131 +1963-06-30,0.9784570076658737,1.0050600698980607 +1963-07-31,0.9946981519507188,1.000088934489468 +1963-08-31,1.0506999422268908,1.008744726271068 +1963-09-30,0.9914783159227603,0.9882926288372472 +1963-10-31,1.0264046658591814,0.9941407674824702 +1963-11-30,0.9918539775115595,1.003306442060827 +1963-12-31,1.018524179855361,1.0094163852654314 +1964-01-31,1.0219723597618302,0.9969309553486984 +1964-02-29,1.0177810463659147,1.0103641242285242 +1964-03-31,1.017465629080274,1.0048580805656955 +1964-04-30,1.0036379124895571,0.9958384002706671 +1964-05-31,1.0183483290622877,1.019303124872573 +1964-06-30,1.0136325521920666,0.9989575150840528 +1964-07-31,1.0186986244268446,1.0077285243985779 +1964-08-31,0.9891215350922932,1.0072981181249718 +1964-09-30,1.0265952692867542,0.9906379404291648 +1964-10-31,1.008218629539197,1.0047084123320786 +1964-11-30,1.0011356879829885,0.9826758836425177 +1964-12-31,1.0019410439645797,1.0251178687188183 +1965-01-31,1.0370722222222222,0.993420687639879 +1965-02-28,1.0080778922304467,1.0098922458637234 +1965-03-31,0.9878478595404079,0.9842224236080818 +1965-04-30,1.0314834672435103,1.0148702669060463 +1965-05-31,0.9920809487139997,1.003708609359037 +1965-06-30,0.9392863331299572,0.9867187240607261 +1965-07-31,1.0173448223272838,1.0169657327375092 +1965-08-31,1.0331209600978442,0.9985898079603674 +1965-09-30,1.033437932618683,1.0100855351490021 +1965-10-31,1.027159983695929,1.031222998180067 +1965-11-30,1.0019237940158763,0.9926644342395888 +1965-12-31,1.0088823100303954,1.0031400596884208 +1966-01-31,1.0072241849197536,1.0030154325138518 +1966-02-28,0.9845428829190056,1.0025556170670897 +1966-03-31,0.9742078627020555,1.0005930499735936 +1966-04-30,1.021336986573844,1.0087165432532905 +1966-05-31,0.9483431557989048,0.9912941713789765 +1966-06-30,0.9881211970570689,1.00766318282403 +1966-07-31,0.9865624323115901,1.0086434828390984 +1966-08-31,0.9182677010360139,0.9885676485039826 +1966-09-30,0.9899812192723696,1.0035629859147115 +1966-10-31,1.041768339389178,0.9947317349453374 +1966-11-30,1.0175501840852192,1.0026958464253002 +1966-12-31,1.004757447748013,0.9975934450405057 +1967-01-31,1.0866530295590693,1.0048229877833104 +1967-02-28,1.0108036808009422,1.0052226050463773 +1967-03-31,1.0445689700898777,1.00083279682869 +1967-04-30,1.0425608343160377,1.0027883252312702 +1967-05-31,0.9585927786499215,0.9969769901187401 +1967-06-30,1.0229355226506378,1.0019075616143613 +1967-07-31,1.0447114907285733,0.9878937593061994 +1967-08-31,0.9903404945454546,1.0053931198406931 +1967-09-30,1.0319484760522495,1.0073852460033181 +1967-10-31,0.9718775125628141,0.9829686324961886 +1967-11-30,1.0035662061329613,1.0089850965808387 +1967-12-31,1.033054040792765,1.013531234047572 +1968-01-31,0.9586732832463992,0.996618192741401 +1968-02-29,0.9626763822688275,1.0034102821507809 +1968-03-31,1.0037470630202143,1.0144003772849155 +1968-04-30,1.0909715308396148,0.9927375972057049 +1968-05-31,1.0231285188158084,1.0023733703506579 +1968-06-30,1.0090607132761706,1.0117684709448878 +1968-07-31,0.9751435403551628,1.007210916081518 +1968-08-31,1.0130833933498575,0.9997056149271085 +1968-09-30,1.0421195260751936,0.9885652798055251 +1968-10-31,1.003737031191979,1.0001906700265046 +1968-11-30,1.055511409395973,1.0121418411010206 +1968-12-31,0.964018356683775,0.9850571280382645 +1969-01-31,0.9889133014001473,1.0082139433036967 +1969-02-28,0.9453468955677268,1.0078666002342456 +1969-03-31,1.0268519363857187,0.9975673833773808 +1969-04-30,1.014136540126692,0.9971018638456864 +1969-05-31,1.0000262257127293,1.0075298934862833 +1969-06-30,0.9260949497679867,0.9851917552258751 +1969-07-31,0.9311470263724436,1.0048978054068127 +1969-08-31,1.0496402792696027,1.0091713231994486 +1969-09-30,0.9718027792624265,0.9878632302339346 +1969-10-31,1.0556596297614809,1.0120173869077764 +1969-11-30,0.9618071687759981,0.9932846657059041 +1969-12-31,0.9741939652518143,0.9985286940605688 +1970-01-31,0.9212316015419659,1.0112022620493186 +1970-02-28,1.0529872993719471,0.9918189353702483 +1970-03-31,0.9953170527417878,1.0027697854897362 +1970-04-30,0.8890496685298322,0.9902986375379047 +1970-05-31,0.9343163135593221,1.0069967730099987 +1970-06-30,0.9469810955590116,1.0000796481595717 +1970-07-31,1.0708379418729819,0.9970257158016894 +1970-08-31,1.0493963217896323,1.0008126665645092 +1970-09-30,1.0423570419218087,1.0046092184891302 +1970-10-31,0.9778801100260139,0.9975297864731273 +1970-11-30,1.0499492585648544,1.0011273292953267 +1970-12-31,1.058937765120925,1.0124788876843573 +1971-01-31,1.0539815499254845,0.9951243762978286 +1971-02-28,1.0165775612661676,0.9985130749361691 +1971-03-31,1.0412760627916844,0.9873714034196678 +1971-04-30,1.0299738476488232,1.0083586571050156 +1971-05-31,0.9593924993686338,0.9932845622433929 +1971-06-30,0.9981365955842305,1.0051700066447553 +1971-07-31,0.9584173951268526,0.991440910682584 +1971-08-31,1.0379071267816953,0.998618699830775 +1971-09-30,0.9932372145263945,1.002297245019121 +1971-10-31,0.9581448303078138,0.9943196841276655 +1971-11-30,0.9981049217744947,1.0085871519718006 +1971-12-31,1.0857983972240584,1.0000851203496202 +1972-01-31,1.0239623281468675,0.9795919590714202 +1972-02-29,1.0249978642445072,1.0057831401155264 +1972-03-31,1.0092303401137805,1.0176466007666984 +1972-04-30,1.0062942303754965,1.002537882028125 +1972-05-31,1.014321677092277,1.0090974304940825 +1972-06-30,0.978640011448197,0.9979709716441202 +1972-07-31,0.9909672557003257,1.0044556152379327 +1972-08-31,1.0329503309913495,1.0019206535386223 +1972-09-30,0.9847214674460794,1.0030088650530669 +1972-10-31,1.0067647697566862,1.015012111236451 +1972-11-30,1.0463335538184007,0.9957679937499486 +1972-12-31,1.0065508830110277,0.9976564431715872 +1973-01-31,0.9646849504165014,1.0054534426599542 +1973-02-28,0.9472085626670861,1.0029914982298926 +1973-03-31,0.9779890500193873,0.989248586225157 +1973-04-30,0.9384658711583471,0.9942346637985785 +1973-05-31,0.9691159728575784,0.9965352430069263 +1973-06-30,0.9814309245604084,1.0019997690857858 +1973-07-31,1.0551640866873064,1.017181918623719 +1973-08-31,0.9462215797625194,0.9667306001463677 +1973-09-30,1.0534230820252044,1.0144124866136586 +1973-10-31,0.9898111517100264,0.9934181638693607 +1973-11-30,0.8654669068376685,1.0037280242950093 +1973-12-31,1.0000506584098514,0.9908907468835305 +1974-01-31,0.9875830190659436,0.9956525119112044 +1974-02-28,0.98031451668151,0.9910821959505793 +1974-03-31,0.9595848668280871,0.9896974308812007 +1974-04-30,0.9478784373956594,1.0007275502562654 +1974-05-31,0.9495931537598203,0.9973613030939844 +1974-06-30,0.97195321299639,0.9975897053862942 +1974-07-31,0.9204789669340637,1.004966234283919 +1974-08-31,0.8991692737968946,0.9973952658120752 +1974-09-30,0.8792332560723923,0.989318272633984 +1974-10-31,1.1588045494699646,0.9969716375104358 +1974-11-30,0.9518714294651237,0.9898766288310575 +1974-12-31,0.9642454181784351,0.9845061814135657 +1975-01-31,1.1373505850029328,1.0081651656309403 +1975-02-28,1.0579404276954363,1.001536828811441 +1975-03-31,1.0313355872105572,1.0052761564076116 +1975-04-30,1.0471811753817677,0.9935362730578393 +1975-05-31,1.0539289649441383,1.0331915679240886 +1975-06-30,1.0453038992788168,0.993308307847106 +1975-07-31,0.9271832920866783,0.9969921925239672 +1975-08-31,0.9711535316543092,1.0035698292820647 +1975-09-30,0.9614013160261409,0.9952147892289859 +1975-10-31,1.0520194918535728,0.9890868041021199 +1975-11-30,1.0265333709131903,1.0073759465907024 +1975-12-31,0.9857875950190781,1.0021354245060932 +1976-01-31,1.1243044882773283,1.0142100453652187 +1976-02-29,1.0109178776914407,0.994119885230983 +1976-03-31,1.0298266412940058,1.0037780407827317 +1976-04-30,0.9905959747528877,1.011408985199085 +1976-05-31,0.9858094425180048,0.9915899111107992 +1976-06-30,1.0405823588441898,1.0134757714559979 +1976-07-31,0.9903584962803963,0.995576046841543 +1976-08-31,0.994202673029629,1.0020517454497475 +1976-09-30,1.0206372806250363,0.9993560142074526 +1976-10-31,0.9753222238342569,1.0053898361696996 +1976-11-30,1.0035523611351946,0.9967222024565706 +1976-12-31,1.0565306057814117,1.007819656591786 +1977-01-31,0.9587727991746904,0.9968859272175131 +1977-02-28,0.9716811046347121,0.9941048911407744 +1977-03-31,0.9870324205420342,0.993808284687326 +1977-04-30,0.9989612347270488,1.004466953570016 +1977-05-31,0.9835700231320196,0.9990643544993814 +1977-06-30,1.0456919101746605,0.9926203877235478 +1977-07-31,0.9846248341074982,1.008972476016858 +1977-08-31,0.9840791441491121,0.9936099082340789 +1977-09-30,1.0002761537614275,1.0019378571638178 +1977-10-31,0.9572044980800877,1.013567427204734 +1977-11-30,1.0379116837832683,1.0100645126409113 +1977-12-31,1.0035811916648578,0.9924702747962896 +1978-01-31,0.9407902963503254,0.9909629361948763 +1978-02-28,0.9886968052410225,1.0131171043457206 +1978-03-31,1.0258074850860062,1.0061359586059442 +1978-04-30,1.074129084499576,0.9917395346788931 +1978-05-31,1.013486002469071,1.0049967361563237 +1978-06-30,0.9808226302483777,0.9998135892775268 +1978-07-31,1.0521110326933056,0.9959300072415749 +1978-08-31,1.0400536933581626,1.0033159988277387 +1978-09-30,0.9873057466529351,1.0104543799417738 +1978-10-31,0.8813554851242205,0.9911387220819502 +1978-11-30,1.0281085688148,1.009087222697169 +1978-12-31,1.0113599312297732,1.0089199884598332 diff --git a/lectures/_static/lecture_specific/hansen_singleton_1982/make_data.py b/lectures/_static/lecture_specific/hansen_singleton_1982/make_data.py new file mode 100644 index 0000000..1cdfc0f --- /dev/null +++ b/lectures/_static/lecture_specific/hansen_singleton_1982/make_data.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +""" +Build the vendored dataset for the ``hansen_singleton_1982`` lecture. + +Downloads the raw inputs from FRED and the Ken French data library, constructs +the monthly gross real return and gross consumption-growth series used in the +lecture, and writes them to ``hansen_singleton_1982_data.csv`` next to this +script. + +Usage +----- + python make_data.py + +Requires only the standard library plus pandas (both ship with Anaconda). + +Note +---- +The committed CSV is a *frozen snapshot*. FRED revises historical series and +the Ken French library is updated over time, so re-running this script may +produce small differences from the committed data. See README.md. +""" +import io +import urllib.request +import zipfile +from pathlib import Path + +import pandas as pd + +FRED_CODES = { + "population_16plus": "CNP16OV", + "cons_nd_real_index": "DNDGRA3M086SBEA", + "cons_nd_price_index": "DNDGRG3M086SBEA", +} +START = "1959-02-01" +END = "1978-12-01" +OUTPUT = Path(__file__).with_name("hansen_singleton_1982_data.csv") + + +def read_fred(codes, start, end): + """Download FRED series as a date-indexed DataFrame (columns = codes).""" + base = "https://fred.stlouisfed.org/graph/fredgraph.csv" + columns = [] + for code in codes: + url = f"{base}?id={code}&cosd={start:%Y-%m-%d}&coed={end:%Y-%m-%d}" + columns.append( + pd.read_csv(url, index_col=0, parse_dates=True, na_values=".")) + fred = pd.concat(columns, axis=1).astype("float64") + fred.index.name = "DATE" + return fred + + +def read_famafrench_factors(start, end): + """Download the monthly Fama-French research factors (percent).""" + url = ("https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/" + "F-F_Research_Data_Factors_CSV.zip") + with urllib.request.urlopen(url) as response: + payload = response.read() + with zipfile.ZipFile(io.BytesIO(payload)) as archive: + text = archive.read(archive.namelist()[0]).decode("utf-8") + + # Preamble, then a monthly table (rows keyed by YYYYMM), then an annual + # table (rows keyed by YYYY). Keep the contiguous monthly block. + records = [] + for line in text.splitlines(): + cells = [cell.strip() for cell in line.split(",")] + key = cells[0] + if len(key) == 6 and key.isdigit(): + records.append([key] + [float(x) for x in cells[1:5]]) + elif records: + break + factors = pd.DataFrame( + records, columns=["date", "Mkt-RF", "SMB", "HML", "RF"]) + factors.index = pd.PeriodIndex( + pd.to_datetime(factors["date"], format="%Y%m"), freq="M") + factors = factors.drop(columns="date") + window = ((factors.index >= pd.Period(start, "M")) + & (factors.index <= pd.Period(end, "M"))) + return factors.loc[window] + + +def to_month_end(index): + return pd.PeriodIndex(pd.DatetimeIndex(index), freq="M").to_timestamp("M") + + +def build(start=START, end=END): + start_period = pd.Timestamp(start).to_period("M") + end_period = pd.Timestamp(end).to_period("M") + + # Pull one extra month to build the first in-sample growth rate. + fetch_start = (start_period - 1).to_timestamp(how="start") + fetch_end = end_period.to_timestamp("M") + sample_start = start_period.to_timestamp("M") + sample_end = end_period.to_timestamp("M") + + fred = read_fred(list(FRED_CODES.values()), fetch_start, fetch_end) + fred = fred.rename(columns={v: k for k, v in FRED_CODES.items()}) + fred.index = to_month_end(fred.index) + fred["cons_real_level"] = fred["cons_nd_real_index"] + fred["cons_price_index"] = fred["cons_nd_price_index"] + fred["consumption_per_capita"] = ( + fred["cons_real_level"] / fred["population_16plus"]) + fred["gross_cons_growth"] = ( + fred["consumption_per_capita"] + / fred["consumption_per_capita"].shift(1)) + fred["gross_inflation_cons"] = ( + fred["cons_price_index"] / fred["cons_price_index"].shift(1)) + + ff = read_famafrench_factors(fetch_start, fetch_end).copy() + ff.columns = [str(col).strip() for col in ff.columns] + if ("Mkt-RF" not in ff.columns) or ("RF" not in ff.columns): + raise KeyError( + "Fama-French data missing required columns: 'Mkt-RF' and 'RF'.") + # Mkt-RF and RF are reported in percent per month. + ff["gross_nom_return"] = 1.0 + (ff["Mkt-RF"] + ff["RF"]) / 100.0 + ff.index = ff.index.to_timestamp(how="end") + ff.index = to_month_end(ff.index) + market = ff[["gross_nom_return"]] + + out = fred.join(market, how="inner") + out["gross_real_return"] = ( + out["gross_nom_return"] / out["gross_inflation_cons"]) + out = out.loc[sample_start:sample_end].dropna() + + frame = out[["gross_real_return", "gross_cons_growth"]].copy() + frame.index.name = "date" + return frame + + +if __name__ == "__main__": + frame = build() + frame.to_csv(OUTPUT) + print(f"wrote {OUTPUT.name}: {frame.shape[0]} rows x {frame.shape[1]} cols " + f"({frame.index.min().date()} .. {frame.index.max().date()})") diff --git a/lectures/_static/lecture_specific/hansen_singleton_1983/hansen_singleton_1983_data.csv b/lectures/_static/lecture_specific/hansen_singleton_1983/hansen_singleton_1983_data.csv new file mode 100644 index 0000000..491212f --- /dev/null +++ b/lectures/_static/lecture_specific/hansen_singleton_1983/hansen_singleton_1983_data.csv @@ -0,0 +1,240 @@ +date,gross_real_return,gross_cons_growth,gross_inflation_cons,consumption_per_capita,gross_real_tbill +1959-02-28,1.0109579062397553,1.0006229224411516,1.0004373018476003,0.0002135783527442639,1.001462058791389 +1959-03-31,1.00571436382525,1.0180902221035215,0.9992896951152881,0.0002174420325819119,1.0029123735578762 +1959-04-30,1.037975704918033,0.9817704517570749,1.0006014544261577,0.00021347816255892023,1.001397704918033 +1959-05-31,1.0206154266958425,1.0184807553981456,0.9989071038251366,0.00021742340026401722,1.003296498905908 +1959-06-30,0.997762130888052,0.9958074219092394,1.0022428884026258,0.00021651183567965163,1.0001567600021832 +1959-07-31,1.0332284787350057,0.993247983171137,1.0010370612957806,0.00021504994412149461,1.0014614231188659 +1959-08-31,0.9862179047619046,1.001525294171654,1.001908396946565,0.00021537795854787765,0.999991619047619 +1959-09-30,0.9525118058948054,1.00821529850278,1.002612244897959,0.0002171473527682678,1.000486484285947 +1959-10-31,1.0133797259977257,0.9992750451488477,1.0023883189491396,0.00021698993074146356,1.0006102236421726 +1959-11-30,1.02031276849642,0.9946087169562763,0.9983213299398929,0.00021582007660719832,1.0042858646127142 +1959-12-31,1.0277770065075922,1.004162246542396,1.000216966804079,0.00021671837297483626,1.0031823427331887 +1960-01-31,0.9350211841390549,0.9964357385736891,0.9983731019522776,0.00021594593203766918,1.004934926670288 +1960-02-29,1.0144448970724023,0.9893925342902301,1.000054318305269,0.0002136552929684153,1.0028455271305194 +1960-03-31,0.9853802764976959,1.0163173699295078,1.0018467220683287,0.00021714158542117832,1.0016502304147465 +1960-04-30,0.9786453316092882,1.017764785481483,1.0062889671997832,0.00022099905910529468,0.9956384623673292 +1960-05-31,1.0343458146930415,0.9709179722539227,0.9995689887398309,0.00021457195833653753,1.0031323613431788 +1960-06-30,1.0234206480133703,1.0085616910776072,0.9997844014445102,0.00021640905715773214,1.0026161625963665 +1960-07-31,0.9760739799763161,1.0025345810761046,1.0015634265998168,0.00021695756345870175,0.9997369846054472 +1960-08-31,1.029428143294484,0.99079410331375,1.0022069114005814,0.0002149602745442004,0.9994942048445137 +1960-09-30,0.9410440365002685,0.996384087876349,1.0005907943498575,0.0002141829970813727,1.0010086097691897 +1960-10-31,0.9934469213868494,1.008487858402606,1.0016639828234033,0.00021600095203284516,1.0005351267349014 +1960-11-30,1.044505804453463,0.998696477646169,1.0035367879534858,0.00021571938996342157,0.9977710952101246 +1960-12-31,1.0473899061533538,0.9853033898833323,1.0014417685694452,0.00021254904619452377,1.0001580036258932 +1961-01-31,1.0641837217984962,1.0048685493734337,0.9997333902100883,0.00021358385172019805,1.002167187583338 +1961-02-28,1.0366024043074953,1.0060859901137909,1.0004800256013655,0.00021488372093023255,1.0009195329992535 +1961-03-31,1.0330478230674713,1.011079709815748,0.9979208870881758,0.0002172645702022677,1.004087611517709 +1961-04-30,1.0092366983309182,0.9981161184493256,0.9954057374859767,0.00021685526948684843,1.006323313476091 +1961-05-31,1.0267367533304685,1.0027101407890602,0.9990876402082327,0.0002174429777980074,1.0027148366996133 +1961-06-30,0.9728199730965832,1.002476272282421,0.9983347657928664,0.00021798142581693568,1.0036713478611783 +1961-07-31,1.026840189873418,0.9909863637951827,1.003174603174603,0.00021601662054521444,0.9986297468354433 +1961-08-31,1.0265493942318,1.0038014943010605,1.000536365586784,0.0002168378064971514,1.0008631714377614 +1961-09-30,0.9809888298728473,1.0049599207987134,0.9991958829205532,0.00021791330484354402,1.0025061323032352 +1961-10-31,1.0289144491593705,1.0005889440900915,0.9988196791673374,0.00021804164359658394,1.0030839608959552 +1961-11-30,1.045943817810721,1.0078399370066953,1.000053714347102,0.00021975107634721747,1.001446207970781 +1961-12-31,1.0013294402322954,1.0046414973238167,0.9988720592974543,0.00022077105037998892,1.0030313598967573 +1962-01-31,0.9621478982122725,0.9998486478698215,1.0016131634134537,0.00022073763621123217,1.0007855693348364 +1962-02-28,1.0156832745349584,0.9968025400551506,1.0043485263327427,0.000220031836461126,0.9976616420782554 +1962-03-31,0.9947746099593928,1.0099083657192807,1.0004276245456492,0.00022221199236666778,1.0015717033554177 +1962-04-30,0.9340541975374449,0.9959690580913071,1.0024043599059627,0.00022131626873402282,0.9997961302702416 +1962-05-31,0.9170709260741926,1.0038630150586507,0.9986141463674645,0.00022217121681286672,1.0037911075527088 +1962-06-30,0.9186180622393326,0.9888965939087042,0.9982385908726983,0.00021970435957079613,1.0037680461982674 +1962-07-31,1.0686570555108608,1.004257045558508,0.9969521976259222,0.00022063965103889184,1.0057653740949317 +1962-08-31,1.0208077663671373,1.0032008132019383,1.0027353177795657,0.00022134587734680818,0.9995658697047495 +1962-09-30,0.9390012372442236,1.008872742785775,1.0116067608044501,0.00022330982238319812,0.9906023158673928 +1962-10-31,1.0046497376093295,0.9902798033248339,0.9974620631311795,0.00022113920699013702,1.0051510098065202 +1962-11-30,1.1110766885802141,1.0035193294325306,0.9998409753511794,0.00022191746870998388,1.002159368041565 +1962-12-31,1.0147671803592304,1.0014352218681717,0.9976672675220021,0.00022223596951400574,1.0046435646721221 +1963-01-31,1.0481125807476441,1.001428214563085,1.0036135614836856,0.00022255337016210698,0.9988904479508632 +1963-02-28,0.9775236125072746,0.9915834699129015,1.0007942391189242,0.00022068024302615243,1.0015045658959842 +1963-03-31,1.036389952762592,1.0078801105544286,0.9968255647849321,0.00022241922773837667,1.0054918687967729 +1963-04-30,1.0489919005102042,0.9956865775751438,0.9986731065230082,0.00022145983965373076,1.0038319781037415 +1963-05-31,1.0186465686534685,0.9989658846886131,1.0013286564625852,0.00022123082464268757,1.0010699219786634 +1963-06-30,0.9784570076658737,1.0050600698980607,1.0039276046918952,0.0002223502680789852,0.998378762886598 +1963-07-31,0.9946981519507188,1.000088934489468,1.0041237113402062,0.00022237004268655985,0.9985821355236139 +1963-08-31,1.0506999422268908,1.008744726271068,1.002474595903754,0.00022431460784073955,1.0000253413865545 +1963-09-30,0.9914783159227603,0.9882926288372472,0.995483193277311,0.0002216884734695207,1.0072495515458477 +1963-10-31,1.0264046658591814,0.9941407674824702,1.00184657592065,0.00022038954915700652,1.0010514824372003 +1963-11-30,0.9918539775115595,1.003306442060827,1.002264468903049,0.00022111825443210596,1.0004345470786045 +1963-12-31,1.018524179855361,1.0094163852654314,1.0026271542664986,0.00022320038910505835,1.0002721308038989 +1964-01-31,1.0219723597618302,0.9969309553486984,1.0033539461272403,0.00022251537714470702,0.9996472370207876 +1964-02-29,1.0177810463659147,1.0103641242285242,1.0003133813851457,0.00022482155415619166,1.002285902255639 +1964-03-31,1.017465629080274,1.0048580805656955,0.9997389306599832,0.0002259137553791873,1.0033619470413122 +1964-04-30,1.0036379124895571,0.9958384002706671,1.0002611375150154,0.00022497359275594868,1.0026381735588972 +1964-05-31,1.0183483290622877,1.019303124872573,0.9983813700918963,0.00022931628610994815,1.0042254693792165 +1964-06-30,1.0136325521920666,0.9989575150840528,1.0020396422781237,0.0002290772273406975,1.0009584029227554 +1964-07-31,1.0186986244268446,1.0077285243985779,1.001670146137787,0.00023084765628135864,1.0013276365152146 +1964-08-31,0.9891215350922932,1.0072981181249718,0.9992705293872447,0.0002325324097457729,1.0035320471373448 +1964-09-30,1.0265952692867542,0.9906379404291648,1.0030242986755658,0.0002303554274735831,0.9997763776252858 +1964-10-31,1.008218629539197,1.0047084123320786,1.0006758161779994,0.00023144003580906095,1.0022226816977506 +1964-11-30,1.0011356879829885,0.9826758836425177,1.001662424022027,0.0002274305416989249,1.0012355220164928 +1964-12-31,1.0019410439645797,1.0251178687188183,1.0015559358954411,0.00023314311218796823,1.001541665372068 +1965-01-31,1.0370722222222222,0.993420687639879,1.0010874631039304,0.00023160919082827286,1.001710676598386 +1965-02-28,1.0080778922304467,1.0098922458637234,0.9993275398303331,0.00023390032588824417,1.0036749314146693 +1965-03-31,0.9878478595404079,0.9842224236080818,1.0023810756250324,0.00023020994562844782,1.0012160289181513 +1965-04-30,1.0314834672435103,1.0148702669060463,1.002633617350891,0.00023363322896436924,1.0004651576019776 +1965-05-31,0.9920809487139997,1.003708609359037,1.0032447466007417,0.00023449968334388855,0.9998557215462807 +1965-06-30,0.9392863331299572,0.9867187240607261,1.0097027568150316,0.00023138522834172603,0.9938568486882245 +1965-07-31,1.0173448223272838,1.0169657327375092,1.0001525320317266,0.0002353108482851793,1.0029470184535612 +1965-08-31,1.0331209600978442,0.9985898079603674,0.9975598596919324,0.00023497901480008836,1.0057541813178412 +1965-09-30,1.033437932618683,1.0100855351490021,0.9983182999541353,0.00023734890391313254,1.0047897549770293 +1965-10-31,1.027159983695929,1.031222998180067,1.001888718734048,0.0002447596483080532,1.0012089978091405 +1965-11-30,1.0019237940158763,0.9926644342395888,1.0012737555408366,0.00024296419781239434,1.0022234123753309 +1965-12-31,1.0088823100303954,1.0031400596884208,1.0044779157337673,0.00024372711989567456,0.998827335359676 +1966-01-31,1.0072241849197536,1.0030154325138518,1.0037487335359676,0.0002444620625775154,1.0000510749974765 +1966-02-28,0.9845428829190056,1.0025556170670897,1.0069647723831634,0.00024508681399689446,0.9965591920609463 +1966-03-31,0.9742078627020555,1.0005930499735936,1.0046110665597434,0.00024523216272546343,0.9991926561564558 +1966-04-30,1.021336986573844,1.0087165432532905,1.0032927559369387,0.00024736973947895794,1.000106892093486 +1966-05-31,0.9483431557989048,0.9912941713789765,0.999005469915465,0.0002452161809210269,1.0050996017919362 +1966-06-30,0.9881211970570689,1.00766318282403,1.0012941762070682,0.00024709531734683514,1.0025025850069598 +1966-07-31,0.9865624323115901,1.0086434828390984,1.0006462517399086,0.00024923108148194406,1.0028519052113865 +1966-08-31,0.9182677010360139,0.9885676485039826,1.007004818917979,0.0002463817841547099,0.9971153872718304 +1966-09-30,0.9899812192723696,1.0035629859147115,1.0034533793783917,0.00024725963898129463,1.0005447394296951 +1966-10-31,1.041768339389178,0.9947317349453374,1.0012782694198623,0.000245957009665821,1.0032176175979575 +1966-11-30,1.0175501840852192,1.0026958464253002,1.0002455072179122,0.0002466200719911061,1.0037535712532522 +1966-12-31,1.004757447748013,0.9975934450405057,1.000539983309607,0.00024602656723374505,1.0034581493474632 +1967-01-31,1.0866530295590693,1.0048229877833104,0.9992149936218231,0.0002472131503618832,1.0050890012766376 +1967-02-28,1.0108036808009422,1.0052226050463773,1.0004910144358246,0.000248504247008494,1.0031074597565763 +1967-03-31,1.0445689700898777,1.00083279682869,0.999263839811543,0.0002487112005573187,1.0046395756593487 +1967-04-30,1.0425608343160377,1.0027883252312702,0.9995579784882864,0.0002494046882731321,1.0036436320754718 +1967-05-31,0.9585927786499215,0.9969769901187401,1.001572327044025,0.0002486507354360499,1.0017249607535323 +1967-06-30,1.0229355226506378,1.0019075616143613,1.0038755886970172,0.0002491250520343504,0.9988289498118555 +1967-07-31,1.0447114907285733,0.9878937593061994,1.0041049699457558,0.00024610908419156696,0.9990987297415681 +1967-08-31,0.9903404945454546,1.0053931198406931,1.0037961746240327,0.00024743637997649533,0.9993064581818183 +1967-09-30,1.0319484760522495,1.0073852460033181,1.0021818181818183,0.00024926375851279224,1.0010159651669086 +1967-10-31,0.9718775125628141,0.9829686324961886,1.0012578616352201,0.00024501845583617957,1.0026388190954774 +1967-11-30,1.0035662061329613,1.0089850965808387,1.0037205257054502,0.0002472199703259556,0.9998799210513649 +1967-12-31,1.033054040792765,1.013531234047572,1.000722091176046,0.00025056516160566994,1.002576048681932 +1968-01-31,0.9586732832463992,0.996618192741401,1.0052434096594187,0.00024971779852339985,0.9987630760396231 +1968-02-29,0.9626763822688275,1.0034102821507809,1.0039718619897593,0.0002505694066744365,0.999928422306959 +1968-03-31,1.0037470630202143,1.0144003772849155,1.002144899904671,0.0002541777006666058,1.0016515576694414 +1968-04-30,1.0909715308396148,0.9927375972057049,1.0032342449464924,0.0002523317598230371,1.0010623192528325 +1968-05-31,1.0231285188158084,1.0023733703506579,1.0040771820035082,0.00025293063654033043,1.0004211010907031 +1968-06-30,1.0090607132761706,1.0117684709448878,1.0022191793757969,0.0002559072433875273,1.0020762131348346 +1968-07-31,0.9751435403551628,1.007210916081518,1.0028267219447848,0.00025775256904424736,1.0019677158695854 +1968-08-31,1.0130833933498575,0.9997056149271085,1.004556985812271,0.0002576766905354213,0.9996446335874293 +1968-09-30,1.0421195260751936,0.9885652798055251,1.0025721367441425,0.00025473022967851047,1.0017234303573095 +1968-10-31,1.003737031191979,1.0001906700265046,1.004944491090587,0.0002547787990981548,0.9994581878945412 +1968-11-30,1.055511409395973,1.0121418411010206,1.002831414779057,0.0002578722827927135,1.0013647211293681 +1968-12-31,0.964018356683775,0.9850571280382645,1.0010182828049061,0.0002540189302884615,1.0032783788782542 +1969-01-31,0.9889133014001473,1.0082139433036967,1.0039302723447543,0.00025610542737991663,1.0013643653279294 +1969-02-28,0.9453468955677268,1.0078666002342456,1.0006908621960207,0.00025812010639493505,1.003906438992958 +1969-03-31,1.0268519363857187,0.9975673833773808,1.0042343627744281,0.0002574921991334865,1.0003640955130848 +1969-04-30,1.014136540126692,0.9971018638456864,1.0056831202163252,0.00025674595168172405,0.9996190447978855 +1969-05-31,1.0000262257127293,1.0075298934862833,1.0038736726974433,0.00025867922135092185,1.0009227528599964 +1969-06-30,0.9260949497679867,0.9851917552258751,1.007672053749773,0.00025484863612317736,0.9974475289453532 +1969-07-31,0.9311470263724436,1.0048978054068127,1.0044600621705635,0.00025609683515110033,1.0008362082884825 +1969-08-31,1.0496402792696027,1.0091713231994486,1.0021528525296017,0.000258445581996627,1.0028410311493017 +1969-09-30,0.9718027792624265,0.9878632302339346,1.0048335123523093,0.00025530888747087716,1.0013599144842331 +1969-10-31,1.0556596297614809,1.0120173869077764,1.000890789239266,0.00025837703315260865,1.0051046635813456 +1969-11-30,0.9618071687759981,0.9932846657059041,1.0056069775720895,0.0002566419450010722,0.9995952916187276 +1969-12-31,0.9741939652518143,0.9985286940605688,1.006062483405611,0.00025626434618308494,1.0003354827358697 +1970-01-31,0.9212316015419659,1.0112022620493186,1.0040906091928745,0.00025913508654292513,1.0019016120553705 +1970-02-28,1.0529872993719471,0.9918189353702483,1.004380585246189,0.00025701508565208116,1.001811479413817 +1970-03-31,0.9953170527417878,1.0027697854897362,0.999781926029309,0.0002577269623069636,1.0059193648300835 +1970-04-30,0.8890496685298322,0.9902986375379047,1.0068053919644027,0.000255226659629369,0.998206811386975 +1970-05-31,0.9343163135593221,1.0069967730099987,1.0021231422505308,0.00025701242263289584,1.0031701271186442 +1970-06-30,0.9469810955590116,1.0000796481595717,1.0008647526807333,0.0002570328931993456,1.0049309832382929 +1970-07-31,1.0708379418729819,0.9970257158016894,1.0033264212890962,0.00025626840432665677,1.0018673670613565 +1970-08-31,1.0493963217896323,1.0008126665645092,1.0008611410118406,0.0002564766650903932,1.004435039793504 +1970-09-30,1.0423570419218087,1.0046092184891302,1.004646160464616,0.00025765882207715826,1.0007503532736695 +1970-10-31,0.9778801100260139,0.9975297864731273,1.0041108208795444,0.0002570223497695452,1.000487176425434 +1970-11-30,1.0499492585648544,1.0011273292953267,1.0008102690946308,0.00025731209859399407,1.00378666268962 +1970-12-31,1.058937765120925,1.0124788876843573,1.0025140617010397,0.0002605230673721748,1.0016817103753135 +1971-01-31,1.0539815499254845,0.9951243762978286,0.9982148170187444,0.00025925285492993264,1.0055951713859912 +1971-02-28,1.0165775612661676,0.9985130749361691,1.0008090270385352,0.0002588673653620676,1.0024889593260722 +1971-03-31,1.0412760627916844,0.9873714034196678,1.0028080326752893,0.0002555982338370966,1.0001914297836232 +1971-04-30,1.0299738476488232,1.0083586571050156,1.0042002545608826,0.00025773469183038846,0.9986056022645653 +1971-05-31,0.9593924993686338,0.9932845622433929,1.0037601926570618,0.0002560038905496832,0.9991430297163061 +1971-06-30,0.9981365955842305,1.0051700066447553,1.0046721104470073,0.00025732743236490826,0.9990324102392224 +1971-07-31,0.9584173951268526,0.991440910682584,1.000712220872261,0.0002551249438874757,1.003285439169388 +1971-08-31,1.0379071267816953,0.998618699830775,1.0045214770158253,0.0002547725397593104,1.0001777194298573 +1971-09-30,0.9932372145263945,1.002297245019121,1.001875468867217,0.00025535781470728124,1.0018211156870085 +1971-10-31,0.9581448303078138,0.9943196841276655,1.0014143683181496,0.0002539073016592748,1.0022824035226188 +1971-11-30,0.9981049217744947,1.0085871519718006,1.000996967557014,0.0002560876422453728,1.0027003402913226 +1971-12-31,1.0857983972240584,1.0000851203496202,1.004606382537245,0.00025610944051501414,0.9990977734633182 +1972-01-31,1.0239623281468675,0.9795919590714202,1.003552544613351,0.00025088274857078805,0.9993497653741662 +1972-02-29,1.0249978642445072,1.0057831401155264,1.0060508767596936,0.0002523336386583413,0.9964704799312631 +1972-03-31,1.0092303401137805,1.0176466007666984,0.9996726811505258,0.0002567864696397534,1.0030283100724429 +1972-04-30,1.0062942303754965,1.002537882028125,0.9995088609667253,0.0002574381634061178,1.0033928053724253 +1972-05-31,1.014321677092277,1.0090974304940825,1.0015560378362884,0.00025978018920422925,1.0014417187947176 +1972-06-30,0.978640011448197,0.9979709716441202,0.9999591152540986,0.00025925308783403804,1.0029410049881429 +1972-07-31,0.9909672557003257,1.0044556152379327,1.0041704145882737,0.0002604082198426725,0.9989340309446255 +1972-08-31,1.0329503309913495,1.0019206535386223,1.0025651465798047,0.00026090837381159964,1.0003339966697802 +1972-09-30,0.9847214674460794,1.0030088650530669,1.0073914632660521,0.0002616934118996139,0.9960378230195526 +1972-10-31,1.0067647697566862,1.015012111236451,1.0024188671638783,0.0002656219825088973,1.0015773175145788 +1972-11-30,1.0463335538184007,0.9957679937499486,1.0032173738186205,0.0002644978686187686,1.0004810783724194 +1972-12-31,1.0065508830110277,0.9976564431715872,1.0033273201042292,0.00026387800283266644,1.0003714439827394 +1973-01-31,0.9646849504165014,1.0054534426599542,1.0072718555218156,0.00026531704639033764,0.9971488774295914 +1973-02-28,0.9472085626670861,1.0029914982298926,1.0089646965489885,0.0002661107418649747,0.9952776379933952 +1973-03-31,0.9779890500193873,0.989248586225157,1.0139172825916025,0.0002632496751692539,0.9908106087630864 +1973-04-30,0.9384658711583471,0.9942346637985785,1.0105854982551377,0.00026173195228698816,0.9946709127882439 +1973-05-31,0.9691159728575784,0.9965352430069263,1.0064842880712122,0.000260825114674991,0.9986246302226288 +1973-06-30,0.9814309245604084,1.0019997690857858,1.0081198536139067,0.0002613467046761146,0.997004469653999 +1973-07-31,1.0551640866873064,1.017181918623719,1.0015503875968992,0.0002658371424884367,1.004842105263158 +1973-08-31,0.9462215797625194,0.9667306001463677,1.0238616627652344,0.00025699290029904186,0.9835313076185559 +1973-09-30,1.0534230820252044,1.0144124866136586,1.0007375175160411,0.0002606968070344071,1.0060580145920848 +1973-10-31,0.9898111517100264,0.9934181638693607,1.0084752008254108,0.00025898094337072574,0.9980413987138265 +1973-11-30,0.8654669068376685,1.0037280242950093,1.014250219234142,0.00025994643061955623,0.9914713163772607 +1973-12-31,1.0000506584098514,0.9908907468835305,1.0122487210894155,0.0002575785127863199,0.9942220513915582 +1974-01-31,0.9875830190659436,0.9956525119112044,1.0173321944622393,0.0002564586932700517,0.9891557600139933 +1974-02-28,0.98031451668151,0.9910821959505793,1.0213048801819136,0.0002541716448966989,0.9848185586079332 +1974-03-31,0.9595848668280871,0.9896974308812007,1.0185654586558883,0.00025155302395711175,0.9872708635996771 +1974-04-30,0.9478784373956594,1.0007275502562654,1.007196663976325,0.00025173604142415606,1.0003011686143573 +1974-05-31,0.9495931537598203,0.9973613030939844,1.0114858096828048,0.0002510717863105175,0.9960594507163134 +1974-06-30,0.97195321299639,0.9975897053862942,1.0058097312999272,0.0002504666293363198,1.0001891696750904 +1974-07-31,0.9204789669340637,1.004966234283919,1.006432556613062,0.00025171050529790745,1.0005638166047086 +1974-08-31,0.8991692737968946,0.9973952658120752,1.0143807474075524,0.00025105486633929816,0.9917380653872119 +1974-09-30,0.8792332560723923,0.989318272633984,1.0124730767994343,0.0002483731667031502,0.995680796951897 +1974-10-31,1.1588045494699646,0.9969716375104358,1.006381965391332,0.0002476210027216921,0.9987261641847552 +1974-11-30,0.9518714294651237,0.9898766288310575,1.0086446239273092,0.00024511424340191467,0.9967831842352208 +1974-12-31,0.9642454181784351,0.9845061814135657,1.0086643728495466,0.0002413164877816943,0.99834992402394 +1975-01-31,1.1373505850029328,1.0081651656309403,1.004527552950662,0.0002432868768739086,1.0012667119439385 +1975-02-28,1.0579404276954363,1.001536828811441,1.0018522520297597,0.0002436607671557339,1.0024432225063937 +1975-03-31,1.0313355872105572,1.0052761564076116,0.9993837241549316,0.00024494635947364617,1.0047191841642773 +1975-04-30,1.0471811753817677,0.9935362730578393,0.99944500971233,0.00024336309309053218,1.0049577417862101 +1975-05-31,1.0539289649441383,1.0331915679240886,1.0023445935523678,0.00025144069572506287,1.002050598627312 +1975-06-30,1.0453038992788168,0.993308307847106,1.0071712166446092,0.00024975813199456127,0.9969506508984233 +1975-07-31,0.9271832920866783,0.9969921925239672,1.0125290306808459,0.00024900690761794805,0.99236660831774 +1975-08-31,0.9711535316543092,1.0035698292820647,1.005402305788616,0.000249895819768199,0.9994009305676462 +1975-09-30,0.9614013160261409,0.9952147892289859,1.0013508240026414,0.0002487000155998128,1.0039438485520717 +1975-10-31,1.0520194918535728,0.9890868041021199,1.0064452305294083,0.0002459859036097662,0.9991601822893397 +1975-11-30,1.0265333709131903,1.0073759465907024,1.0039615166949634,0.0002478002824968575,1.0001379368658398 +1975-12-31,0.9857875950190781,1.0021354245060932,1.003055835756245,0.0002483294412927181,1.001738850601911 +1976-01-31,1.1243044882773283,1.0142100453652187,1.00168594161318,0.00025185821391900706,1.0030089854130986 +1976-02-29,1.0109178776914407,0.994119885230983,0.9956298352329771,0.00025037725871564367,1.007804270715938 +1976-03-31,1.0298266412940058,1.0037780407827317,0.997449433536983,0.00025132319421013996,1.006567316841104 +1976-04-30,0.9905959747528877,1.011408985199085,0.9986917221693626,0.00025419053681307024,1.0055154936286768 +1976-05-31,0.9858094425180048,0.9915899111107992,1.0045551982851018,0.00025205277180367864,0.9991486796479062 +1976-06-30,1.0405823588441898,1.0134757714559979,1.0041492546160458,0.0002554493773513558,1.0001501224875298 +1976-07-31,0.9903584962803963,0.995576046841543,1.003777928632567,0.00025431928127159643,1.0009186009585695 +1976-08-31,0.994202673029629,1.0020517454497475,1.0043223852509628,0.0002548410796997285,0.9998781414685561 +1976-09-30,1.0206372806250363,0.9993560142074526,1.004274505211383,0.0002546769656650444,1.0001249606436942 +1976-10-31,0.9753222238342569,1.0053898361696996,1.0046936038714944,0.0002560496327861752,0.9994091692539825 +1976-11-30,1.0035523611351946,0.9967222024565706,1.0040333110872528,0.00025521035392883266,0.9999668227270102 +1976-12-31,1.0565306057814117,1.007819656591786,1.0037570082654184,0.0002572060112552243,1.000242082229644 +1977-01-31,0.9587727991746904,0.9968859272175131,1.0047218703213177,0.0002564050530160824,0.9988834021091242 +1977-02-28,0.9716811046347121,0.9941048911407744,1.0127808344795965,0.00025489351731649705,0.9908362854394206 +1977-03-31,0.9870324205420342,0.993808284687326,1.0033105087431387,0.00025331528922222716,1.0004878761386389 +1977-04-30,0.9989612347270488,1.004466953570016,1.0063453566090412,0.00025444683685775803,0.99747069274745 +1977-05-31,0.9835700231320196,0.9990643544993814,1.0055206815379443,0.0002542087648197054,0.998189314679078 +1977-06-30,1.0456919101746605,0.9926203877235478,1.0052674117220812,0.00025233280269806017,0.9987392292764071 +1977-07-31,0.9846248341074982,1.008972476016858,1.0027169392847242,0.00025459685271853505,1.0014790422472903 +1977-08-31,0.9840791441491121,0.9936099082340789,1.0027648750276488,0.0002529699554663489,1.0016306165214512 +1977-09-30,1.0002761537614275,1.0019378571638178,1.001323480754384,0.00025346017510678004,1.0029725850864633 +1977-10-31,0.9572044980800877,1.013567427204734,1.0039651944046701,0.0002568989775818404,1.0009311135490948 +1977-11-30,1.0379116837832683,1.0100645126409113,1.0068294020844761,0.00025948454058915003,0.9981830068920428 +1977-12-31,1.0035811916648578,0.9924702747962896,1.004004467569261,0.0002575306933039027,1.0008919606034294 +1978-01-31,0.9407902963503254,0.9909629361948763,1.0043683525070546,0.0002552033719967376,1.000529335170327 +1978-02-28,0.9886968052410225,1.0131171043457206,1.0020260961179996,0.0002585509012565985,1.0025686994500163 +1978-03-31,1.0258074850860062,1.0061359586059442,1.00779143750674,0.00026013735888423854,0.9975278242957653 +1978-04-30,1.074129084499576,0.9917395346788931,1.0092827907225597,0.00025798850325245095,0.9961529209075488 +1978-05-31,1.013486002469071,1.0049967361563237,1.0090913910093298,0.0002592776037345683,0.9960445693572538 +1978-06-30,0.9808226302483777,0.9998135892775268,1.007827480234299,0.000259229271609135,0.9975913732440252 +1978-07-31,1.0521110326933056,0.9959300072415749,1.004456722875238,0.000258174210350914,1.0011382044628956 +1978-08-31,1.0400536933581626,1.0033159988277387,1.0032174364296835,0.00025903031572979,1.002374922408442 +1978-09-30,0.9873057466529351,1.0104543799417738,1.004552038071591,0.00026173831706686687,1.0016404943357364 +1978-10-31,0.8813554851242205,0.9911387220819502,1.0073120494335737,0.00025941898109753473,0.9994916675186585 +1978-11-30,1.0281085688148,1.009087222697169,1.00582762498722,0.0002617763791506407,1.0011655824354544 +1978-12-31,1.0113599312297732,1.0089199884598332,1.0050823338076846,0.0002641114214317213,1.00270392394822 diff --git a/lectures/_static/lecture_specific/hansen_singleton_1983/make_data.py b/lectures/_static/lecture_specific/hansen_singleton_1983/make_data.py new file mode 100644 index 0000000..fa4b1ad --- /dev/null +++ b/lectures/_static/lecture_specific/hansen_singleton_1983/make_data.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +""" +Build the vendored dataset for the ``hansen_singleton_1983`` lecture. + +Downloads the raw inputs from FRED and the Ken French data library, constructs +the monthly series used in the lecture (gross real market return, gross real +T-bill return, gross consumption growth, gross consumption inflation, and per +capita real consumption), and writes them to +``hansen_singleton_1983_data.csv`` next to this script. + +Usage +----- + python make_data.py + +Requires only the standard library plus pandas (both ship with Anaconda). + +Note +---- +The committed CSV is a *frozen snapshot*. FRED revises historical series and +the Ken French library is updated over time, so re-running this script may +produce small differences from the committed data. See README.md. +""" +import io +import urllib.request +import zipfile +from pathlib import Path + +import pandas as pd + +FRED_CODES = { + "population_16plus": "CNP16OV", + "cons_nd_real_index": "DNDGRA3M086SBEA", + "cons_nd_price_index": "DNDGRG3M086SBEA", +} +START = "1959-02-01" +END = "1978-12-01" +OUTPUT = Path(__file__).with_name("hansen_singleton_1983_data.csv") + + +def read_fred(codes, start, end): + """Download FRED series as a date-indexed DataFrame (columns = codes).""" + base = "https://fred.stlouisfed.org/graph/fredgraph.csv" + columns = [] + for code in codes: + url = f"{base}?id={code}&cosd={start:%Y-%m-%d}&coed={end:%Y-%m-%d}" + columns.append( + pd.read_csv(url, index_col=0, parse_dates=True, na_values=".")) + fred = pd.concat(columns, axis=1).astype("float64") + fred.index.name = "DATE" + return fred + + +def read_famafrench_factors(start, end): + """Download the monthly Fama-French research factors (percent).""" + url = ("https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/" + "F-F_Research_Data_Factors_CSV.zip") + with urllib.request.urlopen(url) as response: + payload = response.read() + with zipfile.ZipFile(io.BytesIO(payload)) as archive: + text = archive.read(archive.namelist()[0]).decode("utf-8") + + # Preamble, then a monthly table (rows keyed by YYYYMM), then an annual + # table (rows keyed by YYYY). Keep the contiguous monthly block. + records = [] + for line in text.splitlines(): + cells = [cell.strip() for cell in line.split(",")] + key = cells[0] + if len(key) == 6 and key.isdigit(): + records.append([key] + [float(x) for x in cells[1:5]]) + elif records: + break + factors = pd.DataFrame( + records, columns=["date", "Mkt-RF", "SMB", "HML", "RF"]) + factors.index = pd.PeriodIndex( + pd.to_datetime(factors["date"], format="%Y%m"), freq="M") + factors = factors.drop(columns="date") + window = ((factors.index >= pd.Period(start, "M")) + & (factors.index <= pd.Period(end, "M"))) + return factors.loc[window] + + +def to_month_end(index): + return pd.PeriodIndex(pd.DatetimeIndex(index), freq="M").to_timestamp("M") + + +def build(start=START, end=END): + start_period = pd.Timestamp(start).to_period("M") + end_period = pd.Timestamp(end).to_period("M") + + # Pull one extra month to build the first in-sample growth rate. + fetch_start = (start_period - 1).to_timestamp(how="start") + fetch_end = end_period.to_timestamp("M") + sample_start = start_period.to_timestamp("M") + sample_end = end_period.to_timestamp("M") + + fred = read_fred(list(FRED_CODES.values()), fetch_start, fetch_end) + fred = fred.rename(columns={v: k for k, v in FRED_CODES.items()}) + fred.index = to_month_end(fred.index) + fred["cons_real_level"] = fred["cons_nd_real_index"] + fred["cons_price_index"] = fred["cons_nd_price_index"] + fred["consumption_per_capita"] = ( + fred["cons_real_level"] / fred["population_16plus"]) + fred["gross_cons_growth"] = ( + fred["consumption_per_capita"] + / fred["consumption_per_capita"].shift(1)) + fred["gross_inflation_cons"] = ( + fred["cons_price_index"] / fred["cons_price_index"].shift(1)) + + ff = read_famafrench_factors(fetch_start, fetch_end).copy() + ff.columns = [str(col).strip() for col in ff.columns] + if ("Mkt-RF" not in ff.columns) or ("RF" not in ff.columns): + raise KeyError( + "Fama-French data missing required columns: 'Mkt-RF' and 'RF'.") + # Mkt-RF and RF are reported in percent per month. + ff["gross_nom_return"] = 1.0 + (ff["Mkt-RF"] + ff["RF"]) / 100.0 + ff["gross_nom_tbill"] = 1.0 + ff["RF"] / 100.0 + ff.index = ff.index.to_timestamp(how="end") + ff.index = to_month_end(ff.index) + market = ff[["gross_nom_return", "gross_nom_tbill"]] + + out = fred.join(market, how="inner") + out["gross_real_return"] = ( + out["gross_nom_return"] / out["gross_inflation_cons"]) + out["gross_real_tbill"] = ( + out["gross_nom_tbill"] / out["gross_inflation_cons"]) + out = out.loc[sample_start:sample_end].dropna() + + frame = out[[ + "gross_real_return", + "gross_cons_growth", + "gross_inflation_cons", + "consumption_per_capita", + "gross_real_tbill", + ]].copy() + frame.index.name = "date" + return frame + + +if __name__ == "__main__": + frame = build() + frame.to_csv(OUTPUT) + print(f"wrote {OUTPUT.name}: {frame.shape[0]} rows x {frame.shape[1]} cols " + f"({frame.index.min().date()} .. {frame.index.max().date()})") diff --git a/lectures/_static/quant-econ.bib b/lectures/_static/quant-econ.bib index 7c481ed..d35e991 100644 --- a/lectures/_static/quant-econ.bib +++ b/lectures/_static/quant-econ.bib @@ -1,7 +1,876 @@ -### -QuantEcon Bibliography File used in conjuction with sphinxcontrib-bibtex package -Note: Extended Information (like abstracts, doi, url's etc.) can be found in quant-econ-extendedinfo.bib file in _static/ -### +@article{BreedenLitzenberger1978, + author = {Breeden, Douglas T. and Litzenberger, Robert H.}, + title = {Prices of State-Contingent Claims Implicit in Option Prices}, + journal = {Journal of Business}, + volume = {51}, + number = {4}, + pages = {621--651}, + year = {1978}, + doi = {10.1086/296025} +} + +@article{CarrYu2012, + author = {Carr, Peter and Yu, Jiming}, + title = {Risk, Return, and {Ross} Recovery}, + journal = {Journal of Derivatives}, + volume = {20}, + number = {1}, + pages = {38--59}, + year = {2012}, + doi = {10.3905/jod.2012.20.1.038} +} + +@article{BlackScholes1973, + author = {Black, Fischer and Scholes, Myron}, + title = {The Pricing of Options and Corporate Liabilities}, + journal = {Journal of Political Economy}, + volume = {81}, + number = {3}, + pages = {637--654}, + year = {1973}, + doi = {10.1086/260062} +} + +@article{Merton1973, + author = {Merton, Robert C.}, + title = {Theory of Rational Option Pricing}, + journal = {Bell Journal of Economics and Management Science}, + volume = {4}, + number = {1}, + pages = {141--183}, + year = {1973}, + doi = {10.2307/3003143} +} + +@article{CoxRossRubinstein1979, + author = {Cox, John C. and Ross, Stephen A. and Rubinstein, Mark}, + title = {Option Pricing: A Simplified Approach}, + journal = {Journal of Financial Economics}, + volume = {7}, + number = {3}, + pages = {229--263}, + year = {1979}, + doi = {10.1016/0304-405X(79)90015-1} +} + +@article{JackwerthRubinstein1996, + author = {Jackwerth, Jens Carsten and Rubinstein, Mark}, + title = {Recovering Probability Distributions from Option Prices}, + journal = {Journal of Finance}, + volume = {51}, + number = {5}, + pages = {1611--1631}, + year = {1996}, + doi = {10.1111/j.1540-6261.1996.tb05219.x} +} + +@article{Weitzman2007, + author = {Weitzman, Martin L.}, + title = {Subjective Expectations and Asset-Return Puzzles}, + journal = {American Economic Review}, + volume = {97}, + number = {4}, + pages = {1102--1130}, + year = {2007}, + doi = {10.1257/aer.97.4.1102} +} + +@article{BorovickaHansenScheinkman2016, + author = {Borovička, Jaroslav and Hansen, Lars Peter and Scheinkman, José A.}, + title = {Misspecified Recovery}, + journal = {Journal of Finance}, + volume = {71}, + number = {6}, + pages = {2493--2544}, + year = {2016}, + doi = {10.1111/jofi.12404} +} + +@article{Ross2015, + author = {Ross, Stephen A.}, + title = {The Recovery Theorem}, + journal = {Journal of Finance}, + volume = {70}, + number = {2}, + pages = {615--648}, + year = {2015}, + doi = {10.1111/jofi.12092} +} + +@article{HansenScheinkman2009, + author = {Hansen, Lars Peter and Scheinkman, José A.}, + title = {Long-Term Risk: An Operator Approach}, + journal = {Econometrica}, + volume = {77}, + number = {1}, + pages = {177--234}, + year = {2009}, + doi = {10.3982/ECTA6761} +} + +@article{AlvarezJermann2005, + author = {Alvarez, Fernando and Jermann, Urban J.}, + title = {Using Asset Prices to Measure the Persistence of the Marginal Utility of Wealth}, + journal = {Econometrica}, + volume = {73}, + number = {6}, + pages = {1977--2016}, + year = {2005}, + doi = {10.1111/j.1468-0262.2005.00643.x} +} + +@article{BakshiChabiYo2012, + author = {Bakshi, Gurdip and Chabi-Yo, Fousseni}, + title = {Variance Bounds on the Permanent and Transitory Components of Stochastic Discount Factors}, + journal = {Journal of Financial Economics}, + volume = {105}, + number = {1}, + pages = {191--208}, + year = {2012}, + doi = {10.1016/j.jfineco.2012.01.003} +} + +@article{BackusGregoryZin1989, + author = {Backus, David K. and Gregory, Allan W. and Zin, Stanley E.}, + title = {Risk Premiums in the Term Structure: Evidence from Artificial Economies}, + journal = {Journal of Monetary Economics}, + volume = {24}, + number = {3}, + pages = {371--399}, + year = {1989}, + doi = {10.1016/0304-3932(89)90027-5} +} + +@article{Hansen2012, + author = {Hansen, Lars Peter}, + title = {Dynamic Valuation Decomposition within Stochastic Economies}, + journal = {Econometrica}, + volume = {80}, + number = {3}, + pages = {911--967}, + year = {2012}, + note = {Fisher--Schultz Lecture}, + doi = {10.3982/ECTA8070} +} + +@article{BackusChernovZin2014, + author = {Backus, David K. and Chernov, Mikhail and Zin, Stanley E.}, + title = {Sources of Entropy in Representative Agent Models}, + journal = {Journal of Finance}, + volume = {69}, + number = {1}, + pages = {51--99}, + year = {2014}, + doi = {10.1111/jofi.12090} +} + +@article{Borovicka2020, + author = {Borovička, Jaroslav}, + title = {Survival and Long-Run Dynamics with Heterogeneous Beliefs under Recursive Preferences}, + journal = {Journal of Political Economy}, + volume = {128}, + number = {1}, + pages = {206--251}, + year = {2020}, + publisher = {University of Chicago Press}, + doi = {10.1086/704072} +} + +@article{Sandroni2000Markets, + author = {Sandroni, Alvaro}, + title = {Do Markets Favor Agents Able to Make Accurate Predictions?}, + journal = {Econometrica}, + volume = {68}, + number = {6}, + pages = {1303--1341}, + year = {2000} +} + +@article{Blume_Easley2006, + author = {Blume, Lawrence and Easley, David}, + title = {If You're So Smart, Why Aren't You Rich? {B}elief Selection in Complete and Incomplete Markets}, + journal = {Econometrica}, + volume = {74}, + number = {4}, + pages = {929--966}, + year = {2006} +} + +@article{Epstein_Zin1989, + author = {Epstein, Larry G. and Zin, Stanley E.}, + title = {Substitution, Risk Aversion, and the Temporal Behavior of Consumption and Asset Returns: A Theoretical Framework}, + journal = {Econometrica}, + volume = {57}, + number = {4}, + pages = {937--969}, + year = {1989}, + doi = {10.2307/1913778} +} + +@article{Epstein_Zin1991, + author = {Epstein, Larry G. and Zin, Stanley E.}, + title = {Substitution, Risk Aversion, and the Temporal Behavior of Consumption and Asset Returns: An Empirical Analysis}, + journal = {Journal of Political Economy}, + volume = {99}, + number = {2}, + pages = {263--286}, + year = {1991}, + doi = {10.1086/261750} +} + +@article{Duffie_Epstein1992a, + author = {Duffie, Darrell and Epstein, Larry G.}, + title = {Stochastic Differential Utility}, + journal = {Econometrica}, + volume = {60}, + number = {2}, + pages = {353--394}, + year = {1992} +} + +@article{Dumas_Uppal_Wang2000, + author = {Dumas, Bernard and Uppal, Raman and Wang, Tan}, + title = {Efficient Intertemporal Allocations with Recursive Utility}, + journal = {Journal of Economic Theory}, + volume = {93}, + number = {2}, + pages = {154--183}, + year = {2000} +} + +@article{DeLong_etal1991, + author = {De Long, J. Bradford and Shleifer, Andrei and Summers, Lawrence H. and Waldmann, Robert J.}, + title = {The Survival of Noise Traders in Financial Markets}, + journal = {Journal of Business}, + volume = {64}, + number = {1}, + pages = {1--19}, + year = {1991} +} + +@article{Blume_Easley1992, + author = {Blume, Lawrence and Easley, David}, + title = {Evolution and Market Behavior}, + journal = {Journal of Economic Theory}, + volume = {58}, + number = {1}, + pages = {9--40}, + year = {1992} +} + +@article{Yan2008, + author = {Yan, Hongjun}, + title = {Natural Selection in Financial Markets: Does It Work?}, + journal = {Management Science}, + volume = {54}, + number = {11}, + pages = {1935--1950}, + year = {2008} +} + +@article{Kogan_etal2006, + author = {Kogan, Leonid and Ross, Stephen A. and Wang, Jiang and Westerfield, Mark M.}, + title = {The Price Impact and Survival of Irrational Traders}, + journal = {Journal of Finance}, + volume = {61}, + number = {1}, + pages = {195--229}, + year = {2006} +} + +@article{Kogan_etal2017, + author = {Kogan, Leonid and Ross, Stephen A. and Wang, Jiang and Westerfield, Mark M.}, + title = {Market Selection}, + journal = {Journal of Economic Theory}, + volume = {168}, + pages = {209--236}, + year = {2017} +} + +@article{Kreps_Porteus1978, + author = {Kreps, David M. and Porteus, Evan L.}, + title = {Temporal Resolution of Uncertainty and Dynamic Choice Theory}, + journal = {Econometrica}, + volume = {46}, + number = {1}, + pages = {185--200}, + year = {1978}, + doi = {10.2307/1913656} +} + +@article{Lucas_Stokey1984, + author = {Lucas, Robert E. and Stokey, Nancy L.}, + title = {Optimal Growth with Many Consumers}, + journal = {Journal of Economic Theory}, + volume = {32}, + number = {1}, + pages = {139--171}, + year = {1984}, + doi = {10.1016/0022-0531(84)90079-6} +} + +@book{Karlin_Taylor1981, + author = {Karlin, Samuel and Taylor, Howard M.}, + title = {A Second Course in Stochastic Processes}, + publisher = {Academic Press}, + year = {1981} +} + +@article{Brunnermeier_etal2014, + author = {Brunnermeier, Markus K. and Simsek, Alp and Xiong, Wei}, + title = {A Welfare Criterion for Models with Distorted Beliefs}, + journal = {Quarterly Journal of Economics}, + volume = {129}, + number = {4}, + pages = {1753--1797}, + year = {2014} +} + +@article{Feller1952, + author = {Feller, William}, + title = {The Parabolic Differential Equations and the Associated Semi-Groups of Transformations}, + journal = {Annals of Mathematics}, + volume = {55}, + number = {3}, + pages = {468--519}, + year = {1952} +} + +@article{Geoffard1996, + author = {Geoffard, Pierre-Yves}, + title = {Discounting and Optimizing: Capital Accumulation Problems as Variational Minmax Problems}, + journal = {Journal of Economic Theory}, + volume = {69}, + number = {1}, + pages = {53--70}, + year = {1996} +} + +@article{Garleanu_Panageas2015, + author = {Gârleanu, Nicolae and Panageas, Stavros}, + title = {Young, Old, Conservative, and Bold: The Implications of Heterogeneity and Finite Lives for Asset Pricing}, + journal = {Journal of Political Economy}, + volume = {123}, + number = {3}, + pages = {670--685}, + year = {2015} +} + +@article{Negishi1960, + author = {Negishi, Takashi}, + title = {Welfare Economics and Existence of an Equilibrium for a Competitive Economy}, + journal = {Metroeconomica}, + volume = {12}, + number = {2--3}, + pages = {92--97}, + year = {1960} +} + +@article{MillerSanchirico1999, + author = {Miller, Ronald I. and Sanchirico, Chris William}, + title = {The Role of Absolute Continuity in + ``{Merging} of {Opinions}'' and + ``{Rational} {Learning}''}, + journal = {Games and Economic Behavior}, + year = {1999}, + volume = {29}, + number = {1--2}, + pages = {170--190}, + doi = {10.1006/game.1999.0752} +} + +@article{JacksonKalaiSmorodinsky1999, + author = {Jackson, Matthew O. and Kalai, Ehud and + Smorodinsky, Rann}, + title = {Bayesian Representation of Stochastic Processes + under Learning: {de Finetti} Revisited}, + journal = {Econometrica}, + year = {1999}, + volume = {67}, + number = {4}, + pages = {875--893}, + doi = {10.1111/1468-0262.00055} +} + +@article{KalaiLehrer1993Nash, + author = {Kalai, Ehud and Lehrer, Ehud}, + title = {Rational Learning Leads to {Nash} Equilibrium}, + journal = {Econometrica}, + year = {1993}, + volume = {61}, + number = {5}, + pages = {1019--1045}, + doi = {10.2307/2951492} +} + +@article{KalaiLehrer1993Subjective, + author = {Kalai, Ehud and Lehrer, Ehud}, + title = {Subjective Equilibrium in Repeated Games}, + journal = {Econometrica}, + year = {1993}, + volume = {61}, + number = {5}, + pages = {1231--1240}, + doi = {10.2307/2951500} +} + +@article{KalaiLehrer1994Merging, + author = {Kalai, Ehud and Lehrer, Ehud}, + title = {Weak and Strong Merging of Opinions}, + journal = {Journal of Mathematical Economics}, + year = {1994}, + volume = {23}, + number = {1}, + pages = {73--86}, + doi = {10.1016/0304-4068(94)90037-X} +} + +@article{KalaiLehrerSmorodinsky1999, + author = {Kalai, Ehud and Lehrer, Ehud and Smorodinsky, Rann}, + title = {Calibrated Forecasting and Merging}, + journal = {Games and Economic Behavior}, + year = {1999}, + volume = {29}, + number = {1--2}, + pages = {151--169}, + doi = {10.1006/game.1998.0608} +} + +@article{Sandroni1998Nash, + author = {Sandroni, Alvaro}, + title = {Necessary and Sufficient Conditions for + Convergence to {Nash} Equilibrium: + The Almost Absolute Continuity Hypothesis}, + journal = {Games and Economic Behavior}, + year = {1998}, + volume = {22}, + number = {1}, + pages = {121--147}, + doi = {10.1006/game.1997.0572} +} + +@article{PomattoAlNajjarSandroni2014, + author = {Pomatto, Luciano and Al-Najjar, Nabil I. and + Sandroni, Alvaro}, + title = {Merging and Testing Opinions}, + journal = {The Annals of Statistics}, + year = {2014}, + volume = {42}, + number = {3}, + pages = {1003--1028}, + doi = {10.1214/14-AOS1212} +} + +@article{LehrerSmorodinsky1996Compatible, + author = {Lehrer, Ehud and Smorodinsky, Rann}, + title = {Compatible Measures and Merging}, + journal = {Mathematics of Operations Research}, + year = {1996}, + volume = {21}, + number = {3}, + pages = {697--706}, + doi = {10.1287/moor.21.3.697} +} + +@incollection{LehrerSmorodinsky1996Learning, + author = {Lehrer, Ehud and Smorodinsky, Rann}, + title = {Merging and Learning}, + booktitle = {Statistics, Probability and Game Theory: + Papers in Honor of {David Blackwell}}, + editor = {Ferguson, Thomas S. and Shapley, Lloyd S. and + MacQueen, James B.}, + series = {{IMS} Lecture Notes -- Monograph Series}, + volume = {30}, + pages = {147--168}, + publisher = {Institute of Mathematical Statistics}, + address = {Hayward, CA}, + year = {1996}, + doi = {10.1214/lnms/1215453571} +} + +@article{Nyarko1994, + author = {Nyarko, Yaw}, + title = {Bayesian Learning Leads to Correlated Equilibria + in Normal Form Games}, + journal = {Economic Theory}, + year = {1994}, + volume = {4}, + number = {6}, + pages = {821--841}, + doi = {10.1007/BF01213814} +} + +@article{JacksonKalai1999, + author = {Jackson, Matthew O. and Kalai, Ehud}, + title = {Reputation versus Social Learning}, + journal = {Journal of Economic Theory}, + year = {1999}, + volume = {88}, + number = {1}, + pages = {40--59}, + doi = {10.1006/jeth.1999.2538} +} + +@article{AcemogluChernozhukovYildiz2016, + author = {Acemoglu, Daron and Chernozhukov, Victor and + Yildiz, Muhamet}, + title = {Fragility of Asymptotic Agreement under + {Bayesian} Learning}, + journal = {Theoretical Economics}, + year = {2016}, + volume = {11}, + number = {1}, + pages = {187--225}, + doi = {10.3982/TE436} +} + +@article{DiaconisFreedman1986, + author = {Diaconis, Persi and Freedman, David}, + title = {On the Consistency of {Bayes} Estimates}, + journal = {The Annals of Statistics}, + year = {1986}, + volume = {14}, + number = {1}, + pages = {1--26}, + doi = {10.1214/aos/1176349830} +} + +@article{lucas1967adjustment, + title={Adjustment costs and the theory of supply}, + author={Lucas Jr, Robert E}, + journal={Journal of political economy}, + volume={75}, + number={4, Part 1}, + pages={321--334}, + year={1967}, + publisher={The University of Chicago Press} +} + +@article{Prescott_Visscher_1980, + author = {Prescott, Edward C. and Visscher, Michael}, + title = {Organization Capital}, + journal = {Journal of Political Economy}, + volume = {88}, + number = {3}, + pages = {446--461}, + year = {1980}, + publisher = {University of Chicago Press} +} + +@article{Coase_1937, + author = {Coase, Ronald H.}, + title = {The Nature of the Firm}, + journal = {Economica}, + volume = {4}, + number = {16}, + pages = {386--405}, + year = {1937} +} + +@book{Williamson_1975, + author = {Williamson, Oliver E.}, + title = {Markets and Hierarchies: Analysis and Antitrust Implications}, + publisher = {Free Press}, + address = {New York}, + year = {1975} +} + +@article{Lucas_Prescott_1971, + author = {Lucas, Robert E., Jr. and Prescott, Edward C.}, + title = {Investment under Uncertainty}, + journal = {Econometrica}, + volume = {39}, + number = {5}, + pages = {659--681}, + year = {1971} +} + +@article{Stigler_1958, + author = {Stigler, George J.}, + title = {The Economies of Scale}, + journal = {Journal of Law and Economics}, + volume = {1}, + pages = {54--71}, + year = {1958} +} + +@book{Becker_1975, + author = {Becker, Gary S.}, + title = {Human Capital: A Theoretical and Empirical Analysis, with Special Reference to Education}, + edition = {2nd}, + publisher = {National Bureau of Economic Research}, + address = {New York}, + year = {1975} +} + +@article{Mansfield_1962, + author = {Mansfield, Edwin}, + title = {Entry, {G}ibrat's Law, Innovation, and the Growth of Firms}, + journal = {American Economic Review}, + volume = {52}, + number = {5}, + pages = {1023--1051}, + year = {1962} +} + +@article{Hymer_Pashigian_1962, + author = {Hymer, Stephen and Pashigian, Peter}, + title = {Firm Size and Rate of Growth}, + journal = {Journal of Political Economy}, + volume = {70}, + number = {6}, + pages = {556--569}, + year = {1962} +} + +@article{blackwell1962, + author = {Blackwell, David and Dubins, Lester E.}, + title = {Merging of Opinions with Increasing Information}, + journal = {Annals of Mathematical Statistics}, + year = {1962}, + volume = {33}, + number = {3}, + pages = {882--886}, +} + +@article{aumann1976, + author = {Aumann, Robert J.}, + title = {Agreeing to Disagree}, + journal = {Annals of Statistics}, + year = {1976}, + volume = {4}, + number = {6}, + pages = {1236--1239}, +} + +@book{doob1953, + author = {Doob, Joseph L.}, + title = {Stochastic Processes}, + publisher = {Wiley}, + address = {New York}, + year = {1953}, +} + +@article{kakutani1948, + author = {Kakutani, Shizuo}, + title = {On Equivalence of Infinite Product Measures}, + journal = {Annals of Mathematics}, + year = {1948}, + volume = {49}, + number = {1}, + pages = {214--224}, +} + +@article{girsanov1960, + author = {Girsanov, Igor V.}, + title = {On Transforming a Certain Class of Stochastic Processes + by Absolutely Continuous Substitution of Measures}, + journal = {Theory of Probability and Its Applications}, + year = {1960}, + volume = {5}, + number = {3}, + pages = {285--301}, +} + +@article{novikov1972, + author = {Novikov, Alexander A.}, + title = {On an Identity for Stochastic Integrals}, + journal = {Theory of Probability and Its Applications}, + year = {1972}, + volume = {17}, + number = {4}, + pages = {717--720}, +} + +@inproceedings{blackwell1951, + author = {Blackwell, David}, + title = {Comparison of Experiments}, + booktitle = {Proceedings of the Second {Berkeley} Symposium on Mathematical + Statistics and Probability}, + editor = {Neyman, Jerzy}, + pages = {93--102}, + year = {1951}, + publisher = {University of California Press}, + address = {Berkeley, CA} +} + +@article{blackwell1953, + author = {Blackwell, David}, + title = {Equivalent Comparisons of Experiments}, + journal = {Annals of Mathematical Statistics}, + volume = {24}, + number = {2}, + pages = {265--272}, + year = {1953}, + doi = {10.1214/aoms/1177729032} +} + +@techreport{bonnenblust1949, + author = {Bohnenblust, H. F. and Shapley, Lloyd S. and Sherman, Seymour}, + title = {Reconnaissance in Game Theory}, + institution = {The RAND Corporation}, + number = {RM-208}, + year = {1949}, + address = {Santa Monica, CA}, + note = {Cited for the economic criterion for comparing experiments} +} + +@article{degroot1962, + author = {{DeGroot}, Morris H.}, + title = {Uncertainty, Information, and Sequential Experiments}, + journal = {Annals of Mathematical Statistics}, + volume = {33}, + number = {2}, + pages = {404--419}, + year = {1962}, + doi = {10.1214/aoms/1177704567} +} + +@incollection{kihlstrom1984, + author = {Kihlstrom, Richard E.}, + title = {A {Bayesian} Exposition of {Blackwell}'s Theorem on the + Comparison of Experiments}, + booktitle = {Bayesian Models in Economic Theory}, + editor = {Boyer, Marcel and Kihlstrom, Richard E.}, + series = {Studies in Bayesian Econometrics}, + volume = {5}, + pages = {13--31}, + year = {1984}, + publisher = {North-Holland}, + address = {Amsterdam} +} + +@article{kihlstrom1974a, + author = {Kihlstrom, Richard E.}, + title = {A General Theory of Demand for Information about Product Quality}, + journal = {Journal of Economic Theory}, + volume = {8}, + number = {4}, + pages = {413--439}, + year = {1974}, + doi = {10.1016/0022-0531(74)90019-2} +} + +@inproceedings{hansen2004certainty, + title={Certainty equivalence and model uncertainty}, + author={Hansen, Lars Peter and Sargent, Thomas J}, + booktitle={Conference on Models and Monetary Policy: Research in the Tradition of Dale Henderson, Richard Porter, and Peter Tinsley (http://www. federalreserve. gov/events/conferences/mmp2004/pdf/hansensargent. pdf)}, + year={2004} +} + +@article{evans2005interview, + title={An interview with Thomas J. Sargent}, + author={Evans, George W and Honkapohja, Seppo}, + journal={Macroeconomic Dynamics}, + volume={9}, + number={4}, + pages={561--583}, + year={2005}, + publisher={Cambridge University Press} +} + +@article{hansen2014nobel, + title={Nobel lecture: Uncertainty outside and inside economic models}, + author={Hansen, Lars Peter}, + journal={Journal of Political Economy}, + volume={122}, + number={5}, + pages={945--987}, + year={2014}, + publisher={University of Chicago Press Chicago, IL} +} + +@book{Sargent_Stachurski_2025, + place={Cambridge}, + title={Dynamic Programming: Finite States}, + publisher={Cambridge University Press}, + author={Sargent, Thomas J. and Stachurski, John}, + year={2025} +} + +@book{Sargent_Stachurski_2024, + place={Cambridge}, + series={Structural Analysis in the Social Sciences}, + title={Economic Networks: Theory and Computation}, + publisher={Cambridge University Press}, + author={Sargent, Thomas J. and Stachurski, John}, + year={2024} +} + +@article{slutsky1937, + author = {Slutzky, Eugen}, + title = {The Summation of Random Causes as the Source of Cyclic Processes}, + journal = {Econometrica}, + volume = {5}, + number = {2}, + pages = {105--146}, + year = {1937}, + doi = {10.2307/1907241} +} + +@incollection{frisch33, + author = {Ragnar Frisch}, + booktitle = {Economic Essays in Honour of Gustav Cassel}, + pages = {171--203}, + publisher = {Allen and Unwin}, + title = {Propagation Problems and Impulse Problems in Dynamic Economics}, + year = {1933} +} + +@article{harsanyi1968games, + title={Games with Incomplete Information Played by ``{B}ayesian'' Players, {I}--{III} Part {II}. {B}ayesian Equilibrium Points}, + author={Harsanyi, John C.}, + journal={Management Science}, + volume={14}, + number={5}, + pages={320--334}, + year={1968}, + publisher={INFORMS} +} + +@article{harsanyi1968games3, + title={Games with Incomplete Information Played by ``{B}ayesian'' Players, {I}--{III} Part {III}. {T}he Basic Probability Distribution of the Game}, + author={Harsanyi, John C.}, + journal={Management Science}, + volume={14}, + number={7}, + pages={486--502}, + year={1968}, + publisher={INFORMS} +} + +@article{harsanyi1967games, + title={Games with Incomplete Information Played by ``{B}ayesian'' Players, {I}--{III} Part {I}. {T}he Basic Model}, + author={Harsanyi, John C.}, + journal={Management Science}, + volume={14}, + number={3}, + pages={159--182}, + year={1967}, + publisher={INFORMS} +} + +@article{miller1977risk, + title={Risk, uncertainty, and divergence of opinion}, + author={Miller, Edward M}, + journal={The Journal of finance}, + volume={32}, + number={4}, + pages={1151--1168}, + year={1977}, + publisher={JSTOR} +} + +@article{jeffreys1946invariant, + title={An invariant form for the prior probability in estimation problems}, + author={Jeffreys, Harold}, + journal={Proceedings of the Royal Society of London. Series A. Mathematical and Physical Sciences}, + volume={186}, + number={1007}, + pages={453--461}, + year={1946}, + publisher={The Royal Society London} +} @article{blume2018case, title={A case for incomplete markets}, @@ -60,18 +929,6 @@ @article{alchian1950uncertainty 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}, @@ -81,7 +938,6 @@ @article{mendoza1998international publisher={JSTOR} } - @book{intriligator2002mathematical, title={Mathematical optimization and economic theory}, author={Intriligator, Michael D}, @@ -108,6 +964,14 @@ @book{Burns_2023 address = {New York} } +@book{lucas1981rational, + title={Rational expectations and econometric practice}, + author={Lucas, Robert E and Sargent, Thomas J}, + year={1981}, + publisher={U of Minnesota Press}, + address = {Minneapolis, Minnesota} +} + @article{Orcutt_Winokur_69, issn = {00129682, 14680262}, abstract = {Monte Carlo techniques are used to study the first order autoregressive time series model with unknown level, slope, and error variance. The effect of lagged variables on inference, estimation, and prediction is described, using results from the classical normal linear regression model as a standard. In particular, use of the t and x^2 distributions as approximate sampling distributions is verified for inference concerning the level and residual error variance. Bias in the least squares estimate of the slope is measured, and two bias corrections are evaluated. Least squares chained prediction is studied, and attempts to measure the success of prediction and to improve on the least squares technique are discussed.}, @@ -122,6 +986,16 @@ @article{Orcutt_Winokur_69 year = {1969} } +@incollection{Hurwicz:1962, + address = {Stanford, CA}, + author = {Hurwicz, Leonid}, + booktitle = {Logic, Methodology and Philosophy of Science}, + pages = {232-239}, + publisher = {Stanford University Press}, + title = {On the Structural Form of Interdependent Systems}, + year = {1962} +} + @article{hurwicz1950least, title = {Least squares bias in time series}, author = {Hurwicz, Leonid}, @@ -141,8 +1015,8 @@ @article{wecker1979predicting } @book{Chadhuri_Mukerjee_88, - title = {Randomized Response: Theory and Technique}, - author = {A Chadhuri and R Mukerjee}, + title = {Randomized Response: Theory and Techniques}, + author = {Chaudhuri, A. and Mukerjee, R.}, year = {1988}, publisher = {Marcel Dekker}, address = {New York} @@ -159,7 +1033,6 @@ @article{warner1965randomized publisher = {Taylor \& Francis} } - @article{ljungqvist1993unified, title = {A unified approach to measures of privacy in randomized response models: A utilitarian perspective}, author = {Ljungqvist, Lars}, @@ -180,7 +1053,6 @@ @article{lanke1976degree publisher = {JSTOR} } - @article{leysieffer1976respondent, title = {Respondent jeopardy and optimal designs in randomized response models}, author = {Leysieffer, Frederick W and Warner, Stanley L}, @@ -192,7 +1064,6 @@ @article{leysieffer1976respondent publisher = {Taylor \& Francis} } - @article{anderson1976estimation, title = {Estimation of a proportion through randomized response}, author = {Anderson, Harald}, @@ -224,7 +1095,6 @@ @article{greenberg1977respondent publisher = {Elsevier} } - @article{greenberg1969unrelated, title = {The unrelated question randomized response model: Theoretical framework}, author = {Greenberg, Bernard G and Abul-Ela, Abdel-Latif A and Simmons, Walt R and Horvitz, Daniel G}, @@ -247,8 +1117,6 @@ @article{lanke1975choice publisher = {Taylor \& Francis} } - - @article{schmid2010, title = {Dynamic mode decomposition of numerical and experimental data}, author = {Schmid, Peter J}, @@ -259,7 +1127,6 @@ @article{schmid2010 publisher = {Cambridge University Press} } - @article{apostolakis1990, title = {The concept of probability in safety assessments of technological systems}, author = {Apostolakis, George}, @@ -271,10 +1138,9 @@ @article{apostolakis1990 publisher = {American Association for the Advancement of Science} } - @unpublished{Greenfield_Sargent_1993, - author = {Moses A Greenfield and Thomas J Sargent}, - title = {A Probabilistic Analysis of a Catastrophic Transuranic Waste Hoise Accident at the WIPP}, + author = {Greenfield, Moses A. and Sargent, Thomas J.}, + title = {A Probabilistic Analysis of a Catastrophic Transuranic Waste Hoist Accident at the WIPP}, year = {1993}, month = {June}, note = {Environmental Evaluation Group, Albuquerque, New Mexico}, @@ -291,8 +1157,6 @@ @article{Ardron_2018 year = {2018} } - - @article{Groves_73, author = {Groves, T.}, year = {1973}, @@ -303,12 +1167,12 @@ @article{Groves_73 } @article{Clarke_71, - author = {Clarke, E.}, - year = { 1971}, + author = {Clarke, Edward H.}, + year = {1971}, title = {Multipart pricing of public goods}, journal = {Public Choice}, - volume = {8}, - pages = {19-33} + volume = {11}, + pages = {17--33} } @article{Vickrey_61, @@ -320,9 +1184,6 @@ @article{Vickrey_61 pages = {8-37} } - - - @article{Phelan_Townsend_91, author = {Christopher Phelan and Robert M. Townsend}, title = {{Computing Multi-Period, Information-Constrained Optima}}, @@ -338,7 +1199,6 @@ @article{Phelan_Townsend_91 url = {https://ideas.repec.org/a/oup/restud/v58y1991i5p853-881..html} } - @article{Spear_Srivastava_87, author = {Stephen E. Spear and Sanjay Srivastava}, title = {{On Repeated Moral Hazard with Discounting}}, @@ -354,7 +1214,6 @@ @article{Spear_Srivastava_87 url = {https://ideas.repec.org/a/oup/restud/v54y1987i4p599-617..html} } - @article{tu_Rowley, title = {On dynamic mode decomposition: Theory and applications}, author = {Tu, J. H. and Rowley, C. W. and Luchtenburg, D. M. and Brunton, S. L. and Kutz, J. N.}, @@ -365,26 +1224,20 @@ @article{tu_Rowley pages = {391--421} } - @book{Knight:1921, author = {Knight, Frank H.}, - date-added = {2020-08-20 10:29:34 -0500}, - date-modified = {2020-08-20 11:10:35 -0500}, keywords = {climate,modeling}, publisher = {Houghton Mifflin}, title = {{Risk, Uncertainty, and Profit}}, year = {1921} } - @article{MaccheroniMarinacciRustichini:2006b, author = {Maccheroni, Fabio and Marinacci, Massimo and Rustichini, Aldo}, - date-added = {2021-05-19 08:04:27 -0500}, - date-modified = {2021-05-19 08:04:27 -0500}, journal = {Econometrica}, keywords = {*file-import-17-01-11}, number = {6}, - pages = {1147--1498}, + pages = {1447--1498}, title = {{Ambiguity Aversion, Robustness, and the Variational Representation of Preferences}}, volume = {74}, year = {2006} @@ -392,8 +1245,6 @@ @article{MaccheroniMarinacciRustichini:2006b @article{GilboaSchmeidler:1989, author = {Gilboa, Itzhak and Schmeidler, David}, - date-added = {2020-08-10 09:11:02 -0500}, - date-modified = {2020-08-10 09:11:02 -0500}, journal = {Journal of Mathematical Economics}, keywords = {climate,modeling}, mendeley-groups = {nsfbib}, @@ -405,7 +1256,6 @@ @article{GilboaSchmeidler:1989 year = {1989} } - @book{Sutton_2018, title={Reinforcement learning: An introduction}, author={Sutton, Richard S and Barto, Andrew G}, @@ -428,7 +1278,6 @@ @article{AHS_2003 url = {https://ideas.repec.org/a/tpr/jeurec/v1y2003i1p68-123.html} } - @article{BHS_2009, author = {Barillas, Francisco and Hansen, Lars Peter and Sargent, Thomas J.}, title = {{Doubts or variability?}}, @@ -444,10 +1293,8 @@ @article{BHS_2009 url = {https://ideas.repec.org/a/eee/jetheo/v144y2009i6p2388-2418.html} } - - @article{HST_1999, - author = {Lars Peter Hansen and Thomas J. Sargent and Thomas D. Tallarini}, + author = {Hansen, Lars Peter and Sargent, Thomas J. and Tallarini, Thomas D.}, title = {{Robust Permanent Income and Pricing}}, journal = {Review of Economic Studies}, year = 1999, @@ -461,6 +1308,23 @@ @article{HST_1999 url = {https://ideas.repec.org/a/oup/restud/v66y1999i4p873-907..html} } +@article{simon1956dynamic, + title={Dynamic programming under uncertainty with a quadratic criterion function}, + author={Simon, Herbert A}, + journal={Econometrica, Journal of the Econometric Society}, + pages={74--81}, + year={1956}, + publisher={JSTOR} +} + +@article{theil1957note, + title={A note on certainty equivalence in dynamic planning}, + author={Theil, Henri}, + journal={Econometrica: Journal of the Econometric Society}, + pages={346--349}, + year={1957}, + publisher={JSTOR} +} @article{Jacobson_73, author = {D. H. Jacobson}, @@ -472,9 +1336,6 @@ @article{Jacobson_73 pages = {124-131} } - - - @book{Bucklew_2004, title = {An Introduction to Rare Event Simulation}, author = {James A. Bucklew}, @@ -483,8 +1344,6 @@ @book{Bucklew_2004 year = {2004} } - - @book{Whittle_1990, author = {Peter Whittle}, title = {Risk-Sensitive Optimal Control}, @@ -493,7 +1352,6 @@ @book{Whittle_1990 address = {New York} } - @article{Whittle_1981, author = {Peter Whittle}, year = {1981}, @@ -521,8 +1379,8 @@ @book{Galichon_2016 } @book{DMD_book, - title = {Dynamic mode decomposition: data-driven modeling of complex systems}, - author = {J. N. Kutz and S. L. Brunton and B. W, Brunton and J. L. Proctor}, + title = {Dynamic Mode Decomposition: Data-Driven Modeling of Complex Systems}, + author = {Kutz, J. Nathan and Brunton, Steven L. and Brunton, Bingni W. and Proctor, Joshua L.}, year = {2016}, publisher = {SIAM} } @@ -535,28 +1393,24 @@ @book{DDSE_book address = {New York} } - @book{bertsimas_tsitsiklis1997, - author = {Bertsimas, D. & Tsitsiklis, J. N.}, - title = {{Introduction to linear optimization}}, + author = {Bertsimas, Dimitris and Tsitsiklis, John N.}, + title = {{Introduction to Linear Optimization}}, publisher = {Athena Scientific}, year = {1997} } @book{hu_guo2018, - author = {Hu, Y. & Guo, Y.}, + author = {Hu, Yunquan and Guo, Yaohuang}, title = {{Operations research}}, publisher = {Tsinghua University Press}, edition = {5th}, year = {2018} } - @article{definetti, author = {Bruno de Finetti}, - date-added = {2014-12-26 17:45:57 +0000}, - date-modified = {2014-12-26 17:45:57 +0000}, - journal = {Annales de l'Institute Henri Poincare'}, + journal = {Annales de l'Institut Henri Poincaré}, note = {English translation in Kyburg and Smokler (eds.), {\it Studies in Subjective Probability}, Wiley, New York, 1964}, pages = {1 - 68}, title = {La Prevision: Ses Lois Logiques, Ses Sources Subjectives}, @@ -803,11 +1657,12 @@ @article{benhabib2018skewed year = {2018} } -@article{pareto1896cours, +@book{pareto1896cours, title = {Cours d'{\'e}conomie politique}, - author = {Vilfredo, Pareto}, - journal = {Rouge, Lausanne}, - volume = {2}, + author = {Pareto, Vilfredo}, + publisher = {F. Rouge}, + address = {Lausanne}, + volume = {1}, year = {1896} } @@ -946,14 +1801,6 @@ @article{rosen1994cattle publisher = {The University of Chicago Press} } -@book{HS2013, - title = {Recursive Linear Models of Dynamic Economics}, - author = {Hansen, Lars Peter and Thomas J. Sargent}, - year = {2013}, - publisher = {Princeton University Press}, - address = {Princeton, New Jersey} -} - @article{Reffett1996, title = {Production-based asset pricing in monetary economies with transactions costs}, author = {Reffett, Kevin L}, @@ -967,7 +1814,7 @@ @article{Samuelson1939 title = {Interactions Between the Multiplier Analysis and the Principle of Acceleration}, author = {Samuelson, Paul A.}, - journal = {Review of Economic Studies}, + journal = {The Review of Economics and Statistics}, volume = {21}, number = {2}, year = {1939}, @@ -1002,7 +1849,7 @@ @incollection{Koopmans title = {On the Concept of Optimal Economic Growth}, booktitle = {The Economic Approach to Development Planning}, address = { Chicago}, - publilsher = {Rand McNally}, + publisher = {Rand McNally}, pages = {225-287} } @@ -1094,29 +1941,33 @@ @article{Jovanovic1979 publisher = {The University of Chicago Press} } -@article{Deneckere1992, - title = {Cyclical and chaotic behavior in a dynamic equilibrium model, with implications for fiscal policy}, - author = {Deneckere, Raymond J and Judd, Kenneth L}, - journal = {Cycles and chaos in economic equilibrium}, +@incollection{Deneckere1992, + title = {Cyclical and Chaotic Behavior in a Dynamic Equilibrium Model, with Implications for Fiscal Policy}, + author = {Deneckere, Raymond J. and Judd, Kenneth L.}, + editor = {Benhabib, Jess}, + booktitle = {Cycles and Chaos in Economic Equilibrium}, pages = {308--329}, year = {1992}, - publisher = {Princeton University Press} + publisher = {Princeton University Press}, + address = {Princeton} } @article{Judd1985, title = {On the performance of patents}, author = {Judd, Kenneth L}, journal = {Econometrica}, + volume = {53}, + number = {3}, pages = {567--585}, - year = {1985}, - publisher = {JSTOR} + year = {1985} } @book{Helpman1985, - title = {Market structure and international trade}, - author = {Helpman, Elhanan and Krugman, Paul}, - year = {1985}, - publisher = {MIT Press Cambridge} + title = {Market Structure and Foreign Trade: Increasing Returns, Imperfect Competition, and the International Economy}, + author = {Helpman, Elhanan and Krugman, Paul R.}, + year = {1987}, + publisher = {MIT Press}, + address = {Cambridge, MA} } @article{LettLud2004, @@ -1142,13 +1993,13 @@ @article{LettLud2001 } @article{CampbellShiller88, - author = {John Y. Campbell, Robert J. Shiller}, + author = {Campbell, John Y. and Shiller, Robert J.}, title = {{The Dividend-Price Ratio and Expectations of Future Dividends and Discount Factors}}, journal = {Review of Financial Studies}, year = 1988, volume = {1}, number = {3}, - pages = {195-228} + pages = {195--228} } @book{Friedman98, @@ -1173,16 +2024,6 @@ @article{JuddYeltekinConklin2003 url = {https://ideas.repec.org/a/ecm/emetrp/v71y2003i4p1239-1254.html} } -@book{kreps, - author = {David M. Kreps}, - date-added = {2014-12-26 17:45:57 +0000}, - date-modified = {2014-12-26 17:45:57 +0000}, - publisher = {Westview Press}, - series = {Underground Classics in Economics}, - title = {Notes on the Theory of Choice}, - year = {1988} -} - @book{Kreps88, title = {Notes on the Theory of Choice}, author = {David M. Kreps}, @@ -1192,9 +2033,9 @@ @book{Kreps88 } @book{Bertsekas75, - author = {Dmitri Bertsekas}, + author = {Bertsekas, Dimitri P.}, title = {Dynamic Programming and Stochastic Control}, - year = {1975}, + year = {1976}, publisher = {Academic Press}, address = {New York} } @@ -1217,6 +2058,27 @@ @incollection{Bewley86 address = {Amsterdam}, pages = {27-102} } +@article{jacobson1973optimal, + title={Optimal stochastic linear systems with exponential performance criteria and their relation to deterministic differential games}, + author={Jacobson, David}, + journal={IEEE Transactions on Automatic control}, + volume={18}, + number={2}, + pages={124--131}, + year={1973}, + publisher={IEEE} +} + +@article{hansen1995discounted, + title={Discounted linear exponential quadratic gaussian control}, + author={Hansen, Lars Peter and Sargent, Thomas J}, + journal={IEEE Transactions on Automatic control}, + volume={40}, + number={5}, + pages={968--971}, + year={1995}, + publisher={IEEE} +} @article{Tall2000, author = {Tallarini, Thomas D}, @@ -1229,6 +2091,28 @@ @article{Tall2000 month = {June} } +@article{Hansen_Jagannathan_1991, + author = {Hansen, Lars Peter and Jagannathan, Ravi}, + title = {Implications of Security Market Data for Models of Dynamic Economies}, + journal = {Journal of Political Economy}, + year = {1991}, + volume = {99}, + number = {2}, + pages = {225--262}, + doi = {10.1086/261750} +} + +@article{Weil_1989, + author = {Weil, Philippe}, + title = {The Equity Premium Puzzle and the Risk-Free Rate Puzzle}, + journal = {Journal of Monetary Economics}, + year = {1989}, + volume = {24}, + number = {3}, + pages = {401--421}, + doi = {10.1016/0304-3932(89)90028-7} +} + @book{Lucas1987, title = {Models of business cycles}, author = {Lucas, Robert E}, @@ -1237,35 +2121,6 @@ @book{Lucas1987 publisher = {Oxford Blackwell} } -@article{hansen2009long, - title = {Long-term risk: An operator approach}, - author = {Hansen, Lars Peter and Scheinkman, Jos{\'e} A}, - journal = {Econometrica}, - volume = {77}, - number = {1}, - pages = {177--234}, - year = {2009}, - publisher = {Wiley Online Library} -} - -@article{Hans_Scheink_2009, - author = {Lars Peter Hansen and Jose A. Scheinkman}, - title = {Long-Term Risk: An Operator Approach}, - journal = {Econometrica}, - year = {2009}, - volume = {77}, - number = {1}, - pages = {177-234}, - month = {01} -} - -@book{hansen2008robustness, - title = {Robustness}, - author = {Hansen, Lars Peter and Sargent, Thomas J}, - year = {2008}, - publisher = {Princeton university press} -} - @book{Whittle1963, title = {Prediction and regulation by linear least-square methods}, author = {Whittle, Peter}, @@ -1291,9 +2146,9 @@ @book{Orfanidisoptimum1988 } @book{Athanasios1991, - title = {Probability, random variables, and stochastic processes}, - author = {Athanasios, Papoulis and Pillai, S Unnikrishna}, - publisher = {Mc-Graw Hill}, + title = {Probability, Random Variables, and Stochastic Processes}, + author = {Papoulis, Athanasios}, + publisher = {McGraw-Hill}, year = {1991} } @@ -1323,7 +2178,7 @@ @article{PhelanStacchetti2001 year = 2001, volume = {69}, number = {6}, - pages = {1491-1518}, + pages = {1491--1518}, month = {November} } @@ -1378,6 +2233,16 @@ @article{HarrKreps1978 pages = {323-336} } +@article{Morris1996, + author = {Stephen Morris}, + title = {Speculative Investor Behavior and Learning}, + journal = {The Quarterly Journal of Economics}, + year = {1996}, + volume = {111}, + number = {4}, + pages = {1111-1133} +} + @article{pal2013, title = {Fitted value function iteration with probability one contractions}, author = {P{\'a}l, Jen{\H{o}} and Stachurski, John}, @@ -1458,9 +2323,12 @@ @article{arellano2008default } @article{davis2006flow, - title = {The flow approach to labor markets: New data sources, micro-macro links and the recent downturn}, - author = {Davis, Steven J and Faberman, R Jason and Haltiwanger, John}, + title = {The Flow Approach to Labor Markets: New Data Sources and Micro-Macro Links}, + author = {Davis, Steven J. and Faberman, R. Jason and Haltiwanger, John}, journal = {Journal of Economic Perspectives}, + volume = {20}, + number = {3}, + pages = {3--26}, year = {2006} } @@ -1485,17 +2353,6 @@ @article{AMSS_2002 month = {December} } -@article{aiyagari2002optimal, - title = {Optimal taxation without state-contingent debt}, - author = {Aiyagari, S Rao and Marcet, Albert and Sargent, Thomas J and Sepp{\"a}l{\"a}, Juha}, - journal = {Journal of Political Economy}, - volume = {110}, - number = {6}, - pages = {1220--1254}, - year = {2002}, - publisher = {The University of Chicago Press} -} - @article{Rust1996, title = {Numerical dynamic programming in economics}, author = {Rust, John}, @@ -1506,11 +2363,9 @@ @article{Rust1996 } @book{AKR1990, - author = {Amman, H. M. and Kendrick, D.A. and Rust, J.}, - address = {Burlington, MA}, - publisher = {Elsevier}, + editor = {Amman, H. M. and Kendrick, D. A. and Rust, John}, title = {{Handbook of Computational Economics}}, - year = {1990} + year = {1996} } @book{AndersonMoore2005, @@ -1704,10 +2559,12 @@ @article{Hall1978 } @article{HallMishkin1982, - author = {Hall, Robert E and Mishkin, Frederic S}, - journal = {National Bureau of Economic Research Working Paper Series}, + author = {Hall, Robert E. and Mishkin, Frederic S.}, + journal = {Econometrica}, title = {{The Sensitivity of Consumption to Transitory Income: Estimates from Panel Data on Households}}, - volume = {No. 505}, + volume = {50}, + number = {2}, + pages = {461--481}, year = {1982} } @@ -1782,6 +2639,34 @@ @article{hopenhayn1992entry publisher = {JSTOR} } +@book{bacsar2008h, + title={H-infinity optimal control and related minimax design problems: a dynamic game approach}, + author={Ba{\c{s}}ar, Tamer and Bernhard, Pierre}, + year={2008}, + publisher={Springer Science \& Business Media} +} + +@article{sargent1981interpreting, + title={Interpreting economic time series}, + author={Sargent, Thomas J}, + journal={Journal of political Economy}, + volume={89}, + number={2}, + pages={213--248}, + year={1981}, + publisher={The University of Chicago Press} +} + +@inproceedings{lucas1976econometric, + title={Econometric policy evaluation: A critique}, + author={Lucas, Robert E Jr}, + booktitle={Carnegie-Rochester conference series on public policy}, + volume={1}, + pages={19--46}, + year={1976}, + organization={North-Holland} +} + @article{HopenhaynRogerson1993, author = {Hopenhayn, Hugo A and Rogerson, Richard}, journal = {Journal of Political Economy}, @@ -1857,23 +2742,23 @@ @article{Kuhn2013 } @article{KydlandPrescott1977, - author = {Kydland, Finn E., and Edward C. Prescott}, + author = {Kydland, Finn E. and Prescott, Edward C.}, journal = {Journal of Political Economy}, - pages = {867-896}, + pages = {473--492}, title = {Rules Rather than Discretion: The Inconsistency of Optimal Plans}, - volume = {106}, - number = {5}, + volume = {85}, + number = {3}, year = {1977} } @article{KydlandPrescott1980, - author = {Kydland, Finn E., and Edward C. Prescott}, - journal = {Econometrics}, - pages = {1345-2370}, + author = {Kydland, Finn E. and Prescott, Edward C.}, + journal = {Econometrica}, + pages = {1345--1370}, title = {Time to Build and Aggregate Fluctuations}, volume = {50}, number = {6}, - year = {1980} + year = {1982} } @book{LasotaMackey1994, @@ -1894,7 +2779,7 @@ @book{Ljungqvist2012 @article{Lucas1978, author = {Lucas, Jr., Robert E}, - journal = {Econometrica: Journal of the Econometric Society}, + journal = {Econometrica}, number = {6}, pages = {1429--1445}, title = {{Asset prices in an exchange economy}}, @@ -1902,18 +2787,10 @@ @article{Lucas1978 year = {1978} } -@article{LucasPrescott1971, - author = {Lucas, Jr., Robert E and Prescott, Edward C}, - journal = {Econometrica: Journal of the Econometric Society}, - pages = {659--681}, - title = {{Investment under uncertainty}}, - year = {1971} -} - @article{LucasStokey1983, - author = {Lucas, Jr., Robert E and Stokey, Nancy L}, - journal = {Journal of monetary Economics}, - number = {3}, + author = {Lucas, Jr., Robert E. and Stokey, Nancy L.}, + journal = {Journal of Monetary Economics}, + number = {1}, pages = {55--93}, title = {{Optimal Fiscal and Monetary Policy in an Economy without Capital}}, volume = {12}, @@ -1921,13 +2798,60 @@ @article{LucasStokey1983 } @article{MarcetMarimon1994, - author = {Albert Marcet and Ramon Marimon}, - title = {{Recursive contracts}}, - year = 1994, - institution = {Department of Economics and Business, Universitat Pompeu Fabra}, - type = {Economics Working Papers}, - url = {http://ideas.repec.org/p/upf/upfgen/337.html}, - number = {337} + author = {Marcet, Albert and Marimon, Ramon}, + title = {{Recursive Contracts}}, + journal = {Econometrica}, + volume = {87}, + number = {5}, + pages = {1589--1631}, + year = {2019} +} + +@article{MarcetSargent1989jet, + author = {Marcet, Albert and Sargent, Thomas J.}, + title = {Convergence of Least Squares Learning Mechanisms in + Self-Referential Linear Stochastic Models}, + journal = {Journal of Economic Theory}, + year = {1989}, + volume = {48}, + number = {2}, + pages = {337--368}, + publisher = {Elsevier}, + doi = {10.1016/0022-0531(89)90032-X} +} + +@article{Ljung1977, + author = {Ljung, Lennart}, + title = {Analysis of Recursive Stochastic Algorithms}, + journal = {IEEE Transactions on Automatic Control}, + year = {1977}, + volume = {22}, + number = {4}, + pages = {551--575}, + doi = {10.1109/TAC.1977.1101561} +} + +@article{Evans1985, + author = {Evans, George W.}, + title = {Expectational Stability and the Multiple Equilibria Problem + in Linear Rational Expectations Models}, + journal = {Quarterly Journal of Economics}, + year = {1985}, + volume = {100}, + number = {4}, + pages = {1217--1233}, + doi = {10.2307/1885681} +} + +@article{FourgeaudGourieroux1986, + author = {Fourgeaud, Claude and Gourieroux, Christian and Pradel, Jacqueline}, + title = {Learning Procedures and Convergence to Rationality}, + journal = {Econometrica}, + year = {1986}, + volume = {54}, + number = {4}, + pages = {845--868}, + doi = {10.2307/1912839} } @article{MarcetSargent1989, @@ -2043,12 +2967,13 @@ @article{Pearlman1992 } @article{PearlmanCurrieLevine1986, - author = {Pearlman, J.G. and Currie, D.A. and Levine, P.L.}, - title = {Rational expectations with partial information}, - journal = {Economic Modeling}, + author = {Pearlman, Joseph and Currie, David and Levine, Paul}, + title = {Rational expectations models with partial information}, + journal = {Economic Modelling}, volume = {3}, - pages = {90-105}, - year = {1992} + number = {2}, + pages = {90--105}, + year = {1986} } @book{Popper1992, @@ -2063,9 +2988,9 @@ @article{Prescott1977 author = {Prescott, Edward C.}, year = {1977}, title = {Should Control Theory Be Used for Economic Stabilization?}, - journal = {Journal of Monetary Economics}, + journal = {Carnegie-Rochester Conference Series on Public Policy}, volume = {7}, - pages = {13-38} + pages = {13--38} } @article{Rabault2002, @@ -2101,12 +3026,13 @@ @article{Reiter2009 } @article{Sargent1979, - author = {Sargent, T J}, + author = {Sargent, Thomas J.}, year = {1979}, title = {A Note On Maximum Likelihood Estimation of The Rational Expectations Model of The Term Structure}, journal = {Journal of Monetary Economics}, - volume = {35}, - pages = {245-274} + volume = {5}, + number = {1}, + pages = {133--143} } @book{Sargent1987, @@ -2118,6 +3044,16 @@ @book{Sargent1987 year = {1987} } +@article{Sargent1989, + author = {Sargent, Thomas J}, + title = {Two Models of Measurements and the Investment Accelerator}, + journal = {Journal of Political Economy}, + volume = {97}, + number = {2}, + pages = {251--287}, + year = {1989} +} + @article{SchechtmanEscudero1977, author = {Schechtman, Jack and Escudero, Vera L S}, journal = {Journal of Economic Theory}, @@ -2139,66 +3075,27 @@ @article{Schelling1969 year = {1969} } -@article{bansal2004risks, - title = {Risks for the long run: A potential resolution of asset pricing puzzles}, - author = {Bansal, Ravi and Yaron, Amir}, - journal = {The journal of Finance}, - volume = {59}, - number = {4}, - pages = {1481--1509}, - year = {2004}, - publisher = {Wiley Online Library} -} - @article{Bansal_Yaron_2004, - author = {Ravi Bansal and Amir Yaron}, - title = {{Risks for the Long Run: A Potential Resolution of Asset Pricing Puzzles}}, - journal = {Journal of Finance}, - year = 2004, - volume = {59}, - number = {4}, - pages = {1481-1509}, - month = {08}, - keywords = {}, - doi = {}, - abstract = { We model consumption and dividend growth rates as containing (1) a small long-run predictable component, and (2) fluctuating economic uncertainty (consumption volatility). These dynamics, for which we provide empirical support, in conjunction with Epstein and Zin's (1989) preferences, can explain key asset markets phenomena. In our economy, financial markets dislike economic uncertainty and better long-run growth prospects raise equity prices. The model can justify the equity premium, the risk-free rate, and the volatility of the market return, risk-free rate, and the price-dividend ratio. As in the data, dividend yields predict returns and the volatility of returns is time-varying. Copyright 2004 by The American Finance Association.}, - url = {https://ideas.repec.org/a/bla/jfinan/v59y2004i4p1481-1509.html} + author = {Bansal, Ravi and Yaron, Amir}, + title = {Risks for the Long Run: A Potential Resolution of Asset Pricing Puzzles}, + journal = {Journal of Finance}, + year = {2004}, + volume = {59}, + number = {4}, + pages = {1481--1509}, + doi = {10.1111/j.1540-6261.2004.00670.x} } @article{hansen2008consumption, - title = {Consumption strikes back? Measuring long-run risk}, - author = {Hansen, Lars Peter and Heaton, John C and Li, Nan}, - journal = {Journal of Political economy}, + title = {Consumption Strikes Back? Measuring Long-Run Risk}, + author = {Hansen, Lars Peter and Heaton, John C. and Li, Nan}, + journal = {Journal of Political Economy}, volume = {116}, number = {2}, pages = {260--302}, year = {2008}, - publisher = {The University of Chicago Press} -} - -@article{HHL_2008, - author = {Lars Peter Hansen and John C. Heaton and Nan Li}, - title = {{Consumption Strikes Back? Measuring Long-Run Risk}}, - journal = {Journal of Political Economy}, - year = 2008, - volume = {116}, - number = {2}, - pages = {260-302}, - month = {04}, - keywords = {}, - doi = {}, - abstract = { We characterize and measure a long-term risk-return trade-off for the valuation of cash flows exposed to fluctuations in macroeconomic growth. This trade-off features risk prices of cash flows that are realized far into the future but continue to be reflected in asset values. We apply this analysis to claims on aggregate cash flows and to cash flows from value and growth portfolios by imputing values to the long-run dynamic responses of cash flows to macroeconomic shocks. We explore the sensitivity of our results to features of the economic valuation model and of the model cash flow dynamics. (c) 2008 by The University of Chicago. All rights reserved.}, - url = {https://ideas.repec.org/a/ucp/jpolec/v116y2008i2p260-302.html} -} - -@article{hansen2007beliefs, - title = {Beliefs, doubts and learning: Valuing macroeconomic risk}, - author = {Hansen, Lars Peter}, - journal = {American Economic Review}, - volume = {97}, - number = {2}, - pages = {1--30}, - year = {2007} + publisher = {The University of Chicago Press}, + doi = {10.1086/588200} } @article{Hansen_2007, @@ -2216,16 +3113,6 @@ @article{Hansen_2007 url = {https://ideas.repec.org/a/aea/aecrev/v97y2007i2p1-30.html} } -@article{lucas2003macroeconomic, - title = {Macroeconomic priorities}, - author = {Lucas Jr, Robert E}, - journal = {American economic review}, - volume = {93}, - number = {1}, - pages = {1--14}, - year = {2003} -} - @article{Lucas_2003, author = {Lucas, Jr., Robert E}, title = {{Macroeconomic Priorities}}, @@ -2255,41 +3142,157 @@ @book{StokeyLucas1989 year = {1989} } -@article{STY2004, - author = {Storesletten, Kjetil and Telmer, Christopher I and Yaron, Amir}, - journal = {Journal of Monetary Economics}, - number = {3}, - pages = {609--633}, - title = {{Consumption and risk sharing over the life cycle}}, - volume = {51}, - year = {2004} +@article{STY2004, + author = {Storesletten, Kjetil and Telmer, Christopher I and Yaron, Amir}, + journal = {Journal of Monetary Economics}, + number = {3}, + pages = {609--633}, + title = {{Consumption and risk sharing over the life cycle}}, + volume = {51}, + year = {2004} +} + +@book{Sundaram1996, + author = {Sundaram, R K}, + publisher = {Cambridge University Press}, + title = {{A First Course in Optimization Theory}}, + year = {1996} +} + +@article{Tauchen1986, + author = {Tauchen, George}, + journal = {Economics Letters}, + number = {2}, + pages = {177--181}, + publisher = {Elsevier}, + title = {{Finite state markov-chain approximations to univariate and vector autoregressions}}, + volume = {20}, + year = {1986} +} + +@article{Townsend1983, + author = {Townsend, Robert M.}, + year = {1983}, + title = {Forecasting the Forecasts of Others}, + journal = {Journal of Political Economy}, + volume = {91}, + number = {4}, + pages = {546--588}, + doi = {10.1086/261166} +} + +@article{tobin1992old, + title={An old Keynesian counterattacks}, + author={Tobin, James}, + journal={Eastern Economic Journal}, + volume={18}, + number={4}, + pages={387--400}, + year={1992}, + publisher={JSTOR} +} + +@article{hicks1937mr, + title={Mr. Keynes and the" classics"; a suggested interpretation}, + author={Hicks, John R}, + journal={Econometrica}, + pages={147--159}, + year={1937} +} + +@article{GrossmanShiller1981, + title={The determinants of the variability of stock market prices}, + author={Grossman, Sanford J and Shiller, Robert J}, + journal={American Economic Review}, + volume={71}, + number={2}, + pages={222--227}, + year={1981} +} + +@article{hansen1983stochastic, + title={Stochastic consumption, risk aversion, and the temporal behavior of asset returns}, + author={Hansen, Lars Peter and Singleton, Kenneth J}, + journal={Journal of political economy}, + volume={91}, + number={2}, + pages={249--265}, + year={1983}, + publisher={The University of Chicago Press} +} + +@article{hansen1982generalized, + title={Generalized instrumental variables estimation of nonlinear rational expectations models}, + author={Hansen, Lars Peter and Singleton, Kenneth J}, + journal={Econometrica: Journal of the Econometric Society}, + pages={1269--1286}, + year={1982}, + publisher={JSTOR} +} + +@article{abel1990asset, + title={Asset prices under habit formation and catching up with the Joneses}, + author={Abel, Andrew B}, + journal={American Economic Review}, + volume={80}, + number={2}, + pages={38--42}, + year={1990} +} + +@article{campbell1999force, + title={By force of habit: A consumption-based explanation of aggregate stock market behavior}, + author={Campbell, John Y and Cochrane, John H}, + journal={Journal of Political Economy}, + volume={107}, + number={2}, + pages={205--251}, + year={1999}, + publisher={The University of Chicago Press} +} + +@article{barro2006rare, + title={Rare disasters and asset markets in the twentieth century}, + author={Barro, Robert J}, + journal={The Quarterly Journal of Economics}, + volume={121}, + number={3}, + pages={823--866}, + year={2006}, + publisher={MIT Press} } -@book{Sundaram1996, - author = {Sundaram, R K}, - publisher = {Cambridge University Press}, - title = {{A First Course in Optimization Theory}}, - year = {1996} +@incollection{Brock1982, + title={Asset prices in a production economy}, + author={Brock, William A}, + booktitle={The Economics of Information and Uncertainty}, + editor={McCall, John J.}, + pages={1--46}, + year={1982}, + publisher={University of Chicago Press}, + address={Chicago} } -@article{Tauchen1986, - author = {Tauchen, George}, - journal = {Economics Letters}, - number = {2}, - pages = {177--181}, - publisher = {Elsevier}, - title = {{Finite state markov-chain approximations to univariate and vector autoregressions}}, - volume = {20}, - year = {1986} +@article{PrescottMehra1980, + title={Recursive competitive equilibrium: The case of homogeneous households}, + author={Prescott, Edward C and Mehra, Rajnish}, + journal={Econometrica}, + volume={48}, + number={6}, + pages={1365--1379}, + year={1980}, + publisher={JSTOR} } -@article{Townsend1983, - author = {Townsend, Robert M.}, - year = {1983}, - title = {Forecasting the Forecasts of Others}, - journal = {Journal of Political Economy}, - volume = {91}, - pages = {546-588} +@article{Hansen1982, + title={Large sample properties of generalized method of moments estimators}, + author={Hansen, Lars Peter}, + journal={Econometrica}, + volume={50}, + number={4}, + pages={1029--1054}, + year={1982}, + publisher={JSTOR} } @incollection{Uhlig2001, @@ -2361,26 +3364,6 @@ @techreport{giannoni2010optimal institution = {National Bureau of Economic Research} } -@article{miller1985dynamic, - title = {Dynamic games and the time inconsistency of optimal policy in open economies}, - author = {Miller, Marcus and Salmon, Mark}, - journal = {The Economic Journal}, - pages = {124--137}, - year = {1985}, - publisher = {JSTOR} -} - -@article{pearlman1986rational, - title = {Rational expectations models with partial information}, - author = {Pearlman, Joseph and Currie, David and Levine, Paul}, - journal = {Economic Modelling}, - volume = {3}, - number = {2}, - pages = {90--105}, - year = {1986}, - publisher = {Elsevier} -} - @techreport{backus1986consistency, title = {The consistency of optimal policy in stochastic rational expectations models}, author = {Backus, David and Driffill, John}, @@ -2480,17 +3463,6 @@ @article{kikuchi2018span publisher = {Wiley Online Library} } -@article{coase1937nature, - title = {The nature of the firm}, - author = {Coase, Ronald Harry}, - journal = {economica}, - volume = {4}, - number = {16}, - pages = {386--405}, - year = {1937}, - publisher = {Wiley Online Library} -} - @article{do1999solutions, title = {Solutions for the linear-quadratic control problem of Markov jump linear systems}, author = {Do Val, JBR and Geromel, JC and Costa, OLV}, @@ -2573,12 +3545,14 @@ @book{Hans_Sarg_book_2016 } @article{Neyman_Pearson, - author = {Neyman, J. and Pearson, E. S}, + author = {Neyman, J. and Pearson, E. S.}, year = {1933}, title = {On the problem of the most efficient tests of statistical hypotheses}, - journal = {Phil. Trans. R. Soc. Lond. A. 231 (694–706)}, - pages = {289–337} + journal = {Philosophical Transactions of the Royal Society of London}, + volume = {231}, + number = {694--706}, + pages = {289--337} } @article{ma2020income, @@ -2620,6 +3594,37 @@ @article{diamond1965national publisher = {JSTOR} } +@article{huang1997two, + title = {Two computations to fund social security}, + author = {Huang, He and Imrohoroglu, Selahattin and Sargent, Thomas J}, + journal = {Macroeconomic Dynamics}, + volume = {1}, + number = {1}, + pages = {7--44}, + year = {1997}, + publisher = {Cambridge University Press} +} + +@techreport{faber1982life, + title = {Life Tables for the {United States}: 1900--2050}, + author = {Faber, Joseph F}, + year = {1982}, + number = {Actuarial Study No. 87}, + institution = {Social Security Administration, Office of the Actuary}, + type = {Actuarial Study} +} + +@article{hansen1993cyclical, + title = {The Cyclical and Secular Behaviour of the Labour Input: Comparing Efficiency Units and Hours Worked}, + author = {Hansen, Gary D}, + journal = {Journal of Applied Econometrics}, + volume = {8}, + number = {1}, + pages = {71--80}, + year = {1993}, + publisher = {Wiley} +} + @book{auerbach1987dynamic, title = {Dynamic fiscal policy}, author = {Auerbach, Alan J and Kotlikoff, Laurence J}, @@ -2646,27 +3651,6 @@ @article{fischer2024improving year={2024} } -@article{Lucas_Prescott_1971, - author = {Lucas, Robert E., Jr. and Prescott, Edward C.}, - title = {Investment under Uncertainty}, - journal = {Econometrica}, - volume = {39}, - number = {5}, - pages = {659--681}, - year = {1971} -} - - -@article{Blume_Easley2006, - author = {Blume, Lawrence and Easley, David}, - title = {If You're So Smart, Why Aren't You Rich? {B}elief Selection in Complete and Incomplete Markets}, - journal = {Econometrica}, - volume = {74}, - number = {4}, - pages = {929--966}, - year = {2006} -} - @article{MaCurdy1982, title={The use of time series processes to model the error structure of earnings in a longitudinal data analysis}, author={MaCurdy, Thomas E.}, @@ -2689,3 +3673,469 @@ @article{Meghir2004 publisher={Wiley Online Library} } +@article{Chow1968, + title={The Acceleration Principle and the Nature of Business Cycles}, + author={Chow, Gregory C.}, + journal={The Quarterly Journal of Economics}, + volume={82}, + number={3}, + pages={403--418}, + year={1968}, + month={aug}, + publisher={Oxford University Press} +} + +@article{ChowLevitan1969, + title={Nature of Business Cycles Implicit in a Linear Economic Model}, + author={Chow, Gregory C. and Levitan, Richard E.}, + journal={The Quarterly Journal of Economics}, + volume={83}, + number={3}, + pages={504--517}, + year={1969}, + month={aug}, + publisher={Oxford University Press} +} + +@article{hansen2020twisted, + author = {Hansen, Lars Peter and Sz\H{o}ke, Bal\'{a}zs and Han, Lloyd S. and Sargent, Thomas J.}, + title = {{Twisted probabilities, uncertainty, and prices}}, + journal = {Journal of Econometrics}, + year = 2020, + volume = {216}, + number = {1}, + pages = {151--174} +} + +@unpublished{piazzesi2015trend, + author = {Piazzesi, Monika and Salomao, Juliana and Schneider, Martin}, + title = {{Trend and Cycle in Bond Premia}}, + year = 2015, + note = {Working Paper, Stanford University} +} + +@article{szoke2022estimating, + author = {Sz\H{o}ke, Bal\'{a}zs}, + title = {{Estimating robustness}}, + journal = {Journal of Economic Theory}, + year = 2022, + volume = {199}, + pages = {105225} +} + +@article{AngPiazzesi2003, + author = {Ang, Andrew and Piazzesi, Monika}, + title = {{A no-arbitrage vector autoregression of term structure dynamics with macroeconomic and latent variables}}, + journal = {Journal of Monetary Economics}, + year = 2003, + volume = {50}, + number = {4}, + pages = {745--787} +} + +@article{csiszar1963, + author = {Csisz{\'a}r, Imre}, + title = {{Eine informationstheoretische Ungleichung und ihre Anwendung auf den Beweis der Ergodizit{\"a}t von Markoffschen Ketten}}, + journal = {Magyar Tud. Akad. Mat. Kutat{\'o} Int. K{\"o}zl.}, + year = 1963, + volume = {8}, + pages = {85--108} +} + +@article{morimoto1963, + author = {Morimoto, Tetsuzo}, + title = {{Markov Processes and the H-Theorem}}, + journal = {Journal of the Physical Society of Japan}, + year = 1963, + volume = {18}, + number = {3}, + pages = {328--331}, + doi = {10.1143/JPSJ.18.328} +} + +@article{ali1966, + author = {Ali, S. M. and Silvey, S. D.}, + title = {{A general class of coefficients of divergence of one distribution from another}}, + journal = {Journal of the Royal Statistical Society, Series B}, + year = 1966, + volume = {28}, + number = {1}, + pages = {131--142} +} + +@article{liese2012, + author = {Liese, Friedrich}, + title = {{phi-divergences, sufficiency, Bayes sufficiency, and deficiency}}, + journal = {Kybernetika}, + year = 2012, + volume = {48}, + number = {4}, + pages = {690--713} +} + +@book{chentsov1981, + author = {{\v{C}}encov, Nikolai N.}, + title = {{Statistical Decision Rules and Optimal Inference}}, + series = {Translations of Mathematical Monographs}, + volume = {53}, + publisher = {American Mathematical Society}, + address = {Providence, RI}, + year = 1981 +} + +@book{amari_nagaoka2000, + author = {Amari, Shun-ichi and Nagaoka, Hiroshi}, + title = {{Methods of Information Geometry}}, + series = {Translations of Mathematical Monographs}, + volume = {191}, + publisher = {American Mathematical Society and Oxford University Press}, + address = {Providence, RI}, + year = 2000 +} + +@inproceedings{tishby_pereira_bialek1999, + author = {Tishby, Naftali and Pereira, Fernando C. and Bialek, William}, + title = {{The Information Bottleneck Method}}, + booktitle = {Proceedings of the 37th Annual Allerton Conference on Communication, Control, and Computing}, + year = 1999, + pages = {368--377} +} + +@article{shwartz_ziv_tishby2017, + author = {Shwartz-Ziv, Ravid and Tishby, Naftali}, + title = {{Opening the Black Box of Deep Neural Networks via Information}}, + journal = {arXiv preprint arXiv:1703.00810}, + year = 2017 +} + +@article{kihlstrom_mirman1975, + author = {Kihlstrom, Richard E. and Mirman, Leonard J.}, + title = {Information and Market Equilibrium}, + journal = {The Bell Journal of Economics}, + volume = {6}, + number = {1}, + pages = {357--376}, + year = {1975}, + publisher = {The RAND Corporation} +} + +@article{muth1961, + author = {Muth, John F.}, + title = {Rational Expectations and the Theory of Price Movements}, + journal = {Econometrica}, + volume = {29}, + number = {3}, + pages = {315--335}, + year = {1961} +} + +@article{radner1972, + author = {Radner, Roy}, + title = {Existence of Equilibrium of Plans, Prices, and Price Expectations in a Sequence of Markets}, + journal = {Econometrica}, + volume = {40}, + number = {2}, + pages = {289--303}, + year = {1972} +} + +@article{arrow1964, + author = {Arrow, Kenneth J.}, + title = {The Role of Securities in the Optimal Allocation of Risk-bearing}, + journal = {Review of Economic Studies}, + volume = {31}, + number = {2}, + pages = {91--96}, + year = {1964} +} + +@article{grossman1976, + author = {Grossman, Sanford J.}, + title = {On the Efficiency of Competitive Stock Markets Where Trades Have Diverse Information}, + journal = {Journal of Finance}, + volume = {31}, + number = {2}, + pages = {573--585}, + year = {1976} +} + +@incollection{BrayKreps1987, + author = {Bray, Margaret M. and Kreps, David M.}, + title = {Rational Learning and Rational Expectations}, + booktitle = {Arrow and the Ascent of Modern Economic Theory}, + editor = {Feiwel, George R.}, + publisher = {Palgrave Macmillan}, + address = {London}, + year = {1987}, + pages = {597--625}, + doi = {10.1007/978-1-349-07239-2_19} +} + +@article{Bray1982, + author = {Bray, Margaret M.}, + title = {Learning, Estimation, and the Stability of Rational Expectations}, + journal = {Journal of Economic Theory}, + year = {1982}, + volume = {26}, + number = {2}, + pages = {318--339}, + doi = {10.1016/0022-0531(82)90007-2} +} + +@article{BraySavin1986, + author = {Bray, Margaret M. and Savin, N. E.}, + title = {Rational Expectations Equilibria, Learning and Model Specification}, + journal = {Econometrica}, + year = {1986}, + volume = {54}, + number = {5}, + pages = {1129--1160}, + doi = {10.2307/1912325} +} + +@article{Radner1979, + author = {Radner, Roy}, + title = {Rational Expectations Equilibrium: Generic Existence and the Information Revealed by Prices}, + journal = {Econometrica}, + year = {1979}, + volume = {47}, + number = {3}, + pages = {655--678}, + doi = {10.2307/1910413} +} + +@article{Jordan1982, + author = {Jordan, James S.}, + title = {The Generic Existence of Rational Expectations Equilibrium in the Higher Dimensional Case}, + journal = {Journal of Economic Theory}, + year = {1982}, + volume = {26}, + number = {2}, + pages = {224--243}, + doi = {10.1016/0022-0531(82)90002-3} +} + +@article{Jordan1982b, + author = {Jordan, James S.}, + title = {Admissible Market Data Structures: A Complete Characterization}, + journal = {Journal of Economic Theory}, + year = {1982}, + volume = {28}, + number = {1}, + pages = {19--31}, + doi = {10.1016/0022-0531(82)90089-8} +} + +@article{Admati1985, + author = {Admati, Anat R.}, + title = {A Noisy Rational Expectations Equilibrium for Multi-Asset Securities Markets}, + journal = {Econometrica}, + year = {1985}, + volume = {53}, + number = {3}, + pages = {629--657}, + doi = {10.2307/1911659} +} + +@article{GrossmanStiglitz1980, + author = {Grossman, Sanford J. and Stiglitz, Joseph E.}, + title = {On the Impossibility of Informationally Efficient Markets}, + journal = {American Economic Review}, + year = {1980}, + volume = {70}, + number = {3}, + pages = {393--408} +} + +@article{AndersonSonnenschein1982, + author = {Anderson, Robert M. and Sonnenschein, Hugo}, + title = {On the Existence of Rational Expectations Equilibrium}, + journal = {Journal of Economic Theory}, + year = {1982}, + volume = {26}, + number = {2}, + pages = {261--278}, + doi = {10.1016/0022-0531(82)90004-7} +} + +@article{BlumeEasley1982, + author = {Blume, Lawrence E. and Easley, David}, + title = {Learning to be Rational}, + journal = {Journal of Economic Theory}, + year = {1982}, + volume = {26}, + number = {2}, + pages = {340--351}, + doi = {10.1016/0022-0531(82)90008-4} +} + +@article{Frydman1982, + author = {Frydman, Roman}, + title = {Towards an Understanding of Market Processes: Individual Expectations, Learning, and Convergence to Rational Expectations Equilibrium}, + journal = {American Economic Review}, + year = {1982}, + volume = {72}, + number = {4}, + pages = {652--668} +} + +@article{Grossman1981, + author = {Grossman, Sanford J.}, + title = {An Introduction to the Theory of Rational Expectations under Asymmetric Information}, + journal = {Review of Economic Studies}, + year = {1981}, + volume = {48}, + number = {4}, + pages = {541--559}, + doi = {10.2307/2297195} +} + +@techreport{ArrowGreen1973, + author = {Arrow, Kenneth J. and Green, Jerry R.}, + title = {Notes on Expectations Equilibria in Bayesian Settings}, + year = {1973}, + type = {Working Paper}, + number = {33}, + institution = {Institute for Mathematical Studies in the Social Sciences, Stanford University} +} + +@article{Kreps1977, + author = {Kreps, David M.}, + title = {A Note on Fulfilled Expectations Equilibria}, + journal = {Journal of Economic Theory}, + year = {1977}, + volume = {14}, + number = {1}, + pages = {32--43}, + doi = {10.1016/0022-0531(77)90083-7} +} + +@article{Breeden1979, + author = {Breeden, Douglas T.}, + title = {An Intertemporal Asset Pricing Model with Stochastic + Consumption and Investment Opportunities}, + journal = {Journal of Financial Economics}, + year = {1979}, + volume = {7}, + number = {3}, + pages = {265--296}, + doi = {10.1016/0304-405X(79)90016-3} +} + +@book{Nummelin_1984, + author = {Nummelin, Esa}, + title = {General Irreducible {Markov} Chains and Non-Negative + Operators}, + series = {Cambridge Tracts in Mathematics}, + number = {83}, + publisher = {Cambridge University Press}, + address = {Cambridge}, + year = {1984}, + doi = {10.1017/CBO9780511526237} +} + +@article{friedman1968role, + author = {Friedman, Milton}, + title = {The Role of Monetary Policy}, + journal = {American Economic Review}, + volume = {58}, + number = {1}, + pages = {1--17}, + year = {1968} +} + +@article{nelson_plosser1982, + author = {Nelson, Charles R. and Plosser, Charles I.}, + title = {Trends and Random Walks in Macroeconomic Time Series: + Some Evidence and Implications}, + journal = {Journal of Monetary Economics}, + volume = {10}, + number = {2}, + pages = {139--162}, + year = {1982} +} + +@incollection{blanchard_summers1986, + author = {Blanchard, Olivier J. and Summers, Lawrence H.}, + title = {Hysteresis and the {European} Unemployment Problem}, + booktitle = {NBER Macroeconomics Annual 1986, Volume 1}, + editor = {Fischer, Stanley}, + publisher = {MIT Press}, + pages = {15--78}, + year = {1986} +} + +@article{roed1997hysteresis, + author = {Røed, Knut}, + title = {Hysteresis in Unemployment}, + journal = {Journal of Economic Surveys}, + volume = {11}, + number = {4}, + pages = {389--418}, + year = {1997} +} + +@article{kapetanios_shin_snell2003, + author = {Kapetanios, George and Shin, Yongcheol and Snell, Andy}, + title = {Testing for a Unit Root in the Nonlinear {STAR} Framework}, + journal = {Journal of Econometrics}, + volume = {112}, + number = {2}, + pages = {359--379}, + year = {2003} +} + +@article{EpsteinWang1994, + author = {Epstein, Larry G. and Wang, Tan}, + title = {{Intertemporal Asset Pricing under Knightian Uncertainty}}, + journal = {Econometrica}, + volume = {62}, + number = {2}, + pages = {283--322}, + year = {1994} +} + +@article{Campbell1987, + author = {Campbell, John Y.}, + title = {{Does Saving Anticipate Declining Labor Income? An Alternative Test of the Permanent Income Hypothesis}}, + journal = {Econometrica}, + volume = {55}, + number = {6}, + pages = {1249--1273}, + year = {1987} +} + +@article{GilboaSchmeidler:1989, + author = {Gilboa, Itzhak and Schmeidler, David}, + date-added = {2020-08-10 09:11:02 -0500}, + date-modified = {2020-08-10 09:11:02 -0500}, + journal = {Journal of Mathematical Economics}, + keywords = {climate,modeling}, + mendeley-groups = {nsfbib}, + month = {apr}, + number = {2}, + pages = {141--153}, + title = {{Maxmin Expected Utility with Non-Unique Prior}}, + volume = {18}, + year = {1989} +} + +@article{Whittle_1981, + author = {Peter Whittle}, + year = {1981}, + title = {Risk-Sensitive Linear/Quadratic/Gaussian Control}, + journal = {Advances in Applied Probability}, + volume = {13}, + number = {4}, + pages = {764-777} +} + +@book{Whittle_1990, + author = {Peter Whittle}, + title = {Risk-Sensitive Optimal Control}, + year = {1990}, + publisher = {Wiley}, + address = {New York} +} + + diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 0e950b5..6fce846 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -42,8 +42,12 @@ parts: - file: wald_friedman_2 - file: exchangeable - file: likelihood_bayes + - file: blackwell_kihlstrom + - file: information_market_equilibrium - file: mix_model - file: navy_captain + - file: merging_of_opinions + - file: survival_recursive_preferences - caption: 线性规划 numbered: true chapters: @@ -56,21 +60,28 @@ parts: - file: inventory_dynamics - file: linear_models - file: samuelson + - file: chow_business_cycles - file: kesten_processes - file: wealth_dynamics - file: kalman - file: kalman_2 + - file: kalman_filter_var + - file: organization_capital + - file: measurement_models - caption: 搜索 numbered: true chapters: - file: mccall_model - file: mccall_model_with_separation + - file: mccall_model_with_sep_markov - file: mccall_fitted_vfi - file: mccall_persist_trans - file: career - file: jv - file: mccall_q - file: odu + - file: inventory_q + - file: rs_inventory_q - caption: 消费、储蓄与资本 numbered: true chapters: @@ -82,7 +93,13 @@ parts: - file: os - file: os_numerical - file: os_stochastic + - file: os_time_iter + - file: os_egm + - file: os_egm_jax + - file: ifp_discrete + - file: ifp_opi - file: ifp_egm + - file: ifp_egm_transient_shocks - file: ifp_advanced - caption: LQ控制 numbered: true @@ -92,29 +109,49 @@ parts: - file: cross_product_trick - file: perm_income - file: perm_income_cons + - file: robust_permanent_income + - file: theil_1 + - file: theil_2 + - file: lq_permanent_income + - file: lq_bewley_complete_markets + - file: lq_robust_smoothing - file: lq_inventories - caption: 多主体模型 numbered: true chapters: - file: lake_model + - file: endogenous_lake - file: rational_expectations - file: re_with_feedback - file: markov_perf - file: uncertainty_traps - file: aiyagari + - file: aiyagari_egm - file: ak_aiyagari + - file: two_computation - caption: 资产定价与金融 numbered: true chapters: - file: markov_asset + - file: hansen_singleton_1983 + - file: hansen_singleton_1982 - file: ge_arrow - file: harrison_kreps + - file: morris_learn + - file: rational_learning_re + - file: ls_learning + - file: affine_risk_prices + - file: ross_recovery + - file: long_run_risk_operator + - file: misspecified_recovery - caption: 数据与实证 numbered: true chapters: - file: pandas_panel - file: ols - file: mle + - file: unemployment_linear + - file: unemployment_shocks - caption: 拍卖 numbered: true chapters: diff --git a/lectures/affine_risk_prices.md b/lectures/affine_risk_prices.md new file mode 100644 index 0000000..a05b3e4 --- /dev/null +++ b/lectures/affine_risk_prices.md @@ -0,0 +1,1407 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 资产价格的仿射模型 + headings: + Overview: 概述 + The model: 模型 + The model::State dynamics and short rate: 状态动态与短期利率 + The model::Properties of the SDF: SDF 的性质 + Pricing risky assets: 对风险资产定价 + Pricing risky assets::Lognormal returns: 对数正态回报 + Pricing risky assets::Expected excess returns: 预期超额回报 + Affine term structure of yields: 收益率的仿射期限结构 + Affine term structure of yields::Bond prices: 债券价格 + Affine term structure of yields::Exponential affine prices: 指数仿射价格 + Affine term structure of yields::Yields: 收益率 + Affine term structure of yields::A one-factor Gaussian example: 单因子高斯示例 + Affine term structure of yields::Yield curve shapes: 收益率曲线形状 + Affine term structure of yields::A two-factor model: 双因子模型 + Risk premiums: 风险溢价 + Risk-neutral probabilities: 风险中性概率 + Risk-neutral probabilities::Change of measure: 测度变换 + Risk-neutral probabilities::Asset pricing in a nutshell: 资产定价简述 + Risk-neutral probabilities::Verification via risk-neutral pricing: 通过风险中性定价进行验证 + Distorted beliefs: 扭曲信念 + Distorted beliefs::The subjective measure: 主观测度 + Distorted beliefs::Pricing under distorted beliefs: 扭曲信念下的定价 + Concluding remarks: 结束语 +--- + +(affine_risk_prices)= +```{raw} html +
+ + QuantEcon + +
+``` + +# 资产价格的仿射模型 + +## 概述 + +本讲座描述了一类随机贴现因子的**仿射**或**指数二次型**模型,这类模型在实证金融中已被广泛使用。 + +这些模型在 {cite:t}`Ljungqvist2012` 的第 15 章中有所介绍。 + +这里讨论的模型采用了与 {cite:t}`hansen1983stochastic` 中时间可分的 CRRA 随机贴现因子不同的方法,后者在我们的 {doc}`配套讲座 ` 中进行了研究。 + +CRRA 随机贴现因子为 + +$$ +m_{t+1} = \exp\left(-r_t - \frac{1}{2}\sigma_c^2 \gamma^2 - \gamma\sigma_c\varepsilon_{t+1}\right) +$$ + +其中 $r_t = \rho + \gamma\mu - \frac{1}{2}\sigma_c^2\gamma^2$。 + +该模型断言,对总消费增长的随机部分 $\sigma_c\varepsilon_{t+1}$ 的暴露是*唯一*被定价的风险,是各资产预期回报之间差异的唯一来源。 + +这一设定的实证困难(股权溢价之谜、无风险利率之谜,以及 {doc}`advanced:doubts_or_variability` 中讨论的 Hansen-Jagannathan 边界)促使人们采用本讲座所描述的替代方法。 + +直白地说,本讲座将研究的模型宣告了卢卡斯资产定价模型的随机贴现因子的失败。 + +**仿射模型**保持 $\mathbb{E}(m_{t+1}R_{j,t+1}) = 1$,但将随机贴现因子与消费风险*分离*,从而也在很大程度上与宏观经济学分离。 + +相反,它 + +* 为 $m_{t+1}$ 指定了一个解析上易于处理的随机过程,并 +* 利用应用于 $N$ 种资产的 $\mathbb{E}(m_{t+1}R_{j,t+1}) = 1$ 的过度识别约束,让数据揭示风险及其价格。 + +```{note} +包括 {cite}`Bansal_Yaron_2004` 和 {cite}`hansen2008consumption` 在内的研究者一直不太愿意放弃基于消费的随机贴现因子模型。 +``` + +我们研究的关键应用包括: + +1. *对风险资产定价*:风险价格和暴露如何决定超额回报。 +2. *仿射期限结构模型*:债券收益率作为状态向量的仿射函数({cite:t}`AngPiazzesi2003`)。 +3. *风险中性概率*:定价方程的一种测度变换表示。 +4. *扭曲信念*:当行为主体持有系统性偏差的预测时,重新解释风险价格估计({cite:t}`piazzesi2015trend`);另见 {doc}`advanced:risk_aversion_or_mistaken_beliefs`。 + +我们从以下导入开始: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from collections import namedtuple +from numpy.linalg import eigvals +``` + +## 模型 + +### 状态动态与短期利率 + +该模型有两个部分。 + +*第一部分*是一个向量自回归,描述了经济状态和短期利率的演变: + +```{math} +:label: eq_var + +z_{t+1} = \mu + \phi z_t + C\varepsilon_{t+1} +``` + +```{math} +:label: eq_shortrate + +r_t = \delta_0 + \delta_1^\top z_t +``` + +这里 + +* $\phi$ 是一个稳定的 $m \times m$ 矩阵, +* $C$ 是一个 $m \times m$ 矩阵, +* $\varepsilon_{t+1} \sim \mathcal{N}(0, I)$ 是一个独立同分布的 $m \times 1$ 随机向量, +* $z_t$ 是一个 $m \times 1$ 状态向量。 + +方程 {eq}`eq_shortrate` 表明,**短期利率** $r_t$,即单期无风险债权的净收益率,是状态 $z_t$ 的仿射函数。 + +*第二部分*是一个**风险价格**向量 $\lambda_t$ 及其相关的随机贴现因子 $m_{t+1}$: + +```{math} +:label: eq_riskprices + +\lambda_t = \lambda_0 + \lambda_z z_t +``` + +```{math} +:label: eq_sdf + +\log(m_{t+1}) = -r_t - \frac{1}{2}\lambda_t^\top\lambda_t - \lambda_t^\top\varepsilon_{t+1} +``` + +这里 $\lambda_0$ 是 $m \times 1$,$\lambda_z$ 是 $m \times m$。 + +$\lambda_t$ 中乘以风险 $\varepsilon_{t+1}$ 相应分量的各项被称为**风险价格**,因为它们决定了对每个风险分量的暴露如何影响预期回报(如我们下面所示)。 + +由于 $\lambda_t$ 是 $z_t$ 的仿射函数,随机贴现因子 $m_{t+1}$ 是状态 $z_t$ 的**指数二次型**。 + +我们按如下方式实现模型的各部分。 + +```{code-cell} ipython3 +AffineModel = namedtuple('AffineModel', + ('μ', 'φ', 'C', 'δ_0', 'δ_1', 'λ_0', 'λ_z', 'm', 'φ_rn', 'μ_rn')) + +def create_affine_model(μ, φ, C, δ_0, δ_1, λ_0, λ_z): + """创建一个仿射期限结构模型。""" + μ = np.asarray(μ, float) + φ = np.asarray(φ, float) + C = np.asarray(C, float) + δ_1 = np.asarray(δ_1, float) + λ_0, λ_z = np.asarray(λ_0, float), np.asarray(λ_z, float) + return AffineModel(μ=μ, φ=φ, C=C, δ_0=float(δ_0), δ_1=δ_1, + λ_0=λ_0, λ_z=λ_z, m=len(μ), + φ_rn=φ - C @ λ_z, μ_rn=μ - C @ λ_0) + +def simulate(model, z0, T, rng=None): + """在 T 期内模拟 z_{t+1} = μ + φ z_t + C ε_{t+1}。""" + if rng is None: + rng = np.random.default_rng(42) + Z = np.zeros((T + 1, model.m)) + Z[0] = z0 + for t in range(T): + ε = rng.standard_normal(model.m) + Z[t + 1] = model.μ + model.φ @ Z[t] + model.C @ ε + return Z + +def short_rate(model, z): + """计算 r_t = δ_0 + δ_1^⊤ z_t。""" + return model.δ_0 + model.δ_1 @ z + +def risk_prices(model, z): + """计算 λ_t = λ_0 + λ_z z_t。""" + return model.λ_0 + model.λ_z @ z +``` + +### SDF 的性质 + +由于 $\lambda_t^\top\varepsilon_{t+1}$ 是条件正态的,因此有 + +$$ +\mathbb{E}_t(m_{t+1}) = \exp(-r_t) +$$ + +以及 + +$$ +\text{std}_t(m_{t+1}) \approx \| \lambda_t \|. +$$ + +```{exercise} +:label: arp_ex1 + +证明 {eq}`eq_sdf` 中定义的 SDF 满足 + +$$ +\mathbb{E}_t(m_{t+1}) = \exp(-r_t) +$$ + +以及 + +$$ +\text{std}_t(m_{t+1}) \approx \| \lambda_t \| +$$ + +其中 $\| \lambda_t \| = \sqrt{\lambda_t^\top\lambda_t}$ 表示风险价格向量的欧几里得范数。 + +对于第二个结果,使用对数正态方差公式以及对小的 $x$ 和 $r_t$ 的近似 $\exp(x) \approx 1 + x$ 和 $\exp(-r_t) \approx 1$。 +``` + +```{solution-start} arp_ex1 +:class: dropdown +``` + +由 {eq}`eq_sdf`,我们有 + +$$ +m_{t+1} = \exp\left(-r_t - \frac{1}{2}\lambda_t^\top\lambda_t - \lambda_t^\top\varepsilon_{t+1}\right) +$$ + + +由于 $-\lambda_t^\top \varepsilon_{t+1} \sim \mathcal{N}(0, \lambda_t^\top \lambda_t)$,我们有 +$\mathbb{E}_t[\exp(-\lambda_t^\top \varepsilon_{t+1})] = \exp\left(\frac{1}{2}\lambda_t^\top \lambda_t\right)$。 + +因此, + +$$ +\mathbb{E}_t(m_{t+1}) = \exp(-r_t - \frac{1}{2}\lambda_t^\top\lambda_t) \mathbb{E}_t[\exp(-\lambda_t^\top\varepsilon_{t+1})] = \exp(-r_t) +$$ + +$m_{t+1}$ 是条件对数正态的,其中 $\log m_{t+1} \sim \mathcal{N}(-r_t-\frac{1}{2}\lambda_t^\top\lambda_t, \lambda_t^\top \lambda_t)$。 + +由对数正态方差公式 +$\text{Var}(\exp(X)) = (\exp(\sigma^2) - 1) \exp(2\mu + \sigma^2)$(对于 $X \sim \mathcal{N}(\mu, \sigma^2)$),我们有 + +$$ +\begin{aligned} +\text{Var}_t(m_{t+1}) &= (\exp(\lambda_t^\top \lambda_t) - 1) \exp(-2r_t) \\ +&\approx \lambda_t^\top \lambda_t \exp(-2r_t) +\end{aligned} +$$ + +这是根据对小的 $x$ 的近似 $\exp(x) \approx 1 + x$ 得到的。 + +因此, + +$$ +\text{std}_t(m_{t+1}) \approx \| \lambda_t \| \exp(-r_t) +$$ + +对于小的 $r_t$,有 $\exp(-r_t) \approx 1$,我们得到 + +$$ +\text{std}_t(m_{t+1}) \approx \| \lambda_t \| +$$ + +```{solution-end} +``` + +第一个方程确认 $r_t$ 是无风险单期债券的净收益率。 + +这就是为什么在指数二次型文献中 $r_t$ 被称为**短期利率**。 + +第二个方程表明,SDF 的条件标准差近似等于风险价格向量的大小,这是对整体**市场风险价格**的一种度量。 + +## 对风险资产定价 + +### 对数正态回报 + +考虑一种风险资产 $j$,其总回报具有对数正态的条件分布: + +```{math} +:label: eq_return + +R_{j,t+1} = \exp\left(\nu_t(j) - \frac{1}{2}\alpha_t(j)^\top\alpha_t(j) + \alpha_t(j)^\top\varepsilon_{t+1}\right) +``` + +其中**暴露向量** + +```{math} +:label: eq_exposure + +\alpha_t(j) = \alpha_0(j) + \alpha_z(j)\, z_t +``` + +这里 $\alpha_0(j)$ 是 $m \times 1$,$\alpha_z(j)$ 是 $m \times m$。 + +$\alpha_t(j)$ 的各分量表示 $\log R_{j,t+1}$ 对风险向量 $\varepsilon_{t+1}$ 相应分量的**暴露**。 + +设定 {eq}`eq_return` 蕴含 $\mathbb{E}_t R_{j,t+1} = \exp(\nu_t(j))$, +因此 $\nu_t(j)$ 是预期总回报的对数。 + +### 预期超额回报 + +将定价方程 $\mathbb{E}_t(m_{t+1}R_{j,t+1}) = 1$ 与对数正态随机变量的均值公式一起应用,得到 + +```{math} +:label: eq_excess + +\nu_t(j) = r_t + \alpha_t(j)^\top\lambda_t +``` + +```{exercise} +:label: arp_ex2 + +使用 SDF {eq}`eq_sdf` 和回报设定 {eq}`eq_return`,推导预期超额回报公式 {eq}`eq_excess`: + +$$ +\nu_t(j) = r_t + \alpha_t(j)^\top\lambda_t +$$ + +*提示:* 从计算 $\log(m_{t+1} R_{j,t+1})$ 开始,识别其条件分布,并应用定价条件 $\mathbb{E}_t(m_{t+1}R_{j,t+1}) = 1$。 +``` + +```{solution-start} arp_ex2 +:class: dropdown +``` + +结合 {eq}`eq_sdf` 和 {eq}`eq_return`,我们得到 + +$$ +\log(m_{t+1} R_{j,t+1}) = -r_t + \nu_t(j) - \frac{1}{2}\lambda_t^\top\lambda_t - \frac{1}{2}\alpha_t(j)^\top\alpha_t(j) + (\alpha_t(j) - \lambda_t)^\top\varepsilon_{t+1} +$$ + +这是条件正态的,均值为 $\mu = -r_t + \nu_t(j) - \frac{1}{2}\lambda_t^\top\lambda_t - \frac{1}{2}\alpha_t(j)^\top\alpha_t(j)$,方差为 $\sigma^2 = (\alpha_t(j) - \lambda_t)^\top(\alpha_t(j) - \lambda_t)$。 + +由于对于 $X \sim \mathcal{N}(\mu, \sigma^2)$ 有 $\mathbb{E}_t[\exp(X)] = \exp(\mu + \frac{1}{2}\sigma^2)$,定价条件 $\mathbb{E}_t(m_{t+1}R_{j,t+1}) = 1$ 要求 $\mu + \frac{1}{2}\sigma^2 = 0$。 + +展开 $\frac{1}{2}\sigma^2 = \frac{1}{2}\alpha_t(j)^\top\alpha_t(j) - \alpha_t(j)^\top\lambda_t + \frac{1}{2}\lambda_t^\top\lambda_t$ 并加到 $\mu$ 上,$\frac{1}{2}\lambda_t^\top\lambda_t$ 和 $\frac{1}{2}\alpha_t(j)^\top\alpha_t(j)$ 项相互抵消,剩下 + +$$ +-r_t + \nu_t(j) - \alpha_t(j)^\top\lambda_t = 0 +$$ + +这给出了 {eq}`eq_excess`。 + +```{solution-end} +``` + +这是一个核心结果。 + +它表明: + +> 资产 $j$ 上的对数预期总回报等于短期利率加上资产暴露向量 $\alpha_t(j)$ 与风险价格向量 $\lambda_t$ 的内积。 + +$\lambda_t$ 的每个分量对 $\varepsilon_{t+1}$ 的相应分量进行定价。 + +对具有较大风险价格的风险分量有大量载荷的资产会获得相应较高的预期回报。 + +## 收益率的仿射期限结构 + +最重要的应用之一是 {cite:t}`AngPiazzesi2003` 研究的**仿射期限结构模型**。 + +### 债券价格 + +设 $p_t(n)$ 为在时刻 $t$ 到期于 $t + n$ 的无风险纯贴现债券(支付一单位消费)的价格。 + +从 $t$ 到 $t+1$ 持有一个 $(n+1)$ 期债券的单期总回报为 + +$$ +R_{t+1} = \frac{p_{t+1}(n)}{p_t(n+1)} +$$ + +定价方程 $\mathbb{E}_t(m_{t+1}R_{t+1}) = 1$ 蕴含 + +```{math} +:label: eq_bondrecur + +p_t(n+1) = \mathbb{E}_t\bigl(m_{t+1}\,p_{t+1}(n)\bigr) +``` + +初始条件为 + +$$ +p_t(1) = \mathbb{E}_t(m_{t+1}) = \exp(-r_t) = \exp(-\delta_0 - \delta_1^\top z_t). +$$ + +### 指数仿射价格 + +递归 {eq}`eq_bondrecur` 有一个**指数仿射**解: + +```{math} +:label: eq_bondprice + +p_t(n) = \exp \bigl(\bar A_n + \bar B_n^\top z_t\bigr) +``` + +其中标量 $\bar A_n$ 和 $m \times 1$ 向量 $\bar B_n$ 满足**黎卡提差分方程** + +```{math} +:label: eq_riccati_a + +\bar A_{n+1} = \bar A_n + \bar B_n^\top(\mu - C\lambda_0) + \frac{1}{2}\bar B_n^\top CC^\top\bar B_n - \delta_0 +``` + +```{math} +:label: eq_riccati_b + +\bar B_{n+1}^\top = \bar B_n^\top(\phi - C\lambda_z) - \delta_1^\top +``` + +初始条件为 $\bar A_1 = -\delta_0$ 和 $\bar B_1 = -\delta_1$。 + +```{exercise} +:label: arp_ex3 + +通过将猜想的债券价格 {eq}`eq_bondprice` 代入定价递归 {eq}`eq_bondrecur` 并匹配系数,推导黎卡提差分方程 {eq}`eq_riccati_a` 和 {eq}`eq_riccati_b`。 + +*提示:* 将 $p_{t+1}(n) = \exp(\bar A_n + \bar B_n^\top z_{t+1})$ 和 +{eq}`eq_sdf` 中的 $\log m_{t+1}$ 代入 {eq}`eq_bondrecur`。 + +使用状态动态 {eq}`eq_var` 将 $z_{t+1}$ 用 $z_t$ 和 +$\varepsilon_{t+1}$ 表示,然后使用对数正态矩生成函数求条件期望。 +``` + +```{solution-start} arp_ex3 +:class: dropdown +``` + +我们要证明,如果 $p_t(n) = \exp(\bar A_n + \bar B_n^\top z_t)$, +那么递归 $p_t(n+1) = \mathbb{E}_t(m_{t+1}\, p_{t+1}(n))$ 得到 +$p_t(n+1) = \exp(\bar A_{n+1} + \bar B_{n+1}^\top z_t)$,其中 +$\bar A_{n+1}$ 和 $\bar B_{n+1}$ 由 {eq}`eq_riccati_a` 和 +{eq}`eq_riccati_b` 给出。 + + +由 {eq}`eq_sdf` 和 {eq}`eq_bondprice`, + +$$ +\log(m_{t+1}\, p_{t+1}(n)) = -r_t - \frac{1}{2}\lambda_t^\top\lambda_t - \lambda_t^\top\varepsilon_{t+1} + \bar A_n + \bar B_n^\top z_{t+1} +$$ + +代入 {eq}`eq_var` 中的 $z_{t+1} = \mu + \phi z_t + C\varepsilon_{t+1}$ +和 {eq}`eq_shortrate` 中的 $r_t = \delta_0 + \delta_1^\top z_t$,得到 + +$$ +\log(m_{t+1}\, p_{t+1}(n)) = \bar A_n + \bar B_n^\top\mu - \delta_0 + (\bar B_n^\top\phi - \delta_1^\top) z_t - \frac{1}{2}\lambda_t^\top\lambda_t + (\bar B_n^\top C - \lambda_t^\top)\varepsilon_{t+1} +$$ + + +由于 $\varepsilon_{t+1} \sim \mathcal{N}(0, I)$,将指数写成 $a + b^\top\varepsilon_{t+1}$ 的形式,其中 +$b = C^\top \bar B_n - \lambda_t$,我们有 + +$$ +\mathbb{E}_t[\exp(a + b^\top\varepsilon_{t+1})] = \exp\left(a + \frac{1}{2}b^\top b\right) +$$ + +计算 $\frac{1}{2}b^\top b$: + +$$ +\frac{1}{2}(\bar B_n^\top C - \lambda_t^\top)(\bar B_n^\top C - \lambda_t^\top)^\top = \frac{1}{2}\bar B_n^\top CC^\top \bar B_n - \bar B_n^\top C\lambda_t + \frac{1}{2}\lambda_t^\top\lambda_t +$$ + +$\frac{1}{2}\lambda_t^\top\lambda_t$ 与已经在 $a$ 中的 $-\frac{1}{2}\lambda_t^\top\lambda_t$ 相互抵消,并且 $-\bar B_n^\top C\lambda_t = -\bar B_n^\top C(\lambda_0 + \lambda_z z_t)$。 + + +$$ +\log p_t(n+1) = \underbrace{\bar A_n + \bar B_n^\top(\mu - C\lambda_0) + \frac{1}{2}\bar B_n^\top CC^\top \bar B_n - \delta_0}_{\bar A_{n+1}} + \underbrace{(\bar B_n^\top(\phi - C\lambda_z) - \delta_1^\top)}_{\bar B_{n+1}^\top} z_t +$$ + +匹配常数项和 $z_t$ 上的系数,得到黎卡提 +方程 {eq}`eq_riccati_a` 和 {eq}`eq_riccati_b`。 + +令 $n = 0$,其中 $p_t(1) = \exp(-r_t) = \exp(-\delta_0 - \delta_1^\top z_t)$,得到 $\bar A_1 = -\delta_0$ 和 $\bar B_1 = -\delta_1$。 + +```{solution-end} +``` + +### 收益率 + +$n$ 期债券的**到期收益率**是一个常数利率 $y$, +以该利率将面值贴现可得到观察到的价格, +即 $p_t(n) = e^{-n\,y}$。 + +对 $y$ 求解得到 + +$$ +y_t(n) = -\frac{\log p_t(n)}{n} +$$ + +代入 {eq}`eq_bondprice` 得到 + +```{math} +:label: eq_yield + +y_t(n) = A_n + B_n^\top z_t +``` + +其中 $A_n = -\bar A_n / n$,$B_n = -\bar B_n / n$。 + +*收益率是状态向量 $z_t$ 的仿射函数。* + +这是仿射期限结构模型的定义性质。 + +现在我们实现债券定价公式 {eq}`eq_riccati_a`、{eq}`eq_riccati_b` +和 {eq}`eq_yield`。 + +```{code-cell} ipython3 +def bond_coefficients(model, n_max): + """计算 n = 1, ..., n_max 的 (A_bar_n, B_bar_n)。""" + A_bar = np.zeros(n_max + 1) + B_bar = np.zeros((n_max + 1, model.m)) + A_bar[1], B_bar[1] = -model.δ_0, -model.δ_1 + CC = model.C @ model.C.T + for n in range(1, n_max): + Bn = B_bar[n] + A_bar[n + 1] = (A_bar[n] + Bn @ model.μ_rn + + 0.5 * Bn @ CC @ Bn + - model.δ_0) + B_bar[n + 1] = model.φ_rn.T @ Bn - model.δ_1 + return A_bar, B_bar + +def compute_yields(model, z, n_max): + """计算 n = 1, ..., n_max 的收益率曲线 y_t(n)。""" + A_bar, B_bar = bond_coefficients(model, n_max) + return np.array([(-A_bar[n] - B_bar[n] @ z) / n + for n in range(1, n_max + 1)]) + +def bond_prices(model, z, n_max): + """计算 n = 1, ..., n_max 的债券价格 p_t(n)。""" + A_bar, B_bar = bond_coefficients(model, n_max) + return np.array([np.exp(A_bar[n] + B_bar[n] @ z) + for n in range(1, n_max + 1)]) +``` + +### 单因子高斯示例 + +为了建立直觉,我们从单因子($m=1$)高斯模型开始。 + +当 $m = 1$ 时,状态 $z_t$ 遵循 AR(1) 过程 +$z_{t+1} = \mu + \phi z_t + C\varepsilon_{t+1}$。 + +$z_t$ 的无条件标准差 +为 $\sigma_z = C / \sqrt{1 - \phi^2}$,它通过 $r_t = \delta_0 + \delta_1 z_t$ 决定 +模型所生成的短期利率的范围。 + +```{code-cell} ipython3 +# 单因子高斯模型(季度) +μ = np.array([0.0]) +φ = np.array([[0.95]]) +C = np.array([[1.0]]) +δ_0 = 0.01 # 1%/季度 ≈ 4% 年化 +δ_1 = np.array([0.001]) +λ_0 = np.array([-0.05]) +λ_z = np.array([[-0.01]]) + +model_1f = create_affine_model(μ, φ, C, δ_0, δ_1, λ_0, λ_z) +``` + +### 收益率曲线形状 + +我们计算在一系列短期利率状态 $z_t$ 下的收益率曲线 $y_t(n)$。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 单因子仿射模型下的收益率曲线 + name: fig-yield-curves-1f +--- +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n + +n_max_1f = 60 +maturities_1f = np.arange(1, n_max_1f + 1) + +z_low = np.array([-5.0]) +z_mid = np.array([0.0]) +z_high = np.array([5.0]) + +fig, ax = plt.subplots(figsize=(9, 5.5)) + +r_low = short_rate(model_1f, z_low) * 4 * 100 +r_mid = short_rate(model_1f, z_mid) * 4 * 100 +r_high = short_rate(model_1f, z_high) * 4 * 100 + +for z, label in [ + (z_low, f"低状态 ($y_t(1) = ${r_low:.1f}%)"), + (z_mid, f"中位状态 ($y_t(1) = ${r_mid:.1f}%)"), + (z_high, f"高状态 ($y_t(1) = ${r_high:.1f}%)"), +]: + y = compute_yields(model_1f, z, n_max_1f) * 4 * 100 + line, = ax.plot(maturities_1f, y, lw=2.2, label=label) + ax.plot(1, y[0], 'o', color=line.get_color(), ms=7, zorder=5) + +r_bar = short_rate(model_1f, np.array([0.0])) * 4 * 100 +ax.axhline(r_bar, color='grey', ls=':', lw=1.2, alpha=0.7, + label=f"平均短期利率 ({r_bar:.1f}%)") + +# 长期收益率:B_bar_n 收敛,因此 y_inf = lim -A_bar_n / n +φ_Cλ = (model_1f.φ_rn)[0, 0] # φ - Cλ_z(标量) +B_inf = -model_1f.δ_1[0] / (1 - φ_Cλ) # B 递归的不动点 +A_increment = (B_inf * model_1f.μ_rn[0] + + 0.5 * B_inf**2 * (model_1f.C @ model_1f.C.T)[0, 0] + - model_1f.δ_0) +y_inf = -A_increment * 4 * 100 # 年化 % +ax.axhline(y_inf, color='black', ls='--', lw=1.2, alpha=0.7, + label=f"长期收益率 ({y_inf:.1f}%)") + +ax.set_xlabel("期限(季度)") +ax.set_ylabel("收益率(每年 %)") +ax.legend(fontsize=10, loc='best') +ax.set_xlim(1, n_max_1f) + +ax2 = ax.twiny() +ax2.set_xlim(ax.get_xlim()) +year_ticks = [4, 20, 40, 60] +ax2.set_xticks(year_ticks) +ax2.set_xticklabels([f"{t/4:.0f}y" for t in year_ticks]) +ax2.set_xlabel("期限(年)") + +plt.tight_layout() +plt.show() +``` + +当短期利率较低时,收益率曲线是 +向上倾斜的,而当短期利率较高时,它是向下倾斜的。 + +所有三条曲线在长期限处收敛到同一个长期收益率 $y_\infty$, +并且长期收益率位于平均短期利率 +$\delta_0$ 之上。 + +````{exercise} +:label: arp_ex4 + +证明长期收益率满足 + +```{math} +:label: eq_y_inf + +y_\infty + = \delta_0 + - \bar B_\infty^\top(\mu - C\lambda_0) + - \tfrac{1}{2}\bar B_\infty^\top CC^\top \bar B_\infty +``` + +其中 $\bar B_\infty = -(I - (\phi - C\lambda_z)^\top)^{-1} \delta_1$ +是递归 {eq}`eq_riccati_b` 的不动点。 + +然后解释为什么在这种参数化下 $y_\infty > \delta_0$。 + +*提示:* 使用 {eq}`eq_yield` 和黎卡提方程 +{eq}`eq_riccati_a`--{eq}`eq_riccati_b`。对于不等式,分别考虑 +每个被减去的项。 +```` + +```{solution-start} arp_ex4 +:class: dropdown +``` + + +递归 {eq}`eq_riccati_b` 是一个线性差分方程 $\bar B_{n+1} = (\phi - C\lambda_z)^\top \bar B_n - \delta_1$。 + +当 $\phi - C\lambda_z$ 的特征值在单位圆内时,$\bar B_n$ 收敛到 $\bar B_\infty = -(I - (\phi - C\lambda_z)^\top)^{-1} \delta_1$。 + +由于 $\bar B_\infty$ 是有限的,在 {eq}`eq_yield` 中 $\bar B_n^\top z_t / n \to 0$,因此无论 $z_t$ 为何,$y_t(n) \to \lim_{n\to\infty} -\bar A_n / n$。 + +要找到这个极限,写 $\bar A_n = \bar A_1 + \sum_{k=1}^{n-1}(\bar A_{k+1} - \bar A_k)$。 + +根据 {eq}`eq_riccati_a`,每个增量取决于 $\bar B_k$,它收敛到 $\bar B_\infty$,因此增量收敛到 $L \equiv \bar B_\infty^\top(\mu - C\lambda_0) + \tfrac{1}{2}\bar B_\infty^\top CC^\top \bar B_\infty - \delta_0$。 + +因此 $\bar A_n / n \to L$,$y_\infty = -L$,得到 {eq}`eq_y_inf`。 + +要理解为什么 $y_\infty > \delta_0$,注意在这种参数化下 {eq}`eq_y_inf` 中的两个被减去的项符号相反。 + +二次项 $\tfrac{1}{2}\bar B_\infty^\top CC^\top \bar B_\infty = \tfrac{1}{2}\|C^\top \bar B_\infty\|^2 \geq 0$ 总是成立。 + +这是来自詹森不等式的**凸性效应**,它将 $y_\infty$ 推低到 $\delta_0$ 以下。 + +线性项 $\bar B_\infty^\top(\mu - C\lambda_0)$ 是负的,因为 $\bar B_\infty < 0$(由于 $\delta_1 > 0$)而 $\mu - C\lambda_0 > 0$(由于 $\lambda_0 < 0$)。减去这个负量将 $y_\infty$ 提升到 $\delta_0$ 之上。 + +这是**风险溢价效应**:正的期限溢价将平均收益率曲线向上倾斜。 + +在这种参数化下,风险溢价效应主导了凸性效应,因此 $y_\infty > \delta_0$。 + +```{solution-end} +``` + + +让我们也模拟一下短期利率路径: + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 模拟的短期利率路径 + name: fig-simulated-short-rate +--- +T = 200 +Z = simulate(model_1f, np.array([0.0]), T) +short_rates = np.array([short_rate(model_1f, Z[t]) * 4 * 100 + for t in range(T + 1)]) +r_bar_pct = short_rate(model_1f, np.array([0.0])) * 4 * 100 + +fig, ax = plt.subplots(figsize=(10, 4)) +quarters = np.arange(T + 1) +line, = ax.plot(quarters, short_rates, lw=1.3) +ax.axhline(r_bar_pct, ls="--", lw=1.3, + label=f"无条件均值 ({r_bar_pct:.1f}%)") +ax.fill_between(quarters, short_rates, r_bar_pct, + alpha=0.08, color=line.get_color()) +ax.set_xlabel("季度") +ax.set_ylabel("短期利率(年化 %)") +ax.set_xlim(0, T) +ax.legend(fontsize=11) +plt.tight_layout() +plt.show() +``` + +### 双因子模型 + +为了匹配更丰富的收益率曲线动态,从业者通常使用 $m \geq 2$ +个因子。 + +现在我们引入一个双因子设定,状态为 +$z_t = (z_{1t},\, z_{2t})^\top$,其中 + +$$ +z_{t+1} = \mu + \phi\, z_t + C\,\varepsilon_{t+1}, +\qquad +\phi = \begin{pmatrix} 0.97 & -0.03 \\ 0 & 0.90 \end{pmatrix}, +\qquad +C = I_2 +$$ + +第一个因子 $z_{1t}$ 高度持续($\phi_{11} = 0.97$),并 +通过 $\delta_1$ 驱动短期利率的大部分变化,因此我们 +将其解释为**水平**因子。 + +第二个因子 $z_{2t}$ 更快地均值回归($\phi_{22} = 0.90$),并 +以较小的载荷影响短期利率,捕捉收益率曲线的**斜率**。 + +非对角元素 $\phi_{12} = -0.03$ 允许水平因子 +对当前斜率状态 $z_{2t}$ 做出响应。 + +短期利率为 $r_t = \delta_0 + \delta_1^\top z_t$,其中 +$\delta_1 = (0.002,\; 0.001)^\top$,因此当两个因子为正时都会提高短期 +利率,但水平因子的影响是斜率因子的两倍。 + +风险价格为 $\lambda_t = \lambda_0 + \lambda_z z_t$,其中 +$\lambda_0 = (-0.01,\; -0.005)^\top$, +$\lambda_z = \text{diag}(-0.005,\, -0.003)$。 + +$\lambda_z$ 的负对角元素使得 $\phi - C\lambda_z$ 的特征值比 $\phi$ +更大,因此在风险中性测度下状态更持续,收益率曲线在长期限处 +对当前状态更敏感。 + +```{code-cell} ipython3 +# 双因子模型:z = [水平, 斜率] +μ_2 = np.array([0.0, 0.0]) +φ_2 = np.array([[0.97, -0.03], + [0.00, 0.90]]) +C_2 = np.eye(2) +δ_0_2 = 0.01 +δ_1_2 = np.array([0.002, 0.001]) +λ_0_2 = np.array([-0.01, -0.005]) +λ_z_2 = np.array([[-0.005, 0.0], + [ 0.0, -0.003]]) + +model_2f = create_affine_model(μ_2, φ_2, C_2, δ_0_2, δ_1_2, λ_0_2, λ_z_2) + +print(f"φ 的特征值: {eigvals(φ_2).real.round(4)}") +print(f"φ - Cλ_z 的特征值: {eigvals(model_2f.φ_rn).real.round(4)}") +``` + +这确认了 $\phi - C\lambda_z$ 的特征值比 $\phi$ 的特征值更大,因此在风险中性测度下状态更持续。 + +下图显示了世界不同状态下的收益率曲线,以及决定收益率在每个期限如何载荷于水平和斜率因子的因子载荷 $B_{n,1}$ 和 $B_{n,2}$ + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 双因子模型下的收益率曲线和因子载荷 + name: fig-yield-curves-2f +--- +n_max_2f = 60 +maturities_2f = np.arange(1, n_max_2f + 1) + +states = { + "正常": np.array([0.0, 0.0]), + "低短期利率": np.array([-4.0, 3.0]), + "高短期利率": np.array([4.0, -3.0]), +} + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5.5)) + +for label, z in states.items(): + r_now = short_rate(model_2f, z) * 4 * 100 + y = compute_yields(model_2f, z, n_max_2f) * 4 * 100 + line, = ax1.plot(maturities_2f, y, lw=2.2, + label=f"{label} (r₁ = {r_now:.1f}%)") + ax1.plot(1, y[0], 'o', color=line.get_color(), ms=7, zorder=5) + +ax1.set_xlabel("期限(季度)") +ax1.set_ylabel("收益率(年化 %)") +ax1.legend(fontsize=10) +ax1.set_xlim(1, n_max_2f) + +A_bar, B_bar = bond_coefficients(model_2f, n_max_2f) +ns = np.arange(1, n_max_2f + 1) +B_n = np.array([-B_bar[n] / n for n in ns]) + +ax2.plot(ns, B_n[:, 0], lw=2.2, + label=r"水平载荷 $B_{n,1}$") +ax2.plot(ns, B_n[:, 1], lw=2.2, + label=r"斜率载荷 $B_{n,2}$") +ax2.axhline(0, color='black', lw=0.6) +ax2.set_xlabel("期限(季度)") +ax2.set_ylabel(r"收益率载荷 $B_{n,k}$") +ax2.legend(fontsize=11) +ax2.set_xlim(1, n_max_2f) + +for ax in (ax1, ax2): + ax_top = ax.twiny() + ax_top.set_xlim(ax.get_xlim()) + year_ticks = [4, 12, 20, 40, 60] + ax_top.set_xticks(year_ticks) + ax_top.set_xticklabels([f"{t/4:.0f}y" for t in year_ticks]) + +plt.tight_layout() +plt.show() +``` + +我们可以看到,水平因子在长期限处占主导地位。 + +## 风险溢价 + +仿射期限结构模型中的一个关键对象是**期限溢价**,即 +长期债券相对于滚动短期债券的预期超额回报。 + +对于持有一期的 $(n+1)$ 期债券,冲击载荷为 +$\alpha_n = C^\top \bar B_n$,因此 {eq}`eq_excess` 给出 + +$$ +\log \mathbb{E}_t R_{t+1}^{(n+1)} - r_t \;=\; \bar B_n^\top C \lambda_t +$$ + +期限溢价等于债券冲击暴露 $\bar B_n^\top C$ +与风险价格向量 $\lambda_t$ 的内积。 + +由于期限溢价等于 $\bar B_n^\top C \lambda_t$,其符号 +取决于*当前*风险价格向量 $\lambda_t$,只要 $\lambda_z \neq 0$, +它就是状态依赖的。 + +为了更具体地看到这一点,考虑一个 $C\lambda_t$ 逐分量为负的状态 +(例如,我们下面校准中的 $z_t = 0$)。 + +当 $\delta_1 > 0$ 时,正的冲击 $\varepsilon_{t+1}$ 会提高 +短期利率并降低长期债券价格,因此债券冲击载荷 +$\alpha_n = C^\top \bar B_n$ 为负。 + +那么负的 $C\lambda_t$ 意味着随机贴现因子 +$m_{t+1}$ 对 $\varepsilon_{t+1}$ 正向载荷,即在利率上升 +和债券价格下跌的状态下 SDF 较高。 + +这使得 $\text{Cov}_t(m_{t+1}, R_{t+1}^{(n+1)}) < 0$,因此长期债券 +是有风险的,并带有正的期限溢价。 + +从代数上看,$\bar B_n < 0$ 和 $C\lambda_t < 0$ 结合 +得到 $\bar B_n^\top C \lambda_t > 0$。 + +然而,在其他状态下,$\lambda_t$ 可能会改变符号(例如,在我们的双状态 +校准的低利率状态下,第一个分量翻转),长期债券期限溢价 +在较长期限处可能变为负值。 + +```{exercise} +:label: arp_ex5 + +通过计算 $(n+1)$ 期债券的单期持有回报并识别其冲击载荷,推导上面的期限溢价公式。 + +*提示:* 使用 $R_{t+1}^{(n+1)} = p_{t+1}(n)/p_t(n+1)$ 以及 +$\log p_t(n) = \bar A_n + \bar B_n^\top z_t$,代入状态 +动态 {eq}`eq_var`,并应用黎卡提方程 +{eq}`eq_riccati_a`--{eq}`eq_riccati_b` 进行简化。 +``` + +```{solution-start} arp_ex5 +:class: dropdown +``` + +$(n+1)$ 期债券的单期持有回报为 +$R_{t+1}^{(n+1)} = p_{t+1}(n)/p_t(n+1)$,因此 + +$$ +\log R_{t+1}^{(n+1)} = \bar A_n + \bar B_n^\top z_{t+1} - \bar A_{n+1} - \bar B_{n+1}^\top z_t +$$ + +代入 {eq}`eq_var` 中的 $z_{t+1} = \mu + \phi z_t + C\varepsilon_{t+1}$: + +$$ += \underbrace{(\bar A_n + \bar B_n^\top \mu - \bar A_{n+1})}_{\text{常数}} + + \underbrace{(\bar B_n^\top \phi - \bar B_{n+1}^\top)}_{z_t \text{ 上的载荷}} z_t + + \underbrace{\bar B_n^\top C}_{\text{冲击载荷}}\, \varepsilon_{t+1} +$$ + +现在我们使用黎卡提方程简化每一部分。 + +对于常数部分,{eq}`eq_riccati_a` 给出 +$\bar A_{n+1} = \bar A_n + \bar B_n^\top(\mu - C\lambda_0) + \tfrac{1}{2}\bar B_n^\top CC^\top \bar B_n - \delta_0$,因此 + +$$ +\bar A_n + \bar B_n^\top \mu - \bar A_{n+1} + = \bar B_n^\top C\lambda_0 - \tfrac{1}{2}\bar B_n^\top CC^\top \bar B_n + \delta_0 +$$ + +对于 $z_t$ 系数,{eq}`eq_riccati_b` 给出 +$\bar B_{n+1}^\top = \bar B_n^\top(\phi - C\lambda_z) - \delta_1^\top$,因此 + +$$ +\bar B_n^\top \phi - \bar B_{n+1}^\top = \bar B_n^\top C\lambda_z + \delta_1^\top +$$ + +结合各部分: + +$$ +\log R_{t+1}^{(n+1)} + = \underbrace{(\delta_0 + \delta_1^\top z_t)}_{r_t} + + \bar B_n^\top C\underbrace{(\lambda_0 + \lambda_z z_t)}_{\lambda_t} + - \tfrac{1}{2}\bar B_n^\top CC^\top \bar B_n + + \bar B_n^\top C\,\varepsilon_{t+1} +$$ + +写 $\alpha_n = C^\top \bar B_n$,这就取了通用回报形式 {eq}`eq_return`: + +$$ +\log R_{t+1}^{(n+1)} + = \underbrace{(r_t + \alpha_n^\top \lambda_t)}_{\nu_t} + - \tfrac{1}{2}\alpha_n^\top \alpha_n + + \alpha_n^\top \varepsilon_{t+1} +$$ + +由于 $\mathbb{E}_t R_{t+1}^{(n+1)} = \exp(\nu_t)$,我们得到 + +$$ +\log \mathbb{E}_t R_{t+1}^{(n+1)} - r_t = \alpha_n^\top \lambda_t = \bar B_n^\top C \lambda_t +$$ + +```{solution-end} +``` + +下图绘制了世界不同状态下跨期限的期限溢价,以及正常状态下水平因子和斜率因子对期限溢价的贡献 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 双因子模型下的期限溢价和因子分解 + name: fig-term-premiums-2f +--- +def term_premiums(model, z, n_max): + """计算期限 1 到 n_max 的期限溢价。""" + A_bar, B_bar = bond_coefficients(model, n_max + 1) + λ_t = risk_prices(model, z) + return np.array([B_bar[n-1] @ model.C @ λ_t + for n in range(1, n_max + 1)]) + +n_max_tp = 60 +maturities_tp = np.arange(1, n_max_tp + 1) + +z_states_tp = { + "低利率 ($z_1 < 0$)": np.array([-3.0, 2.0]), + "高利率 ($z_1 > 0$)": np.array([3.0, -2.0]), +} + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5.5)) + +for label, z in z_states_tp.items(): + tp = term_premiums(model_2f, z, n_max_tp) * 4 * 100 + r_now = short_rate(model_2f, z) * 4 * 100 + lam = risk_prices(model_2f, z) + ax1.plot(maturities_tp, tp, lw=2.2, + label=(f"{label}\n r={r_now:.1f}%," + f" λ=[{lam[0]:.3f}, {lam[1]:.3f}]")) + +ax1.axhline(0, color="black", lw=0.8, ls="--") +ax1.set_xlabel("期限(季度)") +ax1.set_ylabel("期限溢价(年化 %)") +ax1.legend(fontsize=9) +ax1.set_xlim(1, n_max_tp) + +z_decomp = np.array([0.0, 0.0]) +A_bar_d, B_bar_d = bond_coefficients(model_2f, n_max_tp + 1) +λ_t = risk_prices(model_2f, z_decomp) +C_lam = model_2f.C @ λ_t + +tp_level = np.array([B_bar_d[n-1, 0] * C_lam[0] + for n in range(1, n_max_tp + 1)]) * 4 * 100 +tp_slope = np.array([B_bar_d[n-1, 1] * C_lam[1] + for n in range(1, n_max_tp + 1)]) * 4 * 100 +tp_total = tp_level + tp_slope + +ax2.plot(maturities_tp, tp_total, 'k-', lw=2.2, label="总计") +ax2.plot(maturities_tp, tp_level, lw=1.8, ls="--", + label="水平因子") +ax2.plot(maturities_tp, tp_slope, lw=1.8, ls="--", + label="斜率因子") +ax2.axhline(0, color="black", lw=0.6, ls=":") +ax2.set_xlabel("期限(季度)") +ax2.set_ylabel("期限溢价(年化 %)") +ax2.legend(fontsize=10) +ax2.set_xlim(1, n_max_tp) + +for ax in (ax1, ax2): + ax_top = ax.twiny() + ax_top.set_xlim(ax.get_xlim()) + year_ticks = [4, 12, 20, 40, 60] + ax_top.set_xticks(year_ticks) + ax_top.set_xticklabels([f"{t/4:.0f}y" for t in year_ticks]) + +plt.tight_layout() +plt.show() +``` + +我们看到,在低利率状态下期限溢价在所有期限都为正,但在高利率状态下的较长期限处变为负值。 + +## 风险中性概率 + +我们回到 VAR 和短期利率方程 +{eq}`eq_var`--{eq}`eq_shortrate`,为方便起见在此重复: + +$$ +z_{t+1} = \mu + \phi z_t + C\varepsilon_{t+1}, \qquad +r_t = \delta_0 + \delta_1^\top z_t +$$ + +其中 $\varepsilon_{t+1} \sim \mathcal{N}(0, I)$。 + +我们假设这一结构描述了数据生成机制。 + +金融经济学家称之为**物理测度** $P$,以区别于 +我们现在描述的**风险中性测度** $Q$。 + +在物理测度下,给定 $z_t$ 的 $z_{t+1}$ 的条件分布 +为 $\mathcal{N}(\mu + \phi z_t,\; CC^\top)$。 + +### 测度变换 + +利用 {eq}`eq_riskprices` 中的风险价格向量 $\lambda_t = \lambda_0 + \lambda_z z_t$,定义非负随机变量 + +```{math} +:label: eq_rn_ratio + +\frac{\xi^Q_{t+1}}{\xi^Q_t} + = \exp\!\left(-\tfrac{1}{2}\lambda_t^\top\lambda_t + - \lambda_t^\top\varepsilon_{t+1}\right) +``` + +这是一个均值为 1 的对数正态随机变量,因此它是一个有效的 +似然比,可用于扭曲 $z_{t+1}$ 的条件分布。 + +将物理条件分布乘以这个似然比 +将其转换为**风险中性条件分布** + +$$ +z_{t+1} \mid z_t \;\overset{Q}{\sim}\; + \mathcal{N}\!\bigl(\mu - C\lambda_0 + (\phi - C\lambda_z)z_t,\; CC^\top\bigr) +$$ + +换句话说,在 $Q$ 下状态遵循 + +$$ +z_{t+1} = (\mu - C\lambda_0) + (\phi - C\lambda_z)\,z_t + + C\varepsilon^Q_{t+1} +$$ + +其中在 $Q$ 下 $\varepsilon^Q_{t+1} \sim \mathcal{N}(0, I)$。 + +风险中性分布将条件均值从 +$\mu + \phi z_t$ 扭曲为 $\mu - C\lambda_0 + (\phi - C\lambda_z)z_t$。 + +调整项 $-C\lambda_0$(常数)和 $-C\lambda_z$ +(状态依赖)编码了定价方程 +$\mathbb{E}^P_t m_{t+1} R_{j,t+1} = 1$ 如何针对 +对风险 $\varepsilon_{t+1}$ 的暴露调整预期回报。 + +### 资产定价简述 + +设 $\mathbb{E}^P$ 表示在自然用于生成数据的物理测度下的期望。 + +我们的关键资产定价方程是 +$\mathbb{E}^P_t m_{t+1} R_{j,t+1} = 1$ 对所有回报 $R_{j,t+1}$ 成立。 + +利用 {eq}`eq_rn_ratio`,我们可以将 SDF {eq}`eq_sdf` 表示为 + +$$ +m_{t+1} = \frac{\xi^Q_{t+1}}{\xi^Q_t}\,\exp(-r_t) +$$ + +那么条件 +$\mathbb{E}^P_t\bigl(\exp(-r_t)\, +\tfrac{\xi^Q_{t+1}}{\xi^Q_t}\, R_{j,t+1}\bigr) = 1$ +等价于 + +```{math} +:label: eq_qpricing + +\mathbb{E}^Q_t R_{j,t+1} = \exp(r_t) +``` + +*在风险中性测度下,所有资产的预期回报等于 +无风险回报。* + +### 通过风险中性定价进行验证 + +债券价格可以通过在 $Q$ 下以 $r_t$ 贴现来计算: + +$$ +p_t(n) = \mathbb{E}^Q_t \left[\exp \left(-\sum_{s=0}^{n-1}r_{t+s}\right)\right] +$$ + +我们可以通过在风险中性 VAR 下迭代仿射 +递归来验证这与 {eq}`eq_bondprice` 一致。 + +下面我们通过数值方法确认这一点 + +```{code-cell} ipython3 +def bond_price_mc_Q(model, z0, n, n_sims=50_000, rng=None): + """通过 Q 下的蒙特卡洛估计 p_t(n)。""" + if rng is None: + rng = np.random.default_rng(0) + m = len(z0) + Z = np.tile(z0, (n_sims, 1)) + disc = np.zeros(n_sims) + for _ in range(n): + disc += model.δ_0 + Z @ model.δ_1 + ε = rng.standard_normal((n_sims, m)) + Z = model.μ_rn + Z @ model.φ_rn.T + ε @ model.C.T + return np.mean(np.exp(-disc)) + +z_test = np.array([0.01, 0.005]) +p_analytic = bond_prices(model_2f, z_test, 40) + +rng = np.random.default_rng(0) +maturities_check = [4, 12, 24, 40] +mc_prices = [bond_price_mc_Q(model_2f, z_test, n, n_sims=100_000, rng=rng) + for n in maturities_check] + +header = (f"{'期限':>10} {'解析解':>12}" + f" {'蒙特卡洛':>12} {'误差 (bps)':>12}") +print(header) +print("-" * 52) +for n, mc in zip(maturities_check, mc_prices): + analytic = p_analytic[n - 1] + error_bp = abs(analytic - mc) / analytic * 10_000 + print(f"{n:>10} {analytic:>12.6f} {mc:>12.6f} {error_bp:>12.2f}") +``` + +解析债券价格和蒙特卡洛债券价格紧密一致,验证了 +黎卡提递归 {eq}`eq_riccati_a`–{eq}`eq_riccati_b`。 + +## 扭曲信念 + +{cite:t}`piazzesi2015trend` 汇集了调查证据,表明经济 +专家的预测相对于物理测度存在系统性偏差。 + +### 主观测度 + +设 $\{z_t\}_{t=1}^T$ 为关于状态的观测记录,设 +$\{\check z_{t+1}\}_{t=1}^T$ 为向前一期专家预测的记录。 + +设 $\check\mu, \check\phi$ 为以下回归中的回归系数 + +$$ +\check z_{t+1} = \check\mu + \check\phi\, z_t + e_{t+1} +$$ + +其中残差 $e_{t+1}$ 均值为零,与 $z_t$ 正交,并 +满足 $\mathbb{E}\,e_{t+1} e_{t+1}^\top = CC^\top$。 + +通过将 {eq}`eq_var` 中 $\mu, \phi$ 的估计与专家预测中 +$\check\mu, \check\phi$ 的估计进行比较,{cite:t}`piazzesi2015trend` +推断出专家的信念存在系统性扭曲。 + +为了组织这一证据,设 $\kappa_t = \kappa_0 + \kappa_z z_t$ 并定义 +似然比 + +```{math} +:label: eq_srat + +\frac{\xi^S_{t+1}}{\xi^S_t} + = \exp\!\left(-\tfrac{1}{2}\kappa_t^\top\kappa_t + - \kappa_t^\top\varepsilon_{t+1}\right) +``` + +这是均值为 1 的对数正态,因此它是一个有效的似然比。 + +将 $z_{t+1}$ 的物理条件分布乘以这个 +似然比,将其转换为专家的**主观条件 +分布** + +$$ +z_{t+1} \mid z_t \;\overset{S}{\sim}\; + \mathcal{N}\!\bigl(\mu - C\kappa_0 + (\phi - C\kappa_z)\,z_t,\; CC^\top\bigr) +$$ + +在专家的预测回归中,$\check\mu$ 估计 +$\mu - C\kappa_0$,$\check\phi$ 估计 $\phi - C\kappa_z$。 + +{cite:t}`piazzesi2015trend` 发现,专家的行为就好像收益率曲线的水平和 +斜率比物理测度下更持续: +$\check\phi$ 的特征值比 $\phi$ 更大。 + +### 扭曲信念下的定价 + +{cite:t}`piazzesi2015trend` 探讨了这样一个假设:一个持有这些扭曲信念的代表性 +行为主体对资产定价,并使回报满足 + +$$ +\mathbb{E}^S_t\bigl(m^\star_{t+1}\, R_{j,t+1}\bigr) = 1 +$$ + +其中 $\mathbb{E}^S_t$ 是在主观 +$S$ 测度下的条件期望,$m^\star_{t+1}$ 是持有这些信念的 +行为主体的 SDF。 + +具体来说,行为主体的 SDF 为 + +$$ +m^\star_{t+1} = \exp\!\left(-r^\star_t + - \tfrac{1}{2}\lambda_t^{\star\top}\lambda^\star_t + - \lambda_t^{\star\top}\varepsilon_{t+1}\right) +$$ + +其中 $r^\star_t$ 是短期利率,$\lambda^\star_t$ 是行为主体的 +风险价格向量。 + +使用 {eq}`eq_srat` 转换到物理测度,主观 +定价方程变为 + +$$ +\mathbb{E}^P_t\!\left[ + \exp\!\left(-r^\star_t + - \tfrac{1}{2}\lambda_t^{\star\top}\lambda^\star_t + - \lambda_t^{\star\top}\varepsilon_{t+1} + \right) + \exp\!\left( + - \tfrac{1}{2}\kappa_t^\top\kappa_t + - \kappa_t^\top\varepsilon_{t+1} + \right) + R_{j,t+1} +\right] = 1 +$$ + +合并两个指数得到 + +$$ +\mathbb{E}^P_t\!\left[ + \exp\!\left(-r_t + - \tfrac{1}{2}(\lambda^\star_t + \kappa_t)^\top(\lambda^\star_t + \kappa_t) + - (\lambda^\star_t + \kappa_t)^\top\varepsilon_{t+1} + \right) R_{j,t+1} +\right] = 1 +$$ + +其中 $r_t = r^\star_t - \lambda_t^{\star\top}\kappa_t$。 + +将其与理性预期计量经济学家的定价 +方程进行比较 + +$$ +\mathbb{E}^P_t\!\left[ + \exp\!\left(-r_t + - \tfrac{1}{2}\lambda_t^\top\lambda_t + - \lambda_t^\top\varepsilon_{t+1} + \right) R_{j,t+1} +\right] = 1 +$$ + +我们看到,计量经济学家解释为 $\lambda_t$ 的实际上是 +$\lambda^\star_t + \kappa_t$。 + +因为计量经济学家的估计部分反映了主观信念中的 +系统性扭曲,在这种校准中它们可能高估了代表性 +行为主体真实的风险价格 $\lambda^\star_t$。 + +下面我们构造一个数值例子来说明这一点。 + +我们保持与上面相同的物理状态动态和短期利率设定,但选择一个单独的真实风险价格过程 $(\lambda_t^\star)$ 和一个扭曲信念计量经济学家过程 $(\hat\lambda_t)$ 来说明这一分解。 + +然后我们设定主观参数 $\check\mu, \check\phi$ 以匹配 +{cite:t}`piazzesi2015trend` 中的证据,即专家的行为就好像收益率曲线的水平和斜率比物理测度下更持续。 + +具体来说,我们使用 + +$$ +\check\phi = \begin{pmatrix} 0.985 & -0.025 \\ 0.00 & 0.94 \end{pmatrix} +$$ + +```{code-cell} ipython3 +φ_P = φ_2.copy() +μ_P = μ_2.copy() + +# 主观参数:专家认为因子更持续 +φ_S = np.array([[0.985, -0.025], [0.00, 0.94]]) +μ_S = np.array([0.005, 0.0]) + +κ_z = np.linalg.solve(C_2, φ_P - φ_S) +κ_0 = np.linalg.solve(C_2, μ_P - μ_S) + +λ_star_0 = np.array([-0.03, -0.015]) +λ_star_z = np.array([[-0.006, 0.0], [0.0, -0.004]]) + +λ_hat_0 = λ_star_0 + κ_0 +λ_hat_z = λ_star_z + κ_z +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与扭曲信念期限溢价及高估比率 + name: fig-distorted-beliefs +--- +model_true = create_affine_model( + μ_2, φ_2, C_2, δ_0_2, δ_1_2, λ_star_0, λ_star_z) +model_econ = create_affine_model( + μ_2, φ_2, C_2, δ_0_2, δ_1_2, λ_hat_0, λ_hat_z) + +z_ref = np.array([0.0, 0.0]) +n_max_db = 60 +maturities_db = np.arange(1, n_max_db + 1) + +tp_true = term_premiums(model_true, z_ref, n_max_db) * 4 * 100 +tp_econ = term_premiums(model_econ, z_ref, n_max_db) * 4 * 100 + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5.5)) + +ax1.plot(maturities_db, tp_true, lw=2.2, + label=r"真实风险价格 $\lambda^\star_t$") +line_econ, = ax1.plot(maturities_db, tp_econ, lw=2.2, ls="--", + label=(r"RE 计量经济学家" + r" $\hat\lambda_t = \lambda^\star_t + \kappa_t$")) +ax1.fill_between(maturities_db, tp_true, tp_econ, + alpha=0.15, color=line_econ.get_color(), + label="信念扭曲成分") +ax1.axhline(0, color="black", lw=0.8, ls=":") +ax1.set_xlabel("期限(季度)") +ax1.set_ylabel("期限溢价(年化 %)") +ax1.legend(fontsize=9.5) +ax1.set_xlim(1, n_max_db) + +mask = np.abs(tp_true) > 1e-8 +ratio = np.full_like(tp_true, np.nan) +ratio[mask] = tp_econ[mask] / tp_true[mask] + +ax2.plot(maturities_db[mask], ratio[mask], lw=2.2) +ax2.axhline(1, color="black", lw=0.8, ls="--", + label="无扭曲(比率 = 1)") +ax2.set_xlabel("期限(季度)") +ax2.set_ylabel(r"$\hat{tp}\, /\, tp^\star$") +ax2.legend(fontsize=11) +ax2.set_xlim(1, n_max_db) + +for ax in (ax1, ax2): + ax_top = ax.twiny() + ax_top.set_xlim(ax.get_xlim()) + year_ticks = [4, 12, 20, 40, 60] + ax_top.set_xticks(year_ticks) + ax_top.set_xticklabels([f"{t/4:.0f}y" for t in year_ticks]) + +plt.tight_layout() +plt.show() +``` + +当专家信念过度持续($\check\phi$ 的特征值比 $\phi$ +更大)时,理性预期计量经济学家将过多的 +观测到的风险溢价归因于风险厌恶。 + +将信念扭曲与真正的风险价格区分开来需要额外的 +数据,例如 {cite:t}`piazzesi2015trend` 使用的调查预测。 + +我们的 {doc}`advanced:risk_aversion_or_mistaken_beliefs` 讲座 +更深入地探讨了这种混淆。 + +## 结束语 + +随机贴现因子的仿射模型为研究资产价格提供了一个灵活且易于处理的 +框架。 + +关键特征是: + +1. **解析易处理性:** 债券价格是 $z_t$ 的指数仿射; + 预期回报可清晰地分解为短期利率加上一个风险价格×暴露内积。 +2. **实证灵活性:** 自由参数 $(\mu, \phi, C, \delta_0, \delta_1, \lambda_0, \lambda_z)$ + 可以通过最大似然估计({doc}`卡尔曼滤波 ` 章节描述了 + 相关方法),而无需施加来自完整一般均衡模型的约束。 +3. **多重风险:** 向量结构可容纳许多风险来源(货币 + 政策、实际活动、波动率等)。 +4. **信念扭曲:** 该框架通过对物理测度的似然比扭曲,自然地容纳 + 非理性信念,如 {cite:t}`piazzesi2015trend` 所示。 + +该模型还直接连接到 {doc}`advanced:doubts_or_variability` 中研究的 +Hansen–Jagannathan 边界,以及 {cite:t}`Ljungqvist2012` 其他章节中描述的 +随机贴现因子的稳健控制解释。 + +关于对本处连续状态框架进行补充的资产定价有限状态方法, +参见 {doc}`资产定价:有限状态模型 `。 \ No newline at end of file diff --git a/lectures/aiyagari_egm.md b/lectures/aiyagari_egm.md new file mode 100644 index 0000000..8d3ad2b --- /dev/null +++ b/lectures/aiyagari_egm.md @@ -0,0 +1,739 @@ +--- +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 +translation: + title: 使用内生网格法的Aiyagari模型 + headings: + Overview: 概述 + Overview::References: 参考文献 + Overview::Preliminaries: 预备知识 + The Economy: 经济 + The Economy::Households: 家庭 + The Economy::Firms: 厂商 + The Economy::Equilibrium: 均衡 + Implementation with EGM: 使用 EGM 的实现 + Implementation with EGM::Household primitives: 家庭原语 + Implementation with EGM::The EGM operator: EGM 算子 + Implementation with EGM::Solving the household problem: 求解家庭问题 + Computing Aggregate Capital by Simulation: 通过模拟计算总资本 + Computing Equilibrium: 计算均衡 + Computing Equilibrium::Visualizing equilibrium: 均衡可视化 + Wealth Distribution: 财富分布 + Summary and Comparison: 总结与比较 + Summary and Comparison::Comparison with standard approach: 与标准方法的比较 + Summary and Comparison::Extensions: 扩展 + Exercises: 练习 +--- + +(aiyagari_egm)= +```{raw} jupyter + +``` + +# 使用内生网格法的Aiyagari模型 + +```{contents} Contents +:depth: 2 +``` + +除了基础 Anaconda 中包含的内容外,我们还需要安装 QuantEcon 的 Python 库和 JAX。 + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install quantecon jax +``` + +## 概述 + +本讲座结合了宏观经济学中两种重要的计算方法: + +1. **Aiyagari模型** {cite}`Aiyagari1994` —— 一个具有不完全市场的异质性主体模型 +2. **内生网格法**(EGM) {cite}`Carroll2006` —— 一种求解动态规划问题的高效算法 + +在 {doc}`标准 Aiyagari 讲座 ` 中,我们使用离散化和值函数迭代来求解家庭问题。 + +然后我们使用有限马尔可夫链的平稳分布,在给定的一组价格下计算总资本。 + +在本讲座中,我们采用不同的方法: + +1. 我们使用**内生网格法**,通过欧拉方程和线性插值来求解家庭问题。 +2. 我们通过**模拟**来计算总资本,而不是使用代数技术(后者仅适用于有限情形)。 + +这些修改使得求解方法更快、更灵活,尤其是在处理更复杂的模型时。 + +我们在整个讲座中使用 [JAX](https://jax.readthedocs.io),这样 EGM 算子、求解器和模拟都是 JIT 编译且向量化的。 + +### 参考文献 + +本讲座的主要参考文献是: + +* 我们的 {doc}`前一个 Aiyagari 讲座 `,介绍了关键思想 +* {cite}`Aiyagari1994`,介绍了经济模型 +* {cite}`Carroll2006`,介绍了内生网格法 +* {cite}`Ljungqvist2012` 的第 18 章,提供了教科书式的处理 + + +### 预备知识 + +我们使用以下导入: + +```{code-cell} ipython3 +import quantecon as qe +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 jax +import jax.numpy as jnp +import numpy as np +from typing import NamedTuple +from functools import partial +from scipy.optimize import bisect +``` + +我们将在 JAX 中使用 64 位浮点数以提高精度。 + +```{code-cell} ipython3 +jax.config.update("jax_enable_x64", True) +``` + +## 经济 + +该经济由家庭和一个代表性厂商组成。 + +### 家庭 + +无限期生存的家庭面临特异性收入冲击和借贷约束。 + +典型家庭面临的储蓄问题是 + +$$ + \max \mathbb E \sum_{t=0}^{\infty} \beta^t u(c_t) +$$ + +约束条件为 + +$$ + a_{t+1} + c_t \leq w z_t + (1 + r) a_t + \quad + c_t \geq 0, + \quad \text{and} \quad + a_t \geq -B +$$ + +其中 + +* $c_t$ 是当期消费 +* $a_t$ 是资产 +* $z_t$ 是劳动收入的外生部分(随机就业状态) +* $w$ 是工资率 +* $r$ 是利率 +* $B$ 是主体被允许借入的最大金额 + +外生过程 $\{z_t\}$ 遵循一个具有随机矩阵 $\Pi$ 的有限状态马尔可夫链。 + +最优内部消费选择满足欧拉方程 + +$$ + u'(c) = \beta \mathbb{E_z} [(1 + r) u'(c')] +$$ + +(我们用 $'$ 符号同时表示导数和未来值,这并不理想,但方便且常见。) + +用资产来表示,即 + +$$ + u'(w z + (1 + r) a - a') + = \beta (1 + r) \sum_{z'} u'(w z' + (1 + r) a' - s(a', z')) \Pi(z, z') +$$ + +其中 $s$ 是最优储蓄策略函数。 + + +### 厂商 + +厂商在规模报酬不变的条件下,通过雇用资本和劳动来生产产出。 + +代表性厂商的产出为 + +$$ +Y = A K^{\alpha} N^{1 - \alpha} +$$ + +其中 + +* $A$ 和 $\alpha$ 是参数,满足 $A > 0$ 和 $\alpha \in (0, 1)$ +* $K$ 是总资本 +* $N$ 是总劳动供给(标准化为 1) + +这些参数存储在以下 namedtuple 中: + +```{code-cell} ipython3 +class Firm(NamedTuple): + A: float = 1.0 # 全要素生产率 + N: float = 1.0 # 总劳动供给 + α: float = 0.33 # 资本份额 + δ: float = 0.05 # 折旧率 +``` + +根据厂商的一阶条件,资本的反需求为 + +```{math} +:label: aiy_egm_rgk + +r = A \alpha \left( \frac{N}{K} \right)^{1 - \alpha} - \delta +``` + +```{code-cell} ipython3 +def r_given_k(K, firm): + """ + 资本的反需求曲线。 + """ + A, N, α, δ = firm + return A * α * (N / K)**(1 - α) - δ +``` + +作为 $r$ 的函数的均衡工资率为 + +```{math} +:label: aiy_egm_wgr + +w(r) = A (1 - \alpha) (A \alpha / (r + \delta))^{\alpha / (1 - \alpha)} +``` + +```{code-cell} ipython3 +def r_to_w(r, firm): + """ + 与给定利率 r 相关的均衡工资。 + """ + A, N, α, δ = firm + return A * (1 - α) * (A * α / (r + δ))**(α / (1 - α)) +``` + +### 均衡 + +一个**平稳理性预期均衡(SREE)**由价格和策略组成,满足: + +* 家庭在给定价格下进行优化 +* 厂商在给定价格下最大化利润 +* 市场出清:资本总供给等于资本总需求 +* 总量在时间上保持恒定 + +## 使用 EGM 的实现 + +### 家庭原语 + +首先我们设置家庭参数和网格: + +```{code-cell} ipython3 +class Household(NamedTuple): + β: float # 贴现因子 + a_grid: jnp.ndarray # 资产网格 + z_grid: jnp.ndarray # 外生状态 + Π: jnp.ndarray # 转移矩阵 + +def create_household(β=0.96, # 贴现因子 + Π=[[0.9, 0.1], [0.1, 0.9]], # 马尔可夫链 + z_grid=[0.1, 1.0], # 外生状态 + a_min=1e-10, a_max=50.0, # 资产网格 + a_size=200): + """ + 创建一个具有自定义网格的 Household namedtuple。 + """ + a_grid = jnp.linspace(a_min, a_max, a_size) + z_grid, Π = map(jnp.array, (z_grid, Π)) + return Household(β=β, a_grid=a_grid, z_grid=z_grid, Π=Π) +``` + +对于效用,我们假设 $u(c) = \log(c)$,这给出 $u'(c) = 1/c$ 和 $(u')^{-1}(x) = 1/x$。 + +```{code-cell} ipython3 +@jax.jit +def u_prime(c): + return 1 / c + +@jax.jit +def u_prime_inv(x): + return 1 / x +``` + +这是价格的 namedtuple: + +```{code-cell} ipython3 +class Prices(NamedTuple): + r: float = 0.01 # 利率 + w: float = 1.0 # 工资 +``` + +### EGM 算子 + +EGM 的关键洞见是通过外生地选择资产网格并直接从欧拉方程计算消费值,来避免求根。 + +使用 EGM 的 Coleman-Reffett 算子工作原理如下: + +1. 从表示在外生(下一期)资产网格 $\{a_i\}$ 上的消费策略 $\sigma$ 开始。 +2. 对于每个资产水平 $a_i$ 和当前就业状态 $z_j$: + - 计算欧拉方程的右侧: + $$\text{RHS} = \beta (1 + r) \sum_{z'} \Pi(z_j, z') \, u'(\sigma(a_i, z'))$$ + - 使用逆边际效用得到当期消费: + $$c_{ij} = (u')^{-1}(\text{RHS})$$ + - 从预算约束恢复隐含的当期资产水平: + $$a_{ij} = \frac{c_{ij} + a_i - w z_j}{1 + r}$$ +3. 通过插值 $(a_{ij}, c_{ij})$ 在原始资产网格上重构新策略 $K\sigma$,并处理借贷约束绑定的情形。 + +整个操作可以很好地向量化,因此我们将其编写为一个 JIT 编译的函数,并在就业状态上使用 `vmap`: + +```{code-cell} ipython3 +@jax.jit +def K_egm(σ, household, prices): + """ + 使用 EGM 的 Coleman-Reffett 算子,用于 Aiyagari 模型。 + + 这里 σ[i, j] 是当下一期资产为 a_grid[i] + 且当前就业状态为 z_grid[j] 时的消费。 + """ + β, a_grid, z_grid, Π = household + r, w = prices + z_size = len(z_grid) + + # 关于下一期冲击的期望 E[u'(c(a', z')) | z] + Eu_prime = (Π @ u_prime(σ).T).T # (a_size, z_size) + + # 欧拉方程 -> 内生网格上的消费 + c_endo = u_prime_inv(β * (1 + r) * Eu_prime) # (a_size, z_size) + + # 隐含的当期资产:a = (c + a' - w z) / (1 + r) + a_endo = (c_endo + a_grid[:, None] - w * z_grid[None, :]) / (1 + r) + + # 为每个就业状态插值回外生网格 + def interp_policy(j): + # 当今日资产低于内生网格时,借贷约束 + # 绑定,因此家庭储蓄 a_grid[0] 并消费 + # 当期收入的其余部分。 + return jnp.where( + a_grid < a_endo[0, j], + w * z_grid[j] + (1 + r) * a_grid - a_grid[0], + jnp.interp(a_grid, a_endo[:, j], c_endo[:, j]) + ) + + σ_new = jax.vmap(interp_policy)(jnp.arange(z_size)) # (z_size, a_size) + return σ_new.T # (a_size, z_size) +``` + +### 求解家庭问题 + +我们通过迭代 EGM 算子直至收敛来求解最优策略。 + +求解器完全 JIT 编译,并使用 `jax.lax.while_loop` 进行迭代: + +```{code-cell} ipython3 +@jax.jit +def solve_household(household, prices, tol=1e-6, max_iter=10_000): + """ + 通过迭代 EGM 算子求解家庭问题。 + + 返回最优消费策略 σ[i, j],其中 i 索引 + 下一期资产,j 索引就业状态。 + """ + β, a_grid, z_grid, Π = household + r, w = prices + + # 初始猜测:消费当期收入的一半 + income = w * z_grid[None, :] + (1 + r) * a_grid[:, None] + σ_init = 0.5 * income + + def condition(state): + i, σ, error = state + return (error > tol) & (i < max_iter) + + def body(state): + i, σ, error = state + σ_new = K_egm(σ, household, prices) + error = jnp.max(jnp.abs(σ_new - σ)) + return i + 1, σ_new, error + + i, σ, error = jax.lax.while_loop(condition, body, (0, σ_init, tol + 1)) + return σ +``` + +让我们在一个示例上测试它: + +```{code-cell} ipython3 +household = create_household() +prices = Prices(r=0.01, w=1.0) + +with qe.Timer(): + σ_star = solve_household(household, prices) + jax.block_until_ready(σ_star) +``` + +我们可以通过测量残差来检查该策略是否是 EGM 算子的不动点: + +```{code-cell} ipython3 +residual = jnp.max(jnp.abs(K_egm(σ_star, household, prices) - σ_star)) +print(f"Final Euler residual: {residual:.2e}") +``` + +让我们绘制得到的策略函数: + +```{code-cell} ipython3 +β, a_grid, z_grid, Π = household +r, w = prices + +# 将消费策略转换为储蓄策略 +income = w * z_grid[None, :] + (1 + r) * a_grid[:, None] +savings = income - σ_star + +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +# 绘制消费策略 +ax = axes[0] +for j, z in enumerate(z_grid): + ax.plot(a_grid, σ_star[:, j], label=f'$z={z:.2f}$', lw=2, alpha=0.7) +ax.set_xlabel('资产 $a$') +ax.set_ylabel('消费 $c$') +ax.set_title('消费策略') +ax.legend() + +# 绘制储蓄策略 +ax = axes[1] +ax.plot(a_grid, a_grid, 'k--', lw=1, alpha=0.5, label='45° 线') +for j, z in enumerate(z_grid): + ax.plot(a_grid, savings[:, j], label=f'$z={z:.2f}$', lw=2, alpha=0.7) +ax.set_xlabel('当期资产 $a$') +ax.set_ylabel("下一期资产 $a'$") +ax.set_title('储蓄策略') +ax.legend() + +plt.tight_layout() +plt.show() +``` + +## 通过模拟计算总资本 + +我们不解析地计算马尔可夫链的平稳分布,而是通过模拟一个大的家庭横截面来计算总资本。 + +这种方法: + +* 更灵活(适用于连续冲击、非线性策略等) +* 避免了存储和操作大型转移矩阵 +* 在概念上更简单 + +模拟是完全向量化的:我们使用 `jax.lax.fori_loop` 同时推进所有家庭,通过逆 CDF 抽样绘制就业转移,并使用 `vmap` 化的插值来查找消费。 + +```{code-cell} ipython3 +@partial(jax.jit, static_argnames=('num_households', 'num_periods')) +def simulate_cross_section(σ, household, prices, key, + num_households=50_000, num_periods=1_000): + """ + 向前模拟家庭面板,并返回资产和就业状态的 + 终端横截面。 + """ + β, a_grid, z_grid, Π = household + r, w = prices + + # Π 每一行的 CDF,用于转移的逆 CDF 抽样 + Π_cdf = jnp.cumsum(Π, axis=1) + + # 向量化的消费查找:为每个 z 沿资产对 σ 进行插值 + @jax.vmap + def consume(a, j): + return jnp.interp(a, a_grid, σ[:, j]) + + # 初始条件:所有人都在网格中间,处于状态 0 + assets = jnp.full(num_households, a_grid[len(a_grid) // 2]) + z_idx = jnp.zeros(num_households, dtype=jnp.int32) + + def step(t, state): + assets, z_idx, key = state + key, subkey = jax.random.split(key) + unif = jax.random.uniform(subkey, (num_households,)) + # 通过逆 CDF 进行马尔可夫转移 + z_idx = (unif[:, None] > Π_cdf[z_idx]).sum(axis=1).astype(jnp.int32) + # 预算约束:消费,然后将资产带到下一期 + income = w * z_grid[z_idx] + (1 + r) * assets + assets = income - consume(assets, z_idx) + # 强制执行资产网格边界 + assets = jnp.clip(assets, a_grid[0], a_grid[-1]) + return assets, z_idx, key + + assets, z_idx, key = jax.lax.fori_loop( + 0, num_periods, step, (assets, z_idx, key) + ) + return assets, z_idx +``` + +现在我们可以通过求解家庭问题并对模拟横截面上的资产取平均,来计算给定价格下的资本供给: + +```{code-cell} ipython3 +def capital_supply(household, prices, key, + num_households=50_000, num_periods=1_000): + """ + 通过模拟计算资本总供给。 + """ + σ = solve_household(household, prices) + assets, _ = simulate_cross_section( + σ, household, prices, key, + num_households=num_households, num_periods=num_periods + ) + return float(jnp.mean(assets)) +``` + +让我们测试它: + +```{code-cell} ipython3 +household = create_household() +prices = Prices(r=0.01, w=1.0) +key = jax.random.PRNGKey(42) + +with qe.Timer(): + K_supply = capital_supply(household, prices, key) + +print(f"Capital supply: {K_supply:.4f}") +``` + +## 计算均衡 + +现在我们可以通过找到使资本供给等于资本需求的资本存量来计算均衡。 + +给定 $K$,均衡映射 $G$ 计算: + +1. 从厂商的一阶条件得到价格 $(r, w)$, +2. 给定这些价格下家庭的最优策略, +3. 通过模拟得到的资本总供给。 + +```{code-cell} ipython3 +def G(K, firm, household, key, + num_households=50_000, num_periods=1_000): + """ + 均衡映射 K -> 资本供给。 + """ + r = r_given_k(K, firm) + w = r_to_w(r, firm) + prices = Prices(r=r, w=w) + return capital_supply(household, prices, key, + num_households=num_households, + num_periods=num_periods) +``` + +我们通过对超额需求 $K - G(K)$ 应用二分法来计算均衡。 + +我们向每次求值传递一个固定的随机 key,使得超额需求函数是确定性的,正如求根器所要求的那样。 + +```{code-cell} ipython3 +def compute_equilibrium(firm, household, key, + K_min=4.0, K_max=12.0, + num_households=50_000, num_periods=1_000, + xtol=1e-2): + """ + 使用二分法计算均衡资本存量。 + """ + def excess_demand(K): + return K - G(K, firm, household, key, + num_households=num_households, + num_periods=num_periods) + + return bisect(excess_demand, K_min, K_max, xtol=xtol) +``` + +让我们计算均衡: + +```{code-cell} ipython3 +firm = Firm() +household = create_household() +key = jax.random.PRNGKey(42) + +with qe.Timer(): + K_star = compute_equilibrium(firm, household, key) + +r_star = r_given_k(K_star, firm) +w_star = r_to_w(r_star, firm) + +print(f"\nEquilibrium capital: {K_star:.4f}") +print(f"Equilibrium interest rate: {r_star:.4f}") +print(f"Equilibrium wage: {w_star:.4f}") +``` + +### 均衡可视化 + +让我们绘制供给和需求曲线: + +```{code-cell} ipython3 +# 供给曲线:作为 r 的函数的家庭供给资本 +r_vals = np.linspace(0.005, 0.04, 10) +K_supply_vals = [] + +for r in r_vals: + w = r_to_w(r, firm) + prices = Prices(r=r, w=w) + K_supply_vals.append(capital_supply(household, prices, key)) + +# 需求曲线:作为 r 的函数的厂商需求资本 +K_vals = np.linspace(4, 12, 50) +r_demand_vals = r_given_k(K_vals, firm) + +fig, ax = plt.subplots(figsize=(10, 6)) + +ax.plot(K_supply_vals, r_vals, 'o-', lw=2, alpha=0.7, + label='资本供给(家庭)', markersize=6) +ax.plot(K_vals, r_demand_vals, lw=2, alpha=0.7, + label='资本需求(厂商)') +ax.plot(K_star, r_star, 'r*', markersize=15, zorder=5, + label=f'均衡 ($K={K_star:.2f}$)') + +ax.set_xlabel('资本 $K$', fontsize=12) +ax.set_ylabel('利率 $r$', fontsize=12) +ax.set_title('Aiyagari 模型均衡', fontsize=14) +ax.legend(fontsize=10) + +plt.tight_layout() +plt.show() +``` + +## 财富分布 + +模拟方法的一个优势是我们可以轻松地检查财富分布。 + +我们重用在均衡价格下模拟的横截面: + +```{code-cell} ipython3 +prices_star = Prices(r=r_star, w=w_star) +σ_star = solve_household(household, prices_star) +assets_dist, z_dist = simulate_cross_section(σ_star, household, prices_star, key) + +assets_dist = np.asarray(assets_dist) +``` + +我们使用 QuantEcon 的 `lorenz_curve` 和 `gini_coefficient` 来概括不平等程度: + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +# 直方图 +ax = axes[0] +ax.hist(assets_dist, bins=50, density=True, alpha=0.7, edgecolor='black') +ax.axvline(np.mean(assets_dist), color='red', linestyle='--', linewidth=2, + label=f'均值 = {np.mean(assets_dist):.3f}') +ax.axvline(np.median(assets_dist), color='orange', linestyle='--', linewidth=2, + label=f'中位数 = {np.median(assets_dist):.3f}') +ax.set_xlabel('资产', fontsize=12) +ax.set_ylabel('密度', fontsize=12) +ax.set_title('财富分布', fontsize=14) +ax.legend() + +# 洛伦兹曲线 +ax = axes[1] +cum_pop, cum_wealth = qe.lorenz_curve(assets_dist) +ax.plot(cum_pop, cum_wealth, lw=2, label='洛伦兹曲线') +ax.plot([0, 1], [0, 1], 'k--', lw=1, alpha=0.5, label='完全平等') +ax.set_xlabel('累积人口份额', fontsize=12) +ax.set_ylabel('累积财富份额', fontsize=12) +ax.set_title('洛伦兹曲线', fontsize=14) +ax.legend() + +plt.tight_layout() +plt.show() + +gini = qe.gini_coefficient(assets_dist) +print(f"\nGini coefficient: {gini:.4f}") +``` + +## 总结与比较 + +本讲座演示了如何使用以下方法求解 Aiyagari 模型: + +1. **内生网格法(EGM)** 用于家庭问题 + - 通过从欧拉方程向后推导,避免了昂贵的求根 + - 直接从边际效用计算消费 + - 比值函数迭代更高效 + +2. **模拟** 用于计算总资本 + - 模拟一个大的家庭横截面 + - 比解析平稳分布更灵活 + - 允许轻松计算财富不平等度量 + +### 与标准方法的比较 + +与 {doc}`标准 Aiyagari 讲座 ` 相比: + +**优势:** + +* EGM 避免了值函数迭代所需的求根 +* 模拟更灵活(适用于连续冲击、非线性策略) +* 易于计算分布统计量(基尼系数、百分位数等) +* 该方法更容易扩展到更复杂的模型 + +**劣势:** + +* 模拟需要大量家庭以保证准确性 +* 均衡计算受蒙特卡洛噪声影响 +* 它不如解析平稳分布精确 + +### 扩展 + +该框架可以轻松扩展到: + +* 连续收入冲击(例如,对数正态分布) +* 更复杂的偏好设定 +* 总量冲击和异质性主体新凯恩斯主义(HANK)模型 +* 具有年龄相关策略的生命周期模型 + +## 练习 + +```{exercise} +:label: aiyagari_egm_ex1 + +比较 EGM 与 {doc}`标准 Aiyagari 讲座 ` 中使用的 +值函数迭代方法的速度和准确性。 + +1. 在相同价格下用两种方法求解家庭问题。 +2. 对两种方法计时并比较得到的策略。 +3. 哪种方法更快?策略是否接近? +``` + +```{exercise} +:label: aiyagari_egm_ex2 + +研究财富分布如何随贴现因子 $\beta$ 变化。 + +1. 计算 $\beta \in \{0.94, 0.95, 0.96, 0.97\}$ 的均衡。 +2. 对于每个 $\beta$,计算并绘制财富分布。 +3. 基尼系数如何随 $\beta$ 变化? +4. 解释其经济直觉。 +``` + +```{exercise} +:label: aiyagari_egm_ex3 + +本讲座介绍的模拟方法使用固定的期数。研究这一选择的影响: + +1. 将 `num_periods` 从 200 变化到 2000。 +2. 对于每个值,用不同的随机 key 多次计算平均资产。 +3. 绘制资本估计的标准差作为 `num_periods` 的函数。 +4. 准确性与计算成本之间的权衡是什么? +``` + +```{exercise} +:label: aiyagari_egm_ex4 + +扩展模型以包含第三种就业状态(例如,失业、兼职、全职): + +1. 建立一个具有适当转移概率的 3 状态马尔可夫链。 +2. 为每个状态定义收入水平。 +3. 重新计算均衡。 +4. 额外的异质性如何影响财富分布? +``` \ No newline at end of file diff --git a/lectures/blackwell_kihlstrom.md b/lectures/blackwell_kihlstrom.md new file mode 100644 index 0000000..bfbbb34 --- /dev/null +++ b/lectures/blackwell_kihlstrom.md @@ -0,0 +1,1380 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 布莱克韦尔的实验比较定理 + headings: + Overview: 概述 + Experiments and stochastic transformations: 实验与随机变换 + Experiments and stochastic transformations::The state space and experiments: 状态空间与实验 + Experiments and stochastic transformations::Stochastic transformations: 随机变换 + Three equivalent criteria: 三个等价标准 + 'Three equivalent criteria::Criterion 1: the economic criterion': 标准 1:经济学标准 + 'Three equivalent criteria::Criterion 2: the sufficiency criterion': 标准 2:充分性标准 + 'Three equivalent criteria::Criterion 3: the uncertainty criterion': 标准 3:不确定性标准 + The main theorem: 主定理 + Kihlstrom's Bayesian interpretation: 基尔斯特罗姆的贝叶斯解释 + Kihlstrom's Bayesian interpretation::Posteriors and standard experiments: 后验与标准实验 + Kihlstrom's Bayesian interpretation::Mean-preserving spreads and Blackwell's order: 均值保持展开与布莱克韦尔序 + Simulating the Blackwell order with many states: 用多状态模拟布莱克韦尔序 + The DeGroot uncertainty function: 德格鲁特不确定性函数 + The DeGroot uncertainty function::Concave uncertainty functions and the value of information: 凹不确定性函数与信息的价值 + The DeGroot uncertainty function::Shannon entropy as a special case: 作为特例的香农熵 + The DeGroot uncertainty function::Value of information as a function of experiment quality: 作为实验质量函数的信息价值 + Connection to second-order stochastic dominance: 与二阶随机占优的关系 + 'Application 1: product quality information': 应用 1:产品质量信息 + 'Application 2: sequential experimental design': 应用 2:序贯实验设计 + Summary: 小结 + The Data Processing Inequality and Coarse-Graining: 数据处理不等式与粗粒化 + The Data Processing Inequality and Coarse-Graining::The DPI for f-divergences: f-散度的 DPI + The Data Processing Inequality and Coarse-Graining::Connection to Blackwell's sufficiency condition: 与布莱克韦尔充分性条件的联系 + 'The Data Processing Inequality and Coarse-Graining::Information geometry: Chentsov''s theorem': 信息几何:陈氏定理 + The Data Processing Inequality and Coarse-Graining::The information bottleneck in machine learning: 机器学习中的信息瓶颈 + The Data Processing Inequality and Coarse-Graining::Summary of the DPI–Blackwell correspondence: DPI-布莱克韦尔对应的小结 + Relation to Bayesian likelihood-ratio learning: 与贝叶斯似然比学习的关系 + Relation to Bayesian likelihood-ratio learning::Summary table: 小结表 +--- + +(blackwell_kihlstrom)= +```{raw} jupyter + +``` + +# 布莱克韦尔的实验比较定理 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + + + +本讲座研究 *布莱克韦尔定理* {cite}`blackwell1951,blackwell1953` ,该定理用于对统计实验进行排序。 + +我们的介绍引入了 {cite:t}`kihlstrom1984` 对布莱克韦尔定理的贝叶斯解释所得到的发现。 + +布莱克韦尔和基尔斯特罗姆研究的统计模型选择问题,与本 QuantEcon 讲座 {doc}`likelihood_bayes` 中遇到的问题密切相关。 + +为了理解其中的关联,理解布莱克韦尔的 **实验** 概念与 {doc}`likelihood_bayes` 中出现的"概率分布"或"参数化统计模型"概念之间的关系是很有帮助的。 + +布莱克韦尔研究的情形是:一个决策者想要知道位于空间 $S$ 中的状态 $s$ 的值。 + +对布莱克韦尔而言,**实验** 是一个 **条件概率模型** $\{\mu(\cdot \mid s) : s \in S\}$ ,即一族由同一状态 $s \in S$ 条件化的概率分布。 + +我们可以自由地将"状态"解释为"参数"或"参数向量"。 + +在两状态情形 $S = \{s_1, s_2\}$ 下,两个条件密度 $f(\cdot) = \mu(\cdot \mid s_1)$ 和 $g(\cdot) = \mu(\cdot \mid s_2)$ 正是我们在本 QuantEcon 讲座 {doc}`likelihood_bayes` 以及本系列 QuantEcon 讲座中其他若干讲座中,反复用于研究经典假设检验和贝叶斯推断的那两个密度。 + +{cite:t}`kihlstrom1984` 将 *哪个实验更具信息量?* 这一问题解释为:询问哪个条件概率模型能让一个对 $\{s_1, s_2\}$ 持有先验的贝叶斯决策者获得更高的期望效用。 + +我们将把"信号"和"实验"作为同义词使用。 + +因此,假设两个信号 $\tilde{x}_\mu$ 和 $\tilde{x}_\nu$ 都对未知状态 $\tilde{s}$ 具有信息量。 + +如果每个贝叶斯决策者用 $\mu$ 都能获得弱高于用 $\nu$ 的期望效用,则称信号 $\mu$ **至少与** 信号 $\nu$ **一样具有信息量**。 + +这个经济学标准等价于两个统计学标准: + +- *充分性*(布莱克韦尔): $\tilde{x}_\nu$ 可以通过对 $\tilde{x}_\mu$ 进行额外的随机化来生成。 +- *不确定性降低*( {cite:t}`degroot1962` ):对每个凹的不确定性函数而言, $\tilde{x}_\mu$ 至少与 $\tilde{x}_\nu$ 一样降低了期望不确定性。 + +基尔斯特罗姆的表述聚焦于 *后验分布*。 + +更具信息量的实验会生成在凸序意义下更为分散的后验分布。 + +在两状态情形下,这就变成了在 $[0, 1]$ 上的均值保持展开比较,可以用检验二阶随机占优的积分 CDF 检验来验证。 + +本讲座的进行方式如下: + +1. 建立记号并将实验定义为马尔可夫矩阵。 +2. 用马尔可夫核定义随机变换。 +3. 陈述三个等价标准。 +4. 陈述主定理并勾勒其证明。 +5. 通过标准实验和均值保持展开建立贝叶斯解释。 +6. 用 Python 模拟来阐释每个概念。 + +我们先进行一些导入。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import minimize +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 实验与随机变换 + +### 状态空间与实验 + +设 $S = \{s_1, \ldots, s_N\}$ 为世界可能状态的有限集合。 + +一个 **实验** 由观测信号 $\tilde{x}$ 在给定状态 $\tilde{s}$ 下的条件分布来描述。 + +当信号空间也是有限的,比如 $X = \{x_1, \ldots, x_M\}$ 时,一个实验就归结为一个 $N \times M$ 的 *马尔可夫矩阵* + +$$ +\mu = [\mu_{ij}], \qquad +\mu_{ij} = \Pr(\tilde{x}_\mu = x_j \mid \tilde{s} = s_i) \geq 0, +\quad \sum_{j=1}^{M} \mu_{ij} = 1 \;\forall\, i. +$$ + +每一行 $i$ 给出了当真实状态为 $s_i$ 时的信号分布。 + + +```{code-cell} ipython3 +μ = np.array([[0.6, 0.3, 0.1], + [0.1, 0.3, 0.6]]) + +Q = np.array([[1.0, 0.0], + [0.5, 0.5], + [0.0, 1.0]]) + +ν = μ @ Q + +print("实验 μ(3 个信号,各行之和为 1):") +print(μ) +print("\n随机变换 Q(3 × 2):") +print(Q) +print("\n实验 ν = μ @ Q(2 个信号):") +print(ν) +print("\nμ 的行和:", μ.sum(axis=1)) +print("ν 的行和:", ν.sum(axis=1)) +``` + +### 随机变换 + +**随机变换** $Q$ 通过进一步的随机化将一个实验的信号映射为另一个实验的信号。 + +在具有 $M$ 个输入信号和 $K$ 个输出信号的离散设定下, $Q$ 是一个 $M \times K$ 的马尔可夫矩阵:对每一行 $l$ 有 $q_{lk} \geq 0$ 且 $\sum_k q_{lk} = 1$ 。 + +```{prf:definition} 充分性 +:label: def-sufficiency + +如果存在一个随机变换 $Q$ (一个 $M \times K$ 的马尔可夫矩阵)使得 + +$$ +\nu = \mu \, Q, +$$ + +则称实验 $\mu$ *对* $\nu$ *充分*,这意味着一个观测到 $\tilde{x}_\mu$ 的观察者可以通过将其信号传递给 $Q$ 来生成 $\tilde{x}_\nu$ 的分布。 +``` + +如果你观测到更具信息量的信号 $\tilde{x}_\mu$ ,那么你总是可以 *丢弃* 信息来重现一个信息量较少的信号。 + +反过来则不可能:一个信息量较少的信号无法被丰富到恢复出所丢失的信息。 + +我们可以用上面定义的两个实验 $\mu$ 和 $\nu$ 来进行数值验证。 + +下面的函数搜索一个使 $\|\nu - \mu \, Q\|$ 最小化的随机变换 $Q$ 。 + +如果存在一个精确的 $Q$ ,残差将接近于零;否则残差会很大。 + +```{code-cell} ipython3 +def find_stochastic_transform(μ, ν, tol=1e-8): + """ + 寻找一个行随机矩阵 Q,使 ||ν - μ @ Q|| 最小化。 + """ + _, M = μ.shape + _, K = ν.shape + + def unpack(q_flat): + return q_flat.reshape(M, K) + + def objective(q_flat): + Q = unpack(q_flat) + return np.linalg.norm(ν - μ @ Q)**2 + + constraints = [ + {"type": "eq", "fun": lambda q_flat, + row=i: unpack(q_flat)[row].sum() - 1.0} + for i in range(M) + ] + bounds = [(0.0, 1.0)] * (M * K) + Q0 = np.full((M, K), 1 / K).ravel() + + result = minimize( + objective, + Q0, + method="SLSQP", + bounds=bounds, + constraints=constraints, + options={"ftol": tol, "maxiter": 1_000}, + ) + + Q = unpack(result.x) + residual = np.linalg.norm(ν - μ @ Q) + return Q, residual + +# 正向:寻找使 ν = μ @ Q 的 Q(应当成功) +Q_fwd, res_fwd = find_stochastic_transform(μ, ν) +print("正向(μ 到 ν):") +print(f" 残差 = {res_fwd:.2e}") +print(f" 存在精确变换:{res_fwd < 1e-6}") + +# 反向:寻找使 μ = ν @ Q' 的 Q'(应当失败) +Q_rev, res_rev = find_stochastic_transform(ν, μ) +print("\n反向(ν 到 μ):") +print(f" 残差 = {res_rev:.2e}") +print(f" 存在精确变换:{res_rev < 1e-6}") +``` + +正向残差接近于零:存在一个从 $\mu$ 到 $\nu$ 的随机变换,这证实了 $\mu$ 对 $\nu$ 充分。 + +反向残差很大:没有任何随机变换能从 $\nu$ 恢复出 $\mu$ 。 + +没有任何随机变换能够撤销这种信息损失。 + +关键在于,随机变换的逆一般来说并不是一个随机变换。 + +事实上,唯一其逆也是随机变换的随机变换是置换矩阵,它仅仅重新标记信号而不损失任何信息。 + +## 三个等价标准 + +布莱克韦尔定理确立了比较实验的三种不同方式最终都是等价的。 + +### 标准 1:经济学标准 + +第一个标准通过实验对决策者的价值来比较实验。 + +设 $A$ 为一个紧凸的行动集合, $u: A \times S \to \mathbb{R}$ 为一个有界效用函数。 + +决策者观测到 $x \in X$ ,通过贝叶斯规则更新对 $\tilde{s}$ 的信念,并选择 $d(x) \in A$ 以最大化期望效用。 + +设 $p = (p_1, \ldots, p_N)$ 为状态上的先验,并记 + +$$ +P = \bigl\{(p_1, \ldots, p_N) : p_i \geq 0,\; \textstyle\sum_i p_i = 1\bigr\} +$$ + +为概率单纯形。 + +对固定的 $A$ 和 $u$ ,在实验 $\mu$ 下的 *可达期望效用向量集合* 为 + +$$ +B(\mu, A, u) = \Bigl\{v \in \mathbb{R}^N : + v_i = \textstyle\int_X u(f(x), s_i)\,\mu_i(dx) + \text{ for some measurable } f: X \to A \Bigr\}. +$$ + +```{prf:definition} 经济学标准 +:label: def-economic-criterion + +如果对每个紧凸行动集 $A$ 和每个有界效用函数 $u: A \times S \to \mathbb{R}$ 都有 + +$$ +B(\mu, A, u) \supseteq B(\nu, A, u) +$$ + +则称 $\mu$ 在经济学意义上 **至少与** $\nu$ **一样具有信息量**。 +``` + +这个标准说的是:如果决策者在看到 $\nu$ 后所能达到的任何结果,在看到 $\mu$ 后也都能达到,那么实验 $\mu$ 就优于实验 $\nu$ 。 + +其原因在于,一个更具信息量的实验允许决策者通过 *忽略* 或 *混淆* 部分额外信息来模仿一个信息量较少的实验。 + +但反过来则未必可能。 + +因此 $B(\mu, A, u) \supseteq B(\nu, A, u)$ 意味着 $\mu$ 给决策者提供的可行期望效用结果至少与 $\nu$ 一样多。 + +等价地,对每个先验 $p \in P$ ,每个贝叶斯决策者用 $\tilde{x}_\mu$ 都能获得弱高于用 $\tilde{x}_\nu$ 的期望效用。 + +### 标准 2:充分性标准 + +第二个标准使用了上面引入的随机变换思想。 + +```{prf:definition} 布莱克韦尔充分性 +:label: def-blackwell-sufficiency + +如果存在一个从 $\mu$ 的信号空间到 $\nu$ 的信号空间的随机变换 $Q$ ,使得 + +$$ +\nu_i(E) = (Q \circ \mu_i)(E) +\quad \forall\, E \in \mathscr{G},\; i = 1, \ldots, N. +$$ + +则称 $\mu \geq \nu$ 在布莱克韦尔意义下成立。 +``` + +对有限实验,用矩阵记号表示: $\nu = \mu \, Q$ 。 + +### 标准 3:不确定性标准 + +第三个标准通过实验对状态不确定性的降低程度来比较实验。 + +{cite:t}`degroot1962` 把任何凹函数 $U: P \to \mathbb{R}$ 称为 **不确定性函数**。 + +典型的例子是香农熵: + +$$ +U(p) = -\sum_{i=1}^{N} p_i \log p_i. +$$ + +```{prf:definition} 德格鲁特不确定性标准 +:label: def-degroot-uncertainty + +如果对每个先验 $p \in P$ 和每个凹函数 $U: P \to \mathbb{R}$ 都有 + +$$ +\int_P U(q)\,\hat\mu^p(dq) +\;\leq\; +\int_P U(q)\,\hat\nu^p(dq), +$$ + +其中 $\hat\mu^p$ 是实验 $\mu$ 在先验 $p$ 下诱导的后验信念分布,则称 $\mu$ **至少与** $\nu$ **一样地降低了期望不确定性**。 +``` + +为看清这一点,设 $Q = p^\mu(X)$ 表示由实验 $\mu$ 诱导的随机后验。 + +那么 $Q$ 服从分布 $\hat\mu^p$ ,因此 + +$$ +\mathbb{E}[U(Q)] = \int_P U(q)\,\hat\mu^p(dq). +$$ + +由于 $U$ 是凹的,詹森不等式给出 + +$$ +\mathbb{E}[U(Q)] \leq U(\mathbb{E}[Q]) = U(p). +$$ + +因此 + +$$ +\int_P U(q)\,\hat\mu^p(dq) \leq U(p), +$$ + +所以任何实验都会弱地降低期望不确定性。 + +基尔斯特罗姆的标准实验构造稍后会让我们在均匀先验 $c = (1 / N, \ldots, 1 / N)$ 下比较后验分布。 + +## 主定理 + +```{prf:theorem} 布莱克韦尔定理 +:label: thm-blackwell + +以下三个条件等价: + +(i) 经济学标准:对每个紧凸 $A$ 和每个有界效用函数 $u$ 都有 $B(\mu, A, u) \supseteq B(\nu, A, u)$ 。 + +(ii) 充分性标准:存在一个从 $\mu$ 的信号空间到 $\nu$ 的信号空间的随机变换 $Q$ ,使得 $\nu = Q \circ \mu$ 。 + +(iii) 不确定性标准:对每个先验 $p \in P$ 和每个凹函数 $U$ 都有 $\int_P U(q)\,\hat\mu^p(dq) \leq \int_P U(q)\,\hat\nu^p(dq)$ 。 +``` + +另见 {cite:t}`blackwell1951` 、 {cite:t}`bonnenblust1949` 和 {cite:t}`degroot1962` 。 + +最困难的部分是经济学标准与充分性标准之间的等价性。 + +*概要(ii $\Rightarrow$ i):* 如果 $\nu = \mu Q$ ,那么任何基于 $\tilde{x}_\nu$ 的决策规则都可以通过如下方式复现:先观测 $\tilde{x}_\mu$ ,再从 $Q$ 中抽取一个合成的 $\tilde{x}_\nu$ ,然后应用同样的规则。 + +*概要(i $\Rightarrow$ ii):* 由于对每个 $A$ 和 $u$ 都有 $B(\mu, A, u) \supseteq B(\nu, A, u)$ ,一个分离超平面(对偶)论证意味着存在一个后验空间中的均值保持核 $D$ ,将 $\nu$ 的标准实验送入 $\mu$ 的标准实验。再从这些后验律回到原始信号空间就得到所需的混淆 $Q$ ,满足 $\nu = \mu Q$ 。因此 $D$ 是后验信念上的中间随机化,而非字面意义上的信号空间核 $Q$ 。 + +*概要(ii $\Rightarrow$ iii):* 在混淆之下,较粗实验的后验是较细实验后验的条件期望,因此詹森不等式对每个凹函数 $U$ 都给出该结果。 + +*概要(iii $\Rightarrow$ ii):* 其逆命题,即对所有凹函数 $U$ 的不等式迫使 $Q$ 存在,在 {cite}`blackwell1953` 中得到证明。基尔斯特罗姆基于后验的表示使这一几何变得透明。 + +## 基尔斯特罗姆的贝叶斯解释 + +### 后验与标准实验 + +基尔斯特罗姆分析中的关键对象是 *后验信念向量*。 + +当先验 $p$ 成立且实验 $\mu$ 产生信号 $x$ 时,贝叶斯规则给出 + +$$ +p_i^\mu(x) = \Pr(\tilde{s} = s_i \mid \tilde{x}_\mu = x) += \frac{\mu_{ix} \, p_i}{\sum_j \mu_{jx}\, p_j}, \qquad i = 1, \ldots, N. +$$ + +后验 $p^\mu(x) \in P$ 是单纯形中的一个随机点。 + +```{prf:property} 均值保持 +:label: prop-mean-preservation + +先验 $p$ 是后验的期望: + +$$ +\mathbb{E}[p^\mu] = \sum_x \Pr(\tilde{x}_\mu = x)\, p^\mu(x) = p. +$$ + +这有时被称为 *信念的迭代期望定律*。 +``` + +对固定的先验 $c$ ,基尔斯特罗姆的 **标准实验** 用 $\mu$ 所生成的后验信念来替换其原始信号。 + +设 $\hat\mu^c$ 表示由 $\mu$ 在先验 $c$ 下诱导的后验分布。 +均值保持意味着 $\int_P q \, \hat\mu^c(dq) = c$ 。 + +当两个实验诱导相同的后验分布时,称它们 **信息等价**。 + +标准实验剥离了信号除后验以外的所有细节,因此它提供了用于比较实验的一个规范的贝叶斯表示。 + +后验信念上的随机核存在于单纯形 $P$ 上,而布莱克韦尔混淆 $Q$ 存在于原始信号空间上。基尔斯特罗姆的构造使用前者来研究凸序,然后在过渡到标准实验之后恢复后者。 + +任何两个生成相同后验分布的实验,都会导致每个贝叶斯决策者做出完全相同的决策,无论它们的原始信号空间看起来多么不同。 + +### 均值保持展开与布莱克韦尔序 + +基尔斯特罗姆的关键重述如下。 + +```{prf:theorem} 基尔斯特罗姆的重述 +:label: thm-kihlstrom + +$\mu \geq \nu$ 在布莱克韦尔意义下成立,当且仅当 $\hat\mu^c$ 是 $\hat\nu^c$ 的一个 +**均值保持展开**;即,对每个凸函数 $g: P \to \mathbb{R}$ 都有 + +$$ +\int_P g(p)\,\hat\mu^c(dp) \;\geq\; \int_P g(p)\,\hat\nu^c(dp) +$$ + +。 +``` + +等价地, $\hat\mu^c$ 在凸序意义下大于 $\hat\nu^c$ 。 + +一个更好的实验会将后验信念推向离先验更远的地方,同时保持它们的均值不变。 + +为了具体地看到这一点,我们为两状态情形定义两个实验并计算它们的后验。 + +```{code-cell} ipython3 +def compute_posteriors(μ, prior, tol=1e-14): + """ + 为每个信号实现计算后验分布。 + """ + N, M = μ.shape + signal_probs = μ.T @ prior + numerators = μ.T * prior + posteriors = np.zeros((M, N)) + np.divide( + numerators, + signal_probs[:, None], + out=posteriors, + where=signal_probs[:, None] > tol, + ) + return posteriors, signal_probs + + +def check_mean_preservation(posteriors, signal_probs, prior): + """验证 E[后验] == 先验。""" + expected_posterior = (posteriors * signal_probs[:, None]).sum(axis=0) + return expected_posterior, np.allclose(expected_posterior, prior) + + +N = 2 +prior = np.array([0.5, 0.5]) + +μ_info = np.array([[0.8, 0.2], + [0.2, 0.8]]) + +ν_info = np.array([[0.6, 0.4], + [0.4, 0.6]]) + +post_μ, probs_μ = compute_posteriors(μ_info, prior) +post_ν, probs_ν = compute_posteriors(ν_info, prior) + +print("实验 μ(更具信息量):\n") +print("信号概率:", probs_μ.round(3)) +print("后验(行 = 信号,列 = 状态):") +print(post_μ.round(3)) +mean_μ, ok_μ = check_mean_preservation(post_μ, probs_μ, prior) +print(f"E[后验] = {mean_μ.round(4)} (等于先验:{ok_μ})") + +print("\n 实验 ν(信息量较少):\n") +print("信号概率:", probs_ν.round(3)) +print("后验:") +print(post_ν.round(3)) +mean_ν, ok_ν = check_mean_preservation(post_ν, probs_ν, prior) +print(f"E[后验] = {mean_ν.round(4)} (等于先验:{ok_ν})") +``` + +对 $N = 2$ 个状态,单纯形 $P$ 是单位区间 $[0, 1]$ (状态 $s_1$ 的概率)。 + +我们可以直接绘制在实验 $\mu$ 和 $\nu$ 下的后验分布。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 两状态情形下的后验分布 + name: fig-blackwell-two-state-posteriors +--- +def plot_posterior_distributions(μ_matrix, ν_matrix, prior, + labels=("μ(更具信息量)", + "ν(信息量较少)")): + """ + 对两状态实验,绘制 [0,1] 上的后验分布 + (即标准实验分布)。 + """ + posts_μ, probs_μ = compute_posteriors(μ_matrix, prior) + posts_ν, probs_ν = compute_posteriors(ν_matrix, prior) + + fig, axes = plt.subplots(1, 2, figsize=(11, 4), sharey=False) + prior_val = prior[0] + + for ax, posts, probs, label in zip( + axes, [posts_μ, posts_ν], [probs_μ, probs_ν], labels): + p_s1 = posts[:, 0] + ax.vlines(p_s1, 0, probs, linewidth=6, color="steelblue", alpha=0.7) + ax.axvline(prior_val, color="tomato", linestyle="--", linewidth=2, + label=f"先验 = {prior_val:.2f}") + ax.set_xlim(0, 1) + ax.set_xlabel(r"后验 $p(s_1 \mid x)$", fontsize=12) + ax.set_ylabel("概率质量", fontsize=12) + mean_post = (p_s1 * probs).sum() + ax.axvline(mean_post, color="green", linestyle=":", linewidth=2, + label=f"E[后验] = {mean_post:.2f}") + ax.text(0.03, 0.94, label, transform=ax.transAxes, va="top") + ax.legend() + + plt.tight_layout() + plt.show() + +plot_posterior_distributions(μ_info, ν_info, prior) +``` + +这就是均值保持展开的实际体现:两个分布具有相同的均值(等于先验),但更具信息量的实验 $\mu$ 将其后验展开得更远。 + +我们可以数值地验证均值保持展开条件。 + +关键事实在于,至多相差一个仿射项,任何凸函数都可以表示为"看涨期权"收益 $g_t(p) = \max(p - t, 0)$ 的混合。 + +由于被比较的两个后验分布具有相同的均值,那个仿射项在比较中会相互抵消。 + +因此只需对所有阈值 $t \in [0, 1]$ 检验 $E[g_t(p^\mu)] \geq E[g_t(p^\nu)]$ 即可。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 两状态情形下的凸序检验 + name: fig-blackwell-convex-order-check +--- +def check_mps_convex_functions(μ_matrix, ν_matrix, prior, n_functions=200): + """ + 使用凸函数 g(p) = max(p - t, 0) 验证 + 均值保持展开条件。 + """ + posts_μ, probs_μ = compute_posteriors(μ_matrix, prior) + posts_ν, probs_ν = compute_posteriors(ν_matrix, prior) + + p_μ = posts_μ[:, 0] + p_ν = posts_ν[:, 0] + + thresholds = np.linspace(0, 1, n_functions) + diffs = [] + for t in thresholds: + Eg_μ = (np.maximum(p_μ - t, 0) * probs_μ).sum() + Eg_ν = (np.maximum(p_ν - t, 0) * probs_ν).sum() + diffs.append(Eg_μ - Eg_ν) + + fig, ax = plt.subplots(figsize=(8, 4)) + ax.plot(thresholds, diffs, color="steelblue", linewidth=2) + ax.axhline(0, color="tomato", linestyle="--", linewidth=2) + ax.fill_between(thresholds, diffs, 0, + where=np.array(diffs) >= 0, + alpha=0.25, color="steelblue", + label="$E[g(p^μ)] - E[g(p^ν)] \\geq 0$") + ax.set_xlabel("阈值 $t$", fontsize=12) + ax.set_ylabel(r"$E[\max(p-t,0)]$ 差值", fontsize=12) + ax.legend(fontsize=11) + plt.tight_layout() + plt.show() + + all_non_negative = all(d >= -1e-10 for d in diffs) + print(f"μ 是 ν 的均值保持展开:{all_non_negative}") + return diffs + +_ = check_mps_convex_functions(μ_info, ν_info, prior) +``` + +差值 $E[g_t(p^\mu)] - E[g_t(p^\nu)]$ 对每个阈值 $t$ 都是非负的,这证实了 $\hat\mu^c$ 是 $\hat\nu^c$ 的均值保持展开,因此在布莱克韦尔序中 $\mu \geq \nu$ 。 + +## 用多状态模拟布莱克韦尔序 + +我们现在转到一个三状态的例子。 + +实验 $\mu$ 与状态强相关,而实验 $\nu$ 是 $\mu$ 的一个混淆。 + +```{code-cell} ipython3 +N3 = 3 +prior3 = np.array([1/3, 1/3, 1/3]) + +μ3 = np.array([[0.7, 0.2, 0.1], + [0.1, 0.7, 0.2], + [0.2, 0.1, 0.7]]) + +Q3 = np.array([[0.9, 0.05, 0.05], + [0.05, 0.8, 0.15], + [0.05, 0.15, 0.8]]) + +ν3 = μ3 @ Q3 + +print("μ (3×3):") +print(np.round(μ3, 2)) +print("\nQ(混淆):") +print(np.round(Q3, 2)) +print("\nν = μ @ Q:") +print(np.round(ν3, 3)) +``` + + +对三个状态,后验信念存在于一个 2-单纯形中。 + +让我们可视化在 $\mu$ 和 $\nu$ 下采样的后验点 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 2-单纯形上采样的后验点 + name: fig-blackwell-simplex-clouds +--- +def sample_posteriors(μ_matrix, prior, n_draws=3000, rng=None): + """ + 从实验中模拟 n_draws 个观测并计算 + 由此得到的后验信念。 + 返回形状为 (n_draws, N) 的数组。 + """ + if rng is None: + rng = np.random.default_rng() + N, M = μ_matrix.shape + states = rng.choice(N, size=n_draws, p=prior) + signals = np.array([rng.choice(M, p=μ_matrix[s]) for s in states]) + posteriors, _ = compute_posteriors(μ_matrix, prior) + return posteriors[signals] + + +def simplex_to_cart(pts): + """将 3-单纯形重心坐标转换为二维笛卡尔坐标。""" + corners = np.array([[0.0, 0.0], + [1.0, 0.0], + [0.5, np.sqrt(3)/2]]) + return pts @ corners + + +def plot_simplex_posteriors(μ_matrix, ν_matrix, prior3, n_draws=3000, seed=0): + rng = np.random.default_rng(seed) + posts_μ = sample_posteriors(μ_matrix, prior3, n_draws, rng=rng) + posts_ν = sample_posteriors(ν_matrix, prior3, n_draws, rng=rng) + + cart_μ = simplex_to_cart(posts_μ) + cart_ν = simplex_to_cart(posts_ν) + prior_cart = simplex_to_cart(prior3[None, :])[0] + + corners = np.array([[0.0, 0.0], + [1.0, 0.0], + [0.5, np.sqrt(3)/2]]) + + fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + panel_labels = ["μ(更具信息量)", "ν(被混淆)"] + data = [(cart_μ, "steelblue"), (cart_ν, "darkorange")] + labels = ["$s_1$", "$s_2$", "$s_3$"] + offsets = [(-0.07, -0.05), (0.02, -0.05), (-0.02, 0.03)] + + for ax, (cart, c), panel_label in zip(axes, data, panel_labels): + tri = plt.Polygon(corners, fill=False, edgecolor="black", linewidth=2) + ax.add_patch(tri) + ax.scatter(cart[:, 0], cart[:, 1], s=4, alpha=0.25, color=c) + ax.scatter(*prior_cart, s=120, color="red", zorder=5, + label="先验", marker="*") + for i, (lbl, off) in enumerate(zip(labels, offsets)): + ax.text(corners[i][0] + off[0], corners[i][1] + off[1], + lbl, fontsize=13) + ax.set_xlim(-0.15, 1.15) + ax.set_ylim(-0.1, np.sqrt(3)/2 + 0.1) + ax.set_aspect("equal") + ax.set_xticks([]) + ax.set_yticks([]) + ax.text(0.03, 0.94, panel_label, transform=ax.transAxes, va="top") + ax.legend(fontsize=11, loc="upper right") + + plt.tight_layout() + plt.show() + +plot_simplex_posteriors(μ3, ν3, prior3) +``` + +由于这个例子只有三个信号,每个面板由重复采样的三个后验原子构成,而非一个连续的点云。 + +在 $\mu$ 下,采样的后验点向顶点延伸得更远。 + +在被混淆的实验 $\nu$ 下,采样的后验点更靠近中心。 + +## 德格鲁特不确定性函数 + +### 凹不确定性函数与信息的价值 + +{cite}`degroot1962` 通过 **不确定性函数** $U: P \to \mathbb{R}$ 将信息的价值形式化。 + +在德格鲁特的公理化中,不确定性函数是: + +- *凹的*:由詹森不等式,观测任何信号都弱地降低期望不确定性。 +- *对称的*:它依赖于 $p$ 的各分量,而不依赖于它们的标记。 +- *归一化的*:它在 $p = (1/N, \ldots, 1/N)$ 处取最大值,在顶点处取最小值。 + +*在给定先验 $p$ 下实验 $\mu$ 的价值* 为 + +$$ +I(\tilde{x}_\mu;\, \tilde{s};\, U) += U(p) - \mathbb{E}[U(p^\mu)], +$$ + +这个量是不确定性的期望降低量。 + +布莱克韦尔序等价于以下陈述:对 *每个* 凹函数 $U$ 都有 $I(\tilde{x}_\mu; \tilde{s}; U) \geq I(\tilde{x}_\nu; \tilde{s}; U)$ 。 + +### 作为特例的香农熵 + +规范的不确定性函数是香农熵 + +$$ +U_H(p) = -\sum_{i=1}^{N} p_i \log p_i. +$$ + +在均匀先验 $c = (1/N, \ldots, 1/N)$ 下,德格鲁特的价值公式变为 + +$$ +I(\tilde{x}_\mu, c;\, U_H) += \log N - H(\tilde{s} \mid \tilde{x}_\mu), +$$ + +其中 $H(\tilde{s} \mid \tilde{x}_\mu)$ 是给定信号时状态的条件熵。 + +要看清原因,将 $H(\tilde{s} \mid \tilde{x}_\mu) = \sum_x \Pr(\tilde{x}_\mu = x) \, H(\tilde{s} \mid \tilde{x}_\mu = x)$ 写出,其中每个条件熵项等于 $-\sum_i p_i^\mu(x) \log p_i^\mu(x) = U_H(p^\mu(x))$ 。 + +代入德格鲁特公式得到 $I = U_H(c) - \mathbb{E}[U_H(p^\mu)] = \log N - H(\tilde{s} \mid \tilde{x}_\mu)$ ,这正是 $\tilde{x}_\mu$ 与 $\tilde{s}$ 之间的 *互信息*。 + +```{note} +布莱克韦尔序蕴含基于熵的不等式,但 *其逆命题不成立*:仅凭熵无法确定完整的布莱克韦尔序。 + +两个实验可以具有相同的互信息却在布莱克韦尔排序中不同,因为单个凹函数无法检测出后验分散度上的所有差异。 + +完整的布莱克韦尔序要求不等式对 *每个* 凹函数 $U$ 都成立,而不仅仅是香农熵。 +``` + +```{code-cell} ipython3 +def entropy(p, ε=1e-12): + """概率向量的香农熵。""" + p = np.asarray(p, dtype=float) + p = np.clip(p, ε, 1.0) + return -np.sum(p * np.log(p)) + + +def degroot_value(μ_matrix, prior, U_func): + """ + 计算德格鲁特信息价值 I = U(先验) - E[U(后验)]。 + """ + posts, probs = compute_posteriors(μ_matrix, prior) + prior_uncertainty = U_func(prior) + expected_post_uncertainty = sum( + probs[j] * U_func(posts[j]) for j in range(len(probs))) + return prior_uncertainty - expected_post_uncertainty + + +def gini_impurity(p): + """基尼不纯度:1 - sum(p_i^2)。""" + return 1.0 - np.sum(np.asarray(p)**2) + + +def tsallis_entropy(p, q=2): + """q 阶查理斯熵(q>1 时为凹)。""" + p = np.clip(p, 1e-12, 1.0) + return (1 - np.sum(p**q)) / (q - 1) + + +def tsallis_q15(p): + """q=1.5 的查理斯熵,用于独立的凹性检验。""" + return tsallis_entropy(p, q=1.5) + + +def sqrt_index(p): + """基于 sum(sqrt(p_i)) 的凹不确定性指数。""" + p = np.clip(np.asarray(p), 0.0, 1.0) + return np.sum(np.sqrt(p)) - 1.0 + +uncertainty_functions = { + "Shannon entropy": entropy, + "Gini impurity": gini_impurity, + "Tsallis (q=1.5)": tsallis_q15, + "Square-root index": sqrt_index, +} + +header = (f"{'Uncertainty function':<22} " + f"{'I(μ)':<10} {'I(ν)':<10} " + f"{'I(μ)>=I(ν)?'}") +print(header) +print("-" * 58) +for name, U in uncertainty_functions.items(): + I_μ = degroot_value(μ_info, prior, U) + I_ν = degroot_value(ν_info, prior, U) + print(f"{name:<22} {I_μ:<10.4f} {I_ν:<10.4f} {I_μ >= I_ν - 1e-10}") +``` + +正如定理所预测的那样,一旦我们知道 $\mu \geq \nu$ 在布莱克韦尔意义下成立,那么对每个凹不确定性函数都有 $I(\mu) \geq I(\nu)$ 。 + +### 作为实验质量函数的信息价值 + +我们现在将介于无信息量和完全有信息量之间的实验连续统参数化。 + +对 $N = 2$ 个状态,一个自然的族是 + +$$ +\mu(\theta) = (1 - \theta) \cdot \tfrac{1}{2}\mathbf{1}\mathbf{1}^\top + + \theta \cdot I_2, +\quad \theta \in [0, 1], +$$ + +第一项是完全混合的矩阵, $I_2$ 是单位矩阵。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 信息价值与实验质量 + name: fig-blackwell-value-by-quality +--- +def make_experiment(θ, N=2): + """参数化实验:θ=0 无信息量,θ=1 完全有信息量。""" + return (1 - θ) * np.ones((N, N)) / N + θ * np.eye(N) + + +θs = np.linspace(0, 1, 100) +prior2 = np.array([0.5, 0.5]) + +fig, ax = plt.subplots(figsize=(9, 4)) +for name, U in uncertainty_functions.items(): + values = [degroot_value(make_experiment(θ), prior2, U) for θ in θs] + vmin, vmax = values[0], values[-1] + normed = (np.array(values) - vmin) / (vmax - vmin + 1e-15) + ax.plot(θs, normed, label=name, linewidth=2) + +ax.set_xlabel("实验质量 θ(0 = 无信息量,1 = 完全有信息量)", + fontsize=11) +ax.set_ylabel("归一化信息价值 I(μ(θ))", fontsize=11) +ax.legend(fontsize=10) +plt.tight_layout() +plt.show() +``` + +每个凹不确定性函数都会给更具信息量的实验赋予弱更高的价值。 + +## 与二阶随机占优的关系 + +如果对每个凹函数 $u$ 都有 $E[u(X)] \geq E[u(Y)]$ ,则称随机变量 $X$ **二阶随机占优** +$Y$ (记作 $X \succeq_{\text{SOSD}} Y$ )。 +等价地, $Y$ 是 $X$ 的一个均值保持展开。 + +不确定性函数表示使得与 SOSD 的联系变得明确。 + +由于 $U$ 是凹的, $-U$ 是凸的,因此条件 + +$$ +\mathbb{E}[U(p^\mu)] \leq \mathbb{E}[U(p^\nu)] \quad \text{for all concave } U +$$ + +正是 $\hat\mu^c$ 在 $P$ 上以凸序占优 $\hat\nu^c$ 的陈述。 + +当 $N = 2$ 时,后验信念是 $[0, 1]$ 中的标量,SOSD 比较简化为经典的积分 CDF 检验。 + +具体地, $\hat\mu^c$ 是 $\hat\nu^c$ 的均值保持展开,当且仅当对所有 $t \in [0,1]$ 都有 $\int_0^t F_\mu(s)\,ds \geq \int_0^t F_\nu(s)\,ds$ ,其中 $F_\mu$ 和 $F_\nu$ 是每个实验下 $s_1$ 后验的 CDF。等价地,用 SOSD 的语言来说,$\nu$ 下信息量较少的后验占优于 $\mu$ 下更为分散的后验。 + +我们可以对上面的两状态例子在图形上验证这一点 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 两状态情形下的积分 CDF 检验 + name: fig-blackwell-integrated-cdf +--- +def cdf_data_1d(weights, values): + """对离散分布排序支撑点和累积质量。""" + idx = np.argsort(values) + sorted_vals = values[idx] + sorted_wts = weights[idx] + cum_mass = np.cumsum(sorted_wts) + return sorted_vals, cum_mass + + +def plot_sosd_posteriors(μ_matrix, ν_matrix, prior): + """为 s1 上的后验分布绘制 CDF 和积分 CDF。""" + posts_μ, probs_μ = compute_posteriors(μ_matrix, prior) + posts_ν, probs_ν = compute_posteriors(ν_matrix, prior) + + p_μ = posts_μ[:, 0] + p_ν = posts_ν[:, 0] + + sv_μ, cm_μ = cdf_data_1d(probs_μ, p_μ) + sv_ν, cm_ν = cdf_data_1d(probs_ν, p_ν) + + fig, axes = plt.subplots(1, 2, figsize=(11, 4)) + + ax = axes[0] + for sv, cm, lbl, c in [(sv_μ, cm_μ, "μ", "steelblue"), + (sv_ν, cm_ν, "ν", "darkorange")]: + xs = np.concatenate([[0], sv, [1]]) + ys = np.concatenate([[0], cm, [1]]) + ax.step(xs, ys, where="post", label=lbl, color=c, linewidth=2) + ax.axvline(prior[0], linestyle="--", color="gray", alpha=0.6, linewidth=2, + label="先验") + ax.set_xlabel(r"后验 $p(s_1 \mid x)$", fontsize=12) + ax.set_ylabel("累积概率", fontsize=12) + ax.text(0.03, 0.94, "CDF", transform=ax.transAxes, va="top") + ax.legend(fontsize=11) + + ax2 = axes[1] + grid = np.linspace(0, 1, 200) + + def integrated_cdf(sorted_vals, cum_mass, grid): + cdf = np.array([cum_mass[sorted_vals <= t].max() + if np.any(sorted_vals <= t) else 0.0 + for t in grid]) + return np.cumsum(cdf) * (grid[1] - grid[0]) + + int_μ = integrated_cdf(sv_μ, cm_μ, grid) + int_ν = integrated_cdf(sv_ν, cm_ν, grid) + + ax2.plot(grid, int_μ, label=r"$\int F_\mu$", color="steelblue", linewidth=2) + ax2.plot(grid, int_ν, color="darkorange", + label=r"$\int F_\nu$", linewidth=2) + ax2.fill_between(grid, int_ν, int_μ, + where=int_μ >= int_ν, + alpha=0.2, color="steelblue", + label=(r"$\int F_\mu \geq \int F_\nu$" + r" ($\mu$ 是 $\nu$ 的 MPS)")) + ax2.set_xlabel(r"$t$", fontsize=12) + ax2.set_ylabel("积分 CDF", fontsize=12) + ax2.text(0.03, 0.94, "积分 CDF", transform=ax2.transAxes, va="top") + ax2.legend(fontsize=10) + + plt.tight_layout() + plt.show() + +plot_sosd_posteriors(μ_info, ν_info, prior) +``` + +## 应用 1:产品质量信息 + +{cite:t}`kihlstrom1974a` 将布莱克韦尔定理应用于消费者对产品质量信息的需求。 + +- 未知状态 $\tilde{s}$ 是一个产品参数 $\theta$ 。 +- 消费者可以以成本 $c(\lambda)$ 购买 $\lambda$ 单位的信息。 +- 随着 $\lambda$ 上升,实验在布莱克韦尔意义下变得更具信息量。 + +布莱克韦尔序表明,在不考虑成本的情况下,对每个期望效用最大化者来说,更多的信息总是更好的。 + +在考虑成本时,消费者选择质量投资 $\theta$ 以最大化 *净价值*。 + +如果质量投资以递减的收益转化为实验精度——比如,对某个速率参数 $a$ ,精度为 $\phi(\theta) = 1 - e^{-a\theta}$ ——那么信息的边际价值最终会随 $\theta$ 递减。 + +在凸成本 $c(\theta) = c \, \theta^2$ 下,递增的边际成本最终会超越递减的边际价值,从而产生一个内部最优。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 具有二次成本的信息需求 + name: fig-blackwell-information-demand +--- +def gross_value(θ, prior2, U=entropy, rate=2): + """质量投资 θ 的总价值(收益递减)。""" + accuracy = 1 - np.exp(-rate * θ) + μ_t = (1 - accuracy) * np.ones((2, 2)) / 2 + accuracy * np.eye(2) + return degroot_value(μ_t, prior2, U) + + +θ_fine = np.linspace(0, 1, 200) +c = 0.6 + +gross_vals = np.array([gross_value(θ, prior2) for θ in θ_fine]) +cost_vals = c * θ_fine**2 +net_vals = gross_vals - cost_vals +marginal_vals = np.gradient(gross_vals, θ_fine) +marginal_cost = 2 * c * θ_fine +opt_idx = int(np.argmax(net_vals)) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +ax = axes[0] +ax.plot(θ_fine, gross_vals, + label="总价值 I(θ)", + color="steelblue", linewidth=2) +ax.plot(θ_fine, cost_vals, + label=r"成本 $c\theta^2$", + color="tomato", linestyle="--", linewidth=2) +ax.plot(θ_fine, net_vals, + label="净价值", color="green", linewidth=2) +ax.axvline(θ_fine[opt_idx], color="green", + linestyle=":", linewidth=2, + label=f"θ* ≈ {θ_fine[opt_idx]:.2f}") +ax.set_xlabel("质量投资 θ", fontsize=11) +ax.set_ylabel("价值(熵单位)", fontsize=11) +ax.legend(fontsize=10) + +ax2 = axes[1] +ax2.plot(θ_fine, marginal_vals, + label="边际价值 I'(θ)", + color="steelblue", linewidth=2) +ax2.plot(θ_fine, marginal_cost, + label=r"边际成本 $2c\theta$", + color="tomato", linestyle="--", linewidth=2) +ax2.axvline(θ_fine[opt_idx], color="green", + linestyle=":", linewidth=2, + label=f"θ* ≈ {θ_fine[opt_idx]:.2f}") +ax2.set_xlabel("质量投资 θ", fontsize=11) +ax2.set_ylabel("边际价值 / 成本", fontsize=11) +ax2.legend(fontsize=10) + +plt.tight_layout() +plt.show() +``` + +最优投资 $\theta^*$ 出现在边际价值等于边际成本的地方。 + +由于实验精度在 $\theta$ 上具有收益递减,投资的边际价值最终会降到上升的边际成本以下,从而产生一个真正的内部最优。 + +提高 $c$ 会使边际成本曲线上移并减小 $\theta^*$ ,而更不对称的先验会使边际价值曲线移动并改变最优。 + +## 应用 2:序贯实验设计 + +{cite:t}`degroot1962` 将不确定性函数框架应用于 *序贯实验设计*。 + +每一期一个统计学家观测一次抽取并更新后验。 + +问题是哪一个实验序列最小化累积期望不确定性。 + +如果一个实验在每一阶段都比另一个更具信息量,那么布莱克韦尔序倾向于在每一时期都使用更好的实验。 + +我们现在为不同质量的实验模拟序贯信念更新。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 不同实验质量下的序贯后验路径 + name: fig-blackwell-sequential-paths +--- +def sequential_update(μ_matrix, prior, T=20, seed=0): + """在实验 μ 下模拟 T 次序贯信念更新。""" + rng = np.random.default_rng(seed) + N, M = μ_matrix.shape + beliefs = np.zeros((T + 1, N)) + beliefs[0] = prior.copy() + + true_state = rng.choice(N, p=prior) + + for t in range(T): + p = beliefs[t] + signal = rng.choice(M, p=μ_matrix[true_state]) + unnorm = μ_matrix[:, signal] * p + beliefs[t + 1] = unnorm / unnorm.sum() + + return beliefs, true_state + + +def plot_sequential_beliefs(θs_compare, prior2, T=25): + fig, axes = plt.subplots(1, len(θs_compare), figsize=(14, 4), sharey=True) + + for ax, θ in zip(axes, θs_compare): + μ_t = make_experiment(θ, N=2) + for seed in range(15): + beliefs, ts = sequential_update(μ_t, prior2, T=T, seed=seed) + c = "steelblue" if ts == 0 else "darkorange" + ax.plot(beliefs[:, 0], alpha=0.35, color=c, linewidth=2) + ax.axhline(prior2[0], linestyle="--", color="gray", linewidth=2, + label="先验") + ax.axhline(1.0, linestyle=":", color="steelblue", linewidth=2) + ax.axhline(0.0, linestyle=":", color="darkorange", linewidth=2) + ax.set_xlabel(r"时期 $t$", fontsize=11) + if θ == θs_compare[0]: + ax.set_ylabel(r"后验 $p(s_1 \mid x^t)$", fontsize=11) + ax.set_ylim(-0.05, 1.05) + ax.text(0.03, 0.94, f"θ = {θ}", transform=ax.transAxes, va="top") + ax.legend(fontsize=9) + + plt.tight_layout() + plt.show() + +plot_sequential_beliefs([0.2, 0.5, 0.9], prior2, T=30) +``` + +更具信息量的实验使信念更快地收敛到真相。 + +在正确的先验下,后验过程是一个鞅。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 后验鞅性质的无条件蕴含 + name: fig-blackwell-martingale-mean +--- +def check_martingale_mean(μ_matrix, prior, T=15, n_paths=2000, seed=0): + """ + 模拟许多信念路径并检验 E[p_t] = p_0。 + """ + rng = np.random.default_rng(seed) + N, M = μ_matrix.shape + all_paths = np.zeros((n_paths, T + 1, N)) + + for k in range(n_paths): + true_state = rng.choice(N, p=prior) + p = prior.copy() + all_paths[k, 0] = p + for t in range(T): + signal = rng.choice(M, p=μ_matrix[true_state]) + unnorm = μ_matrix[:, signal] * p + p = unnorm / unnorm.sum() + all_paths[k, t + 1] = p + + mean_path = all_paths[:, :, 0].mean(axis=0) + + fig, ax = plt.subplots(figsize=(8, 4)) + ax.plot(mean_path, color="steelblue", linewidth=2, + label=r"$\bar p_t(s_1)$(路径均值)") + ax.axhline(prior[0], linestyle="--", color="tomato", linewidth=2, + label=fr"先验 $p_0 = {prior[0]:.2f}$") + ax.set_xlabel(r"时期 $t$", fontsize=12) + ax.set_ylabel(r"$E[p_t(s_1)]$", fontsize=12) + ax.legend(fontsize=11) + ax.set_ylim(0, 1) + plt.tight_layout() + plt.show() + + print(f"先验 = {prior[0]:.4f}") + print(f"各时期的平均信念均值:{mean_path.mean():.4f}") + +check_martingale_mean(μ_info, prior, T=20, n_paths=5000) +``` + +模拟的横截面均值在每一时期都保持接近先验。 + +这是后验鞅性质的无条件蕴含。 + +## 小结 + +布莱克韦尔定理在统计实验上确定了一个 *偏序*,具有三个等价的刻画: + +| 标准 | 条件 | +|-----------|-----------| +| 经济学 | 每个决策者弱地偏好 $\mu$ 甚于 $\nu$ : $B(\mu, A, u) \supseteq B(\nu, A, u)$ | +| 充分性 | $\nu$ 是 $\mu$ 的混淆:对某个马尔可夫矩阵 $Q$ 有 $\nu = \mu Q$ | +| 不确定性 | 对每个先验 $p$ 和每个凹函数 $U$ , $\mu$ 更多地降低期望不确定性 | + +基尔斯特罗姆的贝叶斯阐述将 *后验分布* 置于中心。 + +一个更具信息量的实验会生成一个更为分散、但均值与先验相同的后验分布。 + +恰当的概率语言是后验信念单纯形上的凸序。 + +在两状态情形下,这简化为 $[0, 1]$ 上熟悉的 SOSD / 积分 CDF 检验。 + +德格鲁特的贡献在于将比较从特定效用函数扩展到全部凹不确定性函数类。 + + +## 数据处理不等式与粗粒化 + +布莱克韦尔的条件——对某个马尔可夫核 $Q$ 有 $\nu = \mu Q$ ——与信息论、信息几何和机器学习中支撑 **数据处理不等式**(DPI)和 **粗粒化定理** 的数学操作是同一个。 + +### f-散度的 DPI + +有限空间 $\Omega$ 上两个概率分布 $P$ 和 $Q$ 之间的 **f-散度** 为 + +$$ +D_f(P \| Q) = \sum_{\omega \in \Omega} q_\omega \, f\!\left(\frac{p_\omega}{q_\omega}\right), +$$ + +其中 $f : (0,\infty) \to \mathbb{R}$ 是满足 $f(1) = 0$ 的凸函数。 + +特例包括: + +| 散度 | 生成元 $f(t)$ | +|:---|:---| +| KL 散度 | $t \log t$ | +| 平方 Hellinger $H^2$ | $(\sqrt{t} - 1)^2 / 2$ | +| 全变差 TV | $\lvert t - 1 \rvert / 2$ | +| 卡方 $\chi^2$ | $(t-1)^2$ | + +f-散度这一类别是由 {cite:t}`ali1966` 、 {cite:t}`csiszar1963` 和 {cite:t}`morimoto1963` 独立引入的;另见 {cite:t}`liese2012` 。 + +```{prf:theorem} 数据处理不等式 +:label: thm-data-processing + +对任何 f-散度 $D_f$ 和任何马尔可夫核(随机变换) +$\kappa$ ,以 $P \kappa$ 表示 $P$ 在 $\kappa$ 下的像,我们有 + +$$ +D_f(P \| Q) \geq D_f(P\kappa \| Q\kappa). +$$ + +如果 $\kappa$ 由关于对 $\{P, Q\}$ 的充分统计量诱导,则等式成立。 + +这种形式的逆命题需要额外的假设;下面给出一个清晰的二元模型刻画。 +``` + +该证明来自将詹森不等式应用于凸函数 $f$ ,并利用 $\kappa$ 是随机矩阵这一事实 {cite}`csiszar1963` 。 + +### 与布莱克韦尔充分性条件的联系 + +在布莱克韦尔的框架中, $\mu$ 和 $\nu$ 是在同一状态空间 $S = \{s_1, \ldots, s_N\}$ 上的实验。 + +对两个状态,每个实验有两行: $\mu_1 = \mu(s_1, \cdot)$ 和 $\mu_2 = \mu(s_2, \cdot)$ 。 + +如果 $\nu = \mu Q$ (即 $\nu$ 是 $\mu$ 的混淆),那么对 $(\nu_1, \nu_2) = (\mu_1 Q, \mu_2 Q)$ 就是通过将马尔可夫核 $Q$ 应用于对 $(\mu_1, \mu_2)$ 得到的。 + +粗粒化定理由此立即蕴含: + +$$ +D_f(\mu_1 \| \mu_2) \geq D_f(\nu_1 \| \nu_2) +\quad \text{for every f-divergence } D_f, +$$ + +只要 $\mu \geq \nu$ 在布莱克韦尔序中成立。 + +因此一个更具信息量的实验总是会产生 *更分离的* 条件信号分布,在每个 f-散度的意义下同时如此。 + +由此,DPI 是关于状态 *可区分性* 的一个陈述:混淆一个实验会使得在每种统计可分性度量下,状态都更难被区分。 + +对二元实验,等式条件将 DPI 直接联系回布莱克韦尔:对某个严格凸的 $f$ 有 $D_f(\mu_1 Q \| \mu_2 Q) = D_f(\mu_1 \| \mu_2)$ ,当且仅当 $Q$ 是关于 $(\mu_1, \mu_2)$ 的充分统计量。 + +一旦充分性成立,则对每个凸函数 $f$ 等式都成立 {cite}`liese2012` 。 + +### 信息几何:陈氏定理 + +DPI 有一个无穷小的、微分几何的伴侣。 + +**陈氏定理** {cite}`chentsov1981` 断言, **Fisher 信息矩阵** $I_F(\theta)$ 至多相差一个常数重缩放,是统计流形上在每个马尔可夫态射(粗粒化)下都收缩的 *唯一* 黎曼度量: + +$$ +I_F(\theta;\, \mu) \succeq I_F(\theta;\, \mu\kappa) +\quad \text{for every differentiable family } \{\mu_\theta\} \text{ and every Markov kernel } \kappa. +$$ + +等式成立当且仅当 $\kappa$ 是关于 $\theta$ 的充分统计量。 + +唯一性条款意义深远:它说 Fisher 信息不仅仅是碰巧在粗粒化下收缩的 *某一个* 度量,而是具有该性质的 *唯一一个* 度量。 + +关于信息几何及其与充分性联系的详尽处理,参见 {cite:t}`amari_nagaoka2000` 。 + +### 机器学习中的信息瓶颈 + +{cite:t}`tishby_pereira_bialek1999` 的 **信息瓶颈** 方法提供了 DPI 在机器学习中一个突出的应用。 + +给定输入 $X$ 和目标 $Y$ 上的联合分布 $p(X, Y)$ ,目标是找到一个由随机映射 $p(T \mid X)$ 形成的压缩表示 $T$ ,使其在用尽可能少的比特描述 $X$ 的同时,尽可能多地保留关于 $Y$ 的信息。 + +该方法最小化拉格朗日量 + +$$ +\mathcal{L}[p(T \mid X)] = I(X;\, T) - \beta \, I(T;\, Y), +$$ + +其中 $I(\cdot\,;\,\cdot)$ 表示互信息, $\beta \geq 0$ 支配压缩-相关性权衡。 + +由于 $Y - X - T$ 构成一个马尔可夫链(T 仅从 X 导出),DPI 蕴含 + +$$ +I(T;\, Y) \leq I(X;\, Y), +$$ + +等式成立当且仅当 $T$ 是给定 $X$ 时关于 $Y$ 的 **充分统计量**。 + +布莱克韦尔序解释了为什么对 $X$ 的任何确定性或随机后处理都无法增加与 $Y$ 的互信息:应用于 $X$ 的任何马尔可夫核都是布莱克韦尔意义下的混淆,而 DPI 是粗粒化定理的互信息形式。 + +用机器学习的语言来说,信息瓶颈在 $X$ 的所有混淆中搜索那个在压缩预算约束下最好地保留关于 $Y$ 相关信息的混淆。 + +在一个具有输入 $X$ 、目标 $Y$ 以及层 $X \to T_1 \to T_2 \to \cdots \to T_L \to \hat{Y}$ 的深度神经网络中,每一层的表示都是前一层的混淆。 + +于是 DPI 蕴含如下不等式链 + +$$ +I(X;\, Y) \geq I(T_1;\, Y) \geq I(T_2;\, Y) \geq \cdots \geq I(T_L;\, Y), +$$ + +因此后继各层关于 $Y$ 的信息只会损失,绝不会增加。 + +这一观察被 {cite}`shwartz_ziv_tishby2017` 置于研究深度网络所学内容的中心。 + +{numref}`fig-blackwell-value-by-quality` 已经阐释了这一点:随着实验质量 $\theta$ 增加,每一种信息量度量都单调上升。 + +DPI 反过来说的是同一件事:混淆(降低 $\theta$ )只会收缩这些度量。 + +### DPI-布莱克韦尔对应的小结 + +下表汇集了布莱克韦尔框架与数据处理和粗粒化文献之间的精确对应。 + +| 布莱克韦尔 / 德格鲁特 | 数据处理 / 粗粒化 | +|:---|:---| +| 混淆 $\nu = \mu Q$ | 将马尔可夫核 $\kappa$ 应用于对 $(P, Q) = (\mu_1, \mu_2)$ | +| $\mu \geq \nu$ 在布莱克韦尔序中 | 对每个 f-散度 $D_f(\mu_1 \| \mu_2) \geq D_f(\nu_1 \| \nu_2)$ | +| 充分性( $Q$ 不丢弃任何东西) | DPI 中的等式;在二元模型中,一个严格凸的 $f$ 就已刻画充分性 | +| 德格鲁特价值 $I(\mu; U_H)$ | 互信息 $I(\tilde{x}_\mu;\, \tilde{s})$ (香农 DPI) | +| $\mu$ 与 $\nu$ 下的后验展开 | $\mu$ 下各行之间的 $D_f$ 更大 | +| 布莱克韦尔定理(经济学 $\Leftrightarrow$ 混淆) | 对所有 $f$ 的 DPI $\Leftrightarrow$ 单个马尔可夫核见证占优 | +| 陈氏唯一性定理 | Fisher 信息是唯一在粗粒化下收缩的度量 | +| 信息瓶颈 $I(T;Y) \leq I(X;Y)$ | 应用于马尔可夫链 $Y{-}X{-}T$ 的互信息 DPI | + + +## 与贝叶斯似然比学习的关系 + +讲座 {doc}`likelihood_bayes` 是这里所发展框架的一个动态的两状态特例。 + +设 $S = \{s_1, s_2\}$ ,其中 $s_1 \leftrightarrow f$ 且 $s_2 \leftrightarrow g$ ,其中 $f$ 和 $g$ 是两个候选的数据生成密度。 + +那么单个观测是一个具有行 $f(\cdot)$ 和 $g(\cdot)$ 的布莱克韦尔实验,而历史 $w^t = (w_1, \ldots, w_t)$ 定义了一个更丰富的实验 $\mu_t$ 。 + +由于总是可以丢弃最后 $t-s$ 个观测,对每个 $t > s$ , $\mu_t$ 都布莱克韦尔占优 $\mu_s$ 。 + +似然比过程 + +$$ +L(w^t) = \prod_{i=1}^t \frac{f(w_i)}{g(w_i)} +$$ + +是 $\mu_t$ 的一个充分统计量,而后验 + +$$ +\pi_t = \Pr(s_1 \mid w^t) += \frac{\pi_0 L(w^t)}{\pi_0 L(w^t) + 1 - \pi_0} +$$ + +是基尔斯特罗姆在这个两状态设定下的标准实验。 + +它的鞅性质 $E[\pi_t] = \pi_0$ 正是上面为后验分布证明的均值保持结果。 + +同样地, $\mu_t \geq \mu_s$ 意味着 $\pi_t$ 的分布是 $\pi_s$ 分布的一个均值保持展开,因此额外的数据会把信念推向离 $0$ 和 $1$ 更远的地方,同时在每个凹不确定性函数下降低期望不确定性。 + +### 小结表 + +下表在不重复前面论证的情况下记录了两个讲座之间的对照词典。 + +| {doc}`likelihood_bayes` 中的概念 | 本讲座中的概念 | +|---|---| +| 状态 $\{f, g\}$ | 状态空间 $S = \{s_1, s_2\}$ | +| 密度 $f(\cdot)$ 、 $g(\cdot)$ | 实验矩阵 $\mu$ 的各行 | +| 单次抽取 $w_t$ | 具有连续信号空间的布莱克韦尔实验 | +| $t$ 次 IID 抽取的历史 $w^t$ | 布莱克韦尔占优 $\mu_s$( $s < t$ )的更丰富实验 $\mu_t$ | +| 似然比 $L(w^t)$ | $\mu_t$ 的充分统计量 | +| 先验 $\pi_0$ | 1-单纯形 $[0,1]$ 上的先验 $p \in P$ | +| 后验 $\pi_t$ | $P = [0,1]$ 上的后验(基尔斯特罗姆的标准实验) | +| $\pi_t$ 在各历史上的分布 | $\hat{\mu}^c$ (基尔斯特罗姆的后验分布) | +| 鞅性质 $E[\pi_t] = \pi_0$ | $\hat{\mu}^c$ 的均值保持 | +| $\pi_t \to 0$ 或 $1$ 几乎必然 | 后验向顶点展开(极限中的 MPS) | +| 互信息 $I(\mu_t; U_H)$ | 德格鲁特信息价值 | +| 更多抽取 $\Rightarrow$ 对所有决策者更好 | 布莱克韦尔序 $\mu_t \geq \mu_s$ | +| 混淆(丢弃最后 $t - s$ 次抽取) | 满足 $\mu_s = \mu_t Q$ 的随机变换 $Q$ | \ No newline at end of file diff --git a/lectures/chow_business_cycles.md b/lectures/chow_business_cycles.md new file mode 100644 index 0000000..79c94ff --- /dev/null +++ b/lectures/chow_business_cycles.md @@ -0,0 +1,1686 @@ +--- +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 +translation: + title: 加速原理与商业周期的本质 + headings: + Overview: 概述 + Empirical foundation for the acceleration principle: 加速原理的经验基础 + 'Empirical foundation for the acceleration principle::An example: automobile demand': 一个例子:汽车需求 + Empirical foundation for the acceleration principle::From stock adjustment to acceleration: 从存量调整到加速 + Acceleration enables oscillations: 加速使振荡成为可能 + A linear system with shocks: 带冲击的线性系统 + A linear system with shocks::Autocovariances in terms of eigenvalues: 用特征值表示的自协方差 + A linear system with shocks::Complex roots and damped oscillations: 复根与阻尼振荡 + From autocovariances to spectra: 从自协方差到谱 + Spectral peaks in the Hansen-Samuelson model: Hansen-Samuelson 模型中的谱峰 + Spectral peaks in the Hansen-Samuelson model::The model as a first-order system: 作为一阶系统的模型 + Spectral peaks in the Hansen-Samuelson model::The spectral density formula: 谱密度公式 + Spectral peaks in the Hansen-Samuelson model::Conditions for a spectral peak: 谱峰的条件 + Spectral peaks in the Hansen-Samuelson model::Real positive roots cannot produce peaks: 实正根无法产生峰值 + Real roots can produce peaks in general models: 实根可以在一般模型中产生峰值 + Real roots can produce peaks in general models::Example: 例子 + Real roots can produce peaks in general models::The Slutsky connection: 斯卢茨基联系 + Real roots can produce peaks in general models::The general lesson: 一般教训 + A calibrated model in the frequency domain: 频域中的一个校准模型 + A calibrated model in the frequency domain::The cycle subsystem: 周期子系统 + A calibrated model in the frequency domain::Reconstructing $A$ and computing $F(\omega)$: 重构 $A$ 并计算 $F(\omega)$ + A calibrated model in the frequency domain::Canonical coordinates: 规范坐标 + A calibrated model in the frequency domain::How variables move together across frequencies: 变量如何跨频率一起运动 + A calibrated model in the frequency domain::Lead-lag relationships: 领先-滞后关系 + A calibrated model in the frequency domain::Building blocks of spectral shape: 谱形状的组成部分 + Summary: 总结 + Exercises: 练习 +--- + +(chow_business_cycles)= + +```{raw} jupyter + +``` + +# 加速原理与商业周期的本质 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲座研究 Gregory Chow 的两篇经典论文: + +- {cite:t}`Chow1968` 提出了加速原理的经验证据,描述了加速如何促进振荡,并分析了受随机冲击影响的线性差分方程中谱峰出现的条件 +- {cite:t}`ChowLevitan1969` 提出了对一个校准的美国宏观计量经济模型的谱分析,并讲授了谱增益、相干性和领先-滞后模式 + +这些论文与以下讲座中的思想相关: + +- {doc}`samuelson` 中的乘数-加速数机制 +- {doc}`linear_models` 中的线性随机差分方程和自协方差 +- {doc}`var_dmd` 中的多元动态特征模态 +- {doc}`eig_circulant` 中的傅里叶思想(以及关于经验估计的进阶讲座 {doc}`advanced:estspec`) + +{cite:t}`Chow1968` 建立在早期在美国投资数据上检验加速原理的经验工作之上。 + +在建立理论框架之前,我们先从这些经验证据开始。 + +我们将不断回到三个思想: + +- 在确定性模型中,振荡表明转移矩阵存在复特征值。 +- 在随机模型中,"周期"表现为(单变量)谱密度中的局部峰值。 +- 谱峰依赖于特征值,但也依赖于冲击如何进入系统以及可观测量如何加载于特征模态。 + +让我们从一些标准导入开始: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +我们将在整个讲座中使用以下辅助函数 + +```{code-cell} ipython3 +def spectral_density_var1(A, V, ω_grid): + """VAR(1) 的谱密度矩阵:y_t = A y_{t-1} + u_t。""" + A, V = np.asarray(A), np.asarray(V) + n = A.shape[0] + I = np.eye(n) + F = np.empty((len(ω_grid), n, n), dtype=complex) + for k, ω in enumerate(ω_grid): + H = np.linalg.inv(I - np.exp(-1j * ω) * A) + F[k] = (H @ V @ H.conj().T) / (2 * np.pi) + return F + +def spectrum_of_linear_combination(F, b): + """给定谱矩阵 F(ω),计算 x_t = b'y_t 的谱。""" + b = np.asarray(b).reshape(-1, 1) + return np.array([np.real((b.T @ F[k] @ b).item()) + for k in range(F.shape[0])]) + +def simulate_var1(A, V, T, burn=200, seed=1234): + r"""模拟 y_t = A y_{t-1} + u_t,其中 u_t \sim N(0, V)。""" + rng = np.random.default_rng(seed) + A, V = np.asarray(A), np.asarray(V) + n = A.shape[0] + chol = np.linalg.cholesky(V) + y = np.zeros((T + burn, n)) + + for t in range(1, T + burn): + y[t] = A @ y[t - 1] + chol @ rng.standard_normal(n) + + return y[burn:] + +def sample_autocorrelation(x, max_lag): + """从滞后 0 到 max_lag 计算一维数组的样本自相关。""" + x = np.asarray(x) + x = x - x.mean() + denom = np.dot(x, x) + acf = np.empty(max_lag + 1) + for k in range(max_lag + 1): + acf[k] = np.dot(x[:-k] if k else x, x[k:]) / denom + return acf +``` + +(empirical_section)= +## 加速原理的经验基础 + +{cite:t}`Chow1968` 一开始回顾了来自早期宏观计量经济工作的加速原理的经验证据。 + +Chow 使用 1931--40 年和 1948--63 年的年度观测数据,在三个投资类别上检验了加速方程: + +- 新建筑 +- 生产者耐用设备的私人国内总投资加上企业库存变化 +- 上述后两个变量分别考虑 + +在每种情况下,当回归同时包含 $Y_t$ 和 $Y_{t-1}$(其中 $Y$ 是国民生产总值减去净转移支付后的税收)时,$Y_{t-1}$ 上的系数与 $Y_t$ 上的系数*符号相反*,且绝对值略小。 + +等价地,当用 $\Delta Y_t$ 和 $Y_{t-1}$ 表示时,$Y_{t-1}$ 上的系数是 $\Delta Y_t$ 系数的一个很小的比例。 + +### 一个例子:汽车需求 + +Chow 用他早期关于汽车需求工作中的汽车净投资数据给出了一个清晰的说明。 + +使用 1922--41 年和 1948--57 年的年度数据,他通过最小二乘法估计: + +```{math} +:label: chow_auto_eq5 + +y_t^n = \underset{(0.0022)}{0.0155} Y_t \underset{(0.0020)}{- 0.0144} Y_{t-1} \underset{(0.0056)}{- 0.0239} p_t \underset{(0.0040)}{+ 0.0199} p_{t-1} + \underset{(0.101)}{0.351} y_{t-1}^n + \text{const.} +``` + +其中: +- $Y_t$ 是人均实际可支配个人收入 +- $p_t$ 是汽车的相对价格指数 +- $y_t^n$ 是人均客车净投资 +- 括号中为标准误 + +关键观察:$Y_{t-1}$ 和 $p_{t-1}$ 上的系数是 $Y_t$ 和 $p_t$ 系数的*相反数*。 + +这种模式正是加速原理所预测的。 + +### 从存量调整到加速 + +一旦我们接受资本的存量调整需求方程,对加速的经验支持就不足为奇了: + +```{math} +:label: chow_stock_adj_emp + +s_{it} = a_i Y_t + b_i s_{i,t-1} +``` + +其中 $s_{it}$ 是资本品 $i$ 的存量。 + +加速方程 {eq}`chow_auto_eq5` 本质上是 {eq}`chow_stock_adj_emp` 的*一阶差分*。 + +净投资是存量的变化,$y_{it}^n = \Delta s_{it}$,对 {eq}`chow_stock_adj_emp` 作差分得到: + +```{math} +:label: chow_acc_from_stock + +y_{it}^n = a_i \Delta Y_t + b_i y_{i,t-1}^n +``` + +在水平形式中,$Y_t$ 和 $Y_{t-1}$ 上的系数分别为 $a_i$ 和 $-a_i(1-b_i)$。 + +当 $b_i$ 离 1 不太远时,它们符号相反且大小相近。 + +存量调整与加速之间的这种联系是 Chow 关于为什么加速对商业周期至关重要论证的核心。 + +## 加速使振荡成为可能 + +在建立了加速的经验证据之后,我们现在考察为什么它在理论上对产生振荡至关重要。 + +{cite:t}`Chow1968` 提出了一个基本问题:如果我们仅使用带有简单分布滞后的标准需求方程构建一个宏观模型,系统能否产生持续的振荡? + +他证明了,在自然的符号约束下,答案是否定的。 + +耐用品的存量调整需求导致投资方程中 $Y_{t-1}$ 上的系数为负。 + +这个负系数刻画了**加速效应**:投资不仅对收入水平作出反应,还对其变化率作出反应。 + +这个负系数也是使特征方程中出现复根成为可能的原因。 + +没有它,Chow 证明了只有正系数的需求系统具有实正根,因此没有振荡动态。 + +{doc}`samuelson` 讲座通过 Hansen-Samuelson 乘数-加速数模型详细探讨了这一机制。 + +这里我们简要说明这个效应。 + +取乘数-加速数运动定律: + +```{math} +Y_t = c Y_{t-1} + v (Y_{t-1} - Y_{t-2}), +``` + +并将其重写为 $(Y_t, Y_{t-1})$ 中的一阶系统。 + +```{code-cell} ipython3 +def samuelson_transition(c, v): + return np.array([[c + v, -v], [1.0, 0.0]]) + +# 比较弱加速与强加速 +# 弱:c=0.8, v=0.1 给出实根(判别式 > 0) +# 强:c=0.6, v=0.8 给出复根(判别式 < 0) +cases = [("弱加速", 0.8, 0.1), + ("强加速", 0.6, 0.8)] +A_list = [samuelson_transition(c, v) for _, c, v in cases] + +for (label, c, v), A in zip(cases, A_list): + eig = np.linalg.eigvals(A) + disc = (c + v)**2 - 4*v + print( + f"{label}: c={c}, v={v}, 判别式={disc:.2f}, 特征值={eig}") +``` + +在弱加速($v=0.1$)下,判别式为正,根为实数。 + +在强加速($v=0.8$)下,判别式为负,根是共轭复数,从而使振荡动态成为可能。 + +现在让我们看看这些不同的特征值结构如何影响对 $Y$ 中一次性冲击的脉冲响应 + +```{code-cell} ipython3 +T = 40 +s0 = np.array([1.0, 0.0]) +irfs = [] +for A in A_list: + s = s0.copy() + path = np.empty(T + 1) + for t in range(T + 1): + path[t] = s[0] + s = A @ s + irfs.append(path) + +fig, ax = plt.subplots(figsize=(10, 4)) +ax.plot(range(T + 1), irfs[0], lw=2, + label="弱加速(实根)") +ax.plot(range(T + 1), irfs[1], lw=2, + label="强加速(复根)") +ax.axhline(0.0, lw=0.8, color='gray') +ax.set_xlabel("时间") +ax.set_ylabel(r"$Y_t$") +ax.legend(frameon=False) +plt.tight_layout() +plt.show() +``` + +在弱加速下,脉冲响应单调衰减。 + +在强加速下,它振荡。 + +我们可以问,随着加速数 $v$ 的增加,特征值如何变化。 + +随着我们增加加速数 $v$,特征值离原点越来越远。 + +对于这个模型,特征值的模是 $|\lambda| = \sqrt{v}$,所以稳定性边界是 $v = 1$。 + +```{code-cell} ipython3 +v_grid = [0.2, 0.4, 0.6, 0.8, 0.95] +c = 0.6 +T_irf = 40 # 脉冲响应的周期数 + +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +for v in v_grid: + A = samuelson_transition(c, v) + eig = np.linalg.eigvals(A) + + # 特征值(左图) + axes[0].scatter(eig.real, eig.imag, s=40, label=f'$v={v}$') + + # 脉冲响应(右图) + s = np.array([1.0, 0.0]) + irf = np.empty(T_irf + 1) + for t in range(T_irf + 1): + irf[t] = s[0] + s = A @ s + axes[1].plot(range(T_irf + 1), irf, lw=2, label=f'$v={v}$') + +# 可视化特征值位置和单位圆 +θ_circle = np.linspace(0, 2*np.pi, 100) +axes[0].plot(np.cos(θ_circle), np.sin(θ_circle), + 'k--', lw=0.8, label='单位圆') +axes[0].set_xlabel('实部') +axes[0].set_ylabel('虚部') +axes[0].set_aspect('equal') +axes[0].legend(frameon=False) + +# 脉冲响应面板 +axes[1].axhline(0, lw=0.8, color='gray') +axes[1].set_xlabel('时间') +axes[1].set_ylabel(r'$Y_t$') +axes[1].legend(frameon=False) + +plt.tight_layout() +plt.show() +``` + +随着 $v$ 增加,特征值接近单位圆,振荡变得更加持久。 + +这说明加速创造了复特征值,而复特征值是确定性系统中振荡动态所必需的。 + +但当我们加入随机冲击时会发生什么? + +拉格纳·弗里希 {cite}`frisch33` 的一个洞见是,当系统被随机扰动持续扰动时,阻尼振荡可以被"维持"。 + +为了正式研究这一点,我们需要引入随机框架。 + +## 带冲击的线性系统 + +我们分析一个一阶线性随机系统 + +```{math} +:label: chow_var1 + +y_t = A y_{t-1} + u_t, +\qquad +\mathbb E[u_t] = 0, +\qquad +\mathbb E[u_t u_t^\top] = V, +\qquad +\mathbb E[u_t u_{t-k}^\top] = 0, \quad k \neq 0. +``` + +当 $A$ 的特征值严格位于单位圆内时,该过程是协方差平稳的,其自协方差存在。 + +用 {doc}`linear_models` 的记号,这与保证离散李雅普诺夫方程有唯一解的稳定性条件相同。 + +定义滞后-$k$ 自协方差矩阵 + +```{math} +:label: chow_autocov_def + +\Gamma_k := \mathbb E[y_t y_{t-k}^\top] . +``` + +标准计算(也在 {cite}`Chow1968` 中推导)给出递归 + +```{math} +:label: chow_autocov_rec + +\Gamma_k = A \Gamma_{k-1}, \quad k \ge 1, +\qquad\text{and}\qquad +\Gamma_0 = A \Gamma_0 A^\top + V. +``` + +第二个方程是 $\Gamma_0$ 的离散李雅普诺夫方程。 + +{cite:t}`Chow1968` 用拉格纳·弗里希的一段话来引出随机分析: + +> 我们讨论过的例子……表明,当一个[确定性的]经济系统产生振荡时,这些振荡最常见的是有阻尼的。 +> 但在现实中,周期……通常不是有阻尼的。 +> 如何解释摆动的维持? +> ……我认为一种特别富有成效和有前途的方法是研究,如果一个确定性动态系统的解暴露于一系列不规则冲击之下,它会变成什么样…… +> 因此,通过将两个思想联系起来:(1) 确定性动态系统的连续解,以及 (2) 介入并提供可能维持摆动能量的间断冲击——我们得到了一个理论设定,它似乎为那些我们习惯于在统计时间数据中看到的运动提供了一个理性的解释。 +> +> -- 拉格纳·弗里希 (1933) {cite}`frisch33` + +Chow 的主要洞见是,确定性系统中的振荡对于在随机系统中产生"周期"*既不必要也不充分*。 + +我们必须把随机因素纳入考虑。 + +我们将证明,即使特征值是实数(没有确定性振荡),随机系统也能在其自协方差和谱密度中表现出周期性模式。 + +### 用特征值表示的自协方差 + +设 $\lambda_1, \ldots, \lambda_p$ 是 $A$ 的不同的、可能为复数的特征值,设 $B$ 是以对应右特征向量为列的矩阵: + +```{math} +:label: chow_eigen_decomp + +A B = B D_\lambda, \quad \text{或等价地} \quad A = B D_\lambda B^{-1} +``` + +其中 $D_\lambda = \text{diag}(\lambda_1, \ldots, \lambda_p)$。 + +定义规范变量 $z_t = B^{-1} y_t$。 + +它们满足解耦动态: + +```{math} +:label: chow_canonical_dynamics + +z_t = D_\lambda z_{t-1} + \varepsilon_t +``` + +其中 $\varepsilon_t = B^{-1} u_t$ 具有协方差矩阵 $W = B^{-1} V (B^{-1})^\top$。 + +规范变量的自协方差矩阵,记为 $\Gamma_k^*$,满足 + +```{math} +:label: chow_canonical_autocov + +\Gamma_k^* = D_\lambda^k \Gamma_0^*, \quad k = 1, 2, 3, \ldots +``` + +以及 + +```{math} +:label: chow_gamma0_star + +\Gamma_0^* = \left( \frac{w_{ij}}{1 - \lambda_i \lambda_j} \right) +``` + +其中 $w_{ij}$ 是 $W$ 的元素。 + +原始变量的自协方差矩阵为 + +```{math} +:label: chow_autocov_eigen + +\Gamma_k = B \Gamma_k^* B^\top = B D_\lambda^k \Gamma_0^* B^\top, \quad k = 0, 1, 2, \ldots +``` + +标量自协方差 $\gamma_{ij,k} = \mathbb{E}[y_{it} y_{j,t-k}]$ 是特征值幂的*线性组合*: + +```{math} +:label: chow_scalar_autocov + +\gamma_{ij,k} = \sum_m \sum_n b_{im} b_{jn} \gamma^*_{mn,0} \lambda_m^k = \sum_m d_{ij,m} \lambda_m^k +``` + +将此与来自初始条件 $y_0$ 的确定性时间路径进行比较: + +```{math} +:label: chow_det_path + +y_{it} = \sum_j b_{ij} z_{j0} \lambda_j^t +``` + +自协方差函数 {eq}`chow_scalar_autocov` 和确定性路径 {eq}`chow_det_path` 都是 $\lambda_m^k$(或 $\lambda_j^t$)的线性组合。 + +### 复根与阻尼振荡 + +当特征值以共轭复数对 $\lambda = r e^{\pm i\theta}$($r < 1$)出现时,它们对自协方差函数的贡献是一个**阻尼余弦**: + +```{math} +:label: chow_damped_cosine + +2 s r^k \cos(\theta k + \phi) +``` + +其中适当的幅度 $s$ 和相位 $\phi$ 由特征向量载荷决定。 + +在确定性模型中,这种复根产生阻尼振荡时间路径。 + +在随机模型中,它们产生阻尼振荡自协方差函数。 + +正是在这个意义上,确定性振荡可以在随机模型中被"维持",但正如我们将看到的,特征值与谱峰之间的联系比这暗示的更为微妙。 + +## 从自协方差到谱 + +Chow 的关键步骤是将自协方差序列 $\{\Gamma_k\}$ 转换为一个频域对象。 + +**谱密度矩阵**是 $\Gamma_k$ 的傅里叶变换: + +```{math} +:label: chow_spectral_def + +F(\omega) := \frac{1}{2\pi} \sum_{k=-\infty}^{\infty} \Gamma_k e^{-i \omega k}, +\qquad \omega \in [0, \pi]. +``` + +对于 VAR(1) 系统 {eq}`chow_var1`,这个和有一个闭式 + +```{math} +:label: chow_spectral_closed + +F(\omega) += \frac{1}{2\pi} +\left(I - A e^{-i\omega}\right)^{-1} +V +\left(I - A^\top e^{i\omega}\right)^{-1}. +``` + +$F(\omega)$ 告诉我们 $y_t$ 中有多少变化与(角)频率 $\omega$ 的周期相关联。 + +较高的频率对应于快速振荡,即每单位时间内序列完成许多上下运动的短周期。 + +较低的频率对应于较慢的振荡,即在延长的时间段内展开的长周期。 + +对应的周期长度(或周期)为 + +```{math} +:label: chow_period + +T(\omega) = \frac{2\pi}{\omega}. +``` + +因此,频率 $\omega = \pi$ 对应于 $T = 2$ 个周期的最短可能周期,而接近零的频率对应于非常长的周期。 + +当谱密度 $F(\omega)$ 集中在特定频率时,它表明时间序列在这些频率上表现出显著的周期性行为。 + +进阶讲座 {doc}`advanced:estspec` 解释了如何从数据估计 $F(\omega)$。 + +这里我们关注模型隐含的谱。 + +我们前面看到加速创造了复特征值,这使得振荡脉冲响应成为可能。 + +但复根能保证谱峰吗? + +它们对谱峰是必要的吗? + +Chow 为 Hansen-Samuelson 模型提供了精确的答案。 + +## Hansen-Samuelson 模型中的谱峰 + +{cite:t}`Chow1968` 提供了 Hansen-Samuelson 乘数-加速数模型的详细谱分析,推导了谱峰出现的精确条件。 + +该分析揭示,在这个特定模型中,复根对峰值是*必要的*,但正如我们稍后将看到的,这在一般情况下并不成立。 + +### 作为一阶系统的模型 + +二阶 Hansen-Samuelson 方程可以写成一阶系统: + +```{math} +:label: chow_hs_system + +\begin{bmatrix} y_{1t} \\ y_{2t} \end{bmatrix} = +\begin{bmatrix} a_{11} & a_{12} \\ 1 & 0 \end{bmatrix} +\begin{bmatrix} y_{1,t-1} \\ y_{2,t-1} \end{bmatrix} + +\begin{bmatrix} u_{1t} \\ 0 \end{bmatrix} +``` + +其中 $y_{2t} = y_{1,t-1}$ 只是 $y_{1t}$ 的滞后值。 + +这种结构隐含了自协方差之间的一个特殊关系: + +```{math} +:label: chow_hs_autocov_relation + +\gamma_{11,k} = \gamma_{22,k} = \gamma_{12,k-1} = \gamma_{21,k+1} +``` + +使用自协方差递归,Chow 证明这导致条件 + +```{math} +:label: chow_hs_condition53 + +\gamma_{11,-1} = d_{11,1} \lambda_1^{-1} + d_{11,2} \lambda_2^{-1} = \gamma_{11,1} = d_{11,1} \lambda_1 + d_{11,2} \lambda_2 +``` + +它以一种有用的方式约束了谱密度。 + +### 谱密度公式 + +从方程 {eq}`chow_scalar_autocov` 和标量核 $g_i(\omega) = (1 - \lambda_i^2)/(1 + \lambda_i^2 - 2\lambda_i \cos\omega)$,$y_{1t}$ 的谱密度为: + +```{math} +:label: chow_hs_spectral + +f_{11}(\omega) = d_{11,1} g_1(\omega) + d_{11,2} g_2(\omega) +``` + +它可以写成组合形式: + +```{math} +:label: chow_hs_spectral_combined + +f_{11}(\omega) = \frac{d_{11,1}(1 - \lambda_1^2)(1 + \lambda_2^2) + d_{11,2}(1 - \lambda_2^2)(1 + \lambda_1^2) - 2[d_{11,1}(1-\lambda_1^2)\lambda_2 + d_{11,2}(1-\lambda_2^2)\lambda_1]\cos\omega}{(1 + \lambda_1^2 - 2\lambda_1 \cos\omega)(1 + \lambda_2^2 - 2\lambda_2 \cos\omega)} +``` + +一个关键观察:由于条件 {eq}`chow_hs_condition53`,*分子不是 $\cos\omega$ 的函数*。 + +因此,要找到 $f_{11}(\omega)$ 的最大值,我们只需找到分母的最小值。 + +### 谱峰的条件 + +分母关于 $\omega$ 的一阶导数为: + +```{math} +:label: chow_hs_derivative + +2[(1 + \lambda_1^2)\lambda_2 + (1 + \lambda_2^2)\lambda_1] \sin\omega - 8\lambda_1 \lambda_2 \cos\omega \sin\omega +``` + +对于 $0 < \omega < \pi$,我们有 $\sin\omega > 0$,所以导数为零当且仅当: + +```{math} +:label: chow_hs_foc + +(1 + \lambda_1^2)\lambda_2 + (1 + \lambda_2^2)\lambda_1 = 4\lambda_1 \lambda_2 \cos\omega +``` + +对于*共轭复根* $\lambda_1 = r e^{i\theta}$、$\lambda_2 = r e^{-i\theta}$,代入 {eq}`chow_hs_foc` 得到: + +```{math} +:label: chow_hs_peak_condition + +\cos\omega = \frac{1 + r^2}{2r} \cos\theta +``` + +二阶导数确认当 $\omega < \frac{3\pi}{4}$ 时这是一个最大值。 + +有效解的必要条件是: + +```{math} +:label: chow_hs_necessary + +-1 < \frac{1 + r^2}{2r} \cos\theta < 1 +``` + +我们可以将其解释为: +- 当 $r \approx 1$ 时,因子 $(1+r^2)/2r \approx 1$,所以 $\omega \approx \theta$ +- 当 $r$ 较小(例如 0.3 或 0.4)时,条件 {eq}`chow_hs_necessary` 只有在 $\cos\theta \approx 0$ 时才能满足,这意味着 $\theta \approx \pi/2$(约 4 个周期的周期) + +如果 $\theta = 54^\circ$(对应于 6.67 个周期的周期)且 $r = 0.4$,那么 $(1+r^2)/2r = 1.45$,给出 $\cos\omega = 1.45 \times 0.588 = 0.85$,即 $\omega = 31.5^\circ$,对应于 11.4 个周期的周期,这比确定性周期长得多。 + +```{code-cell} ipython3 +def peak_condition_factor(r): + """计算 (1 + r^2) / (2r)""" + return (1 + r**2) / (2 * r) + +θ_deg = 54 +θ = np.deg2rad(θ_deg) +r_grid = np.linspace(0.3, 0.99, 100) + +# 对每个 r,计算隐含的峰值频率 +ω_peak = [] +for r in r_grid: + factor = peak_condition_factor(r) + cos_ω = factor * np.cos(θ) + if -1 < cos_ω < 1: + ω_peak.append(np.arccos(cos_ω)) + else: + ω_peak.append(np.nan) + +ω_peak = np.array(ω_peak) +period_peak = 2 * np.pi / ω_peak + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].plot(r_grid, np.rad2deg(ω_peak), lw=2) +axes[0].axhline(θ_deg, ls='--', lw=1.0, color='gray', + label=rf'$\theta = {θ_deg}°$') +axes[0].set_xlabel('特征值模 $r$') +axes[0].set_ylabel(r'峰值频率 $\omega$(度)') +axes[0].legend(frameon=False) + +axes[1].plot(r_grid, period_peak, lw=2) +axes[1].axhline(360/θ_deg, ls='--', lw=1.0, color='gray', + label=rf'确定性周期 = {360/θ_deg:.1f}') +axes[1].set_xlabel('特征值模 $r$') +axes[1].set_ylabel('峰值周期') +axes[1].legend(frameon=False) + +plt.tight_layout() +plt.show() + +r_example = 0.4 +factor = peak_condition_factor(r_example) +cos_ω = factor * np.cos(θ) +ω_example = np.arccos(cos_ω) +print(f"Chow 的例子:r = {r_example}, θ = {θ_deg}°") +print(f" cos(ω) = {cos_ω:.3f}") +print(f" ω = {np.rad2deg(ω_example):.1f}°") +print(f" 峰值周期 = {360/np.rad2deg(ω_example):.1f}") +``` + +当 $r \to 1$ 时,峰值频率收敛到 $\theta$。 + +对于较小的 $r$,峰值频率可能与确定性振荡频率有很大不同。 + +### 实正根无法产生峰值 + +对于*实正根* $\lambda_1, \lambda_2 > 0$,一阶条件 {eq}`chow_hs_foc` 无法满足。 + +要理解为什么,回顾在内部频率 $\omega \in (0, \pi)$ 处的谱峰需要 + +```{math} +\cos\omega = \frac{(1 + \lambda_1^2)\lambda_2 + (1 + \lambda_2^2)\lambda_1}{4\lambda_1 \lambda_2}. +``` + +为使其有解,我们需要右边位于 $[-1, 1]$ 内。 + +但对于正的 $\lambda_1, \lambda_2$,分子超过 $4\lambda_1\lambda_2$: + +```{math} +:label: chow_hs_real_proof + +(1 + \lambda_1^2)\lambda_2 + (1 + \lambda_2^2)\lambda_1 - 4\lambda_1\lambda_2 = \lambda_1(1-\lambda_2)^2 + \lambda_2(1-\lambda_1)^2. +``` + +右边是两个非负项之和(每一项都是一个正数乘以一个平方)。 + +它只有在 $\lambda_1 = 1$ 和 $\lambda_2 = 1$ 同时成立时才等于零,这违反了稳定性条件 $|\lambda_i| < 1$。 + +对于任何具有实正根的稳定系统,这个表达式严格为正,所以 + +```{math} +:label: chow_hs_real_impossible + +\cos\omega = \frac{(1 + \lambda_1^2)\lambda_2 + (1 + \lambda_2^2)\lambda_1}{4\lambda_1 \lambda_2} > 1, +``` + +这是不可能的。 + +这是一个关键结果:在 Hansen-Samuelson 模型中,*复根对于内部频率处的谱峰是必要的*。 + +下图说明了具有复根的情况与具有实根的情况之间谱的差异 + +```{code-cell} ipython3 +ω_grid = np.linspace(1e-3, np.pi - 1e-3, 800) +V_hs = np.array([[1.0, 0.0], [0.0, 0.0]]) # 仅第一个方程中有冲击 + +# 情况 1:复根 (c=0.6, v=0.8) +c_complex, v_complex = 0.6, 0.8 +A_complex = samuelson_transition(c_complex, v_complex) +eig_complex = np.linalg.eigvals(A_complex) + +# 情况 2:实根 (c=0.8, v=0.1) +c_real, v_real = 0.8, 0.1 +A_real = samuelson_transition(c_real, v_real) +eig_real = np.linalg.eigvals(A_real) + +print( + f"复根情况 (c={c_complex}, v={v_complex}):特征值 = {eig_complex}") +print( + f"实根情况 (c={c_real}, v={v_real}):特征值 = {eig_real}") + +F_complex = spectral_density_var1(A_complex, V_hs, ω_grid) +F_real = spectral_density_var1(A_real, V_hs, ω_grid) + +f11_complex = np.real(F_complex[:, 0, 0]) +f11_real = np.real(F_real[:, 0, 0]) + +fig, ax = plt.subplots() +ax.plot(ω_grid / np.pi, f11_complex / np.max(f11_complex), lw=2, + label=fr'复根 ($c={c_complex}, v={v_complex}$)') +ax.plot(ω_grid / np.pi, f11_real / np.max(f11_real), lw=2, + label=fr'实根 ($c={c_real}, v={v_real}$)') +ax.set_xlabel(r'频率 $\omega/\pi$') +ax.set_ylabel('归一化谱') +ax.legend(frameon=False) +plt.show() +``` + +对于复根,谱有一个清晰的内部峰值。 + +对于实根,谱单调递减,不可能有内部峰值。 + +## 实根可以在一般模型中产生峰值 + +虽然实正根不能在 Hansen-Samuelson 模型中产生谱峰,{cite:t}`Chow1968` 强调这在一般情况下*并不成立*。 + +在多元系统中,即使所有特征值都是实数且为正,变量线性组合的谱密度也可以有内部峰值。 + +### 例子 + +Chow 构造了以下具有两个实正特征值的明确例子: + +```{math} +:label: chow_real_roots_example + +\lambda_1 = 0.1, \quad \lambda_2 = 0.9 +``` + +```{math} +:label: chow_real_roots_W + +w_{11} = w_{22} = 1, \quad w_{12} = 0.8 +``` + +```{math} +:label: chow_real_roots_b + +b_{m1} = 1, \quad b_{m2} = -0.01 +``` + +线性组合 $x_t = b_m^\top y_t$ 的谱密度为: + +```{math} +:label: chow_real_roots_spectrum + +f_{mm}(\omega) = \frac{0.9913}{1.01 - 0.2\cos\omega} - \frac{0.001570}{1.81 - 1.8\cos\omega} +``` + +Chow 列出了这些值: + +| $\omega$ | $0$ | $\pi/8$ | $2\pi/8$ | $3\pi/8$ | $4\pi/8$ | $5\pi/8$ | $6\pi/8$ | $7\pi/8$ | $\pi$ | +|----------|-----|---------|----------|----------|----------|----------|----------|----------|-------| +| $f_{mm}(\omega)$ | 1.067 | 1.183 | 1.191 | 1.138 | 1.061 | 0.981 | 0.912 | 0.860 | 0.829 | + +在略低于 $\pi/8$ 的 $\omega$ 处(对应约 11 个周期的周期)的峰值"相当明显"。 + +在下图中,我们重现这个表,但用 Python,我们可以绘制更精细的网格以更准确地找到峰值 + +```{code-cell} ipython3 +λ1, λ2 = 0.1, 0.9 +w11, w22, w12 = 1.0, 1.0, 0.8 +bm1, bm2 = 1.0, -0.01 + +# 构造系统 +A_chow_ex = np.diag([λ1, λ2]) + +# W 是规范冲击协方差;我们需要 V = B W B^T +# 对于具有不同特征值的对角 A,B = I,所以 V = W +V_chow_ex = np.array([[w11, w12], [w12, w22]]) +b_chow_ex = np.array([bm1, bm2]) + +# Chow 的公式 +def chow_spectrum_formula(ω): + term1 = 0.9913 / (1.01 - 0.2 * np.cos(ω)) + term2 = 0.001570 / (1.81 - 1.8 * np.cos(ω)) + return term1 - term2 + +# 通过公式和通过我们的一般方法计算 +ω_table = np.array([0, np.pi/8, 2*np.pi/8, 3*np.pi/8, 4*np.pi/8, + 5*np.pi/8, 6*np.pi/8, 7*np.pi/8, np.pi]) +f_formula = np.array([chow_spectrum_formula(ω) for ω in ω_table]) + +# 一般方法 +ω_grid_fine = np.linspace(1e-4, np.pi, 1000) +F_chow_ex = spectral_density_var1(A_chow_ex, V_chow_ex, ω_grid_fine) +f_general = spectrum_of_linear_combination(F_chow_ex, b_chow_ex) + +# 归一化以匹配 Chow 表的尺度 +scale = f_formula[0] / spectrum_of_linear_combination( + spectral_density_var1( + A_chow_ex, V_chow_ex, np.array([0.0])), b_chow_ex)[0] + +print("Chow 的表(方程 67):") +print("ω/π: ", " ".join([f"{ω/np.pi:.3f}" for ω in ω_table])) +print("f_mm(ω): ", " ".join([f"{f:.3f}" for f in f_formula])) + +fig, ax = plt.subplots(figsize=(9, 4)) +ax.plot(ω_grid_fine / np.pi, f_general * scale, lw=2, + label='谱') +ax.scatter(ω_table / np.pi, f_formula, s=50, zorder=3, + label="Chow 的表值") + +# 标记峰值 +i_peak = np.argmax(f_general) +ω_peak = ω_grid_fine[i_peak] +ax.axvline(ω_peak / np.pi, ls='--', lw=1.0, color='gray', alpha=0.7) +ax.set_xlabel(r'频率 $\omega/\pi$') +ax.set_ylabel(r'$f_{mm}(\omega)$') +ax.legend(frameon=False) +plt.show() + +print(f"\n峰值在 ω/π ≈ {ω_peak/np.pi:.3f},周期 ≈ {2*np.pi/ω_peak:.1f}") +``` + +峰值出现在 $\omega/\pi \approx 0.10$ 处,对应约 20 个周期的周期长度,同样比特征值隐含的确定性周期长得多。 + +### 斯卢茨基联系 + +Chow 将这个结果与斯卢茨基 {cite}`slutsky1937` 的发现联系起来,即随机序列的移动平均具有反复出现的周期。 + +VAR(1) 模型可以写成无限移动平均: + +```{math} +:label: chow_ma_rep + +y_t = u_t + A u_{t-1} + A^2 u_{t-2} + \cdots +``` + +这相当于用"几何递减"的权重 $A^0, A^1, A^2, \ldots$ 对随机向量 $u_t$ 取无限移动平均。 + +对于具有 $0 < \lambda < 1$ 的标量过程,不会出现明显的周期。 + +但对于具有 0 到 1 之间实根的矩阵 $A$,周期*可以*在变量的线性组合中出现。 + +正如 Chow 所说:"当两个(规范)变量都没有明显的周期时……一个线性组合可以在其谱密度中有一个峰值。" + +### 一般教训 + +上面的例子说明了以下核心要点: + +1. 在*特定的 Hansen-Samuelson 模型*中,复根对谱峰是必要的 +2. 但在*一般多元系统*中,复根既不必要也不充分 +3. 完整的谱形状依赖于: + - $A$ 的特征值 + - 冲击协方差结构 $V$ + - 感兴趣的可观测量如何加载于特征模态(向量 $b$) + +## 频域中的一个校准模型 + +{cite:t}`ChowLevitan1969` 使用来自 {cite:t}`Chow1968` 的频域对象来研究一个校准的年度宏观计量经济模型。 + +他们使用五个年度总量: + +- $y_1 = C$(消费), +- $y_2 = I_1$(设备加库存), +- $y_3 = I_2$(建筑), +- $y_4 = R_a$(长期利率), +- $y_5 = Y_1 = C + I_1 + I_2$(私人国内 GNP), + +并加入 $y_6 = y_{1,t-1}$ 以将原始系统重写为一阶形式。 + +在整个这一节中,频率以每年周期数衡量,$f = \omega/2\pi \in [0, 1/2]$。 + +遵循论文,我们将每个谱归一化,使其在 $[0, 1/2]$ 上的面积为 1,以便图比较形状而非尺度。 + +我们的目标是重构转移矩阵 $A$,然后计算并解释模型隐含的谱、增益/相干性和相位差。 + +### 周期子系统 + +论文从带有外生输入的简化形式开始, + +```{math} +:label: chow_reduced_full + +y_t = A y_{t-1} + C x_t + u_t. +``` + +为了研究周期,他们移除归因于 $x_t$ 的确定性成分,并专注于零均值子系统 + +```{math} +:label: chow_cycle_system + +y_t = A y_{t-1} + u_t. +``` + +对于二阶矩,唯一额外的组成部分是协方差矩阵 $V = \mathbb E[u_t u_t^\top]$。 + +Chow 和 Levitan 通过以下方式从结构参数计算它 + +```{math} +:label: chow_v_from_structural + +V = M^{-1} \Sigma (M^{-1})^\top +``` + +其中 $\Sigma$ 是结构残差的协方差,$M$ 是同期结构系数矩阵。 + +这里我们将 $A$ 和 $V$ 视为给定,并询问它们对谱和交叉谱意味着什么。 + +Chow 和 Levitan 报告的 $6 \times 6$ 简化形式冲击协方差矩阵 $V$(按 $10^{-7}$ 缩放)为: + +```{math} +:label: chow_V_matrix + +V = \begin{bmatrix} +8.250 & 7.290 & 2.137 & 2.277 & 17.68 & 0 \\ +7.290 & 7.135 & 1.992 & 2.165 & 16.42 & 0 \\ +2.137 & 1.992 & 0.618 & 0.451 & 4.746 & 0 \\ +2.277 & 2.165 & 0.451 & 1.511 & 4.895 & 0 \\ +17.68 & 16.42 & 4.746 & 4.895 & 38.84 & 0 \\ +0 & 0 & 0 & 0 & 0 & 0 +\end{bmatrix}. +``` + +第六行和列为零,因为 $y_6$ 是一个恒等式(滞后的 $y_1$)。 + +转移矩阵 $A$ 有六个特征根: + +```{math} +:label: chow_eigenvalues + +\begin{aligned} +\lambda_1 &= 0.9999725, \quad \lambda_2 = 0.9999064, \quad \lambda_3 = 0.4838, \\ +\lambda_4 &= 0.0761 + 0.1125i, \quad \lambda_5 = 0.0761 - 0.1125i, \quad \lambda_6 = -0.00004142. +\end{aligned} +``` + +两个根接近于 1,因为两个结构方程是一阶差分的。 + +一个根($\lambda_6$)在理论上为零,因为恒等式 $y_5 = y_1 + y_2 + y_3$。 + +共轭复数对 $\lambda_{4,5}$ 的模为 $|\lambda_4| = \sqrt{0.0761^2 + 0.1125^2} \approx 0.136$。 + +右特征向量矩阵 $B$(列是对应于 $\lambda_1, \ldots, \lambda_6$ 的特征向量): + +```{math} +:label: chow_B_matrix + +B = \begin{bmatrix} +-0.008 & 1.143 & 0.320 & 0.283+0.581i & 0.283-0.581i & 0.000 \\ +-0.000 & 0.013 & -0.586 & -2.151+0.742i & -2.151-0.742i & 2.241 \\ +-0.001 & 0.078 & 0.889 & -0.215+0.135i & -0.215-0.135i & 0.270 \\ +1.024 & 0.271 & 0.069 & -0.231+0.163i & -0.231-0.163i & 0.307 \\ +-0.009 & 1.235 & 0.623 & -2.082+1.468i & -2.082-1.468i & 2.766 \\ +-0.008 & 1.143 & 0.662 & 4.772+0.714i & 4.772-0.714i & -4.399 +\end{bmatrix}. +``` + +$V$、$\{\lambda_i\}$ 和 $B$ 一起足以计算所有谱和交叉谱密度。 + +### 重构 $A$ 并计算 $F(\omega)$ + +论文报告了 $(\lambda, B, V)$,这足以重构 +$A = B \, \mathrm{diag}(\lambda_1,\dots,\lambda_6)\, B^{-1}$,然后计算模型隐含的谱对象。 + +```{code-cell} ipython3 +λ = np.array([ + 0.9999725, 0.9999064, 0.4838, + 0.0761 + 0.1125j, 0.0761 - 0.1125j, -0.00004142 +], dtype=complex) + +B = np.array([ + [-0.008, 1.143, 0.320, 0.283+0.581j, 0.283-0.581j, 0.000], + [-0.000, 0.013, -0.586, -2.151+0.742j, -2.151-0.742j, 2.241], + [-0.001, 0.078, 0.889, -0.215+0.135j, -0.215-0.135j, 0.270], + [1.024, 0.271, 0.069, -0.231+0.163j, -0.231-0.163j, 0.307], + [-0.009, 1.235, 0.623, -2.082+1.468j, -2.082-1.468j, 2.766], + [-0.008, 1.143, 0.662, 4.772+0.714j, 4.772-0.714j, -4.399] +], dtype=complex) + +V = np.array([ + [8.250, 7.290, 2.137, 2.277, 17.68, 0], + [7.290, 7.135, 1.992, 2.165, 16.42, 0], + [2.137, 1.992, 0.618, 0.451, 4.746, 0], + [2.277, 2.165, 0.451, 1.511, 4.895, 0], + [17.68, 16.42, 4.746, 4.895, 38.84, 0], + [0, 0, 0, 0, 0, 0] +]) * 1e-7 + +D_λ = np.diag(λ) +A_chow = B @ D_λ @ np.linalg.inv(B) +A_chow = np.real(A_chow) +print("重构 A 的特征值:") +print(np.linalg.eigvals(A_chow).round(6)) +``` + +### 规范坐标 + +Chow 和 Levitan 的规范变换使用 $z_t = B^{-1} y_t$,给出动态 $z_t = D_\lambda z_{t-1} + e_t$。 + +相应地,规范冲击协方差为 + +```{math} +W = B^{-1} V (B^{-1})^\top. +``` + +```{code-cell} ipython3 +B_inv = np.linalg.inv(B) +W = B_inv @ V @ B_inv.T +print("W 的对角线:") +print(np.diag(W).round(10)) +``` + +Chow 和 Levitan 推导了以下谱密度矩阵的闭式公式: + +```{math} +:label: chow_spectral_eigen + +F(\omega) += B \left[ \frac{w_{ij}}{(1 - \lambda_i e^{-i\omega})(1 - \lambda_j e^{i\omega})} \right] B^\top, +``` + +其中 $w_{ij}$ 是规范冲击协方差 $W$ 的元素。 + +```{code-cell} ipython3 +def spectral_density_chow(λ, B, W, ω_grid): + """通过 Chow 的特征分解公式计算谱密度。""" + p = len(λ) + F = np.zeros((len(ω_grid), p, p), dtype=complex) + for k, ω in enumerate(ω_grid): + F_star = np.zeros((p, p), dtype=complex) + for i in range(p): + for j in range(p): + denom = (1 - λ[i] * np.exp(-1j * ω)) \ + * (1 - λ[j] * np.exp(1j * ω)) + F_star[i, j] = W[i, j] / denom + F[k] = B @ F_star @ B.T + return F / (2 * np.pi) + +freq = np.linspace(1e-4, 0.5, 5000) # [0, 1/2] 内每年周期数 +ω_grid = 2 * np.pi * freq # [0, π] 内弧度 +F_chow = spectral_density_chow(λ, B, W, ω_grid) +``` + +让我们绘制消费($y_1$)和设备加库存($y_2$)的单变量谱 + +```{code-cell} ipython3 +variable_names = ['$C$', '$I_1$', '$I_2$', '$R_a$', '$Y_1$'] +freq_ticks = [1/18, 1/9, 1/6, 1/4, 1/3, 1/2] +freq_labels = [r'$\frac{1}{18}$', r'$\frac{1}{9}$', r'$\frac{1}{6}$', + r'$\frac{1}{4}$', r'$\frac{1}{3}$', r'$\frac{1}{2}$'] + +def paper_frequency_axis(ax): + ax.set_xlim([0.0, 0.5]) + ax.set_xticks(freq_ticks) + ax.set_xticklabels(freq_labels) + ax.set_xlabel(r'频率 $\omega/2\pi$') + +# 归一化谱(面积设为 1) +S = np.real(np.diagonal(F_chow, axis1=1, axis2=2))[:, :5] +df = np.diff(freq) +areas = np.sum(0.5 * (S[1:] + S[:-1]) * df[:, None], axis=0) +S_norm = S / areas +mask = freq >= 0.0 + +fig, axes = plt.subplots(1, 2, figsize=(10, 6)) + +# 图 I.1:消费(对数刻度) +axes[0].plot(freq[mask], S_norm[mask, 0], lw=2) +axes[0].set_yscale('log') +paper_frequency_axis(axes[0]) +axes[0].set_ylabel(r'归一化 $f_{11}(\omega)$') + +# 图 I.2:设备 + 库存(对数刻度) +axes[1].plot(freq[mask], S_norm[mask, 1], lw=2) +axes[1].set_yscale('log') +paper_frequency_axis(axes[1]) +axes[1].set_ylabel(r'归一化 $f_{22}(\omega)$') + +plt.tight_layout() +plt.show() + +i_peak = np.argmax(S_norm[mask, 1]) +f_peak = freq[mask][i_peak] +``` + +左图对应于消费,随频率单调递减。 + +它说明了 Granger 关于宏观经济时间序列的"典型谱形状"。 + +右图对应于设备加库存,显示出最清晰(但仍然非常平坦)的内部频率隆起。 + +Chow 和 Levitan 将两个图中极低频率的主导地位与强持续性和长期运动联系起来。 + +极大的低频功率可能源于极接近于 1 的特征值,这在某些方程以一阶差分形式写出时机械地出现。 + +局部峰值不是自动出现的:复根可能具有小的模,而多元相互作用即使在所有根都为实数时也能产生峰值。 + +右图中的内部隆起对应于大约三年的周期,谱在大约两到四年的周期上几乎平坦。 + +(此讨论遵循 {cite}`ChowLevitan1969` 的第 II 节。) + +### 变量如何跨频率一起运动 + +除了单变量谱,我们还可以问变量对如何在每个频率上协变。 + +**交叉谱** $f_{ij}(\omega) = c_{ij}(\omega) - i \cdot q_{ij}(\omega)$ 分解为共谱 $c_{ij}$ 和正交谱 $q_{ij}$。 + +**交叉幅度**为 $g_{ij}(\omega) = |f_{ij}(\omega)| = \sqrt{c_{ij}^2 + q_{ij}^2}$。 + +**平方相干性**衡量频率 $\omega$ 处的线性关联: + +```{math} +:label: chow_coherence + +R^2_{ij}(\omega) = \frac{|f_{ij}(\omega)|^2}{f_{ii}(\omega) f_{jj}(\omega)} \in [0, 1]. +``` + +相干性衡量 $y_i$ 在频率 $\omega$ 处的方差有多少可以由同频率的 $y_j$ "解释"。 + +高相干性意味着两个序列在该频率上紧密地一起运动。 + +**增益**是将 $y_i$ 对 $y_j$ 回归时的频率响应系数: + +```{math} +:label: chow_gain + +G_{ij}(\omega) = \frac{|f_{ij}(\omega)|}{f_{jj}(\omega)}. +``` + +它衡量 $y_i$ 对 $y_j$ 在频率 $\omega$ 处单位变化的反应程度。 + +例如,低频处增益 0.9 意味着 $y_j$ 中的长周期运动几乎一对一地转化为 $y_i$,而高频处增益 0.3 意味着短周期运动被抑制。 + +**相位**捕捉领先-滞后关系(以弧度为单位): + +```{math} +:label: chow_phase + +\Delta_{ij}(\omega) = \tan^{-1}\left( \frac{q_{ij}(\omega)}{c_{ij}(\omega)} \right). +``` + +```{code-cell} ipython3 +def cross_spectral_measures(F, i, j): + """计算变量 i 和 j 之间的相干性、增益(y_i 对 y_j)和相位。""" + f_ij = F[:, i, j] + f_ii, f_jj = np.real(F[:, i, i]), np.real(F[:, j, j]) + g_ij = np.abs(f_ij) + coherence = (g_ij**2) / (f_ii * f_jj) + gain = g_ij / f_jj + phase = np.arctan2(-np.imag(f_ij), np.real(f_ij)) + return coherence, gain, phase +``` + +我们现在绘制增益和相干性,如 {cite}`ChowLevitan1969` 的图 II.1–II.4。 + +```{code-cell} ipython3 +gnp_idx = 4 + +fig, axes = plt.subplots(1, 2, figsize=(8, 6)) + +for idx, var_idx in enumerate([0, 1]): + coherence, gain, phase = cross_spectral_measures(F_chow, var_idx, gnp_idx) + ax = axes[idx] + + ax.plot(freq[mask], coherence[mask], + lw=2, label=rf'$R^2_{{{var_idx+1}5}}(\omega)$') + ax.plot(freq[mask], gain[mask], + lw=2, label=rf'$G_{{{var_idx+1}5}}(\omega)$') + paper_frequency_axis(ax) + ax.set_ylim([0, 1.0]) + ax.set_ylabel('增益、相干性') + ax.legend(frameon=False, loc='best') + +plt.tight_layout() +plt.show() +``` + +增益和相干性模式在各成分之间不同({cite}`ChowLevitan1969` 的图 II.1–II.2): + +- 消费与私人国内 GNP(左图): + - 增益在极低频率处约为 0.9,但对于短于四年的周期降至 0.4 以下。 + - 这证明短周期收入运动转化为消费的程度低于长周期运动,与永久收入解释一致。 + - 相干性始终保持较高。 +- 设备加库存与私人国内 GNP(右图): + - 增益*随频率上升*,短周期时超过 0.5。 + - 这是加速和波动的短期库存运动的频域特征。 + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(8, 6)) + +for idx, var_idx in enumerate([2, 3]): + coherence, gain, phase = cross_spectral_measures(F_chow, var_idx, gnp_idx) + ax = axes[idx] + + ax.plot(freq[mask], coherence[mask], + lw=2, label=rf'$R^2_{{{var_idx+3}5}}(\omega)$') + ax.plot(freq[mask], gain[mask], + lw=2, label=rf'$G_{{{var_idx+3}5}}(\omega)$') + paper_frequency_axis(ax) + ax.set_ylim([0, 1.0]) + ax.set_ylabel('增益、相干性') + ax.legend(frameon=False, loc='best') + +plt.tight_layout() +plt.show() +``` + +- 新建筑与私人国内 GNP(左图): + - 增益在中等周期长度处达到峰值(短周期约为 0.1)。 + - 两个投资序列的相干性在各频率上都保持相当高。 +- 长期债券收益率与私人国内 GNP(右图): + - 增益在各频率上的变化小于实际活动序列。 + - 在商业周期频率上与产出的相干性相对较低,使得难以通过反转货币需求方程来解释利率运动。 + + +### 领先-滞后关系 + +相位告诉我们哪个变量在每个频率上领先。 + +正相位意味着产出领先于该成分;负相位意味着该成分领先于产出。 + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +labels = [r'$\psi_{15}(\omega)/2\pi$', r'$\psi_{25}(\omega)/2\pi$', + r'$\psi_{35}(\omega)/2\pi$', r'$\psi_{45}(\omega)/2\pi$'] + +for var_idx in range(4): + coherence, gain, phase = cross_spectral_measures(F_chow, var_idx, gnp_idx) + phase_cycles = phase / (2 * np.pi) + ax.plot(freq[mask], phase_cycles[mask], lw=2, label=labels[var_idx]) + +ax.axhline(0, lw=0.8) +paper_frequency_axis(ax) +ax.set_ylabel('以周期为单位的相位差') +ax.set_ylim([-0.25, 0.25]) +ax.set_yticks(np.arange(-0.25, 0.3, 0.05), minor=True) +ax.legend(frameon=False) +plt.tight_layout() +plt.show() +``` + +相位关系揭示了: + +- 产出领先消费一小部分周期(6 年周期约 0.06 个周期,3 年周期约 0.04 个周期)。 +- 设备加库存倾向于领先产出(6 年周期约 0.07 个周期,3 年周期约 0.03 个周期)。 +- 新建筑在低频处领先,在高频处接近同步。 +- 债券收益率略微滞后产出,在时间上保持接近同步。 + +这些隐含的领先和滞后大致与其他地方报告的转折点时机总结一致,同一模型的模拟在转折点处产生类似的领先-滞后排序({cite}`ChowLevitan1969` 的图 III)。 + +### 谱形状的组成部分 + +每个特征值通过*标量核*贡献一个特征谱形状 + +```{math} +:label: chow_scalar_kernel + +g_i(\omega) = \frac{1 - |\lambda_i|^2}{|1 - \lambda_i e^{-i\omega}|^2} = \frac{1 - |\lambda_i|^2}{1 + |\lambda_i|^2 - 2 \text{Re}(\lambda_i) \cos\omega + 2 \text{Im}(\lambda_i) \sin\omega}. +``` + +对于实数 $\lambda_i$,这简化为 + +```{math} +g_i(\omega) = \frac{1 - \lambda_i^2}{1 + \lambda_i^2 - 2\lambda_i \cos\omega}. +``` + +每个可观测的谱密度是这些核的线性组合(加上交叉项)。 + +下面,我们绘制每个特征值的标量核,以了解它们如何塑造整体谱 + +```{code-cell} ipython3 +def scalar_kernel(λ_i, ω_grid): + """标量谱核 g_i(ω)。""" + λ_i = complex(λ_i) + mod_sq = np.abs(λ_i)**2 + return np.array( + [(1 - mod_sq) / np.abs(1 - λ_i * np.exp(-1j * ω))**2 + for ω in ω_grid]) + +fig, ax = plt.subplots(figsize=(10, 5)) +for i, λ_i in enumerate(λ): + if np.abs(λ_i) > 0.01: + g_i = scalar_kernel(λ_i, ω_grid) + label = f'$\\lambda_{i+1}$ = {λ_i:.4f}' \ + if np.isreal(λ_i) else f'$\\lambda_{i+1}$ = {λ_i:.3f}' + ax.semilogy(freq, g_i, label=label, lw=2) + +ax.set_xlabel(r'频率 $\omega/2\pi$') +ax.set_ylabel('$g_i(\\omega)$') +ax.set_xlim([1/18, 0.5]) +ax.set_xticks(freq_ticks) +ax.set_xticklabels(freq_labels) +ax.legend(frameon=False) +plt.show() +``` + +该图揭示了特征值大小如何塑造谱贡献: + +- *接近于 1 的特征值*($\lambda_1, \lambda_2 \approx 1$)产生在低频处急剧达到峰值的核,因为这些驱动了上面谱中看到的强低频功率。 +- *中等特征值*($\lambda_3 \approx 0.48$)贡献一个更平坦的成分,将功率更均匀地分布在各频率上。 +- *复数对*($\lambda_{4,5}$)的模太小($|\lambda_{4,5}| \approx 0.136$),以至于其核几乎平坦,太弱而无法产生明显的内部峰值。 + +这个分解解释了为什么谱看起来是这样的:接近于 1 的特征值占主导地位,将方差集中在极低频率处。 + +复数对尽管在原则上使振荡动态成为可能,但模不足,无法产生可见的谱峰。 + +## 总结 + +{cite:t}`Chow1968` 得出了几个对理解商业周期仍然相关的结论。 + +加速原理得到了强有力的经验支持:投资方程中滞后产出的负系数是跨数据集的稳健发现。 + +特征值与谱峰之间的关系比乍看起来更为微妙: + +- 复根保证振荡的自协方差,但它们对明显的谱峰既不必要也不充分。 + +- 特别是在 Hansen–Samuelson 模型中,复根*确实*对峰值是必要的。 + +- 但在一般多元系统中,即使是实根也可以通过冲击和特征向量载荷的相互作用产生峰值。 + +{cite:t}`ChowLevitan1969` 演示了这些对象在一个校准系统中的样子:来自接近于 1 的特征值的强低频功率、频率相关的增益和相干性,以及随周期长度变化的领先-滞后关系。 + +他们的结果与 Granger 关于经济时间序列的"典型谱形状"一致。 + +即一个随频率单调递减的函数,由某些方程以一阶差分形式指定时出现的接近于 1 的特征值驱动。 + +理解这种形状是否反映了真实的数据生成过程,需要分析结构计量经济模型隐含的谱密度。 + +## 练习 + +```{exercise} +:label: chow_cycles_ex1 + +在 Hansen-Samuelson 模型中,为加速数 $v$ 的几个值并排绘制脉冲响应和谱,展示加速强度如何影响时域和频域特征。 + +使用与正文相同的 $v$ 值:$v \in \{0.2, 0.4, 0.6, 0.8, 0.95\}$,$c = 0.6$。 +``` + +```{solution-start} chow_cycles_ex1 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +v_grid_ex1 = [0.2, 0.4, 0.6, 0.8, 0.95] +c_ex1 = 0.6 +freq_ex1 = np.linspace(1e-4, 0.5, 2000) +ω_grid_ex1 = 2 * np.pi * freq_ex1 +V_ex1 = np.array([[1.0, 0.0], [0.0, 0.0]]) +T_irf_ex1 = 40 + +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +for v in v_grid_ex1: + A = samuelson_transition(c_ex1, v) + + # 脉冲响应(左图) + s = np.array([1.0, 0.0]) + irf = np.empty(T_irf_ex1 + 1) + for t in range(T_irf_ex1 + 1): + irf[t] = s[0] + s = A @ s + axes[0].plot(range(T_irf_ex1 + 1), irf, lw=2, label=f'$v={v}$') + + # 谱(右图) + F = spectral_density_var1(A, V_ex1, ω_grid_ex1) + f11 = np.real(F[:, 0, 0]) + df = np.diff(freq_ex1) + area = np.sum(0.5 * (f11[1:] + f11[:-1]) * df) + f11_norm = f11 / area + axes[1].plot(freq_ex1, f11_norm, lw=2, label=f'$v={v}$') + +axes[0].axhline(0, lw=0.8, color='gray') +axes[0].set_xlabel('时间') +axes[0].set_ylabel(r'$Y_t$') +axes[0].legend(frameon=False) + +axes[1].set_xlabel(r'频率 $\omega/2\pi$') +axes[1].set_ylabel('归一化谱') +axes[1].set_xlim([0, 0.5]) +axes[1].set_yscale('log') +axes[1].legend(frameon=False) + +plt.tight_layout() +plt.show() +``` + +随着 $v$ 增加,特征值接近单位圆:振荡在时域中变得更加持久(左),谱峰在频域中变得更尖锐(右)。 + +复根在内部频率处产生明显的峰值——这是商业周期的谱特征。 + +```{solution-end} +``` + +```{exercise} +:label: chow_cycles_ex2 + +对 Hansen-Samuelson 模型数值验证谱峰条件 {eq}`chow_hs_peak_condition`。 + +1. 对于固定 $\theta = 60°$ 的一系列特征值模 $r \in [0.3, 0.99]$,计算: + - 来自公式的理论峰值频率:$\cos\omega = \frac{1+r^2}{2r}\cos\theta$ + - 通过数值最大化谱密度得到的实际峰值频率 +2. 在同一图上绘制两者并验证它们匹配。 +3. 确定没有有效峰值存在的 $r$ 范围(当条件 {eq}`chow_hs_necessary` 被违反时)。 +``` + +```{solution-start} chow_cycles_ex2 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +θ_ex = np.pi / 3 # 60 度 +r_grid = np.linspace(0.3, 0.99, 50) +ω_grid_ex = np.linspace(1e-3, np.pi - 1e-3, 1000) +V_hs_ex = np.array([[1.0, 0.0], [0.0, 0.0]]) + +ω_theory = [] +ω_numerical = [] + +for r in r_grid: + # 理论峰值 + factor = (1 + r**2) / (2 * r) + cos_ω = factor * np.cos(θ_ex) + if -1 < cos_ω < 1: + ω_theory.append(np.arccos(cos_ω)) + else: + ω_theory.append(np.nan) + + # 来自谱密度的数值峰值 + # 构造具有特征值 r*exp(+-iθ) 的 Hansen-Samuelson + # 这对应于 c + v = 2r*cos(θ), v = r^2 + v = r**2 + c = 2 * r * np.cos(θ_ex) - v + A_ex = samuelson_transition(c, v) + F_ex = spectral_density_var1(A_ex, V_hs_ex, ω_grid_ex) + f11 = np.real(F_ex[:, 0, 0]) + i_max = np.argmax(f11) + + # 只有当峰值不在边界时才算作峰值 + if 5 < i_max < len(ω_grid_ex) - 5: + ω_numerical.append(ω_grid_ex[i_max]) + else: + ω_numerical.append(np.nan) + +ω_theory = np.array(ω_theory) +ω_numerical = np.array(ω_numerical) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +# 绘制峰值频率 +axes[0].plot(r_grid, ω_theory / np.pi, lw=2, label="Chow 的公式") +axes[0].plot(r_grid, ω_numerical / np.pi, 'o', markersize=4, label='数值') +axes[0].axhline(θ_ex / np.pi, ls='--', lw=1.0, color='gray', label=r'$\theta/\pi$') +axes[0].set_xlabel('特征值模 $r$') +axes[0].set_ylabel(r'峰值频率 $\omega^*/\pi$') +axes[0].legend(frameon=False) + +# 绘制因子 (1+r^2)/2r 以显示峰值何时有效 +axes[1].plot(r_grid, (1 + r_grid**2) / (2 * r_grid), lw=2) +axes[1].axhline(1 / np.cos(θ_ex), ls='--', lw=1.0, color='red', + label=f'阈值 = 1/cos({np.rad2deg(θ_ex):.0f}°) = {1/np.cos(θ_ex):.2f}') +axes[1].set_xlabel('特征值模 $r$') +axes[1].set_ylabel(r'$(1+r^2)/2r$') +axes[1].legend(frameon=False) + +plt.tight_layout() +plt.show() + +# 找到没有峰值存在的阈值 r +valid_mask = ~np.isnan(ω_theory) +if valid_mask.any(): + r_threshold = r_grid[valid_mask][0] + print(f"峰值存在于 r >= {r_threshold:.2f}") +``` + +理论和数值峰值频率紧密匹配。 + +当 $r \to 1$ 时,峰值频率收敛到 $\theta$。 + +对于较小的 $r$,因子 $(1+r^2)/2r$ 超过阈值,不存在有效峰值。 + +```{solution-end} +``` + +```{exercise} +:label: chow_cycles_ex3 + +在"实根但有峰值"的例子中,保持 $A$ 固定,并将冲击相关性($V$ 的非对角元)在 $0$ 和 $0.99$ 之间变化。 + +内部频率峰值何时出现,它的位置如何变化? +``` + +```{solution-start} chow_cycles_ex3 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +A_ex3 = np.diag([0.1, 0.9]) +b_ex3 = np.array([1.0, -0.01]) +corr_grid = np.linspace(0, 0.99, 50) +peak_periods = [] +for corr in corr_grid: + V_ex3 = np.array([[1.0, corr], [corr, 1.0]]) + F_ex3 = spectral_density_var1(A_ex3, V_ex3, ω_grid_ex) + f_x = spectrum_of_linear_combination(F_ex3, b_ex3) + i_max = np.argmax(f_x) + if 5 < i_max < len(ω_grid_ex) - 5: + peak_periods.append(2 * np.pi / ω_grid_ex[i_max]) + else: + peak_periods.append(np.nan) + +fig, ax = plt.subplots(figsize=(8, 4)) +ax.plot(corr_grid, peak_periods, marker='o', lw=2, markersize=4) +ax.set_xlabel('冲击相关性') +ax.set_ylabel('峰值周期') +plt.show() + +threshold_idx = np.where(~np.isnan(peak_periods))[0] +if len(threshold_idx) > 0: + print( + f"当相关性 >= {corr_grid[threshold_idx[0]]:.2f} 时出现内部峰值") +``` + +内部峰值只有在冲击相关性超过某个阈值时才出现。 + +这说明谱峰依赖于完整的系统结构,而不仅仅是特征值。 + +```{solution-end} +``` + +```{exercise} +:label: chow_cycles_ex4 + +使用校准的 Chow-Levitan 参数,用以下方法计算自协方差矩阵 $\Gamma_0, \Gamma_1, \ldots, \Gamma_{10}$: + +1. 递归 $\Gamma_k = A \Gamma_{k-1}$,其中 $\Gamma_0$ 来自李雅普诺夫方程。 +2. Chow 的特征分解公式 $\Gamma_k = B D_\lambda^k \Gamma_0^* B^\top$,其中 $\Gamma_0^*$ 是规范协方差。 + +验证两种方法给出相同的结果。 +``` + +```{solution-start} chow_cycles_ex4 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +from scipy.linalg import solve_discrete_lyapunov + +Γ_0_lyap = solve_discrete_lyapunov(A_chow, V) +Γ_recursion = [Γ_0_lyap] +for k in range(1, 11): + Γ_recursion.append(A_chow @ Γ_recursion[-1]) + +p = len(λ) +Γ_0_star = np.zeros((p, p), dtype=complex) +for i in range(p): + for j in range(p): + Γ_0_star[i, j] = W[i, j] / (1 - λ[i] * λ[j]) + +Γ_eigen = [] +for k in range(11): + D_k = np.diag(λ**k) + Γ_eigen.append(np.real(B @ D_k @ Γ_0_star @ B.T)) + +print("Γ_5 的比较(前 3x3 块):") +print("\n递归方法:") +print(np.real(Γ_recursion[5][:3, :3]).round(10)) +print("\n特征分解方法:") +print(Γ_eigen[5][:3, :3].round(10)) +print("\n最大绝对差:", + np.max(np.abs(np.real(Γ_recursion[5]) - Γ_eigen[5]))) +``` + +两种方法产生基本相同的结果,直到数值精度。 + +```{solution-end} +``` + +```{exercise} +:label: chow_cycles_ex5 + +通过将 $\lambda_3$ 从 $0.4838$ 改为 $0.95$ 来修改 Chow-Levitan 模型。 + +1. 重新计算谱密度。 +2. 这个变化如何影响每个变量的谱形状? +3. 什么经济解释可能对应于这个参数变化? +``` + +```{solution-start} chow_cycles_ex5 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +# 修改 λ_3 并重构转移矩阵 +λ_modified = λ.copy() +λ_modified[2] = 0.95 +D_λ_mod = np.diag(λ_modified) +A_mod = np.real(B @ D_λ_mod @ np.linalg.inv(B)) + +# 使用原始 V 通过 VAR(1) 公式计算谱 +F_mod = spectral_density_var1(A_mod, V, ω_grid) +F_orig = spectral_density_var1(A_chow, V, ω_grid) + +# 绘制产出 (Y_1) 的谱比率 +f_orig = np.real(F_orig[:, 4, 4]) +f_mod = np.real(F_mod[:, 4, 4]) + +fig, ax = plt.subplots() +ax.plot(freq, f_mod / f_orig, lw=2) +ax.axhline(1.0, ls='--', lw=1, color='gray') +paper_frequency_axis(ax) +ax.set_ylabel(r"比率:$Y_1$ 的修改后 / 原始谱") +plt.show() +``` + +接近于 1 的特征值($\lambda_1, \lambda_2 \approx 0.9999$)如此强烈地主导产出谱,以至于将 $\lambda_3$ 从 0.48 改为 0.95 只产生较小的相对影响。 + +比率图揭示了这个变化:修改后的谱在低到中频处功率略多,在高频处略少。 + +从经济上讲,增加 $\lambda_3$ 为它所支配的模态增加了持续性。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/endogenous_lake.md b/lectures/endogenous_lake.md new file mode 100644 index 0000000..08a2453 --- /dev/null +++ b/lectures/endogenous_lake.md @@ -0,0 +1,669 @@ +--- +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 +translation: + title: 具有内生工作发现率的湖泊模型 + headings: + Overview: 概述 + Set Up: 设置 + Set Up::Reservation wage: 保留工资 + Set Up::Lake model code: 湖泊模型代码 + Set Up::Linking the McCall search model to the lake model: 将 McCall 搜寻模型与湖泊模型联系起来 + Fiscal policy: 财政政策 + Fiscal policy::Computing optimal unemployment insurance: 计算最优失业保险 + Exercises: 练习 +--- + +(endogenous_lake)= +```{raw} jupyter + +``` + +# 具有内生工作发现率的湖泊模型 + +```{include} _admonition/gpu.md +``` + +```{index} single: Lake Model, Endogenous +``` + +```{contents} Contents +:depth: 2 +``` + +除了 Anaconda 中已有的内容外,本讲座还需要以下库: + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install quantecon jax +``` + +## 概述 + +本讲座是 {doc}`湖泊模型讲座 ` 的续篇。 + +我们建议你在继续本讲座之前先阅读那篇讲座。 + +在上一讲座中,我们研究了一个关于失业和就业的湖泊模型,其中状态之间的转移率是外生参数。 + +在本讲座中,我们通过使工作发现率变为内生的来扩展该模型。 + +具体来说,从失业到就业的转移率将由 McCall 搜寻模型 {cite}`McCall1970` 决定。 + +让我们从一些导入开始: + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import jax +import jax.numpy as jnp +from typing import NamedTuple +from quantecon.distributions import BetaBinomial +from functools import partial +import jax.scipy.stats as stats +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + + + + +## 设置 + +模型的基本结构将如 {doc}`湖泊模型讲座 ` 中所讨论的那样。 + +唯一的区别是雇佣率是内生的,由居住在 McCall 搜寻模型 {cite}`McCall1970` 中的最优化代理人的决策决定,其中工资报价为独立同分布,工作分离率为 $\alpha$。 + + +### 保留工资 + +在模型中,最优策略由一个保留工资 $\bar w$ 刻画 + +* 如果手中的工资报价 $w$ 大于或等于 $\bar w$,则工人接受。 +* 否则,工人拒绝。 + +保留工资取决于工资报价分布和以下参数 + +* $\alpha$,分离率 +* $\beta$,贴现因子 +* $\gamma$,报价到达率 +* $c$,失业补偿 + +工资报价分布将是对数正态分布的离散化版本。 + +我们首先定义一个函数来创建这样的离散分布。 + + +```{code-cell} ipython3 +def create_wage_distribution( + max_wage: float, + wage_grid_size: int, + log_wage_mean: float + ): + """ + 创建对数正态密度 LN(log(m),1) 的离散化版本,其中 + m 是 log_wage_mean。 + + """ + w_vec_temp = jnp.linspace(1e-8, max_wage, wage_grid_size + 1) + cdf = stats.norm.cdf( + jnp.log(w_vec_temp), loc=jnp.log(log_wage_mean), scale=1 + ) + pdf = cdf[1:] - cdf[:-1] + p_vec = pdf / pdf.sum() + w_vec = (w_vec_temp[1:] + w_vec_temp[:-1]) / 2 + return w_vec, p_vec +``` + + +下面的单元格创建一个离散化的 $LN(\log(20),1)$ 工资分布并将其绘制出来。 + +```{code-cell} ipython3 +w_vec, p_vec = create_wage_distribution(170, 200, 20) + +fig, ax = plt.subplots() +ax.plot(w_vec, p_vec) +ax.set_xlabel('工资') +ax.set_ylabel('概率') +plt.tight_layout() +plt.show() +``` + + +现在我们组织给定一组参数下求解 McCall 模型的代码。 + +关于该模型及我们求解方法的背景,请参阅 {doc}`关于具有分离的 McCall 模型的讲座 ` + +我们的第一步是定义效用函数和 McCall 模型数据结构。 + + +```{code-cell} ipython3 +def u(c, σ=2.0): + return jnp.where(c > 0, (c**(1 - σ) - 1) / (1 - σ), -10e6) + + +class McCallModel(NamedTuple): + """ + 存储 McCall 搜寻模型的参数 + """ + α: float # 工作分离率 + β: float # 贴现率 + γ: float # 工作报价率 + c: float # 失业补偿 + σ: float # 效用参数 + w_vec: jnp.ndarray # 可能的工资值 + p_vec: jnp.ndarray # w_vec 上的概率 + + +def create_mccall_model( + α=0.2, β=0.98, γ=0.7, c=6.0, σ=2.0, + w_vec=None, + p_vec=None + ) -> McCallModel: + if w_vec is None: + n = 60 # 工资可能结果的数量 + # 工资在 10 到 20 之间 + w_vec = jnp.linspace(10, 20, n) + a, b = 600, 400 # 形状参数 + dist = BetaBinomial(n-1, a, b) + p_vec = jnp.array(dist.pdf()) + return McCallModel( + α=α, β=β, γ=γ, c=c, σ=σ, w_vec=w_vec, p_vec=p_vec + ) +``` + +接下来,我们实现贝尔曼算子 + +```{code-cell} ipython3 +def T(mcm: McCallModel, V, U): + """ + 更新贝尔曼方程。 + """ + α, β, γ, c, σ = mcm.α, mcm.β, mcm.γ, mcm.c, mcm.σ + w_vec, p_vec = mcm.w_vec, mcm.p_vec + + V_new = u(w_vec, σ) + β * ((1 - α) * V + α * U) + U_new = u(c, σ) + β * (1 - γ) * U + β * γ * (jnp.maximum(U, V) @ p_vec) + + return V_new, U_new +``` + +现在我们定义值函数迭代求解器。 + +我们将使用编译的 while 循环以获得额外的速度。 + +```{code-cell} ipython3 +@jax.jit +def solve_mccall_model(mcm: McCallModel, tol=1e-5, max_iter=2000): + """ + 对贝尔曼方程迭代直到收敛。 + """ + def cond(state): + V, U, i, error = state + return jnp.logical_and(error > tol, i < max_iter) + + def update(state): + V, U, i, error = state + V_new, U_new = T(mcm, V, U) + error_1 = jnp.max(jnp.abs(V_new - V)) + error_2 = jnp.abs(U_new - U) + error_new = jnp.maximum(error_1, error_2) + return V_new, U_new, i + 1, error_new + + # 初始状态 + V_init = jnp.ones(len(mcm.w_vec)) + U_init = 1.0 + i_init = 0 + error_init = tol + 1 + + init_state = (V_init, U_init, i_init, error_init) + V_final, U_final, _, _ = jax.lax.while_loop( + cond, update, init_state + ) + return V_final, U_final +``` + + + +### 湖泊模型代码 + +我们还需要上一讲座中的湖泊模型函数来计算稳态失业率: + +```{code-cell} ipython3 +class LakeModel(NamedTuple): + """ + 湖泊模型的参数 + """ + λ: float + α: float + b: float + d: float + A: jnp.ndarray + R: jnp.ndarray + g: float + + +def create_lake_model( + λ: float = 0.283, # 工作发现率 + α: float = 0.013, # 分离率 + b: float = 0.0124, # 出生率 + d: float = 0.00822 # 死亡率 + ) -> LakeModel: + """ + 使用默认参数创建 LakeModel 实例。 + + 计算并存储转移矩阵 A 和 R, + 以及劳动力增长率 g。 + + """ + # 计算增长率 + g = b - d + + # 计算转移矩阵 A + A = jnp.array([ + [(1-d) * (1-λ) + b, (1-d) * α + b], + [(1-d) * λ, (1-d) * (1-α)] + ]) + + # 计算归一化的转移矩阵 R + R = A / (1 + g) + + return LakeModel(λ=λ, α=α, b=b, d=d, A=A, R=R, g=g) + + +@jax.jit +def rate_steady_state(model: LakeModel) -> jnp.ndarray: + r""" + 通过计算对应于最大特征值的特征向量, + 找到系统 :math:`x_{t+1} = R x_{t}` 的稳态。 + + 根据佩龙-弗罗贝尼乌斯定理,由于 :math:`R` 是一个各列 + 之和为 1 的非负矩阵(随机矩阵),最大特征值等于 1, + 对应的特征向量给出稳态。 + """ + λ, α, b, d, A, R, g = model + eigenvals, eigenvec = jnp.linalg.eig(R) + + # 找到对应于最大特征值的特征向量 + # (对于随机矩阵,根据佩龙-弗罗贝尼乌斯定理该值为 1) + max_idx = jnp.argmax(jnp.abs(eigenvals)) + + # 获取对应的特征向量 + steady_state = jnp.real(eigenvec[:, max_idx]) + + # 归一化以确保正值且和为 1 + steady_state = jnp.abs(steady_state) + steady_state = steady_state / jnp.sum(steady_state) + + return steady_state +``` + + +### 将 McCall 搜寻模型与湖泊模型联系起来 + +假设湖泊模型内的所有工人都按照 McCall 搜寻模型行事。 + +离开就业的外生概率仍然是 $\alpha$。 + +但他们的最优决策规则决定了离开失业的概率 $\lambda$。 + +现在这是 + +```{math} +:label: endogenous_lake_lambda + +\lambda += \gamma \mathbb P \{ w_t \geq \bar w\} += \gamma \sum_{w' \geq \bar w} p(w') +``` + +其中 + +* $\bar w$ 是由参数决定的保留工资, +* $p$ 是工资报价分布。 + +工人群体中的工资报价是从 $p$ 中独立抽取的。 + +这里我们在默认参数下计算 $\lambda$: + + +```{code-cell} ipython3 +mcm = create_mccall_model(w_vec=w_vec, p_vec=p_vec) +V, U = solve_mccall_model(mcm) +w_idx = jnp.searchsorted(V - U, 0) +w_bar = jnp.where(w_idx == len(V), jnp.inf, mcm.w_vec[w_idx]) +λ = mcm.γ * jnp.sum(p_vec * (w_vec > w_bar)) +print(f"默认参数下的工作发现率 ={λ}.") +``` + + + +## 财政政策 + +在本节中,我们将运用湖泊模型,考察与不同水平的失业补偿相关联的结果。 + +我们的目标是找到失业保险的最优水平。 + +我们假设政府设定失业补偿 $c$。 + +政府征收足以为总失业支付提供资金的一次性总付税 $\tau$。 + +要在稳态下实现预算平衡,税收、稳态失业率 $u$ 和失业补偿率必须满足 + +$$ + \tau = u c +$$ + +一次性总付税适用于每个人,包括失业工人。 + +* 工资为 $w$ 的就业工人的税后收入为 $w - \tau$。 +* 失业工人的税后收入为 $c - \tau$。 + +对于政府政策的每一种设定 $(c, \tau)$,我们都可以求解工人的最优保留工资。 + +这通过在税后工资上求值的 {eq}`endogenous_lake_lambda` 确定 $\lambda$,进而又确定一个稳态失业率 $u(c, \tau)$。 + +对于给定水平的失业补助 $c$,我们可以求解一个在稳态下平衡预算的税收 + +$$ + \tau = u(c, \tau) c +$$ + +要评估各种备选的政府税收-失业补偿组合,我们需要一个福利标准。 + +我们使用稳态福利标准 + +$$ + W := e \, {\mathbb E} [V \, | \, \text{employed}] + u \, U +$$ + +其中记号 $V$ 和 $U$ 如上文所定义,期望是在稳态下取的。 + + + + +### 计算最优失业保险 + +现在我们建立计算最优失业保险水平的基础设施。 + +首先,我们为经济体的参数定义一个容器: + +```{code-cell} ipython3 +class Economy(NamedTuple): + """经济体的参数""" + α: float + b: float + d: float + β: float + γ: float + σ: float + log_wage_mean: float + wage_grid_size: int + max_wage: float + +def create_economy( + α=0.013, + b=0.0124, + d=0.00822, + β=0.98, + γ=1.0, + σ=2.0, + log_wage_mean=20, + wage_grid_size=200, + max_wage=170 + ) -> Economy: + """ + 使用一组默认值创建一个经济体""" + return Economy(α=α, b=b, d=d, β=β, γ=γ, σ=σ, + log_wage_mean=log_wage_mean, + wage_grid_size=wage_grid_size, + max_wage=max_wage) +``` + +接下来,我们定义一个函数,在给定政策参数下计算工人的最优行为: + +```{code-cell} ipython3 +@jax.jit +def compute_optimal_quantities( + c: float, + τ: float, + economy: Economy, + w_vec: jnp.array, + p_vec: jnp.array + ): + """ + 在给定 c 和 τ 的情况下,计算工人的保留工资、 + 工作发现率和值函数。 + + """ + mcm = create_mccall_model( + α=economy.α, + β=economy.β, + γ=economy.γ, + c=c-τ, # 税后补偿 + σ=economy.σ, + w_vec=w_vec-τ, # 税后工资 + p_vec=p_vec + ) + + # 在给定参数下计算保留工资 + V, U = solve_mccall_model(mcm) + w_idx = jnp.searchsorted(V - U, 0) + w_bar = jnp.where(w_idx == len(V), jnp.inf, mcm.w_vec[w_idx]) + + # 计算工作发现率 + λ = economy.γ * jnp.sum(p_vec * (w_vec - τ > w_bar)) + + return w_bar, λ, V, U +``` + + +此函数在给定失业保险和税收水平的情况下计算稳态结果: + +```{code-cell} ipython3 +@jax.jit +def compute_steady_state_quantities( + c, τ, economy: Economy, w_vec, p_vec + ): + """ + 在给定 c 和 τ 的情况下,使用来自 McCall 模型的最优量并 + 计算相应的稳态量,从而计算稳态失业率 + + """ + + # 通过求解 McCall 模型找到最优值和策略, + # 以及相应的工作发现率。 + w_bar, λ, V, U = compute_optimal_quantities(c, τ, economy, w_vec, p_vec) + + # 使用给定参数和工作发现率建立一个湖泊模型。 + model = create_lake_model(λ=λ, α=economy.α, b=economy.b, d=economy.d) + + # 从该湖泊模型计算稳态就业率和失业率。 + u, e = rate_steady_state(model) + + # 计算以就业为条件的预期终身价值。 + mask = (w_vec - τ > w_bar) + w = jnp.sum(V * p_vec * mask) / jnp.sum(p_vec * mask) + # 计算稳态福利。 + welfare = e * w + u * U + + return e, u, welfare +``` + +我们需要一个函数来找到平衡政府预算的税率: + +```{code-cell} ipython3 +def find_balanced_budget_tax(c, economy: Economy, w_vec, p_vec): + """ + 在给定失业补偿 c 的情况下,找到能够实现预算平衡的税率。 + + """ + + def steady_state_budget(t): + """ + 对于给定的税率 t,计算预算盈余。 + + """ + e, u, w = compute_steady_state_quantities(c, t, economy, w_vec, p_vec) + return t - u * c + + # 使用简单的二分法找到平衡预算的税率 + # (即将盈余设为零) + + t_low, t_high = 0.0, 0.9 * c + tol = 1e-6 + max_iter = 100 + for i in range(max_iter): + t_mid = (t_low + t_high) / 2 + budget = steady_state_budget(t_mid) + if abs(budget) < tol: + return t_mid + elif budget < 0: + t_low = t_mid + else: + t_high = t_mid + + return t_mid +``` + +现在我们计算就业、失业、税收和福利如何随失业补偿率变化: + +```{code-cell} ipython3 +# 创建经济体和工资分布 +economy = create_economy() +w_vec, p_vec = create_wage_distribution( + economy.max_wage, economy.wage_grid_size, economy.log_wage_mean +) + +# 我们希望研究的失业保险水平 +c_vec = jnp.linspace(5, 140, 40) + +tax_vec = [] +unempl_vec = [] +empl_vec = [] +welfare_vec = [] + +for c in c_vec: + t = find_balanced_budget_tax(c, economy, w_vec, p_vec) + e_rate, u_rate, welfare = compute_steady_state_quantities( + c, t, economy, w_vec, p_vec + ) + tax_vec.append(t) + unempl_vec.append(u_rate) + empl_vec.append(e_rate) + welfare_vec.append(welfare) +``` + +让我们可视化结果: + +```{code-cell} ipython3 +fig, axes = plt.subplots(2, 2, figsize=(12, 10)) + +plots = [unempl_vec, empl_vec, tax_vec, welfare_vec] +titles = ['失业', '就业', '税收', '福利'] + +for ax, plot, title in zip(axes.flatten(), plots, titles): + ax.plot(c_vec, plot, lw=2, alpha=0.7) + ax.set_title(title) + +plt.tight_layout() +plt.show() +``` + +随着失业补助的增加,福利先增加后减少。 + +使稳态福利最大化的水平大约为 62。 + +## 练习 + +```{exercise} +:label: endogenous_lake_ex1 + +使稳态福利最大化的失业补偿水平 $c$ 如何随工作分离率 $\alpha$ 变化? + +对于从 0.01 到 0.04 的一系列分离率 $\alpha$,计算并绘制最优 $c$(使福利最大化的值)。 + +对于每个 $\alpha$ 值,通过在 $c$ 值范围内计算福利并选择最大值来找到最优 $c$。 +``` + +```{solution-start} endogenous_lake_ex1 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +# 要探索的分离率范围(更宽的范围,更少的点) +α_values = jnp.linspace(0.01, 0.04, 8) + +# 我们将为每个 α 存储最优 c +optimal_c_values = [] + +# 使用更精细的 c 值网格以获得更好的分辨率 +c_vec_fine = jnp.linspace(5, 140, 150) + +for α_val in α_values: + # 使用该 α 创建经济体参数 + params_α = create_economy(α=α_val) + + # 创建工资分布 + w_vec_α, p_vec_α = create_wage_distribution( + params_α.max_wage, params_α.wage_grid_size, params_α.log_wage_mean + ) + + # 为每个 c 值计算福利 + welfare_values = [] + for c in c_vec_fine: + t = find_balanced_budget_tax(c, params_α, w_vec_α, p_vec_α) + e_rate, u_rate, welfare = compute_steady_state_quantities( + c, t, params_α, w_vec_α, p_vec_α + ) + welfare_values.append(welfare) + + # 福利函数在其最大值附近非常平坦。 + # 由于数值噪声,在单个点上使用 argmax 可能不稳定。 + # 相反,我们找到所有在最大福利 99.9% 范围内的 c 值,并 + # 计算它们的加权平均(质心)。这给出了最优失业补偿水平 + # 的更稳定估计。 + welfare_array = jnp.array(welfare_values) + max_welfare = jnp.max(welfare_array) + threshold = 0.999 * max_welfare + near_optimal_mask = welfare_array >= threshold + + # 计算近最优区域内 c 值的加权平均 + optimal_c = jnp.sum(c_vec_fine * near_optimal_mask * welfare_array) / \ + jnp.sum(near_optimal_mask * welfare_array) + optimal_c_values.append(optimal_c) + +# 绘制这种关系 +fig, ax = plt.subplots(figsize=(10, 6)) +ax.plot(α_values, optimal_c_values, lw=2, marker='o') +ax.set_xlabel(r'分离率 $\alpha$') +ax.set_ylabel('最优失业补偿 $c$') +ax.set_title('最优失业保险如何随工作分离率变化') +ax.grid(True, alpha=0.3) +plt.tight_layout() +plt.show() +``` + +我们看到,随着分离率增加(工人更频繁地失去工作),使福利最大化的失业补偿水平会下降。 + +这是因为更高的分离率增加了稳态失业率,从而提高了为失业补助提供资金所需的税收负担。最优政策在保险与扭曲性税收之间取得平衡。 + + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/hansen_singleton_1982.md b/lectures/hansen_singleton_1982.md new file mode 100644 index 0000000..fdbed03 --- /dev/null +++ b/lectures/hansen_singleton_1982.md @@ -0,0 +1,1141 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 +kernelspec: + name: python3 + display_name: Python 3 (ipykernel) + language: python +translation: + title: 用广义矩方法估计欧拉方程 + headings: + Overview: 概述 + The economic model: 经济模型 + From conditional to unconditional moments: 从条件矩到无条件矩 + GMM criterion and asymptotic theory: GMM 准则与渐近理论 + Covariance estimation and the choice of instruments: 协方差估计与工具的选择 + Covariance estimation and the choice of instruments::Simulation: 模拟 + Empirical GMM estimation: 经验 GMM 估计 + Summary: 小结 +--- + +(hansen_singleton_1982)= +```{raw} jupyter + +``` + +# 用广义矩方法估计欧拉方程 + +```{index} single: Asset Pricing; GMM Estimation +``` + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲实现了 {cite:t}`hansen1982generalized` 针对非线性理性预期模型提出的广义工具变量估计量。 + +前一讲 {doc}`hansen_singleton_1983` 从具有 CRRA 偏好的代表性消费者问题中推导出消费欧拉方程,并在正态性假设下用最大似然法对其进行估计。 + +该方法需要指定消费和回报的联合分布,其有效性取决于对数正态性是否成立。 + +然而,正如我们在 {doc}`hansen_singleton_1983` 中所看到的,对数正态模型被数据所拒绝。 + +此外,在线性-二次型环境之外,均衡的闭式解通常需要对强制变量的随机性质、偏好的性质或生产技术做出很强的假设。 + +{cite:t}`hansen1982generalized` 提出了一种规避这一要求的估计策略。 + +其核心思想是,经济主体最优化问题产生的欧拉方程隐含了一组总体正交条件,这些条件依赖于可观测变量和未知的偏好参数。 + +通过使这些正交条件的样本对应量接近于零,就可以在不显式求解随机均衡、不指定可观测变量分布的情况下估计参数。 + +不过,当分布假设被正确指定时,最大似然估计量(例如 {doc}`hansen_singleton_1983` 中的 MLE)在渐近意义上会更有效率。 + +相对于原论文,我们每次只估计一种回报(市值加权股票回报),仅使用月度非耐用品消费(`ND`),并省略了他们的最大似然比较(表 II)和多回报系统(表 III)。 + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +from IPython.display import Latex +from numba import njit +from scipy import stats +from scipy.optimize import minimize +from statsmodels.sandbox.regression import gmm +from statsmodels.tsa.stattools import acf +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +我们还在下面的隐藏单元格中定义了一个辅助函数,用于将 DataFrame 显示为 LaTeX 数组 + +```{code-cell} ipython3 +:tags: [hide-cell] + +def display_table(df, title=None, fmt=None): + """ + 将 DataFrame 显示为 LaTeX 数组。 + """ + if fmt is None: + fmt = {} + formatted = df.copy() + for col in formatted.columns: + if col in fmt: + formatted[col] = formatted[col].apply( + lambda x: fmt[col].format(x) if np.isfinite(x) else str(x)) + n_cols = len(formatted.columns) + idx_header = r"\text{" + df.index.name + "}" if df.index.name else "" + columns = " & ".join( + [idx_header] + [r"\text{" + c + "}" if "\\" not in c + and "^" not in c and "_" not in c + else c for c in formatted.columns]) + rows = r" \\".join( + [" & ".join([str(idx)] + [str(v) for v in row]) + for idx, row in zip(formatted.index, formatted.values)]) + col_format = "r" + "c" * n_cols + lines = [r"\begin{array}{" + col_format + "}"] + lines.append(columns + r" \\") + lines.append(r"\hline") + lines.append(rows) + lines.append(r"\end{array}") + latex = "\n".join(lines) + if title: + latex = rf"\textbf{{{title}}}" + r"\\" + "\n" + latex + display(Latex("$" + latex + "$")) +``` + + +## 经济模型 + +我们考虑一个单一商品经济,其中有一个代表性消费者,其偏好是 CRRA 类型的,遵循 {cite:t}`hansen1982generalized` 和 {cite:t}`hansen1983stochastic`。 + +```{note} +下面的讨论与 {doc}`hansen_singleton_1983` 中的设定非常接近,但更加一般化,因为它允许具有不同期限的多种资产,且不假设对数正态性。 +``` + +代表性消费者选择随机消费和投资计划,以最大化 + +```{math} +:label: hs82-problem + +\max E_0 \sum_{t=0}^{\infty} \beta^t u(C_t) +``` + +其中 $C_t$ 是第 $t$ 期的消费,$\beta \in (0,1)$ 是主观贴现因子,$u(\cdot)$ 是严格凹的单期效用函数。 + +消费者交易 $N$ 种可能具有不同期限的资产。 + +设 $Q_{jt}$ 表示在日期 $t$ 末持有的资产 $j$ 的数量,$P_{jt}$ 表示其在日期 $t$ 的价格,$R_{jt}$ 表示在日期 $t - M_j$ 购买的一单位 $M_j$ 期资产在日期 $t$ 的收益。 + +可行的消费和投资计划必须满足一系列预算约束 + +```{math} +:label: hs82-budget + +C_t + \sum_{j=1}^{N} P_{jt} Q_{jt} \leq \sum_{j=1}^{N} R_{jt} Q_{jt-M_j} + W_t, +``` + +其中 $W_t$ 是日期 $t$ 的实际劳动收入。 + +我们专门考虑 CRRA 偏好 + +```{math} +:label: hs82-crra + +u(C_t) = \frac{C_t^{1-\gamma}}{1-\gamma}, \quad \gamma > 0, +``` + +其中 $\gamma$ 是相对风险厌恶系数。 + +对 {eq}`hs82-problem` 在 {eq}`hs82-budget` 约束下最大化,给出一阶必要条件(见 {cite:t}`Lucas1978`、{cite:t}`Brock1982`、{cite:t}`PrescottMehra1980` 和 {doc}`hansen_singleton_1983`): + +```{math} +:label: hs82-general-euler + +P_{jt} u'(C_t) = \beta^{M_j} E_t\!\left[R_{jt+M_j} u'(C_{t+M_j})\right], \quad j = 1, \ldots, N. +``` + +当资产 $j$ 是一个单期股票($M_j = 1$),其收益 $R_{jt+1} = P_{jt+1} + D_{jt+1}$,其中 $D_{jt}$ 是股息,则**总实际回报**为 $R_{t+1}^i = (P_{i,t+1}+D_{i,t+1})/P_{i,t}$。 + +将 CRRA 边际效用代入 {eq}`hs82-general-euler`,并将等式两边除以 $P_{jt} u'(C_t)$,得到欧拉方程 + +```{math} +:label: hs82-euler + +E_t\!\left[\beta \left(\frac{C_{t+1}}{C_t}\right)^{-\gamma} R_{t+1}^i\right] = 1, +``` + +其中 $R_{t+1}^i$ 是资产 $i$ 的总实际回报。 + +我们定义**随机贴现因子** $M_{t+1}(\theta) = \beta (C_{t+1}/C_t)^{-\gamma}$,其参数向量为 $\theta = (\gamma, \beta)$。 + +在这种记法下,欧拉方程变为 $E_t[M_{t+1}(\theta) R_{t+1}^i - 1] = 0$。 + +正如我们已经看到并将继续看到的,方程 {eq}`hs82-euler` 是 {doc}`hansen_singleton_1983` 和本讲的核心对象。 + +对于每一种主体的最优性条件都适用的交易资产(内点解,无约束性投资组合限制或交易成本),它都成立。 + +它依赖于可观测量(消费增长和回报)以及未知的偏好参数($\gamma$ 和 $\beta$)。 + +{cite:t}`hansen1982generalized` 所要解决的挑战是,如何在不指定经济环境其余部分的情况下,从 {eq}`hs82-euler` 中估计 $\theta$。 + +## 从条件矩到无条件矩 + +从 {eq}`hs82-euler` 估计 $\theta$ 的一种自然方法是指定整个经济环境,求解均衡,然后应用最大似然法。 + +正如我们在 {doc}`hansen_singleton_1983` 中一起做的那样, + +{cite:t}`hansen1982generalized` 认为,对于大多数非线性模型而言,这是不切实际的,因为它需要对"强制变量"的随机性质和生产技术做出很强的假设。 + +他们的替代方案是直接处理欧拉方程对可观测矩的含义。 + +欧拉方程 {eq}`hs82-euler` 表明 $E_t[M_{t+1}(\theta_0) R_{t+1}^i - 1] = 0$。 + +设 $z_t$ 表示任何 $q$ 维向量,其中的变量位于主体的 $t$ 时刻信息集内,并且被计量经济学家观测到。 + +由于 $z_t$ 在日期 $t$ 已知, + +$$ +E\!\left[\left(M_{t+1}(\theta_0)R_{t+1}^i - 1\right) \otimes z_t\right] += E\!\left[z_t \otimes \underbrace{E_t\!\left[M_{t+1}(\theta_0)R_{t+1}^i - 1\right]}_{=\,0\text{ 根据欧拉方程}}\right] = 0. +$$ + +这产生了矩约束 + +```{math} +:label: hs82-uncond + +E\!\left[\left(M_{t+1}(\theta_0)R_{t+1}^i - 1\right) \otimes z_t\right] = 0, +``` + +其中 $\otimes$ 表示克罗内克积。 + +向量 $z_t$ 扮演**工具**的角色。 + +条件欧拉方程 $E_t[M_{t+1}R_{t+1}^i - 1] = 0$ 表明,给定主体 $t$ 时刻信息集中的*所有内容*,定价误差是不可预测的。 + +这是一个非常强的约束——它表明定价误差与每个 $t$ 时刻可测的随机变量正交。 + +在实践中我们无法使用整个信息集,但我们可以选取任何有限的 $t$ 时刻可观测变量集合 $z_t$,并且正交性仍然必须成立。 + +我们纳入 $z_t$ 中的每个变量都给我们一个样本矩条件 $\frac{1}{T}\sum_t (M_{t+1}R_{t+1}^i - 1)\, z_{kt} \approx 0$,我们可以从数据中计算它。 + +更多的工具意味着更多需要匹配的正交条件,这可以提高效率,并提供更多的过度识别约束来检验模型。 + +有 $q$ 个工具和 $m$ 个欧拉方程时,我们得到 $mq$ 个矩约束用于估计参数向量 $\theta$。 + +对于一个回报和 $p$ 个工具滞后,{cite:t}`hansen1982generalized` 使用 + +```{math} +:label: hs82-instruments + +z_t = \left[1, R_t, g_t, R_{t-1}, g_{t-1}, \ldots, R_{t-p+1}, g_{t-p+1}\right]^\top, +``` + +其中 $g_t = C_t / C_{t-1}$ 是总消费增长。 + +```{note} +{cite:t}`hansen1982generalized` 将 $z_t$ 描述为"$x_{t+1}$ 的滞后值",其中 $x_{t+1} = (R_{t+1}, g_{t+1})$。 + +常数 1 没有明确说明,但由他们表 I 中报告的自由度所隐含。 +``` + +更一般地,{cite:t}`hansen1982generalized` 将一阶条件写为 $E_t[h(x_{t+n}, b_0)] = 0$,其中 $x_{t+n}$ 是日期为 $t+n$ 的可观测量向量,$b_0$ 是真实参数向量。 + +在单期股票的情况下,扰动 $u_{t+1} = h(x_{t+1}, b_0)$ 是序列不相关的。 + +通过克罗内克积堆叠矩条件给出 $f(x_{t+n}, z_t, b) = h(x_{t+n}, b) \otimes z_t$,一个维度为 $mq$ 的向量。 + +由此产生的无条件约束 $E[f(x_{t+n}, z_t, b_0)] = 0$ 同时嵌套了单回报单期欧拉方程和多期限资产定价约束。 + +正交条件和滞后工具向量遵循方程 {eq}`hs82-uncond` 和 {eq}`hs82-instruments` + +```{code-cell} ipython3 +def euler_error_horizon(params, exog, horizon=1): + """ + 在给定视界下,为 (γ, β) 计算欧拉方程定价误差。 + """ + if horizon < 1: + raise ValueError("horizon must be at least one.") + γ, β = params + gross_return = exog[:, 0] + gross_cons_growth = exog[:, 1] + return (β ** horizon) * gross_cons_growth ** (-γ) * gross_return - 1.0 + + +def euler_error_grad_horizon(params, exog, horizon=1): + """ + 在给定视界下,欧拉误差关于 (γ, β) 的梯度。 + """ + if horizon < 1: + raise ValueError("horizon must be at least one.") + γ, β = params + gross_return = exog[:, 0] + gross_cons_growth = exog[:, 1] + + g_pow = gross_cons_growth ** (-γ) + common = (β ** horizon) * g_pow * gross_return + + dγ = -common * np.log(gross_cons_growth) + dβ = horizon * (β ** (horizon - 1)) * g_pow * gross_return + return np.column_stack([dγ, dβ]) + + +def euler_error(params, exog): + """ + 为 (γ, β) 计算单期欧拉方程定价误差。 + """ + return euler_error_horizon(params, exog, horizon=1) +``` + +一个辅助函数为非线性 IV-GMM 对齐结果和滞后工具 + +```{code-cell} ipython3 +def build_gmm_arrays(data, n_lags): + """ + 为非线性 IV-GMM 构建 endog、exog 和工具。 + """ + if n_lags < 1: + raise ValueError("n_lags must be at least one.") + if data.shape[0] <= n_lags: + raise ValueError("Sample size must exceed n_lags.") + + t_obs = data.shape[0] + exog = data[n_lags:, :] + endog = np.zeros(exog.shape[0]) + n_obs = t_obs - n_lags + n_instr = 2 * n_lags + 1 + + instruments = np.empty((n_obs, n_instr)) + instruments[:, 0] = 1.0 + + for j in range(n_lags): + left = 2 * j + 1 + right = left + 2 + instruments[:, left:right] = data[n_lags - 1 - j : t_obs - 1 - j, :] + + return endog, exog, instruments +``` + +当资产的期限 $n > 1$ 时,欧拉方程涉及 $n$ 期复合回报和消费增长。 + +对于 CRRA 偏好,$n$ 期欧拉约束为 + +```{math} +:label: hs82-euler-n + +E_t\!\left[\beta^n \left(\frac{C_{t+n}}{C_t}\right)^{-\gamma} R_{t,t+n}^i\right] = 1. +``` + +对于估计,$n$ 期 exog 既可以使用直接观测到的 $n$ 期回报/收益,也可以通过在 $n$ 个连续周期内复合单期回报和消费增长来构建。 + +同样,{cite:t}`hansen1982generalized` 的一个关键要求是,工具 $z_t$ 必须位于主体的 $t$ 时刻信息集 $\mathcal{I}_t$ 内。 + +对于多期情形,工具必须相对于 $\mathcal{I}_t$ 可测。 + +特别地,应避免使用任何仍包含 $t$ 之后周期的滞后多期总量,因为这些量会嵌入不属于 $\mathcal{I}_t$ 的实现值。 + +$n$ 期 exog 通过复合单期数据构建,工具的时间安排使其位于 $\mathcal{I}_t$ 内。 + +```{code-cell} ipython3 +def build_gmm_arrays_horizon(one_period_data, n_lags, horizon): + """ + 为多期 GMM 构建 endog、exog 和工具。 + + Exog 包含 n 期复合回报和消费增长。 + """ + if horizon < 1: + raise ValueError("horizon must be at least one.") + if n_lags < 1: + raise ValueError("n_lags must be at least one.") + T = one_period_data.shape[0] + if T <= n_lags + horizon: + raise ValueError("Sample size too small for given n_lags and horizon.") + + # 每个观测从索引 t 开始(窗口中的第一个周期) + # 窗口跨越 one_period_data[t : t + horizon] + # 工具使用 one_period_data[t - 1], ..., one_period_data[t - n_lags] + starts = np.arange(n_lags, T - horizon + 1) + n_obs = len(starts) + + exog = np.empty((n_obs, 2)) + n_instr = 2 * n_lags + 1 + instruments = np.empty((n_obs, n_instr)) + instruments[:, 0] = 1.0 + + for i, t in enumerate(starts): + window = one_period_data[t : t + horizon, :] + exog[i, 0] = np.prod(window[:, 0]) # n 期回报 + exog[i, 1] = np.prod(window[:, 1]) # n 期消费增长 + for j in range(n_lags): + instruments[ + i, 2 * j + 1 : 2 * j + 3] = one_period_data[t - 1 - j, :] + + endog = np.zeros(n_obs) + return endog, exog, instruments +``` + +当 $n > 1$ 时,欧拉方程涉及日期为 $t + n$ 的变量,且扰动 $u_{t+n} = h(x_{t+n}, b_0)$ 通常将是序列相关的。 + +正如 {cite:t}`hansen1982generalized` 所指出的,如果 $m$ 种资产都是单期股票,则 $u$ 是序列不相关的,因为对 $x_{t-s}$($s \geq 0$)的观测位于主体的 $t$ 时刻信息集内,且 $E_t[h(x_{t+1}, b_0)] = 0$。 + +但如果对某些资产 $j$ 有 $n_j > 1$,则条件 $E_t[h(x_{t+n}, b_0)] = 0$ 并不排除 $u$ 中的序列相关,因为当 $n > 1$ 时 $x_{t+n-1}$ 不一定在 $I_t$ 中。 + +长期协方差 $S_0$ 中的总体自协方差数量由 $n$ 确定,即移动平均扰动项 $u_t$ 的阶数。 + +我们直接将其实现为一个有限阶协方差估计器 + +```{code-cell} ipython3 +def finite_ma_covariance(moment_series, ma_order): + """ + 为矩向量估计 + S = Gamma_0 + sum_{j=1}^{ma_order}(Gamma_j + Gamma_j.T)。 + """ + if ma_order < 0: + raise ValueError("ma_order must be nonnegative.") + if moment_series.ndim != 2: + raise ValueError("moment_series must be 2D.") + + t_obs, n_mom = moment_series.shape + if t_obs <= ma_order: + raise ValueError("Need more observations than ma_order.") + + # 使用*未中心化*的交叉乘积 + # T^{-1} sum_t f_t f_{t-j}',然后加上对称滞后项。 + s_hat = moment_series.T @ moment_series / t_obs + + for j in range(1, ma_order + 1): + gamma_j = moment_series[j:, :].T @ moment_series[:-j, :] / t_obs + s_hat += gamma_j + gamma_j.T + + ridge = 1e-8 * np.eye(n_mom) + return s_hat + ridge +``` + +{cite:t}`hansen1982generalized` 中的估计程序是一个两步广义工具变量程序。 + +在第一步中,我们用一个次优权重矩阵(单位矩阵)最小化 GMM 准则,以获得一个一致的初步估计 $b_T$。 + +在第二步中,我们使用 $b_T$ 来估计样本矩条件的协方差矩阵,并对其求逆以形成最优权重矩阵,然后重新最小化准则。 + +让我们实现这个算法 + +```{code-cell} ipython3 +def two_step_gmm(data, n_lags, ma_order=0, horizon=1, start_params=None): + """ + 使用有限阶协方差的两步 GMM。 + + 欧拉误差使用 β**horizon。 + """ + if start_params is None: + start_params = np.array([1.0, 0.99]) + else: + start_params = np.asarray(start_params, dtype=float) + + if horizon == 1: + _, exog, instruments = build_gmm_arrays(data, n_lags) + else: + _, exog, instruments = build_gmm_arrays_horizon(data, n_lags, horizon) + n_obs = exog.shape[0] + + def sample_moments(params): + err = euler_error_horizon(params, exog, horizon=horizon) + return err[:, None] * instruments + + def objective(params, weight_matrix): + g_bar = sample_moments(params).mean(axis=0) + return float(g_bar @ weight_matrix @ g_bar) + + def objective_grad(params, weight_matrix): + g_bar = sample_moments(params).mean(axis=0) + grad_err = euler_error_grad_horizon(params, exog, horizon=horizon) + d_bar = (instruments.T @ grad_err) / n_obs + return 2.0 * d_bar.T @ weight_matrix @ g_bar + + q = instruments.shape[1] + w_identity = np.eye(q) + + bounds = [(-2.0, 10.0), (0.85, 1.5)] + + def coarse_starts(weight_matrix, n_best=5): + γ_grid = np.linspace(bounds[0][0], bounds[0][1], 33) + β_grid = np.linspace(bounds[1][0], bounds[1][1], 33) + scored = [] + for γ0 in γ_grid: + for β0 in β_grid: + params0 = np.array([γ0, β0]) + val = objective(params0, weight_matrix) + if np.isfinite(val): + scored.append((val, params0)) + scored.sort(key=lambda item: item[0]) + return [params for _, params in scored[:n_best]] or [start_params] + + def best_local_minimize(weight_matrix, starts): + best = None + for x0 in starts: + res = minimize( + objective, + x0=x0, + args=(weight_matrix,), + jac=objective_grad, + method="L-BFGS-B", + bounds=bounds, + options={"maxiter": 25_000}, + ) + if not np.isfinite(res.fun): + continue + if best is None or (res.fun < best.fun): + best = res + return best if best is not None else minimize( + objective, + x0=start_params, + args=(weight_matrix,), + jac=objective_grad, + method="L-BFGS-B", + bounds=bounds, + options={"maxiter": 25_000}, + ) + + step1_starts = [start_params] + coarse_starts(w_identity, n_best=5) + step1 = best_local_minimize(w_identity, step1_starts) + params1 = step1.x + + m1 = sample_moments(params1) + s_hat = finite_ma_covariance(m1, ma_order=ma_order) + w_opt = np.linalg.pinv(s_hat) + + step2_starts = [params1] + coarse_starts(w_opt, n_best=5) + step2 = best_local_minimize(w_opt, step2_starts) + params2 = step2.x + + m2 = sample_moments(params2) + s_hat2 = finite_ma_covariance(m2, ma_order=ma_order) + w_opt2 = np.linalg.pinv(s_hat2) + g2 = m2.mean(axis=0) + j_stat = float(n_obs * (g2 @ w_opt2 @ g2)) + df = instruments.shape[1] - len(params2) + j_prob = float(stats.chi2.cdf(j_stat, df=df)) if df > 0 else np.nan + p_value = float(1.0 - j_prob) if df > 0 else np.nan + + # 最优权重下的渐近协方差: (D' S^{-1} D)^{-1} / T。 + grad_err = euler_error_grad_horizon(params2, exog, horizon=horizon) + d_hat = (instruments.T @ grad_err) / n_obs + cov_hat = np.linalg.pinv(d_hat.T @ w_opt2 @ d_hat) / n_obs + se_hat = np.sqrt(np.diag(cov_hat)) + + return { + "params_step1": params1, + "params_step2": params2, + "se_step2": se_hat, + "weight_opt": w_opt2, + "j_stat": j_stat, + "j_df": int(df), + "j_prob": j_prob, + "j_pval": p_value, + "n_obs": int(n_obs), + "success": bool(step2.success), + } +``` + +## GMM 准则与渐近理论 + +我们现在将估计程序形式化。 + +设 $m_t(\theta) = (M_{t+1}(\theta) R_{t+1}^i - 1) \otimes z_t$ 表示日期 $t$ 处的矩条件向量,并定义样本均值 + +```{math} +:label: hs82-sample-moments + +g_T(\theta) = \frac{1}{T} \sum_{t=1}^T m_t(\theta). +``` + +如果模型被正确指定,对于较大的 $T$,$g_T(\theta_0)$ 应接近于零。 + +我们通过选择使 $g_T$ 尽可能接近零的参数向量来估计 $\theta$,其接近程度由一个二次型度量: + +```{math} +:label: hs82-criterion + +\hat\theta = \arg\min_\theta g_T(\theta)^\top W_T g_T(\theta) +``` + +其中 $W_T$ 是一个对称正定权重矩阵。 + +在 {cite:t}`Hansen1982` 给出的正则条件下,GMM 估计量是一致的、渐近正态的,并具有三明治协方差矩阵 + +```{math} +:label: hs82-asymptotic + +\sqrt{T}(\hat\theta-\theta_0) \Rightarrow N\!\left(0, (D^\top W D)^{-1} D^\top W S W D (D^\top W D)^{-1}\right), +``` + +其中 $D = E[\partial m_t(\theta_0)/\partial\theta^\top]$ 是矩条件的雅可比矩阵,$S$ 是 $m_t(\theta_0)$ 的长期协方差矩阵,$W$ 是 $W_T$ 的概率极限。 + +{cite:t}`Hansen1982` 表明,最优权重矩阵是 $W^* = S^{-1}$,它在所有 $W$ 的选择中产生最小的渐近协方差矩阵。 + +在 $W = S^{-1}$ 下,三明治简化为 $(D^\top S^{-1} D)^{-1}$。 + +当矩条件的数量 $r$(例如,对于 $m$ 个欧拉方程和 $q$ 个工具,$r = mq$)超过参数数量 $k$ 时,模型是过度识别的,我们可以检验数据是否与所维持的约束一致。 + +{cite:t}`hansen1982generalized` 使用 {cite:t}`Hansen1982` 的一个结果来检验过度识别约束: + +```{math} +:label: hs82-jtest + +J_T = T\, g_T(\hat\theta)^\top \hat S^{-1} g_T(\hat\theta) \Rightarrow \chi^2_{r-k}, +``` + +其中 $\hat S$ 是 $S$ 的一致估计量。 + +相对于 $\chi^2_{r-k}$ 临界值较大的 $J_T$ 导致拒绝模型的过度识别约束。 + +对于多期情形($n > 1$),如上所述,扰动至多为 MA($n-1$),因此 {cite:t}`hansen1982generalized` 通过设置 $W_0 = S_0^{-1}$ 获得最优权重矩阵,其中 + +```{math} +:label: hs82-finite-so + +S_0 = \sum_{j=-n+1}^{n-1} E\!\left[f(x_{t+n}, z_t, b_0)\, f(x_{t+n-j}, z_{t-j}, b_0)^\top\right]. +``` + +## 协方差估计与工具的选择 + +对于单期欧拉方程($n = 1$),扰动 $u_{t+1} = M_{t+1}(\theta_0) R_{t+1} - 1$ 是一个鞅差分序列。 + +在这种情况下,矩向量 $m_t(\theta_0) = u_{t+1} \otimes z_t$ 是序列不相关的,长期协方差 $S$ 等于同期方差 $E[m_t m_t^\top]$。 + +因此,协方差估计器不需要核或带宽的选择。 + +我们只需使用样本类比 $\hat S = T^{-1} \sum_t m_t m_t^\top$。 + +在下面的实现中,我们使用 HAC(异方差和自相关一致)估计器,以应对时间聚合或测量时序可能产生的轻微序列依赖。 + +这是一个现代的预防措施,不属于原始 {cite:t}`hansen1982generalized` 程序的一部分,后者直接利用已知的 MA 阶数,如 {eq}`hs82-finite-so` 所示。 + +工具滞后数 $p$ 决定了我们使用多少正交条件,从而决定了 $J$ 检验的功效。 + +{cite:t}`hansen1982generalized` 报告了 NLAG $= 1, 2, 4, 6$ 的结果,并指出(脚注 12)使用更多的正交条件可能导致估计量具有不太理想的小样本性质。 + +下面我们实现估计程序,允许用户选择滞后数以及是否对协方差矩阵使用 HAC 估计器 + +```{code-cell} ipython3 +def estimate_gmm( + data, + n_lags, + start_params=None, + use_hac=True, + hac_maxlag=None, + maxiter=2, +): + """ + 使用非线性 IV-GMM 估计欧拉方程参数。 + """ + if start_params is None: + start_params = np.array([1.0, 0.99]) + + endog, exog, instruments = build_gmm_arrays(data, n_lags) + model = gmm.NonlinearIVGMM(endog, exog, instruments, euler_error) + + if use_hac: + if hac_maxlag is None: + hac_maxlag = max( + 1, int( + np.floor(4.0 * (endog.shape[0] / 100.0) ** (2.0 / 9.0)))) + result = model.fit( + start_params=start_params, + maxiter=maxiter, + optim_method="bfgs", + optim_args={"disp": False}, + weights_method="hac", + wargs={"maxlag": hac_maxlag}, + ) + else: + result = model.fit( + start_params=start_params, + maxiter=maxiter, + optim_method="bfgs", + optim_args={"disp": False}, + ) + + return result +``` + +接下来,我们包含一个辅助函数,用于跨滞后长度运行 GMM 估计并在表中汇总结果 + +```{code-cell} ipython3 +def run_gmm_by_lag( + data, + lags=(1, 2, 4, 6), + use_hac=True, + hac_maxlag=None, +): + """ + 按滞后长度估计 GMM 模型并返回汇总表。 + """ + rows = [] + results = {} + + for lag in lags: + res = estimate_gmm(data, n_lags=lag, use_hac=use_hac, hac_maxlag=hac_maxlag) + results[lag] = res + j_stat, j_pval, j_df = res.jtest() + j_prob = float(stats.chi2.cdf(j_stat, df=j_df)) if j_df > 0 else np.nan + rows.append( + { + "NLAG": lag, + "γ_hat": res.params[0], + "se_γ": res.bse[0], + "β_hat": res.params[1], + "se_β": res.bse[1], + "j_stat": j_stat, + "j_prob": j_prob, + "j_pval": j_pval, + "j_df": int(j_df), + "n_obs": int(res.nobs), + } + ) + + table = pd.DataFrame(rows).set_index("NLAG") + return table, results + + +def run_two_step_by_lag( + data, + lags=(1, 2, 4, 6), + horizon=1, +): + """ + 跨滞后长度、使用精确 S0(MA 阶数 0)的两步 GMM。 + """ + rows = [] + start_params = None + for lag in lags: + res = two_step_gmm( + data, + n_lags=lag, + ma_order=0, + horizon=horizon, + start_params=start_params, + ) + start_params = res["params_step2"] + rows.append( + { + "NLAG": lag, + "γ_hat": res["params_step2"][0], + "se_γ": res["se_step2"][0], + "β_hat": res["params_step2"][1], + "se_β": res["se_step2"][1], + "j_stat": res["j_stat"], + "j_prob": res["j_prob"], + "j_pval": res["j_pval"], + "j_df": res["j_df"], + "n_obs": res["n_obs"], + } + ) + return pd.DataFrame(rows).set_index("NLAG") +``` + + +### 模拟 + +在将估计量应用于真实数据之前,我们验证 GMM 能从模拟数据中恢复已知参数。 + +我们构建一个模拟器,生成按构造满足欧拉方程的合成回报-增长对。 + +我们从平稳的 AR(1) 生成对数消费增长,在已知的真实参数下计算随机贴现因子,并将总回报构造为 +$R_{t+1} = \xi_{t+1} / M_{t+1}(\theta_0)$,其中 $\xi_{t+1}$ 是均值为一的独立同分布对数正态冲击。 + +```{code-cell} ipython3 +@njit +def _ar1_simulate(mu_c, phi_c, sigma_c, shocks_c, total_n): + """ + 模拟 AR(1) 对数消费增长。 + """ + delta_c = np.empty(total_n) + delta_c[0] = mu_c + for t in range(1, total_n): + delta_c[t] = mu_c * (1.0 - phi_c) + phi_c * delta_c[t - 1] + sigma_c * shocks_c[t] + return delta_c + + +def simulate_euler_sample( + n_obs, + γ_true=0.8, + β_true=0.993, + seed=0, +): + """ + 模拟 [总实际回报, 总消费增长]。 + """ + rng = np.random.default_rng(seed) + mu_c = 0.0015 + sigma_c = 0.006 + phi_c = 0.4 + sigma_eta = 0.02 + burn_in = 200 + + total_n = n_obs + burn_in + shocks_c = rng.standard_normal(total_n) + delta_c = _ar1_simulate(mu_c, phi_c, sigma_c, shocks_c, total_n) + + cons_growth = np.exp(delta_c[burn_in:]) + sdf = β_true * cons_growth ** (-γ_true) + + # 正的均值为一的回报冲击: E[ξ]=1,因此按构造 E[M R]=1。 + eps = rng.standard_normal(n_obs) + xi = np.exp(sigma_eta * eps - 0.5 * sigma_eta**2) + gross_return = xi / sdf + + return np.column_stack([gross_return, cons_growth]) +``` + +我们设定 $\gamma = 2$ 和 $\beta = 0.995$ 作为真实参数,并从欧拉一致的数据生成过程生成 700 个月度观测值。 + +```{code-cell} ipython3 +γ_true = 2.0 +β_true = 0.995 +sim_data = simulate_euler_sample( + n_obs=5000, + γ_true=γ_true, + β_true=β_true, + seed=0, +) + +print(f"Simulation sample size: {sim_data.shape[0]}") +print(f"True γ: {γ_true:.3f}") +print(f"True β: {β_true:.3f}") +``` + +我们现在跨滞后长度估计 GMM,遵循 {cite:t}`hansen1982generalized` 中表 I 的格式。 + +```{code-cell} ipython3 +sim_table = run_two_step_by_lag(sim_data, lags=(1, 2, 4, 6), horizon=1) +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +sim_pretty = sim_table[ + ["γ_hat", "se_γ", "β_hat", "se_β", "j_stat", "j_df", "j_prob"]].rename( + columns={ + "γ_hat": r"\hat{\gamma}", + "se_γ": r"\mathrm{se}(\hat{\gamma})", + "β_hat": r"\hat{\beta}", + "se_β": r"\mathrm{se}(\hat{\beta})", + "j_stat": "J", + "j_df": "df", + "j_prob": "Prob(J)", + } +) +display_table( + sim_pretty, + fmt={ + r"\hat{\gamma}": "{:.4f}", + r"\mathrm{se}(\hat{\gamma})": "{:.4f}", + r"\hat{\beta}": "{:.4f}", + r"\mathrm{se}(\hat{\beta})": "{:.4f}", + "J": "{:.3f}", + "Prob(J)": "{:.3f}", + "df": "{:.0f}", + }, +) +``` + +GMM 在各种滞后设定下相当接近地恢复了真实的 $\gamma$ 和 $\beta$。 + +对于假设检验,右尾 $p$ 值为 $1-\mathrm{Prob}(J)$。 + +两篇论文的表格中都可见的较大标准误表明,偏好参数 $\gamma$ 和 $\beta$ 可能是弱识别的。 + +为了将这一点可视化,我们使用模拟数据在 $(\gamma, \beta)$ 网格上绘制 GMM 准则 + + +```{code-cell} ipython3 +def gmm_objective_surface( + data, + n_lags=2, + γ_grid=None, + β_grid=None, +): + """ + 在参数网格上计算单位矩阵加权的 GMM 目标。 + """ + _, exog, instruments = build_gmm_arrays(data, n_lags) + + if γ_grid is None: + γ_grid = np.linspace(-1.0, 8.0, 70) + if β_grid is None: + β_grid = np.linspace(0.96, 1.02, 70) + + objective = np.empty((len(β_grid), len(γ_grid))) + + for i, β_val in enumerate(β_grid): + for j, γ_val in enumerate(γ_grid): + err = euler_error(np.array([γ_val, β_val]), exog) + moments = (err[:, None] * instruments).mean(axis=0) + objective[i, j] = moments @ moments + + return γ_grid, β_grid, objective +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: GMM 目标等高线曲面(模拟数据) + name: fig-hs82-objective-contour +--- +γ_grid, β_grid, objective = gmm_objective_surface(sim_data, n_lags=2) +log_obj = np.log10(objective + 1e-12) + +fig, ax = plt.subplots() +contours = ax.contourf(γ_grid, β_grid, log_obj, levels=30, cmap="viridis") +ax.set_xlabel(r"$\gamma$") +ax.set_ylabel(r"$\beta$") +ax.plot(γ_true, β_true, "k*", ms=12, lw=2, label="真实值") +ax.legend() +plt.colorbar(contours, ax=ax) +plt.tight_layout() +plt.show() +``` + +准则曲面可能有拉长的谷地,其中许多参数组合几乎同样好地拟合了矩。 + +为了说明 {cite:t}`hansen1982generalized` 第 2 节中的多期情形,我们使用重叠视界的回报和消费增长估计三期欧拉约束,工具由日期为 $t$ 或更早的单期数据构成,并采用适合 MA(2) 扰动的有限阶协方差。 + +```{code-cell} ipython3 +horizon_n = 3 +two_step = two_step_gmm( + sim_data, + n_lags=2, + ma_order=horizon_n - 1, + horizon=horizon_n, +) + +print(f"Horizon n: {horizon_n}") +print(f"Step-2 converged: {two_step['success']}") +print(f"Step-2 gamma: {two_step['params_step2'][0]:.4f}") +print(f"Step-2 beta (one-period): {two_step['params_step2'][1]:.4f}") +print( + f"J({two_step['j_df']}): {two_step['j_stat']:.3f}, " + f"Prob={two_step['j_prob']:.3f}, p={two_step['j_pval']:.3f}" +) + +_, exog_n, _ = build_gmm_arrays_horizon(sim_data, n_lags=2, horizon=horizon_n) +acf_n = acf( + euler_error_horizon(two_step["params_step2"], exog_n, horizon=horizon_n), + nlags=6, + fft=True, +) +print("Euler-error ACF lags 1-3:", ", ".join([f"{v:.3f}" for v in acf_n[1:4]])) +``` + +低滞后 ACF 与 3 期视界所隐含的 MA(2) 依赖性一致。 + +我们现在运行一个具有 500 次重复的蒙特卡洛练习,以可视化 $\hat\gamma$、$\hat\beta$ 和 $J$ 统计量的有限样本分布,并验证 {cite:t}`hansen1982generalized` 第 3 节的渐近理论提供了合理的近似。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 蒙特卡洛 GMM 抽样分布 + name: fig-hs82-monte-carlo +--- +n_rep = 500 +estimates = [] +j_stats = [] + +for rep in range(n_rep): + rep_data = simulate_euler_sample( + n_obs=900, + γ_true=γ_true, + β_true=β_true, + seed=rep, + ) + rep_res = estimate_gmm(rep_data, n_lags=2, use_hac=True, maxiter=2) + estimates.append(rep_res.params) + j_stats.append(rep_res.jval) + +estimates = np.asarray(estimates) +j_stats = np.asarray(j_stats) + +fig, axes = plt.subplots(1, 3, figsize=(15, 4)) +axes[0].hist(estimates[:, 0], bins=20, edgecolor="white") +axes[0].axvline(γ_true, color="red", ls="--", lw=2) +axes[0].set_xlabel(r"$\hat{\gamma}$") +axes[1].hist(estimates[:, 1], bins=20, edgecolor="white") +axes[1].axvline(β_true, color="red", ls="--", lw=2) +axes[1].set_xlabel(r"$\hat{\beta}$") + +df_j = 2 * 2 + 1 - 2 +axes[2].hist(j_stats, bins=20, density=True, edgecolor="white") +grid = np.linspace(0.0, max(j_stats.max(), 1.0), 200) +axes[2].plot(grid, stats.chi2.pdf(grid, df_j), "r-", lw=2) +axes[2].set_xlabel("j-statistic") +plt.tight_layout() +plt.show() +``` + +$\hat\gamma$ 和 $\hat\beta$ 都以其真实值为中心,$J$ 直方图跟踪了 $\chi^2$ 密度,支持了在此样本量下的渐近近似。 + +## 经验 GMM 估计 + +我们现在将 GMM 应用于观测数据,遵循 {cite:t}`hansen1982generalized` 第 5 节的经验策略。 + +{cite:t}`hansen1982generalized` 使用月度人均非耐用品消费(ND)和非耐用品加服务(NDS),并与来自 CRSP 的等权重(EWR)和市值加权(VWR)总股票回报配对,时间跨度为 1959:2 至 1978:12。 + +我们专注于他们的 ND+VWR 设定,使用 FRED 非耐用品消费和 Ken French 市值加权市场回报作为 CRSP 的代理,采用相同的 1959:2--1978:12 样本期。 + +由于 Ken French 回报与原始的 CRSP 纽约证券交易所市值加权回报不完全相同,我们只想在定性上与论文匹配。 + +本讲和配套讲座 {doc}`hansen_singleton_1983` 使用相同的数据构建。 + +下面的隐藏单元格加载了一个供应的月度数据集,包含总实际回报和总消费增长。这些数据由维护脚本 [`_static/lecture_specific/hansen_singleton_1982/make_data.py`](https://github.com/QuantEcon/lecture-python.myst/blob/main/lectures/_static/lecture_specific/hansen_singleton_1982/make_data.py) 从 [FRED](https://fred.stlouisfed.org/) 和 [Ken French](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html) 数据库构建,并在此直接从 GitHub 读取。 + +```{code-cell} ipython3 +:tags: [hide-cell] + +DATA_URL = ( + "https://github.com/QuantEcon/lecture-python.myst/raw/refs/heads/main/" + "lectures/_static/lecture_specific/hansen_singleton_1982/" + "hansen_singleton_1982_data.csv" +) + +# 一次性读取供应的快照;load_hs_monthly_data 只对其切片。 +_data = pd.read_csv(DATA_URL, index_col=0, parse_dates=True) + + +def load_hs_monthly_data(start="1959-02-01", end="1978-12-01"): + """ + 加载月度总实际回报和总消费增长序列。 + + 数据是由维护脚本 + ``_static/lecture_specific/hansen_singleton_1982/make_data.py`` 构建的 + 供应快照,该脚本从 FRED 和 Ken French 数据库构建它们。 + """ + start = pd.Timestamp(start).to_period("M").to_timestamp("M") + end = pd.Timestamp(end).to_period("M").to_timestamp("M") + return _data.loc[start:end].copy() + + +def get_estimation_data( + start="1959-02-01", + end="1978-12-01", +): + """ + 使用观测数据返回 (dataframe, array)。 + """ + frame = load_hs_monthly_data(start=start, end=end) + data = frame[["gross_real_return", "gross_cons_growth"]].to_numpy() + return frame, data +``` + +我们首先检查原始数据的矩。 + +```{code-cell} ipython3 +LAGS = (1, 2, 4, 6) + +emp_frame, emp_data = get_estimation_data() + +print(f"Mean net real return: {(emp_data[:, 0].mean() - 1.0) * 100:.3f}%") +print(f"Std net real return: {emp_data[:, 0].std() * 100:.3f}%") +print(f"Mean net consumption growth: {(emp_data[:, 1].mean() - 1.0) * 100:.3f}%") +print(f"Std net consumption growth: {emp_data[:, 1].std() * 100:.3f}%") +print(f"Std log consumption growth: {np.log(emp_data[:, 1]).std() * 100:.3f}%") +``` + +这些数据的一个特征是回报的波动率与消费增长的波动率之间存在巨大差距。 + +这再次是 {cite:t}`MehraPrescott1985` 股权溢价之谜背后的一个经验事实:用 CRRA 偏好匹配观测到的股权溢价需要难以置信的高风险厌恶。 + +我们现在使用 {cite:t}`hansen1982generalized` 中的两步广义工具变量(GIV)/ GMM 程序来估计欧拉方程。 + +对于单期股票回报欧拉方程($n=1$),扰动是一个鞅差分序列,因此最优权重矩阵使用同期协方差 $S_0 = E[m_t m_t^\top]$。 + +为了匹配表 I,我们报告论文在 +$E_t[\beta (C_{t+1}/C_t)^\alpha R_{t+1} - 1] = 0$ 中的指数参数 $\alpha$。 + +按滞后长度得到的 $\hat{\alpha}$ 和 $\hat{\beta}$ 的两步 GMM 估计为 + +```{code-cell} ipython3 +gmm_raw = run_two_step_by_lag(emp_data, lags=LAGS, horizon=1) +gmm_raw.index.name = "NLAG" + +table_i = pd.DataFrame(index=gmm_raw.index) +table_i.index.name = "NLAG" +table_i[r"\hat{\alpha}"] = -gmm_raw["γ_hat"] +table_i[r"SE(\hat{\alpha})"] = gmm_raw["se_γ"] +table_i[r"\beta"] = gmm_raw["β_hat"] +table_i[r"\mathrm{SE}(\beta)"] = gmm_raw["se_β"] +table_i[r"\chi^2"] = gmm_raw["j_stat"] +table_i["DF"] = gmm_raw["j_df"] +table_i["Prob"] = gmm_raw["j_prob"] + +display_table( + table_i, + fmt={ + r"\hat{\alpha}": "{:.4f}", + r"SE(\hat{\alpha})": "{:.4f}", + r"\beta": "{:.4f}", + r"\mathrm{SE}(\beta)": "{:.4f}", + r"\chi^2": "{:.4f}", + "DF": "{:.0f}", + "Prob": "{:.4f}", + }, +) +``` + +作为比较,{cite:t}`hansen1982generalized` 的表 I(如 [1984 年 *Econometrica* 勘误](https://www.jstor.org/stable/1911486?seq=2) 中所更正的)报告了 1959:2--1978:12 期间以下 ND+VWR 值: + +```{code-cell} ipython3 +:tags: [hide-input] + +table_i_paper = pd.DataFrame( + { + r"\alpha": [-1.2028, -0.5761, -0.6565, -0.9638], + r"SE(\alpha)": [0.7789, 0.7067, 0.6896, 0.6425], + r"\beta": [0.9976, 0.9975, 0.9978, 0.9985], + r"\mathrm{SE}(\beta)": [0.0027, 0.0027, 0.0027, 0.0027], + r"\chi^2": [1.457, 5.819, 7.923, 10.522], + "DF": [1, 3, 7, 11], + "Prob": [0.7726, 0.8792, 0.6606, 0.5159], + }, + index=pd.Index([1, 2, 4, 6], name="NLAG"), +) + +display_table( + table_i_paper, + fmt={ + r"\alpha": "{:.4f}", + r"SE(\alpha)": "{:.4f}", + r"\beta": "{:.4f}", + r"\mathrm{SE}(\beta)": "{:.4f}", + r"\chi^2": "{:.4f}", + "DF": "{:.0f}", + "Prob": "{:.4f}", + }, +) +``` + +它们与我们的估计非常接近。 + +## 小结 + +GMM 估计量只需要欧拉方程隐含的正交条件和一组条件变量。 + +它不需要关于消费和回报的联合分布、生产技术,或除代表性主体一阶条件之外的经济环境任何其他部分的假设。 + +因此,GMM 提供了一种估计某些感兴趣对象的方法,而无需估计 {cite:t}`hansen1983stochastic` 在其消费增长和回报的对数线性模型中估计的所有参数。 + + * 如果 {cite:t}`hansen1983stochastic` 的完整模型被正确指定,那么他们的最大似然估计量有望比本讲中描述的 GMM 估计量更有效率。 + * 估计*某物*而非估计*一切*的主题贯穿了 Lars Peter Hansen 的大部分工作。参见 {cite:t}`hansen2014nobel` \ No newline at end of file diff --git a/lectures/hansen_singleton_1983.md b/lectures/hansen_singleton_1983.md new file mode 100644 index 0000000..647e1cf --- /dev/null +++ b/lectures/hansen_singleton_1983.md @@ -0,0 +1,1844 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 +kernelspec: + name: python3 + display_name: Python 3 (ipykernel) + language: python +translation: + title: 随机消费、风险规避与资产回报的时间行为 + headings: + Overview: 概述 + Euler equation: 欧拉方程 + The Euler equation under lognormality: 对数正态性下的欧拉方程 + The restricted system and its likelihood: 受限系统及其似然 + Likelihood implementation: 似然的实现 + Likelihood implementation::Simulation: 模拟 + Preference parameters and likelihood ratio tests: 偏好参数与似然比检验 + Predictability and the R-squared restriction: 可预测性与 R 平方限制 + Return-difference tests: 回报差异检验 + Empirical MLE estimation: 实证 MLE 估计 + Empirical MLE estimation::Data: 数据 + Empirical MLE estimation::MLE estimation and predictability summaries: MLE 估计与可预测性总结 + Empirical MLE estimation::Treasury bill estimation: 国库券估计 + Residual diagnostics: 残差诊断 + Connection to the equity premium puzzle: 与股权溢价之谜的联系 + Another approach: 另一种方法 +--- + +(hansen_singleton_1983)= +```{raw} jupyter + +``` + +# 随机消费、风险规避与资产回报的时间行为 + +```{index} single: Asset Pricing; MLE Estimation +``` + +```{contents} Contents +:depth: 2 +``` + +> Evans 和 Honkapohja:经济学界对卢卡斯批判最重要的回应是什么? +> +> Sargent:有两个。第一个也是最乐观的回应是完全的理性预期计量经济学。一个理性预期均衡就是一个似然函数。将它最大化。 +> +> -- An Interview with Thomas J. Sargent {cite}`evans2005interview` + +## 概述 + +本讲座描述了 {cite:t}`hansen1983stochastic` 如何构建一个完整的资产回报和消费增长的统计模型,然后用最大似然法估计其参数。 + +他们发现了模型中的一些缺陷,其中一个后来被 {cite:t}`MehraPrescott1985` 称为**股权溢价之谜**。 + +{cite:t}`hansen1983stochastic` 研究了一个基于消费的资产定价模型,其中具有 CRRA 偏好的代表性消费者选择如何在可交易资产之间配置财富。 + +资产持有的一阶条件是随机欧拉方程,它将消费增长、资产回报和偏好参数联系起来。 + +{cite:t}`hansen1983stochastic` 假设消费增长和资产回报*联合服从对数正态分布*。 + +于是欧拉方程对资产价格与回报的联合分布施加了一组限制。 + +这些限制约束了一个关于消费增长和回报对数的线性时间序列模型,其中对数回报中的可预测变动与对数消费增长中的可预测变动成正比。 + +Hansen 和 Singleton 通过 {doc}`mle` 估计了他们的模型。 + +{cite:t}`hansen1983stochastic` 的实证发现构成了 {cite:t}`MehraPrescott1985` 后来所称的**股权溢价之谜**。 + +为了使本讲座保持聚焦,我们每次只估计一种回报(市场代理或国库券),而不是 {cite:t}`hansen1983stochastic` 所研究的完整多资产系统。 + + * 我们只使用月度非耐用品消费(`ND`)。 + +```{code-cell} ipython3 +from itertools import combinations + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +from IPython.display import Latex +from scipy import stats +from scipy.linalg import LinAlgError, cholesky, solve_triangular +from scipy.optimize import minimize +from statsmodels.stats.stattools import durbin_watson + +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +我们还在下面的隐藏单元格中定义一个辅助函数,用于将 DataFrame 显示为 LaTeX 数组 + +```{code-cell} ipython3 +:tags: [hide-cell] + +def display_table(df, title=None, fmt=None): + """ + 将 DataFrame 显示为 LaTeX 数组。 + """ + if fmt is None: + fmt = {} + formatted = df.copy() + for col in formatted.columns: + if col in fmt: + formatted[col] = formatted[col].apply( + lambda x: fmt[col].format(x) if np.isfinite(x) else str(x)) + n_cols = len(formatted.columns) + idx_header = r"\text{" + df.index.name + "}" if df.index.name else "" + columns = " & ".join( + [idx_header] + [r"\text{" + c + "}" if "\\" not in c + and "^" not in c and "_" not in c + else c for c in formatted.columns]) + rows = r" \\".join( + [" & ".join([str(idx)] + [str(v) for v in row]) + for idx, row in zip(formatted.index, formatted.values)]) + col_format = "r" + "c" * n_cols + lines = [r"\begin{array}{" + col_format + "}"] + lines.append(columns + r" \\") + lines.append(r"\hline") + lines.append(rows) + lines.append(r"\end{array}") + latex = "\n".join(lines) + if title: + latex = rf"\textbf{{{title}}}" + r"\\" + "\n" + latex + display(Latex("$" + latex + "$")) +``` + +## 欧拉方程 + +考虑一个由相同消费者构成的单一商品经济,其效用函数为 CRRA 形式 + +```{math} +:label: hs83-crra + +U(c_t) = c_t^{\gamma}/\gamma, \quad \gamma < 1, +``` + +其中 $c_t$ 是人均实际总消费,$U(\cdot)$ 是期间效用函数。 + +代表性消费者选择一个随机消费计划以最大化时间可加效用函数的期望值, + +```{math} +:label: hs83-objective + +E_0 \sum_{t=0}^{\infty} \beta^t U(c_t), \quad 0 < \beta < 1. +``` + +消费者通过交易 $N$ 种金融和资本资产的所有权来用现在的消费替代未来的消费。 + +设 $\mathbf{w}_t$ 表示在时点 $t$ 对 $N$ 种资产的持有量,$\mathbf{q}_t$ 是资产价格向量,$\mathbf{d}_t$ 是红利向量,$y_t$ 是实际劳动收入。 + +一个可行的消费和投资计划 $\{c_t, \mathbf{w}_t\}$ 必须满足如下预算约束序列 + +```{math} +:label: hs83-budget + +c_t + \mathbf{q}_t \cdot \mathbf{w}_{t+1} \leq (\mathbf{q}_t + \mathbf{d}_t) \cdot \mathbf{w}_t + y_t, +``` + +其中 $(\mathbf{q}_t + \mathbf{d}_t) \cdot \mathbf{w}_t$ 是带入第 $t$ 期的投资组合的含红利价值。 + +为了推导一阶条件,对每个时点 $t$ 的预算约束 {eq}`hs83-budget` 附加一个拉格朗日乘子 $\lambda_t$,并构造拉格朗日函数 + +```{math} +:label: hs83-lagrangian + +\mathcal{L} = E_0 \sum_{t=0}^{\infty} \beta^t \left\{ U(c_t) + \lambda_t \left[ (\mathbf{q}_t + \mathbf{d}_t) \cdot \mathbf{w}_t + y_t - c_t - \mathbf{q}_t \cdot \mathbf{w}_{t+1} \right] \right\}. +``` + +对 $\mathcal{L}$ 关于 $c_t$ 求导得 + +```{math} +\frac{\partial \mathcal{L}}{\partial c_t} = 0 \implies \lambda_t = U'(c_t). +``` + +关于 $w_{i,t+1}$(即从时点 $t$ 带入时点 $t+1$ 的资产 $i$ 持有量)求导会汇集两项:$w_{i,t+1}$ 出现在第 $t$ 期预算约束以及第 $t+1$ 期约束中: + +```{math} +\frac{\partial \mathcal{L}}{\partial w_{i,t+1}} = 0 \implies E_0\!\left[\beta^t \big(- \lambda_t\, q_{it} + \beta\, \lambda_{t+1} (q_{i,t+1} + d_{i,t+1})\big)\right] = 0. +``` + +根据迭代期望法则,这变为 + +```{math} +E_0\!\left[\beta^t\, E_t\!\left(- \lambda_t\, q_{it} + \beta\, \lambda_{t+1} (q_{i,t+1} + d_{i,t+1})\right)\right] = 0. +``` + +因此, + +```{math} +\lambda_t\, q_{it} = \beta\, E_t\!\left[\lambda_{t+1}(q_{i,t+1} + d_{i,t+1})\right]. +``` + +代入 $\lambda_t = U'(c_t)$ 和 $\lambda_{t+1} = U'(c_{t+1})$ 得 + +```{math} +q_{it}\, U'(c_t) = \beta\, E_t\!\left[U'(c_{t+1})(q_{i,t+1} + d_{i,t+1})\right]. +``` + +两边同除以 $q_{it}$ 并定义总回报率 $r_{it+1} := (q_{i,t+1} + d_{i,t+1})/q_{it}$,得到随机欧拉方程: + +```{math} +:label: hs83-foc + +U'(c_t) = \beta E_t\!\left[U'(c_{t+1})\, r_{it+1}\right], \quad i = 1, \ldots, N, +``` + +其中 $r_{it+1}$ 是资产 $i$ 的总实际回报率。 + +将 CRRA 边际效用 $U'(c_t) = c_t^{\gamma-1} = c_t^{\alpha}$(其中 $\alpha := \gamma - 1$)代入 {eq}`hs83-foc` 并整理得 + +```{math} +:label: hs83-euler + +E_t\!\left[\beta \left(\frac{c_{t+1}}{c_t}\right)^{\alpha} r_{it+1}\right] = 1, \quad i = 1, \ldots, N. +``` + +相对风险规避系数为 $-\alpha$。 + +## 对数正态性下的欧拉方程 + +利用上面推导的欧拉方程 {eq}`hs83-euler`,我们现在施加 {cite:t}`hansen1983stochastic` 的分布假设。 + +设 $x_t = c_t / c_{t-1}$ 表示消费比率,并定义 $u_{it} = x_t^\alpha r_{it}$,其中 $r_{it}$ 是资产 $i$ 的总实际回报率。 + +欧拉方程 {eq}`hs83-euler` 表明 $E_{t-1}[u_{it}] = 1/\beta$。 + +定义对数变量 $X_t = \log x_t$、$R_{it} = \log r_{it}$ 和 $U_{it} = \log u_{it}$,使得 + +```{math} +:label: hs83-u-def + +U_{i,t}= \alpha X_{t}+R_{i,t}. +``` + +假设向量过程 $\{Y_t\} = \{(X_t, R_{1t}, \ldots, R_{nt})^\top\}$ 是联合平稳且服从高斯分布的。 + +在此假设下,给定信息集 $\psi_{t-1}$,$U_{it}$ 服从具有常数方差 $\sigma_i^2$ 的正态分布,且其条件均值 $\mu_{i,t-1}$ 是过去 $Y$ 的线性函数。 + +由于 $u_{it} = \exp(U_{it})$ 是条件对数正态的, + +```{math} +:label: hs83-lognormal-identity + +E_{t-1}[u_{it}] = \exp\left(\mu_{i,t-1} + \tfrac{1}{2}\sigma_i^2\right). +``` + +令 $E_{t-1}[u_{it}] = 1/\beta$ 并取对数得 $\mu_{i,t-1} + \sigma_i^2/2 = -\log\beta$。 + +现在定义创新 + +```{math} +:label: hs83-v-it + +V_{i,t} := U_{i,t} - \mu_{i,t-1} = \alpha X_{t}+R_{i,t}+\log\beta+\frac{\sigma_i^2}{2}, +\quad i = 1, \ldots, N. +``` + +则 $E_{t-1}[V_{i,t}]=0$,其中 $\sigma_i^2=\operatorname{Var}_{t-1}(\alpha X_t + R_{it})$ 在平稳性和高斯假设下为常数。 + +令 $E_{t-1}[V_{i,t}] = 0$ 给出条件均值限制 + +```{math} +:label: hs83-cond-mean + +E_{t-1}[R_{i,t}] = -\alpha\, E_{t-1}[X_{t}] - \log\beta - \frac{\sigma_i^2}{2}. +``` + +方程 {eq}`hs83-cond-mean` 是 {cite:t}`hansen1983stochastic` 的核心结果。 + +每种资产对数回报的可预测部分与对数消费增长的可预测部分成正比,比例因子为 $-\alpha$。 + +截距吸收了贴现因子 $\beta$ 和对数正态方差项 $\sigma_i^2 / 2$。 + +让我们考虑三个特殊情形,以更好地理解 {eq}`hs83-cond-mean` 的含义: + +- 风险中性($\alpha = 0$):每种资产的对数回报等于一个常数加上一个序列不相关的误差项,因此回报是序列不相关的。 +- 对数效用($\alpha = -1$):差值 $R_{it} - X_t$ 没有随时间变化的可预测成分,因此回报和消费增长共享相同的可预测成分。 +- 风险规避($\alpha < 0$):$E_{t-1}[R_{it}]$ 中随时间变化的部分等于 $-\alpha$ 乘以 $E_{t-1}[X_t]$,因此 $|\alpha|$ 越大,预期回报对预期消费增长的敏感度就越被放大。 + +对于给定的消费-回报协方差结构,更高的相对风险规避($-\alpha$)会扩大风险资产回报与无风险回报之间的差距。 + +股权溢价之谜之所以出现,是因为观测到的价差很大,但估计的 $|\alpha|$ 却很小,正如我们即将在估计中看到的那样。 + +## 受限系统及其似然 + +为了构建似然函数,我们需要对条件期望 $E_{t-1}[X_t]$ 进行参数化。 + +在单一回报的情形下,记 $\mathbf{Y}_t = (X_t, R_t)^\top$,并假设 $X_t$ 的可预测成分是过去观测值的有限阶线性函数: + +```{math} +:label: hs83-x-forecast + +E(X_t\mid\psi_{t-1})=\mathbf{a}(L)^\top \mathbf{Y}_{t-1}+\mu_x, +``` + +其中 $\mathbf{a}(L)$ 是过去 $(X, R)$ 上的滞后多项式系数向量,$\mu_x$ 是一个常数。 + +消费增长方程是不受限制的,因此 $X_t$ 自由地依赖于它自身的滞后值和滞后回报。 + +然而,回报方程受欧拉方程的限制。 + +将 {eq}`hs83-cond-mean` 与 {eq}`hs83-x-forecast` 结合起来,迫使 $R_t$ 的可预测部分等于 $-\alpha$ 乘以 $X_t$ 的可预测部分再加上一个常数。 + +这给出了受限系统 + +```{math} +:label: hs83-restricted + +\mathbf{A}_0\mathbf{Y}_t=\mathbf{A}_1(L)\mathbf{Y}_{t-1}+\boldsymbol{\mu}+\mathbf{V}_t, +``` + +其中 + +```{math} +:label: hs83-a0a1 + +\mathbf{A}_0=\begin{bmatrix}1&0\\\alpha&1\end{bmatrix}, +\quad +\mathbf{A}_1(L)=\begin{bmatrix}\mathbf{a}(L)^\top\\0\end{bmatrix}, +\quad +\boldsymbol{\mu}=\begin{bmatrix}\mu_x\\-\log\beta-\sigma_U^2/2\end{bmatrix}, +``` + +其中在条件同方差下 $\sigma_U^2 := \operatorname{Var}_{t-1}(\alpha X_t + R_t) = \alpha^2 \sigma_{XX} + \sigma_{RR} + 2\alpha \sigma_{XR}$。 + +$\boldsymbol{\mu}$ 第二个元素中的符号直接由 {eq}`hs83-cond-mean` 得出。 + +创新 $\mathbf{V}_t$ 假设服从密度为 $f_V(\mathbf{v})$ 的高斯分布。 + +由于 $\mathbf{V}_t = \mathbf{A}_0 \mathbf{Y}_t - \mathbf{A}_1(L)\mathbf{Y}_{t-1} - \boldsymbol{\mu}$,可观测量 $\mathbf{Y}_t$ 是 $\mathbf{V}_t$ 的线性变换,即 $\mathbf{Y}_t = \mathbf{A}_0^{-1}(\mathbf{V}_t + \mathbf{A}_1(L)\mathbf{Y}_{t-1} + \boldsymbol{\mu})$。 + +密度的变量替换公式给出 + +$$ +f_Y(\mathbf{y}_t \mid \mathbf{Y}_{t-1}) = f_V(\mathbf{A}_0 \mathbf{y}_t - \mathbf{A}_1(L)\mathbf{Y}_{t-1} - \boldsymbol{\mu})\;\left|\det\!\left(\frac{\partial \mathbf{V}_t}{\partial \mathbf{Y}_t}\right)\right| = f_V(\mathbf{v}_t)\;|\det(\mathbf{A}_0)|. +$$ + +由于 $\mathbf{A}_0$ 是单位下三角矩阵,$\det(\mathbf{A}_0) = 1$,所以雅可比项消失,$\mathbf{Y}_t$ 的对数似然等于在残差处求值的 $\mathbf{V}_t$ 的对数似然。 + +由于雅可比为一,$\mathbf{Y}_t$ 的条件密度就是在 $\mathbf{v}_t = \mathbf{A}_0 \mathbf{Y}_t - \mathbf{A}_1(L)\mathbf{Y}_{t-1} - \boldsymbol{\mu}$ 处求值的 $\mathbf{V}_t$ 的高斯密度。 + +对于单个观测值,$\mathbf{V}_t \sim N(\mathbf{0}, \boldsymbol{\Sigma})$ 的密度为 + +$$ +f_V(\mathbf{v}_t) = (2\pi)^{-1} |\boldsymbol{\Sigma}|^{-1/2} \exp\!\left(-\tfrac{1}{2}\,\mathbf{v}_t^\top \boldsymbol{\Sigma}^{-1} \mathbf{v}_t\right). +$$ + +取对数得 + +$$ +\ell_t(\theta) = -\log(2\pi) - \tfrac{1}{2}\log|\boldsymbol{\Sigma}| - \tfrac{1}{2}\,\mathbf{v}_t^\top \boldsymbol{\Sigma}^{-1}\,\mathbf{v}_t. +$$ + +对 $T$ 个观测值求和并舍去常数 $-T\log(2\pi)$,得到对数似然函数 + +```{math} +:label: hs83-loglik + +L(\theta) = -\frac{T}{2}\log|\boldsymbol{\Sigma}| - \frac{1}{2}\sum_{t=1}^{T}(\mathbf{A}_0 \mathbf{Y}_t - \mathbf{A}_1(L)\mathbf{Y}_{t-1} - \boldsymbol{\mu})^\top\boldsymbol{\Sigma}^{-1}(\mathbf{A}_0 \mathbf{Y}_t - \mathbf{A}_1(L)\mathbf{Y}_{t-1} - \boldsymbol{\mu}), +``` + +其中 $\boldsymbol{\Sigma}$ 是创新 $\mathbf{V}_t$ 的协方差矩阵,$\theta$ 汇集了所有自由参数,包括 $\alpha$、$\beta$、协方差参数、第一行截距 $\mu_x$ 以及第一行滞后系数。 + +由 {eq}`hs83-euler` 施加的限制通过 {eq}`hs83-a0a1` 中 $\mathbf{A}_0$、$\mathbf{A}_1(L)$ 和 $\boldsymbol{\mu}$ 的结构进入 {eq}`hs83-loglik`。 + +{eq}`hs83-restricted` 的第二行没有自由滞后系数,其截距由 $\alpha$、$\beta$ 和 $\boldsymbol{\Sigma}$ 决定。 + +一个替代的无限制二元 VAR($p$) 会自由地估计 {eq}`hs83-restricted` 的两行。 + +每一行有 1 个截距加上 $2p$ 个滞后系数($p$ 个滞后 $\times$ 2 个变量),给出 $2(1 + 2p)$ 个均值参数。 + +再加上 3 个自由协方差参数($\sigma_{XX}, \sigma_{RR}, \sigma_{XR}$),总共有 $5 + 4p$ 个参数。 + +受限系统 {eq}`hs83-restricted` 只有 $6 + 2p$ 个自由参数:第一行贡献 $1 + 2p$ 个(它的截距 $\mu_x$ 和 $2p$ 个滞后系数),再加上 $\alpha$、$\beta$ 和 3 个协方差参数。 + +第二行不增加任何参数,因为它的滞后结构和截距通过 {eq}`hs83-cond-mean` 由 $\alpha$、$\beta$ 和 $\boldsymbol{\Sigma}$ 确定。 + +差值 $(\smash{5 + 4p}) - (\smash{6 + 2p}) = 2p - 1$ 给出了我们即将执行的似然比检验的自由度。 + +## 似然的实现 + +现在让我们实现似然 {eq}`hs83-loglik`。 + +组成部分有: + +- 一个用于构造滞后数据矩阵 $(\mathbf{Y}_t, \mathbf{Y}_{t-1}, \ldots, \mathbf{Y}_{t-p})$ 的函数, + +- 一个将参数向量映射到矩阵 $\mathbf{A}_0$、$\mathbf{A}_1$、$\boldsymbol{\mu}$、$\boldsymbol{\Sigma}$ 的函数, + +- 一个计算受限系统残差 $\mathbf{V}_t = \mathbf{A}_0 \mathbf{Y}_t - \mathbf{A}_1(L) \mathbf{Y}_{t-1} - \boldsymbol{\mu}$ 的函数,以及 + +- 高斯对数似然本身。 + +由于我们处理的是对数变换后的数据,我们在下面定义一个用于该变换的辅助函数 + +```{code-cell} ipython3 +def to_mle_array(data): + valid = (data[:, 0] > 0.0) & (data[:, 1] > 0.0) + return np.column_stack( + [np.log(data[valid, 1]), np.log(data[valid, 0])]) +``` + + +首先我们构建滞后数据矩阵,它们是似然函数的输入 + +```{code-cell} ipython3 +def build_lagged_data(data, n_lags): + """ + 为二元数据构建 Y_t 和滞后堆栈 [Y_{t-1}, ..., Y_{t-p}]。 + """ + if data.ndim != 2 or data.shape[1] != 2: + raise ValueError("data must be T x 2.") + if data.shape[0] <= n_lags: + raise ValueError("Sample size must exceed n_lags.") + + t_obs = data.shape[0] + n_obs = t_obs - n_lags + y_t = data[n_lags:, :] + y_lag = np.empty((n_obs, 2 * n_lags)) + + for lag in range(1, n_lags + 1): + y_lag[:, 2 * (lag - 1) : 2 * lag] = data[n_lags - lag : t_obs - lag, :] + + return y_t, y_lag +``` + +接下来,我们验证并解包参数向量,同时施加可行性条件 + +```{code-cell} ipython3 +def unpack_parameters(params, n_lags): + """ + 验证并解包参数向量。 + """ + if len(params) != 6 + 2 * n_lags: + return None + + α, β, σ_x, σ_r, cov_xr, μ_x = params[:6] + a_lags = params[6:] + + tol = 1e-8 + if not np.isfinite(α): + return None + if not (tol < β): + return None + if not (σ_x > tol and σ_r > tol): + return None + + Σ = np.array( + [ + [σ_x ** 2, cov_xr], + [cov_xr, σ_r ** 2], + ] + ) + + try: + cholesky(Σ, lower=True) + except (LinAlgError, ValueError): + return None + + return { + "α": np.array(α), + "β": np.array(β), + "σ_x": np.array(σ_x), + "σ_r": np.array(σ_r), + "cov_xr": np.array(cov_xr), + "μ_x": np.array(μ_x), + "a_lags": a_lags, + } +``` + +下一步将参数和滞后数据映射到受限系统的残差 + +```{code-cell} ipython3 +def restricted_residuals( + params, + y_t, + y_lag, + n_lags, +): + """ + 计算由 A0 Y_t - A1 Y_{t-1} - mu 隐含的 V_t。 + """ + parsed = unpack_parameters(params, n_lags) + if parsed is None: + return None + + α = float(parsed["α"]) + β = float(parsed["β"]) + σ_x = float(parsed["σ_x"]) + σ_r = float(parsed["σ_r"]) + cov_xr = float(parsed["cov_xr"]) + μ_x = float(parsed["μ_x"]) + a_lags = np.asarray(parsed["a_lags"]) + + A0 = np.array([[1.0, 0.0], [α, 1.0]]) + A1 = np.zeros((2, 2 * n_lags)) + A1[0, :] = a_lags + σ_u2 = α ** 2 * σ_x ** 2 + σ_r ** 2 + 2.0 * α * cov_xr + μ = np.array([μ_x, -np.log(β) - 0.5 * σ_u2]) + + resid = y_t @ A0.T - y_lag @ A1.T - μ[None, :] + if np.any(np.abs(resid) > 1e10): + return None + return resid +``` + +这种递归结构也让我们能够从模型中模拟数据。 + +我们可以通过抽取创新 $\mathbf{V}_t \sim N(\mathbf{0}, \boldsymbol{\Sigma})$ 并向前计算 $\mathbf{Y}_t = \mathbf{A}_0^{-1}(\mathbf{A}_1(L) \mathbf{Y}_{t-1} + \boldsymbol{\mu} + \mathbf{V}_t)$ 来从模型生成数据。 + +这对于通过蒙特卡洛检查似然实现很有用 + +```{code-cell} ipython3 +def simulate_restricted_var( + params, + n_obs, + n_lags, + burn_in=200, + seed=0, +): + """ + 从受限模型模拟 [对数消费增长, 对数回报]。 + """ + if seed is not None: + np.random.seed(seed) + + if len(params) != 6 + 2 * n_lags: + raise ValueError("Parameter vector length must be 6 + 2 * n_lags.") + + α, β, σ_x, σ_r, cov_xr, μ_x = params[:6] + a_lags = params[6:] + + Σ_e = np.array( + [ + [σ_x ** 2, cov_xr], + [cov_xr, σ_r ** 2], + ] + ) + + A0 = np.array([[1.0, 0.0], [α, 1.0]]) + Σ_v = A0 @ Σ_e @ A0.T + + eigvals = np.linalg.eigvals(Σ_v) + if np.min(eigvals) <= 0.0: + Σ_v += np.eye(2) * 1e-6 + + A1 = np.zeros((2, 2 * n_lags)) + A1[0, :] = a_lags + σ_u2 = α ** 2 * σ_x ** 2 + σ_r ** 2 + 2.0 * α * cov_xr + μ = np.array([μ_x, -np.log(β) - 0.5 * σ_u2]) + + total_n = n_obs + burn_in + y = np.zeros((total_n, 2)) + + for t in range(n_lags, total_n): + lag_stack = [] + for lag in range(1, n_lags + 1): + lag_stack.append(y[t - lag, :]) + lag_vec = np.concatenate(lag_stack) + shock = np.random.multivariate_normal(np.zeros(2), Σ_v) + y[t, :] = np.linalg.solve(A0, A1 @ lag_vec + μ + shock) + + return y[burn_in:, :] +``` + +接下来,我们编码由残差协方差矩阵隐含的高斯对数似然 + +```{code-cell} ipython3 +def log_likelihood_mle( + params, + y_t, + y_lag, + n_lags, + include_const=True, +): + """ + 为受限系统计算高斯对数似然。 + """ + parsed = unpack_parameters(params, n_lags) + if parsed is None: + return -np.inf + + resid = restricted_residuals(params, y_t, y_lag, n_lags) + if resid is None: + return -np.inf + + α = float(parsed["α"]) + σ_x = float(parsed["σ_x"]) + σ_r = float(parsed["σ_r"]) + cov_xr = float(parsed["cov_xr"]) + + Σ_e = np.array( + [ + [σ_x ** 2, cov_xr], + [cov_xr, σ_r ** 2], + ] + ) + + A0 = np.array([[1.0, 0.0], [α, 1.0]]) + Σ_v = A0 @ Σ_e @ A0.T + + try: + chol = cholesky(Σ_v, lower=True) + log_det = 2.0 * np.sum(np.log(np.diag(chol) + 1e-16)) + std_resid = solve_triangular(chol, resid.T, lower=True).T + quad_form = np.sum(std_resid ** 2) + except (LinAlgError, ValueError): + return -np.inf + + sample_size = y_t.shape[0] + ll = -0.5 * sample_size * log_det - 0.5 * quad_form + if include_const: + ll -= sample_size * np.log(2.0 * np.pi) + + if np.isnan(ll) or np.isinf(ll): + return -np.inf + return float(ll) +``` + +为了将其传递给数值优化器,我们将对数似然包装为一个最小化目标 + +```{code-cell} ipython3 +def negative_log_likelihood( + params, + y_t, + y_lag, + n_lags, +): + """ + 返回用于最小化的负对数似然。 + """ + ll = log_likelihood_mle(params, y_t, y_lag, n_lags, include_const=False) + if np.isfinite(ll): + return -ll + return 1e20 +``` + +我们为多起点优化设置参数界限并生成由数据驱动的起始值。 + +我们保持 $\beta$ 为正,但在估计中不强制 $\beta < 1$ + +```{code-cell} ipython3 +def parameter_bounds(n_lags): + """ + 优化的界限。 + """ + bounds = [ + (-200.0, 200.0), # α(= -风险规避) + (1e-8, 2.0), # β(贴现因子) + (1e-8, None), # σ_x(消费创新的标准差) + (1e-8, None), # σ_r(回报创新的标准差) + (None, None), # cov_xr(协方差) + (None, None), # μ_x(消费增长截距) + ] + bounds += [(-0.99, 0.99)] * (2 * n_lags) # VAR 滞后系数 + return bounds +``` + +我们使用多个起始向量来帮助局部求解器摆脱糟糕的初始化 + +```{code-cell} ipython3 +def starting_values(y_t, y_lag, n_lags, n_starts=10): + """ + 生成多个起始值。 + """ + rng = np.random.default_rng(123) + starts = [] + n_params = 6 + 2 * n_lags + + base = np.zeros(n_params) + base[0] = -0.5 + base[1] = 0.999 + base[2] = max(float(np.std(y_t[:, 0])), 1e-3) + base[3] = max(float(np.std(y_t[:, 1])), 1e-3) + base[4] = float(np.cov(y_t.T)[0, 1]) + base[5] = float(np.mean(y_t[:, 0])) + base[6:] = 0.1 + starts.append(base.copy()) + + # 来自无限制 VAR 的 OLS 种子 + n_obs = y_t.shape[0] + x = np.column_stack([np.ones(n_obs), y_lag]) + coef = np.linalg.lstsq(x, y_t, rcond=None)[0] + resid = y_t - x @ coef + Σ_e = resid.T @ resid / max(1, n_obs) + + a_lags_ols = coef[1:, 0] + r_lags_ols = coef[1:, 1] + denom = float(a_lags_ols @ a_lags_ols) + if denom > 1e-10: + α_ols = -float((a_lags_ols @ r_lags_ols) / denom) + else: + α_ols = -0.5 + + μ_x_ols = float(coef[0, 0]) + μ_r_ols = float(coef[0, 1]) + σ_x_ols = float(np.sqrt(max(Σ_e[0, 0], 1e-8))) + σ_r_ols = float(np.sqrt(max(Σ_e[1, 1], 1e-8))) + cov_xr_ols = float(Σ_e[0, 1]) + σ_u2_ols = ( + α_ols ** 2 * σ_x_ols ** 2 + + σ_r_ols ** 2 + + 2.0 * α_ols * cov_xr_ols + ) + β_ols = float(np.exp(-(μ_r_ols + α_ols * μ_x_ols + 0.5 * σ_u2_ols))) + β_ols = float(np.clip(β_ols, 1e-6, 2.0)) + + ols_seed = np.zeros(n_params) + ols_seed[0] = α_ols + ols_seed[1] = β_ols + ols_seed[2] = σ_x_ols + ols_seed[3] = σ_r_ols + ols_seed[4] = cov_xr_ols + ols_seed[5] = μ_x_ols + ols_seed[6:] = a_lags_ols + starts.append(ols_seed.copy()) + + seeds = [base, ols_seed] + while len(starts) < n_starts: + seed = seeds[len(starts) % len(seeds)] + trial = seed.copy() + trial[:2] += rng.normal(0.0, 0.2, 2) + trial[2:6] *= 1.0 + rng.normal(0.0, 0.15, 4) + trial[6:] += rng.normal(0.0, 0.08, 2 * n_lags) + trial[1] = max(trial[1], 1e-6) + trial[2] = max(trial[2], 1e-6) + trial[3] = max(trial[3], 1e-6) + starts.append(trial) + + return starts +``` + +标准误来自信息矩阵的梯度外积(OPG)近似,通过对每个观测的对数似然贡献进行有限差分计算得到。 + +在此应用中,这往往比有限差分海森矩阵在数值上更稳定。 + +```{code-cell} ipython3 +def log_likelihood_contributions( + params, + y_t, + y_lag, + n_lags, + include_const=False, +): + """ + 每个观测的高斯对数似然贡献向量。 + + 返回一个长度为 T 的数组,如果参数向量不可行则返回 None。 + """ + parsed = unpack_parameters(params, n_lags) + if parsed is None: + return None + + resid = restricted_residuals(params, y_t, y_lag, n_lags) + if resid is None: + return None + + α = float(parsed["α"]) + σ_x = float(parsed["σ_x"]) + σ_r = float(parsed["σ_r"]) + cov_xr = float(parsed["cov_xr"]) + + Σ_e = np.array( + [ + [σ_x ** 2, cov_xr], + [cov_xr, σ_r ** 2], + ] + ) + A0 = np.array([[1.0, 0.0], [α, 1.0]]) + Σ_v = A0 @ Σ_e @ A0.T + + try: + chol = cholesky(Σ_v, lower=True) + log_det = 2.0 * np.sum(np.log(np.diag(chol) + 1e-16)) + std_resid = solve_triangular(chol, resid.T, lower=True).T + except (LinAlgError, ValueError): + return None + + quad = np.sum(std_resid ** 2, axis=1) + ll_t = -0.5 * log_det - 0.5 * quad + if include_const: + ll_t -= np.log(2.0 * np.pi) + if not np.all(np.isfinite(ll_t)): + return None + return ll_t + + +def opg_standard_errors( + params, + y_t, + y_lag, + n_lags, + step=1e-6, + max_step_shrink=12, + eig_floor=1e-12, +): + """ + 通过信息矩阵的 OPG 近似计算标准误。 + """ + n = len(params) + ll0 = log_likelihood_contributions(params, y_t, y_lag, n_lags, include_const=False) + if ll0 is None: + return np.full(n, np.nan) + + n_obs = int(ll0.shape[0]) + scores = np.empty((n_obs, n)) + + for i in range(n): + base_step = step * (abs(params[i]) + 1.0) + hi = base_step + ll_plus = None + ll_minus = None + + for _ in range(max_step_shrink + 1): + p_plus = params.copy() + p_minus = params.copy() + p_plus[i] += hi + p_minus[i] -= hi + ll_plus = log_likelihood_contributions( + p_plus, y_t, y_lag, n_lags, include_const=False + ) + ll_minus = log_likelihood_contributions( + p_minus, y_t, y_lag, n_lags, include_const=False + ) + if ll_plus is not None and ll_minus is not None: + break + hi *= 0.5 + + if ll_plus is None or ll_minus is None: + return np.full(n, np.nan) + + scores[:, i] = (ll_plus - ll_minus) / (2.0 * hi) + + if not np.all(np.isfinite(scores)): + return np.full(n, np.nan) + + # 将得分居中以减轻数值漂移 + scores = scores - scores.mean(axis=0, keepdims=True) + + opg = scores.T @ scores + if not np.all(np.isfinite(opg)): + return np.full(n, np.nan) + opg = 0.5 * (opg + opg.T) + + try: + eigvals, eigvecs = np.linalg.eigh(opg) + except (LinAlgError, ValueError): + return np.full(n, np.nan) + + floor = float(eig_floor) * max(1.0, float(np.max(eigvals))) + eigvals = np.clip(eigvals, floor, None) + cov = eigvecs @ np.diag(1.0 / eigvals) @ eigvecs.T + se = np.sqrt(np.maximum(np.diag(cov), 0.0)) + se[~np.isfinite(se)] = np.nan + return se +``` + +下面的多起点 MLE 估计器组合了这些部分并返回参数、拟合准则和残差 + +```{code-cell} ipython3 +def estimate_mle(data, n_lags, verbose=False): + """ + 通过多起点局部优化估计受限模型。 + """ + y_t, y_lag = build_lagged_data(data, n_lags) + bounds = parameter_bounds(n_lags) + starts = starting_values(y_t, y_lag, n_lags) + + best_result = None + best_ll = -np.inf + + for i, x0 in enumerate(starts): + try: + result = minimize( + negative_log_likelihood, + x0=x0, + args=(y_t, y_lag, n_lags), + method="L-BFGS-B", + bounds=bounds, + ) + except Exception: + continue + + if np.isfinite(result.fun): + ll_val = log_likelihood_mle(result.x, y_t, y_lag, n_lags) + if np.isfinite(ll_val) and ll_val > best_ll: + best_ll = ll_val + best_result = result + if verbose: + print( + f"start={i}, success={result.success}, " + f"status={result.status}, loglike={ll_val:.2f}" + ) + + n_params = 6 + 2 * n_lags + + if best_result is None: + return { + "params": np.full(n_params, np.nan), + "se": np.full(n_params, np.nan), + "loglike": -np.inf, + "converged": False, + "optimizer_success": False, + "residuals": None, + "n_obs": int(y_t.shape[0]), + } + + params = best_result.x + se = opg_standard_errors(params, y_t, y_lag, n_lags) + resid = restricted_residuals(params, y_t, y_lag, n_lags) + ll_val = log_likelihood_mle(params, y_t, y_lag, n_lags) + + return { + "params": params, + "se": se, + "loglike": ll_val, + "converged": bool(np.isfinite(ll_val)), + "optimizer_success": bool(best_result.success), + "residuals": resid, + "n_obs": int(y_t.shape[0]), + } +``` + +下面的残差诊断总结了正态性和序列相关性检查 + +```{code-cell} ipython3 +def residual_diagnostics(resid): + """ + 计算基本残差诊断。 + """ + out = {} + + for i, label in enumerate(["consumption", "return"]): + jb_stat, jb_pval = stats.jarque_bera(resid[:, i]) + out[f"{label}_jb_stat"] = float(jb_stat) + out[f"{label}_jb_pval"] = float(jb_pval) + out[f"{label}_dw"] = float(durbin_watson(resid[:, i])) + + return out +``` + +最后,一个滞后循环包装器在不同滞后长度下运行 MLE 并将结果收集到 DataFrame 中 + +```{code-cell} ipython3 +def run_mle_by_lag( + data, + lags=(2, 4, 6), + verbose=False, +): + """ + 按滞后长度估计受限 MLE 模型。 + """ + rows = [] + fits = {} + + for lag in lags: + fit = estimate_mle(data, n_lags=lag, verbose=verbose) + fits[lag] = fit + + rows.append( + { + "NLAG": lag, + "α_hat": fit["params"][0], + "se_α": fit["se"][0], + "β_hat": fit["params"][1], + "se_β": fit["se"][1], + "loglike": fit["loglike"], + "n_obs": fit["n_obs"], + } + ) + + table = pd.DataFrame(rows).set_index("NLAG") + return table, fits +``` + +### 模拟 + +在将似然应用于真实数据之前,我们先验证它能从受限系统生成的模拟数据中恢复已知参数。 + +对于 `n_lags = 1`,参数向量为 + +```{math} +\theta = (\alpha,\ \beta,\ \sigma_x,\ \sigma_r,\ \sigma_{xr},\ \mu_x,\ a_{x,1},\ a_{r,1}), +``` + +其中最后两项是 $X_t$ 的第一行回归中 $X_{t-1}$ 和 $R_{t-1}$ 的系数。 + +更一般地,对于 `n_lags = p`,我们按顺序 $[a_{x,1}, a_{r,1}, \ldots, a_{x,p}, a_{r,p}]$ 打包 `a_lags`,因此完整参数向量的长度为 $6 + 2p$。 + +协方差参数 $(\sigma_x, \sigma_r, \sigma_{xr})$ 描述了 $(X_t, R_t)$ 的简化式冲击:如果 $\boldsymbol{\varepsilon}_t = (\varepsilon_{x,t}, \varepsilon_{r,t})^\top \sim N(0, \boldsymbol{\Sigma}_\varepsilon)$,那么 $\boldsymbol{\Sigma}_\varepsilon = \begin{bmatrix}\sigma_x^2 & \sigma_{xr}\\ \sigma_{xr} & \sigma_r^2\end{bmatrix}$。 + +受限系统的创新为 $\mathbf{V}_t = \mathbf{A}_0 \boldsymbol{\varepsilon}_t$,因此其协方差为 $\boldsymbol{\Sigma}_V = \mathbf{A}_0 \boldsymbol{\Sigma}_\varepsilon \mathbf{A}_0^\top$,这正是进入似然的量。 + +在模拟递归中,我们抽取 $\mathbf{V}_t \sim N(0, \boldsymbol{\Sigma}_V)$ 并向前计算 $\mathbf{Y}_t = \mathbf{A}_0^{-1}(\mathbf{A}_1(L)\mathbf{Y}_{t-1} + \boldsymbol{\mu} + \mathbf{V}_t)$。 + +下表将真实参数与来自大型模拟样本的 MLE 估计进行比较 + +```{code-cell} ipython3 +α_true = -1.00 +β_true = 0.993 +σ_x_true = 0.015 +σ_r_true = 0.020 +cov_xr_true = 0.0001 +μ_x_true = 0.002 +a_x1_true = 0.40 +a_r1_true = 0.10 + +true_params = np.array( + [ + α_true, + β_true, + σ_x_true, + σ_r_true, + cov_xr_true, + μ_x_true, + a_x1_true, + a_r1_true, + ] +) + +sim_mle_data = simulate_restricted_var( + params=true_params, + n_obs=50000, + n_lags=1, + burn_in=5000, + seed=0, +) + +fit_sim = estimate_mle(sim_mle_data, n_lags=1, verbose=False) +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +sim_results = pd.DataFrame({ + "true": true_params[:2], + "estimate": fit_sim["params"][:2], + "se": fit_sim["se"][:2], +}, index=[r"α", r"β"]) +sim_results[r"t\ (H_0{:}\ \text{true})"] = ( + (sim_results["estimate"] - sim_results["true"]) / sim_results["se"] +) +display_table(sim_results, fmt={ + "true": "{:.4f}", "estimate": "{:.4f}", "se": "{:.6f}", r"t\ (H_0{:}\ \text{true})": "{:.2f}", +}) +``` + +点估计接近真实参数,而针对"真实值正确"这一原假设的 t 统计量在数量级上很小,与抽样变异一致。 + + +## 偏好参数与似然比检验 + +受限系统通过跨方程限制嵌入了偏好参数。 + +参数 $\alpha$ 将回报的可预测变动与消费增长的可预测变动联系起来。 + +在该模型下,回报方程对滞后变量的依赖完全由 $-\alpha$ 乘以消费方程的滞后系数所决定。 + +参数 $\beta$ 通过 $-\log\beta - \sigma_U^2/2$ 移动回报方程的截距。 + +{cite:t}`hansen1983stochastic` 通过将受限系统与在相同样本上估计的无限制二元 VAR 进行比较来检验这些限制。 + +如果欧拉方程施加的限制是正确的,那么受限模型的拟合应该几乎和无限制模型一样好。 + +标准检验是似然比统计量 + +```{math} +:label: hs83-lr-test + +LR = 2(\ell_u - \ell_r) \Rightarrow \chi^2_d, +``` + +其中 $\ell_u$ 和 $\ell_r$ 是无限制和受限模型的最大化对数似然,$d$ 是自由参数数量的差值。 + +两个似然必须在相同的有效样本上求值,LR 分布才有效。 + +{cite:t}`hansen1983stochastic` 报告称,对于价值加权的总股票回报,$\chi^2$ 检验统计量几乎没有提供反对模型的证据。 + +在下面的表格中,我们报告 `chi2.cdf(LR, df)`(对应于 HS 在括号中所报告的内容)和通常的右尾 `p(LR) = 1 - chi2.cdf` + +```{code-cell} ipython3 +def likelihood_ratio_test( + fit_restricted, + fit_unrestricted, + df_diff, +): + """ + 使用 LR 检验比较嵌套设定。 + """ + if not (fit_restricted["converged"] and fit_unrestricted["converged"]): + return {"lr_stat": np.nan, "p_value": np.nan, "chi2_cdf": np.nan} + if fit_restricted.get("n_obs") != fit_unrestricted.get("n_obs"): + return {"lr_stat": np.nan, "p_value": np.nan, "chi2_cdf": np.nan} + + lr_stat = 2.0 * (fit_unrestricted["loglike"] - fit_restricted["loglike"]) + chi2_cdf = stats.chi2.cdf(lr_stat, df=df_diff) + p_value = 1.0 - chi2_cdf + return { + "lr_stat": float(lr_stat), + "p_value": float(p_value), + "chi2_cdf": float(chi2_cdf), + } +``` + +无限制基准是关于 $\mathbf{Y}_t = (X_t, R_t)^\top$ 的高斯 VAR,其中两个方程中所有滞后项的系数都是自由的。 + +```{code-cell} ipython3 +def estimate_unrestricted_var(data, n_lags): + """ + 为 Y_t = [X_t, R_t] 估计一个无限制高斯 VAR。 + """ + y_t, y_lag = build_lagged_data(data, n_lags) + n_obs = y_t.shape[0] + x = np.column_stack([np.ones(n_obs), y_lag]) + coef = np.linalg.lstsq(x, y_t, rcond=None)[0] + resid = y_t - x @ coef + Σ = resid.T @ resid / n_obs + + try: + chol = cholesky(Σ, lower=True) + log_det = 2.0 * np.sum(np.log(np.diag(chol) + 1e-16)) + std_resid = solve_triangular(chol, resid.T, lower=True).T + quad_form = np.sum(std_resid ** 2) + except (LinAlgError, ValueError): + return { + "coef": coef, + "Σ": np.full((2, 2), np.nan), + "residuals": resid, + "loglike": -np.inf, + "converged": False, + "n_obs": int(n_obs), + } + + d = y_t.shape[1] + loglike = float(-0.5 * n_obs * d * np.log(2.0 * np.pi) + - 0.5 * n_obs * log_det - 0.5 * quad_form) + + return { + "coef": coef, + "Σ": Σ, + "residuals": resid, + "loglike": loglike, + "converged": True, + "n_obs": int(n_obs), + } +``` + +```{code-cell} ipython3 +def run_unrestricted_var_by_lag(data, lags=(2, 4, 6)): + """ + 按滞后长度估计无限制 VAR 模型。 + """ + rows = [] + fits = {} + + for lag in lags: + fit = estimate_unrestricted_var(data, n_lags=lag) + fits[lag] = fit + rows.append( + { + "NLAG": lag, + "loglike": fit["loglike"], + "n_obs": fit["n_obs"], + } + ) + + table = pd.DataFrame(rows).set_index("NLAG") + return table, fits +``` + +以下函数在每个滞后长度下计算 LR 统计量,复现了 {cite:t}`hansen1983stochastic` 中表 1 的检验策略。 + +```{code-cell} ipython3 +def restricted_vs_unrestricted_lr(mle_fits, unrestricted_fits, lags=(2, 4, 6)): + """ + 计算受限模型与无限制 VAR 的 LR 检验。 + """ + rows = [] + + for lag in lags: + fit_r = mle_fits[lag] + fit_u = unrestricted_fits[lag] + df_diff = (2 * (1 + 2 * lag) + 3) - (6 + 2 * lag) + lr = likelihood_ratio_test(fit_restricted=fit_r, fit_unrestricted=fit_u, df_diff=df_diff) + rows.append( + { + "NLAG": lag, + "lr_stat": lr["lr_stat"], + "p_value": lr["p_value"], + "chi2_cdf": lr["chi2_cdf"], + "df": df_diff, + "T": fit_r.get("n_obs", np.nan), + } + ) + + return pd.DataFrame(rows).set_index("NLAG") +``` + +## 可预测性与 R 平方限制 + +{cite:t}`hansen1983stochastic` 的第二部分强调了受限系统对回报可预测性的一个含义。 + +由 {eq}`hs83-cond-mean` 和 {eq}`hs83-x-forecast`,对数回报的可预测成分为 + +```{math} +:label: hs83-predictable-return + +E(R_t \mid \psi_{t-1}) = -\alpha\, E(X_t \mid \psi_{t-1}) - \log\beta - \frac{\sigma_U^2}{2}. +``` + +由于可预测回报是可预测消费增长的线性函数,可预测回报成分的方差恰好等于 $\alpha^2$ 乘以可预测消费增长成分的方差: + +```{math} +:label: hs83-var-pred + +\operatorname{Var}[E(R_t \mid \psi_{t-1})] = \alpha^2 \operatorname{Var}[E(X_t \mid \psi_{t-1})]. +``` + +{cite:t}`hansen1983stochastic` 推导出回报投影到 $\psi_{t-1}$ 上所隐含的 $R^2$: + +```{math} +:label: hs83-r2 + +R_R^2 = \frac{\alpha^2 \operatorname{Var}[E(X_t \mid \psi_{t-1})]}{\operatorname{Var}(R_t \mid \psi_{t-1}) + \alpha^2 \operatorname{Var}[E(X_t \mid \psi_{t-1})]}. +``` + +如果 $\alpha = 0$(风险中性),那么 $R_R^2 = 0$,资产回报不可预测。 + +如果 $\alpha = -1$(对数效用),那么 $R_t - X_t$ 不可预测,因此回报和消费增长共享相同的可预测成分。 + +更一般地,只要不可预测回报成分的方差 $\operatorname{Var}(R_t \mid \psi_{t-1})$ 相对于可预测方差较大,回报的 $R_R^2$ 就会很小,而这正是股票回报的情形。 + +下面的函数报告: +- 由欧拉方程隐含的限制方的可预测方差项,以及 +- 来自无限制 VAR 的 $R_X^2$ 和 $R_R^2$。 + +```{code-cell} ipython3 +def predictability_metrics(data, restricted_fit, unrestricted_fit, n_lags): + """ + 计算可预测成分度量和无限制 VAR 的 R^2 值。 + """ + y_t, y_lag = build_lagged_data(data, n_lags) + parsed = unpack_parameters(restricted_fit["params"], n_lags) + α = float(parsed["α"]) + β = float(parsed["β"]) + σ_x = float(parsed["σ_x"]) + σ_r = float(parsed["σ_r"]) + cov_xr = float(parsed["cov_xr"]) + μ_x = float(parsed["μ_x"]) + a_lags = np.asarray(parsed["a_lags"]) + + pred_x = y_lag @ a_lags + μ_x + σ_u2 = α ** 2 * σ_x ** 2 + σ_r ** 2 + 2.0 * α * cov_xr + pred_r = -α * pred_x - np.log(β) - 0.5 * σ_u2 + + x = y_t[:, 0] + r = y_t[:, 1] + resid_x = x - pred_x + resid_r = r - pred_r + + r2_x = 1.0 - np.var(resid_x) / np.var(x) + r2_r = 1.0 - np.var(resid_r) / np.var(r) + + if unrestricted_fit["converged"] and unrestricted_fit.get("coef") is not None: + n_obs = y_t.shape[0] + x_u = np.column_stack([np.ones(n_obs), y_lag]) + pred_u = x_u @ unrestricted_fit["coef"] + resid_u = y_t - pred_u + var_x = np.var(y_t[:, 0]) + var_r = np.var(y_t[:, 1]) + r2_x_unres = np.nan if var_x <= 0.0 else 1.0 - np.var(resid_u[:, 0]) / var_x + r2_r_unres = np.nan if var_r <= 0.0 else 1.0 - np.var(resid_u[:, 1]) / var_r + else: + r2_x_unres = np.nan + r2_r_unres = np.nan + + return { + "alpha_hat": α, + "var_pred_x": float(np.var(pred_x)), + "var_pred_r": float(np.var(pred_r)), + "alpha2_var_pred_x": float(α ** 2 * np.var(pred_x)), + "r2_x_restricted": float(r2_x), + "r2_r_restricted": float(r2_r), + "r2_x_unrestricted": float(r2_x_unres), + "r2_r_unrestricted": float(r2_r_unres), + "T": int(y_t.shape[0]), + } +``` + +## 回报差异检验 + +{cite:t}`hansen1983stochastic` 还提出了基于不同资产间对数回报差异的检验。 + +由 {eq}`hs83-cond-mean`,资产 $i$ 对数回报的条件均值为 $E_{t-1}[R_{it}] = -\alpha\, E_{t-1}[X_t] - \log\beta - \sigma_i^2/2$。 + +$-\alpha\, E_{t-1}[X_t] - \log\beta$ 这一项对所有资产都相同,因此它在差异中被抵消: + +$$ +E_{t-1}[R_{it} - R_{jt}] = \frac{\sigma_j^2 - \sigma_i^2}{2}, +$$ + +这是一个不依赖于 $(t-1)$ 时刻信息的常数。 + +因此,如果模型正确,回报差异应该是不可预测的,无论 $\alpha$ 和 $\beta$ 取何值。 + +这些检验避免了测量消费的需要,代价是失去了识别 $\alpha$ 和 $\beta$ 的能力。 + +{cite:t}`hansen1983stochastic` 报告称,对于具有多种股票回报的模型,回报差异限制被强烈拒绝,即使消除了消费测量问题,也提供了大量反对 CRRA-对数正态设定的证据。 + +下面的代码是对这一逻辑在模拟数据上的说明。 + +复现论文的实证回报差异表格需要估计超出本讲座范围的多资产系统 + +```{code-cell} ipython3 +def simulate_multi_asset_nominal_returns( + n_obs, + n_assets=3, + α_true=-1.0, + β_true=0.993, + seed=0, +): + """ + 模拟满足 E_t[beta * exp(alpha X) * r_i] = 1 的对数名义回报。 + """ + if n_assets < 2: + raise ValueError("n_assets must be at least 2.") + + rng = np.random.default_rng(seed) + x = np.empty(n_obs) + x[0] = 0.001 + for t in range(1, n_obs): + x[t] = 0.001 + 0.4 * (x[t - 1] - 0.001) + 0.006 * rng.standard_normal() + + sigmas = np.linspace(0.03, 0.06, n_assets) + eps = rng.standard_normal((n_obs, n_assets)) * sigmas + log_returns = -np.log(β_true) - α_true * x[:, None] + eps \ + - 0.5 * sigmas[None, :] ** 2 + return x, log_returns + + +def return_difference_test(log_returns, n_lags=2): + """ + 检验成对对数回报差异的可预测性。 + """ + if log_returns.ndim != 2 or log_returns.shape[1] < 2: + raise ValueError("log_returns must be T x m with m >= 2.") + if log_returns.shape[0] <= n_lags + 1: + raise ValueError("Sample size must exceed n_lags + 1.") + + t_obs, n_assets = log_returns.shape + pairs = list(combinations(range(n_assets), 2)) + n_obs = t_obs - n_lags - 1 + z = np.empty((n_obs, 1 + n_assets * n_lags)) + z[:, 0] = 1.0 + + for j in range(n_lags): + z[:, 1 + j * n_assets : 1 + (j + 1) * n_assets] = log_returns[ + n_lags - j : t_obs - 1 - j, : + ] + + rows = [] + for i, j in pairs: + y = log_returns[n_lags + 1 :, i] - log_returns[n_lags + 1 :, j] + coef = np.linalg.lstsq(z, y, rcond=None)[0] + resid = y - z @ coef + sigma2 = float((resid @ resid) / max(1, n_obs - z.shape[1])) + cov = sigma2 * np.linalg.pinv(z.T @ z) + slopes = coef[1:] + cov_slopes = cov[1:, 1:] + stat = float(slopes @ np.linalg.pinv(cov_slopes) @ slopes) + p_value = float(1.0 - stats.chi2.cdf(stat, df=slopes.shape[0])) + rows.append( + { + "pair": f"{i+1}-{j+1}", + "wald_chi2": stat, + "p_value": p_value, + "mean_spread": float(np.mean(y)), + } + ) + + return pd.DataFrame(rows).set_index("pair") +``` + +我们在具有 $m = 3$ 种资产的模拟数据上运行 `return_difference_test`,给出 $\binom{3}{2} = 3$ 对。 + +对于每一对,该函数将回报价差回归到一个常数和所有资产回报的 `n_lags` 个滞后上,然后使用 Wald $\chi^2$ 统计量检验斜率系数是否联合为零 + +```{code-cell} ipython3 +_, sim_log_returns = simulate_multi_asset_nominal_returns( + n_obs=1500, + n_assets=3, + α_true=-1.0, + β_true=0.993, + seed=0, +) + +spread_test = return_difference_test(sim_log_returns, n_lags=2) +spread_pretty = spread_test.rename(columns={ + "wald_chi2": r"\chi^2", "p_value": "p", "mean_spread": r"\overline{\Delta R}", +}) +display_table(spread_pretty, fmt={ + r"\chi^2": "{:.3f}", + "p": "{:.3f}", + r"\overline{\Delta R}": "{:.5f}", +}) +``` + +较大的 $p$ 值证实了在此模拟中回报差异是不可预测的,正如当 $\alpha = -1$ 时模型所预测的那样。 + +## 实证 MLE 估计 + +现在我们将 {cite:t}`hansen1983stochastic` 的最大似然估计器应用于真实数据。 + + +### 数据 + +本讲座和配套讲座 {doc}`hansen_singleton_1982` 使用相同的数据构造。 + +{cite:t}`hansen1982generalized` 和 {cite:t}`hansen1983stochastic` 使用了来自 CRSP 的 1959:2 至 1978:12 期间的月度人均实际消费(非耐用品)和股票回报数据。 + +为了与论文保持一致,我们将默认样本设为 1959:2--1978:12。 + +你可以传入不同的 `start` 和 `end` 日期来研究后续时期。 + +本讲座从 Ken French 数据库(`F-F_Research_Data_Factors`)中提取股票市场和一个月期国库券回报,并将总名义回报构造为市场的 `1 + (Mkt-RF + RF)/100` 和国库券的 `1 + RF/100`。 + +`Mkt-RF` 是所有 CRSP 公司的价值加权回报减去无风险利率,`RF` 是一个月期国库券回报(详情请参阅[此处](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html))。 + +虽然 Hansen-Singleton 使用 CRSP 价值加权 NYSE 回报,但我们使用 Ken French 市场因子作为最接近的开放获取替代方案。 + +消费序列由非耐用品消费(`ND`)与非耐用品平减指数构造而成。 + +下面的隐藏单元格加载了一个封装好的月度回报和消费序列数据集。这些数据由位于 [`_static/lecture_specific/hansen_singleton_1983/make_data.py`](https://github.com/QuantEcon/lecture-python.myst/blob/main/lectures/_static/lecture_specific/hansen_singleton_1983/make_data.py) 的维护脚本从 [FRED](https://fred.stlouisfed.org/) 和 [Ken French](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html) 数据库构建而成,并在此直接从 GitHub 读取。 + +```{code-cell} ipython3 +:tags: [hide-cell] + +DATA_URL = ( + "https://github.com/QuantEcon/lecture-python.myst/raw/refs/heads/main/" + "lectures/_static/lecture_specific/hansen_singleton_1983/" + "hansen_singleton_1983_data.csv" +) + +# 读取一次封装的快照;load_hs_monthly_data 只是对它进行切片。 +_data = pd.read_csv(DATA_URL, index_col=0, parse_dates=True) + + +def load_hs_monthly_data(start="1959-02-01", end="1978-12-01"): + """ + 加载本讲座使用的月度序列:总实际市场回报、 + 总消费增长、总消费通胀、人均实际 + 消费和总实际国库券回报。 + + 这些数据是由位于 + ``_static/lecture_specific/hansen_singleton_1983/make_data.py`` 的维护脚本构建的封装快照, + 该脚本从 FRED 和 Ken French 数据库构建它们。 + """ + start = pd.Timestamp(start).to_period("M").to_timestamp("M") + end = pd.Timestamp(end).to_period("M").to_timestamp("M") + return _data.loc[start:end].copy() + + +def get_estimation_data( + start="1959-02-01", + end="1978-12-01", +): + """ + 使用观测数据返回 (dataframe, array)。 + """ + frame = load_hs_monthly_data(start=start, end=end) + data = frame[["gross_real_return", "gross_cons_growth"]].to_numpy() + return frame, data + + +def get_tbill_estimation_data( + start="1959-02-01", + end="1978-12-01", +): + """ + 使用国库券数据返回 (dataframe, array)。 + """ + frame = load_hs_monthly_data(start=start, end=end) + data = frame[["gross_real_tbill", "gross_cons_growth"]].to_numpy() + return frame, data +``` + +### MLE 估计与可预测性总结 + +有了数据,我们就可以运行 MLE 估计并计算可预测性总结。 + +当假设正确时,对数正态性使 MLE 变得易于处理。 + +然而,正如 {cite:t}`hansen1983stochastic` 所强调的,$\alpha$ 的估计伴随着相对较大的标准误,仅凭总量月度数据无法期望对风险规避进行精确推断。 + +```{code-cell} ipython3 +lags = (2, 4, 6) + +emp_frame, emp_data = get_estimation_data() +``` + +下表报告按滞后长度分列的 $\hat\alpha$ 和 $\hat\beta$ 的受限 MLE 估计 + +```{code-cell} ipython3 +emp_log_data = to_mle_array(emp_data) +mle_table, mle_fits = run_mle_by_lag( + emp_log_data, lags=lags, verbose=False +) +mle_pretty = mle_table.rename(columns={ + "α_hat": r"\hat{\alpha}", "se_α": r"\mathrm{se}(\hat{\alpha})", + "β_hat": r"\hat{\beta}", "se_β": r"\mathrm{se}(\hat{\beta})", + "loglike": "logL", "n_obs": "T", +}) +display_table(mle_pretty, fmt={ + r"\hat{\alpha}": "{:.4f}", r"\mathrm{se}(\hat{\alpha})": "{:.4f}", + r"\hat{\beta}": "{:.4f}", r"\mathrm{se}(\hat{\beta})": "{:.4f}", + "logL": "{:.1f}", "T": "{:.0f}", +}) +``` + +该表报告了上面代码单元格所用样本按滞后长度分列的 $\hat\alpha$ 和 $\hat\beta$。 + +作为对比,{cite:t}`hansen1983stochastic` 报告了对于价值加权回报与非耐用品消费的 $\hat\alpha$ 值在 $-0.32$ 到 $-1.25$ 之间(标准误在 $0.65$ 到 $0.83$ 之间)。 + +我们的数字落在这些范围内。 + +以风险规避单位表示,这对应于 $-\hat\alpha$ 在 $0.32$ 到 $1.25$ 之间。 + +我们现在计算可预测性总结 + +```{code-cell} ipython3 +unres_table, unres_fits = run_unrestricted_var_by_lag( + emp_log_data, + lags=lags, +) +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +pred_rows = [] +for lag in lags: + metrics = predictability_metrics( + emp_log_data, + restricted_fit=mle_fits[lag], + unrestricted_fit=unres_fits[lag], + n_lags=lag, + ) + pred_rows.append({"NLAG": lag, **metrics}) + +pred_df = pd.DataFrame(pred_rows).set_index("NLAG") +pred_pretty = pred_df[ + [ + "alpha_hat", + "var_pred_x", + "var_pred_r", + "alpha2_var_pred_x", + "r2_x_unrestricted", + "r2_r_unrestricted", + "T", + ] +].rename(columns={ + "alpha_hat": r"\hat{\alpha}", + "var_pred_x": r"\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])", + "var_pred_r": r"\mathrm{Var}(\hat E[R_t\mid\psi_{t-1}])", + "alpha2_var_pred_x": r"\hat{\alpha}^2\,\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])", + "r2_x_unrestricted": r"R_X^2", + "r2_r_unrestricted": r"R_R^2", + "T": "T", +}) +display_table(pred_pretty, fmt={ + r"\hat{\alpha}": "{:.4f}", + r"\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])": "{:.6f}", + r"\mathrm{Var}(\hat E[R_t\mid\psi_{t-1}])": "{:.6f}", + r"\hat{\alpha}^2\,\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])": "{:.6f}", + r"R_X^2": "{:.4f}", + r"R_R^2": "{:.4f}", + "T": "{:.0f}", +}) +``` + +如果限制 {eq}`hs83-var-pred` 成立,那么列 $\hat\alpha^2 \operatorname{Var}(\hat E[X_t \mid \psi_{t-1}])$ 应该等于 $\operatorname{Var}(\hat E[R_t \mid \psi_{t-1}])$。 + +列 $R_X^2$ 和 $R_R^2$ 符合论文的惯例,即报告来自无限制 VAR 投影的值。 + +在 {cite:t}`hansen1983stochastic` 中,即使 $R_X^2$ 不可忽略,$R_R^2$ 也很小($0.02$ 到 $0.06$):大部分股票回报变动都是不可预测的。 + +我们的估计显示了相同的模式。 + +我们现在通过将受限系统与无限制 VAR 进行比较来检验欧拉方程限制。 + +```{code-cell} ipython3 +lr_hs83 = restricted_vs_unrestricted_lr(mle_fits, unres_fits, lags=lags) +lr_pretty = lr_hs83.rename(columns={ + "lr_stat": "LR", + "chi2_cdf": "chi2.cdf(LR,df)", + "p_value": "p(LR)", + "df": "df", + "T": "T", +}) +display_table(lr_pretty, fmt={ + "LR": "{:.3f}", + "chi2.cdf(LR,df)": "{:.3f}", + "p(LR)": "{:.3f}", + "df": "{:.0f}", + "T": "{:.0f}", +}) + +sig_level = 0.05 +rejected_lags = [int(lag) for lag in lr_hs83.index if lr_hs83.loc[lag, "p_value"] < sig_level] +not_rejected_lags = [int(lag) for lag in lr_hs83.index if lr_hs83.loc[lag, "p_value"] >= sig_level] +print(f"Not rejected at 5%: {not_rejected_lags if not_rejected_lags else 'none'}") +``` + +LR 检验没有对价值加权回报拒绝模型,与 {cite:t}`hansen1983stochastic` 一致。 + +### 国库券估计 + +现在我们用 1 个月期国库券回报代替股票回报来重复估计。 + +{cite:t}`hansen1983stochastic` 发现,对于国库券,模型被强烈拒绝(他们论文的表 4)。 + +由于名义无风险的国库券回报比股票回报可预测得多,比例限制更有约束力,LR 检验有更大的能力来检测违反 + +```{code-cell} ipython3 +tbill_frame, tbill_data = get_tbill_estimation_data() +``` + +下表报告按滞后长度分列的国库券回报的受限 MLE 估计。 + +```{code-cell} ipython3 +tbill_log_data = to_mle_array(tbill_data) +tbill_mle_table, tbill_mle_fits = run_mle_by_lag( + tbill_log_data, lags=lags, verbose=False +) +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +tbill_mle_pretty = tbill_mle_table.rename(columns={ + "α_hat": r"\hat{\alpha}", "se_α": r"\mathrm{se}(\hat{\alpha})", + "β_hat": r"\hat{\beta}", "se_β": r"\mathrm{se}(\hat{\beta})", + "loglike": "logL", "n_obs": "T", +}) +display_table(tbill_mle_pretty, fmt={ + r"\hat{\alpha}": "{:.4f}", r"\mathrm{se}(\hat{\alpha})": "{:.4f}", + r"\hat{\beta}": "{:.4f}", r"\mathrm{se}(\hat{\beta})": "{:.4f}", + "logL": "{:.1f}", "T": "{:.0f}", +}) +``` + +下面的 LR 检验仍然是论文中主要的设定检查 + +```{code-cell} ipython3 +tbill_unres_table, tbill_unres_fits = run_unrestricted_var_by_lag( + tbill_log_data, + lags=lags, +) + +tbill_unres_pretty = tbill_unres_table.rename(columns={"loglike": "logL", "n_obs": "T"}) +display_table(tbill_unres_pretty, fmt={ + "logL": "{:.1f}", "T": "{:.0f}", +}) +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +tbill_pred_rows = [] +for lag in lags: + metrics = predictability_metrics( + tbill_log_data, + restricted_fit=tbill_mle_fits[lag], + unrestricted_fit=tbill_unres_fits[lag], + n_lags=lag, + ) + tbill_pred_rows.append({"NLAG": lag, **metrics}) + +tbill_pred_df = pd.DataFrame(tbill_pred_rows).set_index("NLAG") +tbill_pred_pretty = tbill_pred_df[ + [ + "alpha_hat", + "var_pred_x", + "var_pred_r", + "alpha2_var_pred_x", + "r2_x_unrestricted", + "r2_r_unrestricted", + "T", + ] +].rename(columns={ + "alpha_hat": r"\hat{\alpha}", + "var_pred_x": r"\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])", + "var_pred_r": r"\mathrm{Var}(\hat E[R_t\mid\psi_{t-1}])", + "alpha2_var_pred_x": r"\hat{\alpha}^2\,\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])", + "r2_x_unrestricted": r"R_X^2", + "r2_r_unrestricted": r"R_R^2", + "T": "T", +}) +display_table(tbill_pred_pretty, fmt={ + r"\hat{\alpha}": "{:.4f}", + r"\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])": "{:.6f}", + r"\mathrm{Var}(\hat E[R_t\mid\psi_{t-1}])": "{:.6f}", + r"\hat{\alpha}^2\,\mathrm{Var}(\hat E[X_t\mid\psi_{t-1}])": "{:.6f}", + r"R_X^2": "{:.4f}", + r"R_R^2": "{:.4f}", + "T": "{:.0f}", +}) +``` + +下表报告了国库券模型的似然比检验。 + +```{code-cell} ipython3 +tbill_lr = restricted_vs_unrestricted_lr(tbill_mle_fits, tbill_unres_fits, lags=lags) +``` + +```{code-cell} ipython3 +:tags: [hide-input] +tbill_lr_pretty = tbill_lr.rename(columns={ + "lr_stat": "LR", + "chi2_cdf": "chi2.cdf(LR,df)", + "p_value": "p(LR)", + "df": "df", + "T": "T", +}) +display_table(tbill_lr_pretty, fmt={ + "LR": "{:.3f}", + "chi2.cdf(LR,df)": "{:.3f}", + "p(LR)": "{:.3f}", + "df": "{:.0f}", + "T": "{:.0f}", +}) + +tbill_rejected_lags = [int(lag) for lag in tbill_lr.index if tbill_lr.loc[lag, "p_value"] < 0.05] +print(f"T-bill model rejected at 5% for lags: {tbill_rejected_lags if tbill_rejected_lags else 'none'}") +``` + +{cite:t}`hansen1983stochastic` 在其 1959--1978 样本中发现了相同的定性模式:国库券模型被拒绝的程度远比价值加权股票回报模型强烈。 + +为什么 LR 检验没有对股票拒绝模型? + +正如我们之前所暗示的,一个原因可能是当回报可预测性较小时(反映在股票的低 $R_R^2$ 上)检验的能力有限。 + +当总股票回报几乎不可预测时,几乎没有可预测变动来构成约束。 + +## 残差诊断 + +作为最后的检查,让我们检查受限模型的残差路径、直方图和诊断统计量,以评估正态性和序列独立性假设是否成立。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 受限模型残差诊断 + name: fig-hs83-residual-diagnostics +--- +diag_lag = 2 +diag_fit = mle_fits[diag_lag] +resid = diag_fit["residuals"] + +if diag_fit["converged"] and resid is not None: + fig, axes = plt.subplots(2, 2, figsize=(12, 8)) + axes[0, 0].plot(resid[:, 0], lw=2) + axes[0, 0].axhline(0.0, color="black", lw=2) + axes[0, 0].set_ylabel("消费残差") + axes[0, 0].set_xlabel("观测值") + + axes[0, 1].plot(resid[:, 1], lw=2) + axes[0, 1].axhline(0.0, color="black", lw=2) + axes[0, 1].set_ylabel("回报残差") + axes[0, 1].set_xlabel("观测值") + + axes[1, 0].hist(resid[:, 0], bins=30, edgecolor="white") + axes[1, 0].set_xlabel("消费残差") + axes[1, 0].set_ylabel("计数") + + axes[1, 1].hist(resid[:, 1], bins=30, edgecolor="white") + axes[1, 1].set_xlabel("回报残差") + axes[1, 1].set_ylabel("计数") + plt.tight_layout() + plt.show() +``` + +下表报告了受限模型残差的 Jarque-Bera 正态性检验和 Durbin-Watson 序列相关性统计量。 + +```{code-cell} ipython3 +if diag_fit["converged"] and resid is not None: + diag = residual_diagnostics(resid) + diag_df = pd.DataFrame({ + "JB stat": [diag["consumption_jb_stat"], diag["return_jb_stat"]], + "JB p-val": [diag["consumption_jb_pval"], diag["return_jb_pval"]], + "DW": [diag["consumption_dw"], diag["return_dw"]], + }, index=pd.Index(["consumption", "return"], name="series")) + display_table(diag_df, fmt={ + "JB stat": "{:.2f}", "JB p-val": "{:.4f}", "DW": "{:.3f}", + }) +``` + +残差时间序列图揭示了波动率聚集的时期,而直方图显示出偏离钟形曲线并具有更肥的尾部。 + +两个序列的 Jarque-Bera 统计量都很大,拒绝了作为似然基础的正态性假设。 + +两个序列的 Durbin-Watson 统计量都接近 2,因此序列相关性不是一个问题。 + +这促成了配套讲座 {doc}`hansen_singleton_1982`,在其中我们讨论了 GMM 如何避免正态性假设。 + +## 与股权溢价之谜的联系 + +我们的估计复现了 {cite:t}`MehraPrescott1985` 后来所称的**股权溢价之谜**的模式。 + +- *估计的风险规避较低:*上表中估计的 $\hat\alpha$ 值(因此风险规避 $-\hat\alpha$)与 {cite:t}`hansen1983stochastic` 中的相似,他们报告 $\hat\alpha$ 在 $-0.32$ 到 $-1.25$ 之间。 + +- *极小的回报可预测性:*无限制 VAR 的 $R_R^2$ 值与 {cite:t}`hansen1983stochastic` 中 0.02 到 0.06 的范围相当——股票回报的可预测成分相对于不可预测成分很小。 + +- *对国库券的强烈拒绝:*对于名义无风险的国库券回报,欧拉方程限制被决定性地拒绝,正如 {cite:t}`hansen1983stochastic` 的表 4 一样。 + +当回报序列更可预测时,限制更有约束力(国库券的无限制 VAR $R_R^2$ 比股票的大得多),这是 {cite:t}`Weil_1989` 后来所称的**无风险利率之谜**的先兆。 + +{cite:t}`MehraPrescott1985` 提出了密切相关的发现。 + +在一个具有 CRRA 效用的基于消费的模型的校准版本中,他们表明,对于范围在 0 到 10 之间的相对风险规避 $\gamma_{\text{MP}}$,模型无法同时匹配: + +1. 约 6\% 的平均年度股权溢价, +2. 约 1\% 的平均年度无风险利率。 + +匹配股权溢价需要 $\gamma_{\text{MP}}$ 远高于 10,而匹配无风险利率则需要较低的 $\gamma_{\text{MP}}$。 + +同样的困难出现在我们的估计中:隐含的风险规避 $-\hat\alpha$ 太低,无法产生大的股权溢价。 + +## 另一种方法 + +配套讲座 {doc}`hansen_singleton_1982` 描述了一篇密切相关的论文,其中 Hansen 和 Singleton 对回报和消费增长的联合分布做了较少的设定。 + +他们构建了一个不完整的概率模型,止步于不指定似然函数。 + +为了推进,他们使用了广义矩估计法(GMM)估计器来估计出现在欧拉方程中的关键参数。 \ No newline at end of file diff --git a/lectures/ifp_discrete.md b/lectures/ifp_discrete.md new file mode 100644 index 0000000..8d46f2b --- /dev/null +++ b/lectures/ifp_discrete.md @@ -0,0 +1,530 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 收入波动问题 I:离散化与 VFI + headings: + Overview: 概述 + Set Up: 设置 + Code: 代码 + Code::Value function iteration: 值函数迭代 + Code::Timing: 计时 + Code::Asset Dynamics: 资产动态 + Exercises: 练习 +--- + +# 收入波动问题 I:离散化与 VFI + +```{include} _admonition/gpu.md +``` + +## 概述 + + +在本讲中,我们研究一个无限存活消费者的最优储蓄问题——即 {cite}`Ljungqvist2012` 第 1.3 节中描述的"共同祖先"。 + +这个储蓄问题通常被称为**收入波动问题**或**家庭问题**。 + +它是许多代表性宏观经济模型的一个基本子问题 + +* {cite}`Aiyagari1994` +* {cite}`Huggett1993` +* 等等 + +它与 {doc}`os_stochastic` 中的决策问题相关,但在一些重要方面有所不同。 + +例如, + +1. 该主体的选择问题包含一个可加性收入项,这会导致一个偶尔起约束作用的约束。 +2. 影响预算约束的冲击是相关的,这迫使我们跟踪一个额外的状态变量。 + +我们将从一个相对基础的模型版本开始,通过传统的离散化 + 值函数迭代来求解它。 + +尽管这种方法并不是最快或最高效的,但它非常稳健和灵活。 + +例如,如果我们突然决定加入 [Epstein--Zin 偏好](https://en.wikipedia.org/wiki/Epstein%E2%80%93Zin_preferences),或者将普通的条件期望修改为分位数,该技术仍然能够很好地工作。 + +```{note} +对于我们将使用的其他一些方法(例如内生网格法),情况就并非如此。 + +这是计算与分析中的一条普遍规律——虽然我们通常可以通过利用结构来设计更快的算法,但这些新算法通常不那么稳健。 + +它们之所以不那么稳健,恰恰是因为它们利用了更多的结构——这意味着它们不可避免地更容易受到变化的影响。 +``` + +除了 Anaconda 之外,本讲还需要以下库: + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install quantecon jax +``` + +我们将使用以下导入: + +```{code-cell} ipython3 +import quantecon as qe +import jax +import jax.numpy as jnp +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'] +from typing import NamedTuple +from time import time +``` + + +我们将使用 64 位浮点数以获得额外的精度。 + +```{code-cell} ipython3 +jax.config.update("jax_enable_x64", True) +``` + +## 设置 + +我们研究一个家庭,它选择一个状态相依的消费计划 $\{c_t\}_{t \geq 0}$ 以最大化 + +$$ +\mathbb{E} \, \sum_{t=0}^{\infty} \beta^t u(c_t) +$$ + +约束条件为 + +$$ + a_{t+1} + c_t \leq R a_t + y_t +$$ + +其中 + +* $c_t$ 是消费且 $c_t \geq 0$, +* $a_t$ 是资产且 $a_t \geq 0$, +* $R = 1 + r$ 是总回报率, +* $(y_t)_{t \geq 0}$ 是劳动收入,取值于某个有限集 $\mathsf Y$。 + +我们在下面假设劳动收入动态遵循一个离散化的 AR(1)过程。 + +我们设 $\mathsf S := \mathbb{R}_+ \times \mathsf Y$,它表示状态空间。 + +**值函数** $V \colon \mathsf S \to \mathbb{R}$ 定义为 + +```{math} +:label: eqvfs + +V(a, y) := \max \, \mathbb{E} +\left\{ +\sum_{t=0}^{\infty} \beta^t u(c_t) +\right\} +``` + +其中最大化是在给定 $(a_0, y_0) = (a, y)$ 时所有可行的消费序列上进行的。 + +贝尔曼方程为 + +$$ + v(a, y) = \max_{0 \leq a' \leq Ra + y} + \left\{ + u(Ra + y - a') + β \sum_{y'} v(a', y') Q(y, y') + \right\} +$$ + +其中 + +$$ + u(c) = \frac{c^{1-\gamma}}{1-\gamma} +$$ + +在代码中我们使用函数 + +$$ + B((a, y), a', v) = u(Ra + y - a') + β \sum_{y'} v(a', y') Q(y, y'). +$$ + +来封装贝尔曼方程的右侧。 + + + +## 代码 + +以下代码定义了一个 `NamedTuple` 来存储模型参数和网格。 + +(prgm:create-consumption-model)= + +```{code-cell} ipython3 +class Model(NamedTuple): + β: float # 贴现因子 + R: float # 总利率 + γ: float # CRRA 参数 + a_grid: jnp.ndarray # 资产网格 + y_grid: jnp.ndarray # 收入网格 + Q: jnp.ndarray # 收入的马尔可夫矩阵 + + +def create_consumption_model( + R=1.01, # 总利率 + β=0.98, # 贴现因子 + γ=2, # CRRA 参数 + a_min=0.01, # 最小资产 + a_max=10.0, # 最大资产 + a_size=150, # 网格大小 + ρ=0.9, ν=0.1, y_size=100 # 收入参数 + ): + """ + 创建消费-储蓄模型的一个实例。 + + """ + a_grid = jnp.linspace(a_min, a_max, a_size) + mc = qe.tauchen(n=y_size, rho=ρ, sigma=ν) + y_grid, Q = jnp.exp(mc.state_values), jax.device_put(mc.P) + return Model(β, R, γ, a_grid, y_grid, Q) +``` + +现在我们定义贝尔曼方程的右侧。 + +我们将使用一种类似于 Matlab 和 NumPy 的向量化编码风格(避免所有循环)。 + +我们邀请你在练习中探索一种基于 `jax.vmap` 的替代风格。 + +```{code-cell} ipython3 +@jax.jit +def B(v, model): + """ + 贝尔曼方程右侧(最大化之前)的向量化版本,它是一个表示 + + B(a, y, a′) = u(Ra + y - a′) + β Σ_y′ v(a′, y′) Q(y, y′) + + 的 3D 数组,涵盖所有 (a, y, a′)。 + """ + + # 解包 + β, R, γ, a_grid, y_grid, Q = model + a_size, y_size = len(a_grid), len(y_grid) + + # 将当前奖励 r(a, y, ap) 计算为数组 r[i, j, ip] + a = jnp.reshape(a_grid, (a_size, 1, 1)) # a[i] -> a[i, j, ip] + y = jnp.reshape(y_grid, (1, y_size, 1)) # z[j] -> z[i, j, ip] + ap = jnp.reshape(a_grid, (1, 1, a_size)) # ap[ip] -> ap[i, j, ip] + c = R * a + y - ap + + # 计算所有 (a, y, ap) 组合下的延续奖励 + v = jnp.reshape(v, (1, 1, a_size, y_size)) # v[ip, jp] -> v[i, j, ip, jp] + Q = jnp.reshape(Q, (1, y_size, 1, y_size)) # Q[j, jp] -> Q[i, j, ip, jp] + EV = jnp.sum(v * Q, axis=3) # 对最后一个索引 jp 求和 + + # 计算贝尔曼方程的右侧 + return jnp.where(c > 0, c**(1-γ)/(1-γ) + β * EV, -jnp.inf) +``` + +一些读者可能会担心我们正在创建高维数组,从而导致效率低下。 + +能否通过更仔细的向量化来避免它们? + +事实上这并不必要:这个函数将由 JAX 进行 JIT 编译,而 JIT 编译器将优化编译后的代码以最小化内存使用。 + +贝尔曼算子 $T$ 可以通过以下方式实现 + +```{code-cell} ipython3 +@jax.jit +def T(v, model): + "贝尔曼算子。" + return jnp.max(B(v, model), axis=2) +``` + +下一个函数在给定 $v$ 的情况下计算一个 $v$-贪婪策略(即最大化贝尔曼方程右侧的策略)。 + +```{code-cell} ipython3 +@jax.jit +def get_greedy(v, model): + "计算 v-贪婪策略,以一组索引的形式返回。" + return jnp.argmax(B(v, model), axis=2) +``` + + +### 值函数迭代 + +现在我们定义一个实现 VFI 的求解器。 + +首先,我们使用标准的 Python 循环编写一个简单的版本。 + +```{code-cell} ipython3 +def value_function_iteration_python(model, tol=1e-5, max_iter=10_000): + """ + 使用 Python 循环通过逐次近似实现 VFI。 + """ + v = jnp.zeros((len(model.a_grid), len(model.y_grid))) + error = tol + 1 + k = 0 + + while error > tol and k < max_iter: + v_new = T(v, model) + error = jnp.max(jnp.abs(v_new - v)) + v = v_new + k += 1 + + return v, get_greedy(v, model) +``` + +接下来我们编写一个使用 `jax.lax.while_loop` 的版本。 + +```{code-cell} ipython3 +@jax.jit +def value_function_iteration(model, tol=1e-5, max_iter=10_000): + """ + 使用逐次近似实现 VFI。 + """ + def body_fun(k_v_err): + k, v, error = k_v_err + v_new = T(v, model) + error = jnp.max(jnp.abs(v_new - v)) + return k + 1, v_new, error + + def cond_fun(k_v_err): + k, v, error = k_v_err + return jnp.logical_and(error > tol, k < max_iter) + + v_init = jnp.zeros((len(model.a_grid), len(model.y_grid))) + k, v_star, error = jax.lax.while_loop(cond_fun, body_fun, + (1, v_init, tol + 1)) + return v_star, get_greedy(v_star, model) +``` + +### 计时 + +让我们创建一个实例并比较两种实现。 + +```{code-cell} ipython3 +model = create_consumption_model() +``` + +首先让我们对 Python 版本计时。 + +```{code-cell} ipython3 +print("Starting VFI using Python loop.") +start = time() +v_star_python, σ_star_python = value_function_iteration_python(model) +python_time = time() - start +print(f"VFI completed in {python_time} seconds.") +``` + +现在让我们对 `jax.lax.while_loop` 版本计时。 + +```{code-cell} ipython3 +print("Starting VFI using jax.lax.while_loop.") +start = time() +v_star_jax, σ_star_jax = value_function_iteration(model) +v_star_jax.block_until_ready() +jax_with_compile = time() - start +print(f"VFI completed in {jax_with_compile} seconds.") +``` + +让我们再次运行它以消除编译时间。 + +```{code-cell} ipython3 +start = time() +v_star_jax, σ_star_jax = value_function_iteration(model) +v_star_jax.block_until_ready() +jax_without_compile = time() - start +print(f"VFI completed in {jax_without_compile} seconds.") +``` + +让我们检查这两种实现是否产生相同的结果。 + +```{code-cell} ipython3 +print(f"Values match: {jnp.allclose(v_star_python, v_star_jax)}") +print(f"Policies match: {jnp.allclose(σ_star_python, σ_star_jax)}") +``` + +这是使用 `jax.lax.while_loop` 带来的加速。 + +```{code-cell} ipython3 +print(f"Relative speed = {python_time / jax_without_compile:.2f}") +``` + + +### 资产动态 + +为了理解长期行为,让我们考察最优策略下的资产积累动态。 + +以下 45 度图展示了资产如何随时间演变: + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +# 绘制第一个和最后一个收入状态的资产积累 +for j, label in zip([0, -1], ['低收入', '高收入']): + # 获取每个当前资产水平的下一期资产 + a_next = model.a_grid[σ_star_jax[:, j]] + ax.plot(model.a_grid, a_next, label=label) + +# 添加 45 度线 +ax.plot(model.a_grid, model.a_grid, 'k--', linewidth=0.5) +ax.set(xlabel='当前资产', ylabel='下一期资产') +ax.legend() +plt.show() +``` + +该图展示了每个收入状态的资产积累规则。 + +虚线是 45 度线,表示 $a_{t+1} = a_t$ 的点。 + +我们看到: + +* 对于低收入水平,资产往往会减少(位于 45 度线下方的点) +* 对于高收入水平,在低资产水平时资产往往会增加 +* 该动态表明会收敛到一个平稳分布 + + +## 练习 + +```{exercise} +:label: ifp_ex1 + +在本练习中,我们探索一种使用 `jax.vmap` 实现值函数迭代的替代方法。 + +对于这个简单的最优储蓄问题,直接向量化相对容易。 + +特别地,将贝尔曼方程的右侧表示为一个数组是很直接的,该数组存储了在每个状态和控制下对该函数的求值。 + +然而,对于更复杂的模型,直接向量化可能要困难得多。 + +出于这个原因,掌握另一种实现快速 JAX 实现的方法会很有帮助。 + +你的任务是实现一个版本,它: + +1. 将贝尔曼算子的右侧写成关于单个状态和控制的函数,以及 +2. 在外部应用 `jax.vmap` 以实现并行化求解。 + +具体来说: + +1. 重写 `B`,使其接受对应于 `(a, y, a′)` 的索引 `(i, j, ip)`,并计算这些特定索引的贝尔曼方程。 +2. 依次使用 `jax.vmap` 对所有索引进行向量化(使用前面示例中展示的分阶段 vmap)。 +3. 使用向量化的 `B` 实现 `T_vmap` 和 `get_greedy_vmap` 函数。 +4. 使用 `jax.lax.while_loop` 实现 `value_iteration_vmap`。 +5. 测试你的实现是否产生与直接向量化方法相同的结果。 +6. 比较两种方法的执行时间。 +``` + +```{solution-start} ifp_ex1 +:class: dropdown +``` + +这是一个解决方案。 + +首先让我们重写 `B` 使其与单个索引一起工作: + +```{code-cell} ipython3 +def B(v, model, i, j, ip): + """ + 最大化之前贝尔曼方程的右侧,其形式为 + + B(a, y, a′) = u(Ra + y - a′) + β Σ_y′ v(a′, y′) Q(y, y′) + + 索引为 (i, j, ip) -> (a, y, a′)。 + """ + β, R, γ, a_grid, y_grid, Q = model + a, y, ap = a_grid[i], y_grid[j], a_grid[ip] + c = R * a + y - ap + EV = jnp.sum(v[ip, :] * Q[j, :]) + return jnp.where(c > 0, c**(1-γ)/(1-γ) + β * EV, -jnp.inf) +``` + +现在我们依次应用 `vmap` 来模拟嵌套循环。 + +```{code-cell} ipython3 +B_1 = jax.vmap(B, in_axes=(None, None, None, None, 0)) +B_2 = jax.vmap(B_1, in_axes=(None, None, None, 0, None)) +B_vmap = jax.vmap(B_2, in_axes=(None, None, 0, None, None)) +``` + +这是 `vmap` 情况下的贝尔曼算子和 `get_greedy` 函数。 + +```{code-cell} ipython3 +@jax.jit +def T_vmap(v, model): + "贝尔曼算子。" + a_indices = jnp.arange(len(model.a_grid)) + y_indices = jnp.arange(len(model.y_grid)) + B_values = B_vmap(v, model, a_indices, y_indices, a_indices) + return jnp.max(B_values, axis=-1) + +@jax.jit +def get_greedy_vmap(v, model): + "计算 v-贪婪策略,以一组索引的形式返回。" + a_indices = jnp.arange(len(model.a_grid)) + y_indices = jnp.arange(len(model.y_grid)) + B_values = B_vmap(v, model, a_indices, y_indices, a_indices) + return jnp.argmax(B_values, axis=-1) +``` + +这是迭代例程。 + +```{code-cell} ipython3 +def value_iteration_vmap(model, tol=1e-5, max_iter=10_000): + """ + 使用 vmap 和逐次近似实现 VFI。 + """ + def body_fun(k_v_err): + k, v, error = k_v_err + v_new = T_vmap(v, model) + error = jnp.max(jnp.abs(v_new - v)) + return k + 1, v_new, error + + def cond_fun(k_v_err): + k, v, error = k_v_err + return jnp.logical_and(error > tol, k < max_iter) + + v_init = jnp.zeros((len(model.a_grid), len(model.y_grid))) + k, v_star, error = jax.lax.while_loop(cond_fun, body_fun, + (1, v_init, tol + 1)) + return v_star, get_greedy_vmap(v_star, model) +``` + +让我们看看使用 `vmap` 方法求解模型需要多长时间。 + +```{code-cell} ipython3 +print("Starting VFI using vmap.") +start = time() +v_star_vmap, σ_star_vmap = value_iteration_vmap(model) +v_star_vmap.block_until_ready() +jax_vmap_with_compile = time() - start +print(f"VFI completed in {jax_vmap_with_compile} seconds.") +``` + +让我们再次运行它以消除编译时间。 + +```{code-cell} ipython3 +start = time() +v_star_vmap, σ_star_vmap = value_iteration_vmap(model) +v_star_vmap.block_until_ready() +jax_vmap_without_compile = time() - start +print(f"VFI completed in {jax_vmap_without_compile} seconds.") +``` + +我们需要确保得到相同的结果。 + +```{code-cell} ipython3 +print(jnp.allclose(v_star_vmap, v_star_jax)) +print(jnp.allclose(σ_star_vmap, σ_star_jax)) +``` + +这是与第一个 JAX 实现(使用直接向量化)的比较。 + +```{code-cell} ipython3 +print(f"Relative speed = {jax_without_compile / jax_vmap_without_compile}") +``` + +两个 JAX 版本的执行时间相对相近。 + +然而,正如上面所强调的,掌握第二种方法(即 `vmap` 方法)在面对具有更复杂贝尔曼方程的动态规划问题时会很有帮助。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/ifp_egm_transient_shocks.md b/lectures/ifp_egm_transient_shocks.md new file mode 100644 index 0000000..02447b1 --- /dev/null +++ b/lectures/ifp_egm_transient_shocks.md @@ -0,0 +1,1062 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.2 +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 收入波动问题 IV:暂时性收入冲击 + headings: + Overview: 概述 + The Household Problem: 家庭问题 + The Household Problem::Set-Up: 设置 + NumPy Implementation: NumPy 实现 + NumPy Implementation::Set Up: 设置 + NumPy Implementation::Solver: 求解器 + JAX Implementation: JAX 实现 + JAX Implementation::Set Up: 设置 + JAX Implementation::Solver: 求解器 + JAX Implementation::Test run: 测试运行 + JAX Implementation::Timing: 计时 + JAX Implementation::Dynamics: 动态 + Simulation: 模拟 + Wealth Inequality: 财富不平等 + Wealth Inequality::Measuring Inequality: 衡量不平等 + Wealth Inequality::Interest Rate and Inequality: 利率与不平等 + Exercises: 练习 +--- + +```{raw} jupyter + +``` + +# {index}`收入波动问题 IV:暂时性收入冲击 ` + +```{include} _admonition/gpu.md +``` + +```{contents} Contents +:depth: 2 +``` + + +## 概述 + +在本讲座中,我们通过向收入过程中添加暂时性冲击,继续扩展 {doc}`ifp_egm` 中的收入波动问题(IFP)。 + +除了 Anaconda 中已有的库之外,本讲座还需要以下库: + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install quantecon jax +``` + +我们还需要以下导入: + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import numba +from quantecon import MarkovChain +import jax +import jax.numpy as jnp +from typing import NamedTuple +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + + + +## 家庭问题 + +```{index} single: Optimal Savings; Problem +``` + +我们先简要概述模型,然后讨论如何求解它。 + +寻求对模型和 EGM 求解方法更深入讨论的读者可以查阅 {doc}`ifp_egm`。 + +### 设置 + +家庭选择一个状态依存的消费计划 $\{c_t\}_{t \geq 0}$,以最大化 + +$$ +\mathbb{E} \, \sum_{t=0}^{\infty} \beta^t u(c_t) +$$ + +约束条件为 + +```{math} +:label: eqst_ts + +a_{t+1} = R (a_t - c_t) + Y_{t+1} +\quad c_t \geq 0, +\quad a_t \geq 0 +\quad t = 0, 1, \ldots +``` + +符号定义和时间安排与 {doc}`ifp_egm` 中相同。 + +现在,非资本收入 $Y_t$ 由 $Y_t = y(Z_t, \eta_t)$ 给出,其中 + +* $\{Z_t\}$ 是一个外生状态过程(持久性成分), +* $\{\eta_t\}$ 是一个独立同分布冲击过程,以及 +* $y$ 是一个取值于 $\mathbb{R}_+$ 的函数。 + +在本讲座中,我们假设 $\eta_t \sim N(0, 1)$。 + +我们再次将 $\{Z_t\}$ 取为一个有限状态马尔可夫链,取值于 $\mathsf Z$,其马尔可夫矩阵为 $\Pi$。 + +冲击过程 $\{\eta_t\}$ 独立于 $\{Z_t\}$,代表暂时性收入波动。 + +除了之前的假设之外,我们假设 $y(z, \eta) = \exp(a_y \eta + z b_y)$,其中 $a_y, b_y$ 为正常数。 + +资产空间和状态空间保持不变,最优路径的定义也保持不变。 + +泛函欧拉方程的形式为 + + +```{math} +:label: eqeul1_ts + + (u' \circ \sigma) (a, z) + = \beta R \, \sum_{z'} \int (u' \circ \sigma) + [R (a - \sigma(a, z)) + y(z', \eta'), \, z'] \phi(\eta') d\eta' \, \Pi(z, z') +``` + +这里 + +* $(u' \circ \sigma)(s) := u'(\sigma(s))$, +* 撇号表示下一期状态(以及导数), +* $\phi$ 是冲击 $\eta_t$ 的密度(标准正态),以及 +* $\sigma$ 是未知函数。 + +等式 {eq}`eqeul1_ts` 在所有内部选择处成立,即 $\sigma(a, z) < a$。 + +我们的目标是找到 {eq}`eqeul1_ts` 的一个不动点 $\sigma$。 + +为此我们使用 EGM。 + +下面我们使用关系式 $a_t = c_t + s_t$ 和 $a_{t+1} = R s_t + Y_{t+1}$。 + +我们从一个外生储蓄网格 $s_0 < s_1 < \cdots < s_m$ 开始,其中 $s_0 = 0$。 + +我们固定策略函数 $\sigma$ 的当前猜测值。 + +对于每个 $i \geq 1$ 的外生储蓄水平 $s_i$ 和当前状态 $z_j$,我们设定 + + +```{math} +:label: cfequ_ts + + c_{ij} := (u')^{-1} + \left[ + \beta R \, \sum_{z'} \int + u' [ \sigma(R s_i + y(z', \eta'), z') ] \phi(\eta') d\eta' \, \Pi(z_j, z') + \right] +``` + +欧拉方程在此处成立,因为 $i \geq 1$ 意味着 $s_i > 0$,从而消费是内部的。 + +对于边界情形 $s_0 = 0$,我们设定 + +$$ + c_{0j} := 0 \quad \text{for all j} +$$ + +然后我们通过以下方式获得对应的内生当前资产网格 + +$$ + a_{ij} := c_{ij} + s_i. +$$ + +我们对策略函数的下一个猜测(记为 $K\sigma$)是插值点 + +$$ \{(a_{0j}, c_{0j}), \ldots, (a_{mj}, c_{mj})\} $$ + +对每个 $j$ 的线性插值。 + + +## NumPy 实现 + +在本节中,我们将编写一个 NumPy 版本的代码,目标仅在于清晰性,而非效率。 + +一旦它能够正常工作,我们将编写一个效率高得多的 JAX 版本,并检查是否得到相同的结果。 + +我们使用 CRRA 效用形式 + +$$ + u(c) = \frac{c^{1 - \gamma}} {1 - \gamma} +$$ + + +### 设置 + +这里我们构建一个名为 `IFPNumPy` 的类,用于存储模型的基本要素。 + +外生状态过程 $\{Z_t\}$ 默认为一个两状态马尔可夫链,转移矩阵为 $\Pi$。 + + +```{code-cell} ipython3 +class IFPNumPy(NamedTuple): + R: float # 总利率 R = 1 + r + β: float # 贴现因子 + γ: float # 偏好参数 + Π: np.ndarray # 外生冲击的马尔可夫矩阵 + z_grid: np.ndarray # Z_t 的马尔可夫状态值 + s: np.ndarray # 外生储蓄网格 + a_y: float # Y_t 的尺度参数 + b_y: float # Y_t 的加性参数 + η_draws: np.ndarray # 用于蒙特卡洛的创新 η 的抽样 + + +def create_ifp(r=0.01, + β=0.96, + γ=1.5, + Π=((0.6, 0.4), + (0.05, 0.95)), + z_grid=(-10.0, np.log(2.0)), + savings_grid_max=16, + savings_grid_size=50, + a_y=0.2, + b_y=0.5, + shock_draw_size=100, + seed=1234): + + np.random.seed(seed) + s = np.linspace(0, savings_grid_max, savings_grid_size) + Π, z_grid = np.array(Π), np.array(z_grid) + R = 1 + r + η_draws = np.random.randn(shock_draw_size) + assert R * β < 1, "Stability condition violated." + return IFPNumPy(R, β, γ, Π, z_grid, s, a_y, b_y, η_draws) +``` + +### 求解器 + +这里是算子 $K$,它将当前猜测值 $\sigma$ 转换为下一期猜测值 $K\sigma$。 + +在实践中,它接收 + +* 最优消费值 $c_{ij}$ 的猜测值,存储为 `c_vec` +* 以及一组对应的内生网格点 $a^e_{ij}$,存储为 `a_vec` + +这些通过对每个 $j$ 在 $i$ 上对 $(a^e_{ij}, c_{ij})$ 进行线性插值,转换为消费策略 $a \mapsto \sigma(a, z_j)$。 + +当我们计算 {eq}`cfequ_ts` 中的消费时,我们将对 $\eta'$ 使用蒙特卡洛方法,从而表达式变为 + +```{math} +:label: cfequmc + + c_{ij} := (u')^{-1} + \left[ + \beta R \, \sum_{z'} \frac{1}{m} \sum_{\ell=1}^m + u' [ \sigma(R s_i + y(z', \eta_{\ell}), z') ] \, \Pi(z_j, z') + \right] +``` + +其中每个 $\eta_{\ell}$ 都是一个标准正态抽样。 + + +```{code-cell} ipython3 +@numba.jit +def K_numpy( + c_in: np.ndarray, # σ 在内生网格上的初始猜测 + a_in: np.ndarray, # 初始内生网格 + ifp_numpy: IFPNumPy + ) -> np.ndarray: + """ + 使用内生网格方法(Endogenous Grid Method)的 IFP 模型的欧拉方程算子。 + + 该算子实现 EGM 算法的一次迭代,用于更新消费策略函数。 + + """ + R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp_numpy + n_a = len(s) + n_z = len(z_grid) + + # 效用函数 + def u_prime(c): + return c**(-γ) + + def u_prime_inv(c): + return c**(-1/γ) + + def y(z, η): + return np.exp(a_y * η + z * b_y) + + c_out = np.zeros_like(c_in) + + for i in range(1, n_a): # 从 1 开始,对应正储蓄水平 + for j in range(n_z): + + # 计算 Σ_z' ∫ u'(σ(R s_i + y(z', η'), z')) φ(η') dη' Π[z_j, z'] + expectation = 0.0 + for k in range(n_z): + z_prime = z_grid[k] + # 对 η 抽样进行积分(蒙特卡洛) + inner_sum = 0.0 + for η in η_draws: + # 计算下一期资产 + next_a = R * s[i] + y(z_prime, η) + # 插值得到 σ(R s_i + y(z', η), z') + next_c = np.interp(next_a, a_in[:, k], c_in[:, k]) + # 加入内部求和 + inner_sum += u_prime(next_c) + # 对 η 抽样取平均以近似积分 + # 当 z' = z_grid[k] 时的 ∫ u'(σ(R s_i + y(z', η'), z')) φ(η') dη' + inner_mean_k = (inner_sum / len(η_draws)) + # 用转移概率加权并加入期望 + expectation += inner_mean_k * Π[j, k] + + # 计算更新后的 c_{ij} 值 + c_out[i, j] = u_prime_inv(β * R * expectation) + + a_out = c_out + s[:, None] + + return c_out, a_out +``` + +为了求解该模型,我们使用一个简单的 while 循环。 + +```{code-cell} ipython3 +def solve_model_numpy( + ifp_numpy: IFPNumPy, + c_init: np.ndarray, + a_init: np.ndarray, + tol: float = 1e-5, + max_iter: int = 1_000 + ) -> np.ndarray: + """ + 使用带 EGM 的时间迭代求解模型。 + + """ + c_in, a_in = c_init, a_init + i = 0 + error = tol + 1 + + while error > tol and i < max_iter: + c_out, a_out = K_numpy(c_in, a_in, ifp_numpy) + error = np.max(np.abs(c_out - c_in)) + i = i + 1 + c_in, a_in = c_out, a_out + + return c_out, a_out +``` + +让我们对 EGM 代码进行实测。 + +```{code-cell} ipython3 +ifp_numpy = create_ifp() +R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp_numpy +# 初始条件 —— 家庭消费掉所有资产 +a_init = s[:, None] * np.ones(len(z_grid)) +c_init = a_init +# 从这些初始条件开始求解 +c_vec, a_vec = solve_model_numpy( + ifp_numpy, c_init, a_init +) +``` + +这里是每个 $z$ 状态下最优消费策略的图形 + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +ax.plot(a_vec[:, 0], c_vec[:, 0], label='bad state') +ax.plot(a_vec[:, 1], c_vec[:, 1], label='good state') +ax.set(xlabel='assets', ylabel='consumption') +ax.legend() +plt.show() +``` + + + +## JAX 实现 + +```{index} single: Optimal Savings; Programming Implementation +``` + +现在我们编写一个效率更高的 JAX 版本,它可以在 GPU 上运行。 + +### 设置 + +我们从一个名为 `IFP` 的类开始,用于存储模型的基本要素。 + +```{code-cell} ipython3 +class IFP(NamedTuple): + R: float # 总利率 R = 1 + r + β: float # 贴现因子 + γ: float # 偏好参数 + Π: jnp.ndarray # 外生冲击的马尔可夫矩阵 + z_grid: jnp.ndarray # Z_t 的马尔可夫状态值 + s: jnp.ndarray # 外生储蓄网格 + a_y: float # Y_t 的尺度参数 + b_y: float # Y_t 的加性参数 + η_draws: jnp.ndarray # 用于蒙特卡洛的创新 η 的抽样 + + +def create_ifp(r=0.01, + β=0.94, + γ=1.5, + Π=((0.6, 0.4), + (0.05, 0.95)), + z_grid=(-10.0, jnp.log(2.0)), + savings_grid_max=16, + savings_grid_size=50, + a_y=0.2, + b_y=0.5, + shock_draw_size=100, + seed=1234): + + key = jax.random.PRNGKey(seed) + s = jnp.linspace(0, savings_grid_max, savings_grid_size) + Π, z_grid = jnp.array(Π), jnp.array(z_grid) + R = 1 + r + η_draws = jax.random.normal(key, (shock_draw_size,)) + assert R * β < 1, "Stability condition violated." + return IFP(R, β, γ, Π, z_grid, s, a_y, b_y, η_draws) +``` + + +### 求解器 + +这里是算子 $K$,它将当前猜测值 $\sigma$ 转换为下一期猜测值 $K\sigma$。 + + +```{code-cell} ipython3 +def K( + c_in: jnp.ndarray, + a_in: jnp.ndarray, + ifp: IFP + ) -> jnp.ndarray: + """ + 使用内生网格方法(Endogenous Grid Method)的 IFP 模型的欧拉方程算子。 + + 该算子实现 EGM 算法的一次迭代,用于更新消费策略函数。 + + """ + R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp + n_a = len(s) + n_z = len(z_grid) + + # 效用函数 + def u_prime(c): + return c**(-γ) + + def u_prime_inv(c): + return c**(-1/γ) + + def y(z, η): + return jnp.exp(a_y * η + z * b_y) + + def compute_c(i, j): + " 当 i >= 1(内部选择)时计算 c_ij。 " + + def expected_mu(k): + " 近似 ∫ u'(σ(R s_i + y(z_k, η'), z_k)) φ(η') dη' " + + def compute_mu_at_eta(η): + " 计算 u'(σ(R * s_i + y(z_k, η), z_k)) " + next_a = R * s[i] + y(z_grid[k], η) + # 插值得到 σ(R * s_i + y(z_k, η), z_k) + next_c = jnp.interp(next_a, a_in[:, k], c_in[:, k]) + # 返回 u'(σ(R * s_i + y(z_k, η), z_k)) + return u_prime(next_c) + + # 对 η 抽样取平均以近似内部积分 + # ∫ u'(σ(R s_i + y(z_k, η'), z_k)) φ(η') dη' + all_draws = jax.vmap(compute_mu_at_eta)(η_draws) + return jnp.mean(all_draws) + + # 计算期望:Σ_k [∫ u'(σ(...)) φ(η) dη] * Π[j, k] + expectations = jax.vmap(expected_mu)(jnp.arange(n_z)) + expectation = jnp.sum(expectations * Π[j, :]) + # 求逆以得到 (s_i, z_j) 处的消费 c_ij + return u_prime_inv(β * R * expectation) + + # 为 vmap 计算所有 c_{ij} 设置索引网格 + i_grid = jnp.arange(1, n_a) + j_grid = jnp.arange(n_z) + + # 对每个 i 在 j 上使用 vmap + compute_c_i = jax.vmap(compute_c, in_axes=(None, 0)) + # 在 i 上使用 vmap + compute_c = jax.vmap(lambda i: compute_c_i(i, j_grid)) + # 计算 i >= 1 时的消费 + c_out_interior = compute_c(i_grid) # 形状:(n_a-1, n_z) + # 对于 i = 0,将消费设为 0 + c_out_boundary = jnp.zeros((1, n_z)) + + # 拼接边界和内部 + c_out = jnp.concatenate([c_out_boundary, c_out_interior], axis=0) + + # 计算内生资产网格:a^e_{ij} = c_{ij} + s_i + a_out = c_out + s[:, None] + + return c_out, a_out +``` + + +这里是一个使用该算子求解模型的 jit 加速迭代例程。 + +```{code-cell} ipython3 +@jax.jit +def solve_model( + ifp: IFP, + c_init: jnp.ndarray, # σ 在内生网格上的初始猜测 + a_init: jnp.ndarray, # 初始内生网格 + tol: float = 1e-5, + max_iter: int = 1000 + ) -> jnp.ndarray: + """ + 使用带 EGM 的时间迭代求解模型。 + + """ + + def condition(loop_state): + c_in, a_in, i, error = loop_state + return (error > tol) & (i < max_iter) + + def body(loop_state): + c_in, a_in, i, error = loop_state + c_out, a_out = K(c_in, a_in, ifp) + error = jnp.max(jnp.abs(c_out - c_in)) + i += 1 + return c_out, a_out, i, error + + i, error = 0, tol + 1 + initial_state = (c_init, a_init, i, error) + final_loop_state = jax.lax.while_loop(condition, body, initial_state) + c_out, a_out, i, error = final_loop_state + + return c_out, a_out +``` + + +### 测试运行 + +让我们对 EGM 代码进行实测。 + +```{code-cell} ipython3 +ifp = create_ifp() +R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp +# 设置家庭消费掉所有资产的初始条件 +a_init = s[:, None] * jnp.ones(len(z_grid)) +c_init = a_init +# 从这些初始条件开始求解 +c_vec_jax, a_vec_jax = solve_model(ifp, c_init, a_init) +``` + +为了验证我们 JAX 实现的正确性,让我们将其与之前开发的 NumPy 版本进行比较。 + +```{code-cell} ipython3 +# 比较结果 +max_c_diff = np.max(np.abs(np.array(c_vec) - c_vec_jax)) +max_ae_diff = np.max(np.abs(np.array(a_vec) - a_vec_jax)) + +print(f"Maximum difference in consumption policy: {max_c_diff:.2e}") +print(f"Maximum difference in asset grid: {max_ae_diff:.2e}") +``` + +这些数字确认了我们使用两种方法计算的策略本质上是相同的。 + +(剩余的差异主要是由于在相对较小的样本上不同的蒙特卡洛积分结果所致。) + +### 计时 + +现在让我们比较 NumPy 和 JAX 实现之间的执行时间。 + +```{code-cell} ipython3 +import time + +# 为 NumPy 版本设置初始条件 +s_np = np.array(s) +z_grid_np = np.array(z_grid) +a_init_np = s_np[:, None] * np.ones(len(z_grid_np)) +c_init_np = a_init_np.copy() + +# 为 JAX 版本设置初始条件 +a_init_jx = s[:, None] * jnp.ones(len(z_grid)) +c_init_jx = a_init_jx + +# 计时 NumPy 版本 +start = time.time() +c_vec_np, a_vec_np = solve_model_numpy(ifp_numpy, c_init_np, a_init_np) +numpy_time = time.time() - start + +# 计时 JAX 版本(包含编译) +start = time.time() +c_vec_jx, a_vec_jx = solve_model(ifp, c_init_jx, a_init_jx) +c_vec_jx.block_until_ready() +jax_time_with_compile = time.time() - start + +# 计时 JAX 版本(不含编译 —— 第二次运行) +start = time.time() +c_vec_jx, a_vec_jx = solve_model(ifp, c_init_jx, a_init_jx) +c_vec_jx.block_until_ready() +jax_time = time.time() - start + +print(f"NumPy time: {numpy_time:.4f} seconds") +print(f"JAX time (with compile): {jax_time_with_compile:.4f} seconds") +print(f"JAX time (without compile): {jax_time:.4f} seconds") +print(f"Speedup (NumPy/JAX): {numpy_time/jax_time:.2f}x") +``` + +由于 JIT 编译和 GPU/TPU 加速(如果可用),JAX 实现明显更快。 + +这里是每个 $z$ 状态下最优策略的图形 + +```{code-cell} ipython3 +fig, ax = plt.subplots() +ax.plot(a_vec[:, 0], c_vec[:, 0], label='bad state') +ax.plot(a_vec[:, 1], c_vec[:, 1], label='good state') +ax.set(xlabel='assets', ylabel='consumption') +ax.legend() +plt.show() +``` + +### 动态 + +为了初步理解在默认参数下家庭持有的长期资产水平,让我们观察 45 度图,它展示了在最优消费策略下资产的运动规律。 + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +def y(z, η): + return jnp.exp(a_y * η + z * b_y) + +def y_bar(k): + """ + 取 z = z_grid[k],计算以下的近似值 + + E_z Y' = Σ_{z'} ∫ y(z', η') φ(η') dη' Π[z, z'] + + 这是给定 Z_t = z 时 Y_{t+1} 的期望。 + """ + # 在给定的 z' 处近似 ∫ y(z', η') φ(η') dη' + def mean_y_at_z(z_prime): + return jnp.mean(y(z_prime, η_draws)) + # 对所有 z' 计算此积分 + y_means = jax.vmap(mean_y_at_z)(z_grid) + # 用转移概率加权并求和 + return jnp.sum(y_means * Π[k, :]) + +for k, label in zip((0, 1), ('low income', 'high income')): + # 在储蓄网格上对消费策略进行插值 + c_on_grid = jnp.interp(s, a_vec[:, k], c_vec[:, k]) + ax.plot(s, R * (s - c_on_grid) + y_bar(k) , label=label) + +ax.plot(s, s, 'k--') +ax.set(xlabel='current assets', ylabel='next period assets') + +ax.legend() +plt.show() +``` + +实线表示每个 $z$ 下资产的更新函数,即 + +$$ + a \mapsto R (a - \sigma^*(a, z)) + \bar{y}(z) +$$ + +其中 + +$$ + \bar{y}(z) := \sum_{z'} \frac{1}{m} \sum_{\ell = 1}^m y(z', \eta_{\ell}) \Pi(z, z') +$$ + +是给定当前状态 $z$ 时预期劳动收入的蒙特卡洛近似。 + +虚线是 45 度线。 + +该图表明,平均而言,动态将是稳定的 —— 即使在最高状态下资产也不会发散。 + +事实证明这确实成立:存在唯一的资产平稳分布。 + +* 详情请参见 {cite}`ma2020income` + +这个平稳分布代表了当家庭面临特异性冲击时,家庭间资产的长期分散情况。 + + + + +## 模拟 + +让我们回到默认模型,研究资产的平稳分布。 + +我们的计划是让大量家庭向前推进 $T$ 期,然后对资产的横截面分布绘制直方图。 + +设置 `num_households=50_000, T=500`。 + +首先我们编写一个函数,将单个家庭向前推进一段时间,并记录资产的最终值。 + +该函数接收一对解 `c_vec` 和 `a_vec`,将它们理解为代表与给定模型 `ifp` 相关联的最优策略 + +```{code-cell} ipython3 +@jax.jit +def simulate_household( + key, a_0, z_idx_0, c_vec, a_vec, ifp, T + ): + """ + 模拟单个家庭 T 期,以近似资产的平稳分布。 + + - key 是随机数生成器的状态 + - ifp 是 IFP 的一个实例 + - c_vec, a_vec 是 ifp 的最优消费策略、内生网格 + + """ + R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp + n_z = len(z_grid) + + def y(z, η): + return jnp.exp(a_y * η + z * b_y) + + # 为消费策略创建插值函数 + σ = lambda a, z_idx: jnp.interp(a, a_vec[:, z_idx], c_vec[:, z_idx]) + + # 向前模拟 T 期 + def update(t, state): + a, z_idx = state + # 从 Π[z, z'] 抽取下一个冲击 z' + current_key = jax.random.fold_in(key, 2*t) + z_next_idx = jax.random.choice(current_key, n_z, p=Π[z_idx]).astype(jnp.int32) + z_next = z_grid[z_next_idx] + # 抽取 η 冲击 + η_key = jax.random.fold_in(key, 2*t + 1) + η = jax.random.normal(η_key) + # 更新资产:a' = R * (a - c) + Y' + a_next = R * (a - σ(a, z_idx)) + y(z_next, η) + # 返回更新后的状态 + return a_next, z_next_idx + + initial_state = a_0, z_idx_0 + final_state = jax.lax.fori_loop(0, T, update, initial_state) + a_final, _ = final_state + return a_final +``` + +现在我们编写一个函数来并行模拟许多家庭。 + +```{code-cell} ipython3 +def compute_asset_stationary( + c_vec, a_vec, ifp, num_households=50_000, T=500, seed=1234 + ): + """ + 模拟 num_households 个家庭 T 期,以近似资产的平稳分布。 + + 返回资产持有的最终横截面。 + + - ifp 是 IFP 的一个实例 + - c_vec, a_vec 是最优消费策略和内生网格。 + + """ + R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp + n_z = len(z_grid) + + # 为消费策略创建插值函数 + # 在内生网格上进行插值 + σ = lambda a, z_idx: jnp.interp(a, a_vec[:, z_idx], c_vec[:, z_idx]) + + # 从 assets = savings_grid_max / 2 开始 + a_0_vector = jnp.full(num_households, s[-1] / 2) + # 初始化每个家庭的外生状态 + z_idx_0_vector = jnp.zeros(num_households).astype(jnp.int32) + + # 对许多家庭进行向量化 + key = jax.random.PRNGKey(seed) + keys = jax.random.split(key, num_households) + # 在 (key, a_0, z_idx_0) 上对 simulate_household 进行向量化 + sim_all_households = jax.vmap( + simulate_household, in_axes=(0, 0, 0, None, None, None, None) + ) + assets = sim_all_households(keys, a_0_vector, z_idx_0_vector, c_vec, a_vec, ifp, T) + + return np.array(assets) +``` + +现在我们调用该函数,生成资产分布并绘制其直方图: + +```{code-cell} ipython3 +ifp = create_ifp() +R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp +a_init = s[:, None] * jnp.ones(len(z_grid)) +c_init = a_init +c_vec, a_vec = solve_model(ifp, c_init, a_init) +assets = compute_asset_stationary(c_vec, a_vec, ifp) + +fig, ax = plt.subplots() +ax.hist(assets, bins=20, alpha=0.5, density=True) +ax.set(xlabel='assets', title="Cross-sectional distribution of wealth") +plt.show() +``` + +正如 {doc}`ifp_egm` 中的情况一样,财富分布看起来不太合理。 + +虽然我们至少获得了一个不平凡的右尾,但我们仍然存在左偏。 + + +## 财富不平等 + +让我们通过计算一些标准的衡量指标来观察财富不平等。 + +我们还将研究不平等如何随利率变化。 + + +### 衡量不平等 + +我们将计算两个常见的财富不平等衡量指标: + +1. **基尼系数**:一种不平等的度量,范围从 0(完全平等)到 1(完全不平等) +2. **前 1% 财富份额**:最富有的 1% 家庭持有的总财富的比例 + +这里是计算这些指标的函数: + +```{code-cell} ipython3 +def gini_coefficient(x): + """ + 计算数组 x 的基尼系数。 + + """ + x = jnp.asarray(x) + n = len(x) + x_sorted = jnp.sort(x) + # 计算基尼系数 + cumsum = jnp.cumsum(x_sorted) + a = (2 * jnp.sum((jnp.arange(1, n+1)) * x_sorted)) / (n * cumsum[-1]) + return a - (n + 1) / n + + +def top_share( + x: jnp.array, # 财富值数组 + p: float=0.01 # 顶部家庭的比例(前 1% 默认为 0.01) + ): + """ + 计算顶部 p 比例家庭持有的总财富份额。 + + """ + x = jnp.asarray(x) + x_sorted = jnp.sort(x) + # 前 p% 家庭的数量 + n_top = int(jnp.ceil(len(x) * p)) + # 前 p% 持有的财富 + wealth_top = jnp.sum(x_sorted[-n_top:]) + # 总财富 + wealth_total = jnp.sum(x_sorted) + return wealth_top / wealth_total +``` + +让我们为基准模拟计算这些指标: + +```{code-cell} ipython3 +gini = gini_coefficient(assets) +top1 = top_share(assets, p=0.01) + +print(f"Gini coefficient: {gini:.4f}") +print(f"Top 1% wealth share: {top1:.4f}") +``` + +这些数字相差甚远,至少对于像美国这样的国家而言! + +近期数据表明 + +* 美国的财富基尼系数约为 0.8 +* 前 1% 的财富份额超过 0.3 + +当然,我们并未花费太多精力去准确估计或校准我们的参数。 + +但实际上原因更深层 —— 具有这种结构的模型[将始终难以](https://arxiv.org/pdf/1807.08404)复现观测到的财富分布。 + +在{doc}`后面的讲座 ` 中,我们将看看是否能改进这些数字。 + + + +### 利率与不平等 + +让我们研究财富不平等如何随利率 $r$ 变化。 + +我们推测更高的利率将增加财富不平等,因为更富有的家庭从其资产回报中获益更多。 + +让我们进行实证研究: + +```{code-cell} ipython3 +# 对 8 个利率值进行测试 +M = 8 +r_vals = np.linspace(0, 0.05, M) + +gini_vals = [] +top1_vals = [] + +# 对每个 r 求解并模拟 +for r in r_vals: + print(f'Analyzing inequality at r = {r:.4f}') + ifp = create_ifp(r=r) + R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp + a_init = s[:, None] * jnp.ones(len(z_grid)) + c_init = a_init + c_vec, a_vec = solve_model(ifp, c_init, a_init) + assets = compute_asset_stationary( + c_vec, a_vec, ifp, num_households=50_000, T=500 + ) + gini = gini_coefficient(assets) + top1 = top_share(assets, p=0.01) + gini_vals.append(gini) + top1_vals.append(top1) + # 使用上次的解作为策略求解器的初始条件 + c_init = c_vec + a_init = a_vec +``` + +现在让我们可视化结果: + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +# 绘制基尼系数与利率的关系 +axes[0].plot(r_vals, gini_vals, 'o-') +axes[0].set_xlabel('interest rate $r$') +axes[0].set_ylabel('Gini coefficient') +axes[0].set_title('Wealth Inequality vs Interest Rate') +axes[0].grid(alpha=0.3) + +# 绘制前 1% 份额与利率的关系 +axes[1].plot(r_vals, top1_vals, 'o-', color='C1') +axes[1].set_xlabel('interest rate $r$') +axes[1].set_ylabel('top 1% wealth share') +axes[1].set_title('Top 1% Wealth Share vs Interest Rate') +axes[1].grid(alpha=0.3) + +plt.tight_layout() +plt.show() +``` + +结果表明,这两个不平等衡量指标都随利率增加而增加。 + +然而差异很小,而且我们无法在不违反稳定性约束的情况下将 $r$ 提高太多。 + +当然,改变利率无法产生我们在数据中看到的那种数字。 + + +## 练习 + +```{exercise} +:label: ifp_egm_ex1 + +让我们考虑利率如何影响消费。 + +* 让 `r` 遍历 `np.linspace(0, 0.016, 4)`。 +* 除 `r` 之外,将所有参数保持在其默认值。 +* 将收入冲击固定在最小值,绘制消费与资产的关系。 + +你的图形应该表明,对于这个模型,更高的利率会抑制消费(因为它们鼓励更多储蓄)。 +``` + +```{solution-start} ifp_egm_ex1 +:class: dropdown +``` + +这里是一个解法: + +```{code-cell} ipython3 +# 当 β=0.96 时,我们需要 R*β < 1,因此 r < 0.0416 +r_vals = np.linspace(0, 0.04, 4) + +fig, ax = plt.subplots() +for r_val in r_vals: + ifp = create_ifp(r=r_val) + R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp + a_init = s[:, None] * jnp.ones(len(z_grid)) + c_init = a_init + c_vec, a_vec = solve_model(ifp, c_init, a_init) + # 绘制策略 + ax.plot(a_vec[:, 0], c_vec[:, 0], label=f'$r = {r_val:.3f}$') + # 用上次的解开始下一轮 + c_init = c_vec + a_init = a_vec + +ax.set(xlabel='asset level', ylabel='consumption (low income)') +ax.legend() +plt.show() +``` + +```{solution-end} +``` + + + +```{exercise-start} +:label: ifp_egm_ex2 +``` + +接着练习 1,让我们看看储蓄和总资产持有量如何随利率变化 + +```{note} +{cite}`Ljungqvist2012` 第 18.6 节可作为本练习所讨论主题的更多背景资料参考。 +``` + +对于模型的给定参数化,资产平稳分布的均值可以解释为一个经济体中的总资本,该经济体拥有单位质量的*事前*相同的、面临特异性冲击的家庭。 + +你的任务是研究这个总资本衡量指标如何随利率变化。 + +直觉表明,更高的利率应该鼓励资本形成 —— 请验证这一点。 + +对于利率网格,使用 + +```{code-cell} ipython3 +M = 8 +r_vals = np.linspace(0, 0.05, M) +``` + +```{exercise-end} +``` + + +```{solution-start} ifp_egm_ex2 +:class: dropdown +``` + +这里是一个解法 + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +asset_mean = [] +for r in r_vals: + print(f'Solving model at r = {r}') + ifp = create_ifp(r=r) + R, β, γ, Π, z_grid, s, a_y, b_y, η_draws = ifp + a_init = s[:, None] * jnp.ones(len(z_grid)) + c_init = a_init + c_vec, a_vec = solve_model(ifp, c_init, a_init) + assets = compute_asset_stationary( + c_vec, a_vec, ifp, num_households=10_000, T=500 + ) + mean = np.mean(assets) + asset_mean.append(mean) + print(f' Mean assets: {mean:.4f}') + # 用上次的解开始下一轮 + c_init = c_vec + a_init = a_vec +ax.plot(r_vals, asset_mean) + +ax.set(xlabel='interest rate', ylabel='capital') + +plt.show() +``` + +正如预期的那样,总储蓄随利率增加而增加。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/ifp_opi.md b/lectures/ifp_opi.md new file mode 100644 index 0000000..74743d9 --- /dev/null +++ b/lectures/ifp_opi.md @@ -0,0 +1,488 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 收入波动问题 II:乐观策略迭代 + headings: + Overview: 概述 + Model and Primitives: 模型与基本要素 + Operators and Policies: 算子与策略 + Value Function Iteration: 值函数迭代 + Optimistic Policy Iteration: 乐观策略迭代 + Timing Comparison: 计时比较 + Exercises: 练习 +--- + +# 收入波动问题 II:乐观策略迭代 + +```{include} _admonition/gpu.md +``` + +## 概述 + +在 {doc}`ifp_discrete` 中,我们研究了收入波动问题,并使用值函数迭代(VFI)求解了它。 + +在本讲座中,我们将使用 **乐观策略迭代**(OPI)来求解同一个问题。这种方法非常通用,通常比 VFI 更快,而且只是略微复杂一些。 + +OPI 结合了值函数迭代和策略迭代两者的要素。 + +关于该算法的详细讨论可以在 [DP1](https://dp.quantecon.org) 中找到。 + +我们的目标是实现 OPI,并测试它对于收入波动问题是否能相较于标准 VFI 带来显著的速度提升。 + +除了 Anaconda 之外,本讲座还需要以下库: + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install quantecon jax +``` + +我们将使用以下导入: + +```{code-cell} ipython3 +import quantecon as qe +import jax +import jax.numpy as jnp +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'] +from typing import NamedTuple +from time import time +``` + + + +## 模型与基本要素 + +模型和参数与 {doc}`ifp_discrete` 中的相同。 + +为方便起见,我们在这里重复关键要素。 + +家庭的问题是最大化 + +$$ +\mathbb{E} \, \sum_{t=0}^{\infty} \beta^t u(c_t) +$$ + +约束条件为 + +$$ + a_{t+1} + c_t \leq R a_t + y_t +$$ + +其中 $u(c) = c^{1-\gamma}/(1-\gamma)$。 + +以下是模型结构: + +```{code-cell} ipython3 +class Model(NamedTuple): + β: float # 贴现因子 + R: float # 总利率 + γ: float # CRRA 参数 + a_grid: jnp.ndarray # 资产网格 + y_grid: jnp.ndarray # 收入网格 + Q: jnp.ndarray # 收入的马尔可夫矩阵 + + +def create_consumption_model( + R=1.01, # 总利率 + β=0.98, # 贴现因子 + γ=2, # CRRA 参数 + a_min=0.01, # 最小资产 + a_max=10.0, # 最大资产 + a_size=150, # 网格大小 + ρ=0.9, ν=0.1, y_size=100 # 收入参数 + ): + """ + Creates an instance of the consumption-savings model. + + """ + a_grid = jnp.linspace(a_min, a_max, a_size) + mc = qe.tauchen(n=y_size, rho=ρ, sigma=ν) + y_grid, Q = jnp.exp(mc.state_values), jax.device_put(mc.P) + return Model(β, R, γ, a_grid, y_grid, Q) +``` + +## 算子与策略 + +我们重复 {doc}`ifp_discrete` 中的一些函数。 + +以下是贝尔曼方程的右侧: + +```{code-cell} ipython3 +def B(v, model, i, j, ip): + """ + The right-hand side of the Bellman equation before maximization, which takes + the form + + B(a, y, a′) = u(Ra + y - a′) + β Σ_y′ v(a′, y′) Q(y, y′) + + The indices are (i, j, ip) -> (a, y, a′). + """ + β, R, γ, a_grid, y_grid, Q = model + a, y, ap = a_grid[i], y_grid[j], a_grid[ip] + c = R * a + y - ap + EV = jnp.sum(v[ip, :] * Q[j, :]) + return jnp.where(c > 0, c**(1-γ)/(1-γ) + β * EV, -jnp.inf) +``` + +现在我们依次应用 `vmap` 以在所有索引上进行向量化: + +```{code-cell} ipython3 +B_1 = jax.vmap(B, in_axes=(None, None, None, None, 0)) +B_2 = jax.vmap(B_1, in_axes=(None, None, None, 0, None)) +B_vmap = jax.vmap(B_2, in_axes=(None, None, 0, None, None)) +``` + +以下是贝尔曼算子: + +```{code-cell} ipython3 +def T(v, model): + "The Bellman operator." + a_indices = jnp.arange(len(model.a_grid)) + y_indices = jnp.arange(len(model.y_grid)) + B_values = B_vmap(v, model, a_indices, y_indices, a_indices) + return jnp.max(B_values, axis=-1) +``` + +以下是计算 $v$-贪婪策略的函数: + +```{code-cell} ipython3 +def get_greedy(v, model): + "Computes a v-greedy policy, returned as a set of indices." + a_indices = jnp.arange(len(model.a_grid)) + y_indices = jnp.arange(len(model.y_grid)) + B_values = B_vmap(v, model, a_indices, y_indices, a_indices) + return jnp.argmax(B_values, axis=-1) +``` + +现在我们定义策略算子 $T_\sigma$,它是固定策略 $\sigma$ 时的贝尔曼算子。 + +对于给定的策略 $\sigma$,策略算子定义为 + +$$ + (T_\sigma v)(a, y) = u(Ra + y - \sigma(a, y)) + \beta \sum_{y'} v(\sigma(a, y), y') Q(y, y') +$$ + +```{code-cell} ipython3 +def T_σ(v, σ, model, i, j): + """ + The σ-policy operator for indices (i, j) -> (a, y). + """ + β, R, γ, a_grid, y_grid, Q = model + + # 获取当前状态下的值 + a, y = a_grid[i], y_grid[j] + # 获取策略选择 + ap = a_grid[σ[i, j]] + + # 计算当前奖励 + c = R * a + y - ap + r = jnp.where(c > 0, c**(1-γ)/(1-γ), -jnp.inf) + + # 计算期望值 + EV = jnp.sum(v[σ[i, j], :] * Q[j, :]) + + return r + β * EV +``` + +应用 vmap 进行向量化: + +```{code-cell} ipython3 +T_σ_1 = jax.vmap(T_σ, in_axes=(None, None, None, None, 0)) +T_σ_vmap = jax.vmap(T_σ_1, in_axes=(None, None, None, 0, None)) + +def T_σ_vec(v, σ, model): + """Vectorized version of T_σ.""" + a_size, y_size = len(model.a_grid), len(model.y_grid) + a_indices = jnp.arange(a_size) + y_indices = jnp.arange(y_size) + return T_σ_vmap(v, σ, model, a_indices, y_indices) +``` + +现在我们需要一个函数将策略算子应用 m 次: + +```{code-cell} ipython3 +def iterate_policy_operator(σ, v, m, model): + """ + Apply the policy operator T_σ exactly m times to v. + """ + def update(i, v): + return T_σ_vec(v, σ, model) + + v = jax.lax.fori_loop(0, m, update, v) + return v +``` + +## 值函数迭代 + +作为比较,以下是来自 {doc}`ifp_discrete` 的 VFI: + +```{code-cell} ipython3 +@jax.jit +def value_function_iteration(model, tol=1e-5, max_iter=10_000): + """ + Implements VFI using successive approximation. + """ + def body_fun(k_v_err): + k, v, error = k_v_err + v_new = T(v, model) + error = jnp.max(jnp.abs(v_new - v)) + return k + 1, v_new, error + + def cond_fun(k_v_err): + k, v, error = k_v_err + return jnp.logical_and(error > tol, k < max_iter) + + v_init = jnp.zeros((len(model.a_grid), len(model.y_grid))) + k, v_star, error = jax.lax.while_loop(cond_fun, body_fun, + (1, v_init, tol + 1)) + return v_star, get_greedy(v_star, model) +``` + +## 乐观策略迭代 + +现在我们实现 OPI。 + +该算法在以下两步之间交替进行 + +1. 执行 $m$ 次策略算子迭代以更新值函数 +2. 基于更新后的值函数计算新的贪婪策略 + +```{code-cell} ipython3 +@jax.jit +def optimistic_policy_iteration(model, m=10, tol=1e-5, max_iter=10_000): + """ + Implements optimistic policy iteration with step size m. + + Parameters: + ----------- + model : Model + The consumption-savings model + m : int + Number of policy operator iterations per step + tol : float + Tolerance for convergence + max_iter : int + Maximum number of iterations + """ + v_init = jnp.zeros((len(model.a_grid), len(model.y_grid))) + + def condition_function(inputs): + i, v, error = inputs + return jnp.logical_and(error > tol, i < max_iter) + + def update(inputs): + i, v, error = inputs + last_v = v + σ = get_greedy(v, model) + v = iterate_policy_operator(σ, v, m, model) + error = jnp.max(jnp.abs(v - last_v)) + i += 1 + return i, v, error + + num_iter, v, error = jax.lax.while_loop(condition_function, + update, + (0, v_init, tol + 1)) + + return v, get_greedy(v, model) +``` + +## 计时比较 + +让我们创建一个模型并比较 VFI 和 OPI 的性能。 + +```{code-cell} ipython3 +model = create_consumption_model() +``` + +首先,让我们对 VFI 计时: + +```{code-cell} ipython3 +print("Starting VFI.") +start = time() +v_star_vfi, σ_star_vfi = value_function_iteration(model) +v_star_vfi.block_until_ready() +vfi_time_with_compile = time() - start +print(f"VFI completed in {vfi_time_with_compile:.2f} seconds.") +``` + +再次运行以消除编译时间: + +```{code-cell} ipython3 +start = time() +v_star_vfi, σ_star_vfi = value_function_iteration(model) +v_star_vfi.block_until_ready() +vfi_time = time() - start +print(f"VFI completed in {vfi_time:.2f} seconds.") +``` + +现在让我们用不同的 m 值对 OPI 计时: + +```{code-cell} ipython3 +print("Starting OPI with m=50.") +start = time() +v_star_opi, σ_star_opi = optimistic_policy_iteration(model, m=50) +v_star_opi.block_until_ready() +opi_time_with_compile = time() - start +print(f"OPI completed in {opi_time_with_compile:.2f} seconds.") +``` + +再次运行: + +```{code-cell} ipython3 +start = time() +v_star_opi, σ_star_opi = optimistic_policy_iteration(model, m=50) +v_star_opi.block_until_ready() +opi_time = time() - start +print(f"OPI completed in {opi_time:.2f} seconds.") +``` + +检查我们是否得到相同的结果: + +```{code-cell} ipython3 +print(f"Values match: {jnp.allclose(v_star_vfi, v_star_opi)}") +``` + +值函数相匹配,确认了两种算法收敛到相同的解。 + +让我们直观地比较两种策略下的资产动态: + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +# VFI 策略 +for j, label in zip([0, -1], ['低收入', '高收入']): + a_next_vfi = model.a_grid[σ_star_vfi[:, j]] + axes[0].plot(model.a_grid, a_next_vfi, label=label) +axes[0].plot(model.a_grid, model.a_grid, 'k--', linewidth=0.5, alpha=0.5) +axes[0].set(xlabel='当前资产', ylabel='下一期资产', title='VFI') +axes[0].legend() + +# OPI 策略 +for j, label in zip([0, -1], ['低收入', '高收入']): + a_next_opi = model.a_grid[σ_star_opi[:, j]] + axes[1].plot(model.a_grid, a_next_opi, label=label) +axes[1].plot(model.a_grid, model.a_grid, 'k--', linewidth=0.5, alpha=0.5) +axes[1].set(xlabel='当前资产', ylabel='下一期资产', title='OPI') +axes[1].legend() + +plt.tight_layout() +plt.show() +``` + +这两种策略在视觉上无法区分,确认了两种方法产生了相同的解。 + +以下是加速情况: + +```{code-cell} ipython3 +print(f"Speedup factor: {vfi_time / opi_time:.2f}") +``` + +让我们尝试不同的 m 值,看看它如何影响性能: + +```{code-cell} ipython3 +m_vals = [1, 5, 10, 25, 50, 100, 200, 400] +opi_times = [] + +for m in m_vals: + start = time() + v_star, σ_star = optimistic_policy_iteration(model, m=m) + v_star.block_until_ready() + elapsed = time() - start + opi_times.append(elapsed) + print(f"OPI with m={m:3d} completed in {elapsed:.2f} seconds.") +``` + +绘制结果: + +```{code-cell} ipython3 +fig, ax = plt.subplots() +ax.plot(m_vals, opi_times, 'o-', label='OPI') +ax.axhline(vfi_time, linestyle='--', color='red', label='VFI') +ax.set_xlabel('m (每次迭代的策略步数)') +ax.set_ylabel('时间(秒)') +ax.legend() +ax.set_title('OPI 执行时间与步长 m 的关系') +plt.show() +``` + +以下是结果的总结 + +* OPI 在很大范围的 $m$ 值上都优于 VFI。 + +* 对于非常大的 $m$,OPI 的性能开始下降,因为我们在迭代策略算子上花费了过多时间。 + + +## 练习 + +```{exercise} +:label: ifp_opi_ex1 + +OPI 所实现的速度提升对参数变化相当稳健。 + +请通过对收入过程的不同参数值($\rho$ 和 $\nu$)进行实验来确认这一点。 + +测量它们如何影响 VFI 与 OPI 的相对性能。 + +尝试: +* $\rho \in \{0.8, 0.9, 0.95\}$ +* $\nu \in \{0.05, 0.1, 0.2\}$ + +对于每种组合,计算加速因子(VFI 时间 / OPI 时间)并报告你的发现。 +``` + +```{solution-start} ifp_opi_ex1 +:class: dropdown +``` + +以下是一个解答: + +```{code-cell} ipython3 +ρ_vals = [0.8, 0.9, 0.95] +ν_vals = [0.05, 0.1, 0.2] + +results = [] + +for ρ in ρ_vals: + for ν in ν_vals: + print(f"\nTesting ρ={ρ}, ν={ν}") + + # 创建模型 + model = create_consumption_model(ρ=ρ, ν=ν) + + # 对 VFI 计时 + start = time() + v_vfi, σ_vfi = value_function_iteration(model) + v_vfi.block_until_ready() + vfi_t = time() - start + + # 对 OPI 计时 + start = time() + v_opi, σ_opi = optimistic_policy_iteration(model, m=10) + v_opi.block_until_ready() + opi_t = time() - start + + speedup = vfi_t / opi_t + results.append((ρ, ν, speedup)) + print(f" VFI: {vfi_t:.2f}s, OPI: {opi_t:.2f}s, Speedup: {speedup:.2f}x") + +# 打印总结 +print("\nSummary of speedup factors:") +for ρ, ν, speedup in results: + print(f"ρ={ρ}, ν={ν}: {speedup:.2f}x") +``` + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/information_market_equilibrium.md b/lectures/information_market_equilibrium.md new file mode 100644 index 0000000..152c407 --- /dev/null +++ b/lectures/information_market_equilibrium.md @@ -0,0 +1,1337 @@ +--- +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 +translation: + title: 信息与市场均衡 + headings: + Overview: 概述 + Setup: 设定 + Setup::Preferences, endowments, and the unknown state: 偏好、禀赋与未知状态 + Setup::The informed agent's problem: 知情代理人的问题 + Price revelation: 价格揭示 + Price revelation::Blackwell sufficiency: Blackwell 充分性 + Price revelation::Two interpretations: 两种解释 + Price revelation::Two interpretations::Insider trading in a stock market: 股票市场中的内幕交易 + Price revelation::Two interpretations::Price as a quality signal: 价格作为质量信号 + Invertibility and the elasticity of substitution: 可逆性与替代弹性 + Invertibility and the elasticity of substitution::The two-state first-order condition: 两状态一阶条件 + Invertibility and the elasticity of substitution::CES utility: CES 效用 + Invertibility and the elasticity of substitution::Equilibrium price as a function of the posterior: 均衡价格作为后验的函数 + Invertibility and the elasticity of substitution::Why monotonicity depends on $\sigma$: 为什么单调性取决于 $\sigma$ + Bayesian price expectations in a dynamic economy: 动态经济中的贝叶斯价格预期 + Bayesian price expectations in a dynamic economy::A stochastic exchange economy: 一个随机交换经济 + Bayesian price expectations in a dynamic economy::The identification problem: 识别问题 + Bayesian price expectations in a dynamic economy::Bayesian updating: 贝叶斯更新 + Bayesian price expectations in a dynamic economy::The convergence theorem: 收敛定理 + Simulating Bayesian learning from prices: 从价格中模拟贝叶斯学习 + Simulating Bayesian learning from prices::Price expectations vs. rational expectations: 价格预期 vs. 理性预期 + Simulating Bayesian learning from prices::Learning the reduced form without identifying the structure: 学到简约形式而不识别结构 + Exercises: 练习 +--- + +(information_market_equilibrium)= +```{raw} jupyter + +``` + +# 信息与市场均衡 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲研究关于**价格的信息作用**的两个问题,这两个问题由 {cite:t}`kihlstrom_mirman1975` 提出并回答。 + +1. *价格何时传递内部信息?* + - 一位知情的内部人观察到与未知世界状态相关的私有信号,并据此调整需求。 + - 均衡价格随之变动。 + - 在什么条件下,外部观察者可以从均衡价格*推断*出内部人的后验分布? + +2. *贝叶斯价格预期会收敛吗?* + - 在一个平稳的随机交换经济中,一位不知情的观察者利用市场价格的历史和贝叶斯法则来形成关于经济结构的信念,进而形成关于其所诱导的价格分布的信念。 + - 这些预期最终会与一位完全知情的观察者的预期一致吗? + +Kihlstrom 和 Mirman 的回答依赖于统计学中的两个经典思想: + +- **Blackwell 充分性**:如果知道随机变量 $\tilde{y}$ 就能给出 $\tilde{y}'$ 所包含的关于状态的所有信息,那么就称随机变量 $\tilde{y}$ 相对于某个未知状态对随机变量 $\tilde{y}'$ 是*充分的*。 +- **贝叶斯一致性**:随着样本增长,后验信念会排除那些隐含错误**价格分布**的模型,因此即使无法从价格中识别出结构,后验对真实**简约形式**的质量仍会收敛到一。 + +{cite:t}`kihlstrom_mirman1975` 的重要发现是: + +- 均衡价格能够传递内部信息,*当且仅当*从内部人后验分布到均衡价格的映射在信号实际可能产生的后验集合上是一一对应的。 + - 对于两状态的情形($S = 2$),当知情者的效用是位似的,且替代弹性处处小于一或处处大于一时,可逆性成立。 +- 在动态经济中,随着信息的累积,贝叶斯价格预期会收敛到**理性预期**,即使无法仅从价格中识别出深层结构。 + +```{note} +{cite:t}`kihlstrom_mirman1975` 以细致的计量经济学家所采用的方式使用了"简约形式"和"结构"模型这两个术语。 + +简约形式模型和结构模型成对出现。 + +对于每一个结构或结构模型,都存在一个简约形式,或者一组对应于不同可能回归的简约形式。 +``` + +本讲的组织结构如下。 + +1. 建立静态两商品模型并定义均衡。 +2. 陈述价格揭示定理和可逆性条件。 +3. 用 CES 和科布-道格拉斯偏好的数值例子来说明可逆性及其失效。 +4. 引入动态随机经济并推导贝叶斯收敛结果。 +5. 模拟从价格观测中进行的贝叶斯学习。 + +本讲以 {doc}`blackwell_kihlstrom` 和 {doc}`likelihood_bayes` 中的思想为基础。 + +我们首先导入一些 Python 包。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import brentq +from scipy.stats import norm +``` + + +## 设定 + +### 偏好、禀赋与未知状态 + +该经济有两种商品。 + +商品 2 是计价商品(价格标准化为 1)。 + +商品 1 以价格 $p > 0$ 交易。 + +一个未知参数 $\bar{a}$ 影响商品 1 的价值。 + +代理人 $i$ 从一束商品 $(x_1^i, x_2^i)$ 中获得的期望效用为 + +$$ +U^i(x_1^i, x_2^i) + = \sum_{s=1}^{S} u^i(a_s x_1^i,\, x_2^i)\, P^i(\bar{a} = a_s), +$$ + +其中 $P^i$ 是代理人 $i$ 在有限状态空间 $A = \{a_1, \ldots, a_S\}$ 上的主观概率分布。 + +每个代理人初始拥有商品 2 的禀赋 $w^i$ 以及代表性企业的一份份额 $\theta^i$。 + +在该论文的形式模型中,一家企业根据 $y_1 = f(y_2)$(其中 $f' < 0$)将商品 2 转化为商品 1,并选择生产以最大化 + +$$ +\pi(p) = \max_{y_2 \leq 0} \{p f(y_2) + y_2\}. +$$ + +企业的利润 $\pi$ 随后按份额 $\theta^i$ 分配给家庭。 + +代理人 $i$ 的预算约束是 + +$$ +p x_1^i + x_2^i = w^i + \theta^i \pi. +$$ + +代理人在预算约束下最大化期望效用。 + +**竞争均衡**是一个能同时出清两个市场的价格 $\hat{p}$。 + +在所维持的凸性假设下,均衡存在,并且遵循 {cite:t}`kihlstrom_mirman1975`,我们假设均衡价格是唯一的,从而可以将 $\hat p = p(\mu)$ 写作知情代理人后验的一个良好定义的函数。 + +在接下来的大部分内容中,生产方面只通过所诱导的均衡价格映射发挥作用,因此当我们转向数值说明时,我们将略去生产,并使用纯交换/投资组合的解释,以保持计算的透明性。 + +### 知情代理人的问题 + +假设**代理人 1**(内部人)在交易前观察到一个与 $\bar{a}$ 相关的私有信号 $\tilde{y}$,其中 $\tilde{y}$ 取值于有限集合 $Y$。 + +在信号到达之前,代理人 1 拥有先验信念 $\mu_0 = P^1$。 + +在观察到 $\tilde{y} = y$ 后,代理人 1 通过贝叶斯法则更新到**后验** $\mu_y = (\mu_{y1}, \ldots, \mu_{yS})$: + +$$ +\mu_{ys} = P(\bar{a} = a_s \mid \tilde{y} = y). +$$ + +由于代理人 1 的需求依赖于 $\mu_y$,新的均衡价格满足 + +$$ +\hat{p} = p(\mu_y). +$$ + +看到 $\hat{p}$ 但看不到 $\tilde{y}$ 的外部观察者可以尝试从价格中*倒推*出内部人的后验。 + +定义已实现后验的集合 + +$$ +M = \{\mu_y : y \in Y,\; P(\tilde y = y) > 0\}. +$$ + +关键问题是映射 $\mu \mapsto p(\mu)$ 在 $M$ 上是否一一对应。 + +为了回答这个问题,我们现在将"价格中的信息"翻译成 Blackwell 的充分性语言。 + +(price_revelation_theorem)= +## 价格揭示 + +### Blackwell 充分性 + +如果观察均衡价格与直接观察信号 $\tilde{y}$ 对 $\bar{a}$ 的信息量相同,那么价格变量 $p(\mu_{\tilde{y}})$ 就*准确地传递*了内部人的私有信息。 + +在 Blackwell 的语言中({cite:t}`blackwell1951` 和 {cite:t}`blackwell1953`),这意味着 $p(\mu_{\tilde{y}})$ 对 $\tilde{y}$ 是**充分的**。 + +```{prf:definition} 充分性 +:label: ime_def_sufficiency + +如果存在一个**独立于** $\bar{a}$ 的条件分布 $P(y' \mid y)$,使得 + +$$ +\phi'_a(y') = \sum_{y \in Y} P(y' \mid y)\, \phi_a(y) +\quad \text{对所有 } a \text{ 和所有 } y', +$$ + +其中 $\phi_a(y) = P(\tilde{y} = y \mid \bar{a} = a)$,那么随机变量 $\tilde{y}$ 相对于 $\bar{a}$ 对 $\tilde{y}'$ 是*充分的*。 + +因此,一旦知道 $\tilde{y}$,$\tilde{y}'$ 就不再提供关于 $\bar{a}$ 的额外信息。 +``` + +{cite:t}`kihlstrom_mirman1975` 证明了 + +```{prf:lemma} 后验充分性 +:label: ime_lemma_posterior_sufficiency + +后验分布 $\mu_{\tilde{y}}$ 是 $\tilde{y}$ 的一个充分统计量。 +``` + +```{prf:proof} (概要) +后验 $\mu_{\tilde{y}}$ 满足 + +$$ +P(\bar{a} = a_s \mid \mu_{\tilde{y}} = \mu_y,\; \tilde{y} = y) = \mu_{ys} + = P(\bar{a} = a_s \mid \mu_{\tilde{y}} = \mu_y). +$$ + +该恒等式表明,一旦知道后验,以原始信号 $\tilde y$ 为条件并不会改变关于 $\bar a$ 的信念。 + +等价地,给定 $\mu_{\tilde y}$ 时 $\tilde y$ 的条件分布独立于 $\bar a$,因此 $\mu_{\tilde y}$ 在 Blackwell 意义下对 $\tilde y$ 是充分的。 +``` + +现在让我们考虑从信念到价格的映射。 + +```{prf:theorem} 价格揭示 +:label: ime_theorem_price_revelation + +在上述模型中,价格随机变量 $p(\mu_{\tilde{y}})$ 对随机变量 $\tilde{y}$ 是充分的,当且仅当函数 $p(P^1)$ 在价格集合 + +$$ +\mathcal{P} = \Bigl\{\, p(\mu_y) : y \in Y,\; + P(\tilde{y} = y) = \sum_{a \in A} \phi_a(y)\,\mu_0(a) > 0 \Bigr\} +$$ + +上是可逆的。 +``` + +其逻辑是 + +$$ +\tilde y \quad \longrightarrow \quad \mu_{\tilde y} \quad \longrightarrow \quad +p(\mu_{\tilde y}). +$$ + +根据 {prf:ref}`ime_lemma_posterior_sufficiency`,第一个箭头没有损失关于 $\bar a$ 的信息,而该定理询问的是第二个箭头何时也没有损失信息。 + +证明分为两部分。 + +如果 $p(\cdot)$ 在 $M$ 上是一一对应的,那么观察价格就等价于观察后验本身,因为 + +$$ +P(\mu_{\tilde y} = \mu \mid p(\mu_{\tilde y}) = p) += \begin{cases} +1 & \text{如果 } \mu = p^{-1}(p), \\ +0 & \text{否则。} +\end{cases} +$$ + +这个条件分布独立于状态,因此价格对后验是充分的;结合 {prf:ref}`ime_lemma_posterior_sufficiency`,价格因而对信号是充分的。 + +反之,如果 $M$ 中两个不同的后验产生了相同的价格,那么价格的观察者就无法分辨发生的是哪个后验,而该论文正式表明,在这种情况下,给定价格时后验的条件分布将依赖于状态,因此价格不可能是充分的。 + +在转向可逆性本身之前,记住该论文所强调的两种经济解释是有帮助的。 + +### 两种解释 + +#### 股票市场中的内幕交易 + +商品 1 是一种具有随机回报 $\bar{a}$ 的风险资产;商品 2 是"货币"。 + +内部人的需求揭示了关于回报的私有信息。 + +如果可逆性条件成立,外部观察者就可以从均衡股票价格中读出内部人的后验分布——即内部人信号所携带的关于 $\bar a$ 的有用信息。 + +#### 价格作为质量信号 + +商品 1 的质量 $\bar{a}$ 是不确定的。 + +有经验的消费者(曾试用过该商品)观察到一个与质量相关的信号,并据此购买。 + +不知情的消费者只要可逆性成立,就可以从市场价格推断质量。 + +(invertibility_conditions)= +## 可逆性与替代弹性 + +信念到价格的映射何时不可逆? + +{prf:ref}`ime_theorem_invertibility_conditions` 表明,对于一个两状态经济($S = 2$),答案取决于代理人 1 的效用函数的**替代弹性** $\sigma$。 + +在陈述该定理之前,先看看该论文论证中的两个中间步骤是有帮助的。 + +```{prf:lemma} 相同价格意味着相同配置 +:label: ime_lemma_same_price_same_allocation + +假设 $u^i$ 具有连续的一阶偏导数,且 $u^i$ 是拟凹的。 + +设 $p \in \mathcal{P}$。 + +如果存在 $M$ 中的两个测度 $\mu^*$ 和 $\mu'$,使得 $p(\mu^*, P^2, \ldots, P^n) = p(\mu', P^2, \ldots, P^n) = p$,那么 + +$$ +x^i(\mu^*, P^2, \ldots, P^n) = x^i(\mu', P^2, \ldots, P^n), \quad +i = 1, \ldots, n. +$$ +``` + +固定除代理人 1 之外所有代理人的信念。 + +该引理表明,如果代理人 1 的两个后验信念 $\mu^*$ 和 $\mu'$ 都支持相同的均衡价格 $p$,那么它们对每一位交易者都支持相同的均衡配置。 + +其直觉是,当价格不变时,不知情交易者的需求也不变,因此市场出清迫使知情代理人的商品束也保持不变。 + +该引理使我们能够将知情代理人的均衡商品束定义为价格的一个函数: + +$$ +x(p) = (x_1(p), x_2(p)). +$$ + +在全文中,$u^i_j$ 表示 $u^i$ 对其第 $j$ 个参数的偏导数。 + +每当知情代理人对两种商品都消费正的数量时,在后验 $\mu$ 下 $x(p)$ 的最优性给出了内部一阶条件 + +$$ +p = \frac{\sum_{s=1}^S a_s u_1^1(a_s x_1(p), x_2(p))\, \mu(a_s)} + {\sum_{s=1}^S u_2^1(a_s x_1(p), x_2(p))\, \mu(a_s)}. +$$ + +对于一个固定的价格 $p$,商品束 $x(p)$ 也是固定的,因此可逆性归结为这个方程是否有唯一的后验 $\mu$。 + +```{prf:lemma} 给定价格下的唯一后验 +:label: ime_lemma_unique_posterior + +假设 $u^1$ 的一阶偏导数存在,且 $u^1$ 是拟凹的。 + +同时假设代理人 1 总是消费两种商品的正数量。 + +那么,如果对每个 $p \in \mathcal{P}$ 都存在唯一的概率测度 $\mu \in M$ 使得 + +$$ +\frac{\sum_{s=1}^S a_s\, u^1_1(a_s x_1(p), x_2(p))\, \mu(a_s)} + {\sum_{s=1}^S u^1_2(a_s x_1(p), x_2(p))\, \mu(a_s)} = p, +$$ + +那么 $p(P^1)$ 在 $\mathcal{P}$ 上是可逆的。 +``` + +如果两个不同的后验给出相同的价格,那么根据 {prf:ref}`ime_lemma_same_price_same_allocation`,它们将共享相同的商品束 $x(p)$,这与在该价格下求解一阶条件的后验的唯一性相矛盾。 + +### 两状态一阶条件 + +当 $S = 2$ 且 $\mu = (q,\, 1-q)$ 时,定义 + +$$ +\alpha_s(p) = a_s\, u^1_1(a_s x_1(p),\, x_2(p)), \qquad +\beta_s(p) = u^1_2(a_s x_1(p),\, x_2(p)), \qquad s = 1, 2. +$$ + +那么一阶条件变为 + +$$ +p = \frac{\alpha_1(p)\, q + \alpha_2(p)\, (1-q)} + {\beta_1(p)\, q + \beta_2(p)\, (1-q)}. +$$ + +在固定价格 $p$ 处,数量 $\alpha_s(p)$ 和 $\beta_s(p)$ 是常数,因此后验的唯一性与求解此方程的标量 $q$ 的唯一性是相同的。 + +```{prf:theorem} 可逆性条件 +:label: ime_theorem_invertibility_conditions + +假设 $u^1$ 的一阶偏导数存在,且 $u^1$ 是拟凹且位似的。 + +同时假设知情代理人在所有均衡配置中总是消费两种商品的正数量。 + +如果 $S = 2$ 且 $u^1$ 的替代弹性始终小于一或始终大于一,那么 $p(P^1)$ 在 $\mathcal{P}$ 上是可逆的。 + +如果 $u^1$ 是科布-道格拉斯型的(替代弹性恒等于一),那么 $p(P^1)$ 在 $\mathcal{P}$ 上是常数。 +``` + +当 $\sigma = 1$ 时,收入效应和替代效应恰好相互抵消,因此代理人 1 对商品 1 的需求不会对关于 $\bar{a}$ 的信念变化做出反应。 + +由于需求不变,市场出清价格也不变,价格因而不揭示内部人信号的任何信息。 + +### CES 效用 + +为具体起见,我们使用一个采用**常替代弹性**(CES)效用函数的简化例子 + +$$ +u(c_1, c_2) = \bigl(c_1^{\rho} + c_2^{\rho}\bigr)^{1/\rho}, \qquad \rho \in +(-\infty,0) \cup (0,1), +$$ + +其替代弹性为 $\sigma = 1/(1-\rho)$。 + +- $\rho \to 0$:科布-道格拉斯($\sigma = 1$)。 +- $\rho < 0$:$\sigma < 1$(互补品)。 +- $0 < \rho < 1$:$\sigma > 1$(替代品)。 + +相关的偏导数为 + +$$ +u_1(c_1,c_2) = \bigl(c_1^\rho + c_2^\rho\bigr)^{1/\rho - 1}\, c_1^{\rho-1}, +\qquad +u_2(c_1,c_2) = \bigl(c_1^\rho + c_2^\rho\bigr)^{1/\rho - 1}\, c_2^{\rho-1}. +$$ + +这个 CES 例子只是一个说明,因为定理本身涵盖任何弹性处处大于一或处处小于一的位似效用。 + +有了这个例子,我们就可以直接将均衡价格计算为后验的函数。 + +### 均衡价格作为后验的函数 + +我们将代理人 1 视为*唯一*的知情交易者,他在均衡时吸收一单位的商品 1(即 $x_1 = 1$)。 + +令 $W_1 = w^1 + \theta^1 \pi$ 表示代理人 1 的总财富(禀赋加利润份额)。 + +代理人 1 的预算约束因而简化为 $x_2 = W_1 - p$,均衡价格是满足一阶条件的唯一的 $p \in (0, W_1)$ + +$$ +p \bigl[q\, u_2(a_1,\, W_1-p) + (1-q)\, u_2(a_2,\, W_1-p)\bigr] += q\, a_1\, u_1(a_1,\, W_1-p) + (1-q)\, a_2\, u_1(a_2,\, W_1-p). +$$ + +对于科布-道格拉斯效用($\sigma = 1$),一阶条件变为 $p = W_1 - p$,得到 $p^* = W_1/2$,与后验 $q$ 无关,这证实了在科布-道格拉斯情形下没有信息通过价格传递。 + +我们在下面数值计算一阶条件。 + +```{code-cell} ipython3 +def ces_derivatives(c1, c2, ρ): + """ + 返回 CES 边际效用。 + + 在 rho = 0 附近使用科布-道格拉斯极限。 + """ + if abs(ρ) < 1e-4: + u1 = 0.5 * np.sqrt(c2 / c1) + u2 = 0.5 * np.sqrt(c1 / c2) + else: + common = (c1**ρ + c2**ρ)**(1 / ρ - 1) + u1 = common * c1**(ρ - 1) + u2 = common * c2**(ρ - 1) + return u1, u2 + + +def eq_price(q, a1, a2, W1, ρ): + """返回后验 q 对应的均衡价格。""" + def residual(p): + x2 = W1 - p + u1_s1, u2_s1 = ces_derivatives(a1, x2, ρ) + u1_s2, u2_s2 = ces_derivatives(a2, x2, ρ) + lhs = p * (q * u2_s1 + (1 - q) * u2_s2) + rhs = q * a1 * u1_s1 + (1 - q) * a2 * u1_s2 + return lhs - rhs + + try: + return brentq(residual, 1e-6, W1 - 1e-6, xtol=1e-10) + except ValueError: + return np.nan +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 均衡价格与后验 + name: fig-eq-price-posterior +--- +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n + +a1, a2 = 2.0, 0.5 # 状态值 (a1 > a2) +W1 = 4.0 + +q_grid = np.linspace(0.05, 0.95, 200) + +ρ_values = [-0.5, 0.0, 0.5] +ρ_labels = [ + r"$\rho = -0.5$ ($\sigma = 0.67$, 互补品)", + r"$\rho = 0$ ($\sigma = 1$, 科布-道格拉斯)", + r"$\rho = 0.5$ ($\sigma = 2$, 替代品)", +] + +fig, ax = plt.subplots(figsize=(8, 5)) + +for ρ, label in zip(ρ_values, ρ_labels): + prices = [eq_price(q, a1, a2, W1, ρ) for q in q_grid] + ax.plot(q_grid, prices, label=label, lw=2) + +ax.set_xlabel(r"后验概率 $q = \Pr(\bar{a} = a_1)$", fontsize=12) +ax.set_ylabel("均衡价格 $p^*(q)$", fontsize=12) +ax.legend(fontsize=10) +plt.tight_layout() +plt.show() +``` + +该图证实了 {prf:ref}`ime_theorem_invertibility_conditions`。 + +对于 $\sigma \neq 1$ 的 CES,均衡价格在 $q$ 上是严格单调的。 + +因此,知道均衡映射 $p^*(\cdot)$ 的外部观察者可以唯一地反转价格以恢复 $q$,故内部信息被完全传递。 + +对于科布-道格拉斯($\sigma = 1$),价格在 $q$ 上是平坦的,因此信息永远不会通过市场传递。 + +```{code-cell} ipython3 +p_cd = [eq_price(q, a1, a2, W1, ρ=0.0) for q in q_grid] + +print(f"Cobb-Douglas (rho=0): min p* = {min(p_cd):.6f}, " + f"max p* = {max(p_cd):.6f}, " + f"range = {max(p_cd)-min(p_cd):.2e}") +print(f"Analytical CD price = W1/2 = {W1/2:.6f}") +``` + +每一项都恰好等于 $W_1/2 = 2.0$,从解析上证实了科布-道格拉斯均衡价格与 $q$ 以及状态值 $a_1, a_2$ 无关。 + +数值图显示了单调性,下一小节将这个模式与 {prf:ref}`ime_theorem_invertibility_conditions` 的证明联系起来。 + +(price_monotonicity)= +### 为什么单调性取决于 $\sigma$ + +固定一个价格 $p$,并将 $\alpha_s(p)$ 和 $\beta_s(p)$ 视为常数。 + +两状态一阶条件的右侧 + +$$ +\frac{\alpha_1(p)\, q + \alpha_2(p)\, (1-q)} + {\beta_1(p)\, q + \beta_2(p)\, (1-q)} +$$ + +因而是 $q$ 单独的函数,其导数为 + +$$ +\frac{\partial}{\partial q} +\frac{\alpha_1 q + \alpha_2 (1-q)} + {\beta_1 q + \beta_2 (1-q)} += \frac{\alpha_1 \beta_2 - \alpha_2 \beta_1} + {\bigl[\beta_1 q + \beta_2 (1-q)\bigr]^2}. +$$ + +因此符号由 $\alpha_1 \beta_2 - \alpha_2 \beta_1$ 决定,如果这个符号是恒定的,那么对每个固定价格,最多有一个与一阶条件相容的后验权重 $q$,这正是 {prf:ref}`ime_theorem_invertibility_conditions` 所要求的。 + +利用 + +$$ +\frac{\alpha_s}{\beta_s} + = \frac{a_s\, u_1(a_s x_1, x_2)}{u_2(a_s x_1, x_2)} + = a_s^{(\sigma-1)/\sigma}\,\Bigl(\frac{x_2}{x_1}\Bigr)^{1/\sigma}, +$$ + +可以证明 + +$$ +\frac{\partial}{\partial a}\,\frac{\alpha}{\beta} + = \frac{(\sigma - 1)}{\sigma}\, a^{-1/\sigma}\, + \Bigl(\frac{x_2}{x_1}\Bigr)^{1/\sigma}. +$$ + +对于 CES 设定,当 $\sigma > 1$ 时该导数为正,当 $\sigma < 1$ 时为负,*当 $\sigma = 1$ 时为零*。 + +换句话说,对于 CES 效用,比率 $\alpha_s / \beta_s$ 随状态值 $a_s$ 单调变化,除非 $\sigma = 1$,这使得固定价格的一阶条件表达式在 $q$ 上单调,进而带来可逆性。 + +科布-道格拉斯情形下导数消失意味着边际替代率与 $a_s$ 无关,因此知情代理人的需求,进而均衡价格,不会对信念变化做出反应。 + +让我们将比率 $\alpha_s / \beta_s$ 作为 $a_s$ 的函数,对不同的 $\sigma$ 值进行可视化: + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 边际替代率 + name: fig-mrs-alpha-beta +--- +a_vals = np.linspace(0.3, 3.0, 300) +x1_fix, x2_fix = 1.0, 1.0 + +fig, ax = plt.subplots(figsize=(7, 4)) +for ρ in [-0.5, -1e-6, 0.5]: + σ = 1 / (1 - ρ) if abs(ρ) > 1e-8 else 1.0 + ratios = [] + for a in a_vals: + u1, u2 = ces_derivatives(a * x1_fix, x2_fix, ρ) + ratios.append(a * u1 / u2) + ax.plot(a_vals, ratios, label=rf"$\sigma = {σ:.2f}$", lw=2) + +ax.set_xlabel(r"状态值 $a_s$", fontsize=12) +ax.set_ylabel(r"$\alpha_s / \beta_s = a_s u_1 / u_2$", fontsize=12) +ax.axhline(y=1.0, color="black", lw=0.8, ls="--") +ax.legend(fontsize=10) +plt.tight_layout() +plt.show() +``` + +当 $\sigma = 1$ 时,该比率在所有 $a_s$ 值上都是常数,因此关于状态的信息对边际替代率没有影响。 + +对于 $\sigma < 1$,该比率在 $a_s$ 上递减,而对于 $\sigma > 1$,它递增,这使得均衡价格在两种情况下都在后验 $q$ 上严格单调。 + +静态分析询问当前价格是否揭示当前私有信息,而下一节则询问整个价格历史随时间揭示了什么。 + +(bayesian_price_expectations)= +## 动态经济中的贝叶斯价格预期 + +我们现在转向 {cite:t}`kihlstrom_mirman1975` 第 3 节所讨论的一个问题。 + +### 一个随机交换经济 + +时间是离散的:$t = 1, 2, \ldots$ + +在每一期 $t$: + +1. 消费者 $i$ 收到一个随机禀赋 $\omega_i^t$。 +2. 市场开放;竞争价格 $p^t = p(\omega^t)$ 出清所有市场。 +3. 消费者进行交易和消费。 + +禀赋向量 $\{\tilde{\omega}^t\}$ 是**独立同分布**的,其密度为 $f(\omega^t \mid \lambda)$,其中 $\lambda = (\lambda_1, \ldots, \lambda_K)$ 是一个**结构参数向量**(维数为 $K$),它是*固定但未知的*。 + +$t$ 时刻的均衡价格是 $\omega^t$ 的确定性函数,因此 $\{p^t\}$ 也是独立同分布的。 + +对于任何可测的价格集合 $P$,令 + +$$ +W(P) = \{\omega^t : p(\omega^t) \in P\}. +$$ + +那么 + +$$ +P_\lambda(p^t \in P) = P_\lambda(\omega^t \in W(P)) += \int_{W(P)} f(\omega^t \mid \lambda)\, d\omega^t. +$$ + +所诱导的价格密度记为 $g(p^t \mid \lambda)$。 + +对于给定的结构 $\lambda$,这个密度是模型的可观测含义,当几个结构隐含相同的密度时,我们将它们归为一个单一的简约形式类。 + +因此下一个问题是观察者仅从价格数据中能够和不能够推断出关于结构的什么信息。 + +### 识别问题 + +由于价格观测仅识别所诱导的价格密度 $g(\cdot \mid \lambda)$,并且由于从结构到简约形式的映射 $\lambda \mapsto g(\cdot \mid \lambda)$ 可能是多对一的,因此价格数据可能只识别一个简约形式类,而不是精确的结构。 + +特别地,即使有无限的价格数据,也可能无法从 $g(p \mid \lambda)$ 中恢复 $\lambda$。 + +为了处理这一点,将 $\Lambda$ 划分为等价类 $\mu$,使得当对所有 $p$ 都有 $g(p \mid \lambda) = g(p \mid \lambda')$ 时,$\lambda \in \mu$ 且 $\lambda' \in \mu$。 + +包含真实 $\lambda$ 的等价类 $\mu$ 是与价格数据相关的**简约形式**。 + +知道无限价格历史的观察者学到了 $\mu$,但不一定学到 $\lambda$。 + +一旦这个区别清楚了,贝叶斯更新就可以直接写出来。 + +### 贝叶斯更新 + +一位不知情的观察者从 $\lambda \in \Lambda$ 上的先验 $h(\lambda)$ 开始。 + +如果观察者能够直接看到禀赋,那么后验将是 + +$$ +h(\lambda \mid \omega^1, \ldots, \omega^t) + = \frac{h(\lambda)\, \prod_{\tau=1}^{t} f(\omega^\tau \mid \lambda)} + {\displaystyle\sum_{\lambda' \in \Lambda} + h(\lambda')\, \prod_{\tau=1}^{t} f(\omega^\tau \mid \lambda')}, +$$ + +该论文诉诸于一个贝叶斯一致性结果,得出结论认为该后验集中于真实结构 $\bar \lambda$。 + +在观察价格序列 $(p^1, \ldots, p^t)$ 之后,观察者的贝叶斯后验为 + +$$ +h(\lambda \mid p^1, \ldots, p^t) + = \frac{h(\lambda)\, \prod_{\tau=1}^{t} g(p^\tau \mid \lambda)} + {\displaystyle\sum_{\lambda' \in \Lambda} + h(\lambda')\, \prod_{\tau=1}^{t} g(p^\tau \mid \lambda')}. +$$ + +价格数据无法区分同一简约形式类内的结构。 + +事实上,如果 $\lambda$ 和 $\lambda'$ 属于同一类 $\mu$,那么 $g(\cdot \mid \lambda) = g(\cdot \mid \lambda')$,因此 + +$$ +\frac{h(\lambda \mid p^1, \ldots, p^t)} + {h(\lambda' \mid p^1, \ldots, p^t)} += \frac{h(\lambda)}{h(\lambda')} +$$ + +对每一个样本历史都成立,因此在一个观测上等价的类内的相对几率永远不会改变。 + +在 $t$ 时刻,观察者对下一期的价格预期为 + +$$ +g(p^{t+1} \mid p^1, \ldots, p^t) + = \sum_{\lambda \in \Lambda} g(p^{t+1} \mid \lambda)\, + h(\lambda \mid p^1, \ldots, p^t). +$$ + +### 收敛定理 + +```{prf:theorem} 贝叶斯收敛 +:label: ime_theorem_bayesian_convergence + +设 $\bar\lambda$ 为真实结构参数,$\bar\mu$ 为包含 $\bar\lambda$ 的简约形式。 + +假设先验对简约形式类 $\bar\mu$ 赋予正概率。 + +将简约形式类上的后验质量定义为 + +$$ +H_t(\mu) = \sum_{\lambda \in \mu} h(\lambda \mid p^1, \ldots, p^t). +$$ + +由于类内所有结构都隐含相同的 $g(\cdot \mid \lambda)$,预测密度可以等价地写为 + +$$ +g(p^{t+1} \mid p^1, \ldots, p^t) + = \sum_{\mu} g(p^{t+1} \mid \mu)\, H_t(\mu). +$$ + +那么 + +$$ +\lim_{t \to \infty} H_t(\mu) + = \begin{cases} 1 & \text{如果 } \mu = \bar\mu, \\ 0 & \text{否则,} + \end{cases} +$$ + +以概率一成立。 + +因此, + +$$ +\lim_{t \to \infty} g(p^{t+1} \mid p^1, \ldots, p^t) = g(p \mid \bar\mu), +$$ + +它等于一位完全知情观察者的理性预期价格分布。 +``` + +```{note} +注意该定理仅要求先验对包含真实结构 $\bar\lambda$ 的简约形式类 $\bar\mu$ 赋予正概率。 + +这一点由对真实结构参数 $\bar\lambda$ 本身赋予正概率所隐含,但比后者更弱。 + +一个先验可以对 $\bar\lambda$ 赋予零质量,同时仍然对 $\bar\mu$ 内的其他结构赋予正质量。 +``` + +重要的区别在于价格观察者不必学到 $\bar \lambda$ 本身。 + +他们只学到哪个简约形式类是正确的。 + +这对于预测就足够了,因为每个 $\lambda \in \bar \mu$ 都产生相同的价格密度 $g(\cdot \mid \bar \mu)$。 + +理性价格预期源于学到简约形式,而非识别经济的每一个结构细节。 + +这里"理性预期"意味着观察者对下一期价格的预测分布与真实简约形式所产生的客观价格分布相匹配。 + +现在让我们转向一个简单的模拟。 + +(bayesian_simulation)= +## 从价格中模拟贝叶斯学习 + +我们用一个两状态例子来说明该定理。 + +两个可能的简约形式 $\mu_1$ 和 $\mu_2$ 分别产生价格 $p^t \sim N(\bar{p}_i, \sigma_p^2)$,其中 $i = 1, 2$。 + +观察者知道这两个可能的价格分布(简约形式),但不知道哪一个支配着数据。 + +这是一个我们在 {doc}`likelihood_bayes` 中见过的**贝叶斯模型选择**问题。 + +给定 $\mu_1$ 上的先验 $h_0$ 和观测到的价格 $p^t$,在第 $t$ 期之后 $\mu_1$ 上的后验权重为 + +$$ +h_t = \frac{h_{t-1}\, g(p^t \mid \mu_1)}{h_{t-1}\, g(p^t \mid \mu_1) + + (1-h_{t-1})\, g(p^t \mid \mu_2)}. +$$ + +我们考虑一个具有两个不同均值的正态分布的数值例子 + +```{code-cell} ipython3 +def simulate_bayesian_learning( + p_bar_true, p_bar_alt, σ_p, T, h0, n_paths, seed=42 +): + """在两个高斯简约形式之间模拟后验学习。""" + rng = np.random.default_rng(seed) + h_paths = np.zeros((n_paths, T + 1)) + h_paths[:, 0] = h0 + + for path in range(n_paths): + h = h0 + prices = rng.normal(p_bar_true, σ_p, size=T) + for t, p in enumerate(prices): + g_true = norm.pdf(p, loc=p_bar_true, scale=σ_p) + g_alt = norm.pdf(p, loc=p_bar_alt, scale=σ_p) + denom = h * g_true + (1 - h) * g_alt + h = h * g_true / denom + h_paths[path, t + 1] = h + + return h_paths + + +def plot_bayesian_learning(h_paths, p_bar_true, p_bar_alt, ax): + """绘制随时间变化的后验信念。""" + T = h_paths.shape[1] - 1 + t_grid = np.arange(T + 1) + + for path in h_paths: + ax.plot(t_grid, path, alpha=0.25, lw=0.8, color="steelblue") + + median_path = np.median(h_paths, axis=0) + ax.plot(t_grid, median_path, color="navy", lw=2, label="后验中位数") + + ax.axhline( + y=1.0, + color="black", + ls="--", + lw=1.2, + label="真实模型权重 = 1", + ) + ax.set_xlabel("时期 $t$", fontsize=12) + ax.set_ylabel(r"$h_t$ = 真实模型上的后验权重", fontsize=12) + ax.legend(fontsize=10) +``` + +我们考虑两种情形,一种容易学习,另一种较难学习,使用 $T = 300$ 个时期、$n = 40$ 条模拟路径、一个扩散先验 $h_0 = 0.5$,以及共同的标准差 $\sigma_p = 0.4$。 + +- *容易的情形*:真实模型 $N(2.0,\, 0.4^2)$,备择模型 $N(1.2,\, 0.4^2)$。 +- *困难的情形*:真实模型 $N(2.0,\, 0.4^2)$,备择模型 $N(1.8,\, 0.4^2)$。 + +学习是容易还是困难取决于真实分布与备择假设相比"有多接近"。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 跨路径的贝叶斯学习 + name: fig-bayesian-learning +--- +T = 300 +h0 = 0.5 # 扩散先验 +n_paths = 40 +σ_p = 0.4 + +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +# 不同的简约形式 +p_bar_true, p_bar_alt = 2.0, 1.2 +h_paths = simulate_bayesian_learning(p_bar_true, p_bar_alt, σ_p, T, h0, n_paths) +plot_bayesian_learning(h_paths, p_bar_true, p_bar_alt, axes[0]) + +# 相似的简约形式 +p_bar_true, p_bar_alt = 2.0, 1.8 +h_paths_hard = simulate_bayesian_learning( + p_bar_true, p_bar_alt, σ_p, T, h0, n_paths +) +plot_bayesian_learning(h_paths_hard, p_bar_true, p_bar_alt, axes[1]) + +plt.tight_layout() +plt.show() +``` + +在两个面板中,真实模型上的后验权重都以概率一收敛到 1,尽管当两个价格分布相似时(右面板)收敛较慢。 + +### 价格预期 vs. 理性预期 + +我们现在验证观察者的价格预期收敛到理性预期分布 $g(p \mid \bar\mu)$。 + +我们使用上面"难以学习"例子的参数化($\bar{p}_{\text{true}} = 2.0$,$\bar{p}_{\text{alt}} = 1.8$,$\sigma_p = 0.4$),扩展到 $T = 1{,}000$ 个时期,使用单条模拟路径和先验 $h_0 = 0.5$ + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 价格分布收敛 + name: fig-price-convergence +--- +def price_expectation(h_t, p_bar_true, p_bar_alt, σ_p, p_grid): + """返回后验权重 h_t 处的预测价格密度。""" + return ( + h_t * norm.pdf(p_grid, loc=p_bar_true, scale=σ_p) + + (1 - h_t) * norm.pdf(p_grid, loc=p_bar_alt, scale=σ_p) + ) + + +p_bar_true, p_bar_alt = 2.0, 1.8 +σ_p = 0.4 +n_paths = 1 +T_long = 1000 + +h_paths_long = simulate_bayesian_learning( + p_bar_true, p_bar_alt, σ_p, T_long, h0=0.5, n_paths=n_paths, seed=7 +) + +p_grid = np.linspace(0.0, 3.5, 300) +re_density = norm.pdf(p_grid, loc=p_bar_true, scale=σ_p) + +fig, ax = plt.subplots(figsize=(8, 5)) +snapshots = [0, 25, 100, 300, 1000] +palette = plt.cm.Blues(np.linspace(0.3, 1.0, len(snapshots))) + +for t_snap, col in zip(snapshots, palette): + h_t = h_paths_long[0, t_snap] + dens = price_expectation(h_t, p_bar_true, p_bar_alt, σ_p, p_grid) + ax.plot( + p_grid, + dens, + color=col, + lw=2, + label=rf"$t = {t_snap}$, $h_t = {h_t:.3f}$", + ) + +ax.plot(p_grid, re_density, "k--", lw=2, + label=r"理性预期 $g(p \mid \bar{\mu})$") +ax.set_xlabel("价格 $p$", fontsize=12) +ax.set_ylabel("密度", fontsize=12) +ax.legend(fontsize=9) +plt.tight_layout() +plt.show() +``` + +预测密度序列(蓝色的深浅)随着经验的累积收敛到理性预期密度(黑色虚线)。 + +这说明了 {prf:ref}`ime_theorem_bayesian_convergence`。 + +我们现在可以通过考察一个学到了简约形式但没有学到底层结构的例子来使这一点更加尖锐。 + +(km_extension_nonidentification)= +### 学到简约形式而不识别结构 + +这个收敛结果特别引人注目,因为即使底层**结构** $\lambda$ *无法*由价格*识别*,观察者也会收敛到*理性预期*。 + +为了说明这一点,考虑一个有*三个*可能结构 $\lambda^{(1)}, \lambda^{(2)}, \lambda^{(3)}$ 但只有*两个*简约形式 $\mu_1 = \{\lambda^{(1)}, \lambda^{(2)}\}$ 和 $\mu_2 = \{\lambda^{(3)}\}$ 的情形(因为 $\lambda^{(1)}$ 和 $\lambda^{(2)}$ 产生相同的价格分布)。 + +我们继续使用难以学习的参数化,因此三个结构的价格均值为 $\bar{p}_1 = \bar{p}_2 = 2.0$ 和 $\bar{p}_3 = 1.8$,共同标准差 $\sigma_p = 0.4$,均匀先验 $h_0 = (1/3, 1/3, 1/3)$,以及 $30$ 条路径上的 $T = 400$ 个时期。 + +真实结构是 $\lambda^{(1)}$。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 非识别情况下的学习 + name: fig-nonidentification +--- +def simulate_learning_3struct( + T, h0_vec, p_bar_vec, σ_p, true_idx, n_paths, seed=0 +): + """模拟具有三个结构和两个简约形式的学习。""" + rng = np.random.default_rng(seed) + h_paths = np.zeros((n_paths, T + 1, 3)) + h_paths[:, 0, :] = h0_vec + + for path in range(n_paths): + h = np.array(h0_vec, dtype=float) + prices = rng.normal(p_bar_vec[true_idx], σ_p, size=T) + for t, p in enumerate(prices): + likelihoods = norm.pdf(p, loc=p_bar_vec, scale=σ_p) + h = h * likelihoods + h /= h.sum() + h_paths[path, t + 1, :] = h + + return h_paths + + +# 结构 0 和 1 共享相同的简约形式 +p_bar_vec = np.array([2.0, 2.0, 1.8]) +h0_vec = np.array([1 / 3, 1 / 3, 1 / 3]) +σ_p = 0.4 +T = 400 +true_idx = 0 # 结构 0 与结构 1 在观测上等价 + +h_paths_3 = simulate_learning_3struct( + T, h0_vec, p_bar_vec, σ_p, true_idx, n_paths=30 +) +t_grid = np.arange(T + 1) + +fig, axes = plt.subplots(1, 3, figsize=(13, 4), sharey=True) +struct_labels = [ + r"$\lambda^{(1)}$", + r"$\lambda^{(2)}$", + r"$\lambda^{(3)}$", +] + +for k, (ax, label) in enumerate(zip(axes, struct_labels)): + for path in h_paths_3: + ax.plot(t_grid, path[:, k], alpha=0.25, lw=0.8, color="steelblue") + ax.plot(t_grid, np.median(h_paths_3[:, :, k], axis=0), + color="navy", lw=2, label=f"{label} 上的中位数权重") + ax.set_xlabel("时期 $t$", fontsize=11) + ax.legend(fontsize=9) + +axes[0].set_ylabel("后验权重", fontsize=11) +plt.tight_layout() +plt.show() +``` + +观察者以概率一正确地排除了 $\lambda^{(3)}$(错误的简约形式),但无法区分 $\lambda^{(1)}$ 和 $\lambda^{(2)}$,因为它们产生相同的价格分布。 + +尽管如此,观察者的**价格预期**收敛到理性预期,因为两个结构都隐含相同的简约形式 $\bar\mu$。 + + +## 练习 + +```{exercise} +:label: km_ex1 + +**CARA 投资组合效用与股票市场解释。** + +考虑一个两状态经济($a_1 = 2$,$a_2 = 0.5$),其中知情代理人对投资组合财富具有 **CARA**(常绝对风险厌恶)偏好: + +$$ +u(W) = -e^{-\gamma W}, \quad W = x_2 + \bar{a}\, x_1. +$$ + +代理人选择 $x_1$ 以最大化 + +$$ +q\,u(W_1) + (1-q)\,u(W_2), \quad W_s = w - p\,x_1 + a_s\,x_1, +$$ + +受预算约束 $p\,x_1 + x_2 = w$ 的约束。 + +商品 1 的总供给为 $X_1 = 1$。 + +1. 推导知情代理人最优 $x_1$ 的一阶条件。 + +1. 使用市场出清条件 $x_1 = 1$(知情代理人吸收全部供给)来得到均衡价格 $p^*(q)$ 的一个隐式方程,并对 $q \in (0,1)$ 和若干 $\gamma$ 值进行数值求解。 + +1. *解析地*证明 $p^*(q)$ 具有闭式解 + + $$ + p^*(q) = \frac{a_2 + R(q,\gamma)\, a_1}{1 + R(q,\gamma)}, + \qquad R(q,\gamma) = \frac{q}{1-q}\, e^{-\gamma(a_1-a_2)}, + $$ + + 并验证 $p^*(q)$ 在 $q$ 上是严格递增的。 +``` + +```{solution-start} km_ex1 +:class: dropdown +``` + +对于一阶条件,定义 $W_s = w + (a_s - p)\,x_1$,其中 $s = 1, 2$。 + +那么 FOC 为 + +$$ +q\,(a_1 - p)\,\gamma\, e^{-\gamma W_1} += (1-q)\,(p - a_2)\,\gamma\, e^{-\gamma W_2}, +$$ + +或等价地(除以 $\gamma$ 并重新排列) + +$$ +q\,(a_1 - p)\, e^{-\gamma(a_1-p) x_1} + = (1-q)\,(p - a_2)\, e^{\gamma(p-a_2) x_1}. +$$ + +设 $x_1 = 1$(知情代理人吸收全部供给),这变成关于 $p$ 的标量求根问题: + +$$ +F(p;\,q,\gamma) \equiv + q\,(a_1-p)\,e^{-\gamma(a_1-p)} - (1-q)\,(p-a_2)\,e^{\gamma(p-a_2)} = 0. +$$ + +```{code-cell} ipython3 +from scipy.optimize import brentq + +def F_cara(p, q, a1, a2, γ, x1=1.0): + """CARA 均衡条件的残差。""" + return (q * (a1 - p) * np.exp(-γ * (a1 - p) * x1) + - (1 - q) * (p - a2) * np.exp(γ * (p - a2) * x1)) + +a1, a2 = 2.0, 0.5 +q_grid = np.linspace(0.05, 0.95, 200) +γ_values = [0.5, 1.0, 2.0, 5.0] +colors_sol = plt.cm.plasma(np.linspace(0.15, 0.85, len(γ_values))) + +fig, ax = plt.subplots(figsize=(8, 5)) +for γ, color in zip(γ_values, colors_sol): + p_eq = [brentq(F_cara, a2, a1, + args=(q, a1, a2, γ)) + for q in q_grid] + ax.plot(q_grid, p_eq, lw=2, color=color, + label=rf"$\gamma = {γ}$") + +ax.set_xlabel(r"后验 $q = \Pr(\bar a = a_1)$", fontsize=12) +ax.set_ylabel("均衡价格 $p^*(q)$", fontsize=12) +ax.set_title("CARA 偏好:均衡价格", fontsize=12) +ax.legend(fontsize=10) +plt.tight_layout() +plt.show() +``` + +对于每个 $\gamma > 0$,价格在 $q$ 上都是严格递增的。 + +对于闭式解,从 $x_1 = 1$ 处的 FOC 出发,两边除以 $(a_1 - p)(p - a_2)$,并合并指数项: + +$$ +\frac{q\,(a_1 - p)}{(1-q)\,(p - a_2)} = e^{\gamma(a_1 - a_2)}. +$$ + +重新排列得到 + +$$ +\frac{p - a_2}{a_1 - p} = \frac{q}{1-q}\, e^{-\gamma(a_1 - a_2)} +\equiv R(q,\gamma), +$$ + +求解所得的关于 $p$ 的线性方程得到 + +$$ +p^*(q) = \frac{a_2 + R(q,\gamma)\, a_1}{1 + R(q,\gamma)}. +$$ + +由于 $R(q,\gamma)$ 在 $q$ 上严格递增,且 $dp^*/dR = (a_1 - a_2)/(1 + R)^2 > 0$,因此均衡价格 $p^*(q)$ 在 $q$ 上严格递增。 + +这个练习使用了 {cite:t}`kihlstrom_mirman1975` 所强调的股票市场解释。 + +投资组合财富为 $W = x_2 + \bar{a}\, x_1$,因此 $a x_1$ 和 $x_2$ 在每个状态中是完全替代品。 + +因此 $u(a x_1, x_2)$ 两个参数之间的替代弹性是无穷大,对应于 {prf:ref}`ime_theorem_invertibility_conditions` 中 $\sigma > 1$ 的一侧。 + +不同之处在于,这个例子不是该定理所分析的完整均衡模型,而是一个具有单一知情代理人和固定风险资产供给的局部均衡模型。 + +```{solution-end} +``` + +```{exercise} +:label: km_ex2 + +在贝叶斯学习模拟中,收敛到理性预期的速度由两个简约形式之间的 **Kullback-Leibler 散度**决定。 + +对于两个均值为 $\bar{p}_1$ 和 $\bar{p}_2$ 且共同方差为 $\sigma_p^2$ 的正态分布,从 $g(\cdot \mid \mu_1)$ 到 $g(\cdot \mid \mu_2)$ 的 KL 散度 $D_{KL}(\mu_1 \| \mu_2)$ 为 + +$$ +D_{KL}(\mu_1 \| \mu_2) = \frac{(\bar{p}_1 - \bar{p}_2)^2}{2\sigma_p^2}, +$$ + +在方差相等的情况下,它关于两个均值是对称的。 + +1. 对于"容易的"情形($\bar{p}_1 = 2.0$,$\bar{p}_2 = 1.2$)和"困难的"情形($\bar{p}_1 = 2.0$,$\bar{p}_2 = 1.8$),计算 $\sigma_p = 0.4$ 时的 $D_{KL}$。 + +1. 用 $n=100$ 条路径重新运行本讲中两种情形的模拟。对每条路径计算 $h_t \geq 0.99$ 的第一个时期 $T_{0.99}$。绘制两种情形下 $T_{0.99}$ 的直方图。 + +1. 中位数 $T_{0.99}$ 如何随 $D_{KL}$ 缩放?数值验证对于某个常数 $C$,大致有 $T_{0.99} \approx C / D_{KL}$。 +``` + +```{solution-start} km_ex2 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +σ_p = 0.4 + +def kl_normal(p1, p2, σ): + """返回 N(p1, σ^2) 和 N(p2, σ^2) 的 KL 散度。""" + return (p1 - p2)**2 / (2 * σ**2) + +cases = [("Easy", 2.0, 1.2), ("Hard", 2.0, 1.8)] +for name, p1, p2 in cases: + kl = kl_normal(p1, p2, σ_p) + print(f"{name} case: D_KL = {kl:.4f}") + +n_paths = 100 + +fig, axes = plt.subplots(1, 2, figsize=(11, 4)) +for ax, (name, p1, p2) in zip(axes, cases): + kl = kl_normal(p1, p2, σ_p) + paths = simulate_bayesian_learning(p1, p2, σ_p, T=2000, + h0=0.5, n_paths=n_paths, seed=42) + # 后验 >= 0.99 的第一个时期 + T99 = [] + for path in paths: + idx = np.where(path >= 0.99)[0] + T99.append(idx[0] if len(idx) > 0 else 2001) + + median_T = np.median(T99) + ax.hist(T99, bins=20, color="steelblue", edgecolor="white", alpha=0.8) + ax.axvline(median_T, color="crimson", lw=2, + label=fr"中位数 $T_{{0.99}} = {median_T:.0f}$") + ax.set_title( + f"{name}: $D_{{KL}} = {kl:.4f}$, " + fr"$\widehat C = T_{{0.99}} D_{{KL}} \approx {median_T * kl:.1f}$", + fontsize=11 + ) + ax.set_xlabel(r"$T_{0.99}$", fontsize=12) + ax.set_ylabel("计数", fontsize=11) + ax.legend(fontsize=10) + +plt.tight_layout() +plt.show() +``` + +中位数 $T_{0.99}$ 大致按 $C/D_{KL}$ 缩放,证实了当两个简约形式更容易区分时(大的 $D_{KL}$)学习更快。 + +```{solution-end} +``` + +```{exercise} +:label: km_ex3 + +{prf:ref}`ime_theorem_bayesian_convergence` 要求先验对真实简约形式类 $\bar\mu$ 赋予正概率,等价地对某个产生真实价格分布 $g(\cdot \mid \bar\mu)$ 的结构赋予正概率。 + +在这个练习中,真实简约形式本身被排除在先验支持之外,因此我们研究当先验中没有模型产生真实价格分布时会发生什么。 + +从 $N(2.0, 0.4^2)$ 模拟 $T = 1,000$ 个时期的价格,但使用一个对两个*错误*模型 $N(1.5, 0.4^2)$ 和 $N(2.3, 0.4^2)$ 赋予相等权重的先验。 + +绘制每个模型随时间变化的后验权重。 + +讨论你的发现。 +``` + +```{solution-start} km_ex3 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +def simulate_misspecified( + T, p_bar_true, p_bar_wrong, σ_p, h0, n_paths, seed=0 +): + """在错误设定的双模型先验下模拟学习。""" + rng = np.random.default_rng(seed) + h_paths = np.zeros((n_paths, T + 1, 2)) + h_paths[:, 0, :] = h0 + + for path in range(n_paths): + h = np.array(h0, dtype=float) + prices = rng.normal(p_bar_true, σ_p, size=T) + for t, price in enumerate(prices): + likes = norm.pdf(price, loc=p_bar_wrong, scale=σ_p) + h = h * likes + h /= h.sum() + h_paths[path, t + 1, :] = h + + return h_paths + + +def predictive_density(weights, means, σ_p, p_grid): + """返回当前后验权重下的预测密度。""" + density = np.zeros_like(p_grid) + for weight, mean in zip(weights, means): + density += weight * norm.pdf(p_grid, loc=mean, scale=σ_p) + return density + + +T = 1000 +p_true = 2.0 +p_wrong = np.array([1.5, 2.3]) +σ_p = 0.4 +h0 = np.array([0.5, 0.5]) +n_paths = 30 + +h_misspec = simulate_misspecified(T, p_true, p_wrong, σ_p, h0, n_paths) + +kl_vals = (p_true - p_wrong)**2 / (2 * σ_p**2) +for mean, kl in zip(p_wrong, kl_vals): + print(f"KL(true || N({mean:.1f}, σ^2)) = {kl:.4f}") + +t_grid = np.arange(T + 1) +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +labels = [r"$N(1.5, \sigma^2)$", r"$N(2.3, \sigma^2)$"] +for ax, k, label in zip(axes, [0, 1], labels): + for path in h_misspec: + ax.plot(t_grid, path[:, k], alpha=0.2, lw=0.8, color="steelblue") + ax.plot(t_grid, np.median(h_misspec[:, :, k], axis=0), + color="navy", lw=2, label="中位数") + ax.set_title(f"{label} 上的后验权重", fontsize=11) + ax.set_xlabel("时期 $t$", fontsize=11) + ax.set_ylabel("后验权重", fontsize=11) + ax.legend(fontsize=9) + +plt.tight_layout() +plt.show() + +# 沿后验中位数路径的预测密度和均值 +median_path = np.median(h_misspec, axis=0) +p_grid = np.linspace(0.0, 3.5, 300) +closer_idx = np.argmin(kl_vals) + +fig, ax = plt.subplots(figsize=(8, 4)) +colors = plt.cm.Blues(np.linspace(0.3, 1.0, 4)) +for t_snap, color in zip([0, 10, 100, T], colors): + dens = predictive_density(median_path[t_snap], p_wrong, σ_p, p_grid) + ax.plot(p_grid, dens, color=color, lw=2, label=f"t = {t_snap}") + +ax.plot( + p_grid, + norm.pdf(p_grid, loc=p_wrong[closer_idx], scale=σ_p), + "k--", + lw=2, + label="KL 最优错误模型", +) +ax.set_xlabel("价格 $p$", fontsize=11) +ax.set_ylabel("密度", fontsize=11) +ax.legend(fontsize=9) +plt.tight_layout() +plt.show() + +pred_mean = np.median( + h_misspec[:, :, 0] * p_wrong[0] + h_misspec[:, :, 1] * p_wrong[1], axis=0 +) +print(f"True mean: {p_true}") +print(f"Predictive mean at T={T}: {pred_mean[-1]:.4f}") +print(f"Closer misspecified mean: {p_wrong[np.argmin(kl_vals)]:.1f}") +``` + +这里 + +$$ +D_{KL}\bigl(N(2.0, 0.4^2)\,\|\,N(2.3, 0.4^2)\bigr) +< +D_{KL}\bigl(N(2.0, 0.4^2)\,\|\,N(1.5, 0.4^2)\bigr), +$$ + +因此均值为 $2.3$ 的模型是两个错误模型中 KL 最优的近似,在模拟中后验权重集中于该模型。 + +后验几率是累积的{doc}`似然比 `。 + +如果我们比较两个错误的高斯模型 $f$ 和 $g$,那么在真实分布 $h$ 下,平均对数似然比满足 + +$$ +\frac{1}{t} E_h[\log L_t] = K(h,g) - K(h,f). +$$ + +因此,如果 $f$ 在 KL 意义上比 $g$ 更接近 $h$,那么 $\log L_t$ 有正的漂移,后验几率会倾向于 $f$。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/inventory_q.md b/lectures/inventory_q.md new file mode 100644 index 0000000..1f87967 --- /dev/null +++ b/lectures/inventory_q.md @@ -0,0 +1,737 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.18.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 通过 Q 学习进行库存管理 + headings: + Introduction: 引言 + The Model: 模型 + Solving via Value Function Iteration: 通过值函数迭代求解 + Solving via Value Function Iteration::Model specification: 模型设定 + Solving via Value Function Iteration::The Bellman operator: 贝尔曼算子 + Solving via Value Function Iteration::Computing the greedy policy: 计算贪婪策略 + Solving via Value Function Iteration::Value function iteration: 值函数迭代 + Solving via Value Function Iteration::Creating and solving an instance: 创建并求解一个实例 + Solving via Value Function Iteration::Simulating the optimal policy: 模拟最优策略 + Q-Learning: Q 学习 + Q-Learning::The Q-factor Bellman equation: Q 因子贝尔曼方程 + Q-Learning::The Q-learning update rule: Q 学习更新规则 + Q-Learning::What the manager needs to know: 经理需要知道什么 + Q-Learning::The Q-table and the role of the max: Q 表和最大值的作用 + Q-Learning::The behavior policy: 行为策略 + Q-Learning::Learning rate: 学习率 + 'Q-Learning::Exploration: epsilon-greedy': 探索:epsilon-贪婪 + Q-Learning::Optimistic initialization: 乐观初始化 + Q-Learning::Implementation: 实现 + Q-Learning::Comparing with the exact solution: 与精确解比较 + Q-Learning::Visualizing learning over time: 可视化随时间的学习 +--- + +(inventory_q)= +```{raw} jupyter + +``` + +# 通过 Q 学习进行库存管理 + +```{contents} Contents +:depth: 2 +``` + +## 引言 + +在本讲座中,我们研究一个经典的库存管理问题。 + +一家公司必须决定每期订购多少库存,同时面临不确定的需求以及在销售损失与订购成本之间的权衡。 + +我们用两种方法处理这个问题。 + +首先,我们假设完全了解模型——需求分布、成本参数以及转移动态——并使用动态规划精确求解它。 + +其次,我们展示一位经理如何仅凭经验学习最优策略,使用 [Q 学习](https://en.wikipedia.org/wiki/Q-learning)。 + +在这个设定中,我们假设经理只观察到 + +* 库存水平, +* 下达的订单, +* 由此产生的利润,以及 +* 下一期的库存水平。 + +经理知道利率——因此也知道贴现因子——但不知道任何其他底层参数。 + +一个关键思想是 *Q 因子* 表示,它重新构造了贝尔曼方程,使得无需了解转移动态即可恢复最优策略。 + +我们证明,只要有足够的经验,经理学习到的策略会收敛到最优策略。 + +本讲座的展开如下: + +1. 我们设置库存模型,并通过值函数迭代精确求解它。 +2. 我们引入 Q 因子并推导 Q 因子贝尔曼方程。 +3. 我们实现 Q 学习,并展示学习到的策略收敛到最优策略。 + +本模型的一个风险敏感扩展在 {doc}`rs_inventory_q` 中研究。 + +我们将使用以下导入: + +```{code-cell} ipython3 +import numpy as np +import numba +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'] +from typing import NamedTuple +``` + + +## 模型 + +我们研究一家公司,其经理试图通过控制库存来最大化股东价值。 + +为了简化问题,我们假设该公司只销售一种产品。 + +设 $\pi_t$ 为时间 $t$ 的利润,$r > 0$ 为利率,则公司的价值为 + +$$ + V_0 = \EE \sum_{t \geq 0} \beta^t \pi_t + \qquad + \text{ where } + \quad \beta := \frac{1}{1+r}. +$$ + +假设公司面临外生需求过程 $(D_t)_{t \geq 0}$。 + +我们假设 $(D_t)_{t \geq 0}$ 是独立同分布的,具有 $\{0, 1, \ldots\}$ 上的共同分布 $\phi$。 + +产品的库存 $(X_t)_{t \geq 0}$ 服从 + +$$ + X_{t+1} = h(X_t, A_t, D_{t+1}) + \qquad + \text{where} + \quad + h(x,a,d) := \max(x - d, 0) + a. +$$ + +项 $A_t$ 是本期订购的库存单位数,它们在需求 $D_{t+1}$ 实现并被满足之后,于 $t+1$ 期初到达: + +* 观察 $X_t$ → 选择 $A_t$ → 需求 $D_{t+1}$ 到达 → 利润实现 → $X_{t+1}$ 确定。 + +(我们在 $A_t$ 中使用 $t$ 下标以表明信息集:它是在观察到 $D_{t+1}$ 之前选择的。) + +我们假设公司一次最多可以存储 $K$ 件物品。 + +利润由下式给出 + +$$ + \pi(X_t, A_t, D_{t+1}) := \min(X_t, D_{t+1}) - c A_t - \kappa 1\{A_t > 0\}. +$$ + +这里 + +* 销售价格设为一(为方便起见) +* 收入是当前库存与需求的最小值,因为超出库存的订单会损失(不会补货) +* $c$ 是单位产品成本,$\kappa$ 是订购库存的固定成本 + +我们可以将库存问题映射到一个动态规划问题,其状态空间为 $\mathsf X := \{0, \ldots, K\}$,动作空间为 $\mathsf A := \mathsf X$。 + +可行对应关系 $\Gamma$ 为 + +$$ + \Gamma(x) := \{0, \ldots, K - x\}. +$$ + +这表示当前库存状态为 $x$ 时的可行订单集合。 + +贝尔曼方程的形式为 + +```{math} +:label: inventory_q_bellman + v(x) + = \max_{a \in \Gamma(x)} \mathbb E + \left[ + \pi(x, a, D) + + \beta v(h(x, a, D)) + \right]. +``` + +这里 $D$ 是一个分布为 $\phi$ 的随机变量。 + + + +## 通过值函数迭代求解 + +让我们从经理知道所有参数、函数形式和分布的设定开始。 + +她使用值函数迭代(VFI)以数值方式求解模型。 + +其思想是对由下式定义的贝尔曼算子 $T$ 进行迭代 + +$$ + (Tv)(x) + = \max_{a \in \Gamma(x)} + \sum_d \phi(d) \left[ \pi(x, a, d) + \beta \, v(h(x, a, d)) \right] +$$ + +从初始猜测 $v_0$ 开始。 + +然后,取该迭代过程的输出 $v$,我们计算一个 **$v$-贪婪策略** $\sigma$,它满足 + +$$ + \sigma(x) \in \argmax_{a \in \Gamma(x)} + \sum_d \phi(d) \left[ \pi(x, a, d) + \beta \, v(h(x, a, d)) \right] +$$ + +当 $r > 0$(等价地,$\beta < 1$)时,序列 $v_{k+1} = T v_k$ 收敛到唯一的不动点 $v^*$,它就是最优策略的值函数(例如,参见 {cite}`Sargent_Stachurski_2025`)。 + + +### 模型设定 + +我们将模型基本要素存储在一个 `NamedTuple` 中。 + +需求服从参数为 $p$ 的[几何分布](https://en.wikipedia.org/wiki/Geometric_distribution),因此对于 $d = 0, 1, 2, \ldots$,$\phi(d) = (1 - p)^d \, p$。 + +```{code-cell} ipython3 +class Model(NamedTuple): + x_values: np.ndarray # 库存值 + d_values: np.ndarray # 用于求和的需求值 + ϕ_values: np.ndarray # 需求概率 + p: float # 需求参数 + c: float # 单位成本 + κ: float # 固定成本 + β: float # 贴现因子 +``` + +下面的函数使用默认参数构造一个 `Model` 实例。 + +出于计算目的,我们在 `D_MAX` 处截断需求分布。 + +```{code-cell} ipython3 +def create_sdd_inventory_model( + K: int = 20, # 最大库存 + D_MAX: int = 21, # 用于求和的需求上界 + p: float = 0.7, + c: float = 0.2, + κ: float = 0.8, + β: float = 0.98 + ) -> Model: + + def demand_pdf(p, d): + return (1 - p)**d * p + + d_values = np.arange(D_MAX) + ϕ_values = demand_pdf(p, d_values) # ϕ_0, ϕ_1,... + x_values = np.arange(K + 1) # 0, 1, ..., K + + return Model(x_values, d_values, ϕ_values, p, c, κ, β) +``` + +### 贝尔曼算子 + +核心计算是贝尔曼算子 $T$。 + +对于每个库存水平 $x$,我们遍历所有可行的订购数量 $a \in \{0, \ldots, K - x\}$,并计算期望值 + +$$ + \sum_d \phi(d) \left[ \min(x, d) - c \, a - \kappa \, \mathbf{1}\{a > 0\} + + \beta \, v\!\left(\max(x - d, 0) + a\right) \right]. +$$ + +然后我们对 $a$ 取最大值。 + +内层循环用 Numba 编译以提升性能。 + + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def T_kernel(v, d_values, ϕ_values, c, κ, β, K): + new_v = np.empty(K + 1) + for x in range(K + 1): + best = -np.inf + for a in range(K - x + 1): # 遍历可行动作 + val = 0.0 + for i in range(len(d_values)): # 计算关于需求的期望 + d = d_values[i] + x_next = max(x - d, 0) + a + revenue = min(x, d) + cost = c * a + κ * (a > 0) + val += ϕ_values[i] * (revenue - cost + β * v[x_next]) + if val > best: + best = val + new_v[x] = best + return new_v +``` + +包装函数 `T` 解包模型并调用已编译的内核。 + +```{code-cell} ipython3 +def T(v, model): + """贝尔曼算子。""" + x_values, d_values, ϕ_values, p, c, κ, β = model + K = len(x_values) - 1 + return T_kernel(v, d_values, ϕ_values, c, κ, β, K) +``` + + +### 计算贪婪策略 + +回想一下,给定值函数 $v$,**$v$-贪婪策略** 通过下式计算 + +$$ + \sigma(x) = \arg\max_{a \in \Gamma(x)} + \sum_d \phi(d) \left[ \pi(x, a, d) + \beta \, v(h(x, a, d)) \right]. +$$ + +其结构与贝尔曼算子相同,只是我们记录的是最大化动作而非最大化的值。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def get_greedy_kernel(v, d_values, ϕ_values, c, κ, β, K): + σ = np.empty(K + 1, dtype=np.int32) + for x in range(K + 1): + best = -np.inf + best_a = 0 + for a in range(K - x + 1): + val = 0.0 + for i in range(len(d_values)): + d = d_values[i] + x_next = max(x - d, 0) + a + revenue = min(x, d) + cost = c * a + κ * (a > 0) + val += ϕ_values[i] * (revenue - cost + β * v[x_next]) + if val > best: + best = val + best_a = a + σ[x] = best_a + return σ +``` + +```{code-cell} ipython3 +def get_greedy(v, model): + """获取一个 v-贪婪策略。""" + x_values, d_values, ϕ_values, p, c, κ, β = model + K = len(x_values) - 1 + return get_greedy_kernel(v, d_values, ϕ_values, c, κ, β, K) +``` + +### 值函数迭代 + +我们从 $v_0 = 0$ 开始迭代 $v_{k+1} = T v_k$ 直到收敛。 + +一旦值函数收敛(达到容差 `tol` 之内),我们通过 `get_greedy` 提取最优策略 $\sigma^*$。 + +```{code-cell} ipython3 +def solve_inventory_model(v_init, model, max_iter=10_000, tol=1e-6): + v = v_init.copy() + i, error = 0, tol + 1 + + while i < max_iter and error > tol: + new_v = T(v, model) + error = np.max(np.abs(new_v - v)) + i += 1 + v = new_v + + print(f"Converged in {i} iterations with error {error:.2e}") + + σ = get_greedy(v, model) + return v, σ +``` + +### 创建并求解一个实例 + +```{code-cell} ipython3 +model = create_sdd_inventory_model() +x_values, d_values, ϕ_values, p, c, κ, β = model +n_x = len(x_values) +v_init = np.zeros(n_x) +``` + +```{code-cell} ipython3 +v_star, σ_star = solve_inventory_model(v_init, model) +``` + +### 模拟最优策略 + +为了可视化解,我们在最优策略 $\sigma^*$ 下模拟库存过程。 + +在每一步,我们从几何分布中抽取一个需求冲击,并通过 $h$ 更新状态。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def sim_inventories(ts_length, σ, p, X_init=0, seed=0): + """在策略 σ 下模拟库存动态。""" + np.random.seed(seed) + X = np.zeros(ts_length, dtype=np.int32) + X[0] = X_init + for t in range(ts_length - 1): + d = np.random.geometric(p) - 1 + X[t+1] = max(X[t] - d, 0) + σ[X[t]] + return X +``` + +下面的图展示了在最优策略下的一条典型库存路径。 + +注意 **S-s 模式**:当库存降到较低水平时,公司下达一个大订单来补充库存(向上的跳跃),此后随着需求被满足,库存逐渐下降。 + +```{code-cell} ipython3 +def plot_ts(ts_length=200, fontsize=10): + X = sim_inventories(ts_length, σ_star, p) + fig, ax = plt.subplots() + + ax.plot(X, label=r"$X_t$", alpha=0.7) + ax.set_xlabel(r"$t$", fontsize=fontsize) + ax.set_ylabel("库存", fontsize=fontsize) + ax.legend(fontsize=fontsize, frameon=False) + ax.set_ylim(0, len(σ_star) + 1) + + plt.tight_layout() + plt.show() +``` + +```{code-cell} ipython3 +plot_ts() +``` + + +## Q 学习 + +现在我们要问:一个智能体能否在不知道模型的情况下**学习**最优策略? + +特别地,假设智能体不知道需求分布 $\phi$、成本参数 $c$ 和 $\kappa$,或转移函数 $h$。 + +相反,智能体只在与环境交互时观察到状态、动作和利润的序列。 + + +### Q 因子贝尔曼方程 + +Q 学习的第一步是修改贝尔曼方程,将其转化为一种能够从这些有限信息中学习的形式。 + +我们不再使用值函数 $v(x)$,而是使用 **Q 函数**(或 Q 因子)$q(x, a)$。 + +我们用值函数 $v^*$ 来定义 $q$,如下 + +$$ + q(x, a) := \mathbb E + \left[ + \pi(x, a, D) + \beta \, v^*(h(x, a, D)) + \right]. +$$ + +换句话说,$q(x, a)$ 是在状态 $x$ 中采取动作 $a$、此后遵循最优策略的期望值。 + +注意贝尔曼方程 {eq}`inventory_q_bellman` 可以写为 + +$$ + v^*(x) = \max_{a \in \Gamma(x)} q(x, a). +$$ + +将其代回 $q$ 的定义中,我们可以消去 $v^*$,得到一个仅关于 $q$ 的不动点方程: + +$$ + q(x, a) = \mathbb E + \left[ + \pi(x, a, D) + \beta \max_{a' \in \Gamma(x')} q(x', a') + \right] +$$ + +其中 $x' = h(x, a, D)$。 + +使用 $q$ 的一个优势是,最优策略可以直接读取为 $\sigma(x) = \arg\max_a q(x, a)$,而无需知道转移函数。 + + +### Q 学习更新规则 + +Q 学习使用 **[随机逼近](https://en.wikipedia.org/wiki/Stochastic_approximation)** 来逼近 Q 因子贝尔曼方程的不动点。 + +在每一步,智能体处于状态 $x$,采取动作 $a$,观察到奖励 $R_{t+1} = \pi(x, a, D_{t+1})$ 和下一状态 $X_{t+1} = h(x, a, D_{t+1})$,并更新 + +$$ + q_{t+1}(x, a) + = (1 - \alpha_t) q_t(x, a) + + \alpha_t \left(R_{t+1} + \beta \max_{a' \in \Gamma(X_{t+1})} q_t(X_{t+1}, a')\right) +$$ + +其中 $\alpha_t$ 是学习率。 + +该更新将当前估计 $q_t(x, a)$ 与贝尔曼目标的一个新样本混合。 + +### 经理需要知道什么 + +注意实现该更新**不**需要什么。 + +经理不需要知道需求分布 $\phi$、单位成本 $c$、固定成本 $\kappa$ 或转移函数 $h$。 + +经理在每一步只需观察: + +1. 当前库存水平 $x$, +2. 订购数量 $a$(由他们选择), +3. 由此产生的利润 $R_{t+1}$(记在账簿上), +4. 贴现因子 $\beta$(由利率决定),以及 +5. 下一期库存水平 $X_{t+1}$(他们可以从仓库读取)。 + +这些都是可直接观察的量——无需模型知识。 + + +### Q 表和最大值的作用 + +理解更新规则如何与经理的动作相关联很重要。 + +经理维护一个 **Q 表**——一个查找表,为每个状态-动作对 $(x, a)$ 存储一个估计 $q_t(x, a)$。 + +在每一步,经理处于某个状态 $x$,必须选择一个具体动作 $a$ 来采取。无论选择哪个 $a$,经理都会观察到利润 $R_{t+1}$ 和下一状态 $X_{t+1}$,并使用上述规则更新表中的*那一个条目* $q_t(x, a)$。 + +人们很容易把更新规则中的 $\max_{a'}$ 理解为规定经理的下一个动作——即把这个更新解读为"移动到状态 $X_{t+1}$ 并采取 $\argmax_{a'} q_t(X_{t+1}, a')$ 中的一个动作"。 + +但 $\max$ 起的是不同的作用。 + +量 $\max_{a' \in \Gamma(X_{t+1})} q_t(X_{t+1}, a')$ 只是在最佳可能延续下处于状态 $X_{t+1}$ 的价值的估计。 + +这个标量作为 $q_t(x, a)$ 的目标值的一部分进入更新。 + +经理在时间 $t+1 *实际采取* 哪个动作是一个单独的决策。 + +简而言之,$\max$ 起的是寻找最优的作用;它并不规定经理实际采取的动作。 + +### 行为策略 + +支配经理如何选择动作的规则称为**行为策略**。 + +因为更新目标中的 $\max$ 总是指向 $q^*$,无论经理如何选择动作,行为策略只影响哪些 $(x, a)$ 条目随时间被访问——从而被更新。 + +在强化学习文献中,这个性质称为**离策略**(off-policy)学习:收敛目标($q^*$)不依赖于行为策略。 + +只要每个 $(x, a)$ 对被无限次访问(这样 Q 表的每个条目都会收到无限多次更新),并且学习率满足标准条件(见下文),Q 表就会收敛到 $q^*$。 + +行为策略影响收敛的*速度*——更频繁地访问重要的状态-动作对会带来更快的学习——但不影响*极限*。 + +在实践中,我们希望经理大多数时候采取好的动作(在学习的同时赚取合理的利润),同时仍偶尔进行实验以发现更好的替代方案。 + +### 学习率 + +我们使用 $\alpha_t = 1 / n_t(x, a)^{0.51}$,其中 $n_t(x, a)$ 是到时间 $t$ 为止对 $(x, a)$ 对访问的次数。 + +它衰减得足够慢,允许从后期(信息更充分)的更新中学习,同时仍满足收敛的 [Robbins–Monro 条件](https://en.wikipedia.org/wiki/Stochastic_approximation#Robbins%E2%80%93Monro_algorithm)。 + + +### 探索:epsilon-贪婪 + +对于我们的行为策略,我们使用 $\varepsilon$-贪婪策略: + +- 以概率 $\varepsilon$,选择一个随机的可行动作(探索)。 +- 以概率 $1 - \varepsilon$,选择当前 $q$-值最高的动作(利用)。 + +探索确保每个状态-动作对都被访问,这是收敛所需要的。 + +利用确保经理在学习的同时赚取合理的利润。 + +我们每一步都衰减 $\varepsilon$:$\varepsilon_{t+1} = \max(\varepsilon_{\min},\; \varepsilon_t \cdot \lambda)$,因此经理在早期广泛实验,并随着经验的积累越来越依赖学习到的 $q$-值。 + +随机需求冲击自然地驱使经理经历不同的库存水平,从而在无需任何人为重置的情况下对状态空间进行探索。 + +### 乐观初始化 + +一个简单但强大的加速学习技术是**乐观初始化**:我们不从零开始初始化 Q 表,而是将每个条目初始化为高于真实最优值的值。 + +因为每个未尝试过的动作看起来都乐观地好,所以每当智能体尝试一个动作时都会"失望"——更新会将该条目向现实拉低。这促使智能体尝试其他动作(它们仍然看起来乐观地高),从而在训练早期产生对状态-动作空间的广泛探索。 + +这个思想有时被称为**面对不确定性时的乐观主义**,在老虎机和强化学习环境中都被广泛使用。 + +在我们的问题中,值函数 $v^*$ 的范围约为 13 到 18。我们将 Q 表初始化为 20——略高于真实最大值——以确保乐观探索,同时不至于极端到扭曲学习。 + +### 实现 + +我们首先定义一个辅助函数,用于从 Q 表中提取贪婪策略。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def greedy_policy_from_q(q, K): + """从 Q 表中提取贪婪策略。""" + σ = np.empty(K + 1, dtype=np.int32) + for x in range(K + 1): + best_val = -np.inf + best_a = 0 + for a in range(K - x + 1): + if q[x, a] > best_val: + best_val = q[x, a] + best_a = a + σ[x] = best_a + return σ +``` + +Q 学习循环在一条连续的轨迹中运行总共 `n_steps` 步——正如一位真实的经理会从持续不断的数据流中学习一样。 + +在指定的步数(由 `snapshot_steps` 给出)处,我们记录当前的贪婪策略。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def q_learning_kernel(K, p, c, κ, β, n_steps, X_init, + ε_init, ε_min, ε_decay, q_init, snapshot_steps, seed): + np.random.seed(seed) + q = np.full((K + 1, K + 1), q_init) + n = np.zeros((K + 1, K + 1)) # 用于学习率的访问计数 + ε = ε_init + + n_snaps = len(snapshot_steps) + snapshots = np.zeros((n_snaps, K + 1), dtype=np.int32) + snap_idx = 0 + + # 初始化状态和动作 + x = X_init + a = np.random.randint(0, K - x + 1) + + for t in range(n_steps): + # 如需要则记录策略快照 + if snap_idx < n_snaps and t == snapshot_steps[snap_idx]: + snapshots[snap_idx] = greedy_policy_from_q(q, K) + snap_idx += 1 + + # === 抽取 D_{t+1} 并观察结果 === + d = np.random.geometric(p) - 1 + reward = min(x, d) - c * a - κ * (a > 0) + x_next = max(x - d, 0) + a + + # === 对下一状态取最大值(用于更新目标的标量值)=== + # 同时记录 argmax 动作供行为策略使用。 + best_next = -np.inf + a_next = 0 + for aa in range(K - x_next + 1): + if q[x_next, aa] > best_next: + best_next = q[x_next, aa] + a_next = aa + + # === Q 学习更新(使用 best_next,即最大值)=== + n[x, a] += 1 + α = 1.0 / n[x, a] ** 0.51 + q[x, a] = (1 - α) * q[x, a] + α * (reward + β * best_next) + + # === 行为策略:ε-贪婪(使用 a_next,即 argmax 动作)=== + x = x_next + if np.random.random() < ε: + a = np.random.randint(0, K - x + 1) + else: + a = a_next + ε = max(ε_min, ε * ε_decay) + + return q, snapshots +``` + +包装函数解包模型并提供默认超参数。 + +```{code-cell} ipython3 +def q_learning(model, n_steps=20_000_000, X_init=0, + ε_init=1.0, ε_min=0.01, ε_decay=0.999999, + q_init=20.0, snapshot_steps=None, seed=1234): + x_values, d_values, ϕ_values, p, c, κ, β = model + K = len(x_values) - 1 + if snapshot_steps is None: + snapshot_steps = np.array([], dtype=np.int64) + return q_learning_kernel(K, p, c, κ, β, n_steps, X_init, + ε_init, ε_min, ε_decay, q_init, snapshot_steps, seed) +``` + +接下来我们运行 $n$ = 500 万步,并在第 10,000 步、第 1,000,000 步和第 $n$ 步处拍摄策略快照。 + +```{code-cell} ipython3 +n = 5_000_000 +snap_steps = np.array([10_000, 1_000_000, n], dtype=np.int64) +q, snapshots = q_learning(model, n_steps=n+1, snapshot_steps=snap_steps) +``` + +### 与精确解比较 + +我们通过下式从最终的 Q 表中提取值函数和策略 + +$$ + v_Q(x) = \max_{a \in \Gamma(x)} q(x, a), + \qquad + \sigma_Q(x) = \argmax_{a \in \Gamma(x)} q(x, a) +$$ + +并将它们与 VFI 得到的 $v^*$ 和 $\sigma^*$ 进行比较。 + +```{code-cell} ipython3 +K = len(x_values) - 1 +# 限制在可行动作 a ∈ {0, ..., K-x} +v_q = np.array([np.max(q[x, :K - x + 1]) for x in range(K + 1)]) +σ_q = np.array([np.argmax(q[x, :K - x + 1]) for x in range(K + 1)]) +``` + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].plot(x_values, v_star, label="VFI") +axes[0].plot(x_values, v_q, '--', label="Q 学习") +axes[0].set_xlabel("库存") +axes[0].set_ylabel("价值") +axes[0].legend() +axes[0].set_title("值函数") + +axes[1].plot(x_values, σ_star, label="VFI") +axes[1].plot(x_values, σ_q, '--', label="Q 学习") +axes[1].set_xlabel("库存") +axes[1].set_ylabel("订购数量") +axes[1].legend() +axes[1].set_title("策略") + +plt.tight_layout() +plt.show() +``` + +### 可视化随时间的学习 + +下面的面板展示了智能体的行为在训练过程中如何演变。 + +每个面板使用从给定训练步骤的 Q 表中提取的贪婪策略来模拟一条库存路径。 + +所有面板使用**相同的需求序列**(通过固定的随机种子),因此差异仅反映策略的变化。 + +顶部面板展示了 VFI 得到的最优策略作为参考。 + +在 10,000 步后,智能体几乎没有探索,其策略很差。 + +到 1,000,000 步时,策略已有所改进,但仍与最优策略有明显差异。 + +到第 500 万步时,学习到的策略产生的库存动态与最优解的 S-s 模式非常相似。 + +```{code-cell} ipython3 +ts_length = 200 +n_snaps = len(snap_steps) +fig, axes = plt.subplots(n_snaps + 1, 1, figsize=(10, 2.5 * (n_snaps + 1)), + sharex=True) + +X_init = K // 2 +sim_seed = 5678 + +# 最优策略 +X_opt = sim_inventories(ts_length, σ_star, p, X_init, seed=sim_seed) +axes[0].plot(X_opt, alpha=0.7) +axes[0].set_ylabel("库存") +axes[0].set_title("最优 (VFI)") +axes[0].set_ylim(0, K + 2) + +# Q 学习快照 +for i in range(n_snaps): + σ_snap = snapshots[i] + X = sim_inventories(ts_length, σ_snap, p, X_init, seed=sim_seed) + axes[i + 1].plot(X, alpha=0.7) + axes[i + 1].set_ylabel("库存") + axes[i + 1].set_title(f"第 {snap_steps[i]:,} 步") + axes[i + 1].set_ylim(0, K + 2) + +axes[-1].set_xlabel(r"$t$") +plt.tight_layout() +plt.show() +``` \ No newline at end of file diff --git a/lectures/kalman_filter_var.md b/lectures/kalman_filter_var.md new file mode 100644 index 0000000..596fb9b --- /dev/null +++ b/lectures/kalman_filter_var.md @@ -0,0 +1,1303 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.11.1 +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 卡尔曼滤波器与向量自回归 + headings: + Overview: 概述 + The state space system: 状态空间系统 + The Kalman filter: 卡尔曼滤波器 + The Kalman filter::Starting distribution: 起始分布 + The Kalman filter::Derivation: 推导 + The Kalman filter::The Kalman filter recursions: 卡尔曼滤波器的递归 + The Kalman filter::The matrix Riccati equation: 矩阵黎卡提方程 + The Gram-Schmidt process: Gram-Schmidt 过程 + Hidden Markov model: 隐马尔可夫模型 + Estimation: 估计 + Estimation::The innovations representation: 新息表示 + Estimation::The likelihood function: 似然函数 + Estimation::Bayesian inference: 贝叶斯推断 + Vector autoregressions and the Kalman filter: 向量自回归与卡尔曼滤波器 + Vector autoregressions and the Kalman filter::Convergence to a steady state: 收敛到稳态 + Vector autoregressions and the Kalman filter::A time-invariant VAR: 一个时不变 VAR + Vector autoregressions and the Kalman filter::Interpreting VARs: 解释 VAR + Spectral factorization identity: 谱分解恒等式 + Spectral factorization identity::Two representations of the spectral density: 谱密度的两种表示 + Spectral factorization identity::The spectral factorization identity: 谱分解恒等式 + Spectral factorization identity::Wold and autoregressive representations: Wold 表示和自回归表示 + Python implementation: Python 实现 + Python implementation::A scalar hidden AR(1) model: 一个标量隐藏 AR(1) 模型 + Python implementation::Convergence of the Riccati equation: 黎卡提方程的收敛 + Python implementation::The VAR representation: VAR 表示 + Python implementation::Likelihood evaluation: 似然评估 + An example: 一个例子 + An example::A linear state-space system and its filter: 一个线性状态空间系统及其滤波器 + An example::Impulse responses of $y_t$ to the innovations $a_t$: $y_t$ 对新息 $a_t$ 的脉冲响应 + An example::Bivariate VAR(2) in state-space form: 状态空间形式的二元 VAR(2) + 'An example::Numerical example: impulse responses to innovations': 数值例子:对新息的脉冲响应 + Summary: 总结 + Exercises: 练习 +--- + +# 卡尔曼滤波器与向量自回归 + +```{index} single: Kalman Filter +``` + +```{index} single: Vector Autoregression; and Kalman filter +``` + +除了 Anaconda 中已有的库之外,本讲座还需要以下库: + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install quantecon +``` + +## 概述 + +本讲座为线性高斯状态空间系统推导**卡尔曼滤波器**,然后用它来构建**向量自回归(VAR)**。 + +它建立在 {doc}`kalman` 之上,在那里滤波器是通过滤波分布和预测分布引入的。 + +它补充了 {doc}`kalman_2`,在那里同样的递归被用于一个工人-企业学习问题中。 + +本讲座将注意力从对隐藏状态的滤波,转移到表示和估计由该隐藏状态所生成的可观测过程。 + +我们的方法依赖于反复应用**总体线性最小二乘**投影公式,其核心洞见是:计算一个联合正态随机向量的条件期望,等同于运行一个总体普通最小二乘法回归。 + +本讲座涵盖: + +- 从第一性原理推导卡尔曼滤波器的递归 +- 支配条件协方差矩阵的**矩阵黎卡提差分方程** +- **新息表示**以及 **Gram-Schmidt** 白化性质 +- **隐马尔可夫模型**的结构 +- 状态空间系统的**似然函数**及其在最大似然估计和贝叶斯估计中的作用 +- 时不变卡尔曼滤波器如何生成一个**向量自回归** +- 为什么卡尔曼滤波器是*解释*由经济数据估计得到的 *VAR* 的一个基本工具 + +## 状态空间系统 + +卡尔曼滤波器适用于以下针对 $t \geq 0$ 的**状态空间系统**: + +$$ +\begin{aligned} +x_{t+1} &= A x_t + C w_{t+1} \\ +y_t &= G x_t + v_t +\end{aligned} +$$ (eq:statespace) + +其中 + +- $x_t$ 是一个 $n \times 1$ 的**状态向量**(隐藏的、不可观测的) +- $y_t$ 是一个关于隐藏状态的 $m \times 1$ **信号**向量(可观测的) +- $w_{t+1}$ 是一个 $p \times 1$ 的独立同分布的正态随机变量序列,均值为 + $0$,协方差矩阵为单位矩阵 +- $v_t$ 是一个独立同分布的正态随机变量序列,均值为零,协方差矩阵为 $R$ +- 对所有 $t+1$ 和 $s \geq 0$,$w_{t+1}$ 与 $v_s$ 正交 + +系数矩阵具有以下维度: +$A$ 是 $n \times n$,$C$ 是 $n \times p$,$G$ 是 $m \times n$,$R$ 是 $m \times m$。 + +初始状态满足 + +$$ +x_0 \sim N(\hat{x}_0, \Sigma_0) +$$ (eq:kalf3) + +在时刻 $t$,我们观测到 $y_t, \ldots, y_0$ 而*不能*观测到 $x_t, \ldots, x_0$, +并且我们知道由 {eq}`eq:statespace` 和 {eq}`eq:kalf3` 所隐含的所有一阶矩和二阶矩。 + +## 卡尔曼滤波器 + +### 起始分布 + +从 $t = 0$ 开始沿时间向前推进,在观测到 $y_0$ 之前, +设定 {eq}`eq:statespace`-{eq}`eq:kalf3` 意味着 $y_0$ 的边缘分布为 + +$$ +y_0 \sim N(G \hat{x}_0,\; G \Sigma_0 G^\top + R) +$$ (eq:kalf4) + +对于 $t \geq 0$,令 $y^t = [y_t, y_{t-1}, \ldots, y_0]$。 + +我们想要一个便于表示的、关于 $y_t$ 在给定历史 $y^{t-1}$ 条件下的条件分布的递归表示。 + +卡尔曼滤波器通过为 $\hat{x}_t$ 和 $\Sigma_t$ 构造递归公式来实现这一点,使得在 $y^{t-1}$ 条件下 $y_t$ 的分布将 {eq}`eq:kalf4` 推广为 + +$$ +y_t \sim N(G \hat{x}_t,\; G \Sigma_t G^\top + R) +$$ (eq:kalf400) + +其中 $t \geq 1$,而在 $y^{t-1}$ 条件下 $x_t$ 的分布为 $N(\hat{x}_t, \Sigma_t)$。 + +对象 $\hat{x}_t$ 和 $\Sigma_t$ 刻画了**总体回归** + +$$ +\hat{x}_t = \mathbb{E}[x_t \mid y_{t-1}, \ldots, y_0] +$$ + +以及**条件协方差矩阵** + +$$ +\Sigma_t = \mathbb{E}\!\left[(x_t - \hat{x}_t)(x_t - \hat{x}_t)^\top \mid y_{t-1}, \ldots, y_0\right] +$$ + +### 推导 + +在每个时刻,我们的方法是*将我们所不知道的对我们所知道的进行回归*。 + +```{note} +因为我们的假设意味着 $\{x_t, y_t\}_{t=0}^\infty$ 是一个联合正态随机过程,所以线性最小二乘回归等于条件数学期望。 + +下面每一步都是对贝叶斯法则的应用。 + +在没有联合正态性、只假设所有均值和协方差存在的较弱假设下,同样的计算得到"广义条件期望",只有当这些条件期望是线性的时候它们才与真正的条件期望一致。 +``` + +我们在 $t = 0$ 时刻已知 $\hat{x}_0$ 和 $\Sigma_0$。 + +$y_0$ 中相对于 $(\hat{x}_0, \Sigma_0)$ 关于 $x_0$ 的新信息即为**新息** + +$$ +a_0 \equiv y_0 - G \hat{x}_0 +$$ + +令 $L_0$ 为隐藏状态误差 $x_0-\hat{x}_0$ 对信号意外 $y_0-G\hat{x}_0$ 的总体回归系数。 + +条件均值 +$\mathbb{E}[x_0 \mid y_0] = \hat{x}_0 + L_0(y_0 - G\hat{x}_0)$ 满足总体回归公式 + +$$ +x_0 - \hat{x}_0 = L_0(y_0 - G\hat{x}_0) + \eta +$$ (eq:kalf5) + +其中 $\eta$ 是最小二乘残差。 + +$\eta$ 与 $(y_0 - G\hat{x}_0)$ 的正交性通过正规方程确定了 $L_0$ + +$$ +\mathbb{E}(x_0 - \hat{x}_0)(y_0 - G\hat{x}_0)^\top += L_0\, \mathbb{E}(y_0 - G\hat{x}_0)(y_0 - G\hat{x}_0)^\top +$$ + +计算矩矩阵并求解 $L_0$ 得到 + +$$ +L_0 = \Sigma_0 G^\top(G \Sigma_0 G^\top + R)^{-1} +$$ (eq:kalf6) + +因此 $L_0$ 更新对 $x_0$ 的估计,而 $K_0=A L_0$ 更新对 $x_1$ 的预测。 + +为了预测 $x_1$,注意 + +$$ +x_1 = A\hat{x}_0 + A(x_0 - \hat{x}_0) + C w_1 +$$ (eq:kalf6a) + +应用 {eq}`eq:kalf5` 得到 $\mathbb{E}[x_1 \mid y_0] = A\hat{x}_0 + AL_0(y_0 - G\hat{x}_0)$, +我们将其写为 + +$$ +\hat{x}_1 = A\hat{x}_0 + K_0(y_0 - G\hat{x}_0) +$$ (eq:kalf7) + +其中时刻 0 的**卡尔曼增益**为 + +$$ +K_0 = A \Sigma_0 G^\top(G \Sigma_0 G^\top + R)^{-1} +$$ (eq:kalf7a) + +将 {eq}`eq:kalf7` 从 {eq}`eq:kalf6a` 中减去得到 + +$$ +x_1 - \hat{x}_1 = A(x_0 - \hat{x}_0) + C w_1 - K_0(y_0 - G\hat{x}_0) +$$ (eq:kalf8) + +利用 {eq}`eq:kalf8` 和 $y_0 = G x_0 + v_0$ 来计算 +$\Sigma_1 \equiv \mathbb{E}[(x_1 - \hat{x}_1)(x_1 - \hat{x}_1)^\top \mid y_0]$ 得到 + +$$ +\Sigma_1 = (A - K_0 G)\Sigma_0(A - K_0 G)^\top + CC^\top + K_0 R K_0^\top +$$ (eq:kalf9) + +因此 $f(x_1 \mid y_0) \sim N(\hat{x}_1, \Sigma_1)$。 + +收集时刻 $0$ 的方程: + +$$ +\begin{aligned} +a_0 &= y_0 - G\hat{x}_0 \\ +K_0 &= A\Sigma_0 G^\top(G\Sigma_0 G^\top + R)^{-1} \\ +\hat{x}_1 &= A\hat{x}_0 + K_0 a_0 \\ +\Sigma_1 &= CC^\top + K_0 R K_0^\top + (A - K_0 G)\Sigma_0(A - K_0 G)^\top +\end{aligned} +$$ (eq:kalf1000) + +系统 {eq}`eq:kalf1000` 将一个均值-协方差对 $(\hat{x}_0, \Sigma_0)$ 映射为一个新的对 $(\hat{x}_1, \Sigma_1)$,并带有辅助输出 $(a_0, K_0)$。 + +认识到"我们在第 1 期开始时所处的情形与第 0 期开始时相同"激活了一个递归,即**卡尔曼滤波器**。 + +### 卡尔曼滤波器的递归 + +迭代系统 {eq}`eq:kalf1000` 得到针对 $t \geq 0$ 的卡尔曼滤波器: + +$$ +\begin{aligned} +a_t &= y_t - G\hat{x}_t \\ +K_t &= A\Sigma_t G^\top(G\Sigma_t G^\top + R)^{-1} \\ +\hat{x}_{t+1} &= A\hat{x}_t + K_t a_t \\ +\Sigma_{t+1} &= CC^\top + K_t R K_t^\top + (A - K_t G)\Sigma_t(A - K_t G)^\top +\end{aligned} +$$ (eq:kalf10) + +这里 $K_t$ 是时刻 $t$ 的**卡尔曼增益**。 + +### 矩阵黎卡提方程 + +将 {eq}`eq:kalf10` 第二行中 $K_t$ 的表达式代入第四行,得到一个等价的更新公式: + +$$ +\Sigma_{t+1} = A\Sigma_t A^\top + CC^\top + - A\Sigma_t G^\top(G\Sigma_t G^\top + R)^{-1} G\Sigma_t A^\top +$$ (eq:riccati) + +方程 {eq}`eq:riccati` 是**矩阵黎卡提差分方程**。 + +它支配着条件协方差矩阵序列 $\{\Sigma_t\}_{t=0}^\infty$,而不涉及观测值 $\{y_t\}$。 + +```{index} single: Riccati equation; matrix difference +``` + +## Gram-Schmidt 过程 + +随机向量 + +$$ +a_t = y_t - \mathbb{E}[y_t \mid y_{t-1}, \ldots, y_0] +$$ + +是 $y_t$ 相对于 $y^{t-1}$ 的**新息**,即 $y_t$ 中无法由过去观测预测的部分。 + +注意 $\mathbb{E} a_t a_t^\top = G\Sigma_t G^\top + R$,即在卡尔曼增益公式 {eq}`eq:kalf10` 中其逆矩阵出现的那个矩阵。 + +利用 $a_t = G(x_t - \hat{x}_t) + v_t$ 直接计算可以表明 +$\mathbb{E} a_t a_{t-1}^\top = 0$,更一般地,$\mathbb{E}[a_t \mid a_{t-1}, \ldots, a_0] = 0$。 + +```{note} +一个从第一性原理出发的替代论证:令 $H(y^t)$ 表示 $y^t$ 的闭线性张成空间。 + +由于 $a_{t+1} = y_{t+1} - \mathbb{E}[y_{t+1} \mid y^t]$ 是一个最小二乘误差,$a_{t+1} \perp H(y^t)$,特别地 $a_{t+1} \perp a_t$。 + +因此 $\{a_t\}$ 是关于 $\{y_t\}$ 的一个白噪声新息过程。 +``` + +有时 {eq}`eq:kalf10` 被称为**白化滤波器**:它以信号过程 $\{y_t\}$ 为输入,并产生白噪声新息过程 $\{a_t\}$ 作为输出。 + +类似地定义 $H(a^t)$,线性空间 $H(a^t)$ 是线性空间 $H(y^t)$ 的一个正交基。 + +卡尔曼滤波器不是通过一个大的回归来计算 $\mathbb{E}[x_t \mid y_{t-1}, \ldots, y_0]$,而是对基 $[a_{t-1}, \ldots, a_0]$ 的一系列相继正交分量执行一系列小回归,这是 **Gram-Schmidt 过程**的一个实例。 + +```{index} single: Gram-Schmidt process +``` + +## 隐马尔可夫模型 + +系统 {eq}`eq:statespace`-{eq}`eq:kalf3` 是一个**隐马尔可夫模型**的例子。 + +```{index} single: hidden Markov model +``` + +可观测过程 $\{y_t\}_{t=0}^\infty$ *不是*马尔可夫的,但隐藏过程 $\{x_t\}_{t=0}^\infty$ *是*马尔可夫的。 + +均值和协方差过程 $\{(\hat{x}_t, \Sigma_t)\}$ 也是马尔可夫的,它们是在 $[y_{t-1}, \ldots, y_0]$ 条件下 $x_t$ 分布的充分统计量。 + +## 估计 + +### 新息表示 + +从卡尔曼滤波器中产生的**新息表示**为 + +$$ +\begin{aligned} +\hat{x}_{t+1} &= A\hat{x}_t + K_t a_t \\ +y_t &= G\hat{x}_t + a_t +\end{aligned} +$$ (eq:innovrep) + +其中对于 $t \geq 1$ 有 $\hat{x}_t = \mathbb{E}[x_t \mid y^{t-1}]$,且 +$\mathbb{E}[a_t a_t^\top \mid y^{t-1}] = G\Sigma_t G^\top + R \equiv \Omega_t$。 + +对于 $t \geq 1$,$\mathbb{E}[y_t \mid y^{t-1}] = G\hat{x}_t$,且在给定 $y^{t-1}$ 条件下 $y_t$ 的条件分布为 $N(G\hat{x}_t, \Omega_t)$。 + +因此,从卡尔曼滤波器递归中产生的对象 $(G\hat{x}_t, \Omega_t)$ 完全刻画了这个条件分布。 + +### 似然函数 + +我们可以将样本 $(y_T, y_{T-1}, \ldots, y_0)$ 的似然分解为 + +$$ +f(y_T, \ldots, y_0) + = f(y_T \mid y^{T-1})\, f(y_{T-1} \mid y^{T-2}) \cdots f(y_1 \mid y_0)\, f(y_0) +$$ (eq:diff100) + +$m \times 1$ 向量 $y_t$ 的对数条件密度为 + +$$ +\log f(y_t \mid y^{t-1}) + = -\frac{m}{2}\log(2\pi) + - \frac{1}{2}\log\det(\Omega_t) + - \frac{1}{2}\, a_t^\top \Omega_t^{-1} a_t +$$ (eq:gauss100) + +同时使用 {eq}`eq:gauss100` 和 {eq}`eq:kalf10`,我们可以对任何构成矩阵 $A, G, C, R$ 基础的参数向量 $\theta$ 递归地计算似然 {eq}`eq:diff100`。 + +此类计算是高效计算自由参数的**最大似然估计**策略的核心。 + +### 贝叶斯推断 + +似然函数在**贝叶斯推断**中也是核心。 + +其中 $\theta$ 是参数向量,$y_0^T$ 是数据,$\tilde{p}(\theta)$ 是在看到 $y_0^T$ 之前关于 $\theta$ 的先验密度,贝叶斯法则给出**后验** + +$$ +\tilde{p}(\theta \mid y_0^T) + = \frac{f(y_0^T \mid \theta)\,\tilde{p}(\theta)} + {\int f(y_0^T \mid \theta)\,\tilde{p}(\theta)\, d\theta} +$$ + +分母是边缘联合密度 $f(y_0^T)$。 + +## 向量自回归与卡尔曼滤波器 + +### 收敛到稳态 + +在 {cite:t}`AHMS1996` 所讨论的条件下,对黎卡提方程 {eq}`eq:riccati` 的迭代从任何正半定初始值 $\Sigma_0$ 出发都收敛到一个**时不变**矩阵 $\Sigma$。 + +{eq}`eq:riccati` 的一个时不变不动点 $\Sigma_t = \Sigma$ 是 $x_t$ 围绕 + +$$ +\mathbb{E}\!\left[x_t \mid \{y_s\}_{s \leq t-1}\right] +$$ + +的协方差矩阵,其中条件作用扩展到**半无限**的过去 $s \leq t-1$。 + +### 一个时不变 VAR + +如果不动点 $\Sigma$ 存在,且我们在 $\Sigma_0 = \Sigma$ 处初始化滤波器,则新息表示 {eq}`eq:innovrep` 变为时不变: + +$$ +\begin{aligned} +\hat{x}_{t+1} &= A\hat{x}_t + K a_t \\ +y_t &= G\hat{x}_t + a_t +\end{aligned} +$$ (eq:innovti) + +其中 $\mathbb{E} a_t a_t^\top = G\Sigma G^\top + R$,且**稳态卡尔曼增益**为 +$K = A\Sigma G^\top(G\Sigma G^\top + R)^{-1}$。 + +从 {eq}`eq:innovti` 我们得到 $\hat{x}_{t+1} = (A - KG)\hat{x}_t + K y_t$。 + +如果 $A - KG$ 的特征值的模严格有界地低于 1,我们可以向前求解此方程得到 + +$$ +\hat{x}_{t+1} = \sum_{j=0}^\infty (A - KG)^j K\, y_{t-j} +$$ (eq:xhatform) + +将 {eq}`eq:xhatform` 代入 {eq}`eq:innovti` 的观测方程,得到**向量自回归** + +$$ +y_t = G \sum_{j=0}^\infty (A - KG)^j K\, y_{t-j-1} + a_t +$$ (eq:var1) + +由构造可知 + +$$ +\mathbb{E}\!\left[a_t\, y_{t-j-1}^\top\right] = 0 \quad \forall\, j \geq 0 +$$ (eq:varorth) + +正交条件 {eq}`eq:varorth` 将 {eq}`eq:var1` 识别为一个向量自回归。 + +通过 $L x_{t+1} \equiv x_t$ 定义滞后算子 $L$,由 {eq}`eq:innovti` 推导出的**移动平均表示**为 + +$$ +y_t = \left[I + G(I - AL)^{-1} KL\right] a_t + = \left[I + G\sum_{j=0}^\infty A^j K L^{j+1}\right] a_t +$$ + +```{index} single: vector autoregression +``` + +### 解释 VAR + +经济模型的均衡(或它们的线性或对数线性近似)通常采用状态空间系统 {eq}`eq:statespace` 的形式。 + +这个隐马尔可夫模型通过 $p \times 1$ 冲击向量 $w_{t+1}$ 扰动状态 $x_t$,并通过 $m \times 1$ 测量误差 $v_t$ 扰动可观测量的 $m \times 1$ 向量 $y_t$。 + +一个经济理论通常使得 $w_{t+1}$ 和 $v_t$ 可以直接被解释为对偏好、技术、禀赋或信息集的冲击。 + +状态空间系统 {eq}`eq:statespace` 用这些**可解释的冲击**来表示 $\{y_t\}$。 + +然而,在通常情形下,即使 $A, G, C, R$ 已知,这些冲击也*不能*直接从 $y_t$ 中恢复出来。 + +新息表示 {eq}`eq:innovti` 用 $m \times 1$ 新息向量 $a_t$ 来表示*同一个*随机过程 $\{y_t\}$,这些新息可以通过运行无限阶总体向量自回归来恢复。 + +它在将原始表示 {eq}`eq:statespace` 映射到 VAR {eq}`eq:var1` 中的作用,使得卡尔曼滤波器成为*解释向量自回归*不可或缺的工具。 + +```{index} single: Kalman Filter; and vector autoregressions +``` + +## 谱分解恒等式 + +```{index} single: spectral factorization identity +``` + +因为原始状态空间系统 {eq}`eq:statespace` 和新息表示 {eq}`eq:innovti` 描述的是*同一个*随机过程 $\{y_t\}$,它们对 $\{y_t\}$ 的**谱密度矩阵**给出了两个不同的公式。 + +令这两个公式相等就得到*谱分解恒等式*。 + +### 谱密度的两种表示 + +首先考虑原始状态空间系统。 + +将 {eq}`eq:statespace` 的第一行写为 +$x_t = (zI - A)^{-1} C w_{t+1}$(使用 $z$ 变换约定 +$z^{-1} x_t = x_{t-1}$),$\{x_t\}$ 的协方差生成函数为 + +$$ +S_x(z) = (zI - A)^{-1} CC^\top (z^{-1}I - A^\top)^{-1}. +$$ + +由于 $v_t$ 与 $x_t$ 正交,$\{y_t\}$ 的谱密度为 + +$$ +S_y(z) = G(zI - A)^{-1} CC^\top (z^{-1}I - A^\top)^{-1} G^\top + R. +$$ (eq:sf_original) + +现在考虑新息表示。 + +时不变新息表示 {eq}`eq:innovti` 给出 +$y_t = [G(zI - A)^{-1}K + I]\, a_t$。 + +由于 $a_t$ 是协方差矩阵为 $G\Sigma G^\top + R$ 的白噪声,谱密度也为 + +$$ +S_y(z) = \bigl[G(zI-A)^{-1}K + I\bigr] + \bigl(G\Sigma G^\top + R\bigr) + \bigl[K^\top(z^{-1}I - A^\top)^{-1}G^\top + I\bigr]. +$$ (eq:sf_innov) + +### 谱分解恒等式 + +令 {eq}`eq:sf_original` 和 {eq}`eq:sf_innov` 相等,得到**谱分解恒等式**: + +$$ +G(zI - A)^{-1} CC^\top (z^{-1}I - A^\top)^{-1} G^\top + R = +\bigl[G(zI-A)^{-1}K + I\bigr] +\bigl(G\Sigma G^\top + R\bigr) +\bigl[K^\top(z^{-1}I - A^\top)^{-1}G^\top + I\bigr]. +$$ (eq:sf_identity) + +左侧用**结构性冲击** $(w_{t+1}, v_t)$ 和矩阵 $(A, C, G, R)$ 表示 $S_y(z)$。 + +右侧将同一对象表示为由新息 $a_t$ 和稳态卡尔曼增益 $K$ 构建的谱因子。 + +### Wold 表示和自回归表示 + +从新息表示 {eq}`eq:innovti` 出发,我们既可以得到 Wold 移动平均表示,也可以得到自回归表示。 + +对于 Wold 表示,迭代 {eq}`eq:innovti` 中的状态方程,用当前和过去的新息表示当前观测。 + +用 $L$ 表示滞后算子,{eq}`eq:innovti` 意味着 + +$$ +y_t = \left[I + G(I - AL)^{-1} K L\right] a_t +$$ (eq:sf_wold) + +这是用 $\{y_t\}$ 的一步预测误差表示的 Wold 移动平均表示。 + +对于自回归表示,将 {eq}`eq:sf_wold` 中的移动平均算子求逆,并用当前和过去的观测来求解 $a_t$。 + +利用恒等式 + +$$ +\left[I + G(I - AL)^{-1} K L\right]^{-1} + = I - G\left[I - (A - KG)L\right]^{-1} K L +$$ + +得到 + +$$ +y_t = G\bigl[I-(A-KG)L\bigr]^{-1}K\, y_{t-1} + a_t + = \sum_{j=1}^\infty G(A-KG)^{j-1}K\, y_{t-j} + a_t, +$$ (eq:sf_var) + +这就是已在 {eq}`eq:var1` 中陈述的向量自回归。 + +关键的分析事实是:在温和的稳定性条件下,$\det[G(zI-A)^{-1}K + I]$ 的零点全部位于单位圆*内部*。 + +这确保了 {eq}`eq:sf_wold` 中的移动平均算子有一个因果的单边逆。 + +因此 $a_t$ 位于当前和过去观测 $y^t$ 的闭线性张成空间中,所以 $a_t$ 是 VAR 中的总体预测误差。 + +## Python 实现 + +我们现在使用 `quantecon` 库来说明该理论,它提供了 `LinearStateSpace` 和 `Kalman` 类,实现了上面推导的所有内容。 + +我们使用以下导入: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +import quantecon as qe +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +### 一个标量隐藏 AR(1) 模型 + +考虑一个带有测量噪声观测的标量隐藏 AR(1) 状态: + +$$ +\begin{aligned} +x_{t+1} &= \rho\, x_t + \sigma_w\, w_{t+1} \\ +y_t &= x_t + \sigma_v\, v_t +\end{aligned} +$$ + +其中 $w_t, v_t \sim N(0, 1)$ 独立同分布。 + +这里 $\rho$ 是持续性参数,而 $\sigma_w$ 和 $\sigma_v$ 是冲击标准差。 + +`LinearStateSpace` 类通过矩阵 $H$ 来参数化测量噪声,使得 $R = HH^\top$。 + +```{code-cell} ipython3 +# 模型参数 +ρ = 0.9 +σ_w = 0.5 +σ_v = 1.0 + +# 状态空间矩阵 +A = np.array([[ρ]]) +C = np.array([[σ_w]]) +G = np.array([[1.0]]) +R = np.array([[σ_v**2]]) + +# 构建一个 LinearStateSpace 和一个 Kalman 滤波器对象 +H = np.array([[σ_v]]) # 测量噪声因子: R = H @ H.T +lss = qe.LinearStateSpace( + A, C, G, H, mu_0=np.zeros(1), Sigma_0=np.eye(1) * 10.0) +kf = qe.Kalman(lss) +kf.set_state(np.zeros(1), np.eye(1) * 10.0) # 弥散先验 +``` + +我们首先模拟一条真实隐藏状态和带噪声观测的样本路径。 + +```{code-cell} ipython3 +T = 200 +x_path, y_path = lss.simulate(ts_length=T, random_state=42) + +# 形状: x_path 是 (n, T+1), y_path 是 (m, T) +x_true = x_path[0, :T] +y_obs = y_path[0, :] +``` + +然后我们手动逐步运行卡尔曼滤波器,以收集滤波后的估计值。 + +```{code-cell} ipython3 +x_hats = np.zeros(T) +Sigmas = np.zeros(T) + +for t in range(T): + kf.update(y_obs[t:t+1]) # 一个完整的滤波周期 + x_hats[t] = kf.x_hat.item() + Sigmas[t] = kf.Sigma.item() +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 标量卡尔曼滤波 + name: fig-kfvar-scalar +--- +fig, axes = plt.subplots(3, 1, figsize=(10, 8), sharex=True) + +t_range = np.arange(T) + +axes[0].plot(t_range, x_true, lw=2, + label='真实状态 $x_t$') +axes[0].plot(t_range, x_hats, lw=2, + linestyle='--', label=r'$\hat{x}_t$ (卡尔曼)') +axes[0].plot(t_range, y_obs, alpha=0.35, lw=2, label='观测 $y_t$') +axes[0].set_title('状态与观测') +axes[0].legend(fontsize=9) + +axes[1].plot(t_range, Sigmas, color='C1', lw=2, + label=r'条件方差 $\Sigma_t$') +axes[1].axhline(kf.Sigma_infinity[0, 0], ls='--', color='k', + label=r'稳态 $\Sigma_\infty$') +axes[1].set_title('条件方差') +axes[1].legend(fontsize=9) + +axes[2].plot(t_range, y_obs - x_hats, color='C2', lw=2, alpha=0.7, + label=r'新息 $a_t = y_t - G\hat{x}_t$') +axes[2].set_title('新息') +axes[2].set_xlabel('时间 $t$') +axes[2].legend(fontsize=9) +fig.tight_layout() +plt.show() +``` + +经过短暂的调整后,卡尔曼估计比原始的带噪声观测更紧密地跟随隐藏状态。 + +条件方差从弥散先验迅速下降,然后稳定到其稳态值。 + +新息序列围绕零波动,正如一步预测误差所应有的那样。 + +### 黎卡提方程的收敛 + +`Kalman` 类通过直接求解离散代数黎卡提方程来计算稳态协方差 $\Sigma_\infty$。 + +```{code-cell} ipython3 +Sigma_inf, K_inf = kf.stationary_values() + +print(f"Steady-state covariance Σ_inf = {Sigma_inf[0, 0]:.6f}") +print(f"Kalman filter converged to Σ_t = {Sigmas[-1]:.6f}") +print(f"Steady-state Kalman gain K = {K_inf[0, 0]:.6f}") + +A_minus_KG = A - K_inf @ G +eigval = np.linalg.eigvals(A_minus_KG)[0] +print(f"\nEigenvalue of (A - KG) = {eigval:.6f}") +print(f"Stable VAR: {np.abs(eigval) < 1}") +``` + +### VAR 表示 + +利用 {eq}`eq:var1`,无限阶 VAR 表示中的系数为 +$G(A - KG)^j K$,其中 $j = 0, 1, 2, \ldots$ + +我们通过 `stationary_coefficients` 来获取它们: + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 来自新息表示的 VAR 系数 + name: fig-kfvar-varcoef +--- +J = 30 +var_coeffs = kf.stationary_coefficients(J, coeff_type='var') + +# 滞后 j+1 的系数矩阵 +lags = np.arange(1, J + 1) +coeff_values = np.array([var_coeffs[j][0, 0] for j in range(J)]) + +fig, ax = plt.subplots() +ax.stem(lags, coeff_values, basefmt=' ') +ax.set_xlabel('滞后 $j$') +ax.set_ylabel(r'VAR 系数 $G(A{-}KG)^{j-1}K$') +fig.tight_layout() +plt.show() +``` + +大部分自回归权重集中在前几个滞后上。 + +后面的系数几乎为零,因此在这个例子中,一个短的有限滞后 VAR 就捕获了无限阶表示的大部分。 + +### 似然评估 + +我们使用 {eq}`eq:gauss100` 来计算模拟样本的对数似然。 + +```{code-cell} ipython3 +def log_likelihood(A, C, G, R, y_data, x_hat_0, Sigma_0): + """使用卡尔曼滤波器递归计算对数似然。""" + H_ = np.linalg.cholesky(R) # R = H_ @ H_.T + lss_ = qe.LinearStateSpace(A, C, G, H_, mu_0=x_hat_0, Sigma_0=Sigma_0) + kf_ = qe.Kalman(lss_) + kf_.set_state(x_hat_0, Sigma_0) + + T_, m_ = y_data.shape + loglik = 0.0 + + for t in range(T_): + x_h = kf_.x_hat + Sig = kf_.Sigma + Omega = G @ Sig @ G.T + R # 新息协方差 + a_t = y_data[t] - (G @ x_h).flatten() + + sign, logdet = np.linalg.slogdet(Omega) + loglik += -0.5 * (m_ * np.log(2 * np.pi) + logdet + + float(a_t @ np.linalg.solve(Omega, a_t))) + kf_.update(y_data[t]) + + return loglik + + +y_data_col = y_obs.reshape(-1, 1) +ll = log_likelihood(A, C, G, R, + y_data_col, + np.zeros(1), np.eye(1) * 10.0) +print(f"Log-likelihood of sample: {ll:.4f}") +``` + +## 一个例子 + +我们现在通过一个结构化的例子来说明一个二元 VAR(2) 如何自然地嵌入状态空间框架,以及卡尔曼滤波器如何给出一个 Wold(新息)表示。 + +### 一个线性状态空间系统及其滤波器 + +状态方程和观测方程为 + +$$ +x_{t+1} = A x_t + C w_{t+1} +$$ (eq:ex_state) + +$$ +y_t = G x_t + v_t +$$ (eq:ex_obs) + +具有初始条件和冲击分布 + +$$ +x_0 \sim N(\hat{x}_0, \Sigma_0), \quad +w_{t+1} \sim N(0, I), \quad +v_t \sim N(0, R). +$$ + +稳态误差协方差矩阵 $\Sigma$ 满足黎卡提方程 + +$$ +\Sigma = A \Sigma A^\top + CC^\top + - A \Sigma G^\top \bigl(G \Sigma G^\top + R\bigr)^{-1} G \Sigma A^\top +$$ (eq:ex_riccati) + +且相关的稳态卡尔曼增益为 + +$$ +K = A \Sigma G^\top \bigl(G \Sigma G^\top + R\bigr)^{-1} +$$ (eq:ex_gain) + +从初始估计 $\hat{x}_0$ 出发,卡尔曼滤波器通过下式更新状态估计 + +$$ +\hat{x}_{t+1} = A \hat{x}_t + K a_t +$$ (eq:ex_kf_update) + +其中新息为 + +$$ +a_t = y_t - G \hat{x}_t +$$ (eq:ex_innovation) + +将 {eq}`eq:ex_innovation` 代入 {eq}`eq:ex_kf_update` 并展开: + +$$ +\hat{x}_{t+1} = A \hat{x}_t + K(y_t - G\hat{x}_t) + = (A - KG)\hat{x}_t + K y_t + = (A - KG)\hat{x}_t + K G x_t + K v_t +$$ (eq:ex_kf_expanded) + +### $y_t$ 对新息 $a_t$ 的脉冲响应 + +计算可观测向量 $y_t$ 对其自身新息 $a_t$ 的**普通脉冲响应函数**是有用的,这个移动平均(Wold)表示是 VAR {eq}`eq:var1` 的镜像。 + +从时不变新息表示 {eq}`eq:innovti` + +$$ +\hat{x}_{t+1} = A\hat{x}_t + K a_t, \qquad y_t = G\hat{x}_t + a_t, +$$ + +移动平均表示 {eq}`eq:sf_wold` 为 + +$$ +y_t = \bigl[I + G(I - AL)^{-1} K L\bigr]\, a_t + = a_t + \sum_{h=1}^{\infty} G A^{h-1} K\, a_{t-h}. +$$ + +因此 $y_t$ 对单位新息 $a_t$ 的脉冲响应为 + +$$ +\Psi_0 = I, \qquad \Psi_h = G A^{h-1} K \quad (h \ge 1). +$$ (eq:ex_y_to_a) + +这些系数以由 $A$ 的特征值支配的速率衰减。 + +我们可以直接从一个 `quantecon` `LinearStateSpace` 对象中读取系数 {eq}`eq:ex_y_to_a`。 + +我们构建一个状态空间系统,其状态是滤波估计 $\hat{x}_t$,其单一"冲击"是通过 $C = K$ 加载的新息 $a_t$,其观测矩阵为 $G$。 + +该对象的 `impulse_response` 方法返回序列 $G A^{j} K$,其中 $j = 0, 1, 2, \ldots$,这些正好是 $h \ge 1$ 时的 $\Psi_h$;我们在前面加上 $\Psi_0 = I$ 以捕获当期直达效应 $y_t = G\hat{x}_t + a_t$。 + +下面返回的数组,其元素 `[h, i, j]` 等于可观测量 `i` 在视界 `h` 处对新息分量 `j` 的响应。 + +```{code-cell} ipython3 +def y_to_a_irf(A, K, G, T=40): + """ + 返回 y_t 对其自身新息 a_t 的 Wold 脉冲响应函数。 + """ + n, m = A.shape[0], G.shape[0] + lss = qe.LinearStateSpace(A, K, G, np.zeros((m, m)), mu_0=np.zeros(n)) + _, ycoef = lss.impulse_response(j=T - 2) # [GK, GAK, GA^2K, ...] + Psi = np.empty((T, m, m)) + Psi[0] = np.eye(m) # 当期响应 + for h in range(1, T): + Psi[h] = ycoef[h - 1] + return Psi +``` + +### 状态空间形式的二元 VAR(2) + +考虑两个可观测序列 $r_t$ 和 $z_t$。 + +将它们堆叠成状态向量 $x_t = (r_t,\; r_{t-1},\; z_t,\; z_{t-1})^\top$。 + +我们假设 VAR(2) 状态转移方程: + +$$ +\begin{pmatrix} r_{t+1} \\ r_t \\ z_{t+1} \\ z_t \end{pmatrix} += +\begin{pmatrix} + d_1 & d_2 & d_3 & d_4 \\ + 1 & 0 & 0 & 0 \\ + \delta_1 & \delta_2 & \delta_3 & \delta_4 \\ + 0 & 0 & 1 & 0 +\end{pmatrix} +\begin{pmatrix} r_t \\ r_{t-1} \\ z_t \\ z_{t-1} \end{pmatrix} ++ +\begin{pmatrix} + c_{11} & c_{12} \\ + 0 & 0 \\ + c_{21} & c_{22} \\ + 0 & 0 +\end{pmatrix} +\begin{pmatrix} w_{1,t+1} \\ w_{2,t+1} \end{pmatrix} +$$ (eq:ex_var2_state) + +我们考虑两种可能的观测方程。 + +第一种是对 $r_t$ 和 $z_t$ 的二元观测: + +$$ +\begin{pmatrix} r_t \\ z_t \end{pmatrix} += +\begin{pmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 +\end{pmatrix} +\begin{pmatrix} r_t \\ r_{t-1} \\ z_t \\ z_{t-1} \end{pmatrix} ++ +\begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix} +\begin{pmatrix} v_{1t} \\ v_{2t} \end{pmatrix} +$$ (eq:ex_var2_obs) + +第二种是对 $r_t$ 的单变量观测: + +$$ +y_t = \begin{pmatrix} 1 & 0 & 0 & 0 \end{pmatrix} +\begin{pmatrix} r_t \\ r_{t-1} \\ z_t \\ z_{t-1} \end{pmatrix} ++ v_{1t} +$$ (eq:ex_scalar_obs) + +我们现在比较这两个观测系统生成的 Wold 脉冲响应。 + +系统 1 同时观测 $r_t$ 和 $z_t$,因此其新息 $a_t$ 是 $2 \times 1$ 的。 + +系统 2 只观测 $r_t$,因此其新息 $u_t$ 是标量。 + +两个系统的转移矩阵相同,但观测矩阵不同。 + +因此,稳态卡尔曼增益也不同,可观测量对其自身新息的 Wold 响应也不同。 + +### 数值例子:对新息的脉冲响应 + +参数值为: + +$$ +\begin{aligned} +d_1 &= 0.80,\quad d_2 = 0.05,\quad d_3 = 0.75,\quad d_4 = -0.72 \\ +\delta_1 &= 0.00,\quad \delta_2 = 0.00,\quad \delta_3 = 0.75,\quad \delta_4 = 0.20 \\ +c_{11} &= 1.0,\quad c_{12} = 0.0,\quad c_{21} = 0.0,\quad c_{22} = 1.0 \\ +R &= 0.0001 \times I_2 \quad \text{(二元情形)}, \qquad +R = 0.0001 \quad \text{(单变量情形)}. +\end{aligned} +$$ + +这些给出 $4 \times 4$ 转移矩阵和 $4 \times 2$ 冲击加载矩阵 + +$$ +A = \begin{pmatrix} +0.80 & 0.05 & 0.75 & -0.72 \\ +1 & 0 & 0 & 0 \\ +0 & 0 & 0.75 & 0.20 \\ +0 & 0 & 1 & 0 +\end{pmatrix}, \qquad +C = \begin{pmatrix} +1 & 0 \\ +0 & 0 \\ +0 & 1 \\ +0 & 0 +\end{pmatrix}. +$$ + +**系统 1** 使用二元观测方程 {eq}`eq:ex_var2_obs`,因此 +$G$ 从状态中选取 $(r_t, z_t)^\top$,新息 $a_t$ 是 $2 \times 1$ 的。 + +**系统 2** 使用单变量观测方程 {eq}`eq:ex_scalar_obs`,因此该方程中的行向量只选取 $r_t$,新息 $u_t$ 是标量。 + +```{code-cell} ipython3 +# 参数 +d1, d2, d3, d4 = 0.80, 0.05, 0.75, -.72 +δ1, δ2, δ3, δ4 = 0.00, 0.00, 0.75, 0.20 +c11, c12, c21, c22 = 1.0, 0.0, 0.0, 1.0 +σ_v = 0.01 # sqrt(0.0001) + +# 共享矩阵 +A_var = np.array([[d1, d2, d3, d4 ], + [1.0, 0.0, 0.0, 0.0 ], + [δ1, δ2, δ3, δ4], + [0.0, 0.0, 1.0, 0.0 ]]) + +C_var = np.array([[c11, c12], + [0.0, 0.0], + [c21, c22], + [0.0, 0.0]]) + +# 系统 1: 二元观测 +G_biv = np.array([[1.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0]]) +H_biv = σ_v * np.eye(2) # H @ H.T = 0.0001 * I_2 + +lss_biv = qe.LinearStateSpace(A_var, C_var, G_biv, H_biv, + mu_0=np.zeros(4), Sigma_0=np.eye(4)) +kf_biv = qe.Kalman(lss_biv) +_, K_biv = kf_biv.stationary_values() + +print("System 1 - steady-state Kalman gain K (4x2):") +print(np.round(K_biv, 5)) + +# 系统 2: 单变量观测 +G_uni = np.array([[1.0, 0.0, 0.0, 0.0]]) +H_uni = np.array([[σ_v]]) # H @ H.T = 0.0001 + +lss_uni = qe.LinearStateSpace(A_var, C_var, G_uni, H_uni, + mu_0=np.zeros(4), Sigma_0=np.eye(4)) +kf_uni = qe.Kalman(lss_uni) +_, K_uni = kf_uni.stationary_values() + +print("\nSystem 2 - steady-state Kalman gain K (4x1):") +print(np.round(K_uni, 5)) +``` + +我们现在应用上面定义的辅助函数 `y_to_a_irf` 来计算可观测量 $y_t$ 对其自身新息 $a_t$ 的普通脉冲响应 {eq}`eq:ex_y_to_a`,分别针对系统 1(二元,因此 $a_t$ 是 $2 \times 1$ 的)和系统 2(单变量,因此 $u_t$ 是标量)。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 系统 1 对自身新息的响应 + name: fig-kfvar-sys1-ya +--- +T_irf = 40 +horizons = np.arange(T_irf) + +Psi_biv = y_to_a_irf(A_var, K_biv, G_biv, T_irf) # 系统 1: (T, 2, 2) +Psi_uni = y_to_a_irf(A_var, K_uni, G_uni, T_irf) # 系统 2: (T, 1, 1) + +obs_labels = [r'$r_t$', r'$z_t$'] +innov_labels = [r'$a_{1,t}$', r'$a_{2,t}$'] + +# 系统 1 的响应 +fig, axes = plt.subplots(2, 2, figsize=(10, 6), sharex=True) +for i, obs in enumerate(obs_labels): + for j, inn in enumerate(innov_labels): + ax = axes[i, j] + ax.plot(horizons, Psi_biv[:, i, j], lw=2) + ax.axhline(0, color='k', lw=0.6, ls='--') + ax.set_title(fr'{obs} 对 {inn}', fontsize=9) + if i == 1: + ax.set_xlabel('视界 $h$') + if j == 0: + ax.set_ylabel('响应') +fig.tight_layout() +plt.show() +``` + +自身新息在冲击时刻对其自身可观测量产生一对一的影响,然后逐渐消退。 + +对角面板从 1 开始,非对角面板从 0 开始,因为 $\Psi_0 = I$。 + +$r_t$ 对 $a_{2,t}$ 的交叉响应在短视界上是相当大的,而 $z_t$ 对 $a_{1,t}$ 的响应在显示的尺度上非常微小。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 系统 2 对自身新息的响应 + name: fig-kfvar-sys2-ya +--- +fig, ax = plt.subplots() +ax.plot(horizons, Psi_uni[:, 0, 0], lw=2) +ax.axhline(0, color='k', lw=0.6, ls='--') +ax.set_xlabel('视界 $h$') +ax.set_ylabel('响应') +fig.tight_layout() +plt.show() +``` + +只观测 $r_t$ 时,单一新息在冲击时刻对 $r_t$ 产生一对一的影响,然后单调地衰减到零。 + +对于 $h \ge 1$,响应通过状态矩阵 $A$ 传播并以几何速率衰减,勾勒出二元(系统 1)和单变量(系统 2)过程的 Wold 移动平均表示。 + +这些是来自 Wold 表示的预测误差响应,不是结构性冲击响应。 + +有了这个例子,我们现在可以把本讲座的主要要点汇总起来。 + +## 总结 + +卡尔曼滤波器通过将先验预测与当前观测中包含的新信息相结合,递归地更新关于隐藏状态的信念。 + +黎卡提方程跟踪滤波器的条件协方差如何演化,其稳态使滤波器成为时不变的。 + +在该稳态处,新息表示用由构造而成的白噪声一步预测误差来表示可观测过程。 + +向后求解新息表示得到一个无限阶 VAR,而向前求解则得到 Wold 移动平均表示。 + +数值例子表明,改变观测变量会改变卡尔曼增益,从而改变 Wold 响应,即使底层状态动态相同也是如此。 + +## 练习 + +```{exercise-start} +:label: kf_ex1 +``` + +考虑上面使用的标量 AR(1) 状态空间系统,其中 $\rho = 0.9$, +$\sigma_w = 0.5$,$\sigma_v = 1.0$。 + +通过在其不动点 $\Sigma_{t+1} = \Sigma_t = \Sigma$ 处求解标量黎卡提方程 {eq}`eq:riccati`,为**稳态**条件方差 $\Sigma_\infty$ 推导一个代数表达式。 + +证明 $\Sigma$ 满足一个二次方程,求出其正根,并数值验证你的公式与 `kf.Sigma_infinity` 相符。 + +```{exercise-end} +``` + +```{solution-start} kf_ex1 +:class: dropdown +``` + +这是一个解答: + +在 {eq}`eq:riccati` 的标量版本中设 $\Sigma_{t+1} = \Sigma_t = \Sigma$,其中 $A = \rho$,$CC^\top = \sigma_w^2$,$GG^\top = 1$, +$R = \sigma_v^2$: + +$$ +\Sigma = \rho^2 \Sigma + \sigma_w^2 - \frac{\rho^2 \Sigma^2}{\Sigma + \sigma_v^2} +$$ + +两边同乘 $\Sigma + \sigma_v^2$ 并重新整理: + +$$ +\Sigma^2 + \left[\sigma_v^2(1-\rho^2) - \sigma_w^2\right]\Sigma + - \sigma_v^2 \sigma_w^2 = 0 +$$ + +取此二次方程的正根: + +$$ +\Sigma_\infty + = \frac{\sigma_w^2 - \sigma_v^2(1-\rho^2) + + \sqrt{\left[\sigma_v^2(1-\rho^2) - \sigma_w^2\right]^2 + + 4 \sigma_v^2 \sigma_w^2}}{2} +$$ + +```{code-cell} ipython3 +ρ_, σ_w_, σ_v_ = 0.9, 0.5, 1.0 + +b = σ_v_**2 * (1 - ρ_**2) - σ_w_**2 +discriminant = b**2 + 4 * σ_v_**2 * σ_w_**2 +Sigma_formula = (-b + np.sqrt(discriminant)) / 2 + +A_ = np.array([[ρ_]]) +C_ = np.array([[σ_w_]]) +G_ = np.array([[1.0]]) +R_ = np.array([[σ_v_**2]]) +H_ = np.array([[σ_v_]]) # R_ = H_ @ H_.T +lss_ = qe.LinearStateSpace(A_, C_, G_, H_, mu_0=np.zeros(1), Sigma_0=np.eye(1)) +kf_ = qe.Kalman(lss_) + +print(f"Analytical Σ_inf = {Sigma_formula:.8f}") +print(f"Numerical Σ_inf = {kf_.Sigma_infinity[0, 0]:.8f}") +``` + +```{solution-end} +``` + +```{exercise-start} +:label: kf_ex2 +``` + +本练习考虑一个二维状态和一维观测: + +$$ +A = \begin{pmatrix} 0.9 & 0.1 \\ 0 & 0.8 \end{pmatrix}, \quad +C = \begin{pmatrix} 0.4 \\ 0.1 \end{pmatrix}, \quad +G = \begin{pmatrix} 1 & 0 \end{pmatrix}, \quad +R = [0.5] +$$ + +1. 从弥散先验出发,从这个系统模拟 $T = 500$ 个观测。 + +2. 运行卡尔曼滤波器,并绘制 $\hat{x}_t$ 的两个分量与真实隐藏状态路径的对比。 + +3. 计算并报告稳态协方差 $\Sigma_\infty$ 和卡尔曼增益 $K_\infty$。 + +4. 检查 $A - K_\infty G$ 的特征值是否严格位于单位圆内,从而确认 VAR 表示 {eq}`eq:var1` 是稳定的。 + +```{exercise-end} +``` + +```{solution-start} kf_ex2 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +A2 = np.array([[0.9, 0.1], + [0.0, 0.8]]) +C2 = np.array([[0.4], + [0.1]]) +G2 = np.array([[1.0, 0.0]]) +R2 = np.array([[0.5]]) +H2 = np.array([[np.sqrt(0.5)]]) # R2 = H2 @ H2.T + +lss2 = qe.LinearStateSpace(A2, C2, G2, H2, + mu_0=np.zeros(2), + Sigma_0=np.eye(2) * 5.0) +kf2 = qe.Kalman(lss2) +kf2.set_state(np.zeros(2), np.eye(2) * 5.0) + +T2 = 500 +x2_path, y2_path = lss2.simulate(ts_length=T2, random_state=0) + +x_hats2 = np.zeros((T2, 2)) +for t in range(T2): + kf2.update(y2_path[:, t]) + x_hats2[t] = kf2.x_hat.ravel() + +fig, axes = plt.subplots(2, 1, figsize=(10, 6), sharex=True) +for i, ax in enumerate(axes): + ax.plot(x2_path[i, :T2], lw=2, label=f'真实 $x_{{{i+1},t}}$') + ax.plot(x_hats2[:, i], lw=2, ls='--', label=rf'$\hat{{x}}_{{{i+1},t}}$') + ax.set_title(f'分量 {i+1}') + ax.legend(fontsize=9) + ax.set_ylabel(f'分量 {i+1}') +axes[1].set_xlabel('时间 $t$') +fig.suptitle('卡尔曼滤波器: 二元隐藏状态') +fig.tight_layout() +plt.show() + +# 稳态值 +Sigma2_inf, K2_inf = kf2.stationary_values() +print("Steady-state covariance Σ_inf:") +print(np.round(Sigma2_inf, 5)) +print("\nSteady-state Kalman gain K_inf:") +print(np.round(K2_inf, 5)) + +# A - K_inf G 的特征值 +AKG2 = A2 - K2_inf @ G2 +eigvals2 = np.linalg.eigvals(AKG2) +print(f"\nEigenvalues of A - K_inf G: {np.round(eigvals2, 5)}") +print(f"Stable VAR: {np.all(np.abs(eigvals2) < 1)}") +``` + +在弥散先验的暂态之后,两个卡尔曼估计都紧密地跟随其对应的隐藏状态路径。 + +第二个分量没有被直接观测,因此它的跟踪来自于状态动态及其与观测信号的联系。 + +打印出的特征值随后检查了 VAR 表示的独立稳定性条件。 + +```{solution-end} +``` + +```{exercise-start} +:label: kf_ex3 +``` + +本练习使用正文中的标量模型研究似然和参数估计,真实参数为 +$(\rho, \sigma_w, \sigma_v) = (0.9, 0.5, 1.0)$: + +1. 模拟 $T = 300$ 个观测。 + +2. 编写一个函数,将**对数似然**作为 $\rho \in (0, 1)$ 的函数进行计算,保持 $\sigma_w = 0.5$ 和 $\sigma_v = 1.0$ 固定,并针对一组网格值绘制对数似然关于 $\rho$ 的图。 + +3. 数值定位最大值,并检查它是否接近真实值 $\rho = 0.9$。 + +```{exercise-end} +``` + +```{solution-start} kf_ex3 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +# 真实参数 +ρ_true, sw_true, sv_true = 0.9, 0.5, 1.0 + +A_t = np.array([[ρ_true]]) +C_t = np.array([[sw_true]]) +G_t = np.array([[1.0]]) +R_t = np.array([[sv_true**2]]) +H_t = np.array([[sv_true]]) # R_t = H_t @ H_t.T + +lss_t = qe.LinearStateSpace(A_t, C_t, G_t, H_t, + mu_0=np.zeros(1), Sigma_0=np.eye(1)) +_, y_sim = lss_t.simulate(ts_length=300, random_state=7) +y_sim = y_sim.T # 形状 (300, 1) + +def ll_rho(ρ_val): + A_ = np.array([[ρ_val]]) + C_ = np.array([[sw_true]]) + G_ = np.array([[1.0]]) + R_ = np.array([[sv_true**2]]) + return log_likelihood(A_, C_, G_, R_, y_sim, + np.zeros(1), np.eye(1) * 10.0) + +ρ_grid = np.linspace(0.5, 0.99, 60) +ll_vals = np.array([ll_rho(r) for r in ρ_grid]) + +ρ_mle = ρ_grid[np.argmax(ll_vals)] + +fig, ax = plt.subplots() +ax.plot(ρ_grid, ll_vals, lw=2) +ax.axvline(ρ_true, color='k', ls='--', label=f'真实 ρ = {ρ_true}') +ax.axvline(ρ_mle, color='C1', ls=':', label=f'MLE $\\hat{{\\rho}}$ = {ρ_mle:.3f}') +ax.set_xlabel(r'$\rho$') +ax.set_ylabel('对数似然') +ax.set_title('作为 $\\rho$ 函数的剖面对数似然') +ax.legend() +fig.tight_layout() +plt.show() + +print(f"True ρ = {ρ_true}, MLE ρ_hat = {ρ_mle:.4f}") +``` + +似然曲线是单峰的,其最大值接近真实值 $\rho = 0.9$。 + +网格最大化器与真实值之间的微小差距来自于有限样本的随机性和离散网格的使用。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/long_run_risk_operator.md b/lectures/long_run_risk_operator.md new file mode 100644 index 0000000..902771b --- /dev/null +++ b/lectures/long_run_risk_operator.md @@ -0,0 +1,2948 @@ +--- +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 +translation: + title: 长期风险:一种算子方法 + headings: + Overview: 概述 + Multiplicative functionals: 乘性泛函 + Multiplicative functionals::Setting: 设定 + Multiplicative functionals::Functionals and càdlàg paths: 泛函与 càdlàg 路径 + Multiplicative functionals::Multiplicativity: 乘性 + Multiplicative functionals::Additive functionals: 可加泛函 + Semigroups: 半群 + Semigroups::Local pricing restriction: 局部定价约束 + The generator: 生成元 + The generator::Discrete-time intuition: 离散时间直觉 + The generator::From discrete to continuous time: 从离散时间到连续时间 + The generator::Extended generator: 扩展生成元 + The generator::A closed form for jump diffusions: 跳跃扩散的闭式 + Principal eigenfunctions: 主特征函数 + Principal eigenfunctions::From eigenfunction to factorization: 从特征函数到分解 + Principal eigenfunctions::Stability of the twisted process: 扭曲过程的稳定性 + Principal eigenfunctions::The long-run approximation: 长期近似 + A finite-state Markov chain: 一个有限状态马尔可夫链 + A finite-state Markov chain::Setup: 设定 + A finite-state Markov chain::Two states: 两个状态 + A finite-state Markov chain::Adding jumps: 加入跳跃 + The affine diffusion example: 仿射扩散例子 + The affine diffusion example::Why exponential-affine eigenfunctions work: 为什么指数-仿射特征函数有效 + The affine diffusion example::A Breeden SDF: 一个 Breeden SDF + The affine diffusion example::Recursive preferences (optional): 递归偏好(可选) + The affine diffusion example::Numerical example: 数值例子 + The affine diffusion example::The martingale component: 鞅成分 + Long-run risk prices: 长期风险价格 + Long-run risk prices::Defining the prices: 定义价格 + Long-run risk prices::Two frontiers: 两个前沿 + Long-run risk prices::Stochastic discount factor decomposition: 随机贴现因子分解 + Long-run risk prices::Comparison in the affine model: 仿射模型中的比较 + Long-run risk prices::Changing valuation functionals: 改变估值泛函 + Long-run risk prices::Changing cash-flow risk: 改变现金流风险 + Assumptions behind the scenes: 幕后的假设 + 'Assumptions behind the scenes::Issue 1: $\hat M$ might fail to be a martingale': 问题 1:$\hat M$ 可能无法成为一个鞅 + 'Assumptions behind the scenes::Issue 2: the twisted process might fail to be stable': 问题 2:扭曲过程可能无法稳定 + 'Assumptions behind the scenes::Issue 3: a principal eigenfunction might not exist': 问题 3:主特征函数可能不存在 + Summary: 小结 + Exercises: 练习 +--- + +(long_run_risk_operator)= +```{raw} jupyter + +``` + +# 长期风险:一种算子方法 + +```{contents} 目录 +:depth: 2 +``` + +## 概述 + +标准的短视界资产定价告诉我们,均衡价格如何补偿投资者所承担的微小、瞬时的冲击暴露。 + +也就是说,它们告诉我们风险价格期限结构的*短端*。 + +但许多最有趣的资产定价问题(例如股权溢价之谜、收益率曲线的斜率、长期期权的价格)关注的是风险价格期限结构的*长端*。 + +本讲座使用 {cite:t}`HansenScheinkman2009` 的算子方法来研究长端。 + +处于核心地位的将是一个随机贴现因子过程和一个回报过程,它们在时间上是乘性的,即条件期望定义了一个以视界 $t$ 为指标的估值算子*半群*。 + +该半群的长视界行为由状态空间上的单一特征值问题所控制。 + +通过求解该特征值问题并选择适当的特征函数,我们可以将乘性泛函 $M_t$ 分解为三个具有经济意义的部分:一个确定性的指数趋势、一个改变概率测度的非负鞅,以及一个瞬态的依赖状态的成分。 + +具体而言,该分解具有如下形式 + +$$ + M_t + = + \exp(\rho t)\, \hat M_t\, + \frac{\phi(X_0)}{\phi(X_t)}, +$$ (eq:hs-factorization) + +其中 + +* $\rho$ 是一个标量(**主特征值**),给出渐近的增长或衰减率, +* $\phi$ 是状态空间上一个严格正的**主特征函数**,捕捉对当前状态的长期依赖性, +* $\hat M$ 是一个用于改变概率测度的正鞅(**鞅成分**),以及 +* $\phi(X_0)/\phi(X_t)$ 是一个瞬态成分,当扭曲过程收敛到其平稳分布时会消失。 + +在有限状态问题中,这恰好是一个正矩阵的佩龙-弗罗贝尼乌斯分解;在一般状态空间中,它是一个连续状态的对应物。 + +我们将把 {eq}`eq:hs-factorization` 称为与 $(\rho,\phi,\hat M)$ 相关联的**乘性分解**。 + +{cite:t}`AlvarezJermann2005` 对随机贴现因子应用了一个相关的永久-瞬态分解。 + +算子方法将该分解与一个显式的特征值问题联系起来。 + +```{seealso} +本讲座与讲座 {doc}`advanced:additive_functionals` 密切相关,后者在离散时间线性高斯设定中,对可加与乘性泛函研究了同类的永久-瞬态分解。 + +同时阅读这两篇讲座,是学习连续时间和离散时间中长期风险表示的一个好方法。 +``` + +我们将逐步推导出 {eq}`eq:hs-factorization`,并用它在具体模型中计算长期风险价格。 + +本讲座的计划是: + +1. 建立正乘性泛函 $M$(贴现因子、回报、随机增长)以及它们所生成的估值半群。 + +2. 引入半群的**生成元**,这是一个局部算子,其特征值问题控制着长期行为。 + +3. 找到主特征函数 $\phi$ 并推导出分解。 + +4. 详细研究两个例子:一个有限状态马尔可夫链(其中一切都归结为佩龙-弗罗贝尼乌斯理论)和一个仿射扩散模型(其中特征函数是指数-仿射的,我们能得到闭式公式)。 + +5. 使用该分解来计算长期风险价格,并将它们与适用于短视界资产定价的局部风险价格进行比较。 + +一个反复出现的主题是,对持久性状态变量的冲击会在局部风险价格与长期风险价格之间形成一个楔子。 + +产生这个楔子的机制正是长期风险模型(如 {cite:t}`Bansal_Yaron_2004`)产生大额股权溢价的途径。 + +我们从以下导入开始 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.linalg import eig, expm +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 乘性泛函 + +### 设定 + +设 $\{X_t : t \geq 0\}$ 是一个具有状态空间 $\mathcal D_0$ 的连续时间马尔可夫过程,并设 $\mathcal F_t$ 表示由其历史生成的过滤族。 + +我们将研究一个强马尔可夫过程,其样本路径是 càdlàg 的(定义如下)。 + +为了得到后面给出的显式公式,我们将专门讨论一个半鞅,它分解为一个连续成分 $X^c$ 和一个纯跳跃成分 $X^j$: + +$$ + X_t = X_t^c + X_t^j . +$$ + +我们将连续成分的动态写为 + +$$ + dX_t^c = \xi(X_{t-})\, dt + \Gamma(X_{t-})\, dB_t, +$$ + +将纯跳跃成分写为 + +$$ + dX_t^j = \int \bigl(y - X_{t-}\bigr)\, \zeta(dy, dt), +$$ + +其中 $\zeta$ 是以*跳后状态* $y$ 为指标的跳跃随机计数测度,因此 $\zeta(B, [0,t])$ 计数了 $[0,t]$ 内落在博雷尔集 $B$ 中的跳跃次数。 + +其补偿子为 $\eta(dy \mid X_{t-})\, dt$,即 $X$ 从 $X_{t-}$ 跳入区域 $dy$ 的速率。 + +我们将在全文中使用这个 "$y$ = 跳后状态" 的约定,以匹配下面生成元中出现的 $\phi(y) - \phi(x)$ 形式。 + +我们还施加两个简化假设: + +* 在有限时间区间上的**有限跳跃**:在任何有界区间上只发生有限次跳跃;这使得对跳跃测度的积分保持良定义且有限。 +* $\Gamma$ 中的**充分秩**,使得与定价相关的布朗冲击可以从状态历史中恢复;这使得马尔可夫状态 $X$ "足够丰富" 以描述估值。 + +这些假设让我们能以闭式写出生成元,并自由地使用基于鞅的测度变换。 + +### 泛函与 càdlàg 路径 + +我们需要一个名称来表示 "一个记录关于 $X$ 历史某些信息的过程"。 + +例如,这包括随机贴现因子或累积回报。 + +```{prf:definition} 泛函 +:label: lrr-def-functional + +一个**泛函**是一个由 $X$ 的历史构造出的实值适应过程 $\{M_t : t \geq 0\}$,使得对每个 $t$,$M_t$ 关于 $\mathcal F_t$ 可测。 +``` + +我们将始终使用泛函的 **càdlàg** 版本,这是法语缩写,意为 "右连续且有左极限"。 + +具体地,对几乎每条样本路径 $\omega$, + +$$ + \lim_{s \downarrow t} M_s(\omega) = M_t(\omega) + \qquad \text{对所有 } t \geq 0, +$$ + +并且左极限 $M_{t-}(\omega) := \lim_{s \uparrow t} M_s(\omega)$ 对所有 $t > 0$ 存在且有限。 + +因此,路径可以跳跃,但每次跳跃 $\Delta M_t := M_t - M_{t-}$ 瞬时发生。 + +在跳跃时刻 $t$,取值是跳后值,而非跳前值。 + +```{note} +为什么值得坚持要求 càdlàg 性质? + +因为我们后面会想要 (i) 对泛函关于时间积分,(ii) 应用可选停止论证,以及 (iii) 取像 $\lim_{t \to \infty} t^{-1}\log M_t$ 这样的极限。 + +这三种操作都需要在 $(\omega,t)$ 中的联合可测性,而 càdlàg 路径自动为我们提供了这一点。 +``` + +### 乘性 + +我们对泛函 $M$ 施加的核心限制是它在时间上是*乘性的*。 + +```{prf:definition} 乘性泛函 +:label: lrr-def-multiplicative-functional + +如果 $M_0 = 1$ 且 + +$$ + M_{t+u} = M_u(\theta_t)\, M_t , + \qquad t, u \geq 0, +$$ (eq:multiplicative) + +则泛函 $\{M_t : t \geq 0\}$ 是**乘性的**,其中 $\theta_t$ 将底层马尔可夫路径向前平移 $t$ 个单位。 +``` + +为什么这是一个有用的要求条件? + +考虑 $M_t = S_t$,一个随机贴现因子。 + +日期 $0$ 时对日期 $t$ 收益 $\Pi_t$ 的估值是 $\mathbb{E}[S_t\Pi_t \mid \mathcal F_0]$。 + +如果我们改为在中间日期 $\tau$ 购买该收益,其日期 $\tau$ 的价格必然是 + +$$ + \mathbb{E}\left[\frac{S_t}{S_\tau}\Pi_t \,\Big|\, \mathcal F_\tau\right]. +$$ + +为使价格只依赖于当前马尔可夫状态 $X_\tau$(而不依赖于直到 $\tau$ 的整个历史),比值 $S_t/S_\tau$ 必须只是 $\tau$ *之后*的马尔可夫路径的函数。 + +因此,$S_{\tau+u}/S_\tau = S_u(\theta_\tau)$,这恰好是 {eq}`eq:multiplicative`。 + +所以乘性正是一价定律的马尔可夫形式。 + +同样的结构性质随后被沿用到随机增长和累积回报。 + +### 可加泛函 + +处理一个严格正的乘性泛函的*对数*通常更容易。 + +如果 $M_t > 0$,我们可以写 $M_t = \exp(A_t)$,那么乘性性质 {eq}`eq:multiplicative` 就变成了 $A$ 的相应可加性质。 + +```{prf:definition} 可加泛函 +:label: lrr-def-additive-functional + +如果 $A_0 = 0$ 且 + +$$ + A_{t+u} = A_u(\theta_t) + A_t , +$$ + +则泛函 $\{A_t : t \geq 0\}$ 是**可加的**。 +``` + +因此,可加泛函的指数恰好是严格正的乘性泛函。 + +在我们的跳跃-扩散设定中,一个有用的参数化是 + +$$ + A_t + = + \int_0^t \beta(X_s)\, ds + + \int_0^t \gamma(X_{s-})^\top dB_s + + \sum_{0 \leq s \leq t} \kappa(X_s, X_{s-}) , +$$ (eq:additive-functional) + +其中三个函数 $(\beta, \gamma, \kappa)$ 扮演以下角色: + +* $\beta(x)$ 是一个**依赖状态的漂移**率(例如,一个短期利率为 $r(x)$ 的纯贴现因子有 $\beta(x) = -r(x)$)。 +* $\gamma(x)$ 是一个**布朗载荷**,控制布朗冲击在状态 $x$ 时如何馈入 $A$。 +* $\kappa(y,x)$ 是一个**跳跃幅度**,每当 $X$ 从 $x$ 跳到 $y$ 时触发。 + +为使一切良定义,我们施加自然的可积性条件 + +$$ + \int_0^t |\beta(X_s)|\, ds < \infty, + \qquad + \int_0^t \|\gamma(X_s)\|^2\, ds < \infty, +$$ + +以及 $\kappa(x,x)=0$(如果状态不改变则无跳跃)和 + +$$ + \int \exp[\kappa(y,x)]\, \eta(dy \mid x) < \infty. +$$ + +这个参数化对本讲座中我们所做的一切都足够丰富,尽管可加泛函也可以包括占用时间之类的东西。 + +## 半群 + +一个乘性泛函 $M$ 连同马尔可夫过程 $X$ 为每个视界 $t$ 定义了一个**估值算子**: + +$$ + \mathbb M_t \psi(x) = \mathbb{E}\left[M_t \psi(X_t) \mid X_0 = x\right] . +$$ + +你应当将 $\mathbb M_t \psi(x)$ 理解为 "从状态 $x$ 出发,日期 $t$ 收益 $\psi(X_t)$ 在日期 $0$ 的估值",用 $M_t$ 加权。 + +算子族 $\{\mathbb M_t\}_{t \geq 0}$ 具有一个关键的复合结构,即*半群性质*。 + +```{prf:definition} 单参数半群 +:label: lrr-def-one-parameter-semigroup + +如果 $T_0=I$ 且对所有 $s,t \geq 0$ 有 $T_{t+s}=T_tT_s$,则线性算子族 $\{T_t : t \geq 0\}$ 是一个**单参数半群**。 + +如果每当 $\psi \geq 0$ 时 $T_t\psi \geq 0$,则它是**正的**。 +``` + +```{prf:definition} 乘性半群 +:label: lrr-def-multiplicative-semigroup + +给定一个乘性泛函 $M$,相关联的**乘性半群**是算子族 + +$$ + \mathbb M_t \psi(x) + = + \mathbb{E}\left[M_t \psi(X_t) \mid X_0 = x\right]. +$$ (eq:m-semigroup) +``` + +半群恒等式 $\mathbb M_{t+u} = \mathbb M_t \mathbb M_u$ 由迭代期望和 $M$ 的乘性性质得出。 + +从经济学上讲,这是*马尔可夫迭代估值律*:为了在今天对日期 $(t+u)$ 的收益估值,我们可以 + +* 直接从 $t+u$ 一步贴现回 $0$(应用 $\mathbb M_{t+u}$),或者 +* 先从 $t+u$ 贴现回 $t$(应用 $\mathbb M_u$),然后将得到的日期 $t$ 价格贴现回 $0$(应用 $\mathbb M_t$)。 + +半群恒等式表明这两个过程给出相同的答案。 + +这是排除跨视界套利的跨期一致性的算子层面版本。 + +下面将经常出现四个正乘性泛函。 + +| 符号 | 对象 | 半群 | +|:---|:---|:---:| +| $S$ | 随机贴现因子 | $\{\mathbb S_t\}$ | +| $V$ | 资产的累积回报 | $\{\mathbb V_t\}$ | +| $G$ | 现金流的随机增长 | $\{\mathbb G_t\}$ | +| $Q=GS$ | 增长现金流的估值 | $\{\mathbb Q_t\}$ | + +前三个是基本要素。 + +第四个结合了贴现和增长,用于对随时间随机增长的现金流估值。 + +```{prf:definition} 随机贴现因子 +:label: lrr-def-stochastic-discount-factor + +一个**随机贴现因子** $S$ 是一个正乘性泛函,对它而言 $\mathbb{E}[S_t Z_t \mid X_0=x]$ 是一个 $\mathcal F_t$-可测收益 $Z_t$ 在日期 $0$ 的估值。 +``` + +```{prf:definition} 估值泛函 +:label: lrr-def-valuation-functional + +给定一个随机贴现因子 $S$,一个**估值泛函** $V$ 是一个正乘性泛函,使得 $\{V_t S_t : t \geq 0\}$ 是一个鞅。 +``` + +```{prf:definition} 随机增长泛函 +:label: lrr-def-stochastic-growth-functional + +一个**随机增长泛函** $G$ 是一个正乘性泛函,解释为应用于日期 $0$ 现金流的乘性增长因子。 +``` + +考虑一个现金流 $D_t = D_0\, G_t\, \psi(X_t)$,其中 $D_0 > 0$ 是日期 $0$ 的水平,$\psi$ 是一个博雷尔状态-收益函数。 + +用 $S$ 贴现并用 $G$ 增长,其日期 $0$ 的估值为 + +$$ + D_0\, \mathbb Q_t \psi(X_0), + \qquad + \mathbb Q_t \psi(x) + = + \mathbb{E}\left[G_t S_t \psi(X_t) \mid X_0=x\right]. +$$ + +```{prf:definition} 现金流估值半群 +:label: lrr-def-cash-flow-valuation-semigroup + +**现金流估值半群**是由 $Q=GS$ 生成的乘性半群。 +``` + +$\mathbb Q_t$ 的长视界行为是本讲座的核心对象:它告诉我们当前价格如何对未来遥远时点上实现的现金流增长风险进行估值。 + +```{note} +分解 $D_t=D_0 G_t \psi(X_t)$ 不是唯一的。 + +对任何正函数 $\varphi$, + +$$ + D_t + = + D_0 + \left[G_t\frac{\varphi(X_t)}{\varphi(X_0)}\right] + \left[\frac{\psi(X_t)\varphi(X_0)}{\varphi(X_t)}\right], +$$ + +因此可以在 $G$ 和 $\psi$ 之间转移一个瞬态的依赖状态的因子而不改变 $D_t$。 + +我们通过归一化增长成分使其永久部分是一个鞅来解决这种不确定性:$G_t = \exp(\delta t)\hat G_t$,其中 $\hat G$ 是一个鞅,$\delta$ 是一个常数趋势。 + +下面的特征函数构造将准确告诉我们应选取哪个鞅。 +``` + +### 局部定价约束 + +在处理长视界之前,最好先理解*短端*的估值。 + +这就是标准的瞬时风险-回报关系。 + +这将给我们一个基准,用于与长期风险价格进行比较。 + +关于同样基于 SDF 的资产定价思想的教科书离散时间处理,见 {doc}`advanced:asset_pricing_lph`。 + +关于基于欧拉方程的资产定价的估计视角,见 {doc}`hansen_singleton_1982`。 + +关键的出发点是,一个估值泛函 $V$ 必须满足无套利要求,即 $VS$ 是一个鞅({prf:ref}`lrr-def-valuation-functional`)。 + +我们将随机贴现因子 $S$ 和估值泛函 $V$ 参数化为可加泛函,系数分别为 $(\beta^s,\gamma^s,\kappa^s)$ 和 $(\beta^v,\gamma^v,\kappa^v)$,采用 {eq}`eq:additive-functional` 的记号。 + +对于一个具有参数 $(\beta,\gamma,\kappa)$ 的一般正乘性泛函 $M = \exp(A)$,将伊藤公式应用于 $\exp(A_t)$ 并要求 $dM_t/M_{t-}$ 的漂移消失,得到**局部鞅约束**: + +$$ + \beta(x) + + \frac{\gamma(x)^\top\gamma(x)}{2} + + \int \big(\exp[\kappa(y,x)] - 1\big)\, \eta(dy \mid x) + = 0 . +$$ (eq:local-martingale-restriction) + +这三项对应于: + +* $A$ 本身的漂移, +* 来自布朗部分的伊藤修正(因为 $M = e^A$ 引入了一个二次变差贡献),以及 +* $M$ 在乘子 $\exp[\kappa(y,x)]$ 处的被补偿跳跃。 + +我们请你在 {ref}`lrr_ex_local_mg` 中验证这一点。 + +将其应用于 $VS$(其参数相加:$(\beta^v + \beta^s, \gamma^v + \gamma^s, \kappa^v + \kappa^s)$),得到**局部定价约束** + +$$ + \beta^v+\beta^s + = + -\frac{\|\gamma^v+\gamma^s\|^2}{2} + - + \int + \left( + \exp[\kappa^v(y,\cdot)+\kappa^s(y,\cdot)]-1 + \right) + \eta(dy \mid \cdot). +$$ (eq:local-pricing-restriction) + +这根据任何候选估值泛函的布朗和跳跃暴露确定了它的漂移 $\beta^v$。 + +为将其转化为*期望回报*,注意 $V$ 上的期望净回报率为 + +$$ + \epsilon^v + = + \beta^v + + \frac{\|\gamma^v\|^2}{2} + + \int + \left(\exp[\kappa^v(y,\cdot)]-1\right) + \eta(dy \mid \cdot) . +$$ + +与 {eq}`eq:local-pricing-restriction` 结合给出 + +$$ +\begin{aligned} + \epsilon^v + &= + -\beta^s + - \gamma^v \cdot \gamma^s + - \frac{\|\gamma^s\|^2}{2} + \\ + &\quad + - + \int + \left( + \exp[\kappa^v(y,\cdot)+\kappa^s(y,\cdot)] + - + \exp[\kappa^v(y,\cdot)] + \right) + \eta(dy \mid \cdot). +\end{aligned} +$$ (eq:local-risk-return) + +因此,布朗局部风险价格向量是 $-\gamma^s(x)$,用与 $\gamma^v(x)$ 相同的暴露单位表示。 + +跳跃风险通过函数 $\kappa^s$ 定价。 + +这个局部关系是风险价格期限结构的一端。 + +下面的特征值计算描述了另一端。 + +## 生成元 + +到目前为止,我们有一个算子族 $\{\mathbb M_t\}_{t \geq 0}$,每个视界 $t$ 对应一个。 + +这比我们能直接使用的信息要多。 + +我们所关心的是长期行为:当 $t \to \infty$ 时 $\mathbb M_t \psi$ 如何增长。 + +**生成元** $\mathbb A$ 将整个半群压缩成状态空间上的一个不依赖时间的算子。 + +它记录 $M_t \psi(X_t)$ 的*瞬时*变化率,其特征值驱动着 $\mathbb M_t$ 的长期增长率。 + +这让我们能将关于一个算子族的渐近问题转化为一个单一的特征值问题。 + +### 离散时间直觉 + +当时间为离散时,生成元的作用最容易看到,因此我们先在那里构建图景,然后再将其沿用。 + +设 $X_n$ 为马尔可夫过程,$M_n$ 为乘性泛函,并定义单期估值算子 + +$$ + K\psi(x) + = + \mathbb{E}\left[M_1 \psi(X_1) \mid X_0=x\right]. +$$ + +迭代给出 $n$-期算子 $K^n$。 + +这类似于转移矩阵的逻辑:正如 $P^n$ 给出 $n$-步概率,$K^n$ 对 $n$-期收益加权,每一步都折叠进了 $M_1$。 + +所以一个局部对象 $K$ 控制着整个以视界为指标的族。 + +它也控制长期增长:如果 $K\phi = \lambda \phi$,那么 + +$$ + K^n \phi = \lambda^n \phi , +$$ + +所以 $\lambda$ 是长期几何增长(或衰减)率,$\phi$ 是对当前状态的长期依赖性。 + +同样的算子给出加权收益的可预测变化率。 + +由乘性, + +$$ + \mathbb{E}\left[ + M_{n+1}\psi(X_{n+1}) - M_n \psi(X_n) + \mid \mathcal F_n + \right] + = + M_n (K\psi - \psi)(X_n) , +$$ + +所以从总变化中减去累积的可预测变化后剩下一个鞅: + +$$ + M_n\psi(X_n) + - \psi(X_0) + - \sum_{j=0}^{n-1} M_j (K\psi - \psi)(X_j) . +$$ + +这里 $K-I$ 是 $M_n \psi(X_n)$ 的*局部*变化率,通过 $K^n$ 它也控制长期增长。 + +### 从离散时间到连续时间 + +连续时间保持同样的逻辑。 + +$K-I$ 的自然对应物是半群 $\{\mathbb M_t\}$ 的**无穷小生成元**,即在零处的时间导数: + +$$ + \mathbb A \psi(x) + := + \lim_{h \downarrow 0} + \frac{\mathbb M_h \psi(x) - \psi(x)}{h}, +$$ + +因此对小的 $h>0$, + +$$ + \mathbb M_h \psi(x) + \approx + \psi(x) + h\, \mathbb A \psi(x) . +$$ + +```{note} +当 $M \equiv 1$ 时,乘性半群约化为标准的马尔可夫转移半群 $\mathbb M_t \psi(x) = \mathbb{E}[\psi(X_t) \mid X_0=x]$,而 $\mathbb A$ 变为教科书随机微积分中 $X$ 的熟悉的无穷小生成元 $\mathcal L$。 + +对于一般的 $M$,$\mathbb A$ 是同类型的对象,但它带有额外的项,用于编码 $M$ 的瞬时 "收益率":贴现率、布朗风险价格、跳跃乘子。 + +这正是我们在下面 {eq}`eq:extended-generator` 中写出其闭式时将看到的。 +``` + +为什么这是正确的对象? + +如果 $\mathbb A\phi = \rho\phi$,那么候选 + +$$ + \hat M_t := \exp(-\rho t)\, M_t\, \frac{\phi(X_t)}{\phi(X_0)} +$$ + +自动是一个*局部*鞅。 + +当 $\hat M$ 实际上是一个鞅时(这是 {cite:t}`HansenScheinkman2009` 中假设 6.1 的内容),取期望给出 $K^n\phi = \lambda^n\phi$ 的连续时间类比: + +$$ + \mathbb M_t \phi = \exp(\rho t)\, \phi . +$$ + +没有这个升级,我们只能得到上鞅不等式 $\mathbb M_t \phi \le \exp(\rho t)\, \phi$,我们将在下面重新讨论它。 + +因此 $\mathbb M_t$ 的长期行为被编码在局部算子 $\mathbb A$ 的一个特征值问题中,连同 $\hat M$ 的鞅性质。 + +### 扩展生成元 + +上面的极限定义需要一个限定条件。 + +为了使极限 $h \downarrow 0$ 严格化,教科书定义要求 $(\mathbb M_h\psi - \psi)/h$ 在选定的范数中收敛到 $\mathbb A\psi$,通常是有界连续函数上的一致收敛,此处半群是一个压缩。 + +但我们最关心的函数是求解 $\mathbb A\phi = \rho\phi$ 的主特征函数 $\phi$,而这些函数通常随状态 $X$ 而*增长*(在仿射-高斯基准中,$\phi$ 关于 $x$ 是指数-仿射的)。 + +所以它们不属于这个空间,极限对它们不一定收敛。 + +{cite:t}`HansenScheinkman2009` 通过用 $M_t \psi(X_t)$ 的一个 *Doob-Meyer 风格* 半鞅分解来刻画 $\mathbb A$,从而绕开了这一点,这是一个不需要任何范数的逐路径条件。 + +这是在离散时间中将 $K - I$ 写为 $M_n\psi(X_n)$ 的可预测变化率的连续时间对应物。 + +由此得到的**扩展生成元**允许无界的 $\psi$,具有比教科书生成元严格更大的定义域,并且在两者都有定义之处与之一致。 + +具体地: + +```{prf:definition} 扩展生成元 +:label: lrr-def-extended-generator + +固定一个博雷尔函数 $\psi$,并寻找第二个博雷尔函数 $\chi$,它将扮演 "$M_t \psi(X_t)$ 在当前状态处的瞬时变化率" 的角色。我们询问是否存在 $\chi$ 使得 + +$$ + N_t + = + M_t \psi(X_t) + - \psi(X_0) + - \int_0^t M_s \chi(X_s)\, ds +$$ + +是一个局部鞅。 + +我们于是称 $\psi$ 属于 $M$ 的**扩展生成元** $\mathbb A$ 的定义域,并*定义*该算子为 + +$$ +\mathbb A \psi := \chi. +$$ + +``` + +这三项扮演与离散时间中相同的角色: + +* $M_t \psi(X_t) - \psi(X_0)$ 是加权收益在 $[0, t]$ 上的总变化, +* $\int_0^t M_s \chi(X_s)\, ds$ 沿路径累积期望变化率, +* $N_t$ 是残差。 + +要求 $N_t$ 是一个局部鞅,就确定了 $\chi = \mathbb A\psi$ 为 $M_t \psi(X_t)$ 在当前状态处的瞬时期望变化率。 + +* 当 $M \equiv 1$ 时,该定义约化为标准马尔可夫生成元的 Dynkin 公式 + $\mathcal L \psi(x) + = \lim_{t \downarrow 0} t^{-1}\bigl[\mathbb{E}\psi(X_t) - \psi(x)\bigr]$。 + +* 当 $X$ 是一个跳跃扩散时,将伊藤公式应用于 $M_t\psi(X_t)$ 产生下面 {eq}`eq:extended-generator` 中 $\mathbb A\psi$ 的闭式表达式。 + +### 跳跃扩散的闭式 + +对于上面引入的跳跃-扩散设定,我们可以通过将伊藤公式应用于 $M_t\phi(X_t)$ 来显式计算 $\mathbb A$。 + +假设 $X$ 的连续部分满足 + +$$ + dX_t^c = \xi(X_t)dt + \Gamma(X_t)dB_t +$$ + +具有扩散矩阵 $\Sigma = \Gamma \Gamma^\top$,并设 $\eta(dy \mid x)$ 表示跳跃补偿子。 + +如果 $M=\exp(A)$ 按 {eq}`eq:additive-functional` 由 $(\beta,\gamma,\kappa)$ 参数化,那么对于光滑的 $\phi$, + +$$ +\begin{aligned} +\mathbb A \phi(x) +&= +\left[\xi(x)+\Gamma(x)\gamma(x)\right]^\top + \frac{\partial \phi(x)}{\partial x} +\\ +&\quad ++ \frac{1}{2} + \operatorname{trace}\left[ + \Sigma(x) + \frac{\partial^2\phi(x)}{\partial x \partial x^\top} + \right] +\\ +&\quad ++ \int + [\phi(y)-\phi(x)] + \exp[\kappa(y,x)] \eta(dy \mid x) +\\ +&\quad ++ \left[ + \beta(x) + + \frac{\gamma(x)^\top \gamma(x)}{2} + + \int + \left(\exp[\kappa(y,x)]-1\right)\eta(dy \mid x) + \right]\phi(x). +\end{aligned} +$$ (eq:extended-generator) + +这四项有透明的解释: + +1. 第一项是标准马尔可夫漂移,被 $\Gamma\gamma$ 修正,这是驱动 $X$ 的布朗冲击与驱动 $M$ 的布朗冲击之间的一个*协方差修正*。 +2. 第二项是标准扩散(伊藤)项。 +3. 第三项将 $\phi$ 对跳跃-被补偿的转移率积分,由跳跃乘子 $\exp[\kappa(y,x)]$ 重新加权。 +4. 第四项是一个乘性的*类收益率*项,它乘以 $\phi(x)$ 本身,并结合了 $M$ 的漂移、布朗伊藤修正和被补偿跳跃。 + +```{note} +当 $M=S$ 是一个随机贴现因子时,局部风险价格分散在生成元的四个部分中,而不是集中在水平项中。 + +* 布朗因子价格通过第一行中的漂移修正 $\xi \to \xi + \Gamma\gamma$ 进入。 +* 跳跃风险价格通过第三行中的倾斜跳跃测度 $\eta \to \exp[\kappa]\,\eta$ 进入。 +* 第四行中的水平项包含瞬时无风险利率成分(期限结构的*短端*)加上跳跃-补偿子贡献 $\int(\exp[\kappa]-1)\,\eta$。 + +我们请读者在 {ref}`lrr_ex4` 中验证 {eq}`eq:extended-generator` 的推导。 +``` + +我们将在下面的仿射-扩散例子中直接应用这个公式。 + +## 主特征函数 + +我们现在来到本讲座的核心技术问题: + +> 在估值半群下,哪些正收益以恒定的比例率增长? + +当答案存在时,它是生成元的一个正特征函数。 + +```{prf:definition} 扩展生成元的特征函数 +:label: lrr-def-generator-eigenfunction + +如果 + +$$ + \mathbb A \phi = \rho \phi , +$$ (eq:generator-eigen) + +则博雷尔函数 $\phi$ 是 $\mathbb A$ 的一个**特征函数**,特征值为 $\rho$。 + +一个**主特征函数**是一个在状态空间上严格正的特征函数 $\phi$:对所有 $x \in \mathcal D_0$ 有 $\phi(x) > 0$。 +``` + +严格正性要求很重要,因为 $\phi$ 将始终出现在分母中:除以它必须是安全的。 + +### 从特征函数到分解 + +为什么 $\mathbb A$ 的一个特征函数会给我们乘性分解 {eq}`eq:hs-factorization`? + +离散时间类比指明了方向。如果 $K\phi = \lambda\phi$,那么 + +$$ + \lambda^{-n}\, M_n\, \frac{\phi(X_n)}{\phi(X_0)} +$$ + +是一个鞅:特征值方程恰好吸收了 $M_n\phi(X_n)$ 的单步漂移。 + +在连续时间中,$\lambda^n$ 变为 $\exp(\rho t)$,候选鞅是 + +$$ + \hat M_t + = + \exp(-\rho t)\, M_t\, \frac{\phi(X_t)}{\phi(X_0)} . +$$ (eq:mhat) + +让我们检查 $\hat M$ 确实是一个局部鞅。 + +根据 $\mathbb A$ 的定义,半鞅 $Z_t := M_t\phi(X_t)$ 允许分解 + +$$ + dZ_t = M_t\, \mathbb A\phi(X_t)\, dt + dN_t , +$$ + +其中 $N$ 是一个局部鞅。 + +特征值方程 $\mathbb A\phi = \rho\phi$ 将漂移替换为 $\rho Z_t\, dt$,分部积分给出 + +$$ + d\bigl(\exp(-\rho t) Z_t\bigr) + = \exp(-\rho t)\,\bigl[dZ_t - \rho Z_t\, dt\bigr] + = \exp(-\rho t)\, dN_t . +$$ + +因此 $\exp(-\rho t) Z_t$ 是一个局部鞅,除以 $\phi(X_0)$ 表明 $\hat M$ 也是如此。 + +将 {eq}`eq:mhat` 关于 $M_t$ 重新排列可恢复分解 {eq}`eq:hs-factorization`,其中 $\hat M$ 扮演鞅成分的角色。 + +```{prf:definition} 鞅成分与扭曲测度 +:label: lrr-def-martingale-component + +当 $\hat M$ 是一个鞅(而不仅仅是一个局部鞅)时,它是与 $(\rho,\phi)$ 相关联的**鞅成分**,并通过用 $\hat M_t$ 对日期 $t$ 事件加权定义**扭曲概率测度**: + +$$ + \widehat{\Pr}(F \mid X_0=x) + = + \mathbb{E}[\hat M_t \mathbf 1_F \mid X_0=x], + \qquad F \in \mathcal F_t. +$$ +``` + +上述验证仅确立 $\hat M$ 是一个*局部*鞅,但上面的定义(以及 $\hat M$ 的测度变换解释)要求它是一个鞅。 + +我们通过采用 {cite:t}`HansenScheinkman2009` 的假设 6.1 来弥补这个缺口: + +> {eq}`eq:mhat` 中定义的局部鞅 $\hat M$ 是一个鞅,即对每个 $t \geq 0$ 和 $x$ 有 $\mathbb{E}[\hat M_t \mid X_0 = x] = 1$。 + +我们从此以后一直采用这个假设。 + +即使不弥补这个缺口,我们仍然得到单侧控制。 + +由于 $\hat M$ 是非负的且 $\hat M_0 = 1$,它是一个上鞅,所以 $\mathbb{E}[\hat M_t \mid X_0=x] \leq 1$。 + +在 {eq}`eq:mhat` 中取期望, + +$$ + \mathbb M_t \phi(x) \leq \exp(\rho t)\, \phi(x) , +$$ + +所以 $\rho$ 至少是 $\mathbb M_t \phi$ 长期增长率的一个上界。 + +当 $\hat M$ 实际上是一个鞅时,$\mathbb{E}[\hat M_t] = 1$,不等式变为等式,局部条件 $\mathbb A\phi = \rho\phi$ 提升为半群特征值方程 + +$$ + \mathbb M_t \phi = \exp(\rho t)\, \phi, + \qquad t \geq 0. +$$ (eq:semigroup-eigen) + +### 扭曲过程的稳定性 + +我们现在有了对*任意*主特征函数的分解 {eq}`eq:hs-factorization`。 + +但要使 $(\rho,\phi)$ 描述 $\mathbb M_t$ 的**长期**行为,扭曲过程必须在 $t \to \infty$ 时收敛到一个平稳状态。 + +如果不这样,瞬态因子 $\phi(X_0)/\phi(X_t)$ 将不会消失,我们就无法仅从 $\rho$ 读出渐近行为。 + +我们需要三个条件,每个都排除了扭曲过程无法稳定下来的一种特定方式。 + +设 $\hat E$ 和 $\widehat{\Pr}$ 表示扭曲测度下的期望和概率,并设 $\hat{\mathbb A}$ 为该测度下 $X$ 的生成元。 + +*条件 1:存在一个平稳分布。* + +```{prf:definition} 扭曲过程的平稳分布 +:label: lrr-def-stationary-distribution + +如果对 $\hat{\mathbb A}$ 的 $L^\infty$ 定义域中的每个 $\psi$, + +$$ + \int \hat{\mathbb A}\psi\, d\hat\varsigma = 0 +$$ + +则 $\mathcal D_0$ 上的概率测度 $\hat\varsigma$ 是扭曲过程的一个**平稳分布**。 +``` + +$\hat\varsigma$ 是候选的长期分布。 + +没有它,扭曲过程就没有稳态,长期极限就无法表示为状态空间积分。 + +*条件 2:每个重要区域都可达。* + +```{prf:definition} 不可约骨架 +:label: lrr-def-irreducible-skeleton + +如果存在 $\Delta > 0$,使得对每个满足 $\hat\varsigma(\Lambda) > 0$ 的博雷尔集 $\Lambda \subseteq \mathcal D_0$, + +$$ + \hat E\!\left[ + \sum_{j=0}^\infty \mathbf 1_{\{X_{\Delta j} \in \Lambda\}} + \,\bigg|\, X_0 = x + \right] > 0 + \qquad \text{对所有 } x \in \mathcal D_0 , +$$ + +则离散采样骨架 $\{X_{\Delta j} : j = 0, 1, \ldots\}$ 相对于 $\hat\varsigma$ 是**不可约的**。 +``` + +没有它,长期分布可能依赖于起始状态;不同的吸引域会给出不同的极限。 + +*条件 3:每个重要区域都被无穷次访问。* + +```{prf:definition} 哈里斯常返 +:label: lrr-def-harris-recurrence + +如果对每个满足 $\hat\varsigma(\Lambda) > 0$ 的博雷尔集 $\Lambda \subseteq \mathcal D_0$, + +$$ + \widehat{\Pr}\!\left\{ + \int_0^\infty \mathbf 1_{\{X_t \in \Lambda\}}\, dt = \infty + \,\bigg|\, X_0 = x + \right\} = 1 + \qquad \text{对所有 } x \in \mathcal D_0 , +$$ + +则过程 $X$ 在扭曲测度下是**哈里斯常返的**。 +``` + +可达性(条件 2)是不够的。 + +一个集合可能是可达的,但以趋于零的概率被访问,因此时间平均无法收敛到 $\hat\varsigma$-平均。 + +哈里斯常返是有限链中 "常返状态" 的连续状态对应物。 + +收集这三个条件: + +```{prf:definition} 随机稳定的扭曲过程 +:label: lrr-def-stochastic-stability + +如果 $\hat M$-扭曲的马尔可夫过程有一个平稳分布 $\hat\varsigma$,骨架 $\{X_{\Delta j}\}$ 相对于 $\hat\varsigma$ 是不可约的,且 $X$ 在扭曲测度下是哈里斯常返的,则它是**随机稳定的**。 +``` + +### 长期近似 + +在 $\hat M$ 的鞅条件、$M$ 的严格正性以及随机稳定性下,长期极限取一个简洁的形式: + +$$ + \lim_{t \to \infty} + \exp(-\rho t)\, \mathbb M_t \psi + = + \phi + \int \frac{\psi}{\phi}\, d\hat\varsigma . +$$ (eq:long-run-limit) + +如下解读它: + +* 因子 $\exp(\rho t)$ 捕捉半群的指数增长或衰减;一旦我们将其除去,剩下的部分有一个有限极限。 +* 该极限中的状态依赖性*完全*由 $\phi(x)$ 捕捉。 +* 标量 $\int (\psi/\phi)\, d\hat\varsigma$ 是收益 $\psi$ 的**长期强度**,用 $1/\phi$ 加权并对扭曲平稳分布取平均。 + +{cite:t}`HansenScheinkman2009` 命题 7.1 的两个精确情形是: + +* **采样网格,$\hat\varsigma$-几乎每个起始状态。** 固定任意 $\Delta>0$ 并假设 $\int |\psi|/\phi\, d\hat\varsigma < \infty$;那么该极限对 $\hat\varsigma$-几乎每个 $x \in \mathcal D_0$ 沿 $t = \Delta j$ 成立。 +* **连续 $t$,每个起始状态。** 如果 $\psi/\phi$ 是有界的,那么该极限对每个 $x \in \mathcal D_0$ 和每个 $t \to \infty$ 成立,无需对 $\psi$ 作连续性假设。 + +```{note} +$\mathbb A$ 可能有不止一个正特征函数使得相关联的 $\hat M$ 是一个鞅,可能有不同的特征值。 + +随机稳定性挑选出一个特定的。 + +根据 {cite:t}`HansenScheinkman2009` 命题 7.2,稳定特征函数的特征值 $\rho$ 是所有满足所维持条件的、允许严格正特征函数的 $\mathbb A$ 特征值中**最小**的。 + +任何共享此 $\rho$ 的其他正特征函数在 $\hat\varsigma$-几乎必然意义下与 $\phi$ 成比例。 + +下面的有限状态部分用更熟悉的佩龙-弗罗贝尼乌斯语言陈述了同样的选择,称 $\rho$ 为 $A$ 所有特征值中实部*最大*的特征值。 + +这两种描述识别出同一个特征值,因为在不可约有限状态情形中,$A$ 只有一个特征值允许严格正的特征向量。 + +在下面的仿射例子中,这两个集合分开了,因为二次方程 {eq}`eq:cf-roots` 有两个根 $c_f$,它们都给出具有不同特征值的严格正指数-仿射特征函数。 + +随机稳定性通过拒绝产生爆炸性扭曲过程的那个根,挑选出较小的 $\rho$。 +``` + +## 一个有限状态马尔可夫链 + +我们现在将该框架应用于一个具体的例子。 + +我们从最简单的情形开始:一个有限状态马尔可夫链。 + +关于离散时间有限马尔可夫链的背景,见 {doc}`finite_markov`。 + +关于激发此处构造的有限状态链的资产定价应用,见 {doc}`markov_asset`。 + +这里,每个抽象对象都坍缩为一个熟悉的对象: + +| 抽象对象 | 有限状态版本 | +|:---|:---| +| 马尔可夫过程 $X$ | 具有强度矩阵 $U$ 的连续时间链 | +| 生成元 $\mathbb A$ | 一个矩阵 $A$ | +| 半群 $\mathbb M_t$ | 矩阵指数 $\exp(tA)$ | +| 主特征函数 $\phi$ | 佩龙右特征向量 | +| 主特征值 $\rho$ | $A$ 的主实特征值 | +| 平稳分布 $\hat\varsigma$ | 扭曲生成元的左特征向量 | + +所以长期分析约化为佩龙-弗罗贝尼乌斯理论。 + +(关于佩龙-弗罗贝尼乌斯定理的介绍,见 {doc}`intro:eigen_II`。) + +### 设定 + +设 $X$ 在 $\{x_1,\ldots,x_N\}$ 中取值,并设 $U$ 为其强度矩阵。 + +```{prf:definition} 强度矩阵 +:label: lrr-def-intensity-matrix + +有限状态连续时间马尔可夫链的**强度矩阵** $U$ 满足对 $i \neq j$ 有 $u_{ij} \geq 0$ 且对每个状态 $i$ 有 $\sum_j u_{ij}=0$。 + +非对角元 $u_{ij}$ 是从状态 $i$ 到状态 $j$ 的跳跃率;对角元 $u_{ii} = -\sum_{j \neq i}u_{ij}$ 是状态 $i$ 的退出率的负值。 +``` + +设乘性泛函有 + +* 状态 $i$ 中的一个**贴现或衰减率** $r_i$(可加参数化中漂移 $\beta(X_s)$ 的类比),以及 +* 一个**跳跃乘子** $\exp[\kappa(x_j,x_i)]$,每当状态从 $i$ 跳到 $j$ 时触发。 + +在下面的代码中,`κ[j, i]` 意为 $\kappa(x_j,x_i)$。 + +那么乘性半群的生成元矩阵 $A$ 为 + +$$ + a_{ij} + = + \begin{cases} + u_{ii} - r_i, & i=j, \\ + u_{ij}\exp[\kappa(x_j,x_i)], & i \neq j . + \end{cases} +$$ (eq:finite-a) + +非对角元是链的跳跃率被跳跃乘子*加权*的结果;对角元将退出率与状态内衰减率结合。 + +半群于是就是 $\mathbb M_t = \exp(tA)$。 + +对于一个具有严格正跳跃乘子的不可约链,主特征值 $\rho$ 是 $A$ 的唯一具有最大实部的实特征值,相关联的右特征向量是严格正的。 + +主特征对 $(\rho,\phi)$ 下的扭曲生成元为 + +$$ + \hat A = D_\phi^{-1} A D_\phi - \rho I, +$$ + +其中 $D_\phi = \operatorname{diag}(\phi)$。 + +$\hat A$ 的行和为零,所以 $\hat A$ 本身是一个有效的强度矩阵。 + +平稳分布 $\hat\varsigma$ 求解 $\hat\varsigma^\top \hat A = 0$。 + +下面的辅助函数实现了这三个计算。 + +```{code-cell} ipython3 +def build_generator(U, r, κ): + """有限状态乘性半群的生成元矩阵。 + + κ[j, i] 是转移 i -> j 的对数跳跃乘子。 + """ + U = np.asarray(U, dtype=float) + r = np.asarray(r, dtype=float) + κ = np.asarray(κ, dtype=float) + + A = U * np.exp(κ.T) + np.fill_diagonal(A, np.diag(U) - r) + return A + + +def principal_eigenpair(A): + """具有正右特征向量的佩龙特征对。""" + vals, vecs = eig(A) + idx = np.argmax(vals.real) + + ρ = vals[idx].real + φ = vecs[:, idx].real + + if φ.sum() < 0: + φ = -φ + + if np.any(φ <= 0): + if np.min(φ) > -1e-10: + φ = np.maximum(φ, 0) + else: + raise ValueError( + "Dominant eigenvector is not strictly positive.") + + φ = φ / φ.mean() + return ρ, φ + + +def twisted_generator(A, ρ, φ): + """扭曲测度下的生成元。""" + D = np.diag(φ) + D_inv = np.diag(1 / φ) + return D_inv @ A @ D - ρ * np.eye(len(φ)) + + +def stationary_distribution(Q): + """有限状态生成元的平稳分布。""" + vals, vecs = eig(Q.T) + idx = np.argmin(np.abs(vals)) + π = vecs[:, idx].real + + if π.sum() < 0: + π = -π + + π = np.maximum(π, 0) + return π / π.sum() +``` + +### 两个状态 + +考虑一个繁荣-衰退经济。 + +状态 1 是*繁荣*(较高的短期利率 $r_1=0.05$,以速率 $\lambda_1 = 0.30$ 切换到衰退)。 + +状态 2 是*衰退*(较低的短期利率 $r_2=0.02$,以速率 $\lambda_2 = 0.50$ 切换到繁荣)。 + +目前我们将跳跃乘子设为零,所以 SDF 只通过状态内衰减率连续变化。 + +```{code-cell} ipython3 +λ_1 = 0.30 +λ_2 = 0.50 + +U = np.array([[-λ_1, λ_1], + [ λ_2, -λ_2]]) + +r = np.array([0.05, 0.02]) +κ = np.zeros((2, 2)) + +A = build_generator(U, r, κ) +ρ, φ = principal_eigenpair(A) + +print("A =") +print(np.round(A, 4)) +print(f"\nρ = {ρ:.6f}") +print(f"φ = {φ}") +print(f"long-run zero-coupon yield = {-ρ:.4f}") +``` + +注意 $-\rho$ 是零息债券的渐近收益率:由 {eq}`eq:hs-factorization`,一个长期零息债券的日期 $0$ 价格像 $\exp(\rho t)$ 一样衰减,所以其收益率为 $-\rho$。 + +让我们数值验证半群特征值方程 $\mathbb M_t \phi = \exp(\rho t)\phi$。 + +```{code-cell} ipython3 +for t in [1.0, 5.0, 25.0]: + lhs = expm(t * A) @ φ + rhs = np.exp(ρ * t) * φ + err = np.max(np.abs(lhs - rhs)) + print(f"t = {t:4.1f}, error = {err:.2e}") +``` + +对每个 $t$,误差都在机器精度水平,所以该方程精确成立,仅有来自特征分解的浮点噪声。 + +接下来我们计算扭曲生成元 $\hat A$ 以及链在扭曲测度下的平稳分布 $\hat\varsigma$。 + +这是出现在长期极限 {eq}`eq:long-run-limit` 中的候选长期分布。 + +```{code-cell} ipython3 +A_hat = twisted_generator(A, ρ, φ) +ς_hat = stationary_distribution(A_hat) + +print("twisted generator row sums:") +print(np.round(A_hat.sum(axis=1), 12)) + +print("\ntwisted stationary distribution:") +print(f" boom {ς_hat[0]:.4f}") +print(f" recession {ς_hat[1]:.4f}") +``` + +这个扭曲平稳分布(而非原始链的平稳分布)决定了长视界估值。 + +它与原始链的平稳分布不同,因为特征函数 $\phi$ 根据各状态对乘性泛函影响的持久程度对它们重新加权。 + +对任何收益函数 $\psi$,长期极限 {eq}`eq:long-run-limit` 是向量 + +$$ + \phi + \sum_i \frac{\psi_i}{\phi_i}\hat\varsigma_i . +$$ + +让我们检查随着 $t$ 增长,重新缩放的半群收敛到此极限。 + +```{code-cell} ipython3 +ψ = np.array([1.0, 2.0]) +limit = φ * np.sum((ψ / φ) * ς_hat) + +for t in [1, 5, 20, 80]: + approx = np.exp(-ρ * t) * expm(t * A) @ ψ + print(f"t = {t:2d}, normalized value = {approx}") + +print("\nlimit =", limit) +``` + +数值值收敛到极限;下一张图以图形方式展示了同样的收敛。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 重新缩放的半群向其长期极限的收敛 + name: fig-lrr-semigroup-convergence +--- +t_grid = np.linspace(0.01, 80, 400) +rescaled = np.array([np.exp(-ρ * t) * expm(t * A) @ ψ for t in t_grid]) + +fig, ax = plt.subplots() +ax.plot(t_grid, rescaled[:, 0], lw=2, label="从繁荣开始") +ax.plot(t_grid, rescaled[:, 1], lw=2, label="从衰退开始") +ax.axhline(limit[0], color="C0", ls="--", lw=1, alpha=0.7) +ax.axhline(limit[1], color="C1", ls="--", lw=1, alpha=0.7) +ax.set_xlabel("$t$") +ax.set_ylabel(r"$e^{-\rho t}\,(\mathbb{M}_t \psi)(x)$") +ax.legend() +plt.show() +``` + +两条实线追踪了从每个状态出发的重新缩放的值,虚线水平线标记了 {eq}`eq:long-run-limit` 所预测的极限。 + +两条曲线都稳定在其预测的极限上,证实了长期行为仅通过 $\phi$ 依赖于起始状态。 + +```{note} +渐近指数收敛率由主特征值 $\rho$ 的*实部*与 $A$ 其余特征值中最大实部之间的差距所控制。 + +对于一个不可约的梅茨勒矩阵,主特征值是实的,其实部严格大于其他特征值,所以这个差距是良定义的。 + +{ref}`lrr_ex3` 通过一个三状态例子详细说明了如何直接检查这个差距。 +``` + +### 加入跳跃 + +这个链中的状态转移是不连续的,所以让乘性泛函在转移时刻跳跃是自然的。 + +这些跳跃是跳跃-扩散参数化中 $\kappa$ 函数的类比。 + +一个自然的例子出现在一个随机贴现因子上,当经济从衰退进入繁荣时它*向下*跳跃,在反向转移时*向上*跳跃。 + +下面的矩阵 `κ_jump` 编码了这一点。 + +我们使用约定 `κ[j, i]` = 转移 $i \to j$ 时 $M$ 的对数跳跃乘子,其中状态索引 0 = 繁荣,状态索引 1 = 衰退。 + +```{code-cell} ipython3 +# 衰退 (1) -> 繁荣 (0): SDF 在好消息时向下跳跃 (exp(-0.20)) +# 繁荣 (0) -> 衰退 (1): SDF 在坏消息时向上跳跃 (exp(+0.30)) +κ_jump = np.array([[ 0.0, -0.20], + [ 0.30, 0.0]]) + +A_jump = build_generator(U, r, κ_jump) +ρ_jump, φ_jump = principal_eigenpair(A_jump) + +print(f"ρ without jumps = {ρ:.6f}") +print(f"ρ with jumps = {ρ_jump:.6f}") +print("\nφ with jumps:") +print(φ_jump) +``` + +为看清长期率 $\rho$ 如何响应跳跃风险,我们固定繁荣到衰退的乘子,并随着衰退到繁荣乘子的变化描绘出 $\rho$。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 跳跃与长期增长率 + name: fig-lrr-jumps-eigenvalue +--- +κ_grid = np.linspace(-0.5, 0.5, 100) +ρ_grid = np.empty_like(κ_grid) + +for n, k in enumerate(κ_grid): + κ_temp = np.array([[0.0, k], + [0.30, 0.0]]) + A_temp = build_generator(U, r, κ_temp) + ρ_grid[n], _ = principal_eigenpair(A_temp) + +fig, ax = plt.subplots() +ax.plot(κ_grid, ρ_grid, lw=2) +ax.axhline(ρ, color="black", ls="--", lw=1) +ax.axvline(0, color="black", ls=":", lw=1) +ax.set_xlabel("衰退到繁荣的跳跃对数乘子") +ax.set_ylabel("主特征值") +plt.show() +``` + +主特征值关于衰退到繁荣的对数乘子单调递增:随着该乘子上升,$M$ 在好消息时向下跳得更少(或向上跳得更多),这机械地推高了 $\rho$。 + +经济上合理的 SDF 区域在零的左侧,那里乘子为负。 + +## 仿射扩散例子 + +我们现在转向一个连续状态模型。 + +我们将使用一个二因子仿射设定,它捕捉资产回报的两个主要经验特征: + +* **随机波动率**,其中冲击的离散度本身是一个状态变量,以及 +* **可预测增长**,其中一个小的、持久的状态变量移动期望增长率。 + +这是长期风险模型(如 {cite:t}`Bansal_Yaron_2004`)中使用的那种状态过程。 + +我们研究两个独立的状态成分:一个 Feller 平方根过程 $X^f$(随机波动率)和一个 Ornstein-Uhlenbeck 过程 $X^o$(可预测增长): + +$$ +\begin{aligned} +dX_t^f +&= +\xi_f(\bar x_f - X_t^f)dt ++ \sqrt{X_t^f}\sigma_f dB_t^f, +\\ +dX_t^o +&= +\xi_o(\bar x_o - X_t^o)dt ++ \sigma_o dB_t^o. +\end{aligned} +$$ (eq:affine-state) + +参数 $\xi_f, \xi_o>0$ 是均值回归速度,$\bar x_f, \bar x_o$ 是无条件均值,$\sigma_f, \sigma_o$ 是扩散系数。 + +OU 过程 $X^o$ 是 {doc}`intro:ar1_processes` 中研究的 AR(1) 过程的连续时间类比,同族中的连续时间线性资产定价模型在 {doc}`affine_risk_prices` 中发展。 + +我们遵循符号约定 $\sigma_o>0$ 和 $\sigma_f<0$:一个正的 $B^f$ 冲击于是*降低*波动率,与经验上的 "杠杆效应" 一致。 + +现在考虑一个具有仿射参数的乘性泛函 $M=\exp(A)$: + +$$ +\begin{aligned} +A_t +&= +\bar\beta t ++ \int_0^t \beta_f X_s^f\, ds ++ \int_0^t \beta_o X_s^o\, ds +\\ +&\quad ++ \int_0^t \sqrt{X_s^f}\,\gamma_f\, dB_s^f ++ \int_0^t \gamma_o\, dB_s^o . +\end{aligned} +$$ (eq:affine-additive) + +所以 $A$ 的漂移关于状态是仿射的($\bar\beta + \beta_f X^f + \beta_o X^o$),布朗载荷在 $B^o$ 方向上是常数,在 $B^f$ 方向上与 $\sqrt{X^f}$ 成比例。 + +### 为什么指数-仿射特征函数有效 + +当状态是仿射的且 $A$ 的漂移是仿射的时,将生成元应用于一个指数-仿射函数 $\phi(x^f,x^o) = \exp(c_f x^f + c_o x^o)$ 会返回另一个指数-仿射函数。 + +这个封闭性质将特征值方程 $\mathbb A\phi = \rho\phi$ 转化为关于 $(c_f, c_o, \rho)$ 的一个小型代数方程组。 + +```{prf:definition} 指数-仿射特征函数 +:label: lrr-def-exponential-affine-eigenfunction + +如果对某个常数 $c_0 \in \mathbb R$ 和向量 $c \in \mathbb R^n$, + +$$ + \phi(x) = \exp(c_0 + c^\top x) + \qquad \text{对所有 } x \in \mathcal D_0 , +$$ + +则状态空间 $\mathcal D_0 \subseteq \mathbb R^n$ 上 $\mathbb A$ 的特征函数 $\phi$ 是**指数-仿射的**。 +``` + +将 $\phi(x^f,x^o) = \exp(c_f x^f + c_o x^o)$ 代入生成元公式 {eq}`eq:extended-generator` 并匹配 $x^f$、$x^o$ 和常数项的系数,得到 + +$$ +0 += +\beta_f ++ \frac{\gamma_f^2}{2} ++ c_f(\gamma_f\sigma_f-\xi_f) ++ c_f^2\frac{\sigma_f^2}{2}, +$$ (eq:cf-eq) + +以及 + +$$ + c_o = \frac{\beta_o}{\xi_o}. +$$ (eq:co-eq) + +$c_f$ 的两个候选值为 + +$$ +c_f += +\frac{ + \xi_f-\gamma_f\sigma_f + \pm + \sqrt{ + (\xi_f-\gamma_f\sigma_f)^2 + - \sigma_f^2(2\beta_f+\gamma_f^2) + } +}{\sigma_f^2}. +$$ (eq:cf-roots) + +特征值随后通过匹配常数项确定: + +$$ +\rho += +\bar\beta ++ \frac{\gamma_o^2}{2} ++ c_f \xi_f \bar x_f ++ c_o(\xi_o\bar x_o+\gamma_o\sigma_o) ++ c_o^2 \frac{\sigma_o^2}{2}. +$$ (eq:affine-rho) + +方程 {eq}`eq:cf-roots` 给出 $c_f$ 的两个候选值,我们需要知道哪一个是主特征函数。 + +这就是随机稳定性({prf:ref}`lrr-def-stochastic-stability`)真正起作用的地方。 + +在扭曲测度下,$X^f$ 的漂移为 + +$$ + \xi_f(\bar x_f - x^f) + + x^f\sigma_f(\gamma_f+c_f\sigma_f), +$$ + +所以均值回归系数变为 + +$$ + \xi_f - \sigma_f(\gamma_f+c_f\sigma_f) . +$$ + +如果这是正的,扭曲平方根过程保持平稳;如果它是负的,扭曲过程是爆炸性的,特征函数不是长期相关的那个。 + +所以我们**选取使扭曲过程保持均值回归的那个根**,这正是抽象理论中随机稳定性选择主特征函数的方式。 + +```{code-cell} ipython3 +def solve_affine_eigenfunction(params): + """求解指数-仿射特征值问题。""" + ξ_f = params["ξ_f"] + xbar_f = params["xbar_f"] + σ_f = params["σ_f"] + ξ_o = params["ξ_o"] + xbar_o = params["xbar_o"] + σ_o = params["σ_o"] + β_bar = params["β_bar"] + β_f = params["β_f"] + β_o = params["β_o"] + γ_f = params["γ_f"] + γ_o = params["γ_o"] + + co = β_o / ξ_o + + disc = ((ξ_f - γ_f * σ_f) ** 2 + - σ_f ** 2 * (2 * β_f + γ_f ** 2)) + + if disc < 0: + raise ValueError("No real affine eigenfunction for these parameters.") + + root = np.sqrt(disc) + cf_roots = ( + ((ξ_f - γ_f * σ_f) - root) / σ_f ** 2, + ((ξ_f - γ_f * σ_f) + root) / σ_f ** 2 + ) + + def mean_reversion(cf): + return ξ_f - σ_f * (γ_f + cf * σ_f) + + for cf in cf_roots: + mr = mean_reversion(cf) + if mr > 0: + break + else: + raise ValueError("Neither root gives a stationary twisted process.") + + ρ = (β_bar + + γ_o ** 2 / 2 + + cf * ξ_f * xbar_f + + co * (ξ_o * xbar_o + γ_o * σ_o) + + co ** 2 * σ_o ** 2 / 2) + + return cf, co, ρ, mr +``` + +### 一个 Breeden SDF + +为使问题具体化,我们现在代入一个特定的随机贴现因子:Breeden CRRA 基于消费的 SDF。 + +{cite:t}`Breeden1979` 为一个对消费流具有时间可分 CRRA 偏好的投资者推导了连续时间 SDF。 + +我们用同样的仿射状态 $X^o$ 驱动期望增长、$\sqrt{X^f}$ 驱动波动率来设定对数消费: + +$$ + dc_t + = + X_t^o\, dt + + \sqrt{X_t^f}\,\vartheta_f\, dB_t^f + + \vartheta_o\, dB_t^o . +$$ + +在时间可分 CRRA 效用(风险厌恶 $a$)和主观贴现率 $b$ 下,随机贴现因子为 + +$$ + S_t + = + \exp\!\big(-bt - a(c_t-c_0)\big), +$$ + +即 $-b$ 乘以时间减去 $a$ 乘以对数消费增长的指数。 + +读出可加泛函系数给出 + +$$ + \bar\beta^s = -b, + \quad + \beta_f^s = 0, + \quad + \beta_o^s = -a, + \quad + \gamma_f^s = -a\vartheta_f, + \quad + \gamma_o^s = -a\vartheta_o . +$$ (eq:breeden-sdf-params) + +我们将在下面的数值例子中使用这些参数。 + +### 递归偏好(可选) + +CRRA 偏好的一个著名局限是它将风险厌恶与跨期替代弹性混为一谈。 + +递归偏好 {cite:t}`Kreps_Porteus1978, Epstein_Zin1989` 将两者分开,并在贴现因子表达式中加入一个前瞻性的延续值项。 + +这就是驱动 {cite:t}`Bansal_Yaron_2004` 中股权溢价结果的机制。 + +一篇在不同设定下研究递归偏好下长期动态的 QuantEcon 讲座是 {doc}`survival_recursive_preferences`。 + +本节推导单位弹性递归设定的 SDF 系数。 + +你可以在第一次阅读时跳过,稍后再回来——数值例子使用上面较简单的 Breeden 参数。 + +对于单位弹性递归设定,猜测一个如下形式的延续值 + +$$ + W_t + = + \frac{1}{1-a} + \exp\left[ + (1-a)(w_f X_t^f + w_o X_t^o + c_t + \bar w) + \right], + \qquad a>1 . +$$ (eq:kp-continuation-value) + +匹配这个延续值的局部均值给出 + +$$ +\begin{aligned} +0 +&= +-\xi_f w_f ++ \frac{(1-a)\sigma_f^2}{2}w_f^2 ++ (1-a)\vartheta_f\sigma_f w_f ++ \frac{(1-a)\vartheta_f^2}{2} +- b w_f, +\\ +0 +&= +-\xi_o w_o + 1 - b w_o, +\\ +b\bar w +&= +\xi_f \bar x_f w_f ++ \xi_o \bar x_o w_o ++ \frac{(1-a)\sigma_o^2}{2}w_o^2 ++ (1-a)\vartheta_o\sigma_o w_o ++ \frac{(1-a)\vartheta_o^2}{2}. +\end{aligned} +$$ (eq:kp-continuation-coefficients) + +相关解有 $w_o=1/(\xi_o+b)$,为 $w_f$ 选择二次方程的稳定根,然后从常数方程确定 $\bar w$。 + +随机贴现因子是乘积 $S_t=\exp(A_t^B)\exp(A_t^W)$,其中类 Breeden 的对数成分为 + +$$ + A_t^B + = + -bt + - \int_0^t X_s^o ds + - \int_0^t \sqrt{X_s^f}\vartheta_f dB_s^f + - \int_0^t \vartheta_o dB_s^o +$$ + +延续值鞅成分为 + +$$ +\begin{aligned} + A_t^W + &= + (1-a)\int_0^t + \sqrt{X_s^f}(\vartheta_f+w_f\sigma_f)dB_s^f + + (1-a)\int_0^t + (\vartheta_o+w_o\sigma_o)dB_s^o +\\ + &\quad + - \frac{(1-a)^2}{2} + \int_0^t X_s^f(\vartheta_f+w_f\sigma_f)^2ds + - \frac{(1-a)^2}{2} + (\vartheta_o+w_o\sigma_o)^2t . +\end{aligned} +$$ (eq:kp-sdf-components) + +因此递归效用 SDF 具有仿射参数 + +$$ +\begin{aligned} +\bar\beta^s +&= +-b-\frac{(1-a)^2}{2}(\vartheta_o+w_o\sigma_o)^2, +\\ +\beta_f^s +&= +-\frac{(1-a)^2}{2}(\vartheta_f+w_f\sigma_f)^2, +\\ +\beta_o^s +&= -1, +\\ +\gamma_f^s +&= +-a\vartheta_f-(a-1)w_f\sigma_f, +\\ +\gamma_o^s +&= +-a\vartheta_o-(a-1)w_o\sigma_o . +\end{aligned} +$$ (eq:kp-sdf-params) + +因此局部布朗风险价格为 $B^f$ 暴露的 $\sqrt{x^f}[a\vartheta_f+(a-1)w_f\sigma_f]$ 和 $B^o$ 暴露的 $a\vartheta_o+(a-1)w_o\sigma_o$。 + +下面的数值例子使用较简单的 Breeden 设定,但一旦将 SDF 参数替换为 {eq}`eq:kp-sdf-params`,同样的算子计算就适用。 + +### 数值例子 + +让我们设定参数并求解主特征对。 + +我们使用标准长期风险邻域中的参数:一个均值回归波动率因子 $X^f$,均值为 $0.04$,一个移动更慢的可预测增长因子 $X^o$,均值为 $0.02$,风险厌恶 $a=4$,以及时间贴现率 $b=0.03$。 + +```{code-cell} ipython3 +params_state = { + "ξ_f": 0.70, + "xbar_f": 0.04, + "σ_f": -0.20, + "ξ_o": 0.50, + "xbar_o": 0.02, + "σ_o": 0.01, +} + +a = 4.0 +b = 0.03 +ϑ_f = 0.06 +ϑ_o = 0.02 + +params_sdf = { + **params_state, + "β_bar": -b, + "β_f": 0.0, + "β_o": -a, + "γ_f": -a * ϑ_f, + "γ_o": -a * ϑ_o, +} + +cf_s, co_s, ρ_s, mr_s = solve_affine_eigenfunction(params_sdf) + +print("principal eigenfunction φ(xf, xo) = exp(cf xf + co xo)") +print(f"cf = {cf_s:.6f}") +print(f"co = {co_s:.6f}") +print(f"ρ = {ρ_s:.6f}") +print(f"twisted mean-reversion coefficient for Xf = {mr_s:.6f}") +print(f"long-run zero-coupon yield = {-ρ_s:.4f}") +``` + +长期零息收益率 $-\rho_s$ 表示 SDF 期望 $\mathbb{E}[S_t]$ 中的渐近衰减率。 + +我们还可以检查 $c_f$ 被拒绝的根本会产生一个非平稳的扭曲过程,这是随机稳定性在两个代数上有效的特征函数中选择其一的一个清晰例子。 + +```{code-cell} ipython3 +ξ_f = params_sdf["ξ_f"] +σ_f = params_sdf["σ_f"] +γ_f = params_sdf["γ_f"] +β_f = params_sdf["β_f"] + +disc = ((ξ_f - γ_f * σ_f) ** 2 + - σ_f ** 2 * (2 * β_f + γ_f ** 2)) +root = np.sqrt(disc) + +cf_candidates = np.array([ + ((ξ_f - γ_f * σ_f) - root) / σ_f ** 2, + ((ξ_f - γ_f * σ_f) + root) / σ_f ** 2 +]) + +for cf in cf_candidates: + mr = ξ_f - σ_f * (γ_f + cf * σ_f) + print(f"cf = {cf:8.4f}, twisted mean reversion = {mr:8.4f}") +``` + +### 鞅成分 + +现在我们有了特征对 $(\rho,\phi)$,我们可以显式写出分解 {eq}`eq:hs-factorization` 的所有三个部分。 + +{eq}`eq:mhat` 中定义的鞅成分 $\hat M_t = \exp(\hat A_t)$ 的对数为 + +$$ +\begin{aligned} +\hat A_t +&= +\int_0^t \sqrt{X_s^f}(\gamma_f+c_f\sigma_f)\, dB_s^f ++ \int_0^t (\gamma_o+c_o\sigma_o)\, dB_s^o +\\ +&\quad +- \frac{1}{2}\int_0^t X_s^f(\gamma_f+c_f\sigma_f)^2\, ds +- \frac{1}{2}\int_0^t (\gamma_o+c_o\sigma_o)^2\, ds . +\end{aligned} +$$ + +第一行是布朗积分("指数鞅" 部分);第二行是使它成为鞅所需的伊藤修正。 + +在由 $\hat M$ 诱导的扭曲测度下,状态变量的漂移移动为 + +$$ +\begin{aligned} +dX_t^f: +\quad& +\xi_f(\bar x_f-X_t^f) ++ X_t^f \sigma_f(\gamma_f+c_f\sigma_f), +\\ +dX_t^o: +\quad& +\xi_o(\bar x_o-X_t^o) ++ \sigma_o(\gamma_o+c_o\sigma_o). +\end{aligned} +$$ + +漂移扭曲恰好是由 $\hat M$ 的布朗载荷诱导的 Girsanov 移动。 + +现在让我们模拟状态并数值检查分解。 + +第一个检查是*代数恒等式*:一旦我们通过 {eq}`eq:mhat` 定义 $\hat M$,方程 $M_t = \exp(\rho t)\hat M_t \phi(X_0)/\phi(X_t)$ 对任何 $(\rho,\phi)$ 的选择都自动成立,下面的误差只是浮点舍入。 + +第二个更实质性的检查是我们求解出的特征对 $(\rho,\phi)$ 是否真的使 $\hat M$ 成为一个鞅,我们通过在许多模拟路径上计算 $\mathbb{E}[\hat M_t]$ 来近似。 + +```{code-cell} ipython3 +def brownian_increments(n, dt, seed=1234): + """用于模拟的独立布朗增量。""" + rng = np.random.default_rng(seed) + draws = rng.normal(scale=np.sqrt(dt), size=(n, 2)) + return draws[:, 0], draws[:, 1] + + +def simulate_states(params, T=40.0, dt=0.01, seed=1234): + """仿射状态过程的欧拉模拟。""" + n = int(T / dt) + t = np.linspace(0, T, n + 1) + Xf = np.empty(n + 1) + Xo = np.empty(n + 1) + dBf, dBo = brownian_increments(n, dt, seed) + + Xf[0] = params["xbar_f"] + Xo[0] = params["xbar_o"] + + for k, (dBf_k, dBo_k) in enumerate(zip(dBf, dBo)): + xf = max(Xf[k], 1e-10) + xo = Xo[k] + + Xf[k + 1] = (xf + + params["ξ_f"] * (params["xbar_f"] - xf) * dt + + np.sqrt(xf) * params["σ_f"] * dBf_k) + Xf[k + 1] = max(Xf[k + 1], 1e-10) + + Xo[k + 1] = (xo + + params["ξ_o"] * (params["xbar_o"] - xo) * dt + + params["σ_o"] * dBo_k) + + return t, Xf, Xo, dBf, dBo + + +def additive_log_M(params, t, Xf, Xo, dBf, dBo): + """沿模拟路径的可加对数泛函。""" + dt = t[1] - t[0] + A = np.zeros_like(t) + + for k, (dBf_k, dBo_k) in enumerate(zip(dBf, dBo)): + xf = max(Xf[k], 1e-10) + xo = Xo[k] + + drift = (params["β_bar"] + + params["β_f"] * xf + + params["β_o"] * xo) + + shock = (np.sqrt(xf) * params["γ_f"] * dBf_k + + params["γ_o"] * dBo_k) + + A[k + 1] = A[k] + drift * dt + shock + + return A + + +t, Xf, Xo, dBf, dBo = simulate_states(params_sdf) +A_log = additive_log_M(params_sdf, t, Xf, Xo, dBf, dBo) + +φ_0 = np.exp(cf_s * Xf[0] + co_s * Xo[0]) +φ_t = np.exp(cf_s * Xf + co_s * Xo) + +M = np.exp(A_log) +M_hat = np.exp(-ρ_s * t) * M * φ_t / φ_0 +transient = φ_0 / φ_t + +identity_error = np.max(np.abs(M - np.exp(ρ_s * t) * M_hat * transient)) +print(f"algebraic identity error = {identity_error:.2e}") +``` + +上面的误差达到机器精度,符合预期。 + +接下来我们在路径的蒙特卡洛样本上估计 $\mathbb{E}[\hat M_t \mid X_0 = \bar x]$。 + +如果 $\hat M$ 是一个鞅,那么总体均值在每个 $t$ 处恰好为 $1$,样本均值应落在 $1$ 的几个标准误之内。 + +```{code-cell} ipython3 +def simulate_M_hat(params, ρ, cf, co, n_paths=2000, T=20.0, dt=0.01, seed=2024): + """沿一组轨迹的 hat M_t 的蒙特卡洛路径。""" + rng = np.random.default_rng(seed) + n = int(T / dt) + t = np.linspace(0, T, n + 1) + M_hat_paths = np.empty((n_paths, n + 1)) + + for k in range(n_paths): + seed_k = rng.integers(1, 10**9) + t_k, Xf_k, Xo_k, dBf_k, dBo_k = simulate_states( + params, T=T, dt=dt, seed=int(seed_k) + ) + A_k = additive_log_M(params, t_k, Xf_k, Xo_k, dBf_k, dBo_k) + φ_t_k = np.exp(cf * Xf_k + co * Xo_k) + φ_0_k = np.exp(cf * Xf_k[0] + co * Xo_k[0]) + M_hat_paths[k] = np.exp(-ρ * t_k) * np.exp(A_k) * φ_t_k / φ_0_k + + return t, M_hat_paths + + +t_mc, M_hat_paths = simulate_M_hat(params_sdf, ρ_s, cf_s, co_s) +M_hat_mean = M_hat_paths.mean(axis=0) +M_hat_se = M_hat_paths.std(axis=0, ddof=1) / np.sqrt(M_hat_paths.shape[0]) + +print(" t mean se (mean - 1) / se") +for t_check in [1.0, 5.0, 10.0, 20.0]: + idx = np.argmin(np.abs(t_mc - t_check)) + mean = M_hat_mean[idx] + se = M_hat_se[idx] + z = (mean - 1.0) / se + print(f"{t_mc[idx]:5.2f} {mean:7.4f} {se:7.4f} {z:+6.2f}") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 仿射状态路径与乘性分解 + name: fig-lrr-factorization-paths +--- +fig, axes = plt.subplots(2, 2, figsize=(12, 8)) + +axes[0, 0].plot(t, Xf) +axes[0, 0].set_ylabel("$X_t^f$") +axes[0, 0].set_xlabel("$t$") + +axes[0, 1].plot(t, Xo) +axes[0, 1].set_ylabel("$X_t^o$") +axes[0, 1].set_xlabel("$t$") + +axes[1, 0].plot(t, M, label="$M_t$") +axes[1, 0].plot(t, np.exp(ρ_s * t) * M_hat * transient, + "--", label="分解") +axes[1, 0].set_ylabel("乘性分解") +axes[1, 0].set_xlabel("$t$") +axes[1, 0].legend() + +axes[1, 1].plot(t, np.exp(ρ_s * t), label="$\\exp(\\rho t)$") +axes[1, 1].plot(t, M_hat, label="$\\hat M_t$", alpha=0.8) +axes[1, 1].plot(t, transient, label="$\\phi(X_0)/\\phi(X_t)$", alpha=0.8) +axes[1, 1].set_ylabel("三个成分") +axes[1, 1].set_xlabel("$t$") +axes[1, 1].legend() + +plt.tight_layout() +plt.show() +``` + +该图展示了这三个成分如何随时间演化。 + +## 长期风险价格 + +我们现在可以使用该分解来计算标准连续时间资产定价中出现的瞬时风险价格的长期类比。 + +我们可以问: + +> 如果一个投资者今天承担对某个冲击的小暴露,当回报按长视界率而非瞬时率衡量时,他们需要多少额外的期望回报? + +这两个答案,局部的和长期的,不一定一致。 + +一个移动持久性状态变量的冲击对现金流有一个小的*即时*影响,但对未来期望增长和贴现有一个大的*累积*影响,这就是这两个答案分开的原因。 + +所以长期风险价格是局部价格*加上一个持久性修正*。 + +修正的大小取决于均值回归的速度。 + +### 定义价格 + +```{prf:definition} 局部布朗风险价格 +:label: lrr-def-local-brownian-risk-price + +**局部布朗风险价格**是依赖状态的向量 $-\gamma^s(x)$。 + +一个小的布朗暴露 $\gamma^v_i$ 每单位时间赚取所需的期望回报 $-\gamma^v_i \gamma^s_i$,所以一单位暴露 $\gamma^v_i$ 的定价为 $-\gamma^s_i$。 +``` + +对于局部价格,我们只需读出 SDF 系数。 + +```{prf:definition} 长期风险价格 +:label: lrr-def-long-run-risk-price + +**长期风险价格**是现金流的长期所需回报关于其风险暴露的小变化的边际变化。 + +当我们处理增长现金流时,长期所需回报为 $R_\infty = -\rho + \delta$,其中 $\rho$ 是 $GS$ 半群的主特征值,$\delta$ 是趋势增长率,保持固定。 +``` + +计算长期价格需要求解主特征值问题,它捕捉了一个冲击如何通过持久性状态成分传播。 + +### 两个前沿 + +我们将看到*两种*相关的改变风险暴露的方式,每种都导致一个略微不同的长期风险价格: + +1. **估值泛函前沿:** + - 保持 SDF $S$ 固定并改变资产的布朗暴露 $(\gamma^v_f, \gamma^v_o)$。 + + - 使用局部定价约束确定漂移 $\beta^v$,然后计算 $V$-半群的 $\rho^v$。 + +2. **现金流前沿:** + - 保持 SDF $S$ 固定并改变现金流的增长暴露 $(\gamma^g_f, \gamma^g_o)$。 + - 设 $M = GS$ 并计算现金流估值半群的主特征值 $\rho$。 + +在简单的对数正态例子中,这两个前沿重合。 + +但在有随机波动率、非线性动态或跳跃风险时它们可能不同。 + +我们将在下面的仿射模型中详细讨论这两种类型的例子。 + +### 随机贴现因子分解 + +在进入风险价格之前,一个自然的基准是情形 $M=S$:将分解 {eq}`eq:hs-factorization` 直接应用于 SDF 本身。 + +分解变为 + +$$ + S_t + = + \exp(\rho t)\hat M_t + \frac{\phi(X_0)}{\phi(X_t)} . +$$ + +这是 {cite:t}`AlvarezJermann2005` 的**永久-瞬态分解**,现在与一个具体的特征函数构造相联系。 + +因子 $\exp(\rho t)$ 是 SDF 中的确定性趋势,鞅 $\hat M$ 是其随机*永久*成分;依赖状态的比值是*瞬态*的且会消失。 + +```{seealso} +定价算子的同一谱分解是 {doc}`ross_recovery` 中的核心工具,它用来从观察到的价格中 "恢复" 主观信念,也是 {doc}`misspecified_recovery` 中的核心工具,后者考察当永久鞅成分被错误地假设不存在时会出什么问题。 +``` + +对于一个长期零息债券, + +$$ + \exp(-\rho t)\, \mathbb{E}[S_t \mid X_0=x] + \to + \phi(x) + \int \frac{1}{\phi}\, d\hat\varsigma , +$$ + +所以长期限贴现债券价格主要通过特征函数 $\phi$ 依赖于当前状态。 + +### 仿射模型中的比较 + +对于仿射设定,我们可以为 $B^o$ 冲击的局部和长期价格写出闭式表达式。 + +局部价格就是 + +$$ + \text{$B^o$ 的局部价格} = -\gamma_o^s. +$$ + +长期价格(我们将在下面使用估值泛函前沿推导它)为 + +$$ + \text{$B^o$ 的长期价格} + = + -\gamma_o^s + - \frac{\beta_o^s}{\xi_o}\sigma_o . +$$ (eq:long-run-price-o) + +额外项 $-(\beta_o^s/\xi_o)\sigma_o$ 是**持久性修正**。 + +它的出现是因为: + +* 一个 $B^o$ 冲击移动持久性增长预测因子 $X^o$,以及 +* $X^o$ 以速率 $\xi_o$ 均值回归,所以该冲击对未来 SDF 增长的累积影响像 $1/\xi_o$ 一样缩放。 + +随着 $\xi_o$ 收缩,持久性增长,长期价格与局部价格分离,这是长期风险模型的核心经济内容。 + +$B^f$ 暴露的局部价格是依赖状态的(它随 $\sqrt{X^f_t}$ 缩放),$B^f$ 暴露的长期价格是非线性的,因为 $c_f$ 是一个二次方程的根。 + +```{code-cell} ipython3 +γ_s_o = params_sdf["γ_o"] +β_s_o = params_sdf["β_o"] +ξ_o = params_sdf["ξ_o"] +σ_o = params_sdf["σ_o"] + +local_price_o = -γ_s_o +long_run_price_o = -γ_s_o - (β_s_o / ξ_o) * σ_o + +print(f"local price of B^o exposure = {local_price_o:.4f}") +print(f"long-run price of B^o exposure = {long_run_price_o:.4f}") +``` + +下一个单元格说明持久性如何改变局部与长期价格之间的楔子。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 持久性与长期风险价格 + name: fig-lrr-persistence-risk-prices +--- +ξ_o_grid = np.array([0.10, 0.20, 0.50, 1.00, 2.00, 5.00]) +local_grid = np.full_like(ξ_o_grid, local_price_o) +long_grid = -γ_s_o - (β_s_o / ξ_o_grid) * σ_o + +fig, ax = plt.subplots() +ax.plot(ξ_o_grid, local_grid, "--", lw=2, label="局部") +ax.plot(ξ_o_grid, long_grid, "o-", lw=2, label="长期") +ax.set_xscale("log") +ax.set_xlabel("均值回归速度 $\\xi_o$") +ax.set_ylabel("风险价格") +ax.legend() +plt.show() +``` + +如我们所见,$B^o$ 暴露的长期价格对均值回归速度 $\xi_o$ 敏感,但局部价格是常数。 + +### 改变估值泛函 + +现在我们通过改变资产的暴露来推导长期风险价格公式,即上面介绍的**估值泛函前沿**。 + +我们保持 SDF $S$ 固定并为资产回报选取布朗暴露 $(\gamma_f^v,\gamma_o^v)$,将估值泛函参数化为 + +$$ +\begin{aligned} +A_t^v +&= +\bar\beta^v t ++ \int_0^t \beta_f^v X_s^f ds ++ \int_0^t \beta_o^v X_s^o ds +\\ +&\quad ++ \int_0^t \sqrt{X_s^f}\gamma_f^v dB_s^f ++ \int_0^t \gamma_o^v dB_s^o . +\end{aligned} +$$ + +$VS$ 上的鞅约束根据所选布朗暴露 $(\gamma_f^v,\gamma_o^v)$ 确定漂移系数: + +$$ +\begin{aligned} +\bar\beta^v +&= +-\bar\beta^s +- \frac{1}{2}(\gamma_o^s+\gamma_o^v)^2, +\\ +\beta_f^v +&= +-\beta_f^s +- \frac{1}{2}(\gamma_f^s+\gamma_f^v)^2, +\\ +\beta_o^v +&= +-\beta_o^s . +\end{aligned} +$$ (eq:valuation-local-restriction-affine) + +将仿射特征值公式应用于 $M=V$ 给出 + +$$ +\begin{aligned} +\rho^v +&= +\bar\beta^v ++ \frac{(\gamma_o^v)^2}{2} ++ c_f^v \xi_f \bar x_f ++ c_o^v(\xi_o\bar x_o+\gamma_o^v\sigma_o) ++ (c_o^v)^2\frac{\sigma_o^2}{2} +\\ +&= +-\bar\beta^s +- \frac{(\gamma_o^s)^2}{2} +- \gamma_o^s\gamma_o^v ++ c_f^v \xi_f \bar x_f ++ c_o^v(\xi_o\bar x_o+\gamma_o^v\sigma_o) ++ (c_o^v)^2\frac{\sigma_o^2}{2}, +\end{aligned} +$$ (eq:valuation-rho-affine) + +其中 $c_o^v=\beta_o^v/\xi_o=-\beta_o^s/\xi_o$,$c_f^v$ 求解与 {eq}`eq:cf-eq` 中相同的二次方程,只是将 $(\beta_f,\gamma_f)$ 替换为 $(\beta_f^v,\gamma_f^v)$。 + +保持 $\gamma_f^v$ 固定,将 {eq}`eq:valuation-rho-affine` 关于 $\gamma_o^v$ 求导给出 $B^o$ 暴露的长期估值泛函价格: + +$$ + \frac{\partial \rho^v}{\partial \gamma_o^v} + = + -\gamma_o^s + + c_o^v\sigma_o + = + -\gamma_o^s + - \frac{\beta_o^s}{\xi_o}\sigma_o . +$$ (eq:valuation-long-run-price-o) + +这与我们上面预览的公式 {eq}`eq:long-run-price-o` 匹配,即局部价格加上持久性修正 $-(\beta_o^s/\xi_o)\sigma_o$。 + +让我们通过对特征值计算作有限差分来数值验证该公式。 + +```{code-cell} ipython3 +def valuation_params_from_exposure(γ_v_o, γ_v_f=0.0): + """估值泛函 V 的仿射参数。""" + p = dict(params_sdf) + p.update({ + "β_bar": (-params_sdf["β_bar"] + - 0.5 * (params_sdf["γ_o"] + γ_v_o) ** 2), + "β_f": (-params_sdf["β_f"] + - 0.5 * (params_sdf["γ_f"] + γ_v_f) ** 2), + "β_o": -params_sdf["β_o"], + "γ_f": γ_v_f, + "γ_o": γ_v_o, + }) + return p + + +def valuation_eigenvalue_for_exposure(γ_v_o, γ_v_f=0.0): + """估值泛函前沿的主特征值。""" + p = valuation_params_from_exposure(γ_v_o, γ_v_f) + _, _, ρ, _ = solve_affine_eigenfunction(p) + return ρ +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 改变估值泛函 + name: fig-lrr-valuation-frontier +--- +γ_v_o_grid = np.linspace(-0.5, 0.5, 101) +ρ_v_grid = np.array([ + valuation_eigenvalue_for_exposure(g) for g in γ_v_o_grid +]) + +fig, ax = plt.subplots() +ax.plot(γ_v_o_grid, ρ_v_grid, lw=2) +ax.set_xlabel("估值暴露 $\\gamma_o^v$") +ax.set_ylabel("主特征值 $\\rho^v$") +plt.show() +``` + +```{code-cell} ipython3 +valuation_slope = ( + valuation_eigenvalue_for_exposure(0.001) + - valuation_eigenvalue_for_exposure(-0.001) +) / 0.002 + +print(f"finite-difference slope = {valuation_slope:.6f}") +print(f"formula = {long_run_price_o:.6f}") +``` + +### 改变现金流风险 + +第二个长期前沿改变现金流对风险的暴露而非回报。 + +我们选取一个增长泛函 $G_t = \exp(A_t^g)$,采用仿射参数化 + +$$ +\begin{aligned} +A_t^g +&= +\delta t ++ \int_0^t \sqrt{X_s^f}\gamma_f^g dB_s^f ++ \int_0^t \gamma_o^g dB_s^o +\\ +&\quad +- \frac{1}{2} + \int_0^t + \left[ + X_s^f(\gamma_f^g)^2 + (\gamma_o^g)^2 + \right] ds . +\end{aligned} +$$ (eq:growth-functional) + +最后一行是使 $\exp(A_t^g-\delta t) = \hat G_t$ 成为一个*局部*鞅的伊藤补偿子,其中 $\delta$ 是常数趋势增长率。 + +增长-扭曲过程的随机稳定性需要三个条件。 + +**Feller 型不可达**不等式 + +$$ + 2(\xi_f+\sigma_f\gamma_f^g)\bar x_f \geq \sigma_f^2 +$$ + +使扭曲的 $X^f$ 不触及零。 + +扭曲的 $X^f$ 的*均值回归*由我们对 SDF 在 {eq}`eq:cf-roots` 中使用的同样的选根论证挑选。 + +$\hat G$ 本身必须是一个鞅,即增长扭曲的假设 6.1 的类比。 + +Feller 不等式是必要的但本身不充分。 + +```{note} +这个 Feller 限制是我们之前标示的一个一般观点的具体实例:改变增长风险可能违反稳定性并使长期近似失效,所以 $(\gamma_f^g, \gamma_o^g)$ 的选择不是自由的。 +``` + +为给现金流 $D_t=D_0G_t\psi(X_t)$ 定价,使用由 $M=GS$ 生成的半群。 + +组合的仿射参数为 + +$$ +\begin{aligned} +\bar\beta &= \bar\beta^s+\delta-\frac{(\gamma_o^g)^2}{2},\\ +\beta_f &= \beta_f^s-\frac{(\gamma_f^g)^2}{2},\\ +\beta_o &= \beta_o^s,\\ +\gamma_f &= \gamma_f^s+\gamma_f^g,\\ +\gamma_o &= \gamma_o^s+\gamma_o^g. +\end{aligned} +$$ + +设 $\rho$ 为这个 $GS$ 半群的主特征值。 + +那么 $-\rho$ 是价值的长期衰减率,以及 + +$$ + R_\infty = -\rho + \delta +$$ + +是扣除现金流增长率后的渐近所需回报。 + +```{code-cell} ipython3 +def required_return_for_growth_exposure(γ_g_o, γ_g_f=0.0, δ=0.02): + """现金流增长暴露的长期所需回报。""" + p = dict(params_sdf) + p.update({ + "β_bar": params_sdf["β_bar"] + δ - 0.5 * γ_g_o ** 2, + "β_f": params_sdf["β_f"] - 0.5 * γ_g_f ** 2, + "β_o": params_sdf["β_o"], + "γ_f": params_sdf["γ_f"] + γ_g_f, + "γ_o": params_sdf["γ_o"] + γ_g_o, + }) + + _, _, ρ, _ = solve_affine_eigenfunction(p) + return -ρ + δ +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 持久性增长风险的局部与长期定价 + name: fig-lrr-cashflow-frontier +--- +γ_g_o_grid = np.linspace(-0.5, 0.5, 101) +required_returns = np.array([ + required_return_for_growth_exposure(g) for g in γ_g_o_grid +]) + +local_line = (required_return_for_growth_exposure(0.0) + + local_price_o * γ_g_o_grid) + +fig, ax = plt.subplots() +ax.plot(γ_g_o_grid, required_returns, lw=2, + label="长期所需回报") +ax.plot(γ_g_o_grid, local_line, "--", lw=2, + label="局部斜率") +ax.set_xlabel("现金流暴露 $\\gamma_o^g$") +ax.set_ylabel("回报率") +ax.legend() +plt.show() +``` + +长期线的斜率是 {eq}`eq:long-run-price-o` 中的风险价格,虚线在 $\gamma_o^g = 0$ 处共享相同的值,但斜率等于局部布朗风险价格 $-\gamma_o^s$。 + +两条斜率之间的差距是*持久性修正*;虚线是一个斜率比较器,而不是实际的 Breeden 局部期望回报前沿(后者在 $X^f$ 和 $X^o$ 中依赖状态)。 + +```{code-cell} ipython3 +finite_difference = ( + required_return_for_growth_exposure(0.001) + - required_return_for_growth_exposure(-0.001) +) / 0.002 + +print(f"finite-difference slope = {finite_difference:.6f}") +print(f"formula = {long_run_price_o:.6f}") +``` + +## 幕后的假设 + +上面的例子使特征函数计算看起来很常规。 + +对于有限状态链和仿射模型,它确实如此;佩龙-弗罗贝尼乌斯理论和闭式代数处理了每个要求。 + +但在一般状态空间中,三件事可能出错,每件都对应我们一直所携带的假设之一。 + +本节其余部分逐一考察每个。 + +### 问题 1:$\hat M$ 可能无法成为一个鞅 + +一个正特征函数 $\phi$ 从 {eq}`eq:mhat` 给我们一个候选鞅 $\hat M$,但 $\hat M$ 只是一个非负局部鞅,因而是一个上鞅。 + +一个上鞅不足以定义一个概率测度:我们需要 $\mathbb{E}[\hat M_t] = 1$,即一个真正的鞅,这是 {cite:t}`HansenScheinkman2009` 中假设 6.1 的内容。 + +验证这一点的标准方式是一个双侧 **Girsanov 构造**:写出由 $\hat M$ 诱导的漂移和跳跃扭曲,检查扭曲的马尔可夫过程表现良好,并验证反向密度($\hat M$ 的逆)是局部可积的。 + +### 问题 2:扭曲过程可能无法稳定 + +即使 $\hat M$ 是一个鞅,长期极限 {eq}`eq:long-run-limit` 也要求扭曲过程实际上稳定到一个稳态。 + +这就是随机稳定性(我们的平稳分布、骨架的不可约性和哈里斯常返三者组合)真正起作用的地方。 + +仿射例子具体说明了这一点,因为我们*拒绝*了两个代数上有效的特征函数中的一个,因为它意味着一个爆炸性的扭曲平方根过程。 + +### 问题 3:主特征函数可能不存在 + +在一般状态空间中,即使是严格正特征函数的*存在性*也不是自动的。 + +一个标准的充分条件从一个 **Lyapunov 型漂移界** 开始:存在一个状态空间上的函数 $V \geq 1$ 和一个常数 $a_0$,使得 + +$$ + \frac{\mathbb A V}{V} \leq a_0 . +$$ + +大致上:$V$ 在半群下增长得不太快。 + +有了这个,对任何 $\alpha > a_0$ 定义**预解算子** + +$$ + F_\alpha \psi(x) + = + \int_0^\infty + \exp(-\alpha t)\, + \mathbb{E}\!\left[ + M_t\, \frac{V(X_t)}{V(x)}\, \psi(X_t) + \,\Big|\, X_0=x + \right] dt . +$$ (eq:existence-resolvent) + +$F_\alpha$ 是由*重新缩放的*乘性泛函 $M_t V(X_t)/V(X_0)$ 生成的半群的拉普拉斯变换。 + +存在性证明随后分三步进行: + +1. **预解算子的不可约性。** 存在一个参考测度 $\nu$ 使得每当 $\nu(\Lambda) > 0$ 时对每个 $x$ 有 $F_\alpha\mathbf 1_\Lambda(x) > 0$,所以预解算子不 "错过" 状态空间的任何区域。 + +2. **Nummelin 极小化。** 不可约性产生一个状态空间上的*有界非负函数* $s$,满足 $\int s\, d\nu > 0$,使得对每个非负 $\psi$, + + $$ + F_\alpha \psi(x)\, \geq\, s(x) \int \psi\, d\nu . + $$ + + 函数 $s$(通常称为*极小化函数*)度量预解算子在多大程度上支配一个固定参考测度 $\nu$。 + +3. **特征函数提取。** 极小化结合额外的有界性或强化的漂移假设,识别出 $F_\alpha$ 的一个临界谱值和一个相关联的正特征函数。 + + - 反演预解变换产生原半群的一个正特征函数。 + +这些步骤都是非平凡的,超出了本讲座的范围。 + +细节在 {cite:t}`HansenScheinkman2009` 的第 9 节。 + +我们可以将条件链总结为: + +| 想要 | 需要 | +|:---|:---| +| 一个分解 {eq}`eq:hs-factorization` | 一个正特征函数 $\phi$ | +| $\hat M$ 定义一个概率测度 | $\hat M$ 是一个鞅(假设 6.1) | +| 长期极限 {eq}`eq:long-run-limit` | 扭曲过程的随机稳定性 | +| 一个唯一的主特征函数 | 稳定性在正特征函数中选择 | + +在有限状态情形中,所有四个都从一次佩龙-弗罗贝尼乌斯计算得出;在仿射模型中,它们约化为挑选一个二次方程的正确根。一般而言,每个都必须单独检查。 + +{cite:t}`HansenScheinkman2009` 中的完整理论还提供了更强的 $L^p$ 近似结果和随机稳定性的 Lyapunov 判据,我们在这里不复现。 + +## 小结 + +Hansen-Scheinkman 方法通过研究估值半群的正特征函数来研究长期风险。 + +主要步骤是: + +1. 用一个正乘性泛函 $M$ 对贴现、增长或累积回报建模。 + +2. 建立半群 $\mathbb M_t\psi(x)=\mathbb{E}[M_t\psi(X_t)\mid X_0=x]$。 + +3. 当 $M = VS$ 是一个估值泛函和一个 SDF 的乘积时,施加 $VS$ 是一个鞅的局部定价约束;对于现金流估值半群 $\mathbb Q_t = GS$,定价约束仅施加于 $S$,而 $G$ 只作为一个增长扭曲进入。 + +4. 求解主特征值问题 $\mathbb A\phi=\rho\phi$。 + +5. 使用分解 $M_t=\exp(\rho t)\hat M_t\phi(X_0)/\phi(X_t)$。 + +6. 在由 $\hat M$ 诱导的扭曲概率测度下,使用稳定性获得 {eq}`eq:long-run-limit` 形式的长期近似。 + +在有限状态问题中,这是佩龙-弗罗贝尼乌斯理论。 + +在仿射扩散问题中,指数-仿射特征函数常产生闭式公式。 + +当冲击移动持久性状态变量时,出现的长期风险价格可能与局部风险价格显著不同。 + +这个持久性效应是长期风险资产定价模型和 {cite:t}`hansen2008consumption` 的经验工作中所强调的经济渠道。 + +## 练习 + +```{exercise} +:label: lrr_ex1 + +考虑一个具有强度矩阵 + +$$ +U = +\begin{bmatrix} + -\lambda & \lambda \\ + \mu & -\mu +\end{bmatrix}. +$$ + +的两状态马尔可夫链。 + +设乘性泛函在状态 1 中有衰减率 $r_1>0$,在状态 2 中有衰减率 $r_2=0$,且无跳跃。 + +1. 写出生成元矩阵 $A$。 + +2. 用 $\lambda$、$\mu$ 和 $r_1$ 表示主特征值 $\rho$。 + +3. 用 $\lambda=0.4$、$\mu=0.6$ 和 $r_1=0.05$ 数值验证。 + +4. 证明 $-r_1 < \rho < 0$。 +``` + +```{solution-start} lrr_ex1 +:class: dropdown +``` + +这是一个解答: + +*1.* 生成元为 + +$$ +A = +\begin{bmatrix} + -\lambda-r_1 & \lambda \\ + \mu & -\mu +\end{bmatrix}. +$$ + +*2.* 特征方程为 + +$$ + \rho^2 + (\lambda+\mu+r_1)\rho + \mu r_1 = 0. +$$ + +因此主特征值是较大的根 + +$$ +\rho += +\frac{ + -(\lambda+\mu+r_1) + + \sqrt{(\lambda+\mu+r_1)^2 - 4\mu r_1} +}{2}. +$$ + +*3.* 数值验证: + +```{code-cell} ipython3 +λ, μ, r1 = 0.4, 0.6, 0.05 + +disc = (λ + μ + r1) ** 2 - 4 * μ * r1 +ρ_formula = (-(λ + μ + r1) + np.sqrt(disc)) / 2 + +U_ex = np.array([[-λ, λ], + [μ, -μ]]) +r_ex = np.array([r1, 0.0]) +κ_ex = np.zeros((2, 2)) + +A_ex = build_generator(U_ex, r_ex, κ_ex) +ρ_numeric, φ_numeric = principal_eigenpair(A_ex) + +print(f"formula ρ = {ρ_formula:.8f}") +print(f"numeric ρ = {ρ_numeric:.8f}") +print(f"difference = {abs(ρ_formula-ρ_numeric):.2e}") +``` + +*4.* 设 + +$$ +q(x)=x^2+(\lambda+\mu+r_1)x+\mu r_1. +$$ + +那么 $q(0)=\mu r_1>0$ 且 + +$$ +q(-r_1) += +-\lambda r_1 +<0. +$$ + +由于抛物线开口向上,一个根位于 $(-r_1,0)$ 中。 + +主特征值是较大的根,所以 $-r_1<\rho<0$。 + +```{solution-end} +``` + +```{exercise} +:label: lrr_ex2 + +在仿射模型中,为 + +$$ + \xi_o \in \{0.1, 0.2, 0.5, 1, 2, 5\}. +$$ + +计算 $B^o$ 暴露的局部和长期价格。 + +使用公式 + +$$ + \text{局部价格} = -\gamma_o^s +$$ + +和 + +$$ + \text{长期价格} + = + -\gamma_o^s + - \frac{\beta_o^s}{\xi_o}\sigma_o . +$$ + +解释为什么当 $\xi_o \to \infty$ 时两个价格收敛。 +``` + +```{solution-start} lrr_ex2 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +ξ_vals = np.array([0.1, 0.2, 0.5, 1.0, 2.0, 5.0]) +local_vals = np.full_like(ξ_vals, -params_sdf["γ_o"]) +long_vals = (-params_sdf["γ_o"] + - (params_sdf["β_o"] / ξ_vals) * params_sdf["σ_o"]) + +for ξ, lp, lrp in zip(ξ_vals, local_vals, long_vals): + print(f"ξ_o = {ξ:3.1f}: local = {lp:.4f}, long-run = {lrp:.4f}") + +fig, ax = plt.subplots() +ax.plot(ξ_vals, local_vals, "--", lw=2, label="局部") +ax.plot(ξ_vals, long_vals, "o-", lw=2, label="长期") +ax.set_xscale("log") +ax.set_xlabel("$\\xi_o$") +ax.set_ylabel("风险价格") +ax.legend() +plt.show() +``` + +随着 $\xi_o$ 增加,$X^o$ 更快地均值回归。 + +一个对 $B^o$ 的冲击于是对未来期望增长有一个寿命更短的影响。 + +持久性项 $(\beta_o^s/\xi_o)\sigma_o$ 收敛到零,所以长期价格收敛到局部价格。 + +```{solution-end} +``` + +```{exercise} +:label: lrr_ex3 + +考虑一个具有状态 {扩张、正常、收缩} 的三状态链,强度矩阵为 + +$$ +U = +\begin{bmatrix} + -0.40 & 0.30 & 0.10 \\ + 0.20 & -0.50 & 0.30 \\ + 0.10 & 0.20 & -0.30 +\end{bmatrix}, +$$ + +衰减率向量 $r = (0.06, 0.04, 0.01)$,乘性泛函中无跳跃。设 $\psi=(3,1,2)$。 + +1. 计算主特征对 $(\rho,\phi)$ 和扭曲平稳分布 $\hat\varsigma$,并报告理论极限 + +$$ + \phi \sum_i \frac{\psi_i}{\phi_i}\hat\varsigma_i . +$$ + +2. 在对数尺度上绘制 + +$$ + \max_i + \left| + \exp(-\rho t)(\mathbb M_t\psi)_i + - + \phi_i \sum_j \frac{\psi_j}{\phi_j}\hat\varsigma_j + \right| +$$ + +3. 将收敛率与 $A$ 特征值中最大和第二大实部之间的谱隙进行比较。 +``` + +```{solution-start} lrr_ex3 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +state_names = ["expansion", "normal", "contraction"] + +U3 = np.array([[-0.40, 0.30, 0.10], + [ 0.20, -0.50, 0.30], + [ 0.10, 0.20, -0.30]]) + +r3 = np.array([0.06, 0.04, 0.01]) +κ3 = np.zeros((3, 3)) + +A3 = build_generator(U3, r3, κ3) +ρ3, φ3 = principal_eigenpair(A3) +A3_hat = twisted_generator(A3, ρ3, φ3) +ς3 = stationary_distribution(A3_hat) + +ψ = np.array([3.0, 1.0, 2.0]) +limit = φ3 * np.sum((ψ / φ3) * ς3) + +print("limit:") +for name, value in zip(state_names, limit): + print(f" {name:11s} {value:.6f}") + +t_vals = np.linspace(0.1, 40, 300) +errors = np.array([ + np.max(np.abs(np.exp(-ρ3 * t_val) * expm(t_val * A3) @ ψ - limit)) + for t_val in t_vals +]) + +eigenvalues = eig(A3, right=False) +real_parts = np.sort(eigenvalues.real)[::-1] +gap = real_parts[0] - real_parts[1] + +fig, ax = plt.subplots() +ax.semilogy(t_vals, errors, lw=2) +ax.set_xlabel("$t$") +ax.set_ylabel("误差") +plt.show() + +print(f"spectral gap = {gap:.6f}") +``` + +归一化半群以由主特征值与其余特征值之间的分离所控制的指数率收敛。 + +在这个有限状态例子中,那个分离就是上面计算的谱隙。 + +```{solution-end} +``` + +```{exercise} +:label: lrr_ex_local_mg + +从伊藤公式推导局部鞅约束 {eq}`eq:local-martingale-restriction`。 + +设 $M = \exp(A)$,其中 $A$ 是 {eq}`eq:additive-functional` 中的可加泛函,参数为 $(\beta,\gamma,\kappa)$。 + +1. 将 $A_t = A_t^c + A_t^j$ 分解为其连续部分和纯跳跃部分,并写出 $dA_t^c$ 和跳跃幅度 $\Delta A_t$。 + +2. 将半鞅的伊藤公式应用于 $f(a) = e^a$ 以证明 + +$$ + dM_t + = + M_{t-}\, dA_t^c + + \tfrac{1}{2}\, M_{t-}\, d\langle A^c, A^c\rangle_t + + M_{t-}\big(\exp[\Delta A_t] - 1\big)\quad\text{在跳跃处}. +$$ + +3. 使用 $d\langle A^c, A^c\rangle_t = \gamma^\top\gamma\, dt$ 并将跳跃项重写为对随机计数测度 $\zeta$ 的积分。 + +4. 将 $\zeta$ 分裂为其补偿子 $\eta(dy \mid X_{t-})\, dt$ 和被补偿鞅测度 $\tilde\zeta = \zeta - \eta(dy\mid X_{t-})\, dt$。 + +5. 收集漂移(可预测)项和鞅项,并得出结论:$M$ 是一个局部鞅当且仅当漂移在每个状态处消失,这给出 {eq}`eq:local-martingale-restriction`。 +``` + +```{solution-start} lrr_ex_local_mg +:class: dropdown +``` + +这是一个解答。 + +*1.* 从参数化 {eq}`eq:additive-functional`, + +$$ + dA_t^c = \beta(X_t)\, dt + \gamma(X_{t-})^\top\, dB_t, + \qquad + \Delta A_t = \kappa(X_t, X_{t-}) \text{ 在跳跃时刻}. +$$ + +*2.* 对 $f(a) = e^a$ 我们有 $f'(a) = f''(a) = e^a$,所以 $f'(A_{t-}) = f''(A_{t-}) = M_{t-}$。 + +半鞅的[(广义)伊藤公式](https://almostsuremath.com/2010/01/25/the-generalized-ito-formula/) 给出 + +$$ + dM_t + = + f'(A_{t-})\, dA_t^c + + \tfrac{1}{2}\, f''(A_{t-})\, d\langle A^c, A^c\rangle_t + + \big[f(A_t) - f(A_{t-})\big] . +$$ + +由于在跳跃处 $A_t = A_{t-} + \Delta A_t$,$f(A_t) - f(A_{t-}) = M_{t-}\big(\exp[\Delta A_t] - 1\big)$,这就是所述的表达式。 + +*3.* 代入 $d\langle A^c, A^c\rangle_t = \gamma(X_{t-})^\top \gamma(X_{t-})\, dt$ 并将跳跃贡献重写为对 $(X, A)$ 的随机计数测度 $\zeta$ 的积分给出 + +$$ +\begin{aligned} +\frac{dM_t}{M_{t-}} +&= +\beta(X_t)\, dt ++ \gamma(X_{t-})^\top dB_t ++ \tfrac{1}{2}\,\gamma(X_{t-})^\top\gamma(X_{t-})\, dt +\\ +&\quad ++ \int \big(\exp[\kappa(y, X_{t-})] - 1\big)\, \zeta(dy, dt) . +\end{aligned} +$$ + +*4.* 写 $\zeta = \tilde\zeta + \eta(dy\mid X_{t-})\, dt$ 将跳跃积分分离为一个鞅和一个可预测漂移贡献: + +$$ +\int \big(\exp[\kappa(y,X_{t-})] - 1\big)\zeta(dy,dt) += +\int\big(\exp[\kappa(y,X_{t-})] - 1\big)\tilde\zeta(dy,dt) ++ \int\big(\exp[\kappa(y,X_{t-})] - 1\big)\eta(dy\mid X_{t-})\, dt . +$$ + +*5.* 收集漂移项和鞅项, + +$$ +\begin{aligned} +\frac{dM_t}{M_{t-}} +&= +\bigg[\beta(X_t) ++ \tfrac{1}{2}\gamma^\top\gamma ++ \int\big(\exp[\kappa(y,X_{t-})] - 1\big)\,\eta(dy\mid X_{t-})\bigg] dt +\\ +&\quad ++ \gamma^\top dB_t ++ \int\big(\exp[\kappa(y,X_{t-})] - 1\big)\,\tilde\zeta(dy,dt) . +\end{aligned} +$$ + +布朗项和被补偿跳跃项是局部鞅,所以 $M$ 是一个局部鞅当且仅当括号中的漂移对每个状态 $x$ 消失,从而给出 {eq}`eq:local-martingale-restriction`。 + +```{solution-end} +``` + +```{exercise} +:label: lrr_ex4 + +推导扩展生成元在 {eq}`eq:extended-generator` 中的闭式表达式。 + +取马尔可夫状态在跳跃之间满足 + +$$ + dX_t^c = \xi(X_t)dt + \Gamma(X_t)dB_t +$$ + +的跳跃-扩散设定,其中 $\Sigma = \Gamma\Gamma^\top$ 且跳跃补偿子为 $\eta(dy \mid x)$。 + +设 $M = \exp(A)$,其中 $A$ 是 {eq}`eq:additive-functional` 中的可加泛函,并设 $\phi$ 是一个光滑的、严格正的函数。 + +回忆 {prf:ref}`lrr-def-extended-generator`,如果 + +$$ + N_t = M_t\phi(X_t) - \phi(X_0) - \int_0^t M_s \chi(X_s)\, ds +$$ + +是一个局部鞅,则 $\mathbb A\phi = \chi$。因此任务有两部分:识别 $M_t\phi(X_t)$ 的可预测漂移以读出候选 $\chi$,并验证残差 $N_t$ 确实是一个局部鞅。 + +(1) 将伊藤公式应用于跳跃之间的 $Y_t = \exp(A_t)\phi(X_t)$ 并证明 $dY_t$ 的连续部分具有漂移 + +$$ + M_t + \left[ + (\xi + \Gamma\gamma)^\top + \frac{\partial \phi}{\partial x} + + \frac{1}{2} + \operatorname{trace}\!\left( + \Sigma \frac{\partial^2 \phi}{\partial x \partial x^\top} + \right) + + \left(\beta + \frac{\gamma^\top \gamma}{2}\right)\phi + \right] dt . +$$ + +(2) 证明在一个跳跃时刻 $t$,$X_{t-}=x$ 和 $X_t=y$, + +$$ + \Delta Y_t = M_{t-}\big[\exp[\kappa(y,x)]\phi(y) - \phi(x)\big] , +$$ + +并得出可预测跳跃补偿子贡献漂移 + +$$ + M_{t-} + \int + \big\{ + \exp[\kappa(y,x)]\phi(y) - \phi(x) + \big\} + \eta(dy \mid x)\, dt . +$$ + +(3) 分解 + +$$ + \exp[\kappa(y,x)]\phi(y) - \phi(x) + = + \exp[\kappa(y,x)] + \big[\phi(y) - \phi(x)\big] + + \big[\exp[\kappa(y,x)] - 1\big]\phi(x), +$$ + +与 (1) 部分结合以获得完整的可预测漂移系数 $\chi(x)$,并检查它匹配闭式 {eq}`eq:extended-generator`。 + +(4) 将 (1) 部分的连续伊藤被积项识别为局部鞅 $N^c_t$,将 (2) 部分的被补偿跳跃和识别为局部鞅 $N^j_t$。 + +证明 $Y_t = M_t\phi(X_t)$ 的半鞅分解意味着 + +$$ + M_t\phi(X_t) - \phi(X_0) - \int_0^t M_s\, \chi(X_s)\, ds + = N^c_t + N^j_t , +$$ + +这是一个局部鞅。通过 {prf:ref}`lrr-def-extended-generator` 得出结论 $\mathbb A \phi = \chi$。 +``` + +```{solution-start} lrr_ex4 +:class: dropdown +``` + +这是一个解答: + +*(1)* 设 $g(a, x) = e^a \phi(x)$,使得 $Y_t = g(A_t, X_t)$。 + +在跳跃之间,$A$ 和 $X$ 的连续部分是 + +$$ + dA_t^c = \beta(X_t)\, dt + \gamma(X_t)^\top dB_t, + \qquad + dX_t^c = \xi(X_t)\, dt + \Gamma(X_t)\, dB_t , +$$ + +具有二次协变差 + +$$ + d\langle A^c, A^c\rangle_t = \gamma^\top \gamma\, dt, + \qquad + d\langle X^c, X^c\rangle_t = \Sigma\, dt, + \qquad + d\langle A^c, X^c\rangle_t = \Gamma\gamma\, dt . +$$ + +$g$ 的偏导数满足 + +$$ + \partial_a g = g, + \quad + \partial_{aa} g = g, + \quad + \partial_x g = e^a \frac{\partial \phi}{\partial x}, + \quad + \partial_{ax} g = e^a \frac{\partial \phi}{\partial x}, + \quad + \partial_{xx} g = e^a \frac{\partial^2 \phi}{\partial x \partial x^\top} . +$$ + +伊藤公式产生一个连续局部鞅 $N^c_t$($dB_t$ 部分)加上漂移 + +$$ +\begin{aligned} + M_t \Big[ + \beta \phi + + \tfrac{1}{2}\gamma^\top \gamma\, \phi + + \xi^\top \tfrac{\partial \phi}{\partial x} + + \tfrac{1}{2}\operatorname{trace}\!\big(\Sigma\, \tfrac{\partial^2 \phi}{\partial x \partial x^\top}\big) + + (\Gamma\gamma)^\top \tfrac{\partial \phi}{\partial x} + \Big]\, dt . +\end{aligned} +$$ + +将梯度项分组给出问题中的表达式。 + +*(2)* 在一个跳跃时刻 $t$,$\Delta A_t = \kappa(X_t, X_{t-}) = \kappa(y, x)$,所以 $M_t = M_{t-}\exp[\kappa(y,x)]$ 且 + +$$ + \Delta Y_t + = M_t \phi(X_t) - M_{t-}\phi(X_{t-}) + = M_{t-}\big[\exp[\kappa(y,x)]\phi(y) - \phi(x)\big] . +$$ + +跳跃和减去其可预测补偿子是一个局部鞅 $N^j_t$,补偿子本身贡献问题中引用的可预测漂移。 + +*(3)* 将 (2) 中的跳跃漂移加到 (1) 中的连续漂移,$Y_t = M_t \phi(X_t)$ 在状态 $x$ 处的可预测漂移是 $M_t\, \chi(x)\, dt$,其中 + +$$ +\begin{aligned} + \chi(x) + &= + (\xi + \Gamma\gamma)^\top \frac{\partial \phi}{\partial x} + + \frac{1}{2}\operatorname{trace}\!\left( + \Sigma \frac{\partial^2 \phi}{\partial x \partial x^\top} + \right) + + \left(\beta + \frac{\gamma^\top \gamma}{2}\right)\phi(x) + \\ + &\quad + + \int \exp[\kappa(y,x)]\big[\phi(y) - \phi(x)\big]\, \eta(dy \mid x) + + \phi(x)\int \big[\exp[\kappa(y,x)] - 1\big]\, \eta(dy \mid x) . +\end{aligned} +$$ + +收集乘以 $\phi(x)$ 的项可恢复 {eq}`eq:extended-generator`。 + +*(4)* 将两个鞅部分放在一起并对漂移积分,步骤 (1) 和 (2) 给出半鞅分解 + +$$ + M_t \phi(X_t) + = + \phi(X_0) + + \int_0^t M_s\, \chi(X_s)\, ds + + N^c_t + N^j_t . +$$ + +重新排列, + +$$ + N_t + := + M_t \phi(X_t) - \phi(X_0) - \int_0^t M_s\, \chi(X_s)\, ds + = N^c_t + N^j_t , +$$ + +这是一个局部鞅,因为它是局部鞅之和。 + +这恰好是 {prf:ref}`lrr-def-extended-generator` 所要求的性质,所以 $\chi = \mathbb A \phi$。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/lq_bewley_complete_markets.md b/lectures/lq_bewley_complete_markets.md new file mode 100644 index 0000000..c0bf596 --- /dev/null +++ b/lectures/lq_bewley_complete_markets.md @@ -0,0 +1,602 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.11.1 +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 不完全市场与完全市场下的消费平滑 + headings: + Overview: 概述 + A brief review: 简要回顾 + Spreading consumption cross sections: 消费截面的扩散 + A borrowers and lenders economy: 借款人与贷款人经济 + Consumption smoothing with complete markets: 完全市场下的消费平滑 + Exercises: 练习 +--- + +(lq_bewley_complete_markets)= +```{raw} jupyter + +``` + +# 不完全市场与完全市场下的消费平滑 + +```{contents} Contents +:depth: 2 +``` + +```{index} single: LQ Permanent Income Model; cross section +``` + +```{index} single: Bewley Model +``` + +```{index} single: Complete Markets +``` + +## 概述 + +本讲研究当众多消费者各自求解 LQ 永久收入问题时,消费的截面分布如何演化。 + +这是关于 LQ 永久收入模型的三讲中的第二讲,直接建立在 {doc}`lq_permanent_income` 的基础之上。 + +我们首先说明,个体消费中的单位根会导致消费的截面方差随时间线性增长。 + +然后,我们遵循 {cite:t}`Bewley1977`,将个体消费者嵌入到一个具有连续统消费者的**封闭经济**中,并展示总名义利率 $R = \beta^{-1}$ 如何作为均衡结果出现。 + +最后,我们用一整套完备的阿罗证券替代单一的无风险债券,并展示完全市场如何实现一个时不变的消费截面分布。 + +第三讲 {doc}`lq_robust_smoothing` 放松了消费者完全信任其收入模型的假设。 + +让我们从一些导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.linalg import inv +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n + +``` + +## 简要回顾 + +我们回顾一下 {doc}`lq_permanent_income` 中的要点。 + +一个具有二次效用、贴现因子 $\beta$、并可获得总回报为 $R = \beta^{-1}$ 的无风险债券的消费者,面临如下的禀赋过程 + +$$ +\begin{aligned} +z_{t+1} &= \check{A}\, z_t + \check{C}\, w_{t+1} \\ +y_t &= \check{G}\, z_t +\end{aligned} +$$ (eq:pi-endowment) + +其中 $w_{t+1}$ 是均值为零、协方差矩阵为单位阵的 IID 过程。 + +最优消费函数将消费表示为总财富的 $r/(1+r) = (1-\beta)$ 倍, + +$$ +c_t = (1-\beta)\!\left[\check{G}(I-\beta\check{A})^{-1} z_t - b_t\right] +$$ (eq:pi-ccf) + +该模型具有一个状态空间表示,其中状态为当前消费 $c_t$ 和外生禀赋状态 $z_t$: + +$$ +\begin{aligned} +c_{t+1} &= c_t + (1-\beta)\,\check{G}(I-\beta\check{A})^{-1}\check{C}\, w_{t+1} \\ +b_t &= \check{G}(I-\beta\check{A})^{-1} z_t - \frac{1}{1-\beta}\,c_t \\ +y_t &= \check{G}\, z_t \\ +z_{t+1} &= \check{A}\, z_t + \check{C}\, w_{t+1} +\end{aligned} +$$ (eq:pi-crep) + +消费是一个**随机游走**:其一阶差分是 IID 新息 $h\, w_{t+1}$,其中 +$h = (1-\beta)\,\check{G}(I-\beta\check{A})^{-1}\check{C}$。 + +在整个讲座中,我们使用 {doc}`lq_permanent_income` 中的双因子禀赋 $y_t = z_{1t} + z_{2t}$,其中 $z_{1t}$ 是永久成分,$z_{2t}$ 是纯粹的暂时成分,因此 $\check{A} = \mathrm{diag}(1,0)$ 且 $\check{C} = \mathrm{diag}(\sigma_1,\sigma_2)$。 + +下面的代码单元重现了校准值和关键矩阵。 + +```{code-cell} ipython3 +# 参数 +β = 0.95 # 贴现因子(因此 R = 1/β) +σ1 = 0.15 # 永久冲击的标准差 +σ2 = 0.30 # 暂时冲击的标准差 + +# 双因子禀赋 +A_check = np.array([[1.0, 0.0], + [0.0, 0.0]]) +C_check = np.array([[σ1, 0.0], + [0.0, σ2]]) +G_check = np.array([[1.0, 1.0]]) + +# 关键矩阵 M = G(I - βA)^{-1} +IbA = np.eye(2) - β * A_check +M = G_check @ inv(IbA) # 形状 (1, 2) +``` + +## 消费截面的扩散 + +```{index} single: Cross-Section Distributions; consumption +``` + +消费中的单位根(表示 {eq}`eq:pi-crep`)导致消费的**截面方差**随时间线性增长。 + +考虑一个连续统的*事前*相同的家庭,均在 $t = 0$ 时出生。 + +所有家庭 $i$ 具有相同的偏好。 + +他们都面临相同形式的非金融收入随机过程 + + +$$ +y_t^i = g( w_t^i, w_{t-1}^i, \ldots, w_0^i; z_0^i), +$$ (eq:gstochpro) + +虽然所有消费者都面临相同的 $g$ 过程,但他们对**特有的**冲击序列 $\{w_{t}^i\}_{t=0}^\infty$ 有不同的、统计独立的实现。 + +设所有家庭从相同的初始条件 $c_0^i = c_0$ 和 $z_0^i$ 出发。 + +由 {eq}`eq:pi-crep`,家庭 $i$ 的消费遵循 + +$$ +c_{t+1}^i = c_t^i + h\, w_{t+1}^i, \qquad h = (1-\beta)\,\check{G}(I-\beta\check{A})^{-1}\check{C} +$$ + +由于 $\{w^i_{t}\}$ 的实现在各主体之间独立, + +$$ +\mathbb{E}_0\bigl(c_t^i - c_0^i\bigr)^2 = t\, h h^\top +$$ (eq:varspread) + +在双因子模型中,$h$ 是一个 $1 \times 2$ 的行向量,因此 $hh^\top$ 是一个正标量,等于 +$\sigma_1^2 + (1-\beta)^2\sigma_2^2$。 + +消费的截面方差按 $t$ 增长。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 消费截面的扩散 + name: fig-lqcs-spread +--- +# 模拟截面扩散 +rng = np.random.default_rng(42) +N = 5000 # 主体数量 +T_sim = 80 # 周期数 + +h_vec = (1 - β) * (M @ C_check) # 形状 (1, 2),然后展平 +h_vec = h_vec.flatten() # h = [h1, h2] + +c = np.zeros((N, T_sim + 1)) # 消费路径 +# 将所有主体初始化为 c_0 = 0(去均值) +for t in range(T_sim): + eps = rng.standard_normal((N, 2)) # N 次二维冲击抽样 + dc = eps @ h_vec # 形状 (N,) + c[:, t+1] = c[:, t] + dc + +# 每个日期的截面方差 +var_c = np.var(c, axis=0) +theory = np.arange(T_sim + 1) * np.dot(h_vec, h_vec) + +fig, ax = plt.subplots() +ax.plot(var_c, label='模拟的截面方差', lw=2) +ax.plot(theory, label=r'理论值: $t \cdot h h^\top$', + linestyle='--', color='C3', lw=2) +ax.set_xlabel('周期 $t$') +ax.set_ylabel('$c$ 的截面方差') +ax.legend() +plt.show() +``` + +## 借款人与贷款人经济 + +```{index} single: Bewley Model +``` + +到目前为止,我们设定 $R = \beta^{-1}$,并将其视为在模型外部决定的("小型开放经济")。 + +遵循 {cite:t}`Bewley1977` 的思想,我们可以构建一个**封闭经济**,其中 +$R = \beta^{-1}$ 是一个**均衡结果**。 + +一个测度为 1 的连续统消费者,以 $i \in [0,1]$ 为索引,交易一种价格为 $\beta$ 的无风险单期债券。 + +所有消费者具有相同的偏好和相同的随机收入过程 {eq}`eq:gstochpro`,但面临**特有的**非金融收入冲击过程的实现。 + +初始债券头寸为零:对所有 $i$ 都有 $b_0^i = 0$。 + +初始禀赋状态 $z_0^i$ 是来自同一初始分布的独立抽样。 + +由于永久成分 $z_{1t}$ 具有单位根,过程 {eq}`eq:pi-endowment` 没有平稳分布,因此在下面的模拟中,我们抽取永久成分 $z_{10}^i \sim N(0,1)$,并从其平稳分布中抽取暂时成分 $z_{20}^i \sim N(0,\sigma_2^2)$。 + +由 {eq}`eq:pi-ccf`,当 $b_0^i = 0$ 时,主体 $i$ 在时刻 0 的消费为 + +$$ +c_0^i = (1-\beta)\,\check{G}(I-\beta\check{A})^{-1} z_0^i +$$ (eq:c_null) + +对于 $t \geq 1$,由 {eq}`eq:pi-crep`: + +$$ +c_{t+1}^i = c_t^i + h\, w_{t+1}^i, \qquad h = (1-\beta)\,\check{G}(I-\beta\check{A})^{-1}\check{C} +$$ (eq:c_future) + +设 $Y$ 表示非金融收入截面平均值的平稳均值。 + +对所有主体积分 {eq}`eq:c_null`: + +$$ +\int_0^1 c_0^i\, di = (1-\beta)\sum_{j=0}^{\infty}\beta^j \mathbb{E}_0\!\int_0^1 y_j^i\, di = Y +$$ (eq:c_marketclear_0) + +因为连续统的特有冲击平均为零。 + +对于未来的周期,对 {eq}`eq:c_future` 积分: + +$$ +\int_0^1 c_{t+1}^i\, di = \int_0^1 c_t^i\, di + h\!\underbrace{\int_0^1 w_{t+1}^i\, di}_{=\,0} = Y +$$ + +商品市场在每个日期都以*恒定*的总消费 $Y$ 出清。 + +债券市场每期以零净供给出清。 + +因此,$R = \beta^{-1}$ 是一个均衡结果。 + + + +虽然消费的截面均值是恒定的,但截面*方差*根据 {eq}`eq:varspread` 无界增长。 + +禀赋抽样 $z_0^i$ 的初始差异造成了消费水平的永久差异。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Bewley 经济的截面矩 + name: fig-lqcs-bewley +--- +# 通过模拟验证 Bewley 市场出清 +# 在线计算均值和方差以避免存储所有路径。 +rng = np.random.default_rng(0) +N_bew = 10000 # 主体数量 +T_bew = 60 + +# 为模拟抽取初始状态。 +z0_i = rng.standard_normal((N_bew, 2)) * np.array([1.0, σ2]) +c0_i = ((1 - β) * (M @ z0_i.T)).flatten() # 形状 (N_bew,) + +# 在各主体间传播消费。 +mean_c = np.zeros(T_bew + 1) +var_c2 = np.zeros(T_bew + 1) +mean_c[0] = c0_i.mean() +var_c2[0] = c0_i.var() + +c_now = c0_i.copy() +for t in range(T_bew): + eps = rng.standard_normal((N_bew, 2)) + c_now = c_now + eps @ h_vec + mean_c[t + 1] = c_now.mean() + var_c2[t + 1] = c_now.var() + +# 在下面重用初始消费。 +c_bew_t0 = c0_i + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].plot(mean_c, lw=2, color='C0') +axes[0].axhline(mean_c[0], linestyle='--', color='C3', label='初始均值') +axes[0].set_xlabel('周期 $t$') +axes[0].set_ylabel('平均消费') +axes[0].set_title('均值') +axes[0].legend() + +axes[1].plot(var_c2, lw=2, color='C0', label='模拟方差') +axes[1].set_xlabel('周期 $t$') +axes[1].set_ylabel('消费方差') +axes[1].set_title('方差') +axes[1].legend() +fig.tight_layout() +plt.show() +``` + +由于每个消费者都不喜欢消费随时间的波动,每个消费者都会更倾向于一个完全平滑的消费流 $c_t^i = c_0^i$(对所有 $t$)。 + +这样的配置是可行的,因为收入的截面平均值是恒定的。 + +下一节描述一个支持这一结果的完全市场配置。 + +## 完全市场下的消费平滑 + +```{index} single: Complete Markets; Arrow securities +``` + +我们用一整套完备的**阿罗证券**替代单一债券。 + +预算约束变为 + +$$ +c_t + b_{t-1}(z_t) = \int q(z_{t+1}|z_t)\, b_t(z_{t+1})\, dz_{t+1} + y_t +$$ (eq:CMbudget) + +其中 $q(z_{t+1}|z_t)$ 是单期或有债权的定价核,而 +$b_t(z_{t+1})$ 是家庭在 $t$ 时刻选择的阿罗证券组合。 + +我们猜测(并验证)均衡定价核为 + +$$ +q(z_{t+1}|z_t) = \beta\,\phi(z_{t+1}|z_t) +$$ (eq:kernel) + +其中 $\phi(z_{t+1}|z_t)$ 是 $z$ 的转移密度。 + +该核将单期无风险债券定价为 $\beta$,因此 $R = \beta^{-1}$,这与不完全市场均衡一致。 + +我们推测均衡为每个消费者 $i$ 提供*恒定*的消费水平: + +$$ +c_t^i = \bar{c}^i = c_0^i, \quad \forall\, t \geq 0 +$$ (eq:constcons) + +其中 $c_0^i = (1-\beta)\,\check{G}(I-\beta\check{A})^{-1} z_0^i$ 是消费者在不完全市场经济中时刻 0 的消费。 + +支持恒定消费的或有债务为 + +$$ +b_{t-1}(z_t) = \check{G}(I-\beta\check{A})^{-1} z_t - \frac{1}{1-\beta}\,\bar{c}^i \;\equiv\; b(z_t, \bar{c}^i) +$$ (eq:cmdebt) + +注意,负债水平仅取决于当前的马尔可夫状态 $z_t$,而*不*取决于先前状态的历史。 + +这种历史依赖性的缺失反映了完全市场下实现的**完全风险分担**。 + +将定价核 {eq}`eq:kernel` 和组合推测 {eq}`eq:cmdebt` 代入预算约束 {eq}`eq:CMbudget`,并使用重复期望法则,可以确认预算约束在每个状态和周期都简化为 $c_t = \bar{c}^i$。 + +在完全市场下,消费的截面分布是**时不变的**。 + +消费者 $i$ 在消费分布中的排名永远固定不变。 + +一次幸运的初始抽样 $z_0^i$ 表现为在所有未来状态中持续较高的消费 $\bar{c}^i$ 和较低的负债 $b(z_t^i, \bar{c}^i)$。 + +这一结果与不完全市场 Bewley 经济中发生的情况形成对比,在后者中,消费的截面方差无界增长。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 不完全市场与完全市场下的截面分布 + name: fig-lqcs-markets +--- +# 完全与不完全消费分布 +rng = np.random.default_rng(1) +N_cm = 5000 +T_cm = 50 + +# 初始消费抽样(与 Bewley 经济相同) +c0_cm = c_bew_t0[:N_cm] + +# 不完全市场:消费演化(随机游走) +c_inc = np.zeros((N_cm, T_cm + 1)) +c_inc[:, 0] = c0_cm +for t in range(T_cm): + eps = rng.standard_normal((N_cm, 2)) + c_inc[:, t+1] = c_inc[:, t] + eps @ h_vec + +# 完全市场:消费保持恒定 +c_comp = np.tile(c0_cm[:, np.newaxis], T_cm + 1) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +for t_plot, color in zip([0, 10, 30, 50], ['C0', 'C1', 'C3', 'C4']): + axes[0].hist(c_inc[:, t_plot], bins=60, alpha=0.4, + label=f't = {t_plot}', color=color, density=True) +axes[0].set_xlabel('$c$') +axes[0].set_ylabel('密度,不完全市场') +axes[0].set_title('不完全市场') +axes[0].legend(fontsize=9) + +for t_plot, color in zip([0, 10, 30, 50], ['C0', 'C1', 'C3', 'C4']): + axes[1].hist(c_comp[:, t_plot], bins=60, alpha=0.4, + label=f't = {t_plot}', color=color, density=True) +axes[1].set_xlabel('$c$') +axes[1].set_ylabel('密度,完全市场') +axes[1].set_title('完全市场') +axes[1].legend(fontsize=9) +fig.tight_layout() +plt.show() +``` + +```{note} +在**完全市场**下,直方图在所有 $t$ 上保持不变(分布完美重合),而在**不完全市场**下,分布随时间扩散。 +``` + +到目前为止,消费者完全信任其随机收入模型。 + +在 {doc}`lq_robust_smoothing` 中,我们放松这一假设,让消费者寻求对合理的模型误设具有稳健性的决策规则。 + +最优稳健规则采用与上述规则相同的形式,但基于一个扭曲的收入过程模型,该模型看起来比近似模型更具持续性。 + +## 练习 + +```{exercise-start} +:label: lqbcm_ex1 +``` + +本练习研究耐心程度如何决定消费截面扩散的速度。 + +由 {eq}`eq:varspread`,消费的截面方差每期增长 $h h^\top = \sigma_1^2 + (1-\beta)^2\sigma_2^2$。 + +1. 对 $\beta \in \{0.90, 0.95, 0.99\}$ 计算这个每期增长率,并分别报告永久成分和暂时成分的贡献。 + +2. 通过模拟确认,对于 $\beta = 0.95$,截面方差以预测的速率线性增长。 + +3. 解释为什么增加 $\beta$ 会减慢由暂时冲击引起的扩散,但保持永久冲击的贡献不变。 + +```{exercise-end} +``` + +```{solution-start} lqbcm_ex1 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +for b in (0.90, 0.95, 0.99): + perm = σ1**2 + tran = (1 - b)**2 * σ2**2 + print(f"β = {b}: growth = {perm + tran:.5f} " + f"(permanent {perm:.5f}, transitory {tran:.5f})") +``` + +```{code-cell} ipython3 +rng = np.random.default_rng(7) +N, T_sim = 20000, 60 +hh = float(h_vec @ h_vec) + +c = np.zeros((N, T_sim + 1)) +for t in range(T_sim): + c[:, t + 1] = c[:, t] + rng.standard_normal((N, 2)) @ h_vec + +var_c = c.var(axis=0) +theory = np.arange(T_sim + 1) * hh + +fig, ax = plt.subplots() +ax.plot(var_c, lw=2, label='模拟方差') +ax.plot(theory, lw=2, linestyle='--', color='C3', + label=r'理论值: $t\cdot h h^\top$') +ax.set_xlabel('周期 $t$') +ax.set_ylabel('$c$ 的截面方差') +ax.legend() +plt.show() +``` + +永久成分的贡献 $\sigma_1^2$ 不依赖于 $\beta$,因为无论耐心程度如何,永久冲击都会一比一地资本化到消费中。 + +暂时成分的贡献 $(1-\beta)^2\sigma_2^2$ 随着 $\beta \to 1$ 而缩小,因为更有耐心的消费者会在更长的视界上平滑暂时冲击,仅按较小的年金价值 $(1-\beta)$ 调整消费。 + +```{solution-end} +``` + +```{exercise-start} +:label: lqbcm_ex2 +``` + +本练习对比不完全市场与完全市场下消费的截面方差。 + +让所有消费者从上面计算的初始消费抽样 `c_bew_t0` 出发。 + +1. 在不完全市场(消费是随机游走)和完全市场(消费恒定)下,计算每个日期 $t = 0, 1, \ldots, 60$ 的截面方差。 + +2. 将两条方差路径绘制在同一坐标轴上,并评论其差异。 + +```{exercise-end} +``` + +```{solution-start} lqbcm_ex2 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +rng = np.random.default_rng(11) +T = 60 +c0 = c_bew_t0 + +# 不完全市场:随机游走消费 +c_inc = np.zeros((len(c0), T + 1)) +c_inc[:, 0] = c0 +for t in range(T): + c_inc[:, t + 1] = c_inc[:, t] + rng.standard_normal((len(c0), 2)) @ h_vec + +var_inc = c_inc.var(axis=0) +var_comp = np.full(T + 1, c0.var()) # 完全市场:消费恒定 + +fig, ax = plt.subplots() +ax.plot(var_inc, lw=2, label='不完全市场') +ax.plot(var_comp, lw=2, linestyle='--', color='C3', label='完全市场') +ax.set_xlabel('周期 $t$') +ax.set_ylabel('$c$ 的截面方差') +ax.legend() +plt.show() +``` + +在不完全市场下,方差无界地线性上升:每个消费者累积一个独立的消费新息随机游走。 + +在完全市场下,方差是平坦的:每个消费者锁定了一个恒定的消费水平 $\bar{c}^i$,因此截面分布永不改变。 + +```{solution-end} +``` + +```{exercise-start} +:label: lqbcm_ex3 +``` + +本练习展示完全市场如何冻结每个消费者在消费分布中的*排名*。 + +在完全市场下,消费恒定,因此消费者在截面分布中的位置永不改变;在不完全市场下,随机游走逐渐打乱排名。 + +1. 从 `c_bew_t0` 出发,在两种市场结构下模拟消费路径。 + +2. 在每种市场结构下,计算 $t = 0$ 时的消费与后续日期 $t$ 时的消费之间的斯皮尔曼秩相关系数,并将其与 $t$ 绘制成图。 + +3. 解释结果。 + +```{exercise-end} +``` + +```{solution-start} lqbcm_ex3 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +from scipy.stats import spearmanr + +rng = np.random.default_rng(3) +T = 60 +c0 = c_bew_t0 + +c_inc = np.zeros((len(c0), T + 1)) +c_inc[:, 0] = c0 +for t in range(T): + c_inc[:, t + 1] = c_inc[:, t] + rng.standard_normal((len(c0), 2)) @ h_vec + +dates = np.arange(0, T + 1, 4) +rank_inc = [spearmanr(c_inc[:, 0], c_inc[:, t]).statistic for t in dates] +rank_comp = [1.0 for _ in dates] # 消费恒定 ⇒ 排名固定 + +fig, ax = plt.subplots() +ax.plot(dates, rank_comp, lw=2, linestyle='--', color='C3', + label='完全市场') +ax.plot(dates, rank_inc, lw=2, marker='o', color='C0', + label='不完全市场') +ax.set_xlabel('周期 $t$') +ax.set_ylabel(r'与 $c_0$ 的秩相关系数') +ax.set_ylim(0, 1.05) +ax.legend() +plt.show() +``` + +在完全市场下,秩相关系数恰好保持为 1:每个消费者永远保持由初始抽样 $z_0^i$ 决定的排名。 + +在不完全市场下,秩相关系数随着累积的随机游走重新洗牌谁富谁穷而衰减至零,即使每个消费者都面临相同的收入过程。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/lq_permanent_income.md b/lectures/lq_permanent_income.md new file mode 100644 index 0000000..da624f9 --- /dev/null +++ b/lectures/lq_permanent_income.md @@ -0,0 +1,723 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.11.1 +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: LQ 永久收入模型 + headings: + Overview: 概述 + The standard LQ permanent income model: 标准 LQ 永久收入模型 + The standard LQ permanent income model::Setup: 设定 + The standard LQ permanent income model::Euler equation and certainty equivalence: 欧拉方程与确定性等价 + The standard LQ permanent income model::The optimal consumption function: 最优消费函数 + 'The standard LQ permanent income model::Representation 1: state $(b_t, z_t)$': 表示 1:状态 $(b_t, z_t)$ + 'The standard LQ permanent income model::Representation 2: state $(c_t, z_t)$': 表示 2:状态 $(c_t, z_t)$ + The standard LQ permanent income model::Debt dynamics: 债务动态 + The standard LQ permanent income model::Two classic examples: 两个经典例子 + The standard LQ permanent income model::Implementation: 实现 + Exercises: 练习 +--- + +(lq_permanent_income)= +```{raw} jupyter + +``` + +# LQ 永久收入模型 + +```{contents} Contents +:depth: 2 +``` + +```{index} single: LQ Permanent Income Model +``` + +```{index} single: Consumption Smoothing +``` + +## 概述 + +本讲座研究线性二次型(LQ)永久收入模型中的消费平滑。 + +它给出了 {cite:t}`Friedman1956` 和 {cite:t}`Hall1978` 永久收入理论的理性预期版本。 + +在整个讲座中,我们设定 $\beta R = 1$,使得基准消费者的主观贴现因子等于债券价格。 + +该模型对于研究以下内容很有用 + +- 脉冲响应函数 +- 最优决策规则的其他状态空间表示 +- 消费与资产的协整 + +我们推导消费者的最优消费函数,给出最优决策规则的两种状态空间表示,并用两个经典例子加以说明。 + +这是关于 LQ 永久收入模型的三讲中的第一讲。 + +后续两讲直接建立在这里开发的工具之上。 + +- {doc}`lq_bewley_complete_markets` 研究消费的横截面行为,并将单个消费者嵌入具有不完全市场和完全市场的封闭经济中。 +- {doc}`lq_robust_smoothing` 研究一个不信任自己收入模型并进行预防性储蓄的消费者。 + +让我们从一些导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +from scipy.linalg import solve, inv, solve_discrete_lyapunov +from scipy.stats import norm + +``` + +## 标准 LQ 永久收入模型 + +```{index} single: LQ Permanent Income Model; standard +``` + +### 设定 + +```{index} single: Permanent Income Hypothesis; Friedman +``` + +一个消费者对消费流具有偏好,其排序由下式给出 + +$$ +\mathbb{E}_0 \sum_{t=0}^{\infty} \beta^t u(c_t) +$$ (eq:sprob1) + +其中 $\mathbb{E}_t$ 是以消费者时刻 $t$ 的信息为条件的数学期望, +$c_t$ 是时刻 $t$ 的消费,$u(c)$ 是严格凹的单期效用函数,且 +$\beta \in (0,1)$ 是贴现因子。 + +消费者通过选择一个计划 +$\{c_t, b_{t+1}\}_{t=0}^{\infty}$ 来最大化 {eq}`eq:sprob1`,并满足预算约束序列 + +$$ +c_t + b_t = R^{-1} b_{t+1} + y_t, \quad t \geq 0 +$$ (eq:sprob2) + +其中 $\{y_t\}$ 是外生的平稳禀赋过程,$R$ 是常数总无风险利率,$b_t$ 是在 $t$ 到期的单期无风险债券,$b_0$ 是给定的初始条件。 + +```{note} +对于 $t \geq 1$,$b_t$ 是在时刻 $t-1$ 选择的。 + +债券 $b_t > 0$ 表示消费者在期初 $t$ 所欠的债务。 +``` + +我们假设 $R^{-1} = \beta$。 + +禀赋或非金融收入过程具有状态空间表示 + +$$ +\begin{aligned} +z_{t+1} &= \check{A}\, z_t + \check{C}\, w_{t+1} \\ +y_t &= \check{G}\, z_t +\end{aligned} +$$ (eq:sprob15) + +其中 $w_{t+1}$ 是均值为零且协方差矩阵为单位矩阵的 IID,$\check{A}$ 是稳定矩阵(特征值的模严格小于一),且 $\check{G}$ 是行向量。 + +家庭在 $t$ 面临的状态是 +$\bigl[b_t \;\; z_t^\top\bigr]^\top$,其中 $b_t$ 是其在期初 $t$ 到期的单期债务, +而 $z_t$ 包含所有对预测其未来禀赋有用的变量。 + +为了使问题成为线性二次型,我们采用**二次效用函数** + +$$ +u(c_t) = -\tfrac{1}{2}(c_t - \gamma)^2 +$$ + +其中 $\gamma > 0$ 是消费的极乐水平。 + +我们允许 $c_t$ 为负(此时是生产者而非消费者)。 + +我们施加一个**横截性条件** + +$$ +\mathbb{E}_0 \sum_{t=0}^{\infty} \beta^t b_t^2 < +\infty , +$$ (eq:sprob3) + +它排除了庞氏骗局。 + +### 欧拉方程与确定性等价 + +在二次效用下,消费者问题的一阶条件意味着 + +$$ +\mathbb{E}_t c_{t+1} = c_t +$$ (eq:sprob5) + +```{note} +方程 {eq}`eq:sprob5` 表明消费是一个鞅。 + +这是 LQ 永久收入模型的关键含义。 + +它与那些具有凸边际效用($u''' > 0$)的模型形成对比,在那些模型中消费反而是一个下鞅。 +``` + +因为消费者在线性转移方程的约束下最大化二次目标, +所以该问题满足**确定性等价**性质。 + +这意味着我们可以通过以下方式找到最优计划 + +- 首先在假装拥有完全预见的情况下求解问题;这让我们能够将 $c_t$ 表示为 $b_t$ 和延续序列 $\{y_{t+j}\}_{j=0}^{\infty}$ 的函数 +- 然后只需用 $\{\mathbb{E}_t y_{t+j}\}_{j=0}^{\infty}$ 替换 $\{y_{t+j}\}_{j=0}^{\infty}$。 + +### 最优消费函数 + +将预算约束 {eq}`eq:sprob2` 向前求解,施加横截性条件,并取条件期望,得到 + +$$ +b_t = \sum_{j=0}^{\infty} \beta^j \mathbb{E}_t y_{t+j} - \frac{1}{1-\beta} c_t +$$ (eq:sprob7) + +重新整理得到**消费函数** + +$$ +c_t = (1-\beta)\!\left[\sum_{j=0}^{\infty} \beta^j \mathbb{E}_t y_{t+j} - b_t\right] +$$ (eq:sprob8) + +等价地,用由 $\beta = 1/(1+r)$ 定义的净利率 $r$ 表示, + +$$ +c_t = \frac{r}{1+r}\!\left[\sum_{j=0}^{\infty} \beta^j \mathbb{E}_t y_{t+j} - b_t\right] +$$ (eq:sprob9) + +显然,$t$ 时刻的消费等于 $r/(1+r)$ 乘以总财富,其中总财富是人力财富 +$\sum_{j=0}^{\infty}\beta^j \mathbb{E}_t y_{t+j}$ 与金融财富 $-b_t$ 之和。 + +使用状态空间表示 {eq}`eq:sprob15` 来计算预期未来禀赋的几何级数和, + +$$ +\sum_{j=0}^{\infty} \beta^j \mathbb{E}_t y_{t+j} = \check{G}(I - \beta \check{A})^{-1} z_t , +$$ (eq:discount1) + +我们得到 + +$$ +c_t = (1-\beta)\!\left[\check{G}(I-\beta\check{A})^{-1} z_t - b_t\right] +$$ (eq:lccf) + +这将 $c_t$ 表示为家庭所面临的状态 $[b_t,\, z_t^\top]^\top$ 的函数。 + +### 表示 1:状态 $(b_t, z_t)$ + +将禀赋运动定律与最优债务动态(通过将 {eq}`eq:lccf` 代入 {eq}`eq:sprob2` 得到)相结合,给出如下表示: + +$$ +\begin{aligned} +z_{t+1} &= \check{A}\, z_t + \check{C}\, w_{t+1} \\ +b_{t+1} &= b_t + \check{G}\bigl[(I - \beta\check{A})^{-1}(\check{A}-I)\bigr] z_t \\ +y_t &= \check{G}\, z_t \\ +c_t &= (1-\beta)\!\left[\check{G}(I-\beta\check{A})^{-1} z_t - b_t\right] +\end{aligned} +$$ (eq:rep1) + +在此表示中,**外生**状态是 $z_t$,而**内生**状态是 $b_t$。 + +现在我们转向另一种表示。 + +### 表示 2:状态 $(c_t, z_t)$ + +{cite:t}`Hall1978` 证明了 LQ 永久收入模型蕴含一种表示, +其中状态由当前消费 $c_t$ 和外生禀赋状态 $z_t$ 构成。 + +在此表示中,$b_t$ 成为一个结果而非状态变量。 + +将 {eq}`eq:sprob8` 向前推移,通过 {eq}`eq:sprob2` 消去 $b_{t+1}$,并重新整理,得到 + +$$ +c_{t+1} - c_t = (1-\beta)\sum_{j=0}^{\infty} \beta^j \bigl(\mathbb{E}_{t+1} y_{t+j+1} - \mathbb{E}_t y_{t+j+1}\bigr) +$$ (eq:sprob11) + +右侧是 $(1-\beta)$ 乘以对禀赋流预期现值的时刻 $(t+1)$ **新息**。 + +假设禀赋具有(Wold)移动平均表示 + +$$ +y_{t+1} = d(L)\, w_{t+1}, \qquad d(L) = \sum_{j=0}^{\infty} d_j L^j +$$ (eq:sprob12) + +其中 $d(L) = \check{G}(I - \check{A} L)^{-1}\check{C}$。 + +那么 + +$$ +\mathbb{E}_{t+1} y_{t+j} - \mathbb{E}_t y_{t+j} = d_{j-1}\, w_{t+1} +$$ (eq:sprob120) + +将 {eq}`eq:sprob120` 代入 {eq}`eq:sprob11` 得到关键结果 + +$$ +c_{t+1} - c_t = (1-\beta)\, d(\beta)\, w_{t+1} . +$$ (eq:sprob13) + +这里,$d(\beta) = \check{G}(I-\beta\check{A})^{-1}\check{C}$ 是**(Wold)移动平均系数的现值**。 + +因此,消费是一个**随机游走**,其新息为 +$(1-\beta)d(\beta)w_{t+1}$。 + +将 {eq}`eq:sprob13` 与 {eq}`eq:sprob7` 结合,得到 + +$$ +\begin{aligned} +c_{t+1} &= c_t + (1-\beta)\,\check{G}(I-\beta\check{A})^{-1}\check{C}\, w_{t+1} \\ +b_t &= \check{G}(I-\beta\check{A})^{-1} z_t - \frac{1}{1-\beta}\,c_t \\ +y_t &= \check{G}\, z_t \\ +z_{t+1} &= \check{A}\, z_t + \check{C}\, w_{t+1} +\end{aligned} +$$ (eq:sprob16) + +这种表示揭示了最优决策规则的若干重要特征: + +1. **状态**:状态由内生分量 $c_t$ 和外生分量 + $z_t$ 构成,金融资产 $b_t$ 被编码在 $c_t$ 中,而不是作为单独的状态携带。 + +2. **随机游走**:消费是一个随机游走,其新息为 $(1-\beta)d(\beta)w_{t+1}$,这 + 确认了欧拉方程 {eq}`eq:sprob5` 已内建于解中,并意味着 + 消费没有渐近平稳分布。 + +3. **箱形脉冲响应**:对于所有 $j \geq 1$,$c_{t+j}$ 对新息 + $w_{t+1}$ 的响应是常数 $(1-\beta)d(\beta)$,给出一个"箱形"脉冲响应。 + +4. **协整**:$c_t$ 和 $b_t$ 都是非平稳的(单位根过程),但 + 线性组合 $(1-\beta)b_t + c_t$ 是平稳的。 + + 由 {eq}`eq:sprob7`, + +$$ +(1-\beta)b_t + c_t = (1-\beta)\mathbb{E}_t\sum_{j=0}^{\infty}\beta^j y_{t+j} +$$ (eq:cointegration) + +左侧是协整残差。 + + + +### 债务动态 + +```{index} single: History Dependence +``` + +将 {eq}`eq:sprob16`($b_t$ 的方程)在时刻 $t$ 从同一方程在时刻 $t+1$ 中减去 +并代入,得到 + +$$ +b_{t+1} - b_t = \check{G}(I-\beta\check{A})^{-1}(\check{A}-I)\, z_t +$$ (eq:debt_evolution) + +这表明 $b_{t+1}$ 在时刻 $t$ 作为 $z_t$ 单独的函数已**预先确定**。 + +从任意 $t$ 向后求解,$b_t$ 依赖于整个历史 $z^{t-1} = [z_{t-1},\ldots,z_0]$ +和初始条件 $b_0$。 + +这种**历史依赖性**是各种不完全市场经济中消费计划的一个标志。 + +### 两个经典例子 + +```{index} single: Permanent Income Model; examples +``` + +我们用两个例子来说明公式 {eq}`eq:sprob16`。 + +在这两个例子中,禀赋均为 +$y_t = z_{1t} + z_{2t}$,其中 + +$$ +\begin{pmatrix}z_{1,t+1}\\z_{2,t+1}\end{pmatrix} += +\begin{pmatrix}1 & 0\\0 & 0\end{pmatrix} +\begin{pmatrix}z_{1t}\\z_{2t}\end{pmatrix} ++ +\begin{pmatrix}\sigma_1 & 0\\0 & \sigma_2\end{pmatrix} +\begin{pmatrix}w_{1,t+1}\\w_{2,t+1}\end{pmatrix} +$$ (eq:twofactor) + +这里 $z_{1t}$ 是 $y_t$ 的**永久性**分量,而 $z_{2t}$ 是**纯暂时性**分量。 + +在完全信息的例子中,消费者在时刻 $t$ 观测到状态 $z_t$,因此他 +可以从 $z_{t+1}$ 和 $z_t$ 重构出 $w_{t+1}$。 + +应用 {eq}`eq:sprob16`: + +$$ +c_{t+1} - c_t = \sigma_1 w_{1,t+1} + (1-\beta)\,\sigma_2\, w_{2,t+1} +$$ (eq:consexample1) + +对永久性分量 $z_{1t}$ 的单位增量*一对一地*永久提高消费, +并导致**零净储蓄**。 + +对纯暂时性分量的单位增量仅永久提高 +消费 $(1-\beta)$ 这一比例,而其余比例 $\beta$ 被储蓄。 + +由 {eq}`eq:debt_evolution`: + +$$ +b_{t+1} - b_t = -z_{2t} = -\sigma_2 w_{2t} +$$ (eq:consexample1a) + +这确认了永久性冲击完全没有被储蓄,而暂时性冲击则全部被储蓄。 + +在不完全信息(Muth 模型)的例子中,消费者观测到 $y_t$ 及其历史, +但不能分别观测到 $z_{1t}$ 和 $z_{2t}$。 + +恰当的方法使用由卡尔曼滤波器推导出的**新息表示**。 + +在卡尔曼滤波器稳态下,**卡尔曼增益** $K \in [0,1]$ 满足 + +$$ +K = \frac{\Sigma}{\Sigma + \sigma_2^2}, \qquad \Sigma = \frac{\sigma_1^2 + \sqrt{\sigma_1^4 + 4\sigma_1^2\sigma_2^2}}{2} +$$ (eq:kalmangain) + +其中 $K$ 随着比率 $\sigma_1^2/\sigma_2^2$(永久性冲击相对于暂时性冲击的方差) +的增大而增大。 + +新息表示将禀赋表示为其自身新息 $a_t = y_t - \mathbb{E}[y_t \mid y^{t-1}]$(提前一步的预测误差)中的 ARMA(1,1): + +$$ +y_{t+1} = y_t - (1-K)\,a_t + a_{t+1} +$$ (eq:muth_innov) + +这里滞后新息上的系数 $-(1-K)$ 反映出只有上期意外的比例 +$K$ 被视为永久性的;其余部分均值回归。 + +标量 $a_t$ 是 IID,方差为 $\Sigma + \sigma_2^2$。 + +将 {eq}`eq:sprob16` 应用于这个新息表示: + +$$ +c_{t+1} - c_t = [1 - \beta(1-K)]\, a_{t+1} +$$ (eq:consexample2) + +消费者将新息 $a_{t+1}$ 的比例 $K$ 视为永久性的,将比例 $1-K$ +视为暂时性的。 + +他将消费永久提高 $a_{t+1}$ 的 $K + (1-\beta)(1-K) = 1 - \beta(1-K)$, +并储蓄其余比例 $\beta(1-K)$。 + +收入的一阶差分服从一阶移动平均: + +$$ +y_{t+1} - y_t = a_{t+1} - (1-K)\,a_t +$$ (eq:incomemaar) + +相比之下,由 {eq}`eq:consexample2`,消费的一阶差分是 IID 的。 + +### 实现 + +```{code-cell} ipython3 +# 参数 +β = 0.95 # 贴现因子(因此 R = 1/β) +σ1 = 0.15 # 永久性冲击的标准差 +σ2 = 0.30 # 暂时性冲击的标准差 + +# 例子 1:完全信息 +A_check = np.array([[1.0, 0.0], + [0.0, 0.0]]) +C_check = np.array([[σ1, 0.0], + [0.0, σ2]]) +G_check = np.array([[1.0, 1.0]]) + +# 关键矩阵 M = G(I - βA)^{-1} +IbA = np.eye(2) - β * A_check +M = G_check @ inv(IbA) # 形状 (1, 2) + +# 消费脉冲响应 +h = (1 - β) * M @ C_check # 形状 (1, 2) +irf_perm_ex1 = h[0, 0] / σ1 # 每单位永久性冲击标准差的响应 +irf_trans_ex1 = h[0, 1] / σ2 # 每单位暂时性冲击标准差的响应 + +print("例子 1(完全信息)") +print(f" c 对永久性冲击的 IRF (已标准化): {irf_perm_ex1:.4f} " + f"(理论值: 1.0)") +print(f" c 对暂时性冲击的 IRF(已标准化): {irf_trans_ex1:.4f} " + f"(理论值: {1-β:.4f})") +``` + +```{code-cell} ipython3 +# 例子 2:部分信息 +Σ = (σ1**2 + np.sqrt(σ1**4 + 4 * σ1**2 * σ2**2)) / 2 +K = Σ / (Σ + σ2**2) + +print("例子 2(部分信息)") +print(f" 稳态卡尔曼增益 K = {K:.4f}") +print(f" c 对单位新息 a_{{t+1}} 的 IRF: {1 - β*(1-K):.4f}") +print(f" 被视为永久性的新息比例(K): {K:.4f}") +print(f" 被储蓄的比例: β(1-K) = {β*(1-K):.4f}") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 消费脉冲响应 + name: fig-lqcs-irf-examples +--- +# 比较脉冲响应 +T = 30 +irf_c_ex1_perm = np.ones(T) * irf_perm_ex1 * σ1 +irf_c_ex1_trans = np.ones(T) * irf_trans_ex1 * σ2 + +irf_c_ex2 = np.ones(T) * (1 - β * (1 - K)) # 每单位新息 a_t + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].axhline(0, color='k', linewidth=0.8) +axes[0].step(range(T), irf_c_ex1_perm, where='post', + label='永久性冲击 ($z_1$)', color='C0', lw=2) +axes[0].step(range(T), irf_c_ex1_trans, where='post', + label='暂时性冲击 ($z_2$)', color='C3', + linestyle='--', lw=2) +axes[0].set_xlabel('冲击后的期数') +axes[0].set_ylabel('$c$ 的响应') +axes[0].set_title('完全信息') +axes[0].legend() + +axes[1].axhline(0, color='k', linewidth=0.8) +axes[1].step(range(T), irf_c_ex2, where='post', + label=f'单位新息 $a_{{t+1}}$ (K = {K:.2f})', + color='C4', lw=2) +axes[1].set_xlabel('冲击后的期数') +axes[1].set_ylabel('$c$ 的响应') +axes[1].set_title('部分信息') +axes[1].legend() +fig.tight_layout() +plt.show() +``` + +```{note} +脉冲响应具有 LQ 永久收入模型特有的"箱形"形状:一旦 +冲击发生,消费便永久转移到一个新水平并保持在那里。 +``` + +这里开发的两种表示和例子是后续两讲的基础。 + +{doc}`lq_bewley_complete_markets` 使用 $(c_t, z_t)$ 表示 {eq}`eq:sprob16` 来研究消费的横截面分布如何在具有不完全市场和完全市场的封闭经济中演变。 + +{doc}`lq_robust_smoothing` 研究一个不信任禀赋过程 {eq}`eq:sprob15` 并进行预防性储蓄的消费者。 + +## 练习 + +```{exercise-start} +:label: lqpi_ex1 +``` + +本练习验证在完全信息的双因子模型中消费和债务对永久性和暂时性冲击的响应。 + +考虑 {eq}`eq:twofactor` 的模型,采用上面使用的校准。 + +假设经济从 $z_0 = 0$ 和 $b_0 = 0$ 开始,并在 $t = 1$ 时受到单一冲击:要么是单位永久性冲击 $w_1 = (1, 0)^\top$,要么是单位暂时性冲击 $w_1 = (0, 1)^\top$,此后没有进一步的冲击。 + +1. 使用表示 {eq}`eq:rep1`,计算并绘制每次冲击后消费 $c_t$ 和债务 $b_t$ 的路径。 + +2. 确认永久性冲击将消费永久提高 $\sigma_1$ 并且不引起储蓄,而暂时性冲击将消费永久提高 $(1-\beta)\sigma_2$,其余部分被储蓄。 + +```{exercise-end} +``` + +```{solution-start} lqpi_ex1 +:class: dropdown +``` + +这里是一个解答: + +我们在 $t = 1$ 时施加单一冲击,将表示 {eq}`eq:rep1` 向前迭代。 + +```{code-cell} ipython3 +def impulse_response(shock, T=20): + """在 t=1 施加单一冲击后 c 和 b 的路径(z_0 = b_0 = 0)。""" + I2 = np.eye(2) + b_coef = M @ (A_check - I2) # b 定律中 z_t 上的系数 + + z = np.zeros((T + 1, 2)) + b = np.zeros(T + 1) + + z[1] = C_check @ shock # 冲击在 t = 1 实现 + for t in range(1, T): + z[t + 1] = A_check @ z[t] + for t in range(T): + b[t + 1] = b[t] + (b_coef @ z[t]).item() + + c = np.array([((1 - β) * (M @ z[t] - b[t])).item() for t in range(T + 1)]) + return c, b + + +c_perm, b_perm = impulse_response(np.array([1.0, 0.0])) +c_tran, b_tran = impulse_response(np.array([0.0, 1.0])) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].step(range(len(c_perm)), c_perm, where='post', + label='永久性冲击', color='C0', lw=2) +axes[0].step(range(len(c_tran)), c_tran, where='post', + label='暂时性冲击', color='C3', linestyle='--', lw=2) +axes[0].axhline(0, color='k', lw=0.8) +axes[0].set_xlabel('期数 $t$') +axes[0].set_ylabel('$c$ 的响应') +axes[0].set_title('消费') +axes[0].legend() + +axes[1].step(range(len(b_perm)), b_perm, where='post', + label='永久性冲击', color='C0', lw=2) +axes[1].step(range(len(b_tran)), b_tran, where='post', + label='暂时性冲击', color='C3', linestyle='--', lw=2) +axes[1].axhline(0, color='k', lw=0.8) +axes[1].set_xlabel('期数 $t$') +axes[1].set_ylabel('$b$ 的响应') +axes[1].set_title('债务') +axes[1].legend() +fig.tight_layout() +plt.show() + +print(f"永久性冲击: Δc = {c_perm[-1]:.4f} (理论 σ1 = {σ1:.4f})," + f" Δb = {b_perm[-1]:.4f}") +print(f"暂时性冲击: Δc = {c_tran[-1]:.4f} " + f"(理论 (1-β)σ2 = {(1-β)*σ2:.4f}), Δb = {b_tran[-1]:.4f}") +``` + +永久性冲击将消费提高 $\sigma_1$ 并使债务保持为零:冲击被完全资本化,因此没有净储蓄。 + +暂时性冲击仅将消费提高 $(1-\beta)\sigma_2$;消费者储蓄其余部分,因此债务降至 $-\sigma_2$(资产积累)。 + +```{solution-end} +``` + +```{exercise-start} +:label: lqpi_ex2 +``` + +本练习说明 {eq}`eq:cointegration` 中所描述的消费与债务的**协整**。 + +协整结果需要一个*平稳*禀赋,因此我们用一个标量 AR(1) 替换双因子过程, + +$$ +z_{t+1} = \rho z_t + \sigma_\varepsilon w_{t+1}, \qquad y_t = z_t, +$$ + +其中 $\rho = 0.7$ 且 $\sigma_\varepsilon = 0.5$。 + +1. 使用表示 {eq}`eq:rep1` 模拟 $c_t$ 和 $b_t$ 的一条长路径。 + +2. 验证 $c_t$ 和 $b_t$ 各自都继承了一个单位根(它们游走),而协整残差 $(1-\beta)b_t + c_t$ 是平稳的,且等于 $(1-\beta)\check{G}(I-\beta\check{A})^{-1}z_t$。 + +```{exercise-end} +``` + +```{solution-start} lqpi_ex2 +:class: dropdown +``` + +这里是一个解答: + +```{code-cell} ipython3 +ρ, σε = 0.7, 0.5 +A_ar = np.array([[ρ]]) +C_ar = np.array([[σε]]) +G_ar = np.array([[1.0]]) + +M_ar = G_ar @ inv(np.eye(1) - β * A_ar) # G(I - βA)^{-1} +b_coef_ar = M_ar @ (A_ar - np.eye(1)) # b 定律中 z_t 上的系数 + +rng = np.random.default_rng(0) +T = 400 +z = np.zeros((T + 1, 1)) +b = np.zeros(T + 1) +for t in range(T): + z[t + 1] = A_ar @ z[t] + C_ar @ rng.standard_normal(1) + b[t + 1] = b[t] + (b_coef_ar @ z[t]).item() + +c = np.array([((1 - β) * (M_ar @ z[t] - b[t])).item() for t in range(T + 1)]) +residual = (1 - β) * b + c +theory = np.array([((1 - β) * (M_ar @ z[t])).item() for t in range(T + 1)]) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) +axes[0].plot(c, label='$c_t$', lw=1.5) +axes[0].plot(b, label='$b_t$', lw=1.5) +axes[0].set_xlabel('期数 $t$') +axes[0].set_title('消费与债务(非平稳)') +axes[0].legend() + +axes[1].plot(residual, label=r'$(1-\beta)b_t + c_t$', lw=1.5, color='C0') +axes[1].plot(theory, label=r'$(1-\beta)\check{G}(I-\beta\check{A})^{-1}z_t$', + lw=1.5, linestyle='--', color='C3') +axes[1].set_xlabel('期数 $t$') +axes[1].set_title('协整残差(平稳)') +axes[1].legend() +fig.tight_layout() +plt.show() + +print(f"max |residual - theory| = {np.max(np.abs(residual - theory)):.2e}") +``` + +$c_t$ 和 $b_t$ 都继承了随机游走消费规则内建于解中的单位根,因此它们漂移而不会稳定下来。 + +它们的线性组合 $(1-\beta)b_t + c_t$ 与 $(1-\beta)\check{G}(I-\beta\check{A})^{-1}z_t$ 一致(直至浮点误差),后者是平稳状态 $z_t$ 的一个平稳函数。 + +```{solution-end} +``` + +```{exercise-start} +:label: lqpi_ex3 +``` + +本练习探讨消费者的信息问题如何在 Muth 模型中塑造他对收入意外的响应。 + +回顾 {eq}`eq:consexample2`,对单位收入新息 $a_{t+1}$ 的永久消费响应为 $1 - \beta(1-K)$,其中 {eq}`eq:kalmangain` 中的卡尔曼增益 $K$ 取决于比率 $\sigma_1/\sigma_2$。 + +1. 在保持 $\sigma_2$ 固定的情况下,将响应 $1 - \beta(1-K)$ 绘制为比率 $\sigma_1/\sigma_2$ 的函数。 + +2. 解释两个极限情形 $\sigma_1/\sigma_2 \to 0$ 和 $\sigma_1/\sigma_2 \to \infty$,并将它们与完全信息模型的两种冲击联系起来。 + +```{exercise-end} +``` + +```{solution-start} lqpi_ex3 +:class: dropdown +``` + +这里是一个解答: + +```{code-cell} ipython3 +ratios = np.linspace(0.02, 6.0, 300) +σ2_fixed = 0.30 + +responses = [] +for r in ratios: + s1 = r * σ2_fixed + Σ = (s1**2 + np.sqrt(s1**4 + 4 * s1**2 * σ2_fixed**2)) / 2 + K = Σ / (Σ + σ2_fixed**2) + responses.append(1 - β * (1 - K)) + +fig, ax = plt.subplots() +ax.plot(ratios, responses, lw=2, color='C0') +ax.axhline(1.0, color='C3', linestyle='--', lw=1, + label=r'永久性极限 ($K\to1$)') +ax.axhline(1 - β, color='C4', linestyle='--', lw=1, + label=r'暂时性极限 ($K\to0$): $1-\beta$') +ax.set_xlabel(r'$\sigma_1/\sigma_2$') +ax.set_ylabel(r'消费响应 $1-\beta(1-K)$') +ax.legend() +plt.show() +``` + +当 $\sigma_1/\sigma_2 \to 0$ 时,禀赋被暂时性噪声主导,因此 $K \to 0$:消费者将每个新息视为暂时性的,仅将消费提高 $1-\beta$,这与完全信息模型中的纯暂时性冲击完全相同。 + +当 $\sigma_1/\sigma_2 \to \infty$ 时,禀赋被永久性冲击主导,因此 $K \to 1$:消费者将每个新息视为永久性的,并一对一地提高消费,这与永久性冲击完全相同。 + +对于中间的比率,消费者最优地拆分每个意外,将他归因于永久性分量的比例 $K$ 资本化,并储蓄其余部分。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/lq_robust_smoothing.md b/lectures/lq_robust_smoothing.md new file mode 100644 index 0000000..262bef8 --- /dev/null +++ b/lectures/lq_robust_smoothing.md @@ -0,0 +1,1093 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.11.1 +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 稳健消费平滑与预防性储蓄 + headings: + Overview: 概述 + A brief review: 简要回顾 + A robust permanent income model: 稳健永久收入模型 + A robust permanent income model::Robustness and precautionary savings: 稳健性与预防性储蓄 + A robust permanent income model::The HST model: HST 模型 + A robust permanent income model::Solution when $\sigma = 0$: $\sigma = 0$ 时的解 + A robust permanent income model::Observational equivalence: 观测等价性 + A robust permanent income model::Precautionary savings interpretation: 预防性储蓄解释 + A robust permanent income model::Observational equivalence and distorted expectations: 观测等价性与扭曲预期 + A robust permanent income model::Frequency domain interpretation: 频域解释 + A robust permanent income model::Detection error probabilities: 检测误差概率 + A robust permanent income model::Robustness of decision rules: 决策规则的稳健性 + A robust permanent income model::Another observational equivalence result: 另一个观测等价性结果 + A robust permanent income model::A robust LQ Bewley model: 稳健 LQ Bewley 模型 + A robust permanent income model::A robust LQ Bewley model::Heterogeneous $(\beta_i, \sigma_i)$ preferences: 异质 $(\beta_i, \sigma_i)$ 偏好 + A robust permanent income model::A robust LQ Bewley model::Computation: 计算 + A robust permanent income model::Concluding remarks: 结束语 + Exercises: 练习 +--- + +(lq_robust_smoothing)= +```{raw} jupyter + +``` + +# 稳健消费平滑与预防性储蓄 + +```{contents} Contents +:depth: 2 +``` + +```{index} single: Robust Control; permanent income +``` + +```{index} single: Precautionary Savings; robustness +``` + +## 概述 + +本讲座研究由 {cite:t}`HST_1999` 和 {cite:t}`HansenSargent2008` 提出的 LQ 永久收入模型的稳健版本。 + +这是关于 LQ 永久收入模型三讲中的第三讲。 + +它建立在 {doc}`lq_permanent_income` 之上,该讲座发展了标准模型,以及 {doc}`lq_bewley_complete_markets`,该讲座研究了其横截面和市场结构方面的含义。 + +一个不信任自己对劳动收入过程设定的消费者会从事某种形式的预防性储蓄。 + +我们对具有稳健性考量的模型的描述包括: + +- (对于数量而言)稳健性考量如何在观测上等价于不耐心程度的增加 +- 消费者用来塑造其决策规则的最坏情况模型如何扭曲基准模型的禀赋过程,使其朝向更强的持续性 +- 对禀赋过程设定误差影响的频域表示 +- 对模型不确定性大小的检测误差概率刻画 + +本讲座最后将 {doc}`lq_bewley_complete_markets` 的 Bewley 经济与稳健性机制相结合。 + +利用 {cite:t}`HansenSargent2008` 的工具,我们展示: + +- 使用相同决策规则的连续统消费者 $i$ 如何仍能在其稳健性参数 $\sigma_i \leq 0$ 和贴现因子 $\beta_i$ 上存在差异,只要 $(\sigma_i, \beta_i)$ 对位于下文推导的观测等价轨迹上 +- 每个这样的消费者如何选择与基准的、对禀赋过程设定误差毫不担忧的普通 $(\sigma = 0, \beta)$ 代理**相同的消费-储蓄规则** +- 均衡利率 $R = \beta^{-1}$ 和所有总量动态因此如何与基准 Bewley 模型的相一致 +- 不同的 $(\sigma_i, \beta_i)$ 代理如何表现得就像他们对其非金融收入过程持有不同的主观模型一样 + +我们首先以其一般形式呈现 HST 模型,其中包括物质资本和投资 $i_t$。 + +当我们回到 {doc}`lq_bewley_complete_markets` 的 Bewley 经济时,我们专门讨论一个没有资本的纯禀赋经济,因此投资在那里不起作用。 + +让我们从一些导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.stats import norm +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n + +``` + +## 简要回顾 + +我们回顾 {doc}`lq_permanent_income` 和 {doc}`lq_bewley_complete_markets` 的要点。 + +一个具有二次效用和贴现因子 $\beta$ 的消费者面对禀赋过程 + +$$ +\begin{aligned} +z_{t+1} &= \check{A}\, z_t + \check{C}\, w_{t+1} \\ +y_t &= \check{G}\, z_t +\end{aligned} +$$ (eq:rs-endowment) + +最优决策规则具有一个状态空间表示,其中状态是当前消费 $c_t$ 和外生禀赋状态 $z_t$: + +$$ +\begin{aligned} +c_{t+1} &= c_t + (1-\beta)\,\check{G}(I-\beta\check{A})^{-1}\check{C}\, w_{t+1} \\ +b_t &= \check{G}(I-\beta\check{A})^{-1} z_t - \frac{1}{1-\beta}\,c_t \\ +y_t &= \check{G}\, z_t \\ +z_{t+1} &= \check{A}\, z_t + \check{C}\, w_{t+1} +\end{aligned} +$$ (eq:rs-crep) + +我们再次使用双因子禀赋 $y_t = z_{1t} + z_{2t}$, + +$$ +\begin{pmatrix}z_{1,t+1}\\z_{2,t+1}\end{pmatrix} += +\begin{pmatrix}1 & 0\\0 & 0\end{pmatrix} +\begin{pmatrix}z_{1t}\\z_{2t}\end{pmatrix} ++ +\begin{pmatrix}\sigma_1 & 0\\0 & \sigma_2\end{pmatrix} +\begin{pmatrix}w_{1,t+1}\\w_{2,t+1}\end{pmatrix} +$$ (eq:pi-twofactor) + +其中 $z_{1t}$ 是永久成分,$z_{2t}$ 是纯粹的暂时成分。 + +下面的单元格固定了后文使用的校准。 + +```{code-cell} ipython3 +# 参数(与前面的讲座相同) +β = 0.95 # 贴现因子 +σ1 = 0.15 # 永久冲击的标准差 +σ2 = 0.30 # 暂时冲击的标准差 +``` + +## 稳健永久收入模型 + +```{index} single: Robust Control; permanent income +``` + +```{index} single: Precautionary Savings; robustness +``` + +### 稳健性与预防性储蓄 + +我们现在研究一个*不信任*自己对支配其劳动收入的随机过程设定的消费者。 + +该模型由 {cite:t}`HST_1999` (HST) 提出,他们用美国季度消费和投资数据对其进行了估计。 + +关于 HST 模型及其资产定价含义的更完整论述,请参见 {doc}`robust_permanent_income`。 + +一个担心模型设定误差的消费者会从事某种形式的**预防性储蓄**,这不同于通常的预防性动机(后者需要凸的边际效用)。 + +在这里,预防性动机之所以产生,是因为消费者想要防范收入冲击**条件均值**的设定误差,并且即使在二次偏好下它也起作用。 + +HST 展示了一个重要的**观测等价性**结果:仅就数量 $(c_t, i_t)$ 而言,稳健性考量与不耐心程度的增加($\beta$ 的减小)是无法区分的。 + +我们在下文中仔细展开这一结果。 + +```{index} single: Observational Equivalence; robustness and discounting +``` + +### HST 模型 + +```{index} single: Hansen Sargent Tallarini; model +``` + +HST 的模型的特点是一个计划者,其偏好作用于消费流 $\{c_t\}$,通过**服务流** $\{s_t\}$ 来中介。 + +设 $b$ 为一个偏好移位项(效用极乐点)。 + +**稳健计划者的贝尔曼方程**为 + +$$ +-x^\top P x - p = +\sup_c \inf_w \Bigl\{-(s-b)^2 + \beta\bigl(\theta (w^*)^\top w^* - \mathbb{E}\,(x^*)^\top P x^* - p\bigr)\Bigr\} +$$ (eq:income1) + +受制于家庭技术、资本积累、禀赋动态以及状态法则: + +$$ +\begin{aligned} +s &= (1+\lambda)c - \lambda h \\ +h^* &= \delta_h h + (1-\delta_h) c \\ +k^* &= \delta_k k + i \\ +c + i &= \gamma k + d \\ +\begin{pmatrix}d\\b\end{pmatrix} &= U z \\ +z^* &= A_{22} z + C_2(\epsilon^* + w^*) +\end{aligned} +$$ (eq:income1a) + +这里 $^*$ 表示下一期的值;$c$ 是消费;$s$ 是标量服务度量;$h$ 是习惯存量;$k$ 是资本存量;$i$ 是投资;$d$ 是禀赋/技术冲击;$b$ 是**偏好冲击**(极乐点移位项,不同于上文使用的债券/债务变量 $b_t$);$\epsilon^* \sim N(0,I)$ 是基准冲击;而 $w^*$ 是由一个最小化代理选择的对 $\epsilon^*$ 条件均值的**扭曲**。 + +惩罚参数 $\theta > 0$ 支配着消费者对稳健性的考量。 + +我们使用变换 + +$$ +\sigma = -\theta^{-1} \leq 0 +$$ + +因此 $\sigma = 0$ 对应于没有稳健性考量,而 $\sigma < 0$ 对应于日益增强的考量。 + +当 $\lambda > 0$ 且 $\delta_h \in (0,1)$ 时,技术 {eq}`eq:income1a` 容纳了**习惯持续性**(正的 $\lambda$)或耐久性。 + +存量 $h_t$ 是当前和过去消费的几何加权平均。 + +方程 $c_t + k_t = Rk_{t-1} + d_t$(其中 $R = \delta_k + \gamma$)将资本积累与线性生产技术结合起来。 + +$R$ 是资本的物质总回报率。 + +设 $x_t^\top = [h_{t-1},\, k_{t-1},\, z_t^\top]$。 + +状态转移方程为: + +$$ +x_{t+1} = A\, x_t + B\, u_t + C(\epsilon_{t+1} + w_{t+1}) +$$ (eq:law0) + +其中 $u_t = c_t$,$w_{t+1}$ 是对 $\epsilon_{t+1}$ 条件均值的扭曲。 + +HST 用美国季度数据(1970Q1-1996Q3)估计了该模型,消费使用非耐久品加服务,投资使用耐久品消费加私人总投资。 + +主要估计值总结在下表中(报告于 HST 的附录 A): + +| 参数 | 习惯 | 无习惯 | +|-----------|-------|----------| +| 无风险利率 | 0.025 | 0.025 | +| $\beta$ | 0.997 | 0.997 | +| $\delta_h$ | 0.682 | — | +| $\lambda$ | 2.443 | 0 | +| $\alpha_1$ | 0.813 | 0.900 | +| $\alpha_2$ | 0.189 | 0.241 | +| $\phi_1$ | 0.998 | 0.995 | +| $\phi_2$ | 0.704 | 0.450 | +| $2 \times \log L$ | 779.05 | 762.55 | + +HST 施加了 $\beta R = 1$ 和 $\delta_k = 0.975$,因此一旦估计出 $\beta$,$\gamma$ 就被确定下来。 + +2.5% 的年实际利率对应于 $\beta = 0.997$。 + +### $\sigma = 0$ 时的解 + +当 $\sigma = 0$ 时目标函数简化为 + +$$ +\mathbb{E}_0\sum_{t=0}^{\infty}\beta^t\bigl\{-(s_t - b_t)^2\bigr\} +$$ (eq:income5) + +构造拉格朗日函数并推导一阶条件得到: + +$$ +\begin{aligned} +\mu_{st} &= b_t - s_t \\ +\mu_{ct} &= (1+\lambda)\mu_{st} + (1-\delta_h)\mu_{ht} \\ +\mu_{ht} &= \beta \mathbb{E}_t[\delta_h \mu_{h,t+1} - \lambda \mu_{s,t+1}] \\ +\mu_{ct} &= \beta R\, \mathbb{E}_t\mu_{c,t+1} +\end{aligned} +$$ (eq:foc) + +这里 $\mu_{st}$ 是**消费服务的边际估值**,它总结了内生状态变量 $h_{t-1}$ 和 $k_{t-1}$。 + +方程 {eq}`eq:foc`(最后一行)意味着 $\mathbb{E}_t\mu_{c,t+1} = (\beta R)^{-1}\mu_{ct}$,因此当 $\beta R = 1$ 时 $\mu_{st}$ 是一个鞅: + +$$ +\mu_{st} = \mu_{s,t-1} + \nu^\top \epsilon_t +$$ (eq:martingale) + +对某个向量 $\nu$。 + +向前求解并代入得到 + +$$ +\mu_{st} = \Psi_1 k_{t-1} + \Psi_2 h_{t-1} + \Psi_3\sum_{j=0}^{\infty} R^{-j} \mathbb{E}_t b_{t+j} + + \Psi_4\sum_{j=0}^{\infty} R^{-j} \mathbb{E}_t d_{t+j} +$$ (eq:income10) + +其中 + +$$ +\Psi_1 = -(1+\lambda)R(1-R^{-2}\beta^{-1})\!\left[\frac{1-R^{-1}\tilde\delta_h}{1-R^{-1}\tilde\delta_h+\lambda(1-\tilde\delta_h)}\right], \quad +\Psi_4 = R^{-1}\Psi_1 +$$ (eq:income100a) + +且 $\tilde\delta_h = (\delta_h + \lambda)/(1+\lambda)$。 + +在被广泛研究的特殊情形 $\lambda = \delta_h = 0$ 下,因此 $s_t = c_t$ 且 $\mu_{st} = b_t - c_t$,从**非人力财富** $Rk_{t-1}$ 中消费的边际倾向等于从**人力财富** $\sum_{j=0}^{\infty}R^{-j}\mathbb{E}_t d_{t+j}$ 中消费的边际倾向,这是 LQ 模型的一个众所周知的特征。 + +$\mu_{st}$ 的公式可以写成 $\mu_{st} = M_s x_t$,其中 $x_t$ 遵循 {eq}`eq:law0`。 + +由此可得 + +$$ +\nu^\top = M_s C, \qquad \alpha = \sqrt{\nu^\top \nu} = \sqrt{M_s C C^\top M_s^\top} +$$ (eq:hsoffset2) + +标量 $\alpha$ 在下文的观测等价性结果中起核心作用。 + +### 观测等价性 + +```{index} single: Observational Equivalence; Theorem 1 +``` + +HST 陈述了一个观测等价性定理。 + +````{prf:theorem} 观测等价性,I +:label: thm-lqcs-oe1 + +固定除 $(\sigma, \beta)$ 之外的所有参数,并假设当 $\sigma = 0$ 时 $\beta R = 1$。 + +存在 $\underline\sigma < 0$,使得对于任意 $\sigma \in (\underline\sigma, 0)$,$(0,\beta)$ 的最优消费-投资计划也被一个参数为 $(\sigma, \hat\beta(\sigma))$ 的稳健决策者所选择,其中 + +$$ +\hat\beta(\sigma) = \frac{1}{R} + \frac{\sigma\alpha^2}{R-1} +$$ (eq:obseq) + +且 $\hat\beta(\sigma) < \beta$。 +```` + +由于 $R > 1$ 且 $\alpha^2 > 0$,更负的 $\sigma$(更强的稳健性考量)会降低 $\hat\beta$。 + +一个稳健的消费者想要储蓄更多,因为他的另一个自我,一个效用最小化的代理,让未来收入看起来比近似模型预测的更糟。 + +较低的贴现因子使消费者更不耐心,因此减少储蓄。 + +当这两种力量根据 {eq}`eq:obseq` 达到平衡时,消费计划在 $(\sigma, \hat\beta(\sigma))$ 对之间是相同的。 + +````{prf:proof} +当 $\beta R = 1$ 且 $\sigma = 0$ 时,边际效用 $\mu_{st}$ 服从鞅 + +$$ +\mu_{st} = \mu_{s,t-1} + \alpha\,\tilde\epsilon_t +$$ (eq:reversee1) + +其中 $\tilde\epsilon_t$ 是标量 IID,均值为零,单位方差。 + +激活稳健性考量($\sigma < 0$)意味着效用最小化的另一个自我设置 + +$$ +\tilde w_t = K(\sigma,\hat\beta)\,\mu_{s,t-1} +$$ + +使 $\mu_{st}$ 的最坏情况模型为: + +$$ +\mu_{st} = (1 + \alpha\,K(\sigma,\hat\beta))\,\mu_{s,t-1} + \alpha\,\tilde\epsilon_t +$$ (eq:reversee3) + +为使配置保持不变,我们要求稳健欧拉方程 $\hat\beta R\,\hat{\mathbb{E}}_t\mu_{s,t+1} = \mu_{st}$ 在最坏情况模型下成立,这给出 + +$$ +(\hat\beta R)^{-1} = 1 + \alpha\, K(\sigma,\hat\beta) +$$ (eq:eulerdist) + +最小化代理的贝尔曼方程,一个纯预测问题,给出 + +$$ +\hat\zeta(\hat\beta) \equiv 1 + \alpha K(\sigma,\hat\beta) = \frac{1}{1 - \sigma\alpha^2 P(\hat\beta)} +$$ (eq:distort2) + +其中 $P(\hat\beta)$ 求解标量贝尔曼方程: + +$$ +-P(\hat\beta) = \frac{\hat\beta - 1 + \sigma\alpha^2 + \sqrt{(\hat\beta-1+\sigma\alpha^2)^2 + 4\sigma\alpha^2}}{-2\sigma\alpha^2} +$$ (eq:distortcons) + +对 $\hat\beta$ 求解 {eq}`eq:eulerdist`-{eq}`eq:distortcons` 恰好给出 {eq}`eq:obseq`。 +```` + +方程 {eq}`eq:obseq` 是有用的数值对象,因为它给出了从稳健性参数到观测等价贴现因子的直线映射。 + +### 预防性储蓄解释 + +```{index} single: Precautionary Savings; robustness vs convex marginal utility +``` + +消费者对模型设定误差的考量激活了观测等价性定理背后的预防性储蓄动机。 + +对稳健性的考量使消费者储蓄*更多*。 + +减小 $\beta$ 使消费者储蓄*更少*。 + +观测等价性定理表明这两种力量可以被设置成恰好相互抵消。 + +在特殊情形 $\lambda = \delta_h = 0$ 下,$s_t = c_t$,消费规则为 + +$$ +c_t = (1 - R^{-2}\beta^{-1})\!\left[Rk_{t-1} + \mathbb{E}_t\sum_{j=0}^{\infty}R^{-j}d_{t+j}\right] + + \left(\frac{(R\beta)^{-1}-1}{R-1}\right)\!b +$$ (eq:consfunction) + +从非人力财富 $Rk_{t-1}$ 中消费的**边际消费倾向** *等于* 从人力财富 $\mathbb{E}_t\sum R^{-j}d_{t+j}$ 中消费的边际消费倾向。 + +这个等倾向性质是 LQ 模型的标志,并且在存在稳健性考量时*仍然存在*,这与通常具有凸边际效用的预防性储蓄模型形成对比。 + +{prf:ref}`thm-lqcs-oe1` 表明,当 $\sigma < 0$ 时,观测等价的 $\hat\beta$ 满足 $\hat\beta < \beta$。 + +如果起点是 $\beta R = 1$,那么 $\hat\beta R < 1$。 + +对于在相同利率下具有贴现因子 $\hat\beta$ 的非稳健消费者,欧拉方程意味着 $\mathbb{E}_t c_{t+1} < c_t$:预期消费随时间下降。 + +这种向下漂移是 {prf:ref}`thm-lqcs-oe1` 中的不耐心抵消。 + +它抵消了稳健消费者的预防性储蓄动机,使得消费和投资数量保持不变。 + +向上漂移的比较出现在 {prf:ref}`thm-lqcs-oe2` 中,该定理提出了相反的观测等价性问题。 + +经典预防性动机之所以产生,是因为: + +$$ +u'''(c) > 0 \;\Rightarrow\; \mathbb{E}_t u'(c_{t+1}) > u'(\mathbb{E}_t c_{t+1}) \;\Rightarrow\; \mathbb{E}_t c_{t+1} > c_t +$$ + +这个渠道需要*边际效用的凸性*,在二次偏好下不存在。 + +相比之下,基于稳健性的预防性动机通过冲击**条件均值**的扭曲运作,移动了对非金融收入创新的一阶矩。 + +### 观测等价性与扭曲预期 + +```{index} single: Distorted Expectations; Stackelberg multiplier game +``` + +观测等价性结果可以用**斯塔克尔伯格乘数博弈**来解释。 + +在最小化代理承诺了一个扭曲过程 $\{w_{t+1}\}$ 之后,最大化消费者面对以下状态 $X_t$ 的最坏情况运动法则: + +$$ +\begin{aligned} +X_{t+1} &= \bigl(A - BF(\sigma,\hat\beta) + CK(\sigma,\hat\beta)\bigr) X_t + C\tilde\epsilon_{t+1} \\ +\begin{pmatrix}b_t\\d_t\end{pmatrix} &= S X_t +\end{aligned} +$$ (eq:sys2) + +一个担心近似模型对非金融收入随机过程可能设定误差的稳健消费者,使用**扭曲转移矩阵** $A - BF + CK$ 而不是近似转移矩阵 $A - BF$ 来形成对未来收入的预期。 + +扭曲预期算子 $\hat{\mathbb{E}}_t$ 满足 + +$$ +\hat{\mathbb{E}}_t X_{t+j} = (A - BF(\sigma,\hat\beta) + CK(\sigma,\hat\beta))^j X_t +$$ + +观测等价性要求修改后的人力财富公式 + +$$ +\hat\Psi_4 \sum_{j=0}^{\infty} R^{-j}\hat{\mathbb{E}}_t d_{t+j} +$$ + +等于其基准对应物 $\Psi_4 \sum_{j=0}^{\infty} R^{-j} \mathbb{E}_t d_{t+j}$。 + +这是通过系数 $\hat\Psi_j$ 通过 $\hat\beta$ 的相互调整以及扭曲预期算子 $\hat{\mathbb{E}}_t$ 通过 $\sigma$ 的相互调整来实现的。 + +$A - BF + CK$ 的最坏情况特征值在模上超过 $A - BF$ 的特征值,因此最坏情况扭曲使收入过程比近似模型下*更具持续性*。 + +这是状态空间形式的预防性动机:最小化代理通过引入低频持续性使未来收入看起来更有风险。 + +### 频域解释 + +```{index} single: Frequency Domain; permanent income model +``` + +LQ 永久收入框架有一个自然的频域解释。 + +消费者的凹效用使他厌恶消费中的**高频**波动,他通过调整储蓄来平滑这些波动。 + +高频波动更容易平滑,因此消费者对收入过程高频特征的设定误差自动稳健。 + +**低频**波动更难平滑,因为它们更具持续性。 + +在 HST 的频域记号中,从冲击 $\epsilon_t$ 到目标 $s_t - b_t$ 的传递函数是 $G(\zeta)$,而 $H_2$ 标准的频率分解为 + +$$ +H_2 = -\frac{1}{2\pi}\int_{-\pi}^{\pi} \operatorname{trace}\!\bigl[G(\sqrt\beta\, e^{i\omega})^\top\,G(\sqrt\beta\, e^{i\omega})\bigr]\, d\omega +$$ + +被积函数 $G^\top G$ 在低频 $\omega \approx 0$ 处*最大*,那里消费者的福利对收入变动性最敏感。 + +认识到这一点,最小化代理将最坏情况扭曲集中在低频处。 + +扭曲过程具有集中在 $\omega = 0$ 附近的谱密度 $W(\zeta)^\top W(\zeta)$。 + +随着 $|\sigma|$ 增大,最坏情况冲击的方差增长。 + +### 检测误差概率 + +```{index} single: Detection Error Probabilities +``` + +一种规范 $\sigma$(或 $\theta$)选择的自然方法是问:**从统计上区分近似模型与最坏情况模型有多困难?** + +对于长度为 $T$ 的样本,可以使用**对数似然比检验**来比较两个假设。 + +**检测误差概率**(DEP)是在不知道哪个模型生成数据时,使用对数似然比统计量做出错误决定的概率。 + +具体来说: + +$$ +\text{DEP}(\sigma) = \frac{1}{2}\bigl[\mathbb{P}\{\text{prefer approx.} \mid \text{worst-case is true}\} + + \mathbb{P}\{\text{prefer worst-case} \mid \text{approx. is true}\}\bigr] +$$ + +当 $\sigma = 0$ 时两个模型相同,DEP $= 0.5$。 + +随着 $|\sigma|$ 增大,模型发散,DEP 趋向于零。 + +完整的 DEP 计算需要一个指定的近似模型、其最坏情况对应物以及似然比实验中使用的样本长度。 + +我们在下文为稳健 Bewley 模型计算这样一个 DEP。 + +```{note} +HST 建议 DEP 高于 0.2 是"合理的",意味着模型在统计上仍然足够难以区分,以至于对稳健性的考量是有正当理由的。 + +对应于 DEP $\geq 0.2$ 的 $\sigma$ 值定义了一组合理的最坏情况模型。 +``` + +### 决策规则的稳健性 + +```{index} single: Robustness; payoff evaluation +``` + +为了评估当数据由扭曲模型生成时稳健决策规则是否比非稳健规则表现更好,定义当决策规则为稳健性参数 $\sigma_2$ 设计而数据由与 $\sigma_1$ 相关联的扭曲模型生成时的**收益**: + +$$ +\pi(\sigma_1;\sigma_2) = -\mathbb{E}_{0,\sigma_1}\sum_{t=0}^{\infty}\beta^t\, x_t^\top H(\sigma_2)^\top H(\sigma_2)\, x_t +$$ (eq:soln3) + +其中状态在决策规则 $F(\sigma_2)$ 和最坏情况冲击 $K(\sigma_1)$ 下演化: + +$$ +x_{t+1} = \bigl(A - BF(\sigma_2) + CK(\sigma_1)\bigr)x_t + C\epsilon_{t+1} +$$ (eq:soln2) + +对于 $\sigma_1 = 0$(近似模型生成数据),非稳健规则($\sigma_2 = 0$)在构造上是最优的。 + +随着 $\sigma_1$ 减小(数据由日益扭曲的模型生成),$\sigma_2 = 0$ 规则的收益比稳健规则的收益衰减得更快。 + +计算收益比较需要求解 $F(\sigma_2)$ 和 $K(\sigma_1)$ 的完整 HST 矩阵问题。 + +### 另一个观测等价性结果 + +```{index} single: Observational Equivalence; Theorem 2 +``` + +````{prf:theorem} 观测等价性,II +:label: thm-lqcs-oe2 + +固定除 $(\sigma,\beta)$ 之外的所有参数,并考虑 $(\hat\sigma, \hat\beta)$ 的一个消费-投资配置,其中 $\hat\beta R = 1$ 且 $\hat\sigma < 0$。 + +那么存在 $\tilde\beta > \hat\beta$,使得 $(\hat\sigma, \hat\beta)$ 配置也求解 $(0, \tilde\beta)$ 问题。 +```` + +{prf:ref}`thm-lqcs-oe1` 表明,从 $\beta R = 1$ 的基准出发,激活稳健性($\sigma < 0$)等价于*减小* $\beta$。 + +{prf:ref}`thm-lqcs-oe2` 走向相反方向:它表明从 $\beta R = 1$ 的起点激活稳健性考量的效果,可以通过*增大* $\beta$ 同时设置 $\sigma = 0$ 来复制。 + +换句话说,当 $\beta R = 1$ 时,稳健性考量的运作方式类似于贴现因子的*增大*,将 $\beta R > 1$ 推高并赋予预期消费轮廓一个*向上的漂移*。 + +````{prf:proof} +当 $\hat\beta R = 1$ 且 $\hat\sigma < 0$ 时,稳健欧拉方程意味着 + +$$ +\hat{\mathbb{E}}_t \mu_{c,t+1} = \mu_{ct} +$$ + +我们寻求 $\tilde\beta > \hat\beta$ 和 $\sigma = 0$,使得相同的配置求解具有贴现因子 $\tilde\beta$ 的非稳健问题。 + +关键步骤是观察到最坏情况扭曲 $K(\hat\sigma, \hat\beta)$ 在边际效用过程中引入了一个漂移,它等价于将贴现因子提高到 $\hat\beta$ 以上所产生的漂移。 + +令这两个漂移相等并求解 $K$ 的标量贝尔曼方程得到 + +$$ +\tilde\beta(\hat\sigma) = \frac{\hat\beta(1+\hat\beta)}{2(1+\hat\sigma\alpha^2)} +\left[1 + \sqrt{1 - 4\hat\beta\,\frac{1+\hat\sigma\alpha^2}{(1+\hat\beta)^2}}\right] +$$ (eq:obsequivn2) + +当 $\hat\sigma < 0$ 时,解满足 $\tilde\beta > \hat\beta$。 +```` + +映射 {eq}`eq:obsequivn2` 是一个封闭形式,因此我们可以直接绘制它。 + +下一个图比较了双因子校准的两个观测等价轨迹,使用 $\alpha^2 = \sigma_1^2 + (1-\beta)^2\sigma_2^2$(在下文 {eq}`eq:bew_alpha2` 中推导)。 + +我们从 $\hat\beta R = 1$ 的基准出发,因此 $\hat\beta = \beta$。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 两个观测等价性实验。轨迹 I(低于 $\beta$)将*非稳健* + 代理固定在 $\beta R=1$,并报告*稳健*孪生代理的 + 贴现因子 $\hat\beta(\sigma)$;轨迹 II(高于 $\beta$)将 + *稳健*代理固定在 $\beta R=1$,并报告*非稳健*孪生代理的 + 贴现因子 $\tilde\beta(\hat\sigma)$。 + name: fig-lqcs-oe-loci +--- +β_bench = β # β R = 1 的基准 +α2 = σ1**2 + (1 - β)**2 * σ2**2 # 双因子 α^2(见 eq:bew_alpha2) + +σ_hat_vals = np.linspace(0.0, -0.16, 60) + +# 轨迹 I(eq:obseq / eq:bew_locus):非稳健代理固定在 βR=1; +# 报告稳健孪生代理的贴现因子 β̂(σ) < β +β_hat = β_bench + σ_hat_vals * α2 * β_bench / (1 - β_bench) + +# 轨迹 II(eq:obsequivn2):稳健代理固定在 βR=1; +# 报告非稳健孪生代理的贴现因子 β̃(σ̂) > β +disc = 1 - 4 * β_bench * (1 + σ_hat_vals * α2) / (1 + β_bench)**2 +β_tilde = (β_bench * (1 + β_bench)) / (2 * (1 + σ_hat_vals * α2)) \ + * (1 + np.sqrt(disc)) + +fig, ax = plt.subplots() +ax.plot(-σ_hat_vals, β_hat, lw=2, color='C3', + label=r'轨迹 I:稳健孪生 $\hat\beta(\sigma)<\beta$' + '\n(非稳健代理固定在 $\\beta R=1$)') +ax.plot(-σ_hat_vals, β_tilde, lw=2, color='C0', + label=r'轨迹 II:非稳健孪生 $\tilde\beta(\hat\sigma)>\beta$' + '\n(稳健代理固定在 $\\beta R=1$)') +ax.axhline(β_bench, color='k', linestyle=':', lw=1, + label=r'基准 $\beta$($\beta R = 1$)') +ax.set_xlabel(r'稳健性考量 $|\sigma|$') +ax.set_ylabel('等价代理的贴现因子') +ax.legend(fontsize=8.5) +plt.show() + +print(f"at σ̂ = {σ_hat_vals[-1]:.3f}: β̃ = {β_tilde[-1]:.4f} > β = {β_bench}") +print(f" β̂ = {β_hat[-1]:.4f} < β = {β_bench}") +``` + +两条轨迹在 $\sigma = 0$ 处都经过基准 $\beta$,并随着稳健性考量的增长而分离。 + +阅读该图的关键在于,两条轨迹固定了*不同的*代理,因此纵轴上绘制的贴现因子在每条曲线上指的是不同的代理。 + +来自 {prf:ref}`thm-lqcs-oe1` 的轨迹 I,将**非稳健**代理固定在基准 $(\sigma = 0, \beta)$($\beta R = 1$),并报告模仿它的**稳健**代理的贴现因子 $\hat\beta(\sigma) < \beta$。 + +这就是 HST 称稳健性考量在观测上等价于*较低*贴现因子的意义所在:因为稳健性已经使代理储蓄更多,所以必须降低其贴现因子才能将配置保持在基准处。 + +因为非稳健基准具有 $\beta R = 1$,它的最优消费是一个鞅,$\mathbb{E}_t c_{t+1} = c_t$。 + +稳健孪生代理选择相同的消费过程,所以它也满足 $\mathbb{E}_t c_{t+1} = c_t$。 + +较低的 $\hat\beta$(具有 $\hat\beta R < 1$)本身会赋予一个向下漂移,但稳健代理的预防性储蓄恰好抵消了它,使预期消费保持平稳。 + +来自 {prf:ref}`thm-lqcs-oe2` 的轨迹 II,则将**稳健**代理固定在 $(\hat\sigma, \beta)$($\beta R = 1$),并报告模仿它的**非稳健**代理的贴现因子 $\tilde\beta(\hat\sigma) > \beta$。 + +这里没有不耐心抵消,所以共同配置继承了稳健代理的预防性*向上*漂移,非稳健孪生代理通过 $\tilde\beta R > 1$ 复制了它。 + +这两个实验编码了*相同的*经济学:稳健性考量增加了预防性储蓄,其作用类似于额外的耐心。 + +它们唯一的区别在于哪个代理被锚定在 $\beta R = 1$,从而在于共同的储蓄动机是表现为恰好抵消的不耐心调整(轨迹 I,预期消费平稳),还是表现为预期消费的向上漂移(轨迹 II)。 + +### 稳健 LQ Bewley 模型 + +```{index} single: Robust Bewley Model +``` + +我们现在通过将 {doc}`lq_bewley_complete_markets` 的 Bewley 经济嵌入 HST 框架并应用观测等价性定理来综合本讲座。 + +我们将构造一族**稳健 Bewley 经济**,以稳健性水平 $\sigma \leq 0$ 为参数,其均衡数量与普通 Bewley 模型的相同。 + +我们首先将 Bewley 经济映射到 HST 记号中,将稳健模型专门化为 $\lambda = \delta_h = 0$(无习惯,无耐久品)以及一个纯禀赋经济(无物质资本,$k_t = 0$)。 + +在这种情况下: + +服务等于消费:$s_t = c_t$。 + +唯一交易的证券是单期无风险债券,我们将家庭的净资产头寸写作 $a_t=-b_t$,因此正的 $a_t$ 表示财富而非债务。 + +禀赋过程遵循状态空间表示 {eq}`eq:rs-endowment`。 + +家庭的增广状态向量是 $x_t = [a_t,\; z_t^\top]^\top$,运动法则 {eq}`eq:law0` 专门化为 + +$$ +\begin{pmatrix} a_{t+1} \\ z_{t+1} \end{pmatrix} += +\underbrace{\begin{pmatrix} R & R\check{G} \\ 0 & \check{A} \end{pmatrix}}_{A} +\begin{pmatrix} a_t \\ z_t \end{pmatrix} ++ +\underbrace{\begin{pmatrix} -R \\ 0 \end{pmatrix}}_{B} +c_t ++ +\underbrace{\begin{pmatrix} 0 \\ \check{C} \end{pmatrix}}_{C} +\epsilon_{t+1} +$$ (eq:bew_law) + +目标函数是 $\mathbb{E}_0 \sum_{t=0}^\infty \beta^t [-(c_t - \gamma)^2/2]$,这是 HST 标准 {eq}`eq:income5`,其中 $\sigma = 0$ 且 $b_t \equiv \gamma$(一个固定的极乐水平)。 + +因此,$\sigma = 0$ 的稳健贝尔曼方程 {eq}`eq:income1` 恰好简化为 {doc}`lq_permanent_income` 的 LQ 问题,证实了 HST 框架嵌套了 Bewley 模型。 + +我们接下来计算稳健性参数 $\alpha^2$。 + +从 $(c_t,z_t)$ 表示 {eq}`eq:rs-crep`,消费创新为 + +$$ +c_{t+1} - c_t = h\, w_{t+1}, \qquad +h = (1-\beta)\,\check{G}(I-\beta\check{A})^{-1}\check{C} +$$ (eq:bew_cinno) + +向量 $h$ 在 HST 标量 $\alpha$ 公式 {eq}`eq:hsoffset2` 中扮演 $\nu^\top = M_s C$ 的角色。 + +因此, + +$$ +\alpha^2 = h h^\top = (1-\beta)^2\, +\check{G}(I-\beta\check{A})^{-1}\check{C}\check{C}^\top(I-\beta\check{A}^\top)^{-1}\check{G}^\top +$$ (eq:bew_alpha) + +对于双因子模型 {eq}`eq:pi-twofactor`,其中 $\check{A} = \mathrm{diag}(1,0)$ 且 $\check{C} = \mathrm{diag}(\sigma_1,\sigma_2)$,这简化为 + +$$ +\alpha^2 = \sigma_1^2 + (1-\beta)^2\,\sigma_2^2 +$$ (eq:bew_alpha2) + +永久冲击方差 $\sigma_1^2$ 以系数 1 进入,因为一个单位的永久冲击被*完全*资本化到消费中。 + +暂时冲击方差 $\sigma_2^2$ 以小系数 $(1-\beta)^2$ 进入,因为只有其年金价值被消费。 + +将 {prf:ref}`thm-lqcs-oe1` {eq}`eq:obseq` 应用于均衡利率 $R = \beta_0^{-1}$ 以及来自 {eq}`eq:bew_alpha2` 的 $\alpha^2$,得到 **Bewley 观测等价轨迹**: + +$$ +\hat\beta(\sigma) = \beta_0 + \frac{\sigma\,\alpha^2\,\beta_0}{1-\beta_0} +$$ (eq:bew_locus) + +对于 $\sigma < 0$,我们有 $\hat\beta(\sigma) < \beta_0$。 + +一个在此轨迹上具有对 $(\sigma, \hat\beta(\sigma))$ 的代理更担心模型设定误差(更低的 $\sigma$),但也更不耐心(更低的 $\hat\beta$);这两种力量恰好抵消,使得消费决策规则保持不变。 + +这些要素结合成一个稳健 Bewley 均衡。 + +````{prf:proposition} +:label: prop-lqcs-bewley + +假设 Bewley 经济中的所有代理共享一个位于轨迹 {eq}`eq:bew_locus` 上的公共对 $(\sigma, \hat\beta(\sigma))$,其中 $R = \beta_0^{-1}$。 + +那么每个代理的最优消费计划与普通 $(\sigma = 0,\, \beta_0)$ 经济的相同,且均衡利率保持 $R = \beta_0^{-1}$。 +```` + +````{prf:proof} +由 {prf:ref}`thm-lqcs-oe1`,每个代理的消费-储蓄规则与基准相同。 + +因此商品市场出清条件 $\int c_t^i\, di = Y$ 在 $R = \beta_0^{-1}$ 处得到满足,原因与基准 Bewley 经济中相同。 +```` + +#### 异质 $(\beta_i, \sigma_i)$ 偏好 + +一个更丰富的扩展在经济中填充了**连续统类型**,每个类型由一个稳健性参数 $\sigma_i \in [\underline\sigma, 0]$ 索引,贴现因子为 + +$$ +\beta_i = \hat\beta(\sigma_i) = \beta_0 + \frac{\sigma_i\,\alpha^2\,\beta_0}{1-\beta_0} +$$ (eq:bew_heterog) + +由于所有对 $(\sigma_i, \beta_i)$ 都位于 {eq}`eq:bew_locus` 上,每个代理采用与基准**相同的消费规则**。 + +总量动态保持不变,因为消费的横截面均值等于 $Y$,横截面方差每期以 $\alpha^2$ 的速率增长。 + +均衡利率保持不变:$R = \beta_0^{-1}$。 + +代理对外部计量经济学家而言在观测上无法区分,因为关于 $(c_t^i, a_t^i)$ 的数据无法揭示代理 $i$ 是具有 $\sigma_i = 0$ 还是 $\sigma_i < 0$。 + +代理在其内部模型上有所不同,因为具有 $\sigma_i < 0$ 的代理对其条件预期应用最坏情况扭曲 $w_{t+1}^i = K(\sigma_i, \beta_i)\,\mu_{s,t}^i$,而具有 $\sigma_i = 0$ 的代理则按面值接受近似模型。 + +这为一个具有**异质模糊厌恶**的 Bewley 模型奠定了基础:尽管每个代理在可观测选择方面表现相同,他们却持有不同的收入过程主观模型,并对模型不确定性有不同的态度。 + +#### 计算 + +```{code-cell} ipython3 +# Bewley 参数 +β0_bew = β # 0.95 +σ1_bew = σ1 # 0.15 +σ2_bew = σ2 # 0.30 +R_bew = 1.0 / β0_bew + +# 双因子 Bewley α^2 +α2_bew = σ1_bew**2 + (1 - β0_bew)**2 * σ2_bew**2 + +print(f"α^2 (Bewley, two-factor) = {α2_bew:.6f}") +print(f" permanent component σ1^2 = {σ1_bew**2:.6f} " + f"({100*σ1_bew**2/α2_bew:.1f} % of α^2)") +print(f" transitory component (1-β)^2σ2^2= {(1-β0_bew)**2*σ2_bew**2:.6f} " + f"({100*(1-β0_bew)**2*σ2_bew**2/α2_bew:.1f} % of α^2)") +``` + +这个计算展示了为什么在此校准中永久冲击主导 $\alpha^2$。 + +我们现在求解附加于此 $\alpha^2$ 的标量稳健预测问题。 + +该解选择满足观测等价欧拉方程的贝尔曼方程根。 + +```{code-cell} ipython3 +def robust_scalar_solution(σ, β0, α2): + """ + 在观测等价轨迹上求解标量稳健边际效用问题。 + """ + α = np.sqrt(α2) + R = 1.0 / β0 + + if np.isclose(σ, 0.0): + return β0, np.nan, 1.0, 0.0 + + β_hat = β0 + σ * α2 * β0 / (1 - β0) + disc = (β_hat - 1 + σ * α2)**2 + 4 * σ * α2 + root_disc = np.sqrt(max(disc, 0.0)) + target_ζ = 1 / (β_hat * R) + + candidates = [] + for sign in (1.0, -1.0): + P = (β_hat - 1 + σ * α2 + sign * root_disc) / (-2 * σ * α2) + ζ = 1 / (1 - σ * α2 * P) + K = (ζ - 1) / α + candidates.append((abs(ζ - target_ζ), P, ζ, K)) + + _, P, ζ, K = min(candidates, key=lambda x: x[0]) + return β_hat, P, ζ, K + + +def log_likelihood_ratio(paths, ζ, α): + """ + 返回 log p_worst(path) - log p_approx(path)。 + """ + lag = paths[:, :-1] + lead = paths[:, 1:] + ll_worst = -0.5 * np.sum(((lead - ζ * lag) / α)**2, axis=1) + ll_approx = -0.5 * np.sum(((lead - lag) / α)**2, axis=1) + return ll_worst - ll_approx + + +def simulate_scalar_paths(ζ, α, T, n_paths, seed): + rng = np.random.default_rng(seed) + paths = np.zeros((n_paths, T + 1)) + shocks = rng.standard_normal((n_paths, T)) + + for t in range(T): + paths[:, t + 1] = ζ * paths[:, t] + α * shocks[:, t] + + return paths + + +def detection_error_probability(ζ, α, T=40, n_paths=10_000, seed=1234): + """ + 近似律和最坏情况标量律的有限样本 DEP。 + """ + if np.isclose(ζ, 1.0): + return 0.5 + + approx_paths = simulate_scalar_paths(1.0, α, T, n_paths, seed) + worst_paths = simulate_scalar_paths(ζ, α, T, n_paths, seed + 1) + + llr_approx = log_likelihood_ratio(approx_paths, ζ, α) + llr_worst = log_likelihood_ratio(worst_paths, ζ, α) + + return 0.5 * (np.mean(llr_worst < 0) + np.mean(llr_approx > 0)) +``` + +下一个图报告了由这个已求解的标量问题所隐含的最坏情况动态和模型检测概率。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 已求解的稳健标量模型 + name: fig-lqcs-robust-scalar +--- +α_bew = np.sqrt(α2_bew) +β_min = 0.88 +σ_min = (β_min - β0_bew) * (1 - β0_bew) / (α2_bew * β0_bew) +σ_vals = np.linspace(0.0, σ_min, 31) + +solutions = np.array([robust_scalar_solution(σ, β0_bew, α2_bew) for σ in σ_vals]) +β_hat_vals = solutions[:, 0] +ζ_vals = solutions[:, 2] +K_vals = solutions[:, 3] +dep_vals = np.array([ + detection_error_probability(ζ, α_bew) + for ζ in ζ_vals +]) + +fig, axes = plt.subplots(1, 2, figsize=(11.2, 4.1)) + +horizons = np.arange(31) +for σ in [0.0, σ_vals[10], σ_vals[20]]: + β_hat, P, ζ, K = robust_scalar_solution(σ, β0_bew, α2_bew) + label = rf'$\sigma={σ:.3f}$, $\zeta={ζ:.3f}$' + axes[0].plot(horizons, ζ**horizons, lw=2, label=label) + +axes[0].set_xlabel('视界') +axes[0].set_ylabel(r'$\mu_{s,t+h}$ 的响应') +axes[0].set_title('最坏情况脉冲响应') +axes[0].legend(fontsize=8.5) + +axes[1].plot(-σ_vals, dep_vals, lw=2, color='C0') +axes[1].axhline(0.2, color='C3', linestyle='--', lw=1.2, + label='DEP = 0.2') +axes[1].set_xlabel(r'稳健性考量 $-\sigma$') +axes[1].set_ylabel('检测误差概率') +axes[1].set_ylim(0.0, 0.52) +axes[1].set_title('有限样本可检测性') +axes[1].legend(fontsize=8.5) + +fig.tight_layout() +plt.show() +``` + +左图显示,随着 $\sigma$ 变得更负,已求解的最坏情况律使边际效用更具持续性。 + +右图从近似标量律 $\mu_{t+1}=\mu_t+\alpha\epsilon_{t+1}$ 与已求解的最坏情况律 $\mu_{t+1}=\zeta(\sigma)\mu_t+\alpha\epsilon_{t+1}$ 之间的精确似然比计算 DEP。 + +### 结束语 + +我们以对全部三讲关键信息的总结来结束。 + +LQ 永久收入模型,弗里德曼永久收入假说的理性预期版本,有两个互补的状态空间表示: + +1. **$(b_t, z_t)$ 表示**:强调消费者的最优借贷是历史依赖的,并与消费协整。 + +2. **$(c_t, z_t)$ 表示**:强调消费是一个鞅(随机游走),并且资产 $b_t$ 编码在消费中,因此消费的脉冲响应函数是"箱形的":水平的永久移动。 + +我们将这个单代理模型嵌入到一个具有连续统事后异质消费者的 Bewley 均衡中。 + +均衡总利率 $R = \beta^{-1}$ 由恒定的平均消费支撑,尽管消费的横截面方差随年龄线性增长。 + +同一模型的完全市场版本实现了完全风险分担和一个时不变的消费分布,代价是更复杂的金融安排(阿罗证券)。 + +对模型设定误差的考量,以 $\sigma = -\theta^{-1} \leq 0$ 为参数,改变了永久收入模型。 + +对稳健性的考量即使在二次偏好下也通过扭曲收入冲击的条件均值产生一个预防性储蓄动机。 + +扭曲的最坏情况模型使收入过程**更具持续性**,将功率移向低频,那里永久收入消费者最脆弱。 + +观测等价性定理 {prf:ref}`thm-lqcs-oe1` 表明,仅就数量 $(c_t, i_t)$ 而言,稳健性考量与 $\beta$ 的减小无法区分。 + +反向定理 {prf:ref}`thm-lqcs-oe2` 表明,从 $\beta R = 1$ 出发,稳健性在观测上等价于 $\beta$ 的*增大*,这赋予预期消费一个向上的漂移。 + +检测误差概率提供了一种校准 $\sigma$ 的原则性方法:选择足够小的 $|\sigma|$,使得近似模型和最坏情况模型在统计上仍然难以区分。 + +观测等价的 $(\sigma, \hat\beta)$ 对**确实**对资产价格有不同的含义,HST 在资产定价背景下进一步探讨了这一点。 + +稳健 Bewley 经济展示了代理如何能够拥有相同的消费决策规则并支撑相同的均衡利率 $R = \beta_0^{-1}$,同时在其最坏情况主观收入动态上有所不同。 + +## 练习 + +```{exercise-start} +:label: lqcs_ex1 +``` + +我们从基准 Bewley 经济转换到 HST 记号。 + +将稳健控制设置专门化为无习惯、无资本的 LQ Bewley 环境($\lambda = \delta_h = 0$,$k_t = 0$),并令禀赋过程为 {eq}`eq:pi-twofactor` 中的双因子模型。 + +1. 将家庭状态写作 $x_t = [a_t, z_t^\top]^\top$,其中 $a_t=-b_t$ 是净资产,并推导运动法则 {eq}`eq:law0` 的矩阵 $(A, B, C)$。 + +2. 证明当 $\sigma = 0$ 时,贝尔曼问题与 LQ 永久收入问题重合。 + +3. 推导 $\alpha^2$ 并验证 + +$$ +\alpha^2 = \sigma_1^2 + (1-\beta)^2\sigma_2^2. +$$ + +从经济学上解释为什么永久成分和暂时成分以不同的权重进入。 + +```{exercise-end} +``` + +```{solution-start} lqcs_ex1 +:class: dropdown +``` + +这是一个解答: + +1. 有 $x_t = [a_t, z_t^\top]^\top$ 以及预算法则 $a_{t+1} = R(a_t + y_t - c_t)$,$y_t = \check G z_t$,$z_{t+1} = \check A z_t + \check C \epsilon_{t+1}$,堆叠的法则是 + +$$ +\begin{pmatrix} a_{t+1} \\ z_{t+1} \end{pmatrix} += +\underbrace{\begin{pmatrix} R & R\check G \\ 0 & \check A \end{pmatrix}}_{A} +\begin{pmatrix} a_t \\ z_t \end{pmatrix} ++ +\underbrace{\begin{pmatrix} -R \\ 0 \end{pmatrix}}_{B} c_t ++ +\underbrace{\begin{pmatrix} 0 \\ \check C \end{pmatrix}}_{C}\epsilon_{t+1}. +$$ + + $B$ 的符号为负,因为更高的 $c_t$ 减少资产积累 $a_{t+1}$。 + +2. 在 $\sigma=0$ 处,稳健贝尔曼问题坍缩为没有最小化扭曲项的普通 LQ 目标,因此计划者/消费者问题恰好是具有二次效用和线性约束的永久收入问题。 + +3. 从 $(c_t,z_t)$ 表示, + +$$ +\Delta c_{t+1} = h\,\epsilon_{t+1}, +\qquad h = (1-\beta)\check G (I-\beta\check A)^{-1}\check C. +$$ + + 在 HST 记号中,$\alpha^2 = h h^\top$,且对于双因子校准 $\check A=\mathrm{diag}(1,0)$ 且 $\check C=\mathrm{diag}(\sigma_1,\sigma_2)$,所以 + +$$ +\alpha^2 = \sigma_1^2 + (1-\beta)^2\sigma_2^2. +$$ + + 永久冲击获得单位权重,因为它们一对一地移动终身资源,而暂时冲击被年金化,因此在消费增长中按 $(1-\beta)$ 缩放。 + +```{solution-end} +``` + +```{exercise-start} +:label: lqcs_ex2 +``` + +这个练习研究一个由稳健但观测等价的 Bewley 消费者组成的连续统。 + +固定一个基准对 $(\beta_0, \sigma = 0)$,其中 $R = \beta_0^{-1}$,并定义 + +$$ +\beta(\sigma) = \beta_0 + \frac{\sigma\alpha^2\beta_0}{1-\beta_0}, +\qquad \sigma \in [-\bar\sigma, 0]. +$$ + +假设一个单位区间的消费者由 $i$ 索引,类型为 $\sigma_i \in [-\bar\sigma, 0]$,贴现因子为 $\beta_i = \beta(\sigma_i)$。 + +1. 使用 {prf:ref}`thm-lqcs-oe1` 证明每种类型都具有与基准 $(\beta_0, 0)$ 代理相同的消费规则。 + +2. 证明总消费和债券市场出清意味着与普通 Bewley 模型相同的均衡利率 $R = \beta_0^{-1}$。 + +3. 解释为什么代理可以在数量上观测等价,同时仍然持有不同的最坏情况主观模型。 + +```{exercise-end} +``` + +```{solution-start} lqcs_ex2 +:class: dropdown +``` + +这是一个解答: + +1. {prf:ref}`thm-lqcs-oe1` 意味着如果 $(\sigma_i, \beta_i)$ 位于 + +$$ +\beta_i = \beta_0 + \frac{\sigma_i\alpha^2\beta_0}{1-\beta_0}, +$$ + + 那么类型 $i$ 选择与基准 $(0,\beta_0)$ 代理相同的决策规则,并且所有类型共享相同的消费政策函数 $c_t = \mathcal C(a_t,z_t)$。 + +2. 由于所有个体政策规则都与基准 Bewley 政策重合,对消费者聚合得到相同的商品和债券市场出清条件,并支撑相同的均衡 $R=\beta_0^{-1}$。 + +3. 观测等价性涉及由最优规则生成的数量,因此不同的 $(\sigma_i,\beta_i)$ 可以生成相同的 $\{c_t^i,a_t^i\}$,同时隐含不同的内部最坏情况信念。 + +```{solution-end} +``` + +```{exercise-start} +:label: lqcs_ex3 +``` + +这个练习在不引入额外校准的情况下将数量与信念分开。 + +考虑稳健 Bewley 经济中的两个代理 $a$ 和 $b$,其中 $\sigma^a < \sigma^b \leq 0$ 且对于 $j \in \{a,b\}$,$\beta^j = \beta_0 + \sigma^j\alpha^2\beta_0/(1-\beta_0)$。 + +1. 使用 {eq}`eq:bew_cinno` 和 {eq}`eq:bew_locus` 证明这两个代理具有相同的消费创新 $h\epsilon_{t+1}$。 + +2. 证明如果这两个代理从相同的 $(a_t,z_t)$ 出发并观测到相同的冲击 $\epsilon_{t+1}$,那么他们的下一期消费和资产选择重合。 + +3. 解释为什么这两个代理仍然可以在 $\epsilon_{t+1}$ 的最坏情况条件均值上意见不一致。 + +总结仅凭数量数据能够识别和不能识别什么。 + +```{exercise-end} +``` + +```{solution-start} lqcs_ex3 +:class: dropdown +``` + +这是一个解答: + +1. 方程 {eq}`eq:bew_locus` 将两个代理都置于观测等价轨迹上,因此 {prf:ref}`thm-lqcs-oe1` 意味着两者都使用基准消费规则,因此在 {eq}`eq:bew_cinno` 中使用相同的创新向量 $h$。 + +2. 有一个共同的状态和共同的冲击,两个代理应用相同的政策函数和相同的运动法则,因此 $c_{t+1}^a=c_{t+1}^b$ 且 $a_{t+1}^a=a_{t+1}^b$。 + +3. 最小化反馈 $K(\sigma^j,\beta^j)$ 可以在不同的 $j$ 之间有所不同,因此即使代理的可观测选择重合,他们也可以对相同的冲击过程赋予不同的最坏情况条件均值。 + +结论:数量识别均衡决策规则,但不识别沿观测等价轨迹的不耐心($\beta$)与稳健性($\sigma$)之间的分解。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/ls_learning.md b/lectures/ls_learning.md new file mode 100644 index 0000000..c1ee6dd --- /dev/null +++ b/lectures/ls_learning.md @@ -0,0 +1,1544 @@ +--- +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 +translation: + title: 自指模型中的最小二乘学习 + headings: + Overview: 概述 + The self-referential structure: 自指结构 + The self-referential structure::Perceived and actual laws of motion: 感知运动规律与实际运动规律 + The self-referential structure::The learning scheme: 学习机制 + The self-referential structure::Lagged and contemporaneous data: 滞后数据与同期数据 + Why a differential equation governs the limit: 为什么一个微分方程支配极限 + The governing ODE: 支配性 ODE + The governing ODE::Small and full ODEs: 小型 ODE 与完整 ODE + The governing ODE::Regularity assumptions: 正则性假设 + The governing ODE::Convergence of least squares: 最小二乘的收敛性 + The governing ODE::Stability governs convergence: 稳定性支配收敛 + The governing ODE::The projection facility: 投影机制 + The governing ODE::The projection facility::What the projection facility does: 投影机制做什么 + The governing ODE::The projection facility::The exogenous-regressor case: 外生回归变量的情形 + Five examples: 五个例子 + 'Example 1: Ordinary linear stochastic difference equations': 例 1:普通线性随机差分方程 + 'Example 2: Bray''s cobweb model': 例 2:Bray 的蛛网模型 + 'Counterexample: Unstable Bray feedback': 反例:不稳定的 Bray 反馈 + 'Example 3: Bray-Savin supply-shifter model': 例 3:Bray-Savin 供给移动因子模型 + 'Example 4: Hyperinflation / asset prices': 例 4:恶性通货膨胀/资产价格 + 'Example 5: Investment under uncertainty': 例 5:不确定性下的投资 + Connection to rational learning: 与理性学习的联系 + Summary: 总结 + Exercises: 练习 +--- + +(ls_learning)= +```{raw} jupyter + +``` + +# 自指模型中的最小二乘学习 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲座是 {doc}`rational_learning_re` 的配套内容,后者介绍了理性学习的 Bray-Kreps 视角。 + +我们研究一个相关但不同的问题:在自指模型中,*最小二乘* 学习是否收敛到理性预期均衡。 + +我们介绍 {cite:t}`MarcetSargent1989jet` 的框架,用于研究一类 **自指** 线性随机模型中的 **最小二乘学习**。 + +自指模型是指经济的 *实际* 运动规律取决于其中主体的 *感知* 运动规律的模型。 + +在理性预期均衡(REE)中,两者重合:感知运动规律与实际运动规律相同。 + +但如果主体从远离均衡的地方出发,通过运行最小二乘回归来更新他们的信念,他们会收敛到 REE 吗? + +{cite:t}`MarcetSargent1989jet` 利用系统控制工程中一项强大的技术来回答这个问题:{cite:t}`Ljung1977` 的微分方程方法。 + +关键洞察是,信念演化的随机差分方程在极限情况下可以由一个确定性的常微分方程(ODE)来近似。 + +几乎必然收敛可以通过该 ODE 的稳定性来研究。 + +小型 ODE 的局部稳定性与局部收敛密切相关,而全局几乎必然收敛还需要有界性和吸引域条件。 + +该框架统一并扩展了 {cite:t}`Bray1982` 和 {cite:t}`BraySavin1986` 的早期工作,并自然地与 {cite:t}`BrayKreps1987` 中讨论的两类学习之间的区别相联系:*在* 理性预期均衡 *内* 学习(在正确设定的模型内进行贝叶斯更新)与 *关于* 理性预期均衡的学习(调整一个数据生成过程随信念变化的 OLS 估计器)。 + + + +让我们从整个讲座将使用的导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from numpy import linalg as la +from scipy.integrate import solve_ivp +from scipy.optimize import fsolve +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +在进行任何模拟之前,我们先描述被学习的对象。 + +## 自指结构 + +### 感知运动规律与实际运动规律 + +在每个日期 $t$,主体持有一个由参数矩阵 $\beta_t$ 概括的 **感知运动规律**。 + +他们相信,他们所关心的变量 $z_{1t}$ 按照如下方式演化 + +$$ +z_{1t} = \beta_t z_{2,t-1} + \eta_t , +$$ (eq:perceived_lom) + +其中 $z_{2t}$ 是主体用于预测 $z_{1,t+1}$ 的变量向量,而 $\eta_t$ 与所有过去的 $z_2$ 正交。 + +因为主体基于这一信念进行优化(或行动),他们的行动会反馈到经济中。 + +为了写出完整状态向量 $z_t = (z_{1t}, z_{1t}^c)^\top$ 的实际运动规律,将 $A(\beta_t)$ 与 $(z_{2,t-1}^c, z_{2,t-1})$ 一致地分块为 $A(\beta_t) = [A_c(\beta_t)\; A_2(\beta_t)]$。 + +$$ +z_t = \begin{bmatrix} + 0 & T(\beta_t) \\ + A_c(\beta_t) & A_2(\beta_t) + \end{bmatrix} + \begin{bmatrix} z_{2,t-1}^c \\ z_{2,t-1} \end{bmatrix} + + \begin{bmatrix} V(\beta_t) \\ B(\beta_t) \end{bmatrix} u_t , +$$ (eq:actual_lom) + +其中 $u_t$ 是协方差为 $\Sigma$ 的 IID 白噪声。 + +映射 $T$ 是关键对象,因为它将 *感知* 系数 $\beta$ 映射到均衡中 *实际* 支配 $z_{1t}$ 的系数。 + +**理性预期均衡** 是一个不动点 $\beta_f = T(\beta_f)$。 + +### 学习机制 + +主体每期使用 **递归最小二乘**(RLS)来更新 $\beta_t$。 + +将 $R_t$ 定义为二阶矩矩阵 $E z_{2t}z_{2t}^\top$ 的动态估计。 + +更新方程为 + +$$ +\beta_t^\top += +\beta_{t-1}^\top ++ \frac{\alpha_t}{t} R_{t-1}^{-1} +\left\{ +z_{2,t-2} z_{2,t-2}^\top +\bigl[ T(\beta_{t-1}) - \beta_{t-1} \bigr]^\top ++ z_{2,t-2} u_{t-1}^\top V(\beta_{t-1})^\top +\right\}, +$$ (eq:rls_beta) + +$$ +R_t = R_{t-1} + \frac{\alpha_t}{t} \bigl[ z_{2,t-1} z_{2,t-1}^\top - R_{t-1}/\alpha_t \bigr] , +$$ (eq:rls_R) + +其中 $\{\alpha_t\}$ 是一个正的、非递减的序列,且当 $t \to \infty$ 时 $\alpha_t \to 1$。 + +当对所有 $t$ 都有 $\alpha_t = 1$ 时,方程 {eq}`eq:rls_beta`-{eq}`eq:rls_R` 简化为递归更新的 **普通最小二乘法**。 + +### 滞后数据与同期数据 + +上述递归是用 *滞后信息* 写出的,因此估计 $\beta_t$ 使用的是直到日期 $t-1$ 为止可用的观测值。 + +{cite:t}`MarcetSargent1989jet` 也处理了一个 *同期数据* 版本,其中主体在日期 $t$ 使用 $z_{1t}$ 和 $z_{2,t-1}$ 进行更新。 + +这种时间安排会产生同时决定性,因为 $z_t$ 取决于正在从 $z_t$ 更新出来的同一个估计 $\beta_t$。 + +一个额外要求是,日期为 $t$ 的系统对每一个历史都必须有唯一解 $(\beta_t, R_t, z_t)$。 + +如果这个唯一性条件成立,并且下面使用的正则性和有界性条件也成立,那么收敛仍然由同一个完整 ODE {eq}`eq:full_ode` 和小型 ODE {eq}`eq:small_ode` 支配。 + +```{note} +正如 {cite:t}`BraySavin1986` 和 {cite:t}`BrayKreps1987` 所强调的,RLS 算法不能从应用于正确设定模型的贝叶斯法则推导出来,因为在学习过渡期间,数据生成过程是非平稳的——信念改变了均衡,而均衡又改变了数据。 + +从它表现得好像环境是平稳的(而实际并非如此)这一意义上说,该算法是 *"非理性的"*。 +``` + +因此,任何对实际运动规律重要的状态变量都必须出现在感知运动规律的回归变量之中。 + +## 为什么一个微分方程支配极限 + +RLS 递归 {eq}`eq:rls_beta`-{eq}`eq:rls_R` 是一个 *随机差分方程*,具有两个关键特征。 + +首先,每次更新前面的 *步长* 是 $\alpha_t / t$,当 $t$ 增长时它收缩到零。 + +其次,{eq}`eq:rls_beta` 右侧括号内的表达式,在回归变量和噪声的长期平均值处,恰好是差异 $T(\beta_{t-1}) - \beta_{t-1}$,它衡量了感知信念与它们实际生成的运动规律之间的距离。 + +将这两个事实结合起来,就出现了一幅清晰的图景。 + +递归每期只对 $\beta_t$ 做微小调整,而这些调整根据大数定律平均后得到确定性漂移 $T(\beta) - \beta$。 + +随着增益 $\alpha_t/t$ 消失,经过时间重标度的轨迹 $\beta_t$ 越来越像连续时间微分方程的解 + +$$ +\frac{d\beta}{dt} = T(\beta) - \beta . +$$ (eq:small_ode) + +为了将 ODE 与经过 $t$ 次观测后的 RLS 进行比较,在 $\tau_t = \sum_{s=1}^t \alpha_s/s$ 处评估 ODE,$\tau_t$ 是学习算法累积的总步长。 + +当 $\alpha_t=1$ 时,这个累积步长为 $\tau_t = \sum_{s=1}^t 1/s \approx \log t$。 + +这一想法归功于 {cite:t}`Ljung1977`,它使得 {cite:t}`MarcetSargent1989jet` 能够将对一个含噪声的自适应学习规则的分析简化为对一个确定性 ODE 的更容易的研究。 + +本节的其余部分将使这一联系变得精确。 + +## 支配性 ODE + +### 小型 ODE 与完整 ODE + +*小型 ODE* {eq}`eq:small_ode` 只保留 $\beta$ 中的漂移,将方差估计器 $R$ 保持在其长期值。 + +它的静止点恰好是模型的理性预期均衡:$\dot\beta = 0$ 当且仅当 $T(\beta) = \beta$。 + +*完整 ODE* 同时追踪 $\beta$ 和 $R$: + +$$ +\frac{d}{dt}\begin{bmatrix} \beta^\top \\ R \end{bmatrix} += \begin{bmatrix} R^{-1} M_{z_2}(\beta)\,[T(\beta) - \beta]^\top \\ M_{z_2}(\beta) - R \end{bmatrix} , +$$ (eq:full_ode) + +其中 $M_{z_2}(\beta) = \mathbb{E}[z_{2t}z_{2t}^\top]$ 是在当主体相信感知规律具有常数参数 $\beta$ 时 $z_{2t}$ 的平稳分布下计算的。 + +{eq}`eq:full_ode` 的不动点是 $(\beta_f, R_f)$,其中 $R_f = M_{z_2}(\beta_f)$——与小型 ODE 相同的 $\beta_f$,配上与之一致的二阶矩矩阵。 + +### 正则性假设 + +{cite:t}`MarcetSargent1989jet` 区分了两组假设,它们的作用相当不同。 + +前五个是关于算子 $T$、冲击 $u_t$ 和增益序列的标准正则性条件;在应用中它们通常容易检验。 + +设 $D_s \subset \mathbb{R}^{n_1 \times n_2}$ 为使得 $T(\beta)$、$A(\beta)$、$B(\beta)$、$V(\beta)$ 有良好定义且 + +$$ +\begin{bmatrix} +0 & T(\beta) \\ +A_c(\beta) & A_2(\beta) +\end{bmatrix} +$$ + +的特征值模小于一的集合,从而由信念 $\beta$ 诱导的状态过程是协方差平稳的。 + +```{prf:assumption} 唯一 REE +:label: ass-ms-a1 + +算子 $T$ 有唯一不动点 $\beta_f = T(\beta_f)$,且 $\beta_f \in D_s$。 +``` + +```{prf:assumption} T、A、B、V 的光滑性 +:label: ass-ms-a2 + +$T$ 是二次可微的,且 $A, B, V$ 在 $D_s$ 上各有一阶导数。 +``` + +```{prf:assumption} 非奇异极限协方差 +:label: ass-ms-a3 + +协方差矩阵 $M_{z_2}(\beta_f)$ 是非奇异的。 +``` + +```{prf:assumption} 增益序列 +:label: ass-ms-a4 + +对所有 $t$,$\alpha_t > 0$;$\alpha_t$ 关于 $t$ 非递减;当 $t \to \infty$ 时 $\alpha_t \to 1$;且 $\limsup_{t \to \infty} t\,|\alpha_t - \alpha_{t-1}| < \infty$。 +``` + +```{prf:assumption} 冲击矩 +:label: ass-ms-a5 + +向量 $u_t$ 序列独立,且对所有 $p > 1$ 和所有 $i = 1, \ldots, m$ 有 $E|u_{it}|^p < \infty$。 +``` + +这五个假设说的是:存在唯一目标,模型在其周围光滑,回归在极限中有良好定义的精度矩阵,增益以正确的速度收缩,且冲击有足够的矩使大数定律起作用。 + +其余两个是 *有界性* 条件。 + +它们是必需的,因为 Ljung 定理要求相关的样本路径无穷多次返回一个有界区域。 + +在这个模型中,这包括回归变量过程 $z_{2t}$ 和协方差估计 $R_t$。 + +```{prf:assumption} 沿子序列的有界性 +:label: ass-ms-a6 + +存在一个集合 $\Omega_0$ 满足 $\mathbb{P}(\Omega_0) = 1$,随机变量 $C_1(\omega)$ 和 $C_2(\omega)$,以及一个子序列 $\{t_k(\omega)\}$,使得 + +$$ +|z_{2t_k}(\omega)| < C_1(\omega) \quad\text{and}\quad |R_{t_k}(\omega)| < C_2(\omega) +$$ + +对所有 $\omega \in \Omega_0$ 和所有 $k = 1, 2, \ldots$ 成立。 +``` + +```{prf:assumption} 样本路径停留在可行域内 +:label: ass-ms-a7 + +紧状态版本或投影集版本之一成立。 + +- *紧状态版本。* + - $D_1 = D_2 = \mathbb{R}^{n_1 \times (n_2)^3}$。 + - 存在一个紧集 $D' \subset D_s$,它对所有 $k$ 和所有 $\omega \in \Omega_0$ 都包含 $\beta_{t_k}(\omega)$。 + - 对于每个初始条件 $(\beta(0), R(0))$,其中 $\beta(0) \in D'$ 且 $R(0)$ 如 {prf:ref}`ass-ms-a6` 中所述有界,{eq}`eq:full_ode` 轨迹的 $\beta$ 分量保持在 $D_s$ 的一个闭子集内。 + +- *投影集版本。* + - $D_2$ 是闭的。 + - $D_1$ 是开且有界的。 + - 对每个 $(\beta, R) \in D_1$ 都有 $\beta \in D_s$。 + - 初始条件在 $D_2$ 中的 {eq}`eq:full_ode` 轨迹从不离开 $D_1$ 的一个闭子集。 +``` + +当回归变量 $z_{2t}$ 是 *外生的* 且遍历时,{prf:ref}`ass-ms-a6` 是自动成立的,但当 $z_{2t}$ 包含内生变量时,它可能会很微妙。 + +当模型有一个自然的有界域使 $T$ 有良好定义时,{prf:ref}`ass-ms-a7` 在紧状态版本中得到满足;否则投影集版本对应于使用下面描述的投影机制。 + +设 $D_A$ 表示 {eq}`eq:full_ode` 的唯一均衡 $(\beta_f, R_f)$ 的吸引域。 + +### 最小二乘的收敛性 + +```{prf:proposition} 最小二乘收敛性 +:label: prop-ms-convergence + +假设 {prf:ref}`ass-ms-a1`、{prf:ref}`ass-ms-a2`、 +{prf:ref}`ass-ms-a3`、{prf:ref}`ass-ms-a4`、{prf:ref}`ass-ms-a5` +以及 {prf:ref}`ass-ms-a6` 成立。 + +如果满足以下之一 + +- {prf:ref}`ass-ms-a7` 的紧状态版本满足且 $D' \subset D_A$,或 +- {prf:ref}`ass-ms-a7` 的投影集版本满足且 $D_1 \subset D_A$, + +那么当 $t \to \infty$ 时 $\beta_t \to \beta_f$ 几乎必然成立。 +``` + +{prf:ref}`prop-ms-convergence` 将递归最小二乘的几乎必然收敛问题简化为检验 ODE {eq}`eq:full_ode` 在 $(\beta_f, R_f)$ 处的 *稳定性* 并保证样本路径的有界性。 + +### 稳定性支配收敛 + +设 $\mathcal{M}$ 为在 REE $\beta_f$ 处评估的 $T(\beta) - \beta$ 的雅可比矩阵: + +$$ +\mathcal{M} = \frac{d\,\operatorname{col}(T(\beta) - \beta)}{d\,\operatorname{col}(\beta)^\top}\Bigg|_{\beta=\beta_f} , +$$ (eq:jacobian) + +并设 $h(\beta, R)$ 表示将 $(\beta^\top, R)$ 堆叠成列向量后完整 ODE {eq}`eq:full_ode` 右侧的雅可比矩阵。 + +```{prf:proposition} 雅可比约化 +:label: prop-ms-jacobian-eigenvalues + +矩阵 $h(\beta_f, R_f)$ 有 $(n_2)^2$ 个等于 $-1$ 的重复特征值;其余 $n_1 \times n_2$ 个特征值与 $\mathcal{M}$ 的特征值重合。 +``` + +因此: + +* 如果 $\mathcal{M}$ 的所有特征值都有 *严格负实部*,那么 {eq}`eq:small_ode` 和 {eq}`eq:full_ode` 都是局部稳定的。 + +* 在 {prf:ref}`prop-ms-convergence` 的有界性和吸引域条件下,可以利用这种局部稳定性来获得 $\beta_t$ 几乎必然收敛到 $\beta_f$。 + +* 如果 $\mathcal{M}$ 的任何特征值有 *正实部*,那么下一个命题表明收敛是不可能的。 + +```{prf:proposition} 必要性 +:label: prop-ms-necessity + +假设 {prf:ref}`ass-ms-a1`、{prf:ref}`ass-ms-a2`、 +{prf:ref}`ass-ms-a3`、{prf:ref}`ass-ms-a4` 和 {prf:ref}`ass-ms-a5` 成立。 + +1. 设 $\hat\beta \neq \beta_f$ 并假设 $M_{z_2}(\hat\beta)$ 是正定的且 $\hat\beta \in \mathrm{int}(D_2)$。 + + 那么 $\mathbb{P}(\beta_t \to \hat\beta) = 0$。 + +2. 如果 $h(\beta_f, R_f)$ 至少有一个特征值具有严格正实部,那么 $\mathbb{P}(\beta_t \to \beta_f) = 0$。 +``` + +第一部分说的是,递归最小二乘不能在可行域内部落到一个非均衡信念上。 + +如果学习有极限,那么该极限必须是 $T$ 的不动点。 + +第二部分说的是,局部不稳定性不仅仅是收敛慢的问题。 + +如果 REE 对于学习 ODE 是不稳定的,那么收敛到该 REE 的概率为零。 + +稳定性条件对所有 $i$ 都有 $\mathrm{Re}(\lambda_i(\mathcal{M})) < 0$,这被称为 **E-稳定性**(参见 {cite:t}`Evans1985`):REE 是期望动态 $\dot\beta = T(\beta) - \beta$ 的稳定静止点。 + +E-稳定性在这里所起的作用类似于贝叶斯学习中先验支持所起的作用:它告诉我们学习过程何时能够找到通往均衡的道路。 + +### 投影机制 + +E-稳定性是使 REE 对学习 ODE 有吸引力的局部条件。 + +单独来看,它并不是一个几乎必然收敛定理。 + +随机递归还必须停留在 ODE 近似有效的有界区域内。 + +反过来,一个严格正的特征值排除了收敛到 REE 的可能性,而实部为零的边界情形不在该定理的覆盖范围之内。 + +Ljung 定理要求学习过程和相关回归变量以概率一返回有界区域。 + +**投影机制** 是一个强制估计系数和协方差矩阵有界的程序。 + +#### 投影机制做什么 + +完整的学习算法用 $(\beta, R)$ 空间中的一个约束集 $D_1 \supset D_2$ 来增强普通的 RLS 更新。 + +在每一步无约束的 RLS 步骤产生候选 $(\tilde\beta_t, \tilde R_t)$ 之后,投影机制强制执行: + +$$ +(\beta_t, R_t) = \begin{cases} + (\tilde\beta_t,\, \tilde R_t) & \text{if } (\tilde\beta_t, \tilde R_t) \in D_1 , \\ + \text{some point in } D_2 & \text{otherwise.} +\end{cases} +$$ (eq:projection) + +选择集合 $D_1$ 使模型保持良好定义(例如,$R_t$ 保持正定;$\beta_t$ 停留在一个使 $T(\beta)$ 有良好定义且状态过程协方差平稳的区域内)。 + +集合 $D_2 \subset D_1$ 是一个稍小的"安全"区域,每当算法有离开 $D_1$ 的危险时,就将其收缩到该区域。 + +没有投影机制,随机路径 $(\beta_t, R_t)$ 可能会暂时游荡到系统 {eq}`eq:actual_lom` 非平稳的区域(例如,一个爆炸性的 VAR)。 + +投影机制使 $(\beta_t, R_t)$ 保持在一个选定的可行区域内。 + +当回归变量包含内生变量时,单独的有界性条件 {prf:ref}`ass-ms-a6` 仍必须沿一个子序列控制 $z_{2t}$。 + +形式上,{cite:t}`MarcetSargent1989jet` 要求源于 $D_1$ 的完整 ODE {eq}`eq:full_ode` 的轨迹不离开 $D_1$。 + +这通常通过验证在边界 $\partial D_1$ 处完整向量场指向内部来检验。 + +```{prf:corollary} +:label: cor-ms-projection-dichotomy + +假设 {prf:ref}`ass-ms-a1`、{prf:ref}`ass-ms-a2`、 +{prf:ref}`ass-ms-a3`、{prf:ref}`ass-ms-a4`、{prf:ref}`ass-ms-a5` +以及 {prf:ref}`ass-ms-a6` 成立。 + +进一步假设 $(\beta, R) \in D_1$ 蕴含 $\beta \in D_s$,且 $D_1$ 是开且有界的,满足 $D_1 \subset D_A$。 + +那么对某个子序列 $\{t_k(\omega)\}$, + +$$ +\mathbb{P}(\beta_t \to \beta_f) + \mathbb{P}\bigl(\beta_{t_k} \to (D_1 \setminus D_2)\bigr) = 1. +$$ +``` + +每当 ODE 轨迹在 $\partial D_1$ 处指向内部时,第二个事件的概率为零,在这种情况下 {prf:ref}`cor-ms-projection-dichotomy` 简化为 $\beta_t \to \beta_f$ 几乎必然成立。 + +#### 外生回归变量的情形 + +当回归变量 $z_{2t}$ 是 *外生的*,使得 $E(z_{2t}z_{2t}^\top) = M_{z_2}(\beta) \equiv M$ 不依赖于 $\beta$ 时,边界条件的验证就变得常规化。 + +设 $H(\beta)$ 为 $T$ 的中值斜率,即满足 + +$$ +\operatorname{col}\{T(\beta)-T(\beta_f)\} += +H(\beta)\operatorname{col}(\beta-\beta_f). +$$ (eq:corollary2_cond) + +的矩阵。 + +```{prf:corollary} +:label: cor-ms-exogenous + +考虑由 {eq}`eq:rls_beta`-{eq}`eq:rls_R` 以及投影规则 {eq}`eq:projection` 定义的算法。 + +选择 $0 < K' < K < \infty$ 并假设 + +1. {prf:ref}`ass-ms-a1`、{prf:ref}`ass-ms-a2`、{prf:ref}`ass-ms-a3`、 + {prf:ref}`ass-ms-a4` 和 {prf:ref}`ass-ms-a5` 成立; +2. $z_{2t}$ 是外生的,使得 $E(z_{2t}z_{2t}^\top) = M_{z_2}(\beta) \equiv M$; +3. 小型 ODE $\dot\beta = T(\beta) - \beta$ 在 $\mathbb{R}^{n_1 \times n_2}$ 中全局稳定; +4. 存在 $\bar\varepsilon > 0$,使得对所有 + $0 < \varepsilon \leq \bar\varepsilon$ 和所有满足 + $|\beta - \beta_f| = K$ 的 $\beta$, + $[I(1-\varepsilon) + \varepsilon H(\beta)]^\top + [I(1-\varepsilon) + \varepsilon H(\beta)]$ 的每个特征值的模都小于 + $\alpha^2$,其中 $\alpha < 1$。 + +取 +$D_1 = \{(\beta, R) : |\beta - \beta_f| < K\}$ 和 +$D_2 = \{(\beta, R) : |\beta - \beta_f| \leq K'\}$,并让投影规则将 $\beta_t$ 收缩到任何满足 $|\beta - \beta_f| \leq K'$ 的值,同时保持 $R_t = \tilde R_t$。 + +那么 $\beta_t \to \beta_f$ 几乎必然成立。 +``` + +对于下面的标量线性例子,条件(4)简化为检验 $T$ 的反馈斜率不太强。 + +对于下面前四个例子,$T$ 是线性的且 $M_{z_2}$ 不依赖于 $\beta$,所以 {prf:ref}`cor-ms-exogenous` 仅使用 $D_1$ 和 $D_2$ 来证明投影论证,并让这些例子进行标量 ODE 稳定性检验。 + +因此在下面的例子中 $D_1$ 和 $D_2$ 并不是经济学的原始量。 + +它们是投影学习算法的证明工具:$D_1$ 是模型和 ODE 保持良好定义的外部可行区域,而 $D_2$ 是当更新试图离开 $D_1$ 时用来重置估计的较小区域。 + +一旦推论说明可以选择合适的集合,这些例子就不再需要展示它们,而可以专注于 $T$、$\beta_f$ 和局部稳定性斜率。 + +## 五个例子 + +我们现在逐一研究 {cite:t}`MarcetSargent1989jet` 中的五个例子。 + +每个实质性的学习例子都遵循相同的模板。 + +1. 写下决定均衡的经济方程。 +2. 代入任何期望变量的感知运动规律,得到作为 $\beta$ 函数的实际运动规律。 +3. 读出算子 $T$ 和 REE $\beta_f = T(\beta_f)$。 +4. 通过在 $\beta_f$ 处计算 $\mathcal M = dT/d\beta - I$ 来检验 E-稳定性。 +5. 绘制 RLS 路径、在累积增益时间处评估的小型 ODE,以及漂移 $T(\beta)-\beta$。 + +在每种情形中,$\beta_t$ 是主体当前在做决策时使用的运动规律,而 $T(\beta_t)$ 是他们的决策实际产生的运动规律。 + +最小二乘学习追问的是,重复的观测是否会使 $\beta_t$ 朝着这个映射的不动点移动。 + +第一个例子是没有自指反馈的对照情形。 + +对于其余的标量例子,模拟图紧接在模型描述之后出现。 + +## 例 1:普通线性随机差分方程 + +第一个例子没有自指成分。 + +设实际运动规律是固定的,对于一个稳定矩阵 $\Gamma$ 有 $T(\beta)=\Gamma$,且 $V(\beta)=I$。 + +从经济学上讲,这是对照情形。 + +主体正在估计一个稳定的、外生的数据生成过程。 + +他们的信念不会反馈到价格、数量或未来数据中。 + +REE 是 $\beta_f=\Gamma$。 + +由于 $T$ 是常数,在 {eq}`eq:corollary2_cond` 中 $H(\beta)=0$。 + +小型 ODE 的雅可比矩阵是 $\mathcal{M}=-I$,所以小型 ODE 是全局稳定的。 + +于是 {prf:ref}`cor-ms-exogenous` 蕴含递归最小二乘几乎必然收敛到真实的运动规律。 + +在这个无反馈基准中,Marcet-Sargent 结果简化为稳定线性随机差分方程的标准最小二乘一致性。 + +## 例 2:Bray 的蛛网模型 + +{cite:t}`Bray1982` 研究了一个简单的蛛网经济,其中均衡价格满足 + +$$ +p_t = a + b \beta_t + \tilde{u}_t , +$$ (eq:bray_price) + +其中 $\beta_t$ 是主体对价格的 OLS 估计(他们对 $p_t$ 的点预测),而 $\tilde{u}_t$ 是均值为零、方差为 $\sigma_u^2$ 的 IID 噪声。 + +这里预测本身是经济的一个状态变量。 + +如果生产者预期一个高价格,他们当前的供给决策会改变市场出清价格。 + +参数 $b$ 衡量这种期望反馈的强度。 + +当 $b < 1$ 时,实际价格反应弱于预测误差,因此最小二乘有一个将信念推回不动点的力量。 + +当 $b > 1$ 时,反馈太强,同样的学习规则会使信念远离 REE。 + +映射 $T$ 就是 $T(\beta) = a + b\beta$。 + +REE 是 + +$$ +\beta_f = \frac{a}{1 - b} , \quad b \neq 1 . +$$ (eq:bray_ree) + +小型 ODE 是 + +$$ +\dot\beta = T(\beta) - \beta = a + b\beta - \beta = a - (1-b)\beta , +$$ (eq:bray_ode) + +它有唯一不动点 $\beta_f = a/(1-b)$。 + +其雅可比矩阵是 $\mathcal{M} = b - 1 < 0$,当 $b < 1$ 时成立。 + +在上述有界性和域条件下,RLS 于是几乎必然收敛。 + +当 $b > 1$ 时,$\mathcal{M} > 0$ 且收敛失败。 + +下面的代码设置 $a=1$ 和 $b=0.6$。 + +于是理性预期价格预测为 $\beta_f=2.5$。 + +三个面板显示了含噪声的 RLS 路径、小型 ODE 近似,以及学习漂移 $T(\beta)-\beta$。 + +下一个单元格设置 Bray 图中使用的模拟器和绘图辅助函数。 + +```{code-cell} ipython3 +def simulate_rls_scalar(T_map, σ_u, β0, T_periods=500, N_paths=100, + a_seq=None, seed=0): + """ + 模拟 z1_t = T(β_t) + u_t、z2_t = 1 的 RLS 递归。 + 返回一个 (N_paths, T_periods) 的信念路径数组。 + """ + rng = np.random.default_rng(seed) + if a_seq is None: + a_seq = np.ones(T_periods) + + β_paths = np.empty((N_paths, T_periods)) + + for i in range(N_paths): + β = β0 + R = 1.0 + + for t in range(T_periods): + α_t = a_seq[t] + z2 = 1.0 + u_t = rng.normal(0, σ_u) + z1 = T_map(β) * z2 + u_t + + R_old = max(R, 1e-8) + β = β + (α_t / (t + 1)) / R_old * z2 * (z1 - β * z2) + R = R + (α_t / (t + 1)) * (z2**2 - R / α_t) + R = max(R, 1e-8) + + β_paths[i, t] = β + + return β_paths + + +def solve_ode_calendar(f_ode, β0, T_periods, a_seq=None): + """ + 求解 dβ/dτ = f_ode(β),并在 RLS 累积增益时间处评估它。 + """ + if a_seq is None: + a_seq = np.ones(T_periods) + + periods = np.arange(T_periods + 1) + gains = a_seq / np.arange(1, T_periods + 1) + ode_time = np.concatenate(([0.0], np.cumsum(gains))) + sol = solve_ivp( + lambda τ, y: [f_ode(y[0])], + (0.0, ode_time[-1]), + [β0], + t_eval=ode_time, + method='RK45', + max_step=0.05 + ) + return periods, sol.y[0] + + +def plot_scalar_drift(ax, β_grid, drift, β_f, color): + """绘制一维学习漂移 T(β) - β。""" + ax.plot(β_grid, drift, color=color, lw=2) + ax.axhline(0, color='black', lw=1.5) + ax.axvline(β_f, color='red', ls='--', lw=2, + label=f'$\\beta_f = {β_f:.2f}$') + ax.fill_between(β_grid, drift, 0, where=(drift > 0), + color=color, alpha=0.12) + ax.fill_between(β_grid, drift, 0, where=(drift < 0), + color=color, alpha=0.12) + + for β_arrow in np.linspace(β_grid[20], β_grid[-20], 7): + dβ = np.interp(β_arrow, β_grid, drift) + if abs(dβ) > 1e-10: + ax.annotate( + '', xy=(β_arrow + 0.25 * np.sign(dβ), 0), + xytext=(β_arrow, 0), + arrowprops=dict(arrowstyle='->', color=color, lw=1.8) + ) + + ax.set_xlabel('$\\beta$') + ax.set_ylabel('$T(\\beta) - \\beta$') + ax.legend(fontsize=9) + + +T_sim = 400 +N_sim = 80 +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Bray 学习动态 + name: fig-bray-learning-dynamics +--- +a_bray, b_bray, σ_bray = 1.0, 0.6, 1.0 + + +def T_bray(β): + return a_bray + b_bray * β + + +β_f_bray = a_bray / (1 - b_bray) + +β0_bray = 0.0 + +β_paths_bray = simulate_rls_scalar( + T_bray, σ_bray, β0_bray, + T_periods=T_sim, N_paths=N_sim +) + + +def ode_bray(β): + return a_bray + b_bray * β - β + + +t_ode, sol_low = solve_ode_calendar(ode_bray, 0.0, T_sim) +_, sol_high = solve_ode_calendar(ode_bray, 4.5, T_sim) + +β_grid_bray = np.linspace(-0.5, 5.0, 300) +drift_bray = np.array([ode_bray(b) for b in β_grid_bray]) + +fig, axes = plt.subplots(1, 3, figsize=(15, 4.8)) + +ax = axes[0] +for i in range(min(30, N_sim)): + ax.plot(β_paths_bray[i], color='steelblue', alpha=0.25, lw=2) +ax.plot(np.mean(β_paths_bray, axis=0), color='navy', lw=2, + label='跨路径平均') +ax.axhline(β_f_bray, color='red', ls='--', lw=2, + label=f'$\\beta_f = {β_f_bray:.2f}$') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta_t$') +ax.legend() + +ax = axes[1] +ax.plot( + t_ode, sol_low, color='steelblue', lw=2, + label='$\\tau_t$ 处的 ODE,$\\beta_0=0$' +) +ax.plot( + t_ode, sol_high, color='darkorange', lw=2, + label='$\\tau_t$ 处的 ODE,$\\beta_0=4.5$' +) +ax.axhline(β_f_bray, color='red', ls='--', lw=2, + label=f'$\\beta_f = {β_f_bray:.2f}$') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta(\\tau_t)$') +ax.legend() + +plot_scalar_drift( + axes[2], β_grid_bray, drift_bray, β_f_bray, 'steelblue' +) + +plt.tight_layout() +plt.show() +print(f"REE: β_f = a/(1-b) = {β_f_bray:.4f}") +print(f"Jacobian M = b - 1 = {b_bray - 1:.4f} (< 0: E-stable)") +``` + +随机路径含有噪声,因为价格中含有 $\tilde u_t$。 + +平均路径和 ODE 路径消除了大部分噪声,揭示了平均学习方向。 + +## 反例:不稳定的 Bray 反馈 + +为了看看当 E-稳定性被违反时会发生什么,用 $b > 1$ 重复 Bray 的模型。 + +它代表一个经济,其中期望对实际价格的影响超过一比一。 + +如果主体从一个过高的预测出发,那么该预测诱导的市场结果会更高,因此最小二乘会提高预测。 + +在 REE 以下,同样的逻辑反向起作用。 + +REE 存在,但它无法被这个自适应规则学到。 + +现在同样的三个诊断面板显示了信念如何被推离 REE 而不是朝向它,而漂移面板显示学习力量在两侧都指向远离不动点的方向。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 不稳定的 Bray 动态 + name: fig-unstable-bray-dynamics +--- +b_unstable = 1.4 + + +def T_unstable(β): + return a_bray + b_unstable * β + + +β_f_unstable = a_bray / (1 - b_unstable) + +β_paths_unstable = simulate_rls_scalar( + T_unstable, σ_bray, β0=0.0, + T_periods=200, N_paths=50 +) + + +def ode_unstable(β): + return T_unstable(β) - β + + +β_grid = np.linspace(-5, 5, 300) +drift = np.array([ode_unstable(b) for b in β_grid]) + +t_ode_un, sol_un_low = solve_ode_calendar(ode_unstable, -4.0, 200) +_, sol_un_high = solve_ode_calendar(ode_unstable, 0.0, 200) + +fig, axes = plt.subplots(1, 3, figsize=(15, 4.8)) + +ax = axes[0] +for i in range(min(30, 50)): + ax.plot(β_paths_unstable[i], color='crimson', alpha=0.3, lw=2) +ax.axhline(β_f_unstable, color='black', ls='--', lw=2, + label=f'$\\beta_f = {β_f_unstable:.2f}$ (unstable)') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta_t$') +ax.legend() + +ax = axes[1] +ax.plot( + t_ode_un, sol_un_low, color='crimson', lw=2, + label='$\\tau_t$ 处的 ODE,$\\beta_0=-4$' +) +ax.plot( + t_ode_un, sol_un_high, color='steelblue', lw=2, + label='$\\tau_t$ 处的 ODE,$\\beta_0=0$' +) +ax.axhline(β_f_unstable, color='black', ls='--', lw=2, + label=f'$\\beta_f = {β_f_unstable:.2f}$') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta(\\tau_t)$') +ax.legend() + +plot_scalar_drift( + axes[2], β_grid, drift, β_f_unstable, 'crimson' +) + +plt.tight_layout() +plt.show() +print(f"Jacobian M = b - 1 = {b_unstable - 1:.2f} (> 0: NOT E-stable)") +``` + +## 例 3:Bray-Savin 供给移动因子模型 + +{cite:t}`BraySavin1986` 研究了一个模型,其中 + +$$ +p_t = x_t^\top(m + a\beta_{t-1}) + \tilde{u}_t , \quad p_t^e = x_t^\top\beta_{t-1} , +$$ (eq:bs_price) + +其中 $x_t$ 是外生供给移动因子,$a$ 是标量反馈参数,主体运行 $p$ 对 $x$ 的 OLS 回归。 + +这是同样的学习问题,只多了一个额外的经济要素:期望以一个观测到的移动因子为条件。 + +主体不只是预测平均价格。 + +他们估计价格如何对 $x_t$ 做出反应。 + +$x_t$ 上的实际系数是 $m+a\beta$,因此感知斜率改变了市场生成的真实斜率。 + +如果 $a < 1$,一个错误的斜率以衰减的方式反馈到实际价格方程中,最小二乘估计被拉向 REE 斜率。 + +映射是 $T(\beta) = m + a\beta$(标量情形),给出 + +$$ +\dot\beta = (a-1)\beta + m , \quad \beta_f = \frac{m}{1-a} , +$$ (eq:bs_ode) + +雅可比矩阵为 $\mathcal{M} = a - 1 < 0$ 当且仅当 $a < 1$。 + +下面的模拟抽取外生移动因子 $x_t$,并让主体更新 $p_t$ 对 $x_t$ 回归中的斜率。 + +它使用 $a=0.7$。 + +漂移面板显示错误的斜率被推回 REE 斜率,而不是被放大。 + +下一个单元格将 RLS 模拟器调整为供给移动因子回归。 + +```{code-cell} ipython3 +def simulate_bray_savin(m, a, σ_x, σ_u, β0, T_periods=500, + N_paths=100, seed=0): + """ + 模拟 p_t = x_t (m + a β_t) + u_t 的 RLS。 + 主体将 p_t 对 x_t 回归。 + """ + rng = np.random.default_rng(seed) + β_paths = np.empty((N_paths, T_periods)) + + for i in range(N_paths): + β = β0 + R = 1.0 + + for t in range(T_periods): + x_t = rng.normal(0.0, σ_x) + u_t = rng.normal(0.0, σ_u) + p_t = x_t * (m + a * β) + u_t + step = 1.0 / (t + 1) + + R_old = max(R, 1e-8) + β = β + step / R_old * x_t * (p_t - β * x_t) + R = R + step * (x_t**2 - R) + R = max(R, 1e-8) + β_paths[i, t] = β + + return β_paths +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Bray-Savin 学习动态 + name: fig-bray-savin-learning-dynamics +--- +m_bs, a_bs = 0.5, 0.7 +σ_x_bs, σ_u_bs = 1.0, 1.0 + + +def T_bs(β): + return m_bs + a_bs * β + + +β_f_bs = m_bs / (1 - a_bs) + +β_paths_bs = simulate_bray_savin( + m_bs, a_bs, σ_x_bs, σ_u_bs, 0.0, + T_periods=T_sim, N_paths=N_sim +) + + +def ode_bs(β): + return T_bs(β) - β + + +t_ode_bs, sol_bs_low = solve_ode_calendar(ode_bs, 0.0, T_sim) +_, sol_bs_high = solve_ode_calendar(ode_bs, 4.0, T_sim) + +β_grid_bs = np.linspace(-0.5, 4.0, 300) +drift_bs = np.array([ode_bs(b) for b in β_grid_bs]) + +fig, axes = plt.subplots(1, 3, figsize=(15, 4.8)) + +ax = axes[0] +for i in range(min(30, N_sim)): + ax.plot(β_paths_bs[i], color='darkorange', alpha=0.25, lw=2) +ax.plot(np.mean(β_paths_bs, axis=0), color='saddlebrown', lw=2, + label='跨路径平均') +ax.axhline(β_f_bs, color='red', ls='--', lw=2, + label=f'$\\beta_f = {β_f_bs:.2f}$') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta_t$') +ax.legend() + +ax = axes[1] +ax.plot( + t_ode_bs, sol_bs_low, color='darkorange', lw=2, + label='$\\tau_t$ 处的 ODE,$\\beta_0=0$' +) +ax.plot( + t_ode_bs, sol_bs_high, color='steelblue', lw=2, + label='$\\tau_t$ 处的 ODE,$\\beta_0=4$' +) +ax.axhline(β_f_bs, color='red', ls='--', lw=2, + label=f'$\\beta_f = {β_f_bs:.2f}$') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta(\\tau_t)$') +ax.legend() + +plot_scalar_drift( + axes[2], β_grid_bs, drift_bs, β_f_bs, 'darkorange' +) + +plt.tight_layout() +plt.show() +print(f"REE: β_f = m/(1-a) = {β_f_bs:.4f}") +print(f"Jacobian M = a - 1 = {a_bs - 1:.4f} (< 0: E-stable)") +``` + +其解释与 Bray 的蛛网模型相似。 + +不同之处在于,主体现在学习的是价格如何与一个外生变量共同变动,而不仅仅是学习一个无条件均值。 + +## 例 4:恶性通货膨胀/资产价格 + +考虑现值资产定价模型 + +$$ +y_t = \lambda \mathbb{E}_t y_{t+1} + x_t , \quad x_t = \rho x_{t-1} + \varepsilon_t , +$$ (eq:pv_model) + +其中 $|\lambda| < 1$、$|\rho| < 1$,且主体感知 $y_t = \beta_t x_{t-1}+ v_t$。 + +在感知规律下,$\mathbb{E}_t y_{t+1} = \beta_t x_t$,所以 {eq}`eq:pv_model` 变为 + +$$ +y_t = (\lambda \beta_t + 1) x_t = (\lambda \beta_t + 1)\rho x_{t-1} + (\lambda \beta_t + 1)\varepsilon_t. +$$ + +因此实际运动规律中 $x_{t-1}$ 上的系数是 $(\lambda \beta_t + 1)\rho$,它给出了下面的算子 $T$。 + +如果 $y_t$ 是价格水平,这个方程类似于 Cagan 式的恶性通货膨胀模型。 + +如果 $y_t$ 是资产价格且 $x_t$ 是股息或基本面,那么它是一个现值关系。 + +在这两种情形中,关于 $y$ 未来价值的信念都进入了 $y$ 的当前价值。 + +乘积 $\lambda\rho$ 衡量前瞻性反馈的强度:$\lambda$ 对未来贴现,$\rho$ 衡量基本面的持续性。 + +当 $|\lambda\rho|<1$ 时,一个错误的感知系数不会无界地放大。 + +映射是 $T(\beta) = (\lambda\beta + 1)\rho$,REE 是 + +$$ +\beta_f = \frac{\rho}{1 - \lambda\rho} . +$$ (eq:pv_ree) + +小型 ODE 是 + +$$ +\dot\beta = (\lambda\rho - 1)\beta + \rho , +$$ (eq:pv_ode) + +对于 $|\lambda\rho| < 1$,雅可比矩阵为 $\mathcal{M} = \lambda\rho - 1 < 0$,所以小型 ODE 是稳定的。 + +于是收敛定理在上述外生回归变量条件下适用。 + +模拟使用 $\lambda=0.8$ 和 $\rho=0.9$,所以 $\lambda\rho=0.72$。 + +这意味着来自期望的反馈足够强到有影响,但仍小于一。 + +下面的 ODE 面板在水平轴上使用 $\tau$ 本身,其中 $\tau$ 是最小二乘累积的总步长。 + +代码模拟自回归基本面 $x_t$,并更新 $y_t$ 对 $x_{t-1}$ 的 OLS 回归。 + +下一个单元格模拟自回归基本面和匹配的 RLS 更新。 + +它使协方差估计 $R_t$ 保持远离零,模仿上面的投影思想,避免误导性的早期样本爆炸。 + +```{code-cell} ipython3 +def simulate_present_value_rls(λ, ρ, σ_ε, β0, T_periods=500, + N_paths=100, seed=0): + """ + 模拟 y_t = (λ β_t + 1) x_t、 + x_t = ρ x_{t-1} + ε_t 的 RLS,将 y_t 对 x_{t-1} 回归。 + """ + rng = np.random.default_rng(seed) + β_paths = np.empty((N_paths, T_periods)) + σ_x = σ_ε / np.sqrt(1 - ρ**2) + R_min = 0.05 * σ_x**2 + + for i in range(N_paths): + β = β0 + R = σ_x**2 + x_lag = rng.normal(0.0, σ_x) + + for t in range(T_periods): + ε_t = rng.normal(0.0, σ_ε) + x_t = ρ * x_lag + ε_t + y_t = (λ * β + 1.0) * x_t + step = 1.0 / (t + 1) + + R_old = max(R, R_min) + β = β + step / R_old * x_lag * (y_t - β * x_lag) + R = R + step * (x_lag**2 - R) + R = max(R, R_min) + β_paths[i, t] = β + x_lag = x_t + + return β_paths +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 现值学习动态 + name: fig-present-value-learning-dynamics +--- +λ, ρ_pv, σ_pv = 0.8, 0.9, 1.0 +T_pv_sim = T_sim +N_pv_sim = N_sim + + +def T_pv(β): + return (λ * β + 1) * ρ_pv + + +β_f_pv = ρ_pv / (1 - λ * ρ_pv) + +β_paths_pv = simulate_present_value_rls( + λ, ρ_pv, σ_pv, 0.0, + T_periods=T_pv_sim, N_paths=N_pv_sim +) + + +def ode_pv(β): + return T_pv(β) - β + + +τ_grid_pv = np.linspace(0.0, 30.0, 300) +sol_pv_low = solve_ivp( + lambda τ, y: [ode_pv(y[0])], + (0.0, τ_grid_pv[-1]), + [0.0], + t_eval=τ_grid_pv, + max_step=0.05 +).y[0] +sol_pv_high = solve_ivp( + lambda τ, y: [ode_pv(y[0])], + (0.0, τ_grid_pv[-1]), + [10.0], + t_eval=τ_grid_pv, + max_step=0.05 +).y[0] + +β_grid_pv = np.linspace(-1.0, 7.0, 300) +drift_pv = np.array([ode_pv(b) for b in β_grid_pv]) + +fig, axes = plt.subplots(1, 3, figsize=(15, 4.8)) + +ax = axes[0] +for i in range(min(30, N_pv_sim)): + ax.plot(β_paths_pv[i], color='seagreen', alpha=0.25, lw=2) +ax.plot(np.mean(β_paths_pv, axis=0), color='darkgreen', lw=2, + label='跨路径平均') +ax.axhline(β_f_pv, color='red', ls='--', lw=2, + label=f'$\\beta_f = {β_f_pv:.2f}$') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta_t$') +ax.legend() + +ax = axes[1] +ax.plot( + τ_grid_pv, sol_pv_low, color='seagreen', lw=2, + label='ODE, $\\beta_0=0$' +) +ax.plot( + τ_grid_pv, sol_pv_high, color='steelblue', lw=2, + label='ODE, $\\beta_0=10$' +) +ax.axhline(β_f_pv, color='red', ls='--', lw=2, + label=f'$\\beta_f = {β_f_pv:.2f}$') +ax.set_xlabel('累积步长 $\\tau$') +ax.set_ylabel('$\\beta(\\tau)$') +ax.legend() + +plot_scalar_drift( + axes[2], β_grid_pv, drift_pv, β_f_pv, 'seagreen' +) + +plt.tight_layout() +plt.show() +print(f"REE: β_f = ρ/(1 - lambda*ρ) = {β_f_pv:.4f}") +print(f"Jacobian M = lambda*ρ - 1 = {λ*ρ_pv - 1:.4f} (< 0: E-stable)") +``` + +REE 系数大于 $\rho$,因为当前价格资本化了预期的未来基本面。 + +学习之所以收敛,是因为 $\beta_t$ 的每次修正都改变了期望,但贴现的持续性项 $\lambda\rho$ 阻止了修正以爆炸性的方式反馈。 + +## 例 5:不确定性下的投资 + +现在让我们考虑 Lucas-Prescott 投资模型的一个版本,其中主体通过对 $(K_{t-1}, w_{t-1})$ 回归来学习关于总资本存量 $K_t$ 的信息,其中 $w_t$ 是外生成本冲击。 + + +企业使用总资本的感知运动规律来选择投资。 + +这些投资选择然后通过市场出清决定了总资本的实际运动规律。 + +因此学习是关于一个状态变量的,而主体自己通过其投资决策帮助创造了这个状态变量。 + +感知运动规律是 + +$$ +K_t = \beta_1 K_{t-1} + \beta_2 w_{t-1} + \eta_t , +$$ + +而实际规律(来自企业的最优投资决策和市场出清)是 + +$$ +K_t = T_1(\beta) K_{t-1} + T_2(\beta) w_{t-1} + V(\beta) u_t , +$$ (eq:inv_actual) + +其中非线性映射 $T_1, T_2$ 来自求解企业的线性二次控制问题。 + +这两个系数具有不同的经济作用。 + +$\beta_1$ 描述总资本中的持续性,而 $\beta_2$ 描述外生冲击 $w_t$ 如何影响下一期的资本。 + +因为最优投资规则取决于整个感知运动规律,映射 $T$ 是非线性的。 + +这就是为什么这里较大的 ODE 比外生回归变量的标量例子更难分析。 + +小型 ODE 分解为: + +$$ +\dot\beta_1 = T_1(\beta_1) - \beta_1 , \quad +\dot\beta_2 = T_2(\beta_1, \beta_2) - \beta_2 , +$$ (eq:inv_ode) + +E-稳定性可以对 $|\beta_1| < b^{-1/2}$(其中 $b$ 是贴现因子)解析地验证。 + + +下面的相图在 $(\beta_1,\beta_2)$ 空间上绘制了向量场 $T(\beta)-\beta$。 + +每个箭头显示如果经济当前在该信念下运行,感知运动规律将如何被修正。 + +所绘制的轨迹是确定性的 ODE 路径,而不是含噪声的最小二乘样本路径。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 投资相图 + name: fig-investment-phase-portrait +--- +def T_invest(β, b=0.95, d=1.0, f=1.0, A1=1.0, N=1.0, ρ_w=0.5): + """投资模型的映射 T,其中 β = [β1, β2]。""" + b1, b2 = β + denom1 = 1 - b1 * b + (1 / d) * f**2 * A1 * N + T1 = (1 - b1 * b) / denom1 + numer2 = 1 - b1 * b + f**2 * A1 * b2 * b * ρ_w + T2 = (-N / (d * (1 - ρ_w * b))) * (numer2 / denom1) * ρ_w + return np.array([T1, T2]) + + +def ode_invest(t, β, **kwargs): + Tb = T_invest(β, **kwargs) + return Tb - β + + +params = dict(b=0.95, d=1.0, f=1.0, A1=1.0, N=1.0, ρ_w=0.5) +β1_bound = params["b"] ** (-0.5) +β_f_inv = fsolve(lambda b: T_invest(b, **params) - b, [0.5, 0.1]) +print(f"REE: β_f = {β_f_inv}") + +eps = 1e-6 +J = np.zeros((2, 2)) +for j in range(2): + e = np.zeros(2) + e[j] = eps + J[:, j] = ( + T_invest(β_f_inv + e, **params) + - T_invest(β_f_inv - e, **params) + ) / (2 * eps) +M = J - np.eye(2) +eigs = la.eigvals(M) +print(f"Jacobian M eigenvalues: {eigs}") +print(f"E-stable: {np.all(eigs.real < 0)}") + +fig, ax = plt.subplots(figsize=(8, 6)) + +b1_grid = np.linspace(-0.1, min(1.0, β1_bound - 1e-3), 20) +b2_grid = np.linspace(-0.8, 0.5, 20) +B1, B2 = np.meshgrid(b1_grid, b2_grid) +U = np.zeros_like(B1) +V_field = np.zeros_like(B2) +for i in range(B1.shape[0]): + for j in range(B1.shape[1]): + β_ij = np.array([B1[i, j], B2[i, j]]) + drift = T_invest(β_ij, **params) - β_ij + U[i, j] = drift[0] + V_field[i, j] = drift[1] + +speed = np.sqrt(U**2 + V_field**2) +speed[speed == 0] = 1e-8 +ax.streamplot(b1_grid, b2_grid, U, V_field, color=speed, + cmap='Blues', density=1.3, linewidth=1) + +starts = [(0.1, 0.0), (0.9, 0.4), (0.98, -0.6), (0.3, -0.7)] +colors_traj = ['red', 'darkorange', 'green', 'purple'] +for (b10, b20), col in zip(starts, colors_traj): + sol = solve_ivp(lambda t, β: ode_invest(t, β, **params), + [0, 30], [b10, b20], + t_eval=np.linspace(0, 30, 300), + method='RK45') + ax.plot(sol.y[0], sol.y[1], color=col, lw=2) + ax.plot(b10, b20, 'o', color=col, ms=7) + +ax.plot(*β_f_inv, 'k*', ms=14, label='REE $\\beta_f$') +ax.set_xlabel('$\\beta_1$', fontsize=12) +ax.set_ylabel('$\\beta_2$', fontsize=12) +ax.legend() +plt.tight_layout() +plt.show() +``` + +星号标记 REE。 + +路径之所以收敛,是因为资本持续性系数 $\beta_1$ 首先被稳定下来,然后给定 $\beta_1$ 的极限值,冲击系数 $\beta_2$ 进行调整。 + +这种递归结构就是为什么即使完整的最小二乘系统有内生回归变量,小型 ODE 仍然是可处理的。 + +## 与理性学习的联系 + +{cite:t}`MarcetSargent1989jet` 的框架属于 *关于* 理性预期均衡的学习纲领,与 *在* 均衡 *内* 学习不同——这一区别由 {cite:t}`BrayKreps1987` 强调。 + +*在* REE *内* 学习(配套讲座 [](rational_learning_re) 的主题)指的是在正确设定的模型内进行贝叶斯推断。 + +在那种设定中,从主体的视角来看,数据生成过程是平稳的,贝叶斯法则是完全合理化的。 + +**关于 REE 的学习** 涉及一个不知道均衡价格函数的主体。 + +因为主体的信念改变了均衡价格,主体用来更新信念的数据本身是由一个非平稳过程生成的。 + +正如 {cite:t}`MarcetSargent1989jet` 所说, + +> 这些模型没有纳入完全最优的行为或理性预期,因为主体在持续被证伪的假设下运作,即运动规律是时间不变且确定已知的。 + +然而它是一个令人信服的规则。 + +每当 E-稳定性与所需的有界性和吸引域条件结合时,尽管存在错误设定,收敛仍然成立。 + +与贝叶斯学习不同,它不需要关于经济统计结构的强先验假设。 + + +## 总结 + +本讲座研究了 {cite:t}`MarcetSargent1989jet` 自指模型中的最小二乘学习。 + +核心对象是从感知运动规律到当主体基于该感知行动时生成的实际运动规律的映射 $T$。 + +理性预期均衡是这个映射的不动点。 + +当相关的 ODE $\dot\beta = T(\beta)-\beta$ 局部稳定且学习过程保持在模型有良好定义的区域内时,递归最小二乘收敛到那个不动点。 + +它补充了在 {doc}`rational_learning_re` 中研究的理性学习,在那里贝叶斯主体在一个已经设定好的均衡结构 *内* 进行学习。 + +## 练习 + +```{exercise} +:label: ls_ex1 + +考虑标量模型,其中 $T(\beta) = a + b\beta$。 + +1. 推导唯一 REE $\beta_f$ 关于 $a$ 和 $b$ 的公式。 + +2. 证明小型 ODE $\dot\beta = T(\beta) - \beta$ 全局稳定当且仅当 $b < 1$。 + +3. 对于 $a = 1$ 和 $b \in \{0.3, 0.7, 0.9, 0.99\}$ 中的每一个(都小于 1),模拟 $N = 200$ 条长度为 $T = 500$ 的路径。 + +在同一张图上为每个 $b$ 值绘制 $\beta_t$ 的跨路径平均,并评论当 $b \to 1$ 时收敛速度如何变化。 +``` + +```{solution-start} ls_ex1 +:class: dropdown +``` + +这是一个解答: + +*第 1 部分。* REE 满足 $\beta_f = T(\beta_f) = a + b\beta_f$,所以 + +$$ +\beta_f (1 - b) = a \implies \beta_f = \frac{a}{1-b} . +$$ + +*第 2 部分。* 小型 ODE 是 $\dot\beta = a + b\beta - \beta = a - (1-b)\beta$。 + +这是线性的,斜率为 $-(1-b)$,所以唯一不动点 $\beta_f = a/(1-b)$ 全局稳定当且仅当 $1-b > 0$,即 $b < 1$。 + +*第 3 部分。* + +```{code-cell} ipython3 +a_ex, T_ex, N_ex = 1.0, 500, 200 +b_values = [0.3, 0.7, 0.9, 0.99] +colors_ex = ['steelblue', 'darkorange', 'seagreen', 'purple'] + +fig, ax = plt.subplots(figsize=(11, 5)) +for b_val, col in zip(b_values, colors_ex): + def T_fn(β, b_val=b_val): + return a_ex + b_val * β + + paths = simulate_rls_scalar(T_fn, σ_u=1.0, β0=0.0, + T_periods=T_ex, N_paths=N_ex, seed=0) + bf = a_ex / (1 - b_val) + ax.plot(np.mean(paths, axis=0), color=col, lw=2, + label=f'$b={b_val}$, $\\beta_f={bf:.2f}$') + +ax.set_xlabel('$t$') +ax.set_ylabel('$E[\\beta_t]$') +ax.set_title('收敛速度随 $b \\to 1$ 而减慢') +ax.legend() +plt.tight_layout() +plt.show() +``` + +当 $b \to 1$ 时,雅可比矩阵 $\mathcal M = b - 1$ 趋近于零,所以 ODE 返回不动点变得缓慢。 + +收敛仍然发生,但花费的时间更长。 + +```{solution-end} +``` + +```{exercise} +:label: ls_ex2 + +{prf:ref}`prop-ms-necessity` 陈述了对于内部任何 $\hat\beta \neq \beta_f$ 都有 $\mathbb{P}(\beta_t \to \hat\beta) = 0$。 + +1. 使用 $a=1$、$b=0.6$ 的 Bray 模型,从 $\beta_0 = 6$(远离 $\beta_f = 2.5$)开始,模拟 100 条长度为 $T = 600$ 的路径,并证明路径仍然收敛到 $\beta_f$。 + +2. 现在考虑 *不稳定* 情形 $b = 1.5$,从 $\beta_0 = -1.9$(接近 REE $\beta_f = -2$)开始,模拟 50 条长度为 $T = 200$ 的路径,并描述发生了什么。 +``` + +```{solution-start} ls_ex2 +:class: dropdown +``` + +这是一个解答: + +*第 1 和第 2 部分。* + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +def T_st(β): + return 1.0 + 0.6 * β + + +paths_far = simulate_rls_scalar(T_st, 1.0, β0=6.0, + T_periods=600, N_paths=100, seed=1) +ax = axes[0] +for i in range(40): + ax.plot(paths_far[i], color='steelblue', alpha=0.2, lw=2) +ax.plot(np.mean(paths_far, axis=0), color='navy', lw=2, label='平均') +ax.axhline(2.5, color='red', ls='--', lw=2, label='$\\beta_f = 2.5$') +ax.set_title('稳定 ($b=0.6$):远处起始仍然收敛') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta_t$') +ax.legend() + +def T_un(β): + return 1.0 + 1.5 * β + + +β_f_un = 1.0 / (1 - 1.5) +paths_un = simulate_rls_scalar(T_un, 1.0, β0=-1.9, + T_periods=200, N_paths=50, seed=2) +ax = axes[1] +for i in range(50): + ax.plot(paths_un[i], color='crimson', alpha=0.3, lw=2) +ax.axhline(β_f_un, color='black', ls='--', lw=2, + label=f'$\\beta_f = {β_f_un}$ (unstable)') +ax.set_title('不稳定 ($b=1.5$):即使接近 REE 也发散') +ax.set_xlabel('$t$') +ax.set_ylabel('$\\beta_t$') +ax.legend() + +plt.tight_layout() +plt.show() +``` + +从几何上看,斜率 $dT/d\beta - 1 = b - 1 = 0.5$ 在 REE 处为正。 + +因此 ODE 在两个方向上都将 $\beta$ 推离 $\beta_f$。 + +```{solution-end} +``` + +```{exercise} +:label: ls_ex3 + +现值模型:$\lambda$ 对 E-稳定性的影响 + +在现值模型 {eq}`eq:pv_model` 中,$T(\beta) = (\lambda\beta + 1)\rho$,雅可比矩阵是 $\mathcal{M} = \lambda\rho - 1$。 + +1. 对于 $\rho = 0.9$ 和 $\lambda \in \{0.5, 0.8, 0.95, 0.99\}$ 中的每一个,计算 $\beta_f$ 和 $\mathcal{M}$,并判断 REE 是否 E-稳定。 + +2. 对于 E-稳定的情形,模拟 100 条长度为 $T=400$ 的路径,在日历时间中绘制有代表性的含噪声路径,然后在累积增益时间中绘制极限 ODE 路径。 + +3. 在 $\lambda = 0.99$ 处,$\mathcal{M} = 0.99\rho - 1 < 0$。 + + 为这个近边界情形模拟路径,并将收敛速度与 $\lambda = 0.5$ 情形比较,提供一个直观的解释。 +``` + +```{solution-start} ls_ex3 +:class: dropdown +``` + +这是一个解答: + +*第 1 部分。* + +```{code-cell} ipython3 +ρ_ex = 0.9 +λ_values = [0.5, 0.8, 0.95, 0.99] + +print(f"{'lambda':>8} {'β_f':>10} {'M = λ*ρ-1':>15} {'E-stable':>10}") +print("-" * 50) +for lv in λ_values: + bf = ρ_ex / (1 - lv * ρ_ex) if abs(lv * ρ_ex) < 1 else float('inf') + M_jac = lv * ρ_ex - 1 + estab = "YES" if M_jac < 0 else "NO" + print(f"{lv:>8.2f} {bf:>10.4f} {M_jac:>15.4f} {estab:>10}") +``` + +*第 2 和第 3 部分。* + +```{code-cell} ipython3 +fig, axes = plt.subplots(len(λ_values), 2, figsize=(13, 14)) +colors_λ = ['steelblue', 'darkorange', 'seagreen', 'purple'] + +for row, (lv, col) in enumerate(zip(λ_values, colors_λ)): + def ode_fn(β, λ_val=lv): + return (λ_val * β + 1) * ρ_ex - β + + bf = ρ_ex / (1 - lv * ρ_ex) + + paths_λ = simulate_present_value_rls( + lv, ρ_ex, 1.0, β0=0.0, + T_periods=400, N_paths=100, seed=3 + ) + + ax = axes[row, 0] + for i in range(20): + ax.plot(paths_λ[i], color=col, alpha=0.2, lw=2) + ax.axhline(bf, color='red', ls=':', lw=2, + label=f'$\\beta_f={bf:.2f}$') + ax.set_title(f'RLS 路径,$\\lambda={lv}$') + ax.set_xlabel('$t$') + ax.set_ylabel('$\\beta_t$') + ax.legend(fontsize=8) + + τ_grid = np.linspace(0.0, 30.0, 300) + sol_low = solve_ivp( + lambda τ, y: [ode_fn(y[0])], + (0.0, τ_grid[-1]), + [0.0], + t_eval=τ_grid, + max_step=0.05 + ).y[0] + sol_high = solve_ivp( + lambda τ, y: [ode_fn(y[0])], + (0.0, τ_grid[-1]), + [1.5 * bf], + t_eval=τ_grid, + max_step=0.05 + ).y[0] + + ax = axes[row, 1] + ax.plot(τ_grid, sol_low, color=col, lw=2, + label='ODE, $\\beta_0=0$') + ax.plot(τ_grid, sol_high, color='black', ls='--', lw=2, + label='ODE, high start') + ax.axhline(bf, color='red', ls=':', lw=2, + label=f'$\\beta_f={bf:.2f}$') + M_jac = lv * ρ_ex - 1 + ax.set_title(f'ODE, $\\mathcal{{M}}={M_jac:.3f}$') + ax.set_xlabel('累积步长 $\\tau$') + ax.set_ylabel('$\\beta(\\tau)$') + ax.legend(fontsize=8) + +plt.tight_layout() +plt.show() +``` + +在每一行中,左面板显示日历时间中的有限样本 RLS 路径,右面板显示累积增益时间中的确定性 ODE 路径。 + +当 $\lambda=0.99$ 时,$\mathcal M = 0.99\rho-1 \approx -0.109$ 的绝对值很小。 + +ODE 在 $\beta_f$ 附近几乎是平的,所以恢复力弱,收敛缓慢。 + +当 $\lambda=0.5$ 时,$\mathcal M=-0.55$,这给出了更强的恢复力和更快的收敛。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/mccall_model_with_sep_markov.md b/lectures/mccall_model_with_sep_markov.md new file mode 100644 index 0000000..7190035 --- /dev/null +++ b/lectures/mccall_model_with_sep_markov.md @@ -0,0 +1,960 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.2 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 工作搜寻 III:带分离和马尔可夫工资的搜寻 + headings: + Model setup: 模型设置 + Model setup::Decision problem: 决策问题 + Model setup::The wage offer process: 工资报价过程 + Model setup::Value functions: 价值函数 + Model setup::Optimal policy: 最优策略 + Code: 代码 + Code::Set up: 设置 + 'Code::Solution: first pass': 求解:第一遍 + Code::Road test: 实地测试 + Improving efficiency: 提高效率 + Sensitivity analysis: 敏感性分析 + Employment simulation: 就业模拟 + Ergodic property: 遍历性 + Cross-sectional analysis: 横截面分析 + Lower unemployment compensation (c=0.5): 更低的失业补偿(c=0.5) + Exercises: 练习 +--- + +(mccall_with_sep_markov)= +```{raw} jupyter + +``` + ++++ + +# 工作搜寻 III:带分离和马尔可夫工资的搜寻 + +```{include} _admonition/gpu.md +``` + +```{index} single: An Introduction to Job Search +``` + +```{contents} Contents +:depth: 2 +``` + +本讲座建立在{doc}`上一讲 `中提出的带分离的工作搜寻模型之上。 + +关键区别在于,工资报价现在遵循{doc}`马尔可夫链 `,而不是独立同分布(IID)。 + +这一修改为工资报价过程增加了持续性,这意味着今天的工资报价提供了关于明天报价的信息。 + +这一特征使模型更加真实,因为劳动力市场条件往往随时间表现出序列相关性。 + +除了 Anaconda 中已有的内容外,本讲座还需要以下库 + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install quantecon jax +``` + +我们使用以下导入: + +```{code-cell} ipython3 +from quantecon.markov import tauchen +import jax.numpy as jnp +import jax +from jax import lax +from typing import NamedTuple +import matplotlib.pyplot as plt +from functools import partial +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 模型设置 + +设定如下: + +- 每个失业的个体从一个有限集合 $\mathbb W$ 中获得一个工资报价 $w$ +- 工资报价遵循一个转移矩阵为 $P$ 的马尔可夫链 +- 工作每期以概率 $\alpha$ 终止(分离率) +- 失业工人每期获得补偿 $c$ +- 未来收益以因子 $\beta \in (0,1)$ 贴现 + +### 决策问题 + +当失业并收到工资报价 $w$ 时,个体在以下两者之间选择: + +1. 接受报价 $w$:以工资 $w$ 就业 +2. 拒绝报价:保持失业,获得 $c$,下一期得到新报价 + +工资更新如下: + +* 如果一个失业个体拒绝了报价 $w$,那么他们的下一个报价从 $P(w, \cdot)$ 中抽取 +* 如果一个就业个体失去了一份工资为 $w$ 的工作,那么他们的下一个报价从 $P(w, \cdot)$ 中抽取 + +### 工资报价过程 + +为了构造工资报价过程,我们从一个 AR1 过程开始。 + +$$ + X_{t+1} = \rho X_t + \nu Z_{t+1} +$$ + +其中 $\{Z_t\}$ 是独立同分布的标准正态分布。 + + +下面我们将始终选择 $\rho \in (0, 1)$。 + +这意味着工资过程将是正相关的:当前工资报价越高,我们明天获得高报价的可能性就越大。 + +为了从 AR1 过程转换到工资报价过程,我们设 $W_t = \exp(X_t)$。 + +实际上,在实践中,我们按如下方式近似这个工资过程: + +* 使用{ref}`Tauchen 方法 `离散化 AR1 过程,以及 +* 取所得工资报价值的指数。 + + + + +### 价值函数 + +我们令 + +- $v_u(w)$ 为当前工资报价为 $w$ 时失业的价值 +- $v_e(w)$ 为以工资 $w$ 就业的价值 + +贝尔曼方程是{doc}`独立同分布情形 `的显然修改。 + +唯一的变化是,下一期的期望是使用以当前工资 $w$ 为条件的转移矩阵 $P$ 计算的,而不是从 $q$ 中独立抽取。 + +失业工人的价值函数满足贝尔曼方程 + +$$ + v_u(w) = \max + \left\{ + v_e(w), u(c) + \beta \sum_{w'} v_u(w') P(w,w') + \right\} +$$ + +就业工人的价值函数满足贝尔曼方程 + +$$ + v_e(w) = + u(w) + \beta + \left[ + \alpha \sum_{w'} v_u(w') P(w,w') + (1-\alpha) v_e(w) + \right] +$$ + +作为一种记号约定,给定一个将值赋给工资的函数 $h$,通常设 + +$$ + (Ph)(w) = \sum_{w'} h(w') P(w,w') +$$ + +(为了理解这个表达式,把 $P$ 想象成一个矩阵,$h$ 想象成一个列向量,$w$ 想象成一个行索引。) + +有了这个记号,贝尔曼方程变为 + +$$ + v_u(w) = \max\{v_e(w), u(c) + \beta (P v_u)(w)\} +$$ + +以及 + +$$ + v_e(w) = + u(w) + \beta + \left[ + \alpha (P v_u)(w) + (1-\alpha) v_e(w) + \right] +$$ + ++++ + +### 最优策略 + +一旦我们有了这些贝尔曼方程的解 $v_e$ 和 $v_u$,我们就可以计算最优策略:如果满足下式,则以当前工资报价 $w$ 接受 + +$$ + v_e(w) \geq u(c) + \beta (P v_u)(w) +$$ + +最优策略被证明是一个保留工资策略:接受所有高于某个阈值的工资。 + ++++ + + +## 代码 + +现在让我们实现这个模型。 + +### 设置 + +默认效用函数是一个 CRRA 效用函数 + +```{code-cell} ipython3 +def u(x, γ): + return (x**(1 - γ) - 1) / (1 - γ) +``` + +让我们设置一个 `Model` 类来存储求解模型所需的信息。 + +我们包含 `P_cumsum`,即转移矩阵的按行累积和,以优化模拟——细节将在下面解释。 + +```{code-cell} ipython3 +class Model(NamedTuple): + n: int + w_vals: jnp.ndarray + P: jnp.ndarray + P_cumsum: jnp.ndarray + β: float + c: float + α: float + γ: float +``` + +下一个函数保存默认值并创建一个 `Model` 实例: + +```{code-cell} ipython3 +def create_js_with_sep_model( + n: int = 200, # 工资网格大小 + ρ: float = 0.9, # 工资持续性 + ν: float = 0.2, # 工资波动率 + β: float = 0.96, # 贴现因子 + α: float = 0.05, # 分离率 + c: float = 1.0, # 失业补偿 + γ: float = 1.5 # 效用参数 + ) -> Model: + """ + 创建一个带分离的工作搜寻模型实例。 + + """ + mc = tauchen(n, ρ, ν) + w_vals, P = jnp.exp(jnp.array(mc.state_values)), jnp.array(mc.P) + P_cumsum = jnp.cumsum(P, axis=1) + return Model(n, w_vals, P, P_cumsum, β, c, α, γ) +``` + + +### 求解:第一遍 + +让我们组装一个(不太高效的)例程来计算保留工资。 + +(我们将在下面仔细考虑效率问题。) + +它的工作方式是从 $v_e$ 和 $v_u$ 的猜测开始,然后迭代至收敛。 + +以下是分别更新 $v_u$ 和 $v_e$ 的贝尔曼算子。 + + +```{code-cell} ipython3 +def T_u(model, v_u, v_e): + """ + 应用失业贝尔曼更新规则并返回 v_u 的新猜测。 + + """ + n, w_vals, P, P_cumsum, β, c, α, γ = model + h = u(c, γ) + β * P @ v_u + v_u_new = jnp.maximum(v_e, h) + return v_u_new +``` + +```{code-cell} ipython3 +def T_e(model, v_u, v_e): + """ + 应用就业贝尔曼更新规则并返回 v_e 的新猜测。 + + """ + n, w_vals, P, P_cumsum, β, c, α, γ = model + v_e_new = u(w_vals, γ) + β * ((1 - α) * v_e + α * P @ v_u) + return v_e_new +``` + +这里是一个迭代至收敛然后计算保留工资的例程。 + +```{code-cell} ipython3 +def solve_model_first_pass( + model: Model, # 包含默认参数的实例 + v_u_init: jnp.ndarray, # v_u 的初始条件 + v_e_init: jnp.ndarray, # v_e 的初始条件 + tol: float=1e-6, # 误差容限 + max_iter: int=1_000, # 循环的最大迭代次数 + ): + n, w_vals, P, P_cumsum, β, c, α, γ = model + i = 0 + error = tol + 1 + v_u = v_u_init + v_e = v_e_init + + while i < max_iter and error > tol: + v_u_next = T_u(model, v_u, v_e) + v_e_next = T_e(model, v_u, v_e) + error_u = jnp.max(jnp.abs(v_u_next - v_u)) + error_e = jnp.max(jnp.abs(v_e_next - v_e)) + error = jnp.maximum(error_u, error_e) + v_u = v_u_next + v_e = v_e_next + i += 1 + + # 计算接受和拒绝值 + continuation_values = u(c, γ) + β * P @ v_u + + # 找到接受变为最优的位置 + accept_indices = v_e >= continuation_values + first_accept_idx = jnp.argmax(accept_indices) # 第一个 True 的索引 + + # 如果没有接受(全为 False),返回无穷大 + # 否则返回第一个接受索引处的工资 + w_bar = jnp.where( + jnp.any(accept_indices), w_vals[first_accept_idx], jnp.inf + ) + return v_u, v_e, w_bar +``` + + +### 实地测试 + +让我们求解这个模型: + +```{code-cell} ipython3 +model = create_js_with_sep_model() +n, w_vals, P, P_cumsum, β, c, α, γ = model +v_u_init = jnp.zeros(n) +v_e_init = jnp.zeros(n) +v_u, v_e, w_bar_first = solve_model_first_pass(model, v_u_init, v_e_init) +``` + +接下来我们计算延续值。 + +```{code-cell} ipython3 +h = u(c, γ) + β * P @ v_u +``` + +让我们绘制结果。 + +```{code-cell} ipython3 +fig, ax = plt.subplots(figsize=(9, 5.2)) +ax.plot(w_vals, h, 'g-', linewidth=2, + label="延续值函数 $h$") +ax.plot(w_vals, v_e, 'b-', linewidth=2, + label="就业价值函数 $v_e$") +ax.legend(frameon=False) +ax.set_xlabel(r"$w$") +plt.show() +``` + +保留工资位于 $v_e$ 与延续值函数(即拒绝的价值)的交点处。 + + +## 提高效率 + +上述求解方法工作得很好,但我们可以做得更好。 + +首先,我们使用就业工人的贝尔曼方程用 $Pv_u$ 来表示 $v_e$ + +$$ + v_e(w) = + \frac{1}{1-\beta(1-\alpha)} \cdot (u(w) + \alpha\beta(Pv_u)(w)) +$$ + +接下来我们代入失业个体的贝尔曼方程得到 + ++++ + +$$ + v_u(w) = + \max + \left\{ + \frac{1}{1-\beta(1-\alpha)} \cdot (u(w) + \alpha\beta(Pv_u)(w)), + u(c) + \beta(Pv_u)(w) + \right\} +$$ + +然后我们使用价值函数迭代来求解 $v_u$。 + +有了 $v_u$,我们可以通过上面的方程恢复 $v_e$,然后计算保留工资。 + +以下是失业工人价值函数的新贝尔曼算子: + +```{code-cell} ipython3 +def T(v: jnp.ndarray, model: Model) -> jnp.ndarray: + """ + v_u 的贝尔曼算子。 + + """ + n, w_vals, P, P_cumsum, β, c, α, γ = model + d = 1 / (1 - β * (1 - α)) + v_e = d * (u(w_vals, γ) + α * β * P @ v) + h = u(c, γ) + β * P @ v + return jnp.maximum(v_e, h) +``` + +这里是一个价值函数迭代的例程。 + +```{code-cell} ipython3 +@jax.jit +def vfi( + model: Model, + tolerance: float = 1e-6, # 误差容限 + max_iter: int = 100_000, # 最大迭代界限 + ): + + v_init = jnp.zeros(model.w_vals.shape) + + def cond(loop_state): + v, error, i = loop_state + return (error > tolerance) & (i <= max_iter) + + def update(loop_state): + v, error, i = loop_state + v_new = T(v, model) + error = jnp.max(jnp.abs(v_new - v)) + new_loop_state = v_new, error, i + 1 + return new_loop_state + + initial_state = (v_init, tolerance + 1, 1) + final_loop_state = lax.while_loop(cond, update, initial_state) + v_final, error, i = final_loop_state + + return v_final +``` + +这里是一个从价值函数计算保留工资的例程。 + +```{code-cell} ipython3 +@jax.jit +def get_reservation_wage(v: jnp.ndarray, model: Model) -> float: + """ + 从失业个体的价值函数 v := v_u 计算保留工资。 + + 保留工资是使得接受 (v_e(w)) 至少和拒绝 (u(c) + β(Pv_u)(w)) + 一样好的最低工资 w。 + + """ + n, w_vals, P, P_cumsum, β, c, α, γ = model + + # 计算接受和拒绝值 + d = 1 / (1 - β * (1 - α)) + v_e = d * (u(w_vals, γ) + α * β * P @ v) + continuation_values = u(c, γ) + β * P @ v + + # 找到接受变为最优的位置 + accept_indices = v_e >= continuation_values + first_accept_idx = jnp.argmax(accept_indices) # 第一个 True 的索引 + + # 如果没有接受(全为 False),返回无穷大 + # 否则返回第一个接受索引处的工资 + return jnp.where(jnp.any(accept_indices), w_vals[first_accept_idx], jnp.inf) +``` + + +让我们使用新方法求解模型: + +```{code-cell} ipython3 +model = create_js_with_sep_model() +n, w_vals, P, P_cumsum, β, c, α, γ = model +v_u = vfi(model) +w_bar = get_reservation_wage(v_u, model) +``` + +让我们验证两种方法产生相同的保留工资: + +```{code-cell} ipython3 +print(f"Reservation wage (first method): {w_bar_first:.6f}") +print(f"Reservation wage (second method): {w_bar:.6f}") +print(f"Difference: {abs(w_bar - w_bar_first):.2e}") +``` + +接下来我们计算一些用于绘图的相关量。 + +```{code-cell} ipython3 +d = 1 / (1 - β * (1 - α)) +v_e = d * (u(w_vals, γ) + α * β * P @ v_u) +h = u(c, γ) + β * P @ v_u +``` + +让我们绘制结果。 + +```{code-cell} ipython3 +fig, ax = plt.subplots(figsize=(9, 5.2)) +ax.plot(w_vals, h, 'g-', linewidth=2, + label="延续值函数 $h$") +ax.plot(w_vals, v_e, 'b-', linewidth=2, + label="就业价值函数 $v_e$") +ax.legend(frameon=False) +ax.set_xlabel(r"$w$") +plt.show() +``` + +结果与之前相同,但我们只在一个数组上迭代——而且我们的 JAX 代码也更高效。 + + +## 敏感性分析 + +让我们检查保留工资如何随分离率变化。 + +```{code-cell} ipython3 +α_vals: jnp.ndarray = jnp.linspace(0.0, 1.0, 10) + +w_bar_vec = [] +for α in α_vals: + model = create_js_with_sep_model(α=α) + v_u = vfi(model) + w_bar = get_reservation_wage(v_u, model) + w_bar_vec.append(w_bar) + +fig, ax = plt.subplots(figsize=(9, 5.2)) +ax.plot( + α_vals, w_bar_vec, linewidth=2, alpha=0.6, label="保留工资" +) +ax.legend(frameon=False) +ax.set_xlabel(r"$\alpha$") +ax.set_ylabel(r"$w$") +plt.show() +``` + +你能为你在这幅图中看到的结果提供一个直观的经济学故事吗? + ++++ + +## 就业模拟 + +现在让我们模拟单个个体在最优策略下的就业动态。 + +请注意,当模拟工资报价的马尔可夫链时,我们需要多次从 $P$ 的每一行的分布中抽取。 + +为此,我们使用逆变换法:抽取一个均匀随机变量并找到它落在累积分布中的位置。 + +这通过在预先计算的累积和 `P_cumsum` 上使用 `jnp.searchsorted` 来实现,这比每次重新计算累积和要快得多。 + +函数 `update_agent` 将个体的状态推进一期。 + +个体的状态是一个对 $(S_t, W_t)$,其中 $S_t$ 是就业状态(0 表示失业,1 表示就业),$W_t$ 是 + +* 他们当前的工资报价(如果失业),或 +* 他们当前的工资(如果就业)。 + +```{code-cell} ipython3 +def update_agent(key, status, wage_idx, model, w_bar): + """ + 更新个体的就业状态和当前工资。 + + 参数: + - key: JAX 随机密钥 + - status: 当前就业状态(0 或 1) + - wage_idx: 当前工资,记录为数组索引 + - model: Model 实例 + - w_bar: 保留工资 + + """ + n, w_vals, P, P_cumsum, β, c, α, γ = model + + key1, key2 = jax.random.split(key) + # 使用预先计算的累积和通过逆变换法 + # 进行高效抽样。 + new_wage_idx = jnp.searchsorted( + P_cumsum[wage_idx, :], jax.random.uniform(key1) + ) + separation_occurs = jax.random.uniform(key2) < α + # 如果当前工资达到或超过保留工资则接受 + accepts = w_vals[wage_idx] >= w_bar + + # 如果就业:无分离则 status = 1,有分离则 status = 0 + # 如果失业:接受则 status = 1,拒绝则 status = 0 + next_status = jnp.where( + status, + 1 - separation_occurs.astype(jnp.int32), # 就业路径 + accepts.astype(jnp.int32) # 失业路径 + ) + + # 如果就业:无分离则工资 = 当前,有分离则工资 = 新的 + # 如果失业:接受则工资 = 当前,拒绝则工资 = 新的 + next_wage = jnp.where( + status, + jnp.where(separation_occurs, new_wage_idx, wage_idx), # 就业路径 + jnp.where(accepts, wage_idx, new_wage_idx) # 失业路径 + ) + + return next_status, next_wage +``` + +这里是一个模拟单个个体就业路径的函数。 + +```{code-cell} ipython3 +def simulate_employment_path( + model: Model, # 模型细节 + w_bar: float, # 保留工资 + T: int = 2_000, # 模拟长度 + seed: int = 42 # 为模拟设置种子 + ): + """ + 从失业开始模拟 T 期的就业路径。 + + """ + key = jax.random.PRNGKey(seed) + # 解包模型 + n, w_vals, P, P_cumsum, β, c, α, γ = model + + # 初始条件 + status = 0 + wage_idx = 0 + + wage_path = [] + status_path = [] + + for t in range(T): + wage_path.append(w_vals[wage_idx]) + status_path.append(status) + + key, subkey = jax.random.split(key) + status, wage_idx = update_agent( + subkey, status, wage_idx, model, w_bar + ) + + return jnp.array(wage_path), jnp.array(status_path) +``` + +让我们创建一个就业模拟的综合图: + +```{code-cell} ipython3 +model = create_js_with_sep_model() + +# 计算用于绘图的保留工资 +v_u = vfi(model) +w_bar = get_reservation_wage(v_u, model) + +wage_path, employment_status = simulate_employment_path(model, w_bar) + +fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(8, 6)) + +# 绘制就业状态 +ax1.plot(employment_status, 'b-', alpha=0.7, linewidth=1) +ax1.fill_between( + range(len(employment_status)), employment_status, alpha=0.3, color='blue' +) +ax1.set_ylabel('就业状态') +ax1.set_title('就业路径(0=失业,1=就业)') +ax1.set_xticks((0, 1)) +ax1.set_ylim(-0.1, 1.1) + +# 绘制带就业状态着色的工资路径 +ax2.plot(wage_path, 'b-', alpha=0.7, linewidth=1) +ax2.axhline(y=w_bar, color='black', linestyle='--', alpha=0.8, + label=f'保留工资:{w_bar:.2f}') +ax2.set_xlabel('时间') +ax2.set_ylabel('工资') +ax2.set_title('工资路径(实际和报价)') +ax2.legend() + +# 绘制失业时间的累积比例 +unemployed_indicator = (employment_status == 0).astype(int) +cumulative_unemployment = ( + jnp.cumsum(unemployed_indicator) / + jnp.arange(1, len(employment_status) + 1) +) + +ax3.plot(cumulative_unemployment, 'r-', alpha=0.8, linewidth=2) +ax3.axhline(y=jnp.mean(unemployed_indicator), color='black', + linestyle='--', alpha=0.7, + label=f'最终比率:{jnp.mean(unemployed_indicator):.3f}') +ax3.set_xlabel('时间') +ax3.set_ylabel('累积失业率') +ax3.set_title('失业时间的累积比例') +ax3.legend() +ax3.set_ylim(0, 1) + +plt.tight_layout() +plt.show() +``` + +该模拟有助于可视化与此模型相关的结果。 + +个体遵循一个保留工资策略。 + +个体经常失去工作,然后立即以不同的工资接受另一份工作。 + +这是因为她使用上一份工作的工资 $w$ 通过 $P(w, \cdot)$ 抽取一个新的工资报价,而正相关意味着高的当前 $w$ 往往导致高的新抽取值。 + ++++ + +## 遍历性 + +下面我们检查横截面失业。 + +特别地,我们将查看横截面模拟中的失业率,并将其与时间平均失业率进行比较,后者是个体在很长时间序列中处于失业状态的时间比例。 + +我们将看到这两个值近似相等——事实上在极限情形下它们完全相等。 + +原因是过程 $(S_t, W_t)$,其中 + +- $S_t$ 是就业状态,以及 +- $W_t$ 是工资 + +是马尔可夫的,因为下一对仅取决于当前对和独立同分布的随机性,并且是遍历的。 + +遍历性作为不可约性的结果而成立。 + +事实上,从任何(状态,工资)对,一个个体最终都可以到达任何其他(状态,工资)对。 + +这成立是因为: + +- 失业个体可以通过接受报价而就业 +- 就业个体可以通过分离而失业(概率 $\alpha$) +- 工资过程可以在所有工资状态之间转移(因为 $P$ 本身是不可约的) + +这些性质确保了链是遍历的,并在状态 $(s, w)$ 上有唯一的平稳分布 $\pi$。 + +对于一个遍历马尔可夫链,遍历定理保证了时间平均 = 横截面平均。 + +特别地,单个个体处于失业状态的时间比例(跨所有工资状态)收敛到横截面失业率: + +$$ + \lim_{T \to \infty} \frac{1}{T} \sum_{t=1}^{T} \mathbb{1}\{S_t = \text{unemployed}\} = \sum_{w=1}^{n} \pi(\text{unemployed}, w) +$$ + +无论初始条件如何,这都成立——前提是我们对横截面分布进行预热(从给定的初始横截面向前推进,以消除该初始条件的影响)。 + +因此,我们可以通过以下方式研究稳态失业: + +- 长时间跟踪一个个体(时间平均),或 +- 在单个时间点观察许多个体(横截面平均) + +对于我们的目的,第二种方法通常更好,因为它更容易并行化。 + ++++ + +## 横截面分析 + +现在让我们同时模拟许多个体来检查横截面失业率。 + +为了高效地做到这一点,我们需要一种与上面定义的 `simulate_employment_path` 不同的方法。 + +关键区别在于: + +- `simulate_employment_path` 记录单个个体的整个历史(所有 T 期),这对可视化有用但占用内存 +- 下面的新函数 `sim_agent` 只跟踪并返回最终状态,这就是我们进行横截面统计所需的全部内容 +- `sim_agent` 使用 `lax.fori_loop` 而不是 Python 循环,使其可 JIT 编译并适用于跨许多个体的向量化 + +我们首先定义一个将单个个体向前模拟 T 个时间步的函数: + +```{code-cell} ipython3 +@jax.jit +def sim_agent(key, initial_status, initial_wage_idx, model, w_bar, T): + """ + 使用 lax.fori_loop 将单个个体向前模拟 T 个时间步。 + + 使用 fold_in 在每个时间步生成一个新的密钥。 + + 参数: + - key: 此个体的 JAX 随机密钥 + - initial_status: 初始就业状态(0 或 1) + - initial_wage_idx: 初始工资索引 + - model: Model 实例 + - w_bar: 保留工资 + - T: 要模拟的时间期数 + + 返回: + - final_status: T 期后的就业状态 + - final_wage_idx: T 期后的工资索引 + """ + def update(t, loop_state): + status, wage_idx = loop_state + step_key = jax.random.fold_in(key, t) + status, wage_idx = update_agent(step_key, status, wage_idx, model, w_bar) + return status, wage_idx + + initial_loop_state = (initial_status, initial_wage_idx) + final_loop_state = lax.fori_loop(0, T, update, initial_loop_state) + final_status, final_wage_idx = final_loop_state + return final_status, final_wage_idx + + +# 创建 sim_agent 的向量化版本以并行处理多个个体 +sim_agents_vmap = jax.vmap(sim_agent, in_axes=(0, 0, 0, None, None, None)) + + +def simulate_cross_section( + model: Model, # 带参数的 Model 实例 + n_agents: int = 100_000, # 要模拟的个体数 + T: int = 200, # 预热长度 + seed: int = 42 # 用于可重复性 + ) -> float: + """ + 模拟个体横截面并返回失业率。 + + 这种方法: + 1. 生成 n_agents 个随机密钥 + 2. 为每个个体调用 sim_agent(通过 vmap 向量化) + 3. 收集最终状态以产生横截面 + + 返回横截面失业率。 + """ + key = jax.random.PRNGKey(seed) + + # 求解最优保留工资 + v_u = vfi(model) + w_bar = get_reservation_wage(v_u, model) + + # 初始化数组 + initial_wage_indices = jnp.zeros(n_agents, dtype=jnp.int32) + initial_status_vec = jnp.zeros(n_agents, dtype=jnp.int32) + + # 生成 n_agents 个随机密钥 + agent_keys = jax.random.split(key, n_agents) + + # 将每个个体向前模拟 T 步(向量化) + final_status, final_wage_idx = sim_agents_vmap( + agent_keys, initial_status_vec, initial_wage_indices, model, w_bar, T + ) + + unemployment_rate = 1 - jnp.mean(final_status) + return unemployment_rate +``` + +此函数生成一个显示许多个体间就业状态分布的直方图: + +```{code-cell} ipython3 +def plot_cross_sectional_unemployment( + model: Model, + t_snapshot: int = 200, # 横截面快照的时间 + n_agents: int = 20_000 # 要模拟的个体数 + ): + """ + 生成特定时间的横截面失业直方图。 + + """ + # 直接获取最终就业状态 + key = jax.random.PRNGKey(42) + v_u = vfi(model) + w_bar = get_reservation_wage(v_u, model) + + # 初始化数组 + initial_wage_indices = jnp.zeros(n_agents, dtype=jnp.int32) + initial_status_vec = jnp.zeros(n_agents, dtype=jnp.int32) + + # 生成 n_agents 个随机密钥 + agent_keys = jax.random.split(key, n_agents) + + # 将每个个体向前模拟 T 步(向量化) + final_status, _ = sim_agents_vmap( + agent_keys, initial_status_vec, initial_wage_indices, model, w_bar, t_snapshot + ) + + # 计算失业率 + unemployment_rate = 1 - jnp.mean(final_status) + + fig, ax = plt.subplots(figsize=(8, 5)) + + # 将直方图绘制为密度(条形之和为 1) + weights = jnp.ones_like(final_status) / len(final_status) + ax.hist(final_status, bins=[-0.5, 0.5, 1.5], + alpha=0.7, color='blue', edgecolor='black', + density=True, weights=weights) + + ax.set_xlabel('就业状态(0=失业,1=就业)') + ax.set_ylabel('密度') + ax.set_title(f't={t_snapshot} 时的横截面分布,' + + f'失业率 = {unemployment_rate:.3f}') + ax.set_xticks([0, 1]) + + plt.tight_layout() + plt.show() +``` + +现在让我们比较时间平均失业率(来自单个个体的长时间模拟)与横截面失业率(来自单个时间点的许多个体)。 + +我们在上面声称,由于遍历性,这些数字在大样本中将近似相等。 + +让我们看看这是否属实。 + +```{code-cell} ipython3 +model = create_js_with_sep_model() +cross_sectional_unemp = simulate_cross_section( + model, n_agents=20_000, T=200 +) + +time_avg_unemp = jnp.mean(unemployed_indicator) +print(f"Time-average unemployment rate (single agent): " + f"{time_avg_unemp:.4f}") +print(f"Cross-sectional unemployment rate (at t=200): " + f"{cross_sectional_unemp:.4f}") +print(f"Difference: {abs(time_avg_unemp - cross_sectional_unemp):.4f}") +``` + +确实,它们非常接近。 + +现在让我们可视化横截面分布: + +```{code-cell} ipython3 +plot_cross_sectional_unemployment(model) +``` + +## 更低的失业补偿(c=0.5) + +当失业补偿更低时,横截面失业率会发生什么变化? + +```{code-cell} ipython3 +model_low_c = create_js_with_sep_model(c=0.5) +plot_cross_sectional_unemployment(model_low_c) +``` + +## 练习 + +```{exercise-start} +:label: mmwsm_ex1 +``` + +创建一幅图,更仔细地研究稳态横截面失业率如何随失业补偿变化。 + +尝试一系列失业补偿 `c` 的值,例如 `c = 0.2, 0.4, 0.6, 0.8, 1.0`。 +对于每个值,计算稳态横截面失业率并将其对 `c` 作图。 + +你观察到失业补偿与失业率之间存在什么关系? + +```{exercise-end} +``` + +```{solution-start} mmwsm_ex1 +:class: dropdown +``` + +我们为不同的失业补偿值计算稳态失业率: + +```{code-cell} ipython3 +c_values = 1.0, 0.8, 0.6, 0.4, 0.2 +rates = [] +for c in c_values: + model = create_js_with_sep_model(c=c) + unemployment_rate = simulate_cross_section(model) + rates.append(unemployment_rate) + +fig, ax = plt.subplots() +ax.plot( + c_values, rates, alpha=0.8, + linewidth=1.5, label='稳态失业率' +) +ax.set_xlabel('失业补偿 (c)') +ax.set_ylabel('失业率') +ax.legend(frameon=False) +plt.show() +``` + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/measurement_models.md b/lectures/measurement_models.md new file mode 100644 index 0000000..270f998 --- /dev/null +++ b/lectures/measurement_models.md @@ -0,0 +1,1269 @@ +--- +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 +translation: + title: 两种测量模型与投资加速数 + headings: + Overview: 概述 + The economic model: 经济模型 + The economic model::Optimal decision rule: 最优决策规则 + The economic model::Net income and the accelerator: 净收入与加速数 + The economic model::The accelerator puzzle: 加速数之谜 + The economic model::State-space formulation: 状态空间表述 + The economic model::True impulse responses: 真实脉冲响应 + Measurement errors: 测量误差 + A classical model of measurements initially collected by an agency: 一个由机构最初收集的经典测量模型 + A classical model of measurements initially collected by an agency::Quasi-differencing: 拟差分 + A classical model of measurements initially collected by an agency::Innovations representation: 新息表示 + A classical model of measurements initially collected by an agency::Wold representation: Wold 表示 + A classical model of measurements initially collected by an agency::Computing coefficients in a Wold moving average representation: 计算 Wold 移动平均表示中的系数 + A classical model of measurements initially collected by an agency::Gaussian likelihood: 高斯似然 + A classical model of measurements initially collected by an agency::Forecast-error-variance decomposition: 预测误差方差分解 + A classical model of measurements initially collected by an agency::Wold impulse responses: Wold 脉冲响应 + A model of optimal estimates reported by an agency: 一个由机构报告最优估计的模型 + A model of optimal estimates reported by an agency::Innovations representation for filtered data: 滤波数据的新息表示 + A model of optimal estimates reported by an agency::Wold representation: Wold 表示 + A model of optimal estimates reported by an agency::Gaussian likelihood: 高斯似然 + A model of optimal estimates reported by an agency::Forecast-error-variance decomposition: 预测误差方差分解 + A model of optimal estimates reported by an agency::Wold impulse responses: Wold 脉冲响应 + Simulation: 模拟 + Summary: 总结 +--- + +(measurement_models)= +```{raw} jupyter + +``` + +# 两种测量模型与投资加速数 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +"理性预期计量经济学"旨在用对经济学家有意义的对象来解释经济时间序列,即描述偏好、技术、信息集、禀赋和均衡概念的参数。 + +当完全推导出来后,理性预期模型通常给出从这些具有经济可解释性的参数到模型所决定的时间序列各阶矩的一个明确定义的映射。 + +如果能够获得这些时间序列的准确观测数据,就可以利用这个映射实现基于似然函数或矩方法的参数估计方法。 + +```{note} 这就是为什么计量经济学估计常被称为"逆"问题,而对给定参数值模拟一个模型被称为"正"问题。正问题指的是我们刚刚描述的映射,而逆问题则涉及以某种方式将该映射的"逆"应用于一个数据集,这个数据集被视为来自该映射所描述的联合概率分布的一次抽样。 +``` + +然而,如果所关心的变量只存在含误差的数据,那么提取参数估计就需要更多步骤。 + +实际上,我们需要一个数据报告机构的模型,这个模型要足够可操作,以便我们能够确定由动态经济模型和测量过程共同诱导出的、通往测量数据概率律的映射。 + +为数据收集机构选择的模型是计量经济学设定的一个方面,它可能对关于经济结构的推断产生重大影响。 + +{cite:t}`Sargent1989` 描述了在一个 {doc}`永久收入 ` 经济中的两种备选数据生成模型,其中投资加速数——即这两个 quantecon 讲座 {doc}`samuelson` 和 {doc}`chow_business_cycles` 所研究的机制——塑造了商业周期波动。 + +- 在模型1中,数据收集机构只是报告它所收集的含误差数据。 +- 在模型2中,数据收集机构首先收集满足经典的变量含误差模型的含误差数据,然后对数据进行滤波,并报告滤波后的对象。 + +尽管这两个模型具有相同的"深层参数",但它们对数据产生了截然不同的约束集。 + +在本讲座中,我们遵循 {cite:t}`Sargent1989` 并研究这些不同的测量方案如何影响实证含义。 + +我们首先导入本讲座中将用于生成 LaTeX 输出的库和辅助函数 + +```{code-cell} ipython3 +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from scipy import linalg +from IPython.display import Latex + +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n + +np.set_printoptions(precision=3, suppress=True) + +def df_to_latex_matrix(df, label=''): + """Convert DataFrame to LaTeX matrix.""" + lines = [r'\begin{bmatrix}'] + + for idx, row in df.iterrows(): + row_str = ' & '.join( + [f'{v:.4f}' if isinstance(v, (int, float)) + else str(v) for v in row]) + r' \\' + lines.append(row_str) + + lines.append(r'\end{bmatrix}') + + if label: + return '$' + label + ' = ' + '\n'.join(lines) + '$' + else: + return '$' + '\n'.join(lines) + '$' + +def df_to_latex_array(df): + """Convert DataFrame to LaTeX array.""" + n_rows, n_cols = df.shape + + # 构建列格式(居中列) + col_format = 'c' * (n_cols + 1) # +1 用于索引 + + # 开始数组 + lines = [r'\begin{array}{' + col_format + '}'] + + # 表头行 + header = ' & '.join([''] + [str(c) for c in df.columns]) + r' \\' + lines.append(header) + lines.append(r'\hline') + + # 数据行 + for idx, row in df.iterrows(): + row_str = str(idx) + ' & ' + ' & '.join( + [f'{v:.3f}' if isinstance(v, (int, float)) else str(v) + for v in row]) + r' \\' + lines.append(row_str) + + lines.append(r'\end{array}') + + return '$' + '\n'.join(lines) + '$' +``` + +## 经济模型 + +数据由一个线性二次型版本的随机最优增长模型生成,该模型是本 quantecon 讲座 {doc}`perm_income` 中所描述模型的一个实例。 + +社会计划者选择 $\{c_t, k_{t+1}\}_{t=0}^\infty$ 的一个随机过程以最大化 + +```{math} +:label: planner_obj +E \sum_{t=0}^{\infty} \beta^t \left( u_0 + u_1 c_t - \frac{u_2}{2} c_t^2 \right) +``` + +受技术所施加的约束限制 + +```{math} +:label: tech_constraint +c_t + k_{t+1} = f k_t + \theta_t, \qquad \beta f^2 > 1. +``` + +这里 $c_t$ 是消费,$k_t$ 是资本存量,$f$ 是资本的总回报率,$\theta_t$ 是遵循下式的禀赋或技术冲击 + +```{math} +:label: shock_process +a(L)\,\theta_t = \varepsilon_t, +``` +其中 $L$ 是后移(或"滞后")算子,$a(z) = 1 - a_1 z - a_2 z^2 - \cdots - a_r z^r$ 的所有零点都在单位圆之外。 + +### 最优决策规则 + +$c_t$ 的最优决策规则是 + +```{math} +:label: opt_decision +c_t = \frac{-\alpha}{f-1} + + \left(1 - \frac{1}{\beta f^2}\right) + \frac{L - f^{-1} a(f^{-1})^{-1} a(L)}{L - f^{-1}}\,\theta_t + + f k_t, +\qquad +k_{t+1} = f k_t + \theta_t - c_t, +``` + +其中 $\alpha = u_1[1-(\beta f)^{-1}]/u_2$。 + +方程 {eq}`shock_process` 和 {eq}`opt_decision` 展现了理性预期模型所特有的跨方程约束。 + +### 净收入与加速数 + +将净产出或国民收入定义为 + +```{math} +:label: net_income +y_{nt} = (f-1)k_t + \theta_t. +``` + +注意 {eq}`tech_constraint` 和 {eq}`net_income` 蕴含 $(k_{t+1} - k_t) + c_t = y_{nt}$。 + +为了同时得到 {cite:t}`Friedman1956` 的几何分布滞后消费函数和一个分布滞后加速数,我们施加两个假设: + +1. $a(L) = 1$,使得 $\theta_t$ 是白噪声。 +2. $\beta f = 1$,使得资本回报率等于时间偏好率。 + +假设1对于加速数的严格形式至关重要。 + +放松它以允许序列相关的 $\theta_t$ 会在广义意义上保留一个加速数,但会丧失 {eq}`mm_accelerator` 的精确几何滞后形式。 + +加入第二个冲击会完全打破单指数结构,即使没有测量误差也能产生非平凡的格兰杰因果关系。 + +假设2不那么重要,只影响各种常数。 + +在这两个假设下,{eq}`opt_decision` 简化为 + +```{math} +:label: simple_crule +c_t = (1-f^{-1})\,\theta_t + (f-1)\,k_t. +``` + +当 {eq}`simple_crule`、{eq}`net_income` 和 {eq}`tech_constraint` 结合起来时,最优计划满足 + +```{math} +:label: friedman_consumption +c_t = \left(\frac{1-\beta}{1-\beta L}\right) y_{nt}, +``` + +```{math} +:label: mm_accelerator +k_{t+1} - k_t = f^{-1} \left(\frac{1-L}{1-\beta L}\right) y_{nt}, +``` + +```{math} +:label: income_process +y_{nt} = \theta_t + (1-\beta)(\theta_{t-1} + \theta_{t-2} + \cdots). +``` + +方程 {eq}`friedman_consumption` 是弗里德曼的消费模型:消费是收入的几何分布滞后,其衰减系数 $\beta$ 等于贴现因子。 + +方程 {eq}`mm_accelerator` 是分布滞后加速数:投资是收入一阶差分的几何分布滞后。 + +这与 {cite:t}`Chow1968` 实证记录的机制相同(见 {doc}`chow_business_cycles`)。 + +方程 {eq}`income_process` 表明,可支配收入的一阶差分是一个一阶移动平均过程,其新息等于禀赋冲击 $\theta_t$ 的新息。 + +正如 {cite:t}`Muth1960` 所展示的,这样的过程可以通过几何分布滞后或"适应性预期"方案最优地预测。 + +### 加速数之谜 + +当所有变量都被准确测量并由单一冲击 $\theta_t$ 驱动时,$(c_t,\, k_{t+1}-k_t,\, y_{nt})$ 的谱密度矩阵在所有频率上的秩为1。 + +每个变量都是同一白噪声的一个可逆单边分布滞后,因此没有任何变量格兰杰引起任何其他变量。 + +然而,从实证上看,产出的度量格兰杰引起投资,但反之不然。 + +{cite:t}`Sargent1989` 表明测量误差可以解决这个谜题。 + +为说明这一点,首先假设产出 $y_{nt}$ 被完美测量,而消费和资本分别被与 $\theta_t$ 正交的序列相关测量误差 $v_{ct}$ 和 $v_{kt}$ 污染。 + +设 $\bar c_t$ 和 $\bar k_{t+1} - \bar k_t$ 表示测量到的序列。那么 + +```{math} +:label: meas_consumption +\bar c_t = \left(\frac{1-\beta}{1-\beta L}\right) y_{nt} + v_{ct}, +``` + +```{math} +:label: meas_investment +\bar k_{t+1} - \bar k_t + = \beta\left(\frac{1-L}{1-\beta L}\right) y_{nt} + + (v_{k,t+1} - v_{kt}), +``` + +```{math} +:label: income_process_ma +y_{nt} = \theta_t + (1-\beta)(\theta_{t-1} + \theta_{t-2} + \cdots). +``` + +在这种情况下,收入格兰杰引起消费和投资,但不被它们格兰杰引起。 + +当每个测量到的序列都被测量误差污染时,每个测量变量通常都会格兰杰引起每个其他变量。 + +这种格兰杰因果关系的强度,如通过 $j$ 步向前预测误差方差的分解来度量,取决于测量误差的相对方差。 + +在这种情况下,每个观测到的序列都将共同信号 $\theta_t$ 与特异性测量噪声混合在一起。 + +测量误差方差较低的序列更紧密地跟踪 $\theta_t$,因此它的新息包含更多关于其他序列未来值的信息。 + +因此,在预测误差方差分解中,对测量较好的序列的冲击在其他变量的 $j$ 步向前预测误差中占更大份额。 + +在像这样的单一共同指数模型中($\theta_t$ 是共同指数),测量较好的变量比测量较差的序列扩展出更多的格兰杰因果关系,反之则不然。 + +这种不对称性驱动了我们很快将观察到的数值结果。 + +### 状态空间表述 + +让我们将经济模型和测量过程映射到一个线性状态空间框架。 + +设 $f = 1.05$ 且 $\theta_t \sim \mathcal{N}(0, 1)$。 + +定义状态向量和观测向量 + +```{math} +x_t = \begin{bmatrix} k_t \\ \theta_t \end{bmatrix}, +\qquad +z_t = \begin{bmatrix} y_{nt} \\ c_t \\ \Delta k_t \end{bmatrix}, +``` + +使得无误差数据由状态空间系统描述 + +```{math} +:label: true_ss +\begin{aligned} +x_{t+1} &= A x_t + \varepsilon_t, \\ +z_t &= C x_t. +\end{aligned} +``` + +其中 $\varepsilon_t = \begin{bmatrix} 0 \\ \theta_t \end{bmatrix}$ 具有协方差 $E \varepsilon_t \varepsilon_t^\top = Q$,而各矩阵为 + +```{math} +A = \begin{bmatrix} +1 & f^{-1} \\ +0 & 0 +\end{bmatrix}, +\qquad +C = \begin{bmatrix} +f-1 & 1 \\ +f-1 & 1-f^{-1} \\ +0 & f^{-1} +\end{bmatrix}, +\qquad +Q = \begin{bmatrix} +0 & 0 \\ +0 & 1 +\end{bmatrix}. +``` + +$Q$ 是奇异的,因为只有一个随机性来源 $\theta_t$;给定 $\theta_t$,资本存量 $k_t$ 确定性地演化。 + +```{code-cell} ipython3 +# 真实经济的基线结构矩阵 +f = 1.05 +β = 1 / f + +A = np.array([ + [1.0, 1.0 / f], + [0.0, 0.0] +]) + +C = np.array([ + [f - 1.0, 1.0], + [f - 1.0, 1.0 - 1.0 / f], + [0.0, 1.0 / f] +]) + +Q = np.array([ + [0.0, 0.0], + [0.0, 1.0] +]) +``` + +(true-impulse-responses)= +### 真实脉冲响应 + +在引入测量误差之前,我们计算无误差变量对单位冲击 $\theta_0 = 1$ 的脉冲响应。 + +这个基准阐明了当我们稍后从无误差变量切换到统计机构报告的变量时会发生什么变化。 + +响应清楚地展示了投资加速数:对净收入 $y_n$ 的全部影响发生在滞后0处,而消费仅调整 $1 - f^{-1} \approx 0.048$,投资吸收余下部分。 + +从滞后1开始,经济处于新的稳态 + +```{code-cell} ipython3 +def table2_irf(A, C, n_lags=6): + x = np.array([0.0, 1.0]) # k_0 = 0, theta_0 = 1 + rows = [] + for j in range(n_lags): + y_n, c, d_k = C @ x + rows.append([y_n, c, d_k]) + x = A @ x + return pd.DataFrame(rows, columns=[r'y_n', r'c', r'\Delta k'], + index=pd.Index(range(n_lags), name='lag')) + +table2 = table2_irf(A, C, n_lags=6) +display(Latex(df_to_latex_array(table2))) +``` + +## 测量误差 + +让我们添加生成报告数据的测量层。 + +计量经济学家不直接观测 $z_t$,而是看到 $\bar z_t = z_t + v_t$,其中 $v_t$ 是一个测量误差向量。 + +测量误差遵循一个 AR(1) 过程 + +```{math} +:label: meas_error_ar1 +v_{t+1} = D v_t + \eta_t, +``` + +其中 $\eta_t$ 是一个向量白噪声,满足 $E \eta_t \eta_t^\top = \Sigma_\eta$ 且对所有 $t, s$ 有 $E \varepsilon_t v_s^\top = 0$。 + +参数为 + +```{math} +D = \operatorname{diag}(0.6, 0.7, 0.3), +\qquad +\sigma_\eta = (0.05, 0.035, 0.65), +``` + +因此 $v_t$ 的无条件协方差为 + +```{math} +R = \operatorname{diag}\!\left(\frac{\sigma_{\eta,i}^2}{1 - \rho_i^2}\right). +``` + +新息方差对消费最小($\sigma_\eta = 0.035$),其次是收入($\sigma_\eta = 0.05$),投资最大($\sigma_\eta = 0.65$)。 + +正如 {cite:t}`Sargent1989` 以及我们上面的讨论,对于格兰杰因果关系不对称性而言重要的是整个系统中的总体测量质量:产出测量相对较好,而投资测量相对较差。 + +```{code-cell} ipython3 +ρ = np.array([0.6, 0.7, 0.3]) +D = np.diag(ρ) + +# η_t 的新息标准差 +σ_η = np.array([0.05, 0.035, 0.65]) +Σ_η = np.diag(σ_η**2) + +# 测量误差 v_t 的无条件协方差 +R = np.diag((σ_η / np.sqrt(1.0 - ρ**2))**2) + +print(f"f = {f}, β = 1/f = {β:.6f}") +print() +display(Latex(df_to_latex_matrix(pd.DataFrame(A), 'A'))) +display(Latex(df_to_latex_matrix(pd.DataFrame(C), 'C'))) +display(Latex(df_to_latex_matrix(pd.DataFrame(D), 'D'))) +``` + +我们将分别分析这两种报告方案,但首先我们需要一个求解稳态卡尔曼增益和误差协方差的求解器。 + +下面的函数在里卡蒂方程上迭代直到收敛,返回卡尔曼增益 $K$、状态协方差 $S$ 和新息协方差 $V$ + +```{code-cell} ipython3 +def steady_state_kalman(A, C_obs, Q, R, W=None, tol=1e-13, max_iter=200_000): + """ + Solve steady-state Kalman equations for + x_{t+1} = A x_t + w_{t+1} + y_t = C_obs x_t + v_t + with cov(w)=Q, cov(v)=R, cov(w,v)=W. + """ + n = A.shape[0] + m = C_obs.shape[0] + if W is None: + W = np.zeros((n, m)) + + S = Q.copy() + for _ in range(max_iter): + V = C_obs @ S @ C_obs.T + R + K = (A @ S @ C_obs.T + W) @ np.linalg.inv(V) + S_new = Q + A @ S @ A.T - K @ V @ K.T + + if np.max(np.abs(S_new - S)) < tol: + S = S_new + break + S = S_new + + V = C_obs @ S @ C_obs.T + R + K = (A @ S @ C_obs.T + W) @ np.linalg.inv(V) + return K, S, V +``` + +有了所需的结构矩阵和工具,我们现在依次遵循 {cite:t}`Sargent1989` 的两种报告方案。 + +## 一个由机构最初收集的经典测量模型 + +数据收集机构观测到 $z_t$ 的一个含噪声版本,即 + +```{math} +:label: model1_obs +\bar z_t = C x_t + v_t. +``` + +我们称之为*模型1*:机构收集含噪声数据并在不滤波的情况下报告它们。 + +为了表示 $\bar z_t$ 过程的二阶矩,方便的做法是得到它的总体向量自回归。 + +向量自回归中的误差向量是 $\bar z_t$ 的新息,可以取为 Wold 移动平均表示中的白噪声,它可以通过"求逆"自回归表示得到。 + +总体向量自回归及其如何依赖于状态空间系统和测量误差过程的参数,为如何解释 $\bar z_t$ 的估计向量自回归提供了洞见。 + +构造向量自回归作为将 $\bar z_t$ 样本的似然作为自由参数 $\{A, C, D, Q, R\}$ 的函数进行计算的中间步骤也是有用的。 + +用于构造向量自回归表示的特定方法也被证明在构造最优报告机构模型时作为中间步骤是有用的。 + +我们使用递归(卡尔曼滤波)方法来获得 $\bar z_t$ 的向量自回归。 + +### 拟差分 + +因为测量误差 $v_t$ 是序列相关的,具有白噪声测量误差的标准卡尔曼滤波器不能直接应用于 $\bar z_t = C x_t + v_t$。 + +一个替代方法是用测量误差 AR 分量来增广状态向量(见 {cite:t}`Sargent1989` 的附录 B)。 + +这里我们采取 {cite:t}`Sargent1989` 中描述的拟差分路线,它将系统简化为一个具有序列不相关观测噪声的系统。 + +定义 + +```{math} +:label: model1_qd +\tilde z_t = \bar z_{t+1} - D \bar z_t, \qquad +\bar\nu_t = C \varepsilon_t + \eta_t, \qquad +\bar C = CA - DC. +``` + +那么状态空间系统 {eq}`true_ss`、测量误差过程 {eq}`meas_error_ar1` 和观测方程 {eq}`model1_obs` 蕴含状态空间系统 + +```{math} +:label: model1_transformed +\begin{aligned} +x_{t+1} &= A x_t + \varepsilon_t, \\ +\tilde z_t &= \bar C\, x_t + \bar\nu_t, +\end{aligned} +``` + +其中 $(\varepsilon_t, \bar\nu_t)$ 是一个白噪声过程,满足 + +```{math} +:label: model1_covs +E \begin{bmatrix} \varepsilon_t \end{bmatrix} +\begin{bmatrix} \varepsilon_t^\top & \bar\nu_t^\top \end{bmatrix} += \begin{bmatrix} Q & W_1 \\ W_1^\top & R_1 \end{bmatrix}, +\qquad +R_1 = C Q C^\top + R, \quad W_1 = Q C^\top. +``` + +具有协方差 {eq}`model1_covs` 的系统 {eq}`model1_transformed` 由五个矩阵 $[A, \bar C, Q, R_1, W_1]$ 刻画。 + +### 新息表示 + +与 {eq}`model1_transformed` 和 {eq}`model1_covs` 相关联的是 $\tilde z_t$ 的**新息表示**, + +```{math} +:label: model1_innov +\begin{aligned} +\hat x_{t+1} &= A \hat x_t + K_1 u_t, \\ +\tilde z_t &= \bar C \hat x_t + u_t, +\end{aligned} +``` + +其中 + +```{math} +:label: model1_innov_defs +\begin{aligned} +\hat x_t &= E[x_t \mid \tilde z_{t-1}, \tilde z_{t-2}, \ldots, \hat x_0] + = E[x_t \mid \bar z_t, \bar z_{t-1}, \ldots], \\ +u_t &= \tilde z_t - E[\tilde z_t \mid \tilde z_{t-1}, \tilde z_{t-2}, \ldots] + = \bar z_{t+1} - E[\bar z_{t+1} \mid \bar z_t, \bar z_{t-1}, \ldots], +\end{aligned} +``` + +$[K_1, S_1]$ 由应用于 $[A, \bar C, Q, R_1, W_1]$ 的稳态卡尔曼滤波器计算,且 + +```{math} +:label: model1_S1 +S_1 = E[(x_t - \hat x_t)(x_t - \hat x_t)^\top]. +``` + +由 {eq}`model1_innov_defs`,$u_t$ 是 $\bar z_t$ 过程的新息过程。 + +### Wold 表示 + +系统 {eq}`model1_innov` 和定义 {eq}`model1_qd` 可用于得到 $\bar z_t$ 过程的 Wold 向量移动平均表示: + +```{math} +:label: model1_wold +\bar z_{t+1} = (I - DL)^{-1}\bigl[\bar C(I - AL)^{-1}K_1 L + I\bigr] u_t, +``` + +其中 $L$ 是滞后算子。 + +由 {eq}`model1_transformed` 和 {eq}`model1_innov`,新息协方差为 + +```{math} +:label: model1_V1 +V_1 = E\, u_t u_t^\top = \bar C\, S_1\, \bar C^\top + R_1. +``` + +下面我们数值计算 $K_1$、$S_1$ 和 $V_1$ + +```{code-cell} ipython3 +C_bar = C @ A - D @ C +R1 = C @ Q @ C.T + R +W1 = Q @ C.T + +K1, S1, V1 = steady_state_kalman(A, C_bar, Q, R1, W1) +``` + + +### 计算 Wold 移动平均表示中的系数 + +为了数值计算 {eq}`model1_wold` 中的移动平均系数,定义增广状态 + +```{math} +r_t = \begin{bmatrix} \hat x_{t-1} \\ \bar z_{t-1} \end{bmatrix}, +``` + +具有动态 + +```{math} +r_{t+1} = F_1 r_t + G_1 u_t, +\qquad +\bar z_t = H_1 r_t + u_t, +``` + +其中 + +```{math} +F_1 = +\begin{bmatrix} +A & 0 \\ +\bar C & D +\end{bmatrix}, +\quad +G_1 = +\begin{bmatrix} +K_1 \\ +I +\end{bmatrix}, +\quad +H_1 = [\bar C \;\; D]. +``` + +移动平均系数则为 $\psi_0 = I$ 和 $\psi_j = H_1 F_1^{j-1} G_1$(对 $j \geq 1$)。 + +```{code-cell} ipython3 +F1 = np.block([ + [A, np.zeros((2, 3))], + [C_bar, D] +]) +G1 = np.vstack([K1, np.eye(3)]) +H1 = np.hstack([C_bar, D]) + + +def measured_wold_coeffs(F, G, H, n_terms=25): + psi = [np.eye(3)] + Fpow = np.eye(F.shape[0]) + for _ in range(1, n_terms): + psi.append(H @ Fpow @ G) + Fpow = Fpow @ F + return psi + + +def fev_contributions(psi, V, n_horizons=20): + """ + Returns contrib[var, shock, h-1] = contribution at horizon h. + """ + P = linalg.cholesky(V, lower=True) + out = np.zeros((3, 3, n_horizons)) + for h in range(1, n_horizons + 1): + acc = np.zeros((3, 3)) + for j in range(h): + T = psi[j] @ P + acc += T**2 + out[:, :, h - 1] = acc + return out + + +psi1 = measured_wold_coeffs(F1, G1, H1, n_terms=40) +resp1 = np.array( + [psi1[j] @ linalg.cholesky(V1, lower=True) for j in range(14)]) +decomp1 = fev_contributions(psi1, V1, n_horizons=20) +``` + +### 高斯似然 + +样本 $\{\bar z_t,\, t=0,\ldots,T\}$ 的高斯对数似然函数,在给定初始状态估计 $\hat x_0$ 的条件下,可表示为 + +```{math} +:label: model1_loglik +\mathcal{L}^* = -T\ln 2\pi - \tfrac{1}{2}T\ln|V_1| + - \tfrac{1}{2}\sum_{t=0}^{T-1} u_t^\top V_1^{-1} u_t, +``` + +其中 $u_t$ 是由下面 {eq}`model1_recursion` 定义的 $\{\bar z_t\}$ 的函数。 + +为了使用 {eq}`model1_innov` 计算 $\{u_t\}$,有用的做法是将其表示为 + +```{math} +:label: model1_recursion +\begin{aligned} +\hat x_{t+1} &= (A - K_1 \bar C)\,\hat x_t + K_1 \tilde z_t, \\ +u_t &= -\bar C\,\hat x_t + \tilde z_t, +\end{aligned} +``` + +其中 $\tilde z_t = \bar z_{t+1} - D\bar z_t$ 是拟差分后的观测。 + +给定 $\hat x_0$,方程 {eq}`model1_recursion` 可以递归地用于计算一个 $\{u_t\}$ 过程。 + +方程 {eq}`model1_loglik` 和 {eq}`model1_recursion` 给出含误差数据样本 $\{\bar z_t\}$ 的似然函数。 + +### 预测误差方差分解 + +为了度量每个新息的相对重要性,我们分解每个测量变量的 $j$ 步向前预测误差方差。 + +写 $\bar z_{t+j} - E_t \bar z_{t+j} = \sum_{i=0}^{j-1} \psi_i u_{t+j-i}$。 + +设 $P$ 是 $V_1$ 的下三角 Cholesky 因子,使得正交化的新息为 $e_t = P^{-1} u_t$。 + +那么正交化新息 $k$ 对变量 $m$ 的 $j$ 步向前方差的贡献为 $\sum_{i=0}^{j-1} (\psi_i P)_{mk}^2$。 + +下表显示了在视界1到20下每个正交化新息对 $y_n$、$c$ 和 $\Delta k$ 预测误差方差的累积贡献。 + +每个面板固定一个正交化新息并报告其对每个变量预测误差方差的累积贡献。 + +行是预测视界,列是被预测的变量。 + +```{code-cell} ipython3 +horizons = np.arange(1, 21) +labels = [r'y_n', r'c', r'\Delta k'] + +def fev_table(decomp, shock_idx, horizons): + return pd.DataFrame( + np.round(decomp[:, shock_idx, :].T, 4), + columns=labels, + index=pd.Index(horizons, name='j') + ) +``` + +```{code-cell} ipython3 +shock_titles = [r'\text{A. Innovation in } y_n', + r'\text{B. Innovation in } c', + r'\text{C. Innovation in } \Delta k'] + +parts = [] +for i, title in enumerate(shock_titles): + arr = df_to_latex_array(fev_table(decomp1, i, horizons)).strip('$') + parts.append( + r'\begin{array}{c} ' + title + r' \\ ' + arr + r' \end{array}') + +display(Latex('$' + r' \quad '.join(parts) + '$')) +``` + +收入新息在所有三个变量中占预测误差方差的相当大比例,而消费和投资新息主要贡献于它们自身的方差。 + +这是一个**格兰杰因果关系**模式:收入似乎格兰杰引起消费和投资,但反之不然。 + +这与论文的信息相符,即在单一共同指数模型中,测量相对最好的序列具有最强的预测能力。 + +让我们看看新息的协方差矩阵 + +```{code-cell} ipython3 +print('Covariance matrix of innovations:') +df_v1 = pd.DataFrame(np.round(V1, 4), index=labels, columns=labels) +display(Latex(df_to_latex_matrix(df_v1))) +``` + +新息的协方差矩阵不是对角的,但如下所示,其特征值分离得很好 + + +```{code-cell} ipython3 +print('Eigenvalues of covariance matrix:') +print(np.sort(np.linalg.eigvalsh(V1))[::-1].round(4)) +``` + +第一个特征值远大于其他特征值,这与存在一个占主导地位的共同冲击 $\theta_t$ 相一致 + +### Wold 脉冲响应 + +Wold 表示中的脉冲响应使用正交化新息报告($V_1$ 的 Cholesky 分解,排序为 $y_n$、$c$、$\Delta k$)。 + +在此方法下,滞后0的响应反映了同期协方差和 Cholesky 排序两者。 + +我们首先定义一个辅助函数来将响应系数格式化为 LaTeX 数组 + +```{code-cell} ipython3 +lags = np.arange(14) + +def wold_response_table(resp, shock_idx, lags): + return pd.DataFrame( + np.round(resp[:, :, shock_idx], 4), + columns=labels, + index=pd.Index(lags, name='j') + ) +``` + +现在我们在一个具有三个面板的单一表格中报告对每个正交化新息的脉冲响应 + +```{code-cell} ipython3 +wold_titles = [r'\text{A. Response to } y_n \text{ innovation}', + r'\text{B. Response to } c \text{ innovation}', + r'\text{C. Response to } \Delta k \text{ innovation}'] + +parts = [] +for i, title in enumerate(wold_titles): + arr = df_to_latex_array(wold_response_table(resp1, i, lags)).strip('$') + parts.append( + r'\begin{array}{c} ' + title + r' \\ ' + arr + r' \end{array}') + +display(Latex('$' + r' \quad '.join(parts) + '$')) +``` + +在冲击时刻,第一个正交化新息载荷于所有三个测量变量。 + +在后续滞后处,收入新息在所有三个变量中产生持续的响应,因为作为测量最好的序列,它的新息由真实的永久冲击 $\theta_t$ 主导。 + +消费和投资新息产生的响应根据它们各自测量误差的 AR(1) 结构衰减($\rho_c = 0.7$,$\rho_{\Delta k} = 0.3$),对其他变量几乎没有溢出。 + +## 一个由机构报告最优估计的模型 + +假设数据收集机构不是报告含误差数据 $\bar z_t$,而是报告真实数据在含误差数据历史上的线性最小二乘投影。 + +这个模型提供了一种解释数据报告过程两个特征的可能方式。 + +- *季节调整*:如果 $v_t$ 的各分量有强季节性,最优滤波器将呈现一种可以部分地用季节调整滤波器来解释的形状,这种滤波器对当前和过去的 $\bar z_t$ 是单边的。 + +- *数据修正*:如果 $z_t$ 包含某个感兴趣变量的当前值和滞后值,那么该模型会同时确定"初步"、"修订"和"最终"估计,作为基于逐渐延长的含误差观测历史的连续条件期望。 + +为了使其可操作,我们赋予报告机构一个生成真实数据和测量误差的联合过程的模型。 + +我们假设报告机构具有"理性预期":它知道导致 {eq}`model1_transformed`--{eq}`model1_covs` 的经济和测量结构。 + +为了准备其估计,报告机构自己计算卡尔曼滤波器以获得新息表示 {eq}`model1_innov`。 + +报告机构不报告含误差数据 $\bar z_t$,而是报告 $\tilde z_t = G \hat x_t$,其中 $G$ 是一个"选择矩阵",对于机构所报告的数据可能等于 $C$。 + +数据 $G \hat x_t = E[G x_t \mid \bar z_t, \bar z_{t-1}, \ldots, \hat x_0]$。 + +报告数据的状态空间表示则为 + +```{math} +:label: model2_state +\begin{aligned} +\hat x_{t+1} &= A \hat x_t + K_1 u_t, \\ +\tilde z_t &= G \hat x_t, +\end{aligned} +``` + +其中 {eq}`model2_state` 的第一行来自新息表示 {eq}`model1_innov`。 + +注意 $u_t$ 是 $\bar z_{t+1}$ 的新息,而*不是* $\tilde z_t$ 的新息。 + +为了得到 $\tilde z_t$ 的 Wold 表示以及 $\tilde z_t$ 样本的似然函数,我们需要为 {eq}`model2_state` 得到一个新息表示。 + +### 滤波数据的新息表示 + +为了给 {eq}`model2_state` 增加一点一般性,我们将其修改为系统 + +```{math} +:label: model2_obs +\begin{aligned} +\hat x_{t+1} &= A \hat x_t + K_1 u_t, \\ +\tilde z_t &= G \hat x_t + \eta_t, +\end{aligned} +``` + +其中 $\eta_t$ 是一个第二类白噪声测量误差过程("打字错误"),假定其协方差矩阵 $R_2$ 非常小。 + +联合噪声的协方差矩阵为 + +```{math} +:label: model2_Q +E \begin{bmatrix} K_1 u_t \\ \eta_t \end{bmatrix} + \begin{bmatrix} K_1 u_t \\ \eta_t \end{bmatrix}^\top += \begin{bmatrix} Q_2 & 0 \\ 0 & R_2 \end{bmatrix}, +``` + +其中 $Q_2 = K_1 V_1 K_1^\top$。 + +如果 $R_2$ 是奇异的,就有必要通过使用诱导"降阶观测器"的变换来调整卡尔曼滤波公式。 + +在实践中,我们用矩阵 $\epsilon I$(其中 $\epsilon > 0$ 很小)来近似一个零 $R_2$ 矩阵,以保持卡尔曼滤波器数值上良态。 + +对于系统 {eq}`model2_obs` 和 {eq}`model2_Q`,一个新息表示为 + +```{math} +:label: model2_innov +\begin{aligned} +\check{x}_{t+1} &= A \check{x}_t + K_2 a_t, \\ +\tilde z_t &= G \check{x}_t + a_t, +\end{aligned} +``` + +其中 + +```{math} +:label: model2_innov_defs +\begin{aligned} +a_t &= \tilde z_t - E[\tilde z_t \mid \tilde z_{t-1}, \tilde z_{t-2}, \ldots], \\ +\check{x}_t &= E[\hat x_t \mid \tilde z_{t-1}, \tilde z_{t-2}, \ldots, \check{x}_0], \\ +S_2 &= E[(\hat x_t - \check{x}_t)(\hat x_t - \check{x}_t)^\top], \\ +[K_2, S_2] &= \text{kalmanfilter}(A, G, Q_2, R_2, 0). +\end{aligned} +``` + +因此 $\{a_t\}$ 是报告数据 $\tilde z_t$ 的新息过程,其新息协方差为 + +```{math} +:label: model2_V2 +V_2 = E\, a_t a_t^\top = G\, S_2\, G^\top + R_2. +``` + +### Wold 表示 + +由 {eq}`model2_innov` 得到 $\tilde z_t$ 的 Wold 移动平均表示为 + +```{math} +:label: model2_wold +\tilde z_t = \bigl[G(I - AL)^{-1} K_2 L + I\bigr] a_t, +``` + +系数为 $\psi_0 = I$ 和 $\psi_j = G A^{j-1} K_2$(对 $j \geq 1$)。 + +注意这比模型1的 Wold 表示 {eq}`model1_wold` 更简单,因为不需要撤销拟差分。 + +### 高斯似然 + +当使用类似于模型1的方法时,可以通过首先利用下式从 $\tilde z_t$ 的观测中计算一个 $\{a_t\}$ 序列来计算 $\tilde z_t$ 的高斯对数似然 + +```{math} +:label: model2_recursion +\begin{aligned} +\check{x}_{t+1} &= (A - K_2 G)\,\check{x}_t + K_2 \tilde z_t, \\ +a_t &= -G\,\check{x}_t + \tilde z_t. +\end{aligned} +``` + +$T$ 个观测样本 $\{\tilde z_t\}$ 的似然函数则为 + +```{math} +:label: model2_loglik +\mathcal{L}^{**} = -T\ln 2\pi - \tfrac{1}{2}T\ln|V_2| + - \tfrac{1}{2}\sum_{t=0}^{T-1} a_t^\top V_2^{-1} a_t. +``` + +注意相对于为含误差数据计算似然函数 {eq}`model1_loglik`,为最优滤波数据计算似然函数需要更多计算。 + +两个似然函数都要求计算卡尔曼滤波器 {eq}`model1_innov_defs`,而滤波数据的似然函数要求还要计算卡尔曼滤波器 {eq}`model2_innov_defs`。 + +实际上,为了解释和使用机构报告的滤波数据,有必要重新追溯机构用来合成这些数据的步骤。 + +卡尔曼滤波器 {eq}`model1_innov_defs` 应该由机构构建。 + +机构不需要使用卡尔曼滤波器 {eq}`model2_innov_defs`,因为它不需要滤波数据的 Wold 表示。 + +在我们的参数化中 $G = C$。 + +```{code-cell} ipython3 +Q2 = K1 @ V1 @ K1.T +ε = 1e-6 + +K2, S2, V2 = steady_state_kalman(A, C, Q2, ε * np.eye(3)) + + +def filtered_wold_coeffs(A, C, K, n_terms=25): + psi = [np.eye(3)] + Apow = np.eye(2) + for _ in range(1, n_terms): + psi.append(C @ Apow @ K) + Apow = Apow @ A + return psi + + +psi2 = filtered_wold_coeffs(A, C, K2, n_terms=40) +resp2 = np.array( + [psi2[j] @ linalg.cholesky(V2, lower=True) for j in range(14)]) +decomp2 = fev_contributions(psi2, V2, n_horizons=20) +``` + +### 预测误差方差分解 + +因为滤波数据几乎无噪声,新息协方差 $V_2$ 接近奇异,具有一个占主导地位的特征值。 + +这意味着滤波经济基本上由一个冲击驱动,就像真实经济一样 + +```{code-cell} ipython3 +parts = [] +for i, title in enumerate(shock_titles): + arr = df_to_latex_array(fev_table(decomp2, i, horizons)).strip('$') + parts.append( + r'\begin{array}{c} ' + title + r' \\ ' + arr + r' \end{array}') + +display(Latex('$' + r' \quad '.join(parts) + '$')) +``` + +在模型2中,第一个新息几乎占据所有预测误差方差,就像在真实经济中单个结构冲击 $\theta_t$ 驱动一切一样。 + +第二和第三个新息贡献可忽略不计。 + +这证实了滤波剥离了在模型1中制造多个独立变异来源假象的测量噪声。 + +模型2新息的协方差矩阵和特征值为 + +```{code-cell} ipython3 +print('Covariance matrix of innovations:') +df_v2 = pd.DataFrame(np.round(V2, 4), index=labels, columns=labels) +display(Latex(df_to_latex_matrix(df_v2))) +``` + +```{code-cell} ipython3 +print('Eigenvalues of covariance matrix:') +print(np.sort(np.linalg.eigvalsh(V2))[::-1].round(4)) +``` + +正如 {cite:t}`Sargent1989` 所强调的,尽管两个测量模型共享相同的底层参数,它们却对经济动态产生了截然不同的推断。 + +### Wold 脉冲响应 + +我们再次使用正交化 Wold 表示脉冲响应,采用 $V_2$ 的 Cholesky 分解,排序为 $y_n$、$c$、$\Delta k$。 + +```{code-cell} ipython3 +parts = [] +for i, title in enumerate(wold_titles): + arr = df_to_latex_array( + wold_response_table(resp2, i, lags)).strip('$') + parts.append( + r'\begin{array}{c} ' + title + r' \\ ' + arr + r' \end{array}') + +display(Latex('$' + r' \quad '.join(parts) + '$')) +``` + +模型2中的收入新息产生的响应紧密逼近来自结构冲击 $\theta_t$ 的真实脉冲响应函数。 + +读者可以将左表与上面 {ref}`true-impulse-responses` 部分中的表格进行比较。 + +数字本质上相同。 + +消费和投资新息产生的响应小几个数量级,证实滤波数据基本上由一个冲击驱动。 + +与模型1不同,模型2的滤波数据*无法*重现加速数文献实证记录的表观格兰杰因果关系模式。 + +因此,在总体层面上,尽管两个测量模型共享相同的结构经济,它们却蕴含不同的实证故事。 + +- 在模型1(原始数据)中,测量噪声制造出多个新息和一个表观格兰杰因果关系模式。 +- 在模型2(滤波数据)中,新息坍缩回本质上一个占主导地位的冲击,反映了真实的单指数经济。 + +让我们在一个有限样本模拟中验证这些含义。 + +## 模拟 + +上面的表格刻画了两个模型的总体矩。 + +让我们模拟80期的真实、测量和滤波数据,以将总体含义与有限样本行为进行比较。 + +首先,我们定义一个函数来模拟真实经济,生成带有 AR(1) 测量误差的测量数据,并应用模型1卡尔曼滤波器以产生滤波估计 + +```{code-cell} ipython3 +def simulate_series(seed=7909, T=80, k0=10.0): + """ + Simulate true, measured, and filtered series. + """ + rng = np.random.default_rng(seed) + + # 真实状态/可观测量 + θ = rng.normal(0.0, 1.0, size=T) + k = np.empty(T + 1) + k[0] = k0 + + y = np.empty(T) + c = np.empty(T) + dk = np.empty(T) + + for t in range(T): + x_t = np.array([k[t], θ[t]]) + y[t], c[t], dk[t] = C @ x_t + k[t + 1] = k[t] + (1.0 / f) * θ[t] + + # 带有 AR(1) 误差的测量数据 + v_prev = np.zeros(3) + v = np.empty((T, 3)) + for t in range(T): + η_t = rng.multivariate_normal(np.zeros(3), Σ_η) + v_prev = D @ v_prev + η_t + v[t] = v_prev + + z_meas = np.column_stack([y, c, dk]) + v + + # 通过模型1变换滤波器的滤波数据 + xhat_prev = np.array([k0, 0.0]) + z_prev = np.zeros(3) + z_filt = np.empty((T, 3)) + k_filt = np.empty(T) + + for t in range(T): + z_bar_t = z_meas[t] - D @ z_prev + u_t = z_bar_t - C_bar @ xhat_prev + xhat_t = A @ xhat_prev + K1 @ u_t + + z_filt[t] = C @ xhat_t + k_filt[t] = xhat_t[0] + + xhat_prev = xhat_t + z_prev = z_meas[t] + + out = { + "y_true": y, "c_true": c, "dk_true": dk, "k_true": k[:-1], + "y_meas": z_meas[:, 0], "c_meas": z_meas[:, 1], + "dk_meas": z_meas[:, 2], + "y_filt": z_filt[:, 0], "c_filt": z_filt[:, 1], + "dk_filt": z_filt[:, 2], "k_filt": k_filt + } + return out + + +sim = simulate_series(seed=7909, T=80, k0=10.0) +``` + +我们使用以下辅助函数将真实序列与测量序列或滤波序列进行对比绘图 + +```{code-cell} ipython3 +def plot_true_vs_other(t, true_series, other_series, + other_label, ylabel=""): + fig, ax = plt.subplots(figsize=(8, 4)) + ax.plot(t, true_series, lw=2, label="真实") + ax.plot(t, other_series, lw=2, ls="--", label=other_label) + ax.set_xlabel("时间") + ax.set_ylabel(ylabel) + ax.legend() + plt.tight_layout() + plt.show() + + +t = np.arange(1, 81) +``` + +让我们首先将真实序列与测量序列进行比较,以查看测量误差如何扭曲数据 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与测量的消费 + name: fig-true-measured-consumption + image: + alt: True and measured consumption plotted over 80 time periods +--- +plot_true_vs_other(t, sim["c_true"], sim["c_meas"], + "测量", ylabel="消费") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与测量的投资 + name: fig-true-measured-investment + image: + alt: True and measured investment plotted over 80 time periods +--- +plot_true_vs_other(t, sim["dk_true"], sim["dk_meas"], + "测量", ylabel="投资") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与测量的收入 + name: fig-true-measured-income + image: + alt: True and measured income plotted over 80 time periods +--- +plot_true_vs_other(t, sim["y_true"], sim["y_meas"], + "测量", ylabel="收入") +``` + +投资被扭曲得最厉害,因为它的测量误差具有最大的新息方差($\sigma_\eta = 0.65$),而收入被扭曲得最少($\sigma_\eta = 0.05$)。 + +对于滤波序列,我们期望卡尔曼滤波器通过剥离测量噪声来更紧密地恢复真实序列 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与滤波的消费 + name: fig-true-filtered-consumption + image: + alt: True and filtered consumption plotted over 80 time periods +--- +plot_true_vs_other(t, sim["c_true"], sim["c_filt"], + "滤波", ylabel="消费") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与滤波的投资 + name: fig-true-filtered-investment + image: + alt: True and filtered investment plotted over 80 time periods +--- +plot_true_vs_other(t, sim["dk_true"], sim["dk_filt"], + "滤波", ylabel="投资") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与滤波的收入 + name: fig-true-filtered-income + image: + alt: True and filtered income plotted over 80 time periods +--- +plot_true_vs_other(t, sim["y_true"], sim["y_filt"], + "滤波", ylabel="收入") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 真实与滤波的资本存量 + name: fig-true-filtered-capital + image: + alt: True and filtered capital stock plotted over 80 time periods +--- +plot_true_vs_other(t, sim["k_true"], sim["k_filt"], + "滤波", ylabel="资本存量") +``` + +事实上,来自模型1的卡尔曼滤波估计消除了大部分测量噪声,并紧密地跟踪真实值。 + +在真实模型中,国民收入恒等式 $c_t + \Delta k_t = y_{n,t}$ 精确成立。 + +独立的测量误差在测量数据中打破了这个会计恒等式。 + +卡尔曼滤波器近似地恢复了它。 + +下图通过显示测量和滤波数据两者的残差 $c_t + \Delta k_t - y_{n,t}$ 来证实这一点 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 国民收入恒等式残差 + name: fig-identity-residual +--- +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 4)) + +ax1.plot(t, sim["c_meas"] + sim["dk_meas"] - sim["y_meas"], lw=2) +ax1.axhline(0, color='black', lw=0.8, ls='--', alpha=0.5) +ax1.set_xlabel("时间") +ax1.set_ylabel("测量残差") + +ax2.plot(t, sim["c_filt"] + sim["dk_filt"] - sim["y_filt"], lw=2) +ax2.axhline(0, color='black', lw=0.8, ls='--', alpha=0.5) +ax2.set_xlabel("时间") +ax2.set_ylabel("滤波残差") + +plt.tight_layout() +plt.show() +``` + +正如我们所预测的,测量数据的残差大而波动,而滤波数据的残差在数值上为0。 + +## 总结 + +{cite:t}`Sargent1989` 展示了测量误差如何改变计量经济学家对由投资加速数驱动的永久收入经济的看法。 + +模型1(原始测量)和模型2(滤波测量)的 Wold 表示和方差分解存在显著差异,即使底层经济是相同的。 + +测量误差可以重塑关于哪些冲击驱动哪些变量的推断。 + +模型1重现了实证加速数文献中记录的**格兰杰因果关系**模式:收入似乎格兰杰引起消费和投资,{cite:t}`Sargent1989` 将这一结果归因于原始报告数据中的测量误差和信号提取。 + +模型2使用滤波数据,将几乎所有方差归因于单个结构冲击 $\theta_t$,并且*无法*重现格兰杰因果关系模式。 + +{doc}`卡尔曼滤波器 ` 有效地从数据中剥离了测量噪声,因此滤波序列紧密地跟踪真实值。 + +原始测量误差打破了国民收入会计恒等式,但接近零的残差表明滤波器近似地恢复了它。 \ No newline at end of file diff --git a/lectures/merging_of_opinions.md b/lectures/merging_of_opinions.md new file mode 100644 index 0000000..0576948 --- /dev/null +++ b/lectures/merging_of_opinions.md @@ -0,0 +1,1343 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 观点的融合:布莱克韦尔-杜宾斯定理 + headings: + Overview: 概述 + Probability measures on sequence spaces: 序列空间上的概率测度 + Probability measures on sequence spaces::The sequence space and its filtration: 序列空间及其滤流 + Probability measures on sequence spaces::Absolute continuity: 绝对连续性 + Probability measures on sequence spaces::Total variation distance: 全变差距离 + Probability measures on sequence spaces::The merging question: 融合问题 + The likelihood-ratio martingale: 似然比鞅 + The likelihood-ratio martingale::The likelihood ratio: 似然比 + The likelihood-ratio martingale::Connecting conditional measures to the likelihood ratio: 将条件测度与似然比联系起来 + The Blackwell–Dubins theorem: 布莱克韦尔-杜宾斯定理 + The Beta–Bernoulli model: 贝塔-伯努利模型 + The Beta–Bernoulli model::Model: 模型 + The Beta–Bernoulli model::The marginal likelihood and likelihood ratio: 边缘似然与似然比 + The Beta–Bernoulli model::The exact Blackwell–Dubins distance: 精确的布莱克韦尔-杜宾斯距离 + The Beta–Bernoulli model::Simulation: 模拟 + The Beta–Bernoulli model::Almost-sure convergence across many paths: 跨多条路径的几乎必然收敛 + The Beta–Bernoulli model::The supermartingale property of $d_n$: $d_n$ 的上鞅性质 + 'Failure of merging: mutual singularity': 融合的失败:相互奇异 + 'Failure of merging: mutual singularity::Point-mass priors': 点质量先验 + 'Kakutani''s theorem: when does merging hold?': 角谷定理:融合何时成立? + 'Kakutani''s theorem: when does merging hold?::Hellinger affinities': 海林格亲和度 + 'Kakutani''s theorem: when does merging hold?::Kakutani''s dichotomy': 角谷二分法 + 'Kakutani''s theorem: when does merging hold?::Implication for merging': 对融合的蕴含 + 'Kakutani''s theorem: when does merging hold?::A Gaussian product-measure example': 一个高斯乘积测度例子 + Extension to continuous time: 推广到连续时间 + Extension to continuous time::Girsanov's theorem and the likelihood-ratio process: 吉尔萨诺夫定理与似然比过程 + Extension to continuous time::The dichotomy at infinity: 无穷远处的二分法 + Applications: 应用 + Applications::Bayesian learning: 贝叶斯学习 + Applications::Rational expectations and heterogeneous priors: 理性预期与异质先验 + Applications::Ergodic Markov chains: 遍历马尔可夫链 + The rate of merging: 融合的速率 + Summary and extensions: 总结与推广 + Summary and extensions::Applications in economics: 经济学中的应用 + Summary and extensions::A companion result from probability: 一个来自概率论的配套结果 +--- + +(merging_of_opinions)= +```{raw} jupyter + +``` + +# 观点的融合:布莱克韦尔-杜宾斯定理 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲座研究 {cite:t}`blackwell1962` 的观点融合定理。 + +该定理提出了一个简单的问题: + +> 如果两个主体对某个随机过程持有不同的先验信念,但无限期地观察相同的数据流,他们的概率评估最终会收敛吗? + +在绝对连续性条件下,答案是肯定的。 + +如果 $Q \ll P$(即 $P$ 支配 $Q$),那么在 $P$ 和 $Q$ 下关于整个未来路径的条件分布会在全变差意义下融合,$Q$-几乎必然。 + +如果此外还有 $P \ll Q$(因而 $P \sim Q$),那么同样的结论在两个主体的概率下都成立。 + +这个结果与其他若干思想相关联: + +- 贝叶斯一致性:当先验位于正确的绝对连续性类中时,后验预测趋近于真值({doc}`likelihood_bayes`)。 +- 一致性结果:即使主体从不同的先验出发,共同的数据也能消除分歧({cite:t}`aumann1976`)。 +- 角谷二分法:对于乘积测度,等价性与奇异性可以从一个海林格准则中读出。 + +我们在离散时间中展开理论,然后勾勒连续时间的类比。 + +在整个讨论中,我们使用贝塔-伯努利模型作为贯穿始终的例子。 + +两个主体观察相同的抛硬币结果流,但从关于硬币偏差的不同先验出发。 + +让我们从一些导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.stats import beta as beta_dist +from scipy.special import betaln +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + + +## 序列空间上的概率测度 + +### 序列空间及其滤流 + +设 $(S, \mathscr{S})$ 是一个标准博雷尔空间(即与完备可分度量空间的一个博雷尔子集同构的可测空间),称为信号空间。 + +标准博雷尔假设保证了正则条件分布的存在性,这正是该定理所要求的。 + +令 $\Omega = S^{\mathbb{N}}$,即所有无限序列 +$\omega = (x_1, x_2, \ldots)$(其中 $x_n \in S$)的集合,配备乘积 +$\sigma$-代数 $\mathscr{F} = \mathscr{S}^{\otimes \mathbb{N}}$。 + +对于每个 $n \geq 1$,定义**有限视界** $\sigma$-代数 + +$$ +\mathscr{F}_n = \sigma(x_1, \ldots, x_n), +$$ + +因此 $\mathscr{F}_1 \subseteq \mathscr{F}_2 \subseteq \cdots \subseteq \mathscr{F}$。 + +定义**尾 $\sigma$-代数** $\mathscr{F}_\infty = \sigma\!\left(\bigcup_{n \geq 1} \mathscr{F}_n\right)$,它编码了最终能够学到的一切。 + +集合 $\{\mathscr{F}_n\}_{n \geq 1}$ 是由观察过程生成的**自然滤流**;$\mathscr{F}_n$ 编码了从前 $n$ 个数据点能够学到的一切。 + +设 $P$ 和 $Q$ 表示 $(\Omega, \mathscr{F})$ 上的两个概率测度。 + +记 $P_n = P|_{\mathscr{F}_n}$ 和 $Q_n = Q|_{\mathscr{F}_n}$ 表示它们 +限制到时刻 $n$ 之前的历史。 + +### 绝对连续性 + +```{prf:definition} 绝对连续性 +:label: absolute_continuity + +$P$ 关于 $Q$ **绝对连续**,记为 $P \ll Q$,如果对于每个 $A \in \mathscr{F}$, +$Q(A) = 0$ 蕴含 $P(A) = 0$。 + +它们**相互绝对连续**,或**等价**,记为 $P \sim Q$, +如果 $P \ll Q$ 和 $Q \ll P$ 都成立。 + +$P$ 关于 $Q$ **局部绝对连续**,如果对于每个 $n \geq 1$,$P_n \ll Q_n$。 +``` + +全局绝对连续性 $P \ll Q$ 蕴含局部绝对连续性,但 +反之不然。 + +相互绝对连续意味着两个主体在哪些事件是*可能的*这一点上意见一致。 + +他们可以对概率有不同看法,但都不会排除对方认为可能的事件。 + +### 全变差距离 + +```{prf:definition} 全变差距离 +:label: total_variation_distance + +对于 $(E, \mathscr{E})$ 上的两个概率测度 $\mu$ 和 $\nu$, + +$$ +\|\mu - \nu\|_{\mathrm{TV}} += \sup_{A \in \mathscr{E}} |\mu(A) - \nu(A)| += \frac{1}{2} \int_E \left|\frac{d\mu}{d\lambda} - \frac{d\nu}{d\lambda}\right| d\lambda, +$$ + +其中 $\lambda$ 是任意**支配测度**,即 $\mu \ll \lambda$ 且 $\nu \ll \lambda$(例如 $\lambda = \mu + \nu$)。 + +等价地,$\|\mu - \nu\|_{\mathrm{TV}} \in [0,1]$,其中 0 表示 $\mu = \nu$,1 表示 $\mu \perp \nu$(相互奇异)。 +``` + +当 $\mu \ll \nu$ 且 $f = d\mu/d\nu$ 时, + +$$ +\|\mu - \nu\|_{\mathrm{TV}} = \mathbb{E}_\nu[(f-1)^+] = 1 - \mathbb{E}_\nu[\min(f,1)]. +$$ + +```{exercise} +:label: tv_derivation + +证明上述恒等式。 + +*提示:*从 $\|\mu - \nu\|_{\mathrm{TV}} = \tfrac{1}{2}\,\mathbb{E}_\nu[|f - 1|]$(这由取 $\nu$ 作为支配测度得出)出发,并利用 $\mathbb{E}_\nu[f] = 1$ 这一事实。 +``` + +```{solution} tv_derivation +:class: dropdown + +由于 $\mu \ll \nu$,我们可以取 $\nu$ 作为支配测度,因此 $d\mu/d\nu = f$ 且 $d\nu/d\nu = 1$,给出 + +$$ +\|\mu - \nu\|_{\mathrm{TV}} = \tfrac{1}{2}\,\mathbb{E}_\nu[|f - 1|]. +$$ + +写出 $|f-1| = (f-1)^+ + (1-f)^+$。 + +由于 $\mu$ 是概率测度,$\mathbb{E}_\nu[f] = 1$,因此两部分贡献相等:$\mathbb{E}_\nu[(f-1)^+] = \mathbb{E}_\nu[(1-f)^+]$。 + +因此 $\tfrac{1}{2}\,\mathbb{E}_\nu[|f-1|] = \mathbb{E}_\nu[(f-1)^+]$。 + +接下来,注意 $(f-1)^+ = f - \min(f,1)$,所以 $\mathbb{E}_\nu[(f-1)^+] = \mathbb{E}_\nu[f] - \mathbb{E}_\nu[\min(f,1)] = 1 - \mathbb{E}_\nu[\min(f,1)]$。 +``` + +全变差是概率测度之间距离的最强的标准概念之一。 + +如果两个测度在全变差意义下接近,那么它们对每个事件的概率都接近。 + +### 融合问题 + +布莱克韦尔-杜宾斯定理研究给定*过去*时*未来*的条件分布。 + +在时刻 $n$,观察到 $(x_1,\ldots,x_n)$ 之后,每个主体对所有未来事件形成一个条件分布: + +$$ +P(\,\cdot\,|\,\mathscr{F}_n)(\omega), \qquad +Q(\,\cdot\,|\,\mathscr{F}_n)(\omega). +$$ + +这些是关于整个未来路径的概率测度,而不仅仅是下一个观察。 + +融合问题询问是否 + +$$ +d_n \;:=\; \bigl\|P(\,\cdot\,|\,\mathscr{F}_n) - Q(\,\cdot\,|\,\mathscr{F}_n)\bigr\|_{\mathrm{TV}} +\;\longrightarrow\; 0 +$$ + +当 $n \to \infty$ 时几乎必然成立。 + + +## 似然比鞅 + +我们的主要工具是拉东-尼科迪姆导数过程。 + +### 似然比 + +由于对于每个 $n$,$Q \ll P$ 蕴含 $Q_n \ll P_n$,拉东-尼科迪姆 +定理保证了似然比的存在性 + +$$ +Z_n = \frac{dQ_n}{dP_n}, \qquad Z_n \geq 0 \;\; P\text{-a.s.}, +\qquad \mathbb{E}_P[Z_n] = 1. +$$ + +关键的结构性质是,全局绝对连续性 $Q \ll P$ +蕴含在整个 $(\Omega, \mathscr{F})$ 上存在总体拉东-尼科迪姆导数 $Z = dQ/dP$, +并且 + +$$ +Z_n = \mathbb{E}_P[Z \,|\, \mathscr{F}_n] \qquad P\text{-a.s.} +$$ + +也就是说,$\{Z_n, \mathscr{F}_n\}_{n \geq 1}$ 是一个非负、一致 +可积的 $P$-鞅。 + +```{prf:lemma} 鞅收敛 +:label: martingale_convergence + +似然比过程 $\{Z_n\}$ 满足: + +1. 当 $n \to \infty$ 时,$Z_n \to Z_\infty$ $P$-几乎必然。 +2. $Z_\infty = \mathbb{E}_P[Z \,|\, \mathscr{F}_\infty]$ $P$-a.s. +3. $Z_n \to Z_\infty$ 在 $L^1(P)$ 中:$\;\mathbb{E}_P[|Z_n - Z_\infty|] \to 0$。 + +*证明概要。*非负性和鞅性质给出了在 $L^1(P)$ 中的 +有界性。 + +然后几乎必然收敛由杜布鞅 +收敛定理 {cite:t}`doob1953` 得出。 + +一致可积性(它通过条件延森不等式 +由 $Z \in L^1(P)$ 得出)将其提升到 +$L^1(P)$ 收敛。$\square$ +``` + +### 将条件测度与似然比联系起来 + +下面的恒等式将似然比与条件分布联系起来。 + +在集合 $\{Z_n > 0\}$ 上,$Q(\,\cdot\,|\,\mathscr{F}_n)$ 关于 $P(\,\cdot\,|\,\mathscr{F}_n)$ 的 +拉东-尼科迪姆导数为 + +$$ +\frac{d\,Q(\,\cdot\,|\,\mathscr{F}_n)}{d\,P(\,\cdot\,|\,\mathscr{F}_n)} += \frac{Z_\infty}{Z_n} +\qquad P\text{-a.s. on } \{Z_n > 0\}. +$$ + +于是应用带 $f = Z_\infty / Z_n$ 的全变差公式给出 + +$$ +d_n += \mathbb{E}_{P(\cdot|\mathscr{F}_n)}\!\left[\left(\frac{Z_\infty}{Z_n} - 1\right)^{\!+}\right] += 1 - \mathbb{E}_{P(\cdot|\mathscr{F}_n)}\!\left[\min\!\left(\frac{Z_\infty}{Z_n},\,1\right)\right]. +$$ + +两边乘以 $Z_n$ 并取 $P$-期望(然后对 $\mathscr{F}_n$-可测的 $g$ 使用 $\mathbb{E}_P[Z_n \, g(\mathscr{F}_n)] = \mathbb{E}_Q[g(\mathscr{F}_n)]$): + +$$ +2\,\mathbb{E}_Q[d_n] \;=\; \mathbb{E}_P[|Z_\infty - Z_n|], +$$ + +因此鞅的 $L^1(P)$ 收敛控制了全变差距离趋于零的速度。 + + +## 布莱克韦尔-杜宾斯定理 + +```{prf:theorem} 布莱克韦尔-杜宾斯(1962) +:label: blackwell_dubins + +设 $P$ 和 $Q$ 是 $(\Omega, \mathscr{F})$ 上的概率测度,满足 +$Q \ll P$。 + +定义 + +$$ +d_n = \bigl\|P(\,\cdot\,|\,\mathscr{F}_n) - Q(\,\cdot\,|\,\mathscr{F}_n)\bigr\|_{\mathrm{TV}}. +$$ + +那么 $d_n \to 0$ $Q$-几乎必然。 +``` + +证明有三个步骤。 + +步骤 1. 通过 $Z_n$ 表示 $d_n$。 + +如上所示,$d_n$ 可以用 $Z_\infty / Z_n$ 表示,其中 $Z_n = \mathbb{E}_P[Z \,|\, \mathscr{F}_n]$ 且 $Z = dQ/dP$。 + +这将问题化归为关于 $P$ 下一个鞅的陈述。 + +步骤 2. $\{d_n\}$ 是一个非负上鞅。 + +对更多信息取条件平均地降低了可区分性。 + +形式上,因为 +$P(\,\cdot\,|\,\mathscr{F}_n) = \mathbb{E}[P(\,\cdot\,|\,\mathscr{F}_{n+1})\,|\,\mathscr{F}_n]$ +且全变差是凸的, + +$$ +\mathbb{E}_Q[d_{n+1}\,|\,\mathscr{F}_n] \leq d_n \qquad Q\text{-a.s.} +$$ + +因此 $\{d_n, \mathscr{F}_n\}$ 是 $[0,1]$ 中的非负 $Q$-上鞅。 + +由杜布定理,$d_n \to d_\infty$ $Q$-几乎必然,其中 $d_\infty$ 是某个取值于 $[0,1]$ 的随机变量。 + +步骤 3. 几乎必然的极限为零。 + +由步骤 1 和 $L^1$ 界: + +$$ +\mathbb{E}_Q[d_n] = \tfrac{1}{2}\,\mathbb{E}_P[|Z_\infty - Z_n|] \to 0. +$$ + +右边由鞅的 $L^1(P)$ 收敛而消失。 + +因此 $d_n \to 0$ 在 $L^1(Q)$ 中,从而在 $Q$-概率意义下成立。 + +由于 $d_n$ 已经 $Q$-几乎必然收敛,其极限必须满足 $d_\infty = 0$ $Q$-a.s. $\square$ + +```{prf:remark} 单边绝对连续性 vs. 相互绝对连续性 +:label: one_sided_vs_mutual + +该定理只要求 $Q \ll P$,而不要求 $P \ll Q$。 + +单边绝对连续性 $Q \ll P$ 给出 $Q$-几乎必然的融合。 + +由于 $Q \ll P$ 意味着每个 $P$-零集也是 $Q$-零集,$Q$-a.s. 收敛并不*自动*蕴含 $P$-a.s. 收敛。 + +要得出在*两个*主体的测度下 $d_n \to 0$,需要相互绝对连续性 $P \sim Q$。 + +在加上 $P \ll Q$ 之后,可以将 $P$ 和 $Q$ 的角色互换运行该证明,从而也得到 $d_n \to 0$ $P$-a.s.。 +``` + +```{prf:remark} 尖锐性 +:label: sharpness + +绝对连续性很重要。 + +当 $P$ 和 $Q$ 奇异时,融合可能完全失败。 + +下面的点质量例子对每个 $n$ 都有 $d_n = 1$。 + +对于乘积测度,后面的角谷定理给出了一个尖锐的等价性与奇异性二分法。 +``` + + +## 贝塔-伯努利模型 + +在转向 Python 之前,我们介绍贯穿所有 +模拟的主要例子。 + +### 模型 + +假设数据流 $(x_1, x_2, \ldots)$ 由独立同分布的伯努利 +抽样构成,未知概率为 $p^* \in (0,1)$。 + +主体 $i$ 有一个贝塔先验: + +$$ +p \sim \mathrm{Beta}(\alpha_i, \beta_i), \qquad i = 1, 2. +$$ + +在观察到 $n$ 次抽样中有 $k$ 次成功之后,贝叶斯法则给出 +后验 + +$$ +p \,|\, x^n \;\sim\; \mathrm{Beta}(\alpha_i + k,\; \beta_i + n - k), +$$ + +而单步向前预测概率为 + +$$ +\hat{p}_i^n = \mathbb{E}[p\,|\,x^n] = \frac{\alpha_i + k}{\alpha_i + \beta_i + n}. +$$ + +由强大数定律,$k/n \to p^*$ 几乎必然,因此无论 +主体的初始先验 $(\alpha_i, \beta_i)$ 如何,$\hat{p}_1^n$ 和 $\hat{p}_2^n$ 都收敛到 $p^*$。 + +### 边缘似然与似然比 + +对于每个固定的值 $p \in (0,1)$,令 $P_p$ 表示无限序列上的独立同分布伯努利$(p)$ +概率律。 + +主体 $i$ 不知道 $p$。 + +相反,主体 $i$ 对 $p$ 放置先验密度 $\pi_i$,这通过下式在数据序列上诱导出 +一个概率测度 $P_i$ + +$$ +P_i(A) = \int_0^1 P_p(A)\,\pi_i(p)\,dp +\qquad \text{对于每个事件 } A. +$$ + +因此 $P_i$ 是主体在对 $p$ 的不确定性取平均之后关于 +历史的边缘概率测度。 + +特别地,如果 $x^n$ 是一个精确的观察历史,有 $k$ 次成功,那么 +$P_i(x^n)$ 表示主体 $i$ 在这个混合测度下赋予该历史的概率。 + +要计算它,从贝塔密度出发 + +$$ +\pi_i(p) += \frac{p^{\alpha_i - 1} (1-p)^{\beta_i - 1}}{B(\alpha_i, \beta_i)}, +\qquad 0 < p < 1. +$$ + +给定 $p$,该有序历史的概率为 $p^k (1-p)^{n-k}$。 + +因此 + +$$ +\begin{aligned} +P_i(x^n) +&= \int_0^1 p^k (1-p)^{n-k} \pi_i(p)\, dp \\ +&= \frac{1}{B(\alpha_i, \beta_i)} +\int_0^1 p^{\alpha_i + k - 1} (1-p)^{\beta_i + n - k - 1}\, dp \\ +&= \frac{B(\alpha_i + k,\; \beta_i + n - k)}{B(\alpha_i,\, \beta_i)}. +\end{aligned} +$$ + +其中 $B(a,b) = \Gamma(a)\Gamma(b)/\Gamma(a+b)$ 是贝塔函数。 + +这个表达式是有序历史 $x^n$ 的概率。 + +它仅通过计数 $k$ 依赖于数据,因此成功次数相同的历史获得相同的概率。 + +因此时刻 $n$ 处的似然比为 + +$$ +Z_n = \frac{P_{1,n}(x^n)}{P_{2,n}(x^n)} += \frac{B(\alpha_2,\, \beta_2)}{B(\alpha_1,\, \beta_1)} +\cdot +\frac{B(\alpha_1 + k,\, \beta_1 + n - k)}{B(\alpha_2 + k,\, \beta_2 + n - k)}. +$$ + +这是 $P_2$(主体 2 的概率)下的一个鞅,它几乎必然 +收敛到一个有限正极限 $Z_\infty$,反映了对于任何具有正参数的贝塔先验, +$P_1 \sim P_2$ 这一事实。 + +### 精确的布莱克韦尔-杜宾斯距离 + +对于贝塔-伯努利模型,存在一个 $d_n$ 的简洁公式。 + +由德菲内蒂定理,给定过去时每个主体对*未来无限序列*的条件分布 +是独立同分布伯努利$(p)$ +过程的混合,其中 $p$ 从后验贝塔分布抽取。 + +由于不同 $p$ 的伯努利$(p)^{\infty}$ 测度相互 +奇异(经验频率精确地识别出 $p$),关于未来的两个条件分布之间的全变差距离 +等于关于参数 $p$ 的两个后验分布之间的全变差 +距离。 + +全变差距离为 + +$$ +d_n += \bigl\|\mathrm{Beta}(\alpha_1 + k_n,\,\beta_1 + n - k_n) +- \mathrm{Beta}(\alpha_2 + k_n,\,\beta_2 + n - k_n)\bigr\|_{\mathrm{TV}}. +$$ + +当 $k_n/n \to p^*$ 且 $n \to \infty$ 时,两个后验贝塔都集中于 $p^*$ 附近,方差为 $1/n$ 阶,因此 $d_n \to 0$。 + +下面的代码实现了上述贝塔-伯努利更新、预测概率、全变差距离和似然比的计算。 + +```{code-cell} ipython3 +def beta_bernoulli_update(data, a0, b0): + """ + 序贯贝塔-伯努利贝叶斯更新。 + """ + n = len(data) + cum_k = np.concatenate([[0], np.cumsum(data)]) # 累积成功次数 + ns = np.arange(n + 1) # 0, 1, ..., n + a_post = a0 + cum_k + b_post = b0 + (ns - cum_k) + return a_post, b_post + + +def predictive_prob(a_post, b_post): + """单步向前预测概率 P(X=1 | data)。""" + return a_post / (a_post + b_post) + + +def tv_distance_beta(a1, b1, a2, b2, n_grid=2000): + """ + 通过网格求积计算 Beta(a1,b1) 和 Beta(a2,b2) 之间的全变差距离。 + 在 (0,1) 上使用精细网格。 + """ + x = np.linspace(1e-8, 1 - 1e-8, n_grid) + dx = x[1] - x[0] + p1 = beta_dist.pdf(x, a1, b1) + p2 = beta_dist.pdf(x, a2, b2) + return 0.5 * np.sum(np.abs(p1 - p2)) * dx + + +def log_likelihood_ratio(data, a1, b1, a2, b2): + """ + 计算对数似然比 log Z_n = log P1_n(data) - log P2_n(data) + 对 `data` 的每个前缀。 + + 返回一个长度为 len(data) + 1 的数组,从 0 开始(数据之前)。 + """ + a1p, b1p = beta_bernoulli_update(data, a1, b1) + a2p, b2p = beta_bernoulli_update(data, a2, b2) + log_P1 = betaln(a1p, b1p) - betaln(a1, b1) + log_P2 = betaln(a2p, b2p) - betaln(a2, b2) + return log_P1 - log_P2 + + +def run_simulation(p_true, a1, b1, a2, b2, n_steps, seed=0): + """ + 模拟融合实验的一次实现。 + + 返回一个字典,包含长度为 n_steps + 1 的数组(索引 0 = 先验)。 + """ + rng = np.random.default_rng(seed) + data = rng.binomial(1, p_true, n_steps) + + a1p, b1p = beta_bernoulli_update(data, a1, b1) + a2p, b2p = beta_bernoulli_update(data, a2, b2) + + pred1 = predictive_prob(a1p, b1p) + pred2 = predictive_prob(a2p, b2p) + tv_1step = np.abs(pred1 - pred2) + + # 后验贝塔之间的全变差;在此模型中它等于 d_n + tv_beta = np.array([ + tv_distance_beta(a1p[i], b1p[i], a2p[i], b2p[i]) + for i in range(n_steps + 1) + ]) + + log_Z = log_likelihood_ratio(data, a1, b1, a2, b2) + + return dict(data=data, pred1=pred1, pred2=pred2, + tv_1step=tv_1step, tv_beta=tv_beta, log_Z=log_Z) +``` + +### 模拟 + +我们选择两个对一枚硬币偏差持有非常不同信念的主体,这枚硬币正面朝上的真实概率为 $p^* = 0.65$。 + +- 主体 1(怀疑者):先验 $\mathrm{Beta}(1, 8)$,因此 + $\hat{p}_1^0 = 1/9 \approx 0.11$。 +- 主体 2(乐观者):先验 $\mathrm{Beta}(8, 1)$,因此 + $\hat{p}_2^0 = 8/9 \approx 0.89$。 + +两个先验都支撑在整个 $(0,1)$ 上,因此 $P_1 \sim P_2$。 + +布莱克韦尔-杜宾斯保证融合。 + +下图展示了这种融合的样子。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 贝塔-伯努利例子中的融合。 + 四个面板显示后验预测均值、全变差距离 $d_n$、对数似然比 $\log Z_n$,以及选定视界处的后验密度。 + name: fig-merging-of-opinions-beta-bernoulli +--- +p_true = 0.65 +a1, b1 = 1.0, 8.0 # 怀疑者 +a2, b2 = 8.0, 1.0 # 乐观者 +n_steps = 600 + +sim = run_simulation(p_true, a1, b1, a2, b2, n_steps, seed=7) +steps = np.arange(n_steps + 1) + +fig, axes = plt.subplots(2, 2, figsize=(11, 7)) +ax = axes[0, 0] +ax.plot(steps, sim['pred1'], color='steelblue', lw=2, + label=r'主体 1 $\hat p_1^n$(先验:怀疑者)') +ax.plot(steps, sim['pred2'], color='firebrick', lw=2, + label=r'主体 2 $\hat p_2^n$(先验:乐观者)') +ax.axhline(p_true, color='black', lw=1.0, ls='--', + label=f'真值 $p^*={p_true}$') +ax.set_xlabel('观察数 $n$') +ax.set_ylabel('预测概率') +ax.set_title('(a) 后验预测均值') +ax.legend(fontsize=8) +ax.set_ylim(0, 1) + +ax = axes[0, 1] +ax.semilogy(steps, sim['tv_beta'] + 1e-10, color='mediumpurple', lw=2) +ax.set_xlabel('观察数 $n$') +ax.set_ylabel( + r'$d_n = \|P(\cdot|\mathscr{F}_n)' + r' - Q(\cdot|\mathscr{F}_n)\|_{\mathrm{TV}}$' +) +ax.set_title(r'(b) 全变差距离 $d_n$') +ax.set_ylim(bottom=1e-4) + +ax = axes[1, 0] +ax.plot(steps, sim['log_Z'], color='darkorange', lw=2) +ax.axhline(0, color='black', lw=0.8, ls=':') +ax.set_xlabel('观察数 $n$') +ax.set_ylabel(r'$\log Z_n$') +ax.set_title(r'(c) 对数似然比') + +ax = axes[1, 1] +xs = np.linspace(0.01, 0.99, 500) +epochs = [0, 20, 100, n_steps] +colors = plt.cm.viridis(np.linspace(0.2, 0.85, len(epochs))) + +for epoch, col in zip(epochs, colors): + k_e = int(np.sum(sim['data'][:epoch])) + pdf1 = beta_dist.pdf(xs, a1 + k_e, b1 + epoch - k_e) + pdf2 = beta_dist.pdf(xs, a2 + k_e, b2 + epoch - k_e) + ax.plot(xs, pdf1, color=col, lw=2, ls='-') + ax.plot(xs, pdf2, color=col, lw=2, ls='--') + +ax.axvline(p_true, color='black', lw=1.0, ls=':', label=f'$p^*={p_true}$') +ax.set_xlabel('$p$') +ax.set_ylabel('后验密度') +ax.set_title('(d) 后验密度') + +from matplotlib.lines import Line2D +handles = [ + Line2D([0], [0], color='black', lw=2, label='主体 1'), + Line2D([0], [0], color='black', lw=2, ls='--', label='主体 2'), +] +for epoch, col in zip(epochs, colors): + handles.append(Line2D([0], [0], color=col, lw=2, label=f'$n={epoch}$')) +handles.append( + Line2D([0], [0], color='black', lw=1.0, ls=':', label=f'$p^*={p_true}$') +) +ax.legend(handles=handles, fontsize=8) +ax.set_ylim(bottom=0) + +plt.tight_layout() +plt.show() +``` + +四个面板显示: + +- 面板 (a):从 $\hat{p}_1^0 \approx 0.11$ 和 + $\hat{p}_2^0 \approx 0.89$ 出发,两个主体的预测概率都 + 收敛到 $p^* = 0.65$。 +- 面板 (b):全变差距离 $d_n$ 在 + 对数刻度上衰减到零,与定理一致。 +- 面板 (c):对数似然比 $\log Z_n$ 收敛到一个有限 + 值,这与本例中的相互绝对连续性一致。 +- 面板 (d):两个主体的后验贝塔密度起初相距 + 甚远(一个接近 0,一个接近 1),并逐渐集中到以真值为中心的相同 + 分布。 + + +### 跨多条路径的几乎必然收敛 + +为了说明该定理的几乎必然特性,我们运行许多独立重复。 + +该定理关注参考测度下的几乎每条路径,而不仅仅是跨路径的平均。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 跨多条样本路径的几乎必然融合。 + 左面板绘制全变差距离,右面板绘制对数似然比 $\log Z_n$。 + name: fig-merging-of-opinions-many-paths +--- +N_paths = 80 +n_steps = 500 + +fig, axes = plt.subplots(1, 2, figsize=(11, 4)) + +ax_tv = axes[0] +ax_log = axes[1] + +tv_all = np.empty((N_paths, n_steps + 1)) +logZ_all = np.empty((N_paths, n_steps + 1)) +steps = np.arange(n_steps + 1) + +for i in range(N_paths): + s = run_simulation(p_true, a1, b1, a2, b2, n_steps, seed=i) + tv_all[i] = s['tv_beta'] + logZ_all[i] = s['log_Z'] + +for i in range(N_paths): + ax_tv.semilogy(steps, tv_all[i] + 1e-10, color='steelblue', + lw=0.8, alpha=0.3) +ax_tv.semilogy(steps, tv_all.mean(axis=0) + 1e-10, + color='black', lw=2, label='跨路径均值') +ax_tv.set_xlabel('观察数 $n$') +ax_tv.set_ylabel(r'$d_n$(对数刻度)') +ax_tv.legend() + +for i in range(N_paths): + ax_log.plot(steps, logZ_all[i], color='firebrick', + lw=0.8, alpha=0.3) +ax_log.plot(steps, logZ_all.mean(axis=0), + color='black', lw=2, label='跨路径均值') +ax_log.axhline(0, color='gray', lw=0.8, ls=':') +ax_log.set_xlabel('观察数 $n$') +ax_log.set_ylabel(r'$\log Z_n$') +ax_log.legend() + +plt.tight_layout() +plt.show() + +# 有限视界摘要 +frac_below = np.mean(tv_all[:, -1] < 0.30) +mean_final = tv_all[:, -1].mean() +print(f"n = {n_steps} 时 d_n < 0.30 的路径比例: {frac_below:.2f}") +print(f"n = {n_steps} 时的平均距离: {mean_final:.3f}") +``` + +在这个有限视界处,距离已从初始水平大幅下降,但尚未接近零。 + +这仍然与定理一致,因为几乎必然收敛是一个渐近陈述。 + + +### $d_n$ 的上鞅性质 + +证明依赖于 $\{d_n\}$ 是一个非负上鞅。 + +我们可以通过观察跨多条路径的平均增量来数值地说明这一点。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 上鞅性质的一个说明。 + 图中显示 $d_n$ 的平均增量及其跨多条模拟路径的累积和。 + name: fig-merging-of-opinions-supermartingale +--- +diffs = np.diff(tv_all, axis=1) # 形状 (N_paths, n_steps) +mean_diffs = diffs.mean(axis=0) # 每步的平均增量 +cum_sum = np.cumsum(mean_diffs) # 累积平均变化 + +fig, axes = plt.subplots(1, 2, figsize=(10, 4)) + +ax = axes[0] +ax.plot(mean_diffs[:200], color='purple', lw=2) +ax.axhline(0, color='black', lw=0.8, ls='--') +ax.fill_between(range(200), mean_diffs[:200], 0, + where=(mean_diffs[:200] < 0), alpha=0.25, + color='purple', label='负增量') +ax.fill_between(range(200), mean_diffs[:200], 0, + where=(mean_diffs[:200] > 0), alpha=0.25, + color='red', label='正增量') +ax.set_xlabel('观察数 $n$') +ax.set_ylabel(r'$\mathbb{E}[d_{n+1} - d_n]$') +ax.legend(fontsize=8) + +ax = axes[1] +ax.plot(cum_sum[:200], color='darkorange', lw=2) +ax.axhline(0, color='black', lw=0.8, ls='--') +ax.set_xlabel('观察数 $n$') +ax.set_ylabel(r'$d_n$ 的累积平均变化') + +plt.tight_layout() +plt.show() + +frac_decrease = np.mean(mean_diffs < 0) +print(f"平均减量的步骤比例: {frac_decrease:.2%}") +``` + +平均增量在大多数步骤为负,累积漂移向下。 + +这只是一个说明,而不是证明,因为它使用的是无条件平均,而不是定理中完整的条件期望。 + + +## 融合的失败:相互奇异 + +当假设 $Q \ll P$ 失败时会发生什么? + +奇异情形是最简洁的反例。 + +### 点质量先验 + +假设两个主体都持有退化(点质量)先验: + +- 主体 P:确信 $p = p_P = 0.30$。 +- 主体 Q:确信 $p = p_Q = 0.75$。 + +由于 $P$ 仅对经验频率收敛到 $0.30$ 的序列赋值,而 $Q$ 仅对经验频率收敛到 $0.75$ 的序列赋值,这两个测度相互奇异:$P \perp Q$。 + +条件分布不更新,因为两个主体都已经确信各自的模型。 + +对于定理的对象,即整个未来路径的条件律, + +$$ +\|P(\,\cdot\,|\,\mathscr{F}_n) - Q(\,\cdot\,|\,\mathscr{F}_n)\|_{\mathrm{TV}} += \|P - Q\|_{\mathrm{TV}} = 1 +\quad \text{对所有 } n. +$$ + +这个等式成立是因为具有不同成功概率的无限乘积伯努利测度是奇异的。 + +如果我们只向前看一步,预测距离为 $|p_P - p_Q| = 0.45$。 + +这小于一,但它不是出现在布莱克韦尔-杜宾斯中的量。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 奇异先验下融合的失败。 + 整个未来路径距离保持在一, + 而单步预测差距保持 + 在 $|p_P - p_Q|$。 + name: fig-merging-of-opinions-singular-priors +--- +p_P = 0.30 +p_Q = 0.75 +n_steps = 500 + +tv_singular_full = np.ones(n_steps + 1) +tv_singular_1step = np.full(n_steps + 1, np.abs(p_P - p_Q)) + +sim_abs_cont = run_simulation( + p_Q, 1.0, 8.0, 8.0, 1.0, n_steps, seed=1 +) + +fig, ax = plt.subplots(figsize=(8, 4)) +ax.plot(np.arange(n_steps + 1), tv_singular_full, + color='firebrick', lw=2, + label=r'奇异:整路径 $d_n = 1$') +ax.plot(np.arange(n_steps + 1), tv_singular_1step, + color='gray', lw=2, ls=':', + label=r'单步差距 $= |p_P - p_Q|$') +ax.plot(np.arange(n_steps + 1), + sim_abs_cont['tv_beta'], + color='steelblue', lw=2, + label=(r'$\mathrm{Beta}(1,8)$ vs' + r' $\mathrm{Beta}(8,1)$')) +ax.set_xlabel('观察数 $n$') +ax.set_ylabel(r'$d_n$') +ax.legend(fontsize=8) +ax.set_ylim(0, 1.05) + +plt.tight_layout() +plt.show() +``` + +对比是鲜明的。 + +对于相互绝对连续的先验,$d_n$ 衰减到零。 + +对于奇异的点质量先验,整个未来路径距离永远保持在一。 + +更多的数据无法调和这两个主体,因为每个主体都排除了对方赋予正概率的路径。 + + +## 角谷定理:融合何时成立? + +一个自然的问题是:对于哪些乘积测度,布莱克韦尔-杜宾斯 +假设 $Q \ll P$ 成立? + +对于无限乘积测度,答案由 +{cite:t}`kakutani1948` 的经典结果给出。 + +### 海林格亲和度 + +```{prf:definition} 海林格亲和度 +:label: hellinger_affinity + +对于 $(S, \mathscr{S})$ 上具有共同 +支配测度 $\lambda$ 的概率测度 $P_n$ 和 $Q_n$,**海林格亲和度**为 + +$$ +\rho_n = \int_S \sqrt{\frac{dP_n}{d\lambda} \cdot \frac{dQ_n}{d\lambda}}\,d\lambda +\;\in\; [0, 1]. +$$ + +$\rho_n = 1$ 当且仅当 $P_n = Q_n$;$\rho_n = 0$ 当且仅当 $P_n \perp Q_n$。 +``` + +对于两个特定的一维族: + +- 高斯:$P_n = \mathcal{N}(\mu_n, 1)$ vs $Q_n = \mathcal{N}(0,1)$: + +$$ +\rho_n^{\text{Gauss}} = \exp\!\left(-\frac{\mu_n^2}{8}\right). +$$ + +- 伯努利:$P_n = \mathrm{Bernoulli}(p)$ vs $Q_n = \mathrm{Bernoulli}(q)$: + +$$ +\rho_n^{\text{Bern}} = \sqrt{pq} + \sqrt{(1-p)(1-q)}. +$$ + +### 角谷二分法 + +```{prf:theorem} 角谷(1948) +:label: kakutani_dichotomy + +设 $P = \bigotimes_{n=1}^\infty P_n$ 和 $Q = \bigotimes_{n=1}^\infty Q_n$ +是无限乘积测度,其因子逐对等价:对于每个 $n$,$P_n \sim Q_n$。 + +那么要么 $P \sim Q$,要么 $P \perp Q$;不存在 +中间情形。 + +具体地, + +$$ +P \sim Q +\quad \iff \quad +\prod_{n=1}^\infty \rho_n > 0 +\quad \iff \quad +\sum_{n=1}^\infty (1 - \rho_n) < \infty. +$$ + +如果 $\prod_{n=1}^\infty \rho_n = 0$,那么 $P \perp Q$。 + +*证明思路。* +一个标准证明研究似然比鞅 +$Z_N = \prod_{n=1}^N (dP_n/dQ_n)$ 连同恒等式 +$\mathbb{E}_Q[\sqrt{Z_N}] = \prod_{n=1}^N \rho_n$。 + +乘积保持正对应于等价性,而乘积坍缩到零对应于奇异性。 + +$\square$ +``` + +### 对融合的蕴含 + +对于独立同分布类型的序列,角谷定理给出以下图景: + +| 情形 | $\sum_n (1-\rho_n)$ | 结论 | 融合? | +|---|---|---|---| +| 对所有 $n$,$P_n = Q_n$ | $0$ | $P = Q$ | 平凡地是 | +| $P_n \ne Q_n$ 且 $\sum_n (1-\rho_n) < \infty$ | 有限 | $P \sim Q$ | 是;布莱克韦尔-杜宾斯适用 | +| $P_n = P \ne Q = Q_n$ 固定,$n \ge 1$ | $\infty$ | $P \perp Q$ | 否 | + +具有不同固定边缘分布的独立同分布情形是标准的不融合例子。 + +如果两个主体对每个观察永久地赋予不同的分布,他们最终处于互不相交的概率世界中。 + +### 一个高斯乘积测度例子 + +我们用高斯乘积测度来说明角谷二分法。 + +取 $Q = \mathcal{N}(0,1)^{\otimes\mathbb{N}}$ 作为参考测度,取 $P = \bigotimes_n \mathcal{N}(\mu_n,1)$ 作为备择。 + +$\mu_n$ 的三种选择: + +1. $\mu_n = \mu > 0$ 常数($\sum (1-\rho_n) = \infty$)$\Rightarrow P \perp Q$。 +2. $\mu_n = c/\!\sqrt{n}$($\sum (1-\rho_n) \approx \sum c^2/(8n) = \infty$)$\Rightarrow P \perp Q$。 +3. $\mu_n = c/n$($\sum (1-\rho_n) \approx \sum c^2/(8n^2) < \infty$)$\Rightarrow P \sim Q$。 + +```{code-cell} ipython3 +N_max = 2000 +ns = np.arange(1, N_max + 1) +c = 2.0 +N_plot = 400 +rng = np.random.default_rng(0) + +cases = [ + (r'$\mu_n = c$(常数)', np.full(N_max, c)), + (r'$\mu_n = c/\sqrt{n}$', c / np.sqrt(ns)), + (r'$\mu_n = c/n$', c / ns), +] +``` + +在常数漂移下,$\log Z_N$ 在 $Q$ 下漂移到 $-\infty$,因此 $Z_N \to 0$ $Q$-a.s. 且 $P \perp Q$。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 常数漂移 $\mu_n = c$: + 似然比坍缩($P \perp Q$)。 + name: fig-kakutani-constant +--- +label, μ_seq = cases[0] +x = rng.standard_normal(N_plot) +log_Z_inc = μ_seq[:N_plot] * x - μ_seq[:N_plot]**2 / 2 +log_Z = np.concatenate([[0], np.cumsum(log_Z_inc)]) + +fig, ax = plt.subplots(figsize=(8, 3)) +ax.plot(np.arange(N_plot + 1), log_Z, + color='darkorange', lw=2, label=label) +ax.axhline(0, color='black', lw=0.8, ls=':') +ax.set_xlabel('视界 $N$') +ax.set_ylabel(r'$Q$ 下的 $\log Z_N$') +ax.legend(fontsize=8) +plt.tight_layout() +plt.show() +``` + +$\mu_n = c/\sqrt{n}$ 的情形显示出相同的定性图景:尽管漂移消失,但消失得太慢。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 漂移 $\mu_n = c/\sqrt{n}$:仍然 + 奇异($P \perp Q$)。 + name: fig-kakutani-sqrt +--- +label, μ_seq = cases[1] +x = rng.standard_normal(N_plot) +log_Z_inc = μ_seq[:N_plot] * x - μ_seq[:N_plot]**2 / 2 +log_Z = np.concatenate([[0], np.cumsum(log_Z_inc)]) + +fig, ax = plt.subplots(figsize=(8, 3)) +ax.plot(np.arange(N_plot + 1), log_Z, + color='purple', lw=2, label=label) +ax.axhline(0, color='black', lw=0.8, ls=':') +ax.set_xlabel('视界 $N$') +ax.set_ylabel(r'$Q$ 下的 $\log Z_N$') +ax.legend(fontsize=8) +plt.tight_layout() +plt.show() +``` + +只有在 $\mu_n = c/n$ 时 $\sum (1-\rho_n) < \infty$ 才成立,因此似然比保持非退化且 $P \sim Q$。 + +布莱克韦尔-杜宾斯仅在此情形下适用。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 漂移 $\mu_n = c/n$:似然 + 比稳定($P \sim Q$)。 + name: fig-kakutani-inv-n +--- +label, μ_seq = cases[2] +x = rng.standard_normal(N_plot) +log_Z_inc = μ_seq[:N_plot] * x - μ_seq[:N_plot]**2 / 2 +log_Z = np.concatenate([[0], np.cumsum(log_Z_inc)]) + +fig, ax = plt.subplots(figsize=(8, 3)) +ax.plot(np.arange(N_plot + 1), log_Z, + color='steelblue', lw=2, label=label) +ax.axhline(0, color='black', lw=0.8, ls=':') +ax.set_xlabel('视界 $N$') +ax.set_ylabel(r'$Q$ 下的 $\log Z_N$') +ax.legend(fontsize=8) +plt.tight_layout() +plt.show() +``` + + +## 推广到连续时间 + +同样的逻辑推广到连续时间。 + +### 吉尔萨诺夫定理与似然比过程 + +在典范维纳空间上,$Q$ 为维纳测度(标准 +布朗运动 $W$),假设主体 $P$ 相信该过程有一个 +额外漂移 $\theta = \{\theta_s\}_{s \geq 0}$: + +$$ +W_t = \widetilde{W}_t + \int_0^t \theta_s\, ds, +$$ + +其中 $\widetilde{W}$ 是一个 $P$-布朗运动。 + +吉尔萨诺夫-卡梅隆-马丁定理 {cite:p}`girsanov1960` 将 +似然比过程给出为随机指数 + +$$ +Z_t += \exp\!\left(\int_0^t \theta_s\, dW_s - \frac{1}{2}\int_0^t \theta_s^2\, ds\right). +$$ + +$Z_t$ 始终是一个非负的 $Q$-局部鞅;它是一个真鞅 +当且仅当对所有 $t$,$\mathbb{E}_Q[Z_t] = 1$。 + +诺维科夫条件 {cite:p}`novikov1972`, +对所有 $T$,$\mathbb{E}_Q\!\left[\exp\!\left(\tfrac{1}{2}\int_0^T \theta_s^2\,ds\right)\right] < \infty$, +是充分的。 + +### 无穷远处的二分法 + +$[0,+\infty)$ 上的一个关键微妙之处是局部绝对连续性*不*蕴含 $\mathscr{F}_\infty$ 上的全局绝对连续性。 + +```{prf:remark} 无限视界的微妙之处 +:label: dichotomy_at_infinity + +假设 $Z_t$ 对每个有限视界都是一个真 $Q$-鞅,并令 $Z_t \to Z_\infty$ $Q$-a.s. + +如果 $\{Z_t\}$ 在 $[0,\infty)$ 上一致可积,那么在 $\mathscr{F}_\infty$ 上 $P \ll Q$,且 $dP/dQ = Z_\infty$。 + +对于布莱克韦尔-杜宾斯结论,我们需要在 $\mathscr{F}_\infty$ 上 $Q \ll P$(反方向)。 + +在许多标准设定中,包括满足下面能量条件的确定性漂移,这些测度实际上在 $\mathscr{F}_\infty$ 上是*等价的*($P \sim Q$),因此两个方向都成立。 + +如果一致可积性失败,那么 $\mathscr{F}_\infty$ 上的全局绝对连续性可能失败。 + +在许多标准例子中,包括一个非零常数漂移,这些测度实际上在 $\mathscr{F}_\infty$ 上是奇异的。 +``` + +确定性漂移例子中的一个方便的充分条件是**能量条件** + +$$ +\int_0^\infty \theta_s^2\,ds < \infty \quad Q\text{-a.s.} +$$ + +非形式地说,这表示在无限视界上区分两个测度的信息总量是有限的。 + +在能量条件下,$\mathscr{F}_\infty$ 上 $P \sim Q$,因此布莱克韦尔-杜宾斯适用,融合在两个测度下都成立。 + +当 $\theta$ 是非零常数时,该条件失败,这些测度在 $\mathscr{F}_\infty$ 上奇异,融合不会发生。 + +一旦在 $\mathscr{F}_\infty$ 上建立了 $Q \ll P$,连续时间布莱克韦尔-杜宾斯结果的证明 +就与离散时间证明完全相同。 + +$\{d_t, \mathscr{F}_t\}$ 是 $[0,1]$ 中的非负 $Q$-上鞅,因此 $d_t \to d_\infty$ $Q$-a.s. + +$L^1$ 界 +$\mathbb{E}_Q[d_t] = \tfrac{1}{2}\mathbb{E}_P[|Z_t - Z_\infty|] \to 0$ +迫使 $d_\infty = 0$。 + + +## 应用 + +### 贝叶斯学习 + +最直接的应用是贝叶斯推断。 + +假设数据 $(x_1, x_2, \ldots)$ 从真实测度 $Q^*$ 抽取。 + +一个主体在族 $\{Q_\theta : \theta \in \Theta\}$ 上持有先验 $\pi$,诱导出边缘 $P = \int Q_\theta\,\pi(d\theta)$。 + +如果 $Q^* \ll P$(即主体的边缘模型支配真值),那么布莱克韦尔-杜宾斯给出 + +$$ +\bigl\|P(\,\cdot\,|\,x_1,\ldots,x_n) - Q^*(\,\cdot\,|\,x_1,\ldots,x_n)\bigr\|_{\mathrm{TV}} +\to 0 \quad Q^*\text{-a.s.} +$$ + +这是贝叶斯一致性的一种强形式:主体的预测在真实测度下与真值融合。 + +对真实参数邻域赋予正质量的先验通常保证对每个有限视界 $n$ 的*局部*绝对连续性 $Q^*_n \ll P_n$,但不保证布莱克韦尔-杜宾斯所要求的 $\mathscr{F}_\infty$ 上的全局条件 $Q^* \ll P$。 + +例如,在具有非原子先验 $\pi$ 的贝塔-伯努利模型中,混合 $P = \int \mathrm{Bernoulli}(p)^{\infty}\,\pi(dp)$ 对每个 $n$ 满足 $Q^*_n \ll P_n$,但全局上 $Q^* \not\ll P$,因为集合 $\{\lim k_n/n = p^*\}$ 的 $Q^*$-测度为一,但 $P$-测度为零(不同的伯努利乘积测度相互奇异)。 + +在额外结构下,全局绝对连续性确实成立,例如当参数空间有限或模型足够正则以允许杜布一致性论证时。 + +{cite:t}`DiaconisFreedman1986` 研究贝叶斯估计的一致性,并在其他结果中表明,局部与全局绝对连续性之间的相互作用在确保后验收敛中起着核心作用。 + +当 $P \perp Q^*$ 时,存在在 $Q^*$ 下概率为一但在 $P$ 下概率为零的事件,因此主体的信念仍然从根本上被错误设定。 + +### 理性预期与异质先验 + +在宏观经济学中,理性预期模型通常施加共同先验。 + +布莱克韦尔-杜宾斯为较弱的初始一致性提供了动态论证。 + +如果两个主体从等价先验出发并观察相同的历史,他们的条件预测最终在每个事件上达成一致。 + +{cite:t}`aumann1976` 的一致性定理强化了这一点:具有 +共同先验的主体不能对后验概率"同意不一致"。 + +布莱克韦尔-杜宾斯补充了奥曼,表明等价先验足以实现最终一致。 + +### 遍历马尔可夫链 + +对于具有转移核 $\Pi$ 和两个初始 +分布 $\mu$ 和 $\nu$ 的马尔可夫链,$n$-步分布为 $\mu\Pi^n$ +和 $\nu\Pi^n$。 + +如果 $\Pi$ 是遍历的,具有唯一平稳分布 +$\pi$,两者都收敛到 $\pi$,因此 + +$$ +\|\mu\Pi^n - \nu\Pi^n\|_{\mathrm{TV}} +\leq \|\mu\Pi^n - \pi\|_{\mathrm{TV}} + \|\nu\Pi^n - \pi\|_{\mathrm{TV}} +\to 0. +$$ + +这是融合的一种特殊形式,它*不*要求绝对连续性,因为遍历性已经迫使两个分布趋于相同的极限。 + +布莱克韦尔-杜宾斯是非遍历或非马尔可夫环境的正确类比,在这些环境中不必存在单一的不变分布。 + + +## 融合的速率 + +布莱克韦尔-杜宾斯是定性的。 + +它告诉我们 $d_n \to 0$,但没有告诉我们速度有多快。 + +界 + +$$ +\mathbb{E}_Q[d_n] = \tfrac{1}{2}\,\mathbb{E}_P[|Z_n - Z_\infty|] +$$ + +表明融合的速率由似然比鞅的 $L^1(P)$ 收敛速率控制。 + +在正则参数例子中,人们常常看到 $n^{-1/2}$ 型的行为。 + +下图在贝塔-伯努利模型中检验了这个启发式。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: | + 贝塔-伯努利模型中平均融合距离的对数-对数图。 + 拟合斜率接近 $-1/2$,这与本实验中的平方根衰减一致。 + name: fig-merging-of-opinions-rate +--- +N_paths_rate = 200 +n_steps_rate = 800 + +tv_rate = np.empty((N_paths_rate, n_steps_rate + 1)) +for i in range(N_paths_rate): + s = run_simulation(p_true, a1, b1, a2, b2, n_steps_rate, seed=100 + i) + tv_rate[i] = s['tv_beta'] + +ns_rate = np.arange(1, n_steps_rate + 1) +mean_tv = tv_rate[:, 1:].mean(axis=0) # 平均 d_n, n = 1, ..., n_steps_rate + +# 使用样本的后半部分拟合参考线 d_n ~ C / sqrt(n) +fit_start = 200 +log_ns = np.log(ns_rate[fit_start:]) +log_tv = np.log(mean_tv[fit_start:] + 1e-12) +coeffs = np.polyfit(log_ns, log_tv, 1) +slope = coeffs[0] + +# 参考曲线 C/sqrt(n) +C_ref = np.exp(coeffs[1]) +ref_curve = C_ref / np.sqrt(ns_rate) + +fig, ax = plt.subplots(figsize=(8, 4)) +ax.loglog(ns_rate, mean_tv, color='steelblue', lw=2, + label=r'$\mathbb{E}_Q[d_n]$(蒙特卡洛)') +ax.loglog(ns_rate, ref_curve, color='firebrick', lw=2, ls='--', + label=(rf'参考 $C/\sqrt{{n}}$' + rf'(拟合斜率 $\approx {slope:.2f}$)')) +ax.set_xlabel('样本大小 $n$') +ax.set_ylabel(r'$\mathbb{E}_Q[d_n]$') +ax.legend() +plt.tight_layout() +plt.show() + +print(f"拟合的对数-对数斜率: {slope:.3f} (预测: -0.50)") +``` + +拟合样本的后半部分给出接近 $-0.5$ 的斜率。 + +这与本模拟中的 $n^{-1/2}$ 标度一致。 + + +## 总结与推广 + +布莱克韦尔-杜宾斯定理背后的逻辑流程是: + +$$ +Q \ll P +\;\Longrightarrow\; +Z = \frac{dQ}{dP} \in L^1(P) +\;\Longrightarrow\; +Z_n = \mathbb{E}_P[Z \,|\, \mathscr{F}_n] +\xrightarrow{L^1(P)} +Z_\infty +\;\Longrightarrow\; +d_n \xrightarrow{Q\text{-a.s.}} 0. +$$ + +要点: + +1. 单边绝对连续性 $Q \ll P$ 给出 $Q$-几乎必然的融合。对于在*两个*测度下的融合,需要相互绝对连续性 $P \sim Q$。 + +2. 似然比鞅 $Z_n = \mathbb{E}_P[Z|\mathscr{F}_n]$ 及其 $L^1(P)$ 收敛驱动了这个结果。 + +3. 更多的数据只能(在期望上)降低区分两个假设的难度。 + +4. 对于无限乘积测度,角谷定理给出一个尖锐的等价性与奇异性二分法:要么 $P \sim Q$(当 $\sum_n (1 - \rho_n) < \infty$ 时),要么 $P \perp Q$(当该和发散时),不存在中间情形。 + +5. 当 $P \sim Q$ 时,布莱克韦尔-杜宾斯适用,融合在两个测度下都发生;当 $P \perp Q$ 时,分歧永远持续。 + +### 经济学中的应用 + +一些有影响力的应用和推广是: + +- {cite}`KalaiLehrer1993Nash`:当先验关于真值绝对连续时,重复博弈学习驱动策略趋向纳什行为。 +- {cite}`KalaiLehrer1993Subjective`:在相同条件下,主观均衡和客观均衡渐近地重合。 +- {cite}`KalaiLehrer1994Merging`:为完全全变差收敛过强的环境引入了弱和强融合概念。 +- {cite}`KalaiLehrerSmorodinsky1999`:将融合与校准预测联系起来。 +- {cite}`JacksonKalaiSmorodinsky1999`:将德菲内蒂式的表示与贝叶斯学习和后验收敛联系起来。 +- {cite}`JacksonKalai1999`:社会学习削弱了依赖于跨群体持续分歧的声誉效应。 +- {cite}`Sandroni1998Nash`:表明近似绝对连续性条件足以在重复博弈中实现纳什型收敛。 +- {cite}`MillerSanchirico1999`:给出了一个替代证明,并从相互有利的赌注角度对持续分歧作出了经济学解释。 +- {cite}`LehrerSmorodinsky1996Compatible`:研究超越布莱克韦尔-杜宾斯绝对连续性的更广泛的兼容性概念。 +- {cite}`LehrerSmorodinsky1996Learning`:综述重复策略环境中的融合与学习。 +- {cite}`Nyarko1994`:将绝对连续性下的贝叶斯学习与趋向相关均衡的收敛联系起来。 +- {cite}`PomattoAlNajjarSandroni2014`:将定理推广到有限可加概率,并将融合与检验可操纵性联系起来。 +- {cite}`AcemogluChernozhukovYildiz2016`:表明当主体对信号结构本身不确定时分歧如何持续。 + +### 一个来自概率论的配套结果 + +{cite}`DiaconisFreedman1986` 研究贝叶斯估计的一致性,证明了涉及后验收敛的等价性,并提供了突出先验作用的反例。 + +他们的工作与布莱克韦尔-杜宾斯处于相同的思想传统中,在经济学学习文献中通常与融合定理一起被引用。 \ No newline at end of file diff --git a/lectures/misspecified_recovery.md b/lectures/misspecified_recovery.md new file mode 100644 index 0000000..664e8b4 --- /dev/null +++ b/lectures/misspecified_recovery.md @@ -0,0 +1,2089 @@ +--- +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 +translation: + title: 误设定下的恢复 + headings: + Overview: 概述 + Three transition matrices: 三个转移矩阵 + Three transition matrices::Degenerate Martingale Component: 退化的鞅成分 + Martingale Component: 鞅成分 + From matrices to the general framework: 从矩阵到一般框架 + From matrices to the general framework::Probability space and state: 概率空间和状态 + From matrices to the general framework::Information and $Y$: 信息与 $Y$ + From matrices to the general framework::Multiplicative functionals: 乘性泛函 + From matrices to the general framework::Stochastic discount factors and pricing operators: 随机贴现因子和定价算子 + From matrices to the general framework::Martingales and equivalent probability measures: 鞅和等价概率测度 + From matrices to the general framework::What Perron--Frobenius recovers: 佩龙-弗罗贝尼乌斯恢复了什么 + From matrices to the general framework::Selection and recovery: 选择与恢复 + From matrices to the general framework::Continuous-time version: 连续时间版本 + When the recovery fails: 恢复何时失败 + When the recovery fails::Recursive utility: 递归效用 + When the recovery fails::Permanent Shocks: 永久冲击 + When the recovery fails::Long-run risk: 长期风险 + When the recovery fails::Long-run risk::Stationary Densities: 平稳密度 + When the recovery fails::Long-run risk::Yield implications: 收益率含义 + Additional state vector: 额外的状态向量 + Measuring the martingale component: 度量鞅成分 + Lessons: 教训 + Exercises: 练习 +--- + +(misspecified_recovery)= +```{raw} html + +``` + +# 误设定下的恢复 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +讲座 {doc}`ross_recovery` 研究了恢复有效的情形。 + +在那里,**转移独立性**让我们能够使用阿罗价格将投资者的信念与定价核分离开来。 + +本讲座探讨当不施加该限制时,相同的佩龙-弗罗贝尼乌斯方法会给出什么结果。 + +我们将保持三个概率测度相互分离。 + +第一个是正确设定的概率测度,它支配着模型中的马尔可夫状态。 + +第二个是单期风险中性概率测度,它来自用债券价格对单期阿罗价格进行归一化。 + +第三个是通过佩龙-弗罗贝尼乌斯理论恢复的概率测度,也称为长期风险中性测度。 + +核心问题是恢复的概率测度是否等于正确设定的概率测度。 + +{cite:t}`BorovickaHansenScheinkman2016` 表明,一般而言,答案是否定的。 + +该论文研究了恢复的概率测度与正确设定的概率测度之比。 + +原因在于随机贴现因子可能包含一个改变概率测度的鞅成分。 + +如果该鞅成分恒等于一,Ross 恢复会返回正确设定的转移概率。 + +如果它不恒等于一,恢复的概率测度会吸收长期风险调整,因为鞅增量沿历史路径复合。 + +在下面的例子中,恢复的概率测度对不利长期风险状态赋予的概率比正确设定的概率测度更多。 + +我们将: + +- 使用 {doc}`ross_recovery` 的结论而不重新证明它, +- 通过鞅成分研究误设定, +- 说明为什么递归效用和永久冲击会使恢复的概率测度不同于正确设定的概率测度, +- 在长期风险模型中度量这种差异。 + +我们将使用以下导入。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy import linalg +from scipy.integrate import solve_ivp +from scipy.stats import gaussian_kde +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +下一个单元包含从上一讲座继承的代码。 + +它对阿罗价格进行行归一化,找到佩龙-弗罗贝尼乌斯特征值和正的右特征向量,并计算平稳分布。 + +```{code-cell} ipython3 +:tags: [hide-input] + +def risk_neutral_probs(Q): + """用单期债券价格对阿罗价格进行归一化。""" + q_bonds = Q.sum(axis=1) + P_bar = Q / q_bonds[:, None] + return P_bar, q_bonds + + +def perron_frobenius(Q): + """佩龙-弗罗贝尼乌斯特征对及相关的转移矩阵。""" + eigenvalues, eigenvectors = linalg.eig(Q) + eigenvalues = np.real_if_close(eigenvalues, tol=1000) + eigenvectors = np.real_if_close(eigenvectors, tol=1000) + + real_mask = np.isreal(eigenvalues) + vals = np.asarray(eigenvalues[real_mask].real, dtype=float) + vecs = np.asarray(eigenvectors[:, real_mask].real, dtype=float) + + for idx in np.argsort(vals)[::-1]: + exp_eta = vals[idx] + e = vecs[:, idx] + if e.sum() < 0: + e = -e + if exp_eta > 0 and np.all(e > 0): + break + else: + raise ValueError("No strictly positive Perron-Frobenius eigenvector found") + + e = e / e.sum() + eta = np.log(exp_eta) + P_hat = (1 / exp_eta) * Q * e[None, :] / e[:, None] + + if np.max(np.abs(P_hat.sum(axis=1) - 1)) > 1e-8: + raise ValueError("Recovered transition matrix is not stochastic") + if P_hat.min() < -1e-10: + raise ValueError("Recovered transition matrix has negative entries") + + return eta, exp_eta, e, P_hat + + +def stationary_dist(P): + """遍历转移矩阵的平稳分布。""" + n = P.shape[0] + A = P.T - np.eye(n) + A[-1] = 1 + b = np.zeros(n) + b[-1] = 1 + return linalg.solve(A, b) + + +def martingale_increment(Q, P): + """恢复的概率测度的鞅增量。""" + eta, exp_eta, e, P_hat = perron_frobenius(Q) + H = np.ones_like(P) + mask = P > 0 + H[mask] = P_hat[mask] / P[mask] + return H, eta, e, P_hat +``` + +## 三个转移矩阵 + +设 $\mathbf{P}=[p_{ij}]$ 表示正确设定的转移矩阵,$\mathbf{Q}=[q_{ij}]$ 表示阿罗价格矩阵。 + +这里"正确设定"意味着 $\mathbf{P}$ 是支配模型中马尔可夫状态的转移矩阵。 + +单期随机贴现因子(SDF)满足 + +```{math} +:label: eq-mr-arrow-price-finite + +q_{ij} = s_{ij} p_{ij}. +``` + +我们将把 $\mathbf{P}$ 与由 $\mathbf{Q}$ 构造的两个概率矩阵进行比较。 + +第一个是**单期风险中性矩阵**。 + +它将 $\mathbf{Q}$ 的每一行除以当前状态下单期贴现债券的价格: + +$$ +\bar p_{ij} += \frac{q_{ij}}{\sum_k q_{ik}}. +$$ + +这个矩阵将单期风险调整吸收进转移概率中。 + +第二个是与**长期风险中性概率**相关的转移矩阵。 + +它从 $\mathbf{Q}$ 的佩龙-弗罗贝尼乌斯特征值和正的右特征向量出发。 + +设 $(\exp(\hat \eta), \hat e)$ 满足 + +```{math} +:label: eq-mr-pf-finite + +\mathbf{Q}\hat e = \exp(\hat \eta)\hat e. +``` + +然后定义 + +```{math} +:label: eq-mr-phat-finite + +\hat p_{ij} += \exp(-\hat \eta) q_{ij} \frac{\hat e_j}{\hat e_i}. +``` + +选择因子 $\hat e_j/\hat e_i$ 是为了抵消任何形如 $\exp(\hat \eta)\hat e_i/\hat e_j$ 的 SDF 成分。 + +结果是一个随机矩阵 $\hat{\mathbf{P}}$。 + +这一构造假设 $\mathbf{Q}$ 在相差一个比例因子的意义下有唯一的正右特征向量。 + +对于有限的不可约非负矩阵,佩龙根有一个在相差比例因子意义下唯一的严格正右特征向量。 + +对于长视界的支配性和收敛性,通常会施加更强的条件,如原始性或非周期性;该论文使用了对 $\sum_{t=0}^{\infty}\lambda^t\mathbf Q^t$ 的正性条件。 + +在一般状态空间中,这一保证不再成立:可能存在多个正特征函数,需要额外的选择条件来确定长期风险中性测度。 + +下一节的一般框架使该选择条件变得明确。 + +遵循 {cite:t}`BorovickaHansenScheinkman2016`,$\hat{\mathbf{P}}$ 被称为**长期风险中性**转移矩阵。 + +这个名称意味着佩龙-弗罗贝尼乌斯特征值和特征向量分离出了在长期限阿罗债权定价中占支配地位的部分。 + +它与单期风险中性矩阵 $\bar{\mathbf{P}}$ 不是同一个转移矩阵。 + +在 {doc}`ross_recovery` 中,转移独立性将 SDF 限制为 + +$$ +s_{ij}=\exp(-\delta)\frac{m_j}{m_i} +$$ + +其中 $m$ 是正向量,$\delta$ 是标量,这确定了 $s_{ij}$ 与 $p_{ij}$ 之间的划分。 + +在这里我们放弃这一限制。 + +问题是与长期风险中性概率相关的转移矩阵 $\hat{\mathbf{P}}$ 是否仍然等于正确设定的矩阵 $\mathbf{P}$。 + +### 退化的鞅成分 + +我们从一个三状态经济开始:衰退、正常和扩张。 + +正确设定的转移矩阵故意设置得很简单。 + +对于趋势平稳消费和幂效用,SDF 为 + +$$ +s_{ij}=A\left(\frac{c_j}{c_i}\right)^{-\gamma}. +$$ + +这是 Ross 恢复应该返回正确设定的转移矩阵的一个情形。 + +```{code-cell} ipython3 +P_true = np.array([ + [0.70, 0.25, 0.05], + [0.15, 0.65, 0.20], + [0.05, 0.30, 0.65], +]) + +c_levels = np.array([0.997, 1.000, 1.003]) +state_names = ['衰退', '正常', '扩张'] + +δ = -np.log(0.99) # 月度主观贴现率 +γ_power = 5.0 # 风险厌恶 +g_c = 0.002 # 月度趋势增长 + +# 用实际概率乘以幂效用 SDF 来给阿罗债权定价 +S_power = ( + np.exp(-δ - γ_power * g_c) + * (c_levels[None, :] / c_levels[:, None])**(-γ_power) +) +Q_power = S_power * P_true +``` + +我们现在从同一个阿罗价格矩阵计算单期风险中性矩阵和与长期风险中性概率相关的转移矩阵。 + +```{code-cell} ipython3 +P_bar, q_bonds = risk_neutral_probs(Q_power) +η_hat, exp_η, e_hat, P_hat = perron_frobenius(Q_power) +π_true = stationary_dist(P_true) +π_bar = stationary_dist(P_bar) +π_hat = stationary_dist(P_hat) +``` + +这两个矩阵不应被期望是一致的。 + +行归一化矩阵 $\bar{\mathbf{P}}$ 是一个短视界风险中性测度变换:它将单期 SDF 折叠进转移概率中,因此它通常不同于正确设定的矩阵 $\mathbf{P}$。 + +其逻辑来自 {doc}`ross_recovery` 中的佩龙-弗罗贝尼乌斯构造。 + +在转移独立的情形中,定价核具有形式 $s_{ij}=\exp(\hat\eta)\hat e_i/\hat e_j$。 + +将其代入佩龙-弗罗贝尼乌斯转移公式得到 + +$$ +\hat p_{ij} += \exp(-\hat\eta) q_{ij}\frac{\hat e_j}{\hat e_i} += \exp(-\hat\eta) + \left(\exp(\hat\eta)\frac{\hat e_i}{\hat e_j}p_{ij}\right) + \frac{\hat e_j}{\hat e_i} +=p_{ij}. +$$ + +因此,与长期风险中性概率相关的转移矩阵 $\hat{\mathbf{P}}$ 抵消了 SDF 中转移独立的部分。 + +在这个幂效用基准中,整个 SDF 恰好具有这种形式,因此剩余的鞅增量应为一,$\hat{\mathbf{P}}$ 应与 $\mathbf{P}$ 一致。 + +下一个计算通过将佩龙-弗罗贝尼乌斯特征函数与 $c_i^\gamma$ 进行比较,然后计算比值 $\hat{\mathbf{P}}/\mathbf{P}$ 来验证这一点。 + +定义单期鞅增量 + +$$ +\hat h_{ij} += \frac{\hat p_{ij}}{p_{ij}} += \exp(-\hat\eta)s_{ij}\frac{\hat e_j}{\hat e_i}. +$$ + +当对每个转移都有 $\hat h_{ij}=1$ 时,$\hat{\mathbf P}$ 和 $\mathbf P$ 相同。 + +下一节解释为什么这个比值是单期鞅增量。 + +在幂效用例子中,记 + +$$ +A = \exp(-\delta-\gamma g_c), +\qquad +s_{ij}=A\left(\frac{c_j}{c_i}\right)^{-\gamma}. +$$ + +取 $\hat e_i=c_i^\gamma$(相差一个比例因子),得到 + +$$ +[\mathbf{Q}\hat e]_i += \sum_j A\left(\frac{c_j}{c_i}\right)^{-\gamma}p_{ij}c_j^\gamma += A c_i^\gamma += A\hat e_i, +$$ + +因此 $\exp(\hat\eta)=A$。 + +因此, + +$$ +\hat h_{ij} += A^{-1}A\left(\frac{c_j}{c_i}\right)^{-\gamma} + \frac{c_j^\gamma}{c_i^\gamma} +=1. +$$ + +```{code-cell} ipython3 +H_power = np.divide(P_hat, P_true, out=np.ones_like(P_true), where=P_true > 0) +e_theory = c_levels**γ_power + +print("佩龙-弗罗贝尼乌斯特征函数:数值 vs c^gamma") +for name, e_num, e_th in zip(state_names, e_hat / e_hat[1], + e_theory / e_theory[1]): + print(f"{name:9s}: {e_num:.6f} {e_th:.6f}") + +print("\n鞅增量 h_hat = P_hat / P") +print(np.round(H_power, 6)) + +print("\nP 下的条件均值") +print(np.round((P_true * H_power).sum(axis=1), 6)) + +print(f"\nmax |h_hat - 1| = " + f"{np.max(np.abs(H_power[P_true > 0] - 1)):.2e}") +``` + +输出将短视界风险调整与佩龙-弗罗贝尼乌斯方法分离开来。 + +单期风险中性矩阵 $\bar{\mathbf{P}}$ 接近但不等于正确设定的矩阵 $\mathbf{P}$。 + +它改变了转移概率,因为单期阿罗价格包含了单期风险调整。 + +相比之下,在这个例子中,长期风险中性矩阵 $\hat{\mathbf{P}}$ 与 $\mathbf{P}$ 完全相同。 + +计算确认了原因:对每个转移,鞅增量 $\hat h_{ij}$ 都为一。 + +这是 Ross 恢复返回正确设定的转移矩阵的条件。 + +在这个例子中,这种抵消耗尽了 SDF,因此鞅成分是退化的。 + +## 鞅成分 + +设 $(\hat \eta, \hat e)$ 是 $\mathbf{Q}$ 的佩龙-弗罗贝尼乌斯特征值指数和正的右特征向量: + +$$ +\mathbf{Q} \hat e = \exp(\hat\eta) \hat e. +$$ + +相关的长期风险中性转移矩阵为 + +$$ +\hat p_{ij} += \exp(-\hat\eta) q_{ij} \frac{\hat e_j}{\hat e_i}. +$$ + +要看恢复是否改变了概率测度,将每个恢复的转移概率与对应的正确设定的转移概率进行比较。 + +对于 $p_{ij}>0$ 的可行转移,定义单期鞅增量 + +```{math} +:label: eq-mr-hhat-finite + +\hat h_{ij} = \frac{\hat p_{ij}}{p_{ij}}. +``` + +如果 $\hat h_{ij}>1$,恢复的概率测度对转移 $(i,j)$ 赋予的概率比正确设定的概率测度更多。 + +如果 $\hat h_{ij}<1$,它对该转移赋予的概率更少。 + +对于固定的当前状态 $i$,在正确设定的转移概率下,数值 $\hat h_{ij}$ 的平均值为一: + +$$ +\sum_j \hat h_{ij} p_{ij}=1. +$$ + +因此 $\hat h_{ij}$ 是一个单期鞅增量。 + +沿着状态历史将这些增量相乘,得到整个历史的恢复概率测度与正确设定概率测度之比。 + +该比值过程是一个鞅,这就是为什么 {eq}`eq-mr-finite-sdf-decomposition` 中的最后一项被称为鞅成分。 + +使用 {eq}`eq-mr-arrow-price-finite`、{eq}`eq-mr-phat-finite` 和 {eq}`eq-mr-hhat-finite`,单期 SDF 可以写为 + +```{math} +:label: eq-mr-finite-sdf-decomposition + +s_{ij} += \exp(\hat\eta) \frac{\hat e_i}{\hat e_j} \hat h_{ij}. +``` + +因此佩龙-弗罗贝尼乌斯方法将 SDF 分离为: + +| 部分 | 作用 | +|---|---| +| $\exp(\hat\eta)$ | 确定性长期贴现 | +| $\hat e_i / \hat e_j$ | 状态相关的长期项 | +| $\hat h_{ij}$ | 改变概率的鞅增量 | + +如果对每个可行转移都有 $\hat h_{ij}=1$,那么与恢复的概率测度相关的转移矩阵和正确设定的转移矩阵相同。 + +这是 Ross 恢复返回正确设定的转移矩阵的条件。 + +```{prf:proposition} 有限状态鞅成分 +:label: prop-misspecified-recovery-martingale-component + +在本讲座使用的有限状态假设下,对于具有正确设定转移矩阵 $\mathbf{P}$ 和阿罗矩阵 $\mathbf{Q}$ 的马尔可夫模型,通过佩龙-弗罗贝尼乌斯理论恢复的概率测度返回正确设定的转移矩阵,当且仅当对每个 $p_{ij}>0$ 的转移都有 $\hat h_{ij}=1$。 + +等价地,恢复返回正确设定的转移矩阵,当且仅当 {eq}`eq-mr-finite-sdf-decomposition` 中的 SDF 没有非常数的鞅成分: + +$$ +s_{ij}=\exp(\hat\eta)\frac{\hat e_i}{\hat e_j}. +$$ +``` + +```{prf:proof} +使用 $q_{ij}=s_{ij}p_{ij}$, + +$$ +\hat h_{ij} +=\frac{\hat p_{ij}}{p_{ij}} +=\exp(-\hat\eta)s_{ij}\frac{\hat e_j}{\hat e_i}. +$$ + +因此 $\hat{\mathbf{P}}=\mathbf{P}$ 当且仅当对每个可行转移都有 $\hat h_{ij}=1$。 + +这个条件等同于说 SDF 可以写成 {eq}`eq-mr-finite-sdf-decomposition` 而没有额外的鞅增量。 +``` + +这个有限状态推论是该论文一般识别结果的一个特例。 + +如果一对 $(S,P)$ 能解释资产价格,且 $H$ 是一个正的乘性鞅,那么相同的资产价格也可以由改变后的概率测度 $P^H$ 连同调整后的随机贴现因子来解释 + +$$ +S_t^H = S_t\frac{H_0}{H_t}. +$$ + +更一般地,任何严格正的鞅都可以改变概率测度,但乘性保持了这里使用的马尔可夫结构。 + +因此,仅凭阿罗价格通常无法区分信念的变化与 SDF 的变化。 + +Ross 恢复只有在施加某个限制之后才成为一个识别结果,例如 + +$$ +S_t = \exp(-\delta t)\frac{m(X_t)}{m(X_0)}, +$$ + +这排除了一个非平凡的鞅成分。 + +上面的幂效用例子说明了这个命题。 + +在那个基准中,鞅增量 $\hat h_{ij}$ 恒等于一。 + +## 从矩阵到一般框架 + +有限状态计算有三个对象: + +1. 正确设定的转移概率 $p_{ij}$, +2. SDF 增量 $s_{ij}$, +3. 阿罗价格 $q_{ij}=s_{ij}p_{ij}$。 + +它还有一个诊断对象: + +$$ +\hat h_{ij} += \frac{\hat p_{ij}}{p_{ij}} += \exp(-\hat\eta)s_{ij}\frac{\hat e_j}{\hat e_i}. +$$ + +数值 $\hat h_{ij}$ 是单期鞅增量。 + +它们将单期转移的概率从 $p_{ij}$ 改变为 $\hat p_{ij}=\hat h_{ij}p_{ij}$。 + +{cite:t}`BorovickaHansenScheinkman2016` 中的一般框架在不假设状态有限的情况下做同样的事情。 + +转移矩阵变成马尔可夫概率测度,阿罗价格矩阵变成一族定价算子,单期比值 $\hat h_{ij}$ 变成正的乘性鞅的增量。 + +本节的目的是建立这个对照关系。 + +### 概率空间和状态 + +从一个概率空间 $(\Omega,\mathcal F,P)$ 开始。 + +这里 $P$ 是正确设定的概率测度。 + +在该论文的理性预期诠释中,这是支配状态的实际或原始概率测度。 + +在有限状态一节中,$P$ 由转移矩阵 $\mathbf P=[p_{ij}]$ 表示。 + +索引集要么是离散时间 $\mathbb T=\{0,1,2,\ldots\}$,要么是连续时间 $\mathbb T=\mathbb R_+$。 + +主要状态过程是 $X=\{X_t:t\in\mathbb T\}$,它在 $P$ 下是平稳且马尔可夫的。 + +第二个过程 $W=\{W_t:t\in\mathbb T\}$ 记录驱动 $X$ 和其他经济量的冲击。 + +在离散时间中,日期 $t$ 和 $t+1$ 之间的冲击增量为 + +$$ +\Delta W_{t+1}=W_{t+1}-W_t. +$$ + +已知函数 $\phi_x$ 将今天的状态和下一个冲击增量映射到明天的状态。 + +离散时间的状态演化为 + +$$ +X_{t+1}=\phi_x(X_t,\Delta W_{t+1}). +$$ + +由该方程生成的条件律是有限矩阵中以当前状态 $x$ 为索引的行的一般状态替代物。 + +````{prf:assumption} 马尔可夫状态和冲击增量 +:label: assumption-mr-markov-shocks + +过程 $X$ 在 $P$ 下是遍历的。 + +给定 $X_t$ 时 $\Delta W_{t+1}$ 的条件分布不随时间变化,且在给定 $X_t$ 条件下与过去的冲击历史无关。 +```` + +滤波 $\{\mathcal F_t\}$ 由初始条件 $X_0$ 和直到日期 $t$ 的冲击历史生成。 + +### 信息与 $Y$ + +马尔可夫状态和揭示冲击的信息不必一致。 + +状态 $X_t$ 在日期 $t$ 被观测到。 + +下一个冲击 $\Delta W_{t+1}$ 不必能直接从对 $(X_t,X_{t+1})$ 观测得到。 + +如果 $(X_t,X_{t+1})$ 确实揭示了 $\Delta W_{t+1}$,那么 $X$ 本身就携带了相关的冲击信息。 + +如果不能,则引入一个具有平稳增量的辅助过程 $Y=\{Y_t\}$。 + +已知函数 $\phi_y$ 将今天的状态和下一个冲击增量映射到 $Y$ 的增量。 + +辅助增量的离散时间演化为 + +$$ +Y_{t+1}-Y_t=\phi_y(X_t,\Delta W_{t+1}). +$$ + +对 $(X_{t+1},Y_{t+1}-Y_t)$ 连同 $X_t$ 一起就足够丰富,以恢复冲击增量 $\Delta W_{t+1}$。 + +这个手段让模型能够处理影响收益和 SDF 但不能仅由下一个马尔可夫状态完全概括的冲击或增长成分。 + +将扩展过程记为 $Z=(X,Y)$。 + +过程 $Z$ 是马尔可夫的,具有三角结构:$(X_{t+1},Y_{t+1}-Y_t)$ 的条件分布仅通过 $X_t$ 依赖于过去。 + +$Z$ 的历史连同 $X_0$ 生成与冲击历史相同的信息。 + +这就是为什么下一个佩龙-弗罗贝尼乌斯问题可以首先用仅关于 $X$ 的特征函数来提出。 + +后面的 {ref}`mr_additional_state` 一节回到当允许特征函数也依赖于 $Y$ 时会发生什么变化。 + +### 乘性泛函 + +一般框架需要一种描述随时间复合的对象的方法。 + +这就是正的乘性泛函 $M=\{M_t\}$ 的作用。 + +它的对数增量是今天的状态和下一个冲击增量的函数: + +$$ +\log \frac{M_{t+1}}{M_t} += \kappa(X_t,\Delta W_{t+1}). +$$ + +等价地, + +$$ +\frac{M_{t+1}}{M_t} += \exp\{\kappa(X_t,\Delta W_{t+1})\}. +$$ + +因此 $M_t/M_0$ 是正的单期增量的乘积。 + +这是该论文中使用的乘性泛函的条件-1 版本。 + +正式定义稍微更宽泛,但这种形式涵盖了下面研究的模型。 + +在 {prf:ref}`assumption-mr-markov-shocks` 下,$M$ 的对数具有平稳增量。 + +正的乘性泛函的乘积和倒数仍然是正的乘性泛函。 + +$Y$ 的分量的线性组合的指数函数就是例子。 + +随机贴现因子、随机增长因子和正的乘性鞅都以这种方式建模。 + +在有限状态模型中,SDF 增量 $s_{ij}$ 是乘性泛函增量的一个例子。 + +改变概率的比值 $h_{ij}$ 是另一个例子。 + +### 随机贴现因子和定价算子 + +随机贴现因子 $S=\{S_t\}$ 是一个满足 $S_0=1$ 且在给定 $X_0$ 条件下具有有限一阶矩的正的乘性泛函。 + +设 $\Phi_t$ 是关于日期-$t$ 信息可测的有界收益。 + +$\Phi_t$ 在日期 $\tau$ 的价格为 + +$$ +\Pi_{\tau,t}(\Phi_t) += E\left[\frac{S_t}{S_\tau}\Phi_t\mid\mathcal F_\tau\right]. +$$ + +比值 $S_t/S_\tau$ 是从日期 $t$ 回到日期 $\tau$ 的随机贴现因子。 + +如果收益是未来马尔可夫状态的有界函数 $f(X_t)$,这个定价公式通过下式定义了一个视界-$t$ 算子 $Q_t$ + +$$ +[Q_t f](x) += E[S_t f(X_t)\mid X_0=x]. +$$ + +这个算子是将收益向量乘以阿罗价格矩阵 $\mathbf Q$ 的一般状态类比。 + +为了看清这种联系,再次假设状态空间是有限的且 $t=1$。 + +那么 + +$$ +[Q_1 f]_i += \sum_j s_{ij}p_{ij}f_j += \sum_j q_{ij}f_j. +$$ + +因此 $Q_1$ 恰好是矩阵 $\mathbf Q$。 + +在离散时间中,$S$ 的乘性性质意味着 $Q_t$ 是通过重复应用单期算子 $Q_1$ 得到的。 + +在连续时间中,族 $\{Q_t:t\geq0\}$ 是定价算子的半群。 + +### 鞅和等价概率测度 + +不同的随机贴现因子/概率对可以产生相同的定价算子,而这种灵活性是识别问题的来源。 + +对于这里使用的马尔可夫设定,感兴趣的概率变化由正的乘性鞅生成。 + +在概率变化的层面上,设 $H=\{H_t\}$ 是在 $P$ 下满足 $E[H_0]=1$ 的严格正的鞅。 + +对于在日期 $\tau$ 可观测的事件 $A$,改变后的概率测度 $P^H$ 定义为 + +$$ +P^H(A)=E[1_A H_\tau]. +$$ + +迭代期望定律使这个定义在各日期之间保持一致。 + +当 $H$ 也是乘性泛函时,使其成为乘性鞅,概率的变化保持了 $Z$ 的马尔可夫结构。 + +在 $P^H$ 下表示相同价格的 SDF 为 + +$$ +S_t^H=S_t\frac{H_0}{H_t}. +$$ + +因此相同的定价算子可以由对 $(S,P)$ 或对 $(S^H,P^H)$ 来表示。 + +在有限状态模型中,这就是 + +$$ +p^H_{ij}=h_{ij}p_{ij}, +\qquad +s^H_{ij}=\frac{s_{ij}}{h_{ij}}, +$$ + +使得 + +$$ +s^H_{ij}p^H_{ij}=s_{ij}p_{ij}=q_{ij}. +$$ + +因此,相同的阿罗价格可以通过改变概率测度并在 SDF 中抵消该变化来解释。 + +这也是阿罗价格本身不能识别信念的确切意义。 + +### 佩龙-弗罗贝尼乌斯恢复了什么 + +现在回到佩龙-弗罗贝尼乌斯步骤。 + +有限状态方程是 {eq}`eq-mr-pf-finite`。 + +一般状态的替代物是定价算子的特征函数问题:找到标量 $\hat\eta$ 和正函数 $\hat e$,使得对每个视界 $t$, + +```{math} +:label: eq-mr-pf-general + +[Q_t\hat e](x) +=\exp(\hat\eta t)\hat e(x). +``` + +正函数 $\hat e$ 是佩龙-弗罗贝尼乌斯特征向量的一般状态对应物。 + +标量 $\hat\eta$ 是对数特征值。 + +在有限状态中,$\hat e$ 只是一个每个状态对应一个分量的正向量。 + +在一般状态空间中,$\hat e(x)$ 是当前状态的正函数。 + +它的作用是记录长视界估值中依赖于状态的部分。 + +方程 {eq}`eq-mr-pf-general` 表明,等于 $\hat e(X_t)$ 的未来收益具有日期-0 价格 $\exp(\hat\eta t)\hat e(X_0)$。 + +因此 $\hat\eta$ 给出共同的增长率或贴现率,而 $\hat e$ 给出依赖于状态的缩放。 + +由于特征函数只在相差比例因子的意义下定义,唯一性始终意味着在相差正常数乘子的意义下的唯一性。 + +在一般状态空间中,正特征函数的存在性也是一个实质性条件。 + +特征函数方程蕴含条件矩限制 + +$$ +E[S_t\hat e(X_t)\mid\mathcal F_\tau] +=\exp((t-\tau)\hat\eta)S_\tau\hat e(X_\tau), +\qquad t\geq \tau. +$$ + +用这个限制来定义 + +```{math} +:label: eq-mr-hhat-process + +\frac{\hat H_t}{\hat H_0} +=\exp(-\hat\eta t)S_t + \frac{\hat e(X_t)}{\hat e(X_0)}. +``` + +这个过程是鞅,因为对于 $t\geq \tau$, + +$$ +\begin{aligned} +E\left[\frac{\hat H_t}{\hat H_0}\mid\mathcal F_\tau\right] +&= +\frac{\exp(-\hat\eta t)}{\hat e(X_0)} +E[S_t\hat e(X_t)\mid\mathcal F_\tau] \\ +&= +\frac{\exp(-\hat\eta t)}{\hat e(X_0)} +\exp((t-\tau)\hat\eta)S_\tau\hat e(X_\tau) \\ +&= +\exp(-\hat\eta \tau)S_\tau +\frac{\hat e(X_\tau)}{\hat e(X_0)} +=\frac{\hat H_\tau}{\hat H_0}. +\end{aligned} +$$ + +该过程是正的,因为 $S$ 和 $\hat e$ 是正的。 + +它的单期增量为 + +```{math} +:label: eq-mr-hhat-increment-general + +\frac{\hat H_{t+1}}{\hat H_t} += \exp(-\hat\eta)\frac{S_{t+1}}{S_t} + \frac{\hat e(X_{t+1})}{\hat e(X_t)}. +``` + +在有限状态模型中,当 $X_t=i$ 且 $X_{t+1}=j$ 时,{eq}`eq-mr-hhat-increment-general` 变为 + +$$ +\frac{\hat H_{t+1}}{\hat H_t} += \exp(-\hat\eta)s_{ij}\frac{\hat e_j}{\hat e_i} += \hat h_{ij} += \frac{\hat p_{ij}}{p_{ij}}. +$$ + +这与 {eq}`eq-mr-finite-sdf-decomposition` 是相同的三成分分解。 + +在有限状态中,{eq}`eq-mr-finite-sdf-decomposition` 等价于 + +$$ +\frac{S_{t+1}}{S_t} += \exp(\hat\eta) + \frac{\hat e(X_t)}{\hat e(X_{t+1})} + \frac{\hat H_{t+1}}{\hat H_t}. +$$ + +唯一的变化是记号:$\hat h_{ij}$ 是有限马尔可夫链中的单期密度比,而 $\hat H_{t+1}/\hat H_t$ 是一般马尔可夫设定中对应的单期密度比。 + +在给定 $X_0$ 条件下,直到日期 $t$ 的历史的似然比是 $\hat H_t/\hat H_0$。 + +对于 $\mathcal F_t$ 上的无条件测度,拉东-尼科迪姆密度是 $\hat H_t$,其中 $\hat H_0$ 调整初始分布。 + +如果 $\hat H_{t+1}/\hat H_t$ 不恒等于一,恢复的概率测度不同于正确设定的概率测度。 + +我们在下一节展示排除这种差异的限制条件。 + +### 选择与恢复 + +在有限不可约矩阵问题中,佩龙-弗罗贝尼乌斯理论给出一个在相差比例因子意义下唯一的正特征向量,因此恢复的转移矩阵由 $\mathbf Q$ 确定。 + +在一般状态空间中,正特征函数不一定存在,而当它存在时,多个正特征函数可能都能求解相同的定价算子问题。 + +因此该论文对候选特征函数所诱导的概率测度施加了一个选择条件。 + +````{prf:assumption} 恢复测度的遍历性 +:label: assumption-mr-ergodicity + +在 $P^{\hat H}$(由上一节定义的乘性鞅 $\hat H$ 诱导的概率测度)下,过程 $X$ 是平稳且遍历的。 +```` + +````{prf:proposition} 佩龙-弗罗贝尼乌斯解的唯一性 +:label: prop-mr-uniqueness + +对于佩龙-弗罗贝尼乌斯问题,至多存在一个解 $(\hat e, \hat\eta)$,使得在诱导的概率测度 $P^{\hat H}$ 下 $X$ 是平稳且遍历的。 +```` + +这个选出的解,当它存在时,识别了长期风险中性测度。 + +它本身并不识别主观信念。 + +要使恢复识别信念,需要对 SDF 施加额外的限制。 + +Ross 恢复使用的限制是该论文的条件 4: + +````{prf:assumption} +:label: assumption-mr-condition-4 + +设 + +$$ +S_t=\exp(-\delta t)\frac{m(X_t)}{m(X_0)} +$$ + +其中 $m$ 为某个正函数,$\delta$ 为实数。 +```` + +这是 {doc}`ross_recovery` 中的转移独立性限制,施加于想要恢复其概率测度的 SDF 表示上。 + +在这个限制下,令 $\hat e=1/m$ 且 $\hat\eta=-\delta$ 得到 + +$$ +\frac{\hat H_t}{\hat H_0} += \exp(\delta t) + \left[\exp(-\delta t)\frac{m(X_t)}{m(X_0)}\right] + \frac{1/m(X_t)}{1/m(X_0)} +=1. +$$ + +因此归一化后鞅成分恒等于一。 + +这是有限状态条件"对每个可行转移都有 $\hat h_{ij}=1$"的一般状态版本。 + +如果这个鞅不恒等于一,恢复的概率测度会吸收它,通常不同于正确设定的概率测度。 + +我们将在下一节看到一些重要的例子。 + +{ref}`mr_additional_state` 一节回到当允许特征函数依赖于辅助过程 $Y$ 时会发生什么。 + +### 连续时间版本 + +在讨论恢复失败的例子之前,让我们简要介绍连续时间中的模型。 + +我们引入扩散记号,因为下面的长期风险例子是用连续时间写的。 + +对象与之前相同: + +- $X$ 是马尔可夫状态, +- $Y$ 记录额外的增长或揭示冲击的成分, +- $M$ 是正的乘性泛函,例如 SDF、现金流增长过程,或用于改变概率的鞅。 + +在连续时间版本中,$W$ 是布朗运动。 + +状态、辅助过程和乘性泛函满足 + +$$ +\begin{aligned} +dX_t &= \mu_x(X_t)dt+\sigma_x(X_t)dW_t,\\ +dY_t &= \mu_y(X_t)dt+\sigma_y(X_t)dW_t,\\ +d\log M_t &= \beta(X_t)dt+\alpha(X_t)\cdot dW_t. +\end{aligned} +$$ + +这里 $\mu_x$ 和 $\mu_y$ 是漂移函数,而 $\sigma_x$ 和 $\sigma_y$ 是冲击暴露矩阵。 + +函数 $\beta$ 是 $\log M$ 的漂移,$\alpha$ 是 $\log M$ 的布朗冲击暴露。 + +对堆叠的冲击暴露矩阵的可逆性假设是离散时间条件"$(X_{t+1},Y_{t+1}-Y_t)$ 揭示冲击增量"的连续时间对应物。 + +它让 $Z=(X,Y)$ 的历史揭示布朗信息。 + +为使 $M$ 成为局部鞅,它的漂移必须满足 + +$$ +\beta(x)=-\frac{1}{2}\alpha(x)\cdot\alpha(x). +$$ + +这来自伊藤公式: + +$$ +\frac{dM_t}{M_t} += \left(\beta(X_t)+\frac{1}{2}\alpha(X_t)\cdot\alpha(X_t)\right)dt + + \alpha(X_t)\cdot dW_t. +$$ + +局部鞅在 $dM_t/M_t$ 中的漂移为零,这给出了所显示的限制。 + +然后额外的可积性条件确保这个局部鞅是真正的鞅。 + +在由具有这个暴露 $\alpha$ 的鞅 $H$ 诱导的概率测度下,$\widetilde W_t=W_t-\int_0^t\alpha(X_s)ds$ 是布朗运动。 + +按照这个符号约定,$X$ 的漂移从 $\mu_x$ 变为 $\mu_x+\sigma_x\alpha$,$Y$ 的漂移从 $\mu_y$ 变为 $\mu_y+\sigma_y\alpha$。 + +这是在有限状态模型中用 $h_{ij}p_{ij}$ 替换 $p_{ij}$ 的连续时间类比。 + +$Z$ 的马尔可夫和三角结构得以保持,这就是为什么可以应用相同的佩龙-弗罗贝尼乌斯分解。 + + +## 恢复何时失败 + +现在让我们讨论几个恢复的概率测度不同于正确设定的概率测度的例子。 + +### 递归效用 + +我们现在使用鞅成分来看恢复的概率测度何时不同于正确设定的概率测度。 + +在前面的例子中,SDF 中所有的风险调整都可以写成今天状态的函数与明天状态的函数之比。 + +佩龙-弗罗贝尼乌斯转移公式恰好抵消了这种项。 + +递归效用增加了一个延续值项。 + +关键点在于这个项的行为类似于上面定义的鞅增量。 + +对于 {cite:t}`BorovickaHansenScheinkman2016` 中的单位 EIS Epstein-Zin 情形,令 $C_t=\exp(g_c t)c(X_t)$,将平移后的延续值记为 $V_t=g_c t+v(X_t)$,并定义 + +$$ +v_i^*=\exp((1-\gamma)v_i). +$$ + +SDF 为 + +$$ +s_{ij} += \exp(-\delta-g_c) \frac{c_i}{c_j} + \frac{v_j^*}{\sum_k p_{ik}v_k^*}. +$$ + +在这个单位 EIS 例子中,佩龙-弗罗贝尼乌斯特征函数是 $\hat e_j=c_j$ 且 $\hat\eta=-(\delta+g_c)$。 + +因此应用佩龙-弗罗贝尼乌斯转移公式留下 + +$$ +\hat p_{ij} += p_{ij}\frac{v_j^*}{\sum_k p_{ik}v_k^*}. +$$ + +分母是给定当前状态 $i$ 时 $v_j^*$ 的条件期望。 + +因此最后一个分数在 $\mathbf{P}$ 下的条件均值为一。 + +因此它是一个鞅增量。 + +当 $v^*$ 不是常数时,该比值在下一期状态之间变化。 + +这种变化是为什么通过佩龙-弗罗贝尼乌斯理论恢复的概率测度不再给出正确设定的转移矩阵的原因。 + +下一个单元求解有限状态延续值方程并构建 SDF。 + +```{code-cell} ipython3 +def solve_ez_unit_eis(P, c, δ, γ, g_c, tol=1e-12, max_iter=10_000): + """有限状态单位 EIS Epstein-Zin 延续值和 SDF。""" + β = np.exp(-δ) + log_c = np.log(c) + n = len(c) + flow = (1 - β) * log_c + β * g_c + + if abs(γ - 1) < 1e-10: + v = linalg.solve(np.eye(n) - β * P, flow) + v_star = np.ones(n) + Pv_star = np.ones(n) + else: + v = log_c.copy() + for _ in range(max_iter): + v_star = np.exp((1 - γ) * v) + Pv_star = P @ v_star + v_new = flow + β / (1 - γ) * np.log(Pv_star) + if np.max(np.abs(v_new - v)) < tol: + v = v_new + break + v = v_new + else: + raise ValueError("Epstein-Zin fixed point did not converge.") + + v_star = np.exp((1 - γ) * v) + Pv_star = P @ v_star + + S = ( + np.exp(-δ - g_c) + * (c[:, None] / c[None, :]) + * (v_star[None, :] / Pv_star[:, None]) + ) + + return v, v_star, S +``` + +在对数效用下,$v^*$ 是常数且鞅增量为一。 + +随着风险厌恶上升,延续值变得更重要。 + +恢复的概率测度于是与正确设定的概率测度差异更大。 + +为了在一个小的三状态例子中使这个机制可见,下面的图使用了更加分散的消费向量 + +$$ +c=(0.85, 1.00, 1.15). +$$ + +热图报告鞅增量偏离一的百分比:$100(\hat h_{ij}-1)$。 + +正的项是在恢复的概率测度下比在正确设定的概率测度下接收更多概率的转移。 + +右图报告恢复的衰退概率的增加,以百分点度量。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 递归效用产生非常数的鞅增量。 + name: fig-mr-recursive-martingale +--- +c_recursive = np.array([0.85, 1.00, 1.15]) +γ_demo = 10.0 +_, _, S_demo = solve_ez_unit_eis(P_true, c_recursive, δ, γ_demo, g_c) +Q_demo = S_demo * P_true +H_demo, _, _, P_hat_demo = martingale_increment(Q_demo, P_true) +H_dev = 100 * (H_demo - 1) + +γ_grid = np.linspace(1, 15, 80) +rec_prob = [] +for γ in γ_grid: + _, _, S_g = solve_ez_unit_eis(P_true, c_recursive, δ, γ, g_c) + Q_g = S_g * P_true + _, _, _, P_hat_g = martingale_increment(Q_g, P_true) + rec_prob.append(stationary_dist(P_hat_g)[0]) +rec_prob = np.array(rec_prob) +rec_prob_gain = 100 * (rec_prob - π_true[0]) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4.5)) + +bound = np.max(np.abs(H_dev)) +im = axes[0].imshow(H_dev, cmap='RdBu_r', vmin=-bound, vmax=bound) +axes[0].set_xticks(range(3)) +axes[0].set_yticks(range(3)) +axes[0].set_xticklabels(state_names, rotation=20) +axes[0].set_yticklabels(state_names) +axes[0].set_xlabel('下一个状态') +axes[0].set_ylabel(r'当前状态') +axes[0].set_title(r'鞅增量, $\gamma=10$') + +for i in range(3): + for j in range(3): + axes[0].text(j, i, f"{H_dev[i, j]:.1f}", + ha='center', va='center', fontsize=9) +plt.colorbar(im, ax=axes[0], fraction=0.046, pad=0.04, + label=r'$100(\hat h_{ij}-1)$') + +axes[1].plot(γ_grid, rec_prob_gain, lw=2.5) +axes[1].axhline(0, ls='--', lw=1.5, color='0.5') +axes[1].set_xlabel(r"风险厌恶 $\gamma$") +axes[1].set_ylabel('衰退概率的增加\n(百分点)') +axes[1].set_title('恢复的衰退概率') +axes[1].set_ylim(0, rec_prob_gain.max() * 1.08) + +plt.tight_layout() +plt.show() +``` + +递归效用使恢复的概率测度对衰退转移赋予更多的概率。 + +在 $\gamma=10$ 时,转移进入衰退在恢复的概率测度下接收更多的概率,而转移进入扩张接收更少。 + +随着风险厌恶上升,恢复的概率测度下的平稳衰退概率进一步高于其正确设定的值。 + +因此,随着延续值项产生非常数的 $\hat h_{ij}$,与长期风险中性概率相关的转移矩阵不再等于正确设定的转移矩阵。 + +### 永久冲击 + +递归效用给出了一个非常数的鞅成分。 + +永久冲击提供了另一个。 + +假设消费具有永久冲击, + +$$ +\log C_{t+1}-\log C_t += g + x(X_{t+1})-x(X_t) + \sigma \varepsilon_{t+1}, +$$ + +其中 $\varepsilon_{t+1}$ 在时间上是独立的。 + +在幂效用下,SDF 包含 + +$$ +\exp(-\delta-\gamma g) +\exp\{-\gamma[x(X_{t+1})-x(X_t)]\} +\exp(-\gamma\sigma\varepsilon_{t+1}). +$$ + +中间项仅依赖于当前和下一个马尔可夫状态。 + +它是状态函数之比,因此佩龙-弗罗贝尼乌斯转移公式可以抵消它。 + +永久冲击项依赖于新的冲击 $\varepsilon_{t+1}$。 + +因为在这个构造中该冲击不能由有限马尔可夫状态概括,所以没有状态函数的比值可以抵消它。 + +除以其条件均值后,冲击项变成一个鞅增量: + +$$ +\frac{\exp(-\gamma\sigma\varepsilon_{t+1})} + {E[\exp(-\gamma\sigma\varepsilon_{t+1})]}. +$$ + +因此,即使在普通的幂效用下,永久消费冲击也能使恢复的概率测度不同于投资者的信念。 + +这个陈述是相对于恢复过程中使用的马尔可夫状态而言的。 + +扩大状态或信息结构以考虑该冲击可以容纳它,但这样做会导致 {ref}`mr_additional_state` 中讨论的识别问题。 + +### 长期风险 + +我们现在从小的有限状态例子转向一个标准的连续时间宏观金融模型。 + +该模型是 Bansal-Yaron 长期风险模型,使用 {cite:t}`BorovickaHansenScheinkman2016` 报告的校准。 + +目的是在一个标准的宏观金融模型中比较恢复的概率测度与正确设定的概率测度。 + +构造具有与之前相同的结构。 + +我们首先写下正确设定的状态动态,然后计算佩龙-弗罗贝尼乌斯方法所隐含的概率测度。 + +状态向量 $X_t=(X_{1t},X_{2t})'$ 遵循 + +$$ +\begin{aligned} +dX_{1t} +&= [\mu_{11}(X_{1t}-\iota_1)+\mu_{12}(X_{2t}-\iota_2)]dt + + \sqrt{X_{2t}}\sigma_1 dW_t, \\ +dX_{2t} +&= \mu_{22}(X_{2t}-\iota_2)dt + + \sqrt{X_{2t}}\sigma_2 dW_t . +\end{aligned} +$$ + +这里 $X_1$ 是可预测的消费增长,$X_2$ 是随机波动率。 + +代表性行为人具有单位跨期替代弹性的 Epstein-Zin 效用。 + +延续值引入了上面鞅成分的连续时间类比。 + +我们将该过程记为 $H^*$,SDF 满足 + +$$ +d\log S_t = -\delta dt - d\log C_t + d\log H_t^*. +$$ + +这里 $H^*$ 是进入 Epstein-Zin SDF 的延续值鞅。 + +与佩龙-弗罗贝尼乌斯问题相关的乘性鞅 $\hat H$ 只有在同时纳入佩龙-弗罗贝尼乌斯特征函数之后才能得到。 + +在消费增长中带有鞅成分的模型中,$H^*$ 和 $\hat H$ 不必一致。 + +下一个单元设定校准。 + +```{code-cell} ipython3 +lrr_params = dict( + δ=0.002, + γ=10.0, + μ11=-0.021, + μ12=0.0, + μ22=-0.013, + ι1=0.0, + ι2=1.0, + σ1=np.array([0.0, 0.00034, 0.0]), + σ2=np.array([0.0, 0.0, -0.038]), + β_c0=0.0015, + β_c1=1.0, + β_c2=0.0, + α_c=np.array([0.0078, 0.0, 0.0]), +) +``` + +下一个代码块计算不同的概率测度如何改变状态向量的漂移。 + +第一个量是延续值。 + +在这个仿射模型中,平移后的延续值是状态的线性函数: + +$$ +v(x) = v_0 + v_1 x_1 + v_2 x_2. +$$ + +这就是为什么我们称 $v_1$ 和 $v_2$ 为斜率。 + +它们是延续值关于可预测增长和波动率的导数。 + +这些斜率进入延续值鞅 $H^*$。 + +在代码中,这个鞅具有冲击暴露 + +$$ +\alpha_{H^*} += (1-\gamma)(\alpha_c + \sigma_1 v_1 + \sigma_2 v_2). +$$ + +由于 SDF 是 $d\log S_t=-\delta dt-d\log C_t+d\log H_t^*$,其冲击暴露为 + +$$ +\alpha_S = -\alpha_c + \alpha_{H^*}. +$$ + +这个向量 $\alpha_S$ 驱动单期风险中性测度变换。 + +第二个量是佩龙-弗罗贝尼乌斯特征函数。 + +它是指数仿射的: + +$$ +\hat e(x) = \exp(e_0 + e_1 x_1 + e_2 x_2). +$$ + +因此 $e_1$ 和 $e_2$ 是对数特征函数的斜率。 + +因为 $X_1$ 和 $X_2$ 具有冲击载荷 $\sigma_1$ 和 $\sigma_2$,佩龙-弗罗贝尼乌斯特征函数贡献了额外的冲击暴露 + +$$ +\sigma_1 e_1 + \sigma_2 e_2. +$$ + +因此,单期风险中性动态仅使用 $\alpha_S$,而长期风险中性测度下的动态使用 + +$$ +\alpha_S + \sigma_1 e_1 + \sigma_2 e_2. +$$ + +下面的函数遵循此顺序:计算 $(v_1, v_2)$,计算 $\alpha_S$ 和 $(e_1, e_2)$,然后将这些冲击暴露转化为 $X$ 的漂移。 + +```{code-cell} ipython3 +def solve_value_function(p): + """仿射延续值的斜率。""" + δ, γ = p["δ"], p["γ"] + μ11, μ12, μ22 = p["μ11"], p["μ12"], p["μ22"] + σ1, σ2 = p["σ1"], p["σ2"] + β_c1, β_c2 = p["β_c1"], p["β_c2"] + α_c = p["α_c"] + + # v1 是 v(x) 中可预测增长的系数。 + v1 = β_c1 / (δ - μ11) + + # v2 是波动率的系数。 + # 在仿射模型中它是一个标量二次方程的稳定根。 + A_vec = α_c + σ1 * v1 + B_vec = σ2 + + a = 0.5 * (1 - γ) * np.dot(B_vec, B_vec) + b = (μ22 - δ) + (1 - γ) * np.dot(A_vec, B_vec) + c = β_c2 + μ12 * v1 + 0.5 * (1 - γ) * np.dot(A_vec, A_vec) + + disc = b**2 - 4 * a * c + if disc < 0: + raise ValueError("Value function does not exist for these parameters.") + + v2 = (-b - np.sqrt(disc)) / (2 * a) + return v1, v2 + + +def solve_pf_lrr(p, v1, v2): + """佩龙-弗罗贝尼乌斯特征函数斜率和 SDF 扩散载荷。""" + δ, γ = p["δ"], p["γ"] + μ11, μ12, μ22 = p["μ11"], p["μ12"], p["μ22"] + ι1, ι2 = p["ι1"], p["ι2"] + σ1, σ2 = p["σ1"], p["σ2"] + α_c = p["α_c"] + β_c0, β_c1, β_c2 = p["β_c0"], p["β_c1"], p["β_c2"] + + # 延续值鞅暴露和 SDF 暴露。 + α_h_star = (1 - γ) * (α_c + σ1 * v1 + σ2 * v2) + α_s = -α_c + α_h_star + + # 佩龙-弗罗贝尼乌斯分解之前 log S 的漂移系数。 + β_s11 = -β_c1 + β_s12 = -β_c2 - 0.5 * np.dot(α_h_star, α_h_star) + β_s0 = -δ - β_c0 - 0.5 * ι2 * np.dot(α_h_star, α_h_star) + + # e1 和 e2 是 log e(x) = e0 + e1 x1 + e2 x2 中的系数。 + e1 = -β_s11 / μ11 + + # e2 求解来自佩龙-弗罗贝尼乌斯特征值方程的剩余二次方程。 + const = (β_s12 + 0.5 * np.dot(α_s, α_s) + + e1 * (μ12 + np.dot(σ1, α_s)) + + 0.5 * e1**2 * np.dot(σ1, σ1)) + lin = μ22 + np.dot(σ2, α_s) + e1 * np.dot(σ1, σ2) + quad = 0.5 * np.dot(σ2, σ2) + + disc = lin**2 - 4 * quad * const + roots = [(-lin - np.sqrt(disc)) / (2 * quad), + (-lin + np.sqrt(disc)) / (2 * quad)] + + candidates = [] + for e2 in roots: + eta = (β_s0 - β_s11 * ι1 - β_s12 * ι2 + - e1 * (μ11 * ι1 + μ12 * ι2) - e2 * μ22 * ι2) + candidates.append((eta, e2)) + + # 选择给出较小特征值指数的解。 + eta, e2 = min(candidates) + return e1, e2, eta, α_s + + +def recovered_lrr_dynamics(p, e1, e2, α_s): + """长期风险中性测度下的状态动态。""" + μ11, μ12, μ22 = p["μ11"], p["μ12"], p["μ22"] + ι1, ι2 = p["ι1"], p["ι2"] + σ1, σ2 = p["σ1"], p["σ2"] + + # 长期风险中性测度使用 SDF 暴露加上特征函数暴露。 + α_h = α_s + σ1 * e1 + σ2 * e2 + + # 扩散测度变换将每个漂移移动 sigma_i 点乘 alpha_h。 + μ_hat_11 = μ11 + μ_hat_12 = μ12 + np.dot(σ1, α_h) + μ_hat_22 = μ22 + np.dot(σ2, α_h) + + # 用均值回复形式重写移动后的漂移。 + ι_hat_2 = (μ22 / μ_hat_22) * ι2 + ι_hat_1 = ι1 + (μ12 * ι2 - μ_hat_12 * ι_hat_2) / μ11 + + return dict( + μ11=μ_hat_11, + μ12=μ_hat_12, + μ22=μ_hat_22, + ι1=ι_hat_1, + ι2=ι_hat_2, + σ1=σ1, + σ2=σ2, + α_h=α_h, + ) + + +def risk_neutral_lrr_dynamics(p, α_s): + """单期风险中性测度下的状态动态。""" + μ11, μ12, μ22 = p["μ11"], p["μ12"], p["μ22"] + ι1, ι2 = p["ι1"], p["ι2"] + σ1, σ2 = p["σ1"], p["σ2"] + + # 单期风险中性测度仅使用 SDF 暴露。 + μ_bar_11 = μ11 + μ_bar_12 = μ12 + np.dot(σ1, α_s) + μ_bar_22 = μ22 + np.dot(σ2, α_s) + + # 用均值回复形式重写移动后的漂移。 + ι_bar_2 = (μ22 / μ_bar_22) * ι2 + ι_bar_1 = ι1 + (μ12 * ι2 - μ_bar_12 * ι_bar_2) / μ11 + + return dict( + μ11=μ_bar_11, + μ12=μ_bar_12, + μ22=μ_bar_22, + ι1=ι_bar_1, + ι2=ι_bar_2, + σ1=σ1, + σ2=σ2, + ) +``` + +对于这里使用的校准,恢复的概率测度改变了长期状态分布。 + +它降低了预期增长的均值并提高了波动率的均值。 + +```{code-cell} ipython3 +v1, v2 = solve_value_function(lrr_params) +e1, e2, η_lrr, α_s = solve_pf_lrr(lrr_params, v1, v2) +dyn_hat = recovered_lrr_dynamics(lrr_params, e1, e2, α_s) +dyn_bar = risk_neutral_lrr_dynamics(lrr_params, α_s) + +print(f"值斜率: v1 = {v1:.4f}, v2 = {v2:.4f}") +print(f"特征函数系数: e1 = {e1:.4f}, e2 = {e2:.4f}") +print(f"对数特征值: eta = {η_lrr:.6f} " + f"(年化 {12 * η_lrr:.4f})") +print() +print("三种测度下的长期均值") +print("测度 iota_1 iota_2 mu_12 mu_22") +print("--------- -------- -------- -------- --------") +print(f"实际 {lrr_params['ι1']:8.5f} {lrr_params['ι2']:8.5f}" + f" {lrr_params['μ12']:8.5f} {lrr_params['μ22']:8.5f}") +print(f"单期 {dyn_bar['ι1']:8.5f} {dyn_bar['ι2']:8.5f}" + f" {dyn_bar['μ12']:8.5f} {dyn_bar['μ22']:8.5f}") +print(f"长期 {dyn_hat['ι1']:8.5f} {dyn_hat['ι2']:8.5f}" + f" {dyn_hat['μ12']:8.5f} {dyn_hat['μ22']:8.5f}") +``` + +这些数值清楚地展示了这个机制。 + +正的值斜率 $v_1$ 表明延续值对可预测的消费增长非常敏感。 + +在这个校准中波动率斜率 $v_2$ 为负,因此更高的波动率降低延续值。 + +特征函数系数 $e_1$ 具有相反的符号:长期测度变换对可预测增长具有负载荷。 + +因此恢复的概率测度对具有较低预期增长的历史赋予更多的概率。 + +正的 $e_2$ 对波动率具有相反的含义,对更高波动率状态赋予更多的概率。 + +该表将那些系数转化为状态动态。 + +相对于正确设定的概率测度,两个风险中性测度都降低了可预测增长的长期均值并提高了波动率的长期均值。 + +长期风险中性测度在那个方向上移动得比单期风险中性测度更远:$\iota_1$ 从 $0$ 下降到约 $-0.0027$,而 $\iota_2$ 从 $1$ 上升到约 $1.13$。 + +小的负对数特征值意味着 $\exp(\eta)$ 略低于一;按照通常的收益率符号约定,$-\eta$ 是对应的长期贴现率。 + +#### 平稳密度 + +系数表给出了概率测度之间差异的一个概括。 + +平稳密度图给出了另一个。 + +它不仅显示 $X_1$ 和 $X_2$ 的均值移动,还显示增长和波动率的哪些组合变得更可能。 + +这很重要,因为将恢复的概率测度视为信念改变了整个预测分布,而不仅仅是一对长期平均值。 + +在恢复的概率测度下,概率质量向不利的长期风险状态转移。 + +这些是具有较低可预测增长 $X_1$ 和较高波动率 $X_2$ 的状态。 + +虚线轮廓添加了单期风险中性概率测度。 + +在这个校准中,单期风险中性和长期风险中性平稳分布彼此接近,且两者都远离正确设定的分布。 + +因此,鞅成分解释了状态动态中大部分的风险调整。 + +该论文的图 1 报告了模型隐含的平稳密度;下面的模拟是对那些密度的数值近似。 + +下图模拟每个概率测度下的状态过程,并估计 $(X_2, X_1)$ 的平稳联合密度。 + +水平线标记 $X_1=0$,垂直线标记正确设定的波动率均值 $X_2=\iota_2$。 + +```{code-cell} ipython3 +def simulate_lrr(dyn, T=180_000, seed=123): + """ + 在一个概率测度下对 LRR 状态过程进行欧拉模拟。 + """ + rng = np.random.default_rng(seed) + X1 = np.zeros(T) + X2 = np.full(T, dyn["ι2"]) + + # 以月度时间增量进行欧拉步 + for t in range(1, T): + X2_prev = max(X2[t-1], 1e-9) + dW = rng.standard_normal(3) + sqrt_X2 = np.sqrt(X2_prev) + + X1[t] = ( + X1[t-1] + + dyn["μ11"] * (X1[t-1] - dyn["ι1"]) + + dyn["μ12"] * (X2_prev - dyn["ι2"]) + + sqrt_X2 * np.dot(dyn["σ1"], dW) + ) + X2[t] = max( + X2_prev + + dyn["μ22"] * (X2_prev - dyn["ι2"]) + + sqrt_X2 * np.dot(dyn["σ2"], dW), + 1e-9, + ) + + burn = T // 5 + return X1[burn:], X2[burn:] + + +def kde2d_contour(ax, X1, X2, label, levels=7, fill=True, + linestyle='solid', outer_only=False): + """估计平稳密度并绘制其等高线。""" + m = min(25_000, len(X1)) + idx = np.linspace(0, len(X1) - 1, m, dtype=int) + x1 = X1[idx] + x2 = X2[idx] + + kde = gaussian_kde(np.vstack([x2, x1])) + x2_grid = np.linspace(0.6, 1.6, 140) + x1_grid = np.linspace(-0.006, 0.006, 140) + X2g, X1g = np.meshgrid(x2_grid, x1_grid) + Z = kde(np.vstack([X2g.ravel(), X1g.ravel()])).reshape(X2g.shape) + + contour_levels = np.linspace(0.12 * Z.max(), 0.9 * Z.max(), levels) + if outer_only: + contour_levels = contour_levels[:1] + + if fill: + fill_levels = np.r_[contour_levels, Z.max()] + ax.contourf(X2g, X1g, Z, levels=fill_levels, cmap='Greys', + alpha=0.85) + ax.contour(X2g, X1g, Z, levels=contour_levels, colors='0.55', + linewidths=0.4) + ax.plot([], [], color='0.25', lw=1.5, label=label) + else: + ax.contour(X2g, X1g, Z, levels=contour_levels, colors='black', + linewidths=1.5, linestyles=linestyle) + ax.plot([], [], color='black', lw=1.5, ls=linestyle, label=label) + + +dyn_true = dict( + μ11=lrr_params["μ11"], + μ12=lrr_params["μ12"], + μ22=lrr_params["μ22"], + ι1=lrr_params["ι1"], + ι2=lrr_params["ι2"], + σ1=lrr_params["σ1"], + σ2=lrr_params["σ2"], +) + +X1_P, X2_P = simulate_lrr(dyn_true, seed=1) +X1_H, X2_H = simulate_lrr(dyn_hat, seed=2) +X1_B, X2_B = simulate_lrr(dyn_bar, seed=3) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4.8), sharex=True, sharey=True) +kde2d_contour(axes[0], X1_P, X2_P, label=r'正确设定 $\mathbf{P}$') +kde2d_contour(axes[1], X1_H, X2_H, + label=r'长期风险中性 $\hat{\mathbf{P}}$') +kde2d_contour(axes[1], X1_B, X2_B, + label=r'风险中性 $\bar{\mathbf{P}}$', + fill=False, linestyle='--', outer_only=True) + +for ax in axes: + ax.axhline(0, lw=0.8, ls='--') + ax.axvline(lrr_params["ι2"], lw=0.8, ls='--') + ax.set_xlim(0.6, 1.6) + ax.set_ylim(-0.006, 0.006) + ax.set_xlabel(r"条件波动率 $X_2$") + ax.legend(fontsize=9) + +axes[0].set_ylabel(r"平均增长率 $X_1$") +plt.tight_layout() +plt.show() +``` + +水平线以下的移动意味着较低的预期增长,而垂直线右侧的移动意味着较高的波动率。 + +#### 收益率含义 + +概率测度之间的差异对资产定价诠释很重要,因为收益率混合了两个量:一个收益预测和一个资产价格。 + +恢复的概率测度被称为长期风险中性,因为它吸收了给长视界风险定价的鞅成分。 + +对于随机增长的现金流,该论文的长视界结果是,在恢复的概率测度下,相对于期限匹配债券的风险溢价消失,这取决于用于极限的稳定性和矩条件。 + +在正确设定的概率测度下,那些相同的长期风险溢价不必消失。 + +对于现金流 $G_t$,将正确设定的概率测度下的期望记为 $E_P$,将恢复的概率测度下的期望记为 $E_{\hat P}$。 + +在正确设定的概率测度下计算的收益率为 + +$$ +y_t^P[G](x) += \frac{1}{t}\log E_P[G_t \mid X_0=x] + - \frac{1}{t}\log E_P[S_tG_t \mid X_0=x]. +$$ + +第一项是收益预测。 + +第二项是资产价格,用原始 SDF 表示写成。 + +阿罗价格决定第二项。 + +这里的问题是,如果分析师将恢复的概率测度 $\hat{\mathbf{P}}$ 视为投资者的信念,第一项会发生什么。 + +在那个比较中,价格保持固定,只重新计算预测项: + +$$ +y_t^{\hat P}[G](x) += \frac{1}{t}\log E_{\hat P}[G_t \mid X_0=x] + - \frac{1}{t}\log E_P[S_tG_t \mid X_0=x]. +$$ + +对于总消费收益,答案是显著的。 + +恢复的概率测度对低增长、高波动率状态赋予更多的概率,因此它预测更低的未来消费。 + +保持价格固定,那个较低的预测转化为较低的消费收益率。 + +零息债券是比较情形。 + +它的收益是一,因此预测项总是 $\log E[1]=0$。 + +因此改变信念不会移动债券收益率图。 + +同一个佩龙-弗罗贝尼乌斯问题的解也出现在长债券和远期测度极限中。 + +极长债券的极限单期回报为 + +$$ +R^\infty_{t,t+1} += \exp(-\hat\eta)\frac{\hat e(X_{t+1})}{\hat e(X_t)}. +$$ + +鞅增量满足 + +$$ +\frac{\hat H_{t+1}}{\hat H_t} += \frac{S_{t+1}}{S_t} R^\infty_{t,t+1}. +$$ + +因此来自远期测度的极限单期转移与长期风险中性概率相关的转移一致。 + +下面的计算使用长期风险模型隐含的仿射公式。 + +如果乘性泛函 $M$ 具有关于 $X$ 仿射的对数漂移和与 $\sqrt{X_2}$ 成比例的扩散,那么 + +$$ +E[M_t \mid X_0=x] += \exp\{\theta_0(t)+\theta_1(t)x_1+\theta_2(t)x_2\}, +$$ + +其中系数求解里卡蒂方程。 + +下面的代码在正确设定的测度下计算这些仿射期望,仅在恢复的概率测度下重新计算消费预测,并保持资产价格固定。 + +然后它在相同的模拟初始状态上绘制中位数和四分位区间收益率带。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: >- + 将恢复的概率测度用作信念的收益率含义。 + 虚线消费收益率带使用在恢复的概率测度下的收益预测,价格固定;债券收益率不变,因为零息收益没有预测项。 + name: fig-mr-lrr-figure-2 +--- +def affine_expectation_coeffs(dyn, β0, β1, β2, α, horizons): + """log E[M_t | X_0=x] 的里卡蒂系数。""" + μ11, μ12, μ22 = dyn["μ11"], dyn["μ12"], dyn["μ22"] + ι1, ι2 = dyn["ι1"], dyn["ι2"] + σ1, σ2 = dyn["σ1"], dyn["σ2"] + + def ode(_, θ): + θ0, θ1, θ2 = θ + θ0_dot = (β0 - β1 * ι1 - β2 * ι2 + - θ1 * (μ11 * ι1 + μ12 * ι2) + - θ2 * μ22 * ι2) + θ1_dot = β1 + μ11 * θ1 + θ2_dot = (β2 + μ12 * θ1 + μ22 * θ2 + + 0.5 * np.dot(α, α) + + θ1 * np.dot(σ1, α) + + θ2 * np.dot(σ2, α) + + 0.5 * θ1**2 * np.dot(σ1, σ1) + + θ1 * θ2 * np.dot(σ1, σ2) + + 0.5 * θ2**2 * np.dot(σ2, σ2)) + return [θ0_dot, θ1_dot, θ2_dot] + + sol = solve_ivp(ode, (0, horizons[-1]), np.zeros(3), + t_eval=horizons, rtol=1e-8, atol=1e-10) + if not sol.success: + raise ValueError("Riccati equation failed to solve") + return sol.y.T + + +def log_expectation(θ, X1, X2): + """在模拟状态上求 log E[M_t | X_0=x]。""" + return θ[:, 0, None] + θ[:, 1, None] * X1[None, :] + θ[:, 2, None] * X2[None, :] + + +def yield_quantiles(log_num, log_den, horizons): + """跨初始状态的年化收益率的四分位数。""" + yields = 12 * (log_num - log_den) / horizons[:, None] + return np.quantile(yields, [0.25, 0.5, 0.75], axis=1) + + +def transform_functional(β0, β1, β2, α, dyn_old, dyn_new, α_h): + """改变概率后重写乘性泛函。""" + # 漂移改变是因为鞅成分改变了用于预测现金流的 + # 布朗冲击暴露。 + β_level = β0 - β1 * dyn_old["ι1"] - β2 * dyn_old["ι2"] + β2_new = β2 + np.dot(α, α_h) + β0_new = β_level + β1 * dyn_new["ι1"] + β2_new * dyn_new["ι2"] + return β0_new, β1, β2_new, α + + +def sdf_coefficients(p, v1, v2): + """仿射期望计算中使用的 SDF 系数。""" + δ, γ = p["δ"], p["γ"] + α_c, σ1, σ2 = p["α_c"], p["σ1"], p["σ2"] + + α_h_star = (1 - γ) * (α_c + σ1 * v1 + σ2 * v2) + α_s = -α_c + α_h_star + + β_s1 = -p["β_c1"] + β_s2 = -p["β_c2"] - 0.5 * np.dot(α_h_star, α_h_star) + β_s0 = -δ - p["β_c0"] - 0.5 * p["ι2"] * np.dot(α_h_star, α_h_star) + + return β_s0, β_s1, β_s2, α_s + + +quarters = np.arange(1, 101) +horizons = 3 * quarters + +β_c0, β_c1, β_c2 = (lrr_params["β_c0"], + lrr_params["β_c1"], + lrr_params["β_c2"]) +α_c = lrr_params["α_c"] + +β_s0, β_s1, β_s2, α_s = sdf_coefficients(lrr_params, v1, v2) + +# 正确设定测度下收益率的分子和分母 +θ_C_P = affine_expectation_coeffs(dyn_true, β_c0, β_c1, β_c2, α_c, horizons) +θ_S_P = affine_expectation_coeffs(dyn_true, β_s0, β_s1, β_s2, α_s, horizons) +θ_SC_P = affine_expectation_coeffs( + dyn_true, β_s0 + β_c0, β_s1 + β_c1, β_s2 + β_c2, + α_s + α_c, horizons +) + +# 恢复的概率测度下总消费收益的分子 +β_Ch0, β_Ch1, β_Ch2, α_Ch = transform_functional( + β_c0, β_c1, β_c2, α_c, dyn_true, dyn_hat, dyn_hat["α_h"] +) +θ_C_H = affine_expectation_coeffs(dyn_hat, β_Ch0, β_Ch1, β_Ch2, + α_Ch, horizons) + +log_C_P = log_expectation(θ_C_P, X1_P, X2_P) +log_C_H = log_expectation(θ_C_H, X1_P, X2_P) +log_S_P = log_expectation(θ_S_P, X1_P, X2_P) +log_SC_P = log_expectation(θ_SC_P, X1_P, X2_P) + +qC_P = yield_quantiles(log_C_P, log_SC_P, horizons) +qC_H = yield_quantiles(log_C_H, log_SC_P, horizons) +qB_P = yield_quantiles(np.zeros_like(log_S_P), log_S_P, horizons) +# 零息收益在任一信念下都有相同的分子 log E[1] = 0。 +qB_H = qB_P.copy() + +fig, axes = plt.subplots(1, 2, figsize=(12, 4.8), sharex=True) + +def plot_yield_band(ax, x, q, color, label, linestyle='solid', + alpha=0.35): + """绘制四分位区间带和四分位线。""" + ax.fill_between(x, q[0], q[2], color=color, alpha=alpha, linewidth=0) + ax.plot(x, q[1], color=color, lw=2.4, ls=linestyle, label=label) + ax.plot(x, q[0], color=color, lw=1.3, ls=linestyle) + ax.plot(x, q[2], color=color, lw=1.3, ls=linestyle) + + +plot_yield_band(axes[0], quarters, qC_P, color='0.2', + label='正确设定测度', alpha=0.45) +plot_yield_band(axes[0], quarters, qC_H, color='0.65', + label='恢复的概率测度', linestyle='--', alpha=0.35) +plot_yield_band(axes[1], quarters, qB_P, color='0.2', + label='正确设定测度', alpha=0.45) +plot_yield_band(axes[1], quarters, qB_H, color='0.65', + label='恢复的概率测度', linestyle='--', alpha=0.25) + +axes[0].set_xlabel('期限(季度)') +axes[0].set_ylabel('消费到期收益率') +axes[1].set_xlabel('期限(季度)') +axes[1].set_ylabel('债券到期收益率') + +axes[0].legend(fontsize=9) + +plt.tight_layout() +plt.show() +``` + +左图是关键:将恢复的概率测度视为信念,对低增长、高波动率状态赋予更多的概率,因此消费的隐含预测更低,当价格保持固定时消费收益率下降。 + +债券图验证了零息比较。 + +由于在任何测度下 $\log E[1]=0$,实线和虚线债券收益率带重合。 + +(mr_additional_state)= +## 额外的状态向量 + +{cite:t}`BorovickaHansenScheinkman2016` 接着提出扩大状态向量是否会改变恢复问题的问题。 + +到目前为止,佩龙-弗罗贝尼乌斯特征函数仅依赖于马尔可夫状态 $X_t$。 + +但许多模型还包含一个增长成分 $Y_t$,例如对数消费,其增量由相同的冲击增量驱动。 + +这里 $\Delta W_{t+1}$ 表示日期 $t$ 和 $t+1$ 之间的冲击增量。 + +映射 $\phi_x$ 将今天的状态和下一个冲击增量送到明天的状态。 + +映射 $\phi_y$ 将今天的状态和下一个冲击增量送到 $Y$ 的增量。 + +$$ +X_{t+1}=\phi_x(X_t,\Delta W_{t+1}), +\qquad +Y_{t+1}-Y_t=\phi_y(X_t,\Delta W_{t+1}). +$$ + +设 $\varepsilon$ 表示一个特征函数候选,它被允许依赖于平稳状态 $X_t$ 和增长成分 $Y_t$。 + +设 $\zeta$ 是 $Y$ 上的载荷向量,$e_\zeta$ 是 $X$ 的正函数。 + +那么一个自然的候选是 + +$$ +\varepsilon(x,y)=\exp(\zeta \cdot y)e_\zeta(x). +$$ + +这种形式很自然,因为 $Y$ 通过增量进入。 + +沿着一条路径, + +$$ +\exp(\zeta \cdot Y_{t+1}) += \exp(\zeta \cdot Y_t) + \exp\{\zeta \cdot (Y_{t+1}-Y_t)\}. +$$ + +由于 $Y_{t+1}-Y_t$ 是 $(X_t,\Delta W_{t+1})$ 的函数,比值 $\exp(\zeta \cdot Y_{t+1})/\exp(\zeta \cdot Y_t)$ 是一个单期正的乘性泛函增量。 + +对于固定的 $\zeta$,这个因子将单期定价算子倾斜 $\exp\{\zeta \cdot (Y_{t+1}-Y_t)\}$。 + +因此依赖于 $x$ 的项并不是简单地重用早先的特征函数。 + +对于 $\zeta$ 的每个选择,剩余的依赖于 $x$ 的部分求解一个不同的佩龙-弗罗贝尼乌斯问题: + +$$ +E\left[ + \frac{S_{t+1}}{S_t} + \exp\{\zeta \cdot (Y_{t+1}-Y_t)\} + e_\zeta(X_{t+1}) + \mid X_t=x +\right] +=\exp(\eta_\zeta)e_\zeta(x). +$$ + +改变 $\zeta$ 会改变多少长期增长风险被载入特征函数。 + +因此,添加 $Y_t$ 可以使主观概率测度成为一个可能的解,但它也创造了一族可能的解。 + +因此额外的状态变量并不能消除识别问题;它通常使选择问题变得更明确。 + +该论文还指出了一个相关的实际问题。 + +高度持久的平稳过程可能难以与具有平稳增量的过程区分。 + +对于每个有限持久度水平,平稳近似可能对佩龙-弗罗贝尼乌斯问题有唯一解,但随着持久度变得极端,极限问题可能有许多近似解。 + +在数值上,这意味着恰好在用平稳模型近似随机增长的情形中,佩龙-弗罗贝尼乌斯问题的解可能是敏感的。 + +然而,有一条结构化的前进道路。 + +如果分析师提供一个已知与 SDF 具有相同鞅成分的参考乘性泛函 $Y^r$,那么可以将扩大的特征函数限制为形式 + +$$ +(Y^r)^{-1}e(x). +$$ + +这个限制选择了哪个长期鞅成分被允许进入特征函数。 + +有了这个额外的结构,阿罗价格可以再次揭示主观概率。 + +但关键的输入是外部的:长期鞅成分是由分析师提供的,而不是仅从阿罗价格中恢复的。 + +## 度量鞅成分 + +该论文还提出鞅成分在资产市场数据中有多大的问题。 + +在理性预期下,这度量了长期风险调整对估值有多重要。 + +在主观信念诠释下,只有在施加主观 SDF 本身没有鞅成分之后,它才度量主观信念与正确设定的概率测度之间的差异。 + +有了那个额外的限制,小的鞅成分会使恢复的概率测度接近信念,而大的鞅成分会使长期风险调整对恢复的概率测度更重要。 + +一族度量对鞅增量 $\hat H_{t+1}/\hat H_t$ 应用凸函数。 + +例如,条件相对熵使用 + +$$ +E\left[ + \frac{\hat H_{t+1}}{\hat H_t} + \log\frac{\hat H_{t+1}}{\hat H_t} + \mid X_t=x +\right]. +$$ + +这个表达式仅当鞅增量恒等于一时才为零。 + +在不完整的资产市场数据下,完整的鞅增量不可观测。 + +因此该论文使用定价限制和长债券回报近似来推导这类差异度量的下界。 + +这些界是一种方法,用于在不需要完整的阿罗价格集的情况下检验鞅成分在经济上是否很小。 + +## 教训 + +佩龙-弗罗贝尼乌斯方法在误设定下仍然有用,但它本身不再解决信念恢复问题。 + +它给出一个可能包含长视界风险溢价的概率测度。 + +只有当鞅成分恒等于一时,那个测度才等于投资者的信念。 + +递归效用、永久冲击和长期风险模型赋予这个鞅一个经济上重要的角色,因此在评估转移独立性对信念恢复的含义时不应忽视它。 + +## 练习 + +```{exercise} +:label: ex_misspecified_recovery_martingale_component + +**一个两状态鞅成分。** + +设 + +$$ +\mathbf{P} = +\begin{pmatrix} +0.8 & 0.2 \\ +0.4 & 0.6 +\end{pmatrix}, +\qquad +\mathbf{Q} = +\begin{pmatrix} +0.72 & 0.15 \\ +0.36 & 0.42 +\end{pmatrix}. +$$ + +1. 计算单期风险中性转移矩阵 $\bar{\mathbf{P}}$。 +2. 计算与恢复的概率测度相关的转移矩阵 $\hat{\mathbf{P}}$。 +3. 计算 $\hat h_{ij}=\hat p_{ij}/p_{ij}$ 并判断恢复是否返回正确设定的转移矩阵。 +``` + +```{solution-start} ex_misspecified_recovery_martingale_component +:class: dropdown +``` + +这是一个解: + +```{code-cell} ipython3 +P2 = np.array([[0.8, 0.2], + [0.4, 0.6]]) +Q2 = np.array([[0.72, 0.15], + [0.36, 0.42]]) + +Pbar2, qb2 = risk_neutral_probs(Q2) +H2, eta2, e2, Phat2 = martingale_increment(Q2, P2) + +print("单期风险中性转移矩阵 P_bar") +print(np.round(Pbar2, 4)) +print("\n与恢复的概率测度相关的转移矩阵 P_hat") +print(np.round(Phat2, 4)) +print("\n鞅增量 h_hat") +print(np.round(H2, 4)) +print("\n恢复返回 P:", np.allclose(H2[P2 > 0], 1)) +``` + +```{solution-end} +``` + +```{exercise} +:label: ex_power_utility_success + +**幂效用基准。** + +对于趋势平稳消费和幂效用, + +$$ +s_{ij}=A\left(\frac{c_j}{c_i}\right)^{-\gamma}. +$$ + +证明 $\hat e_i=c_i^\gamma$ 是佩龙-弗罗贝尼乌斯特征向量,且 $\hat{\mathbf{P}}=\mathbf{P}$。 + +然后使用讲座中的三状态基准进行数值验证。 +``` + +```{solution-start} ex_power_utility_success +:class: dropdown +``` + +解析检查是: + +$$ +[\mathbf{Q}\hat e]_i +=\sum_j A\left(\frac{c_j}{c_i}\right)^{-\gamma}p_{ij}c_j^\gamma +=A c_i^\gamma +=A\hat e_i. +$$ + +因此 $\exp(\hat\eta)=A$ 且 + +$$ +\hat p_{ij} +=\frac{1}{A}q_{ij}\frac{\hat e_j}{\hat e_i} +=p_{ij}. +$$ + +下面是数值检查。 + +```{code-cell} ipython3 +H_power, _, e_power, P_hat_power = martingale_increment(Q_power, P_true) +e_theory = c_levels**γ_power +e_theory = e_theory / e_theory.sum() + +print("佩龙-弗罗贝尼乌斯特征向量") +print(np.round(e_power, 6)) +print("\n归一化的 c^gamma") +print(np.round(e_theory, 6)) +print("\nmax |P_hat - P|:", + np.max(np.abs(P_hat_power - P_true))) +print("max |h_hat - 1|:", + np.max(np.abs(H_power[P_true > 0] - 1))) +``` + +```{solution-end} +``` + +```{exercise} +:label: ex_recursive_utility_martingale_component + +**递归效用和风险厌恶。** + +使用带有 $c=(0.85, 1.00, 1.15)$ 的有限状态 Epstein-Zin 例子,计算 $\gamma \in \{1, 5, 10, 15\}$ 时 $\hat{\mathbf{P}}$ 的平稳分布。 + +随着 $\gamma$ 上升,哪个状态的平稳概率增加最大? +``` + +```{solution-start} ex_recursive_utility_martingale_component +:class: dropdown +``` + +这是一个解: + +```{code-cell} ipython3 +for γ in [1, 5, 10, 15]: + _, _, S_g = solve_ez_unit_eis(P_true, c_recursive, δ, γ, g_c) + Q_g = S_g * P_true + _, _, _, P_hat_g = martingale_increment(Q_g, P_true) + π_g = stationary_dist(P_hat_g) + print(f"gamma={γ:2.0f}: {np.round(π_g, 4)}") + +print("\n正确设定:", np.round(π_true, 4)) +``` + +衰退状态的增加最大。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/morris_learn.md b/lectures/morris_learn.md new file mode 100644 index 0000000..e092fcf --- /dev/null +++ b/lectures/morris_learn.md @@ -0,0 +1,712 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.1 +kernelspec: + name: python3 + display_name: Python 3 (ipykernel) + language: python +translation: + title: 贝叶斯学习下的投机行为 + headings: + Overview: 概述 + Structure of the model: 模型结构 + Structure of the model::Possible trades: 可能的交易 + Information and beliefs: 信息与信念 + Source of heterogeneous priors: 异质先验的来源 + Beta priors: 贝塔先验 + Market prices with learning: 具有学习的市场价格 + Two Traders: 两个交易者 + Two Traders::Implementation: 实现 + 'Two Traders::Case A: global optimist (no premium)': 情形 A:全局乐观者(无溢价) + 'Two Traders::Case B: perpetual switching (positive premium)': 情形 B:永久切换(正溢价) + Two Traders::General N–trader extension: 一般的 N 交易者扩展 + Concluding remarks: 结束语 + Exercise: 练习 +--- + +(morris_learn)= +```{raw} jupyter + +``` + +# 贝叶斯学习下的投机行为 + +```{index} single: Models; Morris Learning +``` + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲介绍 {cite:t}`Morris1996` 如何扩展了 Harrison–Kreps 的投机资产定价模型 {cite}`HarrKreps1978`。 + +与 Harrison 和 Kreps 的模型一样,Morris 的模型确定了一种支付股息的资产的价格,该资产由具有异质信念的风险中性投资者进行交易。 + +Harrison-Kreps 模型假设交易者对资产的股息流具有教条式的、固定的信念。 + +Morris 用运用贝叶斯定律来更新其对未来股息信念的交易者,替换了 Harrison 和 Kreps 那些对股息流持有固定信念的交易者——随着新的股息数据到来,这些交易者会更新信念。 + +```{note} +Morris 的交易者不使用资产过去价格的数据来更新他们对股息过程的信念。 +``` + +Morris 模型环境的关键特征包括: + +* 所有交易者共享一套关于未来股息的统计模型 +* 单一参数为这套统计模型索引 +* 所有交易者观察到相同的股息历史 +* 所有交易者使用贝叶斯定律来更新信念 +* 交易者对该参数有不同的初始*先验分布* +* 交易者对该参数的*后验分布*最终会趋于一致 +* 在后验分布趋于一致之前,交易者对未来股息的预测密度存在分歧 + * 因此他们对资产价值存在分歧 + +正如在 Harrison 和 Kreps 的固定信念模型中一样,这些意见分歧会促使投资者从事以下意义上的*投机行为*: + + * 有时他们愿意为资产支付比他们认为的"基本"价值更高的价格,即其未来股息流的预期贴现值 + +在阅读本讲之前,你可能想复习以下 quantecon 讲座: + +* {doc}`Harrison-Kreps 模型 ` +* {doc}`似然比过程 ` +* {doc}`贝叶斯统计与频率派统计 ` + +让我们从一些标准导入开始: + +```{code-cell} ipython3 +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'] +``` + + + +## 模型结构 + +某种资产的股份供给量是固定的。 + +每一股赋予其所有者一个*二元* i.i.d. 股息流 $\{d_t\}$,其中 + +$$ +d_{t+1} \in \{0,1\} +$$ + +时刻 $t$ 的股息以未知概率 $\theta \in (0,1)$ 等于 $1$,以概率 $1-\theta$ 等于 $0$。 + +与 {cite}`HarrKreps1978` 中交易者对马尔可夫转移矩阵持有固定信念不同,在 Morris 的模型中: + +* 真实的股息概率 $\theta$ 是未知的 +* 交易者对 $\theta$ 有*先验信念* +* 交易者观察股息实现值,并通过贝叶斯定律更新信念 + +存在一个有限的*风险中性*交易者集合 $\mathcal{I}$。 + +所有交易者具有相同的贴现因子 $\beta \in (0,1)$。 + +* 你可以把 $\beta$ 看作通过 $\beta = 1/(1+r)$ 与净无风险利率 $r$ 相关联。 + +在第 $t$ 期末持有资产的所有者有权获得时刻 $t+1, t+2, \ldots$ 的股息。 + +由于股息过程是 i.i.d. 的,交易者 $i$ 认为资产的基本价值是股息流的资本化价值,即 $\sum_{j=1}^\infty \beta^j \hat \theta_i += \frac{\hat \theta_i}{r}$,其中 $\hat \theta_i$ 是该交易者关于 $\theta$ 的后验分布的均值。 + +### 可能的交易 + +交易者在每个时期 $t = 0, 1, 2, \ldots$ 于股息支付后,在竞争市场上买卖这种风险资产。 + +与 Harrison-Kreps 中一样: + +* 该资产以*除息*方式交易 +* 在时刻 $t$ 末持有一股的所有者有权获得时刻 $t+1$ 的股息 +* 在第 $t$ 期末持有一股的所有者还有权在收到时刻 $t+1$ 的股息后,于时刻 $t+1$ 出售该股份。 + +*禁止卖空*。 + +这一点很重要,因为它限制了悲观者表达其观点的方式: + +* 他们*可以*通过出售自己的股份来表达观点 +* 他们*不能*通过借入股份并立即出售的方式来更强烈地表达观点 + +所有交易者都有足够的财富来购买风险资产。 + +## 信息与信念 + +在时刻 $t \geq 1$,所有交易者观察到 $(d_1, d_2, \ldots, d_t)$。 + +所有交易者通过应用贝叶斯规则来更新他们关于 $\theta$ 的主观分布。 + +交易者对未知的股息概率 $\theta$ 具有*异质先验*。 + +先验中的这种异质性产生了异质的后验信念。 + +## 异质先验的来源 + +将不同的统计模型赋予模型内部的主体是有争议的。 + +许多博弈论学者和理性预期的应用经济学家认为这是个坏主意。 + +虽然这些经济学家经常构建其中主体拥有不同*信息*的模型,但他们更倾向于假设模型内部所有主体始终共享相同的统计模型——即对被建模的随机过程具有相同的联合概率分布。 + +对于统计学家或经济理论家而言,统计模型是由已知参数向量所刻画的联合概率分布。 + +当处理由参数(例如已知集合 $\Theta$ 中的 $\theta$)扫出的一*组*统计模型时,经济理论家通过将同一个关于 $\theta$ 的先验概率分布赋予模型内部所有主体,将这组模型简化为单一模型。 + + +```{note} +一组具有特定几何结构的统计模型称为统计模型的[流形](https://en.wikipedia.org/wiki/Manifold)。Morris 赋予交易者一个共享的统计模型流形。 +``` + +以这种方式进行遵循了*哈萨尼共同先验学说*。 + + + +{cite}`harsanyi1967games`、{cite}`harsanyi1968games`、{cite}`harsanyi1968games3` 论证说,如果两个理性主体具有相同的信息和相同的推理能力,他们对相关结果将具有相同的联合概率分布。 + +哈萨尼将关于未来结果的分歧解释为源于主体信息集的差异,而非其统计模型的差异。 + + +显然,{cite}`HarrKreps1978` 在固定教条式的不同信念时,背离了哈萨尼的共同统计模型假设。 + +{cite:t}`Morris1996` 对哈萨尼学说的背离不如 Harrison 和 Kreps 那么彻底。 + + * Morris 确实假设主体共享相同的统计模型集合,但 $\ldots$ + * Morris 假设他们对索引这些模型的参数具有不同的初始先验分布 + +Morris 的主体以不同的方式表达他们对参数的初始无知——他们具有不同的先验。 + + +Morris 通过援引 {cite}`miller1977risk` 提出的首次公开募股的明显"错误定价"来为他的假设辩护。 + +Miller 描述了这样一种情况:主体几乎没有或完全没有关于一个新企业的数据。 + +Morris 希望他的交易者在关于参数的信息到来时能够改变他们的观点。 + +众所周知,知识渊博的统计学家对于适当的先验会有分歧。 + +例如,Morris 描述了*不同*的、值得尊重的方式来表达对伯努利分布参数的"最大无知" + + * $[0, 1]$ 上的均匀分布 + * 对重参数化不变的杰弗里斯先验 {cite}`jeffreys1946invariant`;在当前情形下,杰弗里斯先验采取参数为 $.5, .5$ 的贝塔分布的形式 + +这些先验中的一个是否比另一个更"理性"? + +Morris 认为不是。 + + + + +## 贝塔先验 + +为了便于处理,假设交易者 $i$ 对股息概率具有贝塔先验 + +$$ +\theta \sim \text{Beta}(a_i, b_i) +$$ + +其中 $a_i, b_i > 0$ 是先验参数。 + +```{note} +贝塔分布也出现在以下 quantecon 讲座中 {doc}`divergence_measures`、{doc}`likelihood_ratio_process`、{doc}`odu`。 +``` + +假设交易者 $i$ 观察到一段 $t$ 期的历史,其中共支付了 $s$ 次股息(即 $s$ 次有股息的成功和 $t-s$ 次无股息的失败)。 + +根据贝叶斯规则,关于 $\theta$ 的后验密度为: + +$$ +\pi_i(\theta \mid s, t) = \frac{\theta^s (1-\theta)^{t-s} \pi_i(\theta)}{\int_0^1 \theta^s (1-\theta)^{t-s} \pi_i(\theta) d\theta} +$$ + +其中 $\pi_i(\theta)$ 是交易者 $i$ 的先验密度。 + +```{note} +贝塔分布是二项似然的共轭先验。这意味着当先验为 $\text{Beta}(a_i, b_i)$ 且我们在 $t$ 次试验中观察到 $s$ 次成功时,后验为 $\text{Beta}(a_i+s, b_i+t-s)$。 +``` + +后验均值(或预期股息概率)为: + +$$ +\mu_i(s,t) = \int_0^1 \theta \pi_i(\theta \mid s, t) d\theta += \mathbb{E}[\text{Beta}(a_i+s, b_i+t-s)] = \frac{a_i + s}{a_i + b_i + t} +$$ + +Morris 将 $\mu_i(s,t)$ 称为交易者 $i$ 在历史 $(s,t)$ 之后对资产的**基本估值**。 + +这是交易者 $i$ 赋予下一期收到股息的概率。 + +它嵌入了交易者 $i$ 关于 $\theta$ 的更新信念。 + +## 具有学习的市场价格 + +基本估值等于我们的异质交易者赋予*永久*持有资产这一选择的股息预期现值。 + +均衡价格过程由以下条件确定:在时刻 $t$ 资产由在时刻 $t$ 对资产赋予最高估值的交易者持有。 + +资产的所有者可以选择在收到当期股息后出售它。 + +交易者会将此考虑在内。 + +这就产生了一种可能性:交易者愿意为资产支付比该交易者的基本估值更高的价格。 + +```{prf:definition} 最乐观估值 +:label: most_optimistic_valuation + +在历史 $(s,t)$ 之后,*最乐观的基本估值*为: + +$$ +\mu^*(s,t) = \max_{i \in \mathcal{I}} \mu_i(s,t) +$$ +``` + +```{prf:definition} 均衡资产价格 +:label: equilibrium_asset_price + +将 $\tilde{p}(s,t,r)$ 记为当利率为 $r$ 时,在历史 $(s,t)$ 之后风险资产的竞争均衡价格(以当前美元计)。 + +均衡价格满足: + +$$ +\tilde{p}(s,t,r) = \frac{1}{1+r} \Bigl[ \mu^*(s,t) \{1 + \tilde{p}(s+1,t+1,r)\} ++ (1 - \mu^*(s,t)) \tilde{p}(s,t+1,r) \Bigr] +$$ +``` + +均衡价格等于所有交易者中持有资产至下一期所获得的最高预期贴现回报。 + +```{prf:definition} 归一化价格 +:label: normalized_price + +将归一化价格定义为: + +$$ +p(s,t,r) = r \tilde{p}(s,t,r) +$$ + +由于无风险资产当前的"美元"价格为 $1/r$,这表示以无风险资产为单位的风险资产价格。 +``` + +将前面的公式代入均衡条件得到: + +$$ +p(s,t,r) = \frac{r}{1+r} \mu^*(s,t) + \frac{1}{1+r} +\Bigl[ \mu^*(s,t) p(s+1,t+1,r) + (1 - \mu^*(s,t)) p(s,t+1,r) \Bigr] +$$ + +或等价地: + +$$ +p(s,t,r) = \mu^*(s,t) + \frac{r}{1+r} +\Bigl[ \mu^*(s,t) p(s+1,t+1,r) + (1 - \mu^*(s,t)) p(s,t+1,r) - \mu^*(s,t) \Bigr] +$$ + +满足均衡条件的价格函数可以递归计算。 + +设 $p^0(s,t,r) = 0$ 对所有 $(s,t,r)$ 成立,并通过下式定义 $p^{n+1}(s,t,r)$: + +$$ +p^{n+1}(s,t,r) = \frac{r}{1+r} \mu^*(s,t) + \frac{1}{1+r} +\Bigl[ \mu^*(s,t) p^n(s+1,t+1,r) + (1 - \mu^*(s,t)) p^n(s,t+1,r) \Bigr] +$$ + +序列 $\{p^n(s,t,r)\}$ 收敛到均衡价格 $p(s,t,r)$。 + +```{prf:definition} 投机溢价 +:label: speculative_premium + +当最乐观交易者的身份会随未来股息实现值而切换时,市场价格超过*每一位*交易者的基本估值。 + +以归一化单位表示: + +$$ +p(s,t,r) > \mu_i(s,t) \quad \text{对所有 } i \in \mathcal{I} +$$ + +将**投机溢价**定义为: + +$$ +p(s,t,r) - \mu^*(s,t) > 0 +$$ +``` + + +## 两个交易者 + +我们现在聚焦于一个具有两个交易者的例子,他们的贝塔先验参数分别为 $(a_1,b_1)$ 和 $(a_2,b_2)$。 + +```{prf:definition} 比率支配(贝塔先验) +:label: rate_dominance_beta + +如果满足以下条件,则交易者 1 **比率支配**交易者 2: + +$$ +a_1 \geq a_2 \quad \text{和} \quad b_1 \leq b_2 +$$ +``` + +```{prf:theorem} 全局乐观者(两个交易者) +:label: two_trader_optimist + +对于具有贝塔先验的两个交易者: + +1. 如果交易者 1 比率支配交易者 2,则交易者 1 是**全局乐观者**:对所有历史 $(s,t)$,有 $\mu_1(s,t) \geq \mu_2(s,t)$ +2. 在这种 $p(s,t,r) = \mu_1(s,t)$ 对所有 $(s,t,r)$ 成立的情形下,*不存在投机溢价*。 +``` + +当两个交易者中没有一个比率支配另一个时,最乐观交易者的身份可能随着股息累积而切换。 + +在发生永久切换的历史路径上,只要交易者继续存在分歧,资产价格就会严格超过两个交易者的基本估值: + +$$ +p(s,t,r) > \max\{\mu_1(s,t), \mu_2(s,t)\} +$$ + +因此,在这样的历史路径上,存在持续的投机溢价。 + +### 实现 + +为了便于计算,我们使用有限视界 $T$ 并通过后向归纳求解。 + +```{note} +在第 1122 页,{cite:t}`Morris1996` 提供了一个论证:这类有限视界经济当 $T\rightarrow + \infty$ 时的极限提供了一个有用的选择算法,它排除了涉及庞氏骗局价格成分的额外均衡,Morris 认为这些均衡是脆弱的,予以摒弃。 +``` + +遵循 {prf:ref}`equilibrium_asset_price`,我们使用贴现因子参数化 $\beta = 1/(1+r)$ 并通过下式计算美元价格 $\tilde{p}(s,t)$: + +$$ +\tilde{p}(s,t) = \beta \max_{i\in\{1,2\}} \Bigl[ \mu_i(s,t) \{1 + \tilde{p}(s+1,t+1)\} + (1-\mu_i(s,t)) \tilde{p}(s,t+1) \Bigr] +$$ + +我们将终端价格 $\tilde{p}(s,T)$ 设为最乐观信念下的永续年金价值。 + +```{code-cell} ipython3 +def posterior_mean(a, b, s, t): + """ + 计算 Beta(a, b) 先验的后验均值 μ_i(s,t)。 + """ + return (a + s) / (a + b + t) + +def perpetuity_value(a, b, s, t, β=.75): + """ + 计算永续年金价值 (β/(1-β)) * μ_i(s,t)。 + """ + return (β / (1 - β)) * posterior_mean(a, b, s, t) + +def price_learning_two_agents(prior1, prior2, β=.75, T=200): + """ + 通过后向归纳计算两个贝塔先验交易者的 \tilde p(s,t)。 + """ + a1, b1 = prior1 + a2, b2 = prior2 + price_array = np.zeros((T+1, T+1)) + + # 终端条件:设为最大信念下的永续年金价值 + for s in range(T+1): + perp1 = perpetuity_value(a1, b1, s, T, β) + perp2 = perpetuity_value(a2, b2, s, T, β) + price_array[s, T] = max(perp1, perp2) + + # 后向归纳 + for t in range(T-1, -1, -1): + for s in range(t, -1, -1): + μ1 = posterior_mean(a1, b1, s, t) + μ2 = posterior_mean(a2, b2, s, t) + + # 每个交易者信念下的单步延续值 + cont1 = μ1 * (1.0 + price_array[s+1, t+1]) \ + + (1.0 - μ1) * price_array[s, t+1] + cont2 = μ2 * (1.0 + price_array[s+1, t+1]) \ + + (1.0 - μ2) * price_array[s, t+1] + price_array[s, t] = β * max(cont1, cont2) + + def μ1_fun(s, t): + return posterior_mean(a1, b1, s, t) + def μ2_fun(s, t): + return posterior_mean(a2, b2, s, t) + + return price_array, μ1_fun, μ2_fun +``` + +(hk_go)= +### 情形 A:全局乐观者(无溢价) + +选择具有比率支配的先验,例如,交易者 1:$\text{Beta}(a_1,b_1)=(2,1)$ 和交易者 2:$(a_2,b_2)=(1,2)$。 + +交易者 1 是全局乐观者,因此归一化价格等于交易者 1 的基本估值:$p(s,t,r) = \mu_1(s,t)$。 + +```{code-cell} ipython3 +β = 0.75 +price_go, μ1_go, μ2_go = price_learning_two_agents( + (2,1), (1,2), β=β, T=200) + +perpetuity_1 = (β / (1 - β)) * μ1_go(0, 0) +perpetuity_2 = (β / (1 - β)) * μ2_go(0, 0) + +print("Price at (0, 0) =", price_go[0,0]) +print("Valuation of trader 1 at (0, 0) =", perpetuity_1) +print("Valuation of trader 2 at (0, 0) =", perpetuity_2) +``` + +价格等于交易者 1 的永续年金价值。 + +### 情形 B:永久切换(正溢价) + +现在假设交易者 1 具有 $\text{Beta}(1,1)$,交易者 2 具有 $\text{Beta}(1/2,1/2)$。 + +这些会产生交叉的后验,因此不存在全局乐观者,且价格在早期超过两者的基本价值。 + +```{code-cell} ipython3 +price_ps, μ1_ps, μ2_ps = price_learning_two_agents( + (1,1), (0.5,0.5), β=β, T=200) + +price_00 = price_ps[0,0] +μ1_00 = μ1_ps(0,0) +μ2_00 = μ2_ps(0,0) + +perpetuity_1 = (β / (1 - β)) * μ1_ps(0, 0) +perpetuity_2 = (β / (1 - β)) * μ2_ps(0, 0) + +print("Price at (0, 0) =", np.round(price_00, 6)) +print("Valuation of trader 1 at (0, 0) =", perpetuity_1) +print("Valuation of trader 2 at (0, 0) =", perpetuity_2) +``` + +由此产生的溢价反映了这样一种期权价值:当股息依次到来时,可以将资产转售给暂时变得更乐观的任一交易者。 + +在这一设定中,我们可以重现 {cite:t}`Morris1996` 报告的两个关键图形 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 归一化价格关于利率的图形 + name: fig-normalized-price-interest +--- +def normalized_price_two_agents(prior1, prior2, r, T=250): + """返回两个交易者的 p(s,t,r) = r \tilde p(s,t,r)。""" + β = 1.0 / (1.0 + r) + price_array, *_ = price_learning_two_agents(prior1, prior2, β=β, T=T) + return r * price_array + +# 图 I:p*(0,0,r) 作为 r 的函数 +r_grid = np.linspace(1e-3, 5.0, 200) +priors = ((1,1), (0.5,0.5)) +p00 = np.array([normalized_price_two_agents( + priors[0], priors[1], r, T=300)[0,0] + for r in r_grid]) + +fig, ax = plt.subplots() +ax.plot(r_grid, p00, lw=2) +ax.set_xlabel(r'$r$') +ax.set_ylabel(r'$p^*(0,0,r)$') +ax.axhline(0.5, color='C1', linestyle='--') +plt.show() +``` + +在第一幅图中,注意: + +- 转售期权将归一化价格 $p^*(0,0,r)$ 推高到基本价值 $(0.5)$ 之上,对任何有限的 $r$ 都成立。 + +- 随着 $r$ 增加($\beta$ 减小),期权价值消退,$p^*(0,0,r) \to 0.5$。 + +- 在 $r = 0.05$ 处,溢价约为 $8–9\%$,与 Morris (1996, 第 IV 节) 一致。 + + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 归一化价格关于时间的图形 + name: fig-normalized-price-time +--- +# 图 II:p*(t/2,t,0.05) 作为 t 的函数 +r = 0.05 +T = 60 +p_mat = normalized_price_two_agents(priors[0], priors[1], r, T=T) +t_vals = np.arange(0, 54, 2) +s_vals = t_vals // 2 +y = np.array([p_mat[s, t] for s, t in zip(s_vals, t_vals)]) + +fig, ax = plt.subplots() +ax.plot(t_vals, y, lw=2) +ax.set_xlabel(r'$t$') +ax.set_ylabel(r'$p^*(t/2,t,0.05)$') +ax.axhline(0.5, color='C1', linestyle='--') +plt.show() + +p0 = p_mat[0,0] +μ0 = 0.5 +print("Initial normalized premium at r=0.05 (%):", + np.round(100 * (p0 / μ0 - 1.0), 2)) +``` + +在第二幅图中,注意: + +- 沿对称路径 $s = t/2$,两个交易者的基本估值在每个 $t$ 处都等于 $0.5$,然而价格从高于 $0.5$ 开始,并随着学习减少分歧、转售期权失去价值而向 $0.5$ 下降。 + + +### 一般的 N 交易者扩展 + +同样的递归可以通过每一期对 $i$ 取最大值,扩展到任何有限的贝塔先验集合 $\{(a_i,b_i)\}_{i=1}^N$。 + +```{code-cell} ipython3 +def price_learning(priors, β=0.75, T=200): + """ + 具有异质贝塔先验的 N 交易者版本。 + """ + price_array = np.zeros((T+1, T+1)) + + def perp_i(i, s, t): + a, b = priors[i] + return perpetuity_value(a, b, s, t, β) + + # 终端条件 + for s in range(T+1): + price_array[s, T] = max( + perp_i(i, s, T) for i in range(len(priors))) + + # 后向归纳 + for t in range(T-1, -1, -1): + for s in range(t, -1, -1): + conts = [] + for (a, b) in priors: + μ = posterior_mean(a, b, s, t) + conts.append(μ * + (1.0 + price_array[s+1, t+1]) + + (1.0 - μ) * price_array[s, t+1]) + price_array[s, t] = β * max(conts) + + return price_array + +β = 0.75 +priors = [(1,1), (0.5,0.5), (3,2)] +price_N = price_learning(priors, β=β, T=150) + +# 计算每个交易者在 (0,0) 处的估值 +μ_vals = [posterior_mean(a, b, 0, 0) for a, b in priors] +perp_vals = [(β / (1 - β)) * μ for μ in μ_vals] + +print("Three-trader example at (s,t)=(0,0):") +print(f"Price at (0,0) = {np.round(price_N[0,0], 6)}") +print(f"\nTrader valuations:") +for i, (μ, perp) in enumerate(zip(μ_vals, perp_vals), 1): + print(f" Trader {i} = {np.round(perp, 6)}") +``` + +注意资产价格高于所有交易者的估值。 + +Morris 告诉我们在这种情况下不存在比率支配。 + +让我们使用下面的代码来验证这一点 + +```{code-cell} ipython3 +dominant = None +for i in range(len(priors)): + is_dom = all( + priors[i][0] >= priors[j][0] and priors[i][1] <= priors[j][1] + for j in range(len(priors)) if i != j) + if is_dom: + dominant = i + break + +if dominant is not None: + print(f"\nTrader {dominant+1} is the global optimist (rate-dominant)") +else: + print(f"\nNo global optimist and speculative premium exists") +``` + +的确,不存在全局乐观者,且存在投机溢价。 + +## 结束语 + +{cite:t}`Morris1996` 使用他的模型来解释 {cite}`miller1977risk` 描述的一种"热门发行"异象,根据该异象,首次公开募股的开盘市场价格似乎高于后来出现的价值价格。 + + + +## 练习 + +```{exercise-start} +:label: hk_ex3 +``` + +Morris {cite}`Morris1996` 对投机泡沫何时出现给出了尖锐的刻画。 + +关键条件是不存在*全局乐观者*。 + +在本练习中,你将为以下几组具有贝塔先验的交易者验证这一条件: + +1. 交易者 1:$\text{Beta}(2,1)$,交易者 2:$\text{Beta}(1,2)$ +2. 交易者 1:$\text{Beta}(1,1)$,交易者 2:$\text{Beta}(1/2,1/2)$ +3. 交易者 1:$\text{Beta}(3,1)$,交易者 2:$\text{Beta}(2,1)$,交易者 3:$\text{Beta}(1,2)$ +4. 交易者 1:$\text{Beta}(1,1)$,交易者 2:$\text{Beta}(1/2,1/2)$,交易者 3:$\text{Beta}(3/2,3/2)$ + +```{exercise-end} +``` + +```{solution-start} hk_ex3 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +def check_rate_dominance(priors): + """ + 检查是否有某个交易者比率支配所有其他交易者。 + """ + N = len(priors) + + for i in range(N): + a_i, b_i = priors[i] + is_dominant = True + + for j in range(N): + if i == j: + continue + a_j, b_j = priors[j] + + # 检查比率支配条件 + if not (a_i >= a_j and b_i <= b_j): + is_dominant = False + break + + if is_dominant: + return i + + return None + +# 测试用例 +test_cases = [ + ([(2, 1), (1, 2)], "Global optimist exists"), + ([(1, 1), (0.5, 0.5)], "Perpetual switching"), + ([(3, 1), (2, 1), (1, 2)], "Three traders with dominant"), + ([(1, 1), (0.5, 0.5), (1.5, 1.5)], "Three traders, no dominant") +] + +for priors, description in test_cases: + dominant = check_rate_dominance(priors) + + print(f"\n{description}") + print(f"Priors: {priors}") + print("=="*8) + if dominant is not None: + print(f"Trader {dominant+1} is the global optimist (rate-dominant)") + else: + print(f"No global optimist exists") + print("=="*8 + "\n") +``` + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/organization_capital.md b/lectures/organization_capital.md new file mode 100644 index 0000000..07ccef2 --- /dev/null +++ b/lectures/organization_capital.md @@ -0,0 +1,845 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.11.1 +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 组织资本 + headings: + Overview: 概述 + The basic idea: 基本思想 + Personnel information as organization capital: 人员信息作为组织资本 + Personnel information as organization capital::Setup: 设置 + Personnel information as organization capital::Three tasks: 三项任务 + Personnel information as organization capital::Bayesian learning: 贝叶斯学习 + Personnel information as organization capital::Per unit costs of production: 单位生产成本 + Personnel information as organization capital::Growth rate and screening time: 增长率与筛选时间 + 'Personnel information as organization capital::Combined effect: growth rate and per unit costs': 综合效应:增长率与单位成本 + Industry equilibrium: 行业均衡 + 'Industry equilibrium::Key property: growth rates independent of size': 关键性质:增长率与规模无关 + Bayesian screening simulation: 贝叶斯筛选模拟 + Team information: 团队信息 + Team information::Structure: 结构 + Firm-specific human capital: 企业专用人力资本 + Firm-specific human capital::Concave transformation frontier: 凹转换前沿 + Costs of transferring organization capital: 转移组织资本的成本 + Summary and implications: 总结与启示 +--- + +# 组织资本 + +```{index} single: Organization Capital +``` + +## 概述 + +本讲座描述了由 {cite:t}`Prescott_Visscher_1980` 提出的**组织资本**理论。 + +普雷斯科特和维斯彻将组织资本定义为企业积累的关于其员工、团队和生产过程的信息。 + +这些信息是企业的一项*资产*,因为它影响生产可能性集,并且与产出共同生产。 + +调整组织资本存量的成本约束了企业的增长率,这为以下现象提供了解释: + +1. 为什么企业增长率与企业规模无关(基布拉特定律) +1. 为什么快速增长的调整成本是内生产生的,而不是被假定的 + +该论文提供了组织资本的三个例子: + +* *人员信息*:关于员工与任务之间匹配的知识 +* *团队信息*:关于工人群体之间如何协作的知识 +* *企业专用人力资本*:通过在职培训提升的员工技能 + +在每种情况下,投资可能性都会导致企业以共同的速率增长,从而在快速规模调整的成本递增的同时产生规模报酬不变。 + +```{note} +该理论与 {cite:t}`Coase_1937` 和 {cite:t}`Williamson_1975` 关于企业性质的观点有关。 + +普雷斯科特和维斯彻强调企业作为信息仓库的角色,并认为企业内部创造了激励机制以促进对该信息的有效积累和使用。 +``` + +让我们从一些导入开始: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.stats import norm +from scipy.optimize import brentq +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 基本思想 + +企业是信息的仓库。 + +在企业内部,创造了激励机制以促进对该信息的有效积累和使用。 + +普雷斯科特和维斯彻利用这一概念来解释关于企业增长和规模分布的某些事实。 + +关键洞见是:信息积累的过程自然会导致 + +1. *规模报酬不变*,以及 +2. *快速企业规模调整的成本递增* + +规模报酬不变解释了为什么观察不到唯一的最优企业规模(参见 {cite:t}`Stigler_1958`)。 + +如果没有调整成本,企业在面对市场需求变化时的投资模式将呈现出我们观察不到的不连续性。 + +此外,如果没有对快速增长的成本惩罚,第一个发现先前未开发市场的企业将通过在有利可图的投资出现时占用所有这些投资来抢占竞争,从而意味着比实际更普遍的垄断。 + + +## 人员信息作为组织资本 + +```{index} single: Organization Capital; Personnel Information +``` + +组织资本的第一个例子是关于员工与任务之间匹配的信息。 + +### 设置 + +工人拥有不同的技能和才能。 + +变量 $\theta$ 衡量一个工人对某种特定工作的适应能力。 + +* $\theta$ 高的工人在需要反复关注细节的任务中具有比较优势 +* $\theta$ 低的工人在需要广泛定义职责的工作中具有比较优势 + +$\theta$ 的总体分布是均值为零、精度(方差的倒数)为 $\pi$ 的正态分布: + +$$ +\theta \sim N(0, 1/\pi) +$$ + +当从劳动力池中雇用一名工人时,工人和雇主都不知道 $\theta$。 + +两者都只知道总体分布。 + +### 三项任务 + +如果生产 $q$ 单位的产出,假设: + +* $\varphi_1 q$ 名工人被分配到*任务 1*(筛选) +* $\varphi q$ 名工人被分配到*任务 2* +* 其余工人被分配到*任务 3* + +其中 $\varphi_1 + 2\varphi = 1$。 + +```{note} +固定系数技术要求在职务 2 和 3 中的人员数量与分配到职务 1 的人员数量之间保持恒定比率。 +``` + +对于任务 1(筛选任务),单位生产成本对于分配人员的 $\theta$ 值是*不变*的。 + +然而,工人的 $\theta$ 越大,他在任务 2 中的产出相对于任务 3 中的产出就越大。 + +因此: + +* $\theta$ 高度为正的工人更适合任务 2 +* $\theta$ 高度为负的工人更适合任务 3 + +### 贝叶斯学习 + +任务 2 或任务 3 中的表现无法在个人层面观察到。 + +但是,关于工人 $\theta$ 值的信息可以从观察其在任务 1(筛选任务)中的表现获得。 + +监督学徒的专家每期确定一个 $z$ 值: + +$$ +z_{it} = \theta_i + \epsilon_{it} +$$ (eq:signal) + +其中 $\epsilon_{it} \sim N(0, 1)$ 在工人 $i$ 和期数 $t$ 上都是独立分布的。 + +在筛选工作中对一名工人进行 $n$ 次观察后,$\theta$ 的*后验分布*是正态分布,具有 + +*后验均值:* + +$$ +m = \frac{1}{\pi + n} \sum_{k=1}^{n} z_k +$$ (eq:post_mean) + +*后验精度:* + +$$ +h = \pi + n +$$ (eq:post_prec) + +因此,关于一个人的知识完全由这一对 $(m, h)$ 来刻画。 + +```{code-cell} ipython3 +def bayesian_update(z_observations, prior_precision): + """ + 观察信号后计算后验均值和精度。 + """ + n = len(z_observations) + h = prior_precision + n + m = np.sum(z_observations) / h + return m, h +``` + +让我们可视化当我们观察一名真实 $\theta = 0.8$ 的工人时后验如何演变: + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 后验均值收敛与不确定性 + name: fig-posterior-evolution +--- +np.random.seed(0) + +θ_true = 0.8 +π = 1.0 + +T = 20 +ε = np.random.randn(T) +z_signals = θ_true + ε + +posterior_means = [] +posterior_stds = [] + +for n in range(1, T + 1): + m, h = bayesian_update(z_signals[:n], π) + posterior_means.append(m) + posterior_stds.append(1 / np.sqrt(h)) + +fig, axes = plt.subplots(1, 2, figsize=(12, 5)) + +ax = axes[0] +ax.plot(range(1, T + 1), posterior_means, '-o', markersize=4, lw=2, + label='后验均值 $m$') +ax.axhline(θ_true, color='r', linestyle='--', + label=fr'真实 $\theta = {θ_true}$') +ax.set_xlabel('观察次数 $n$') +ax.set_ylabel('后验均值 $m$') +ax.legend() + +ax = axes[1] +ax.plot(range(1, T + 1), posterior_stds, '-o', markersize=4, lw=2, + label=r'后验标准差 $1/\sqrt{h}$') +ax.set_xlabel('观察次数 $n$') +ax.set_ylabel('后验标准差') +ax.legend() + +plt.tight_layout() +plt.show() +``` + +随着筛选观察次数 $n$ 的增加,后验均值收敛到真实的 $\theta$,后验不确定性以 $1/\sqrt{n}$ 的速率缩小。 + +### 单位生产成本 + +在非顺序分配规则下,资历最深的员工被分配到职务 2 和 3,而较新的员工留在筛选任务中。 + +$m > 0$ 的工人被分配到任务 2,$m \leq 0$ 的工人被分配到任务 3。 + +假设在 $n$ 个筛选期后进行此分配,单位生产成本为: + +$$ +c(n) = c_1 + c_2 + c_3 - E\{\theta \mid m > 0\} + E\{\theta \mid m \leq 0\} +$$ (eq:unit_cost) + +由于 $m$ 服从正态分布,对 {eq}`eq:unit_cost` 中的条件期望进行求值得到作为 $n$ 函数的单位成本: + +$$ +c(n) = c - 0.7978 \frac{n}{\pi(\pi + n)} +$$ (eq:cost_n) + +其中 $c = c_1 + c_2 + c_3$ 且 $0.7978 = 2 \int_0^{\infty} \frac{t}{\sqrt{2\pi}} e^{-t^2/2} dt$。 + +```{note} +常数 $0.7978 \approx \sqrt{2/\pi}$ 是标准半正态分布的均值。 + +它来源于对正态分布计算 $E[\theta \mid m > 0] - E[\theta \mid m \leq 0]$。 +``` + +函数 $c(n)$ 随 $n$ 以*递减的速率*下降。 + +更多的筛选观察降低了成本,但收益递减。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 按筛选时间的单位成本 + name: fig-cost-screening +--- +def cost_per_unit(n_vals, π, c_bar=1.0): + """ + 作为筛选期 n 函数的单位成本。 + """ + n_vals = np.asarray(n_vals, dtype=float) + return c_bar - 0.7978 * n_vals / (π * (π + n_vals)) + + +fig, ax = plt.subplots(figsize=(10, 6)) + +n_vals = np.linspace(0.1, 50, 200) + +for π in [0.5, 1.0, 2.0, 5.0]: + costs = cost_per_unit(n_vals, π) + ax.plot(n_vals, costs, lw=2, label=fr'$\pi = {π}$') + +ax.set_xlabel('筛选期 $n$') +ax.set_ylabel('单位成本 $c(n)$') +ax.legend() +ax.set_xlim(0, 50) +plt.tight_layout() +plt.show() +``` + +图表显示: + +* 成本随着更多的筛选时间 $n$ 而下降 +* 下降的速率是递减的(筛选的收益递减) +* 对于较小的先验精度 $\pi$(关于工人类型的初始不确定性更大),筛选带来的收益更大 + +这种收益递减的结构是*快速调整成本递增*的来源。 + + +### 增长率与筛选时间 + +增长率越大,$n$ 就必须越小——即在分配到职务 2 或 3 之前花在筛选任务上的时间越少。 + +如果 $\gamma$ 是产出的增长率,$\rho$ 是离职率,$y_i$ 是当前第 $i$ 代员工的数量,那么 + +$$ +(1 + \gamma) y_{i+1} = (1 - \rho) y_i +$$ + +令 $\xi = (1 - \rho)/(1 + \gamma)$,由上式得 $y_i = \xi^i y_0$。 + +对于固定系数技术,当前人员中代数大于 $n$ 的比例必须等于 $2\varphi / (\varphi_1 + 2\varphi)$,这给出: + +$$ +\xi^{n+1} = \frac{2\varphi}{\varphi_1 + 2\varphi} +$$ (eq:cutoff) + +求解 $n$ 作为 $\gamma$ 的函数: + +$$ +n(\gamma) = \frac{\log(2\varphi) - \log(\varphi_1 + 2\varphi)}{\log(1 - \rho) - \log(1 + \gamma)} - 1 \quad \text{对于 } \gamma > -\rho +$$ (eq:n_gamma) + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 筛选时间与增长率的关系 + name: fig-screening-growth +--- +def screening_time(γ, ρ, φ1, φ): + """ + 作为增长率 γ 函数的筛选时间 n。 + """ + γ = np.asarray(γ, dtype=float) + numerator = np.log(2 * φ) - np.log(φ1 + 2 * φ) + denominator = np.log(1 - ρ) - np.log(1 + γ) + return numerator / denominator - 1 + + +ρ = 0.1 +φ1 = 0.5 +φ = 0.25 + +γ_vals = np.linspace(-0.05, 0.30, 200) + +valid = γ_vals > -ρ +γ_valid = γ_vals[valid] +n_vals = screening_time(γ_valid, ρ, φ1, φ) +mask = n_vals > 0 +γ_plot = γ_valid[mask] +n_plot = n_vals[mask] + +fig, ax = plt.subplots(figsize=(10, 6)) +ax.plot(γ_plot, n_plot, lw=2) +ax.set_xlabel(r'增长率 $\gamma$') +ax.set_ylabel(r'筛选期 $n(\gamma)$') +ax.set_xlim(γ_plot[0], γ_plot[-1]) +plt.tight_layout() +plt.show() +``` + +图表显示了关键的权衡:*更快的增长迫使筛选期更短*。 + +当增长迅速时,新工人必须更快地从筛选任务提升到生产性任务,因此在分配之前收集到的关于每个工人的信息更少。 + + +### 综合效应:增长率与单位成本 + +将函数 $c(n)$ 和 $n(\gamma)$ 组合起来揭示了单位成本如何依赖于增长率: + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 单位成本与增长率的关系 + name: fig-cost-growth +--- +fig, ax = plt.subplots(figsize=(10, 6)) + +π = 1.0 +c_bar = 1.0 + +n_of_γ = screening_time(γ_plot, ρ, φ1, φ) +costs_of_γ = cost_per_unit(n_of_γ, π, c_bar) + +ax.plot(γ_plot, costs_of_γ, lw=2) +ax.set_xlabel(r'增长率 $\gamma$') +ax.set_ylabel(r'单位成本 $c(n(\gamma))$') +ax.set_xlim(γ_plot[0], γ_plot[-1]) +plt.tight_layout() +plt.show() +``` + +这确立了关键结果:*快速调整的成本递增内生地产生*于筛选与增长之间的权衡。 + +企业增长越快,其筛选工人的时间就越少,工人与任务之间的匹配就越差,单位生产成本就越高。 + + +## 行业均衡 + +```{index} single: Organization Capital; Industry Equilibrium +``` + +在这个模型中,企业增长率与企业规模无关,因为技术约束的数学结构与 {cite:t}`lucas1967adjustment` 中所考虑的相同,只是组织资本的存量是一个向量而不是一个标量。 + +面对价格接受型企业的技术集是一个**凸锥**:存在规模报酬不变。 + +规模报酬不变和内部调整成本,以及在企业之间转移资本的一些成本,产生了*与企业规模无关*的最优企业增长率——这就是基布拉特定律。 + +有界的、向下倾斜的反行业需求函数为 + +$$ +P_t = p(Q_t, u_t) +$$ + +其中 $Q_t$ 是所有企业产出之和,$u_t$ 是受平稳马尔可夫过程约束的需求冲击。 + +普雷斯科特和维斯彻使用 {cite:t}`Lucas_Prescott_1971` 的框架证明了竞争均衡的存在。 + +要最大化的贴现消费者剩余为 + +$$ +\sum_{t=0}^{\infty} \beta^t \left\{ \int_0^{Q_t} p(y, u_t) dy - Bw - Q_t \sum_i (A_{i2t} + A_{i3t}) c(i) / \sum_i (A_{i2t} + A_{i3t}) \right\} +$$ (eq:surplus) + +其中 $A_{i2t}, A_{i3t}$ 和 $B$ 分别通过对行业中所有企业求和 $a_{i2t}$、$a_{i3t}$ 和 $b$ 得到。 + + +### 关键性质:增长率与规模无关 + +如果两个企业在某一时点的组织资本向量 $\underline{k}$ 成比例,那么它们在所有未来时期都将成比例。 + +也就是说,*增长率与企业规模无关*。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 企业产出水平与增长率 + name: fig-firm-growth +--- +def simulate_firm_growth(T, γ, ρ, q0, seed=42): + """ + 模拟带有随机冲击的企业产出增长。 + """ + rng = np.random.default_rng(seed) + output = np.zeros(T) + output[0] = q0 + for t in range(1, T): + shock = rng.normal(0, 0.02) + output[t] = output[t-1] * (1 + γ + shock) + return output + + +T = 50 +γ_eq = 0.05 +ρ = 0.1 + +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +ax = axes[0] +for q0, label in [(10, '小企业'), (50, '中型企业'), + (200, '大企业')]: + output = simulate_firm_growth(T, γ_eq, ρ, q0, + seed=int(q0)) + ax.plot(range(T), output, lw=2, label=f'{label} ($q_0={q0}$)') +ax.set_xlabel('期') +ax.set_ylabel('产出 $q_t$') +ax.legend() + +ax = axes[1] +for q0, label in [(10, '小企业'), (50, '中型企业'), + (200, '大企业')]: + output = simulate_firm_growth(T, γ_eq, ρ, q0, + seed=int(q0)) + ax.plot(range(T), np.log(output), lw=2, + label=f'{label} ($q_0={q0}$)') +ax.set_xlabel('期') +ax.set_ylabel(r'$\log(q_t)$') +ax.legend() + +plt.tight_layout() +plt.show() +``` + +右图显示所有企业以相同的速率增长,无论初始规模如何——对数产出路径是平行的。 + +这就是**基布拉特定律**:增长率与企业规模无关。 + +## 贝叶斯筛选模拟 + +```{index} single: Organization Capital; Bayesian Screening +``` + +让我们模拟单个企业的完整筛选和分配过程。 + +我们从总体中抽取工人,观察他们在筛选任务中的信号,然后根据后验均值将他们分配到适当的生产性任务。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 筛选与工人分配准确性 + name: fig-screening-assignment +--- +def simulate_screening(n_workers, n_screen, π, seed=123): + """ + 模拟工人的筛选和分配。 + """ + rng = np.random.default_rng(seed) + + θ = rng.normal(0, 1/np.sqrt(π), n_workers) + signals = (θ[:, None] + + rng.normal(0, 1, (n_workers, n_screen))) + posterior_means = signals.sum(axis=1) / (π + n_screen) + + assignment = np.where(posterior_means > 0, 2, 3) + correct_assignment = np.where(θ > 0, 2, 3) + misassignment_rate = np.mean(assignment != correct_assignment) + + return { + 'theta': θ, + 'posterior_means': posterior_means, + 'assignment': assignment, + 'correct_assignment': correct_assignment, + 'misassignment_rate': misassignment_rate + } + + +π = 1.0 +n_workers = 5000 +screening_periods = [1, 3, 5, 10, 20, 50] + +fig, axes = plt.subplots(2, 3, figsize=(15, 10)) +axes = axes.flatten() + +misassignment_rates = [] + +for idx, n_screen in enumerate(screening_periods): + results = simulate_screening(n_workers, n_screen, π) + misassignment_rates.append(results['misassignment_rate']) + + ax = axes[idx] + θ = results['theta'] + m = results['posterior_means'] + + correct = results['assignment'] == results['correct_assignment'] + ax.scatter(θ[correct], m[correct], alpha=0.1, s=5, + color='blue', label='正确') + ax.scatter(θ[~correct], m[~correct], alpha=0.3, s=5, + color='red', label='错误分配') + ax.axhline(0, color='k', linewidth=0.5) + ax.axvline(0, color='k', linewidth=0.5) + mis = results['misassignment_rate'] + ax.set_xlabel(r'真实 $\theta$') + ax.set_ylabel('后验均值 $m$') + if idx == 0: + ax.legend(markerscale=5, loc='upper left') + +plt.tight_layout() +plt.show() +``` + +红点是被*错误分配*的工人——由于后验均值相对于其真实 $\theta$ 具有错误的符号而被安排到错误的生产性任务中。 + +随着 $n$ 增加: +* 后验均值 $m$ 与 $\theta$ 的相关性更强 +* 错误分配率下降 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 按筛选时间的错误分配率 + name: fig-misassignment-rate +--- +fig, ax = plt.subplots(figsize=(10, 6)) + +n_range = np.arange(1, 51) +mis_rates = [] +for n_screen in n_range: + results = simulate_screening(n_workers, n_screen, π) + mis_rates.append(results['misassignment_rate']) + +ax.plot(n_range, mis_rates, '-o', markersize=3, lw=2) +ax.set_xlabel('筛选期 $n$') +ax.set_ylabel('错误分配率') +plt.tight_layout() +plt.show() +``` + +这证实了理论预测:更好分配所带来的成本节约在筛选时间 $n$ 上呈现*收益递减*。 + +## 团队信息 + +```{index} single: Organization Capital; Team Information +``` + +人员信息不仅仅因为便于工人与任务的匹配而有价值。 + +人员信息的另一个同样有价值的用途是*工人与工人的匹配*。 + +对于企业内许多活动的表现来说,重要的不仅仅是分配到某项任务的个人的适应能力,还有该个人的特征与执行相关职责的其他人的特征的协调程度。 + +### 结构 + +假设工人被分组为团队,被分配到筛选任务的团队 $i$ 具有观察到的生产率指标 + +$$ +z_{it} = \theta_i + \epsilon_{it} +$$ + +其中: +* $\theta_i$ 是与团队工人配对得如何直接相关的确定性成分 +* $\epsilon_{it} \sim N(0, 1)$ 是独立同分布的随机成分 + +所有可能团队的 $\theta$ 近似地独立且正态分布 $N(\mu, 1/\pi)$。 + +在对团队 $i$ 进行 $n$ 次观察后,$\theta_i$ 的后验分布是正态分布,具有 + +$$ +m = \mu + \frac{1}{\pi + n} \sum_{k=1}^{n} (z_k - \mu) +$$ + +以及精度 $h = \pi + n$。 + +如果团队的解散也会解散所积累的信息,那么团队信息模型与人员信息模型具有*相同的数学结构*。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 按筛选期的团队质量估计 + name: fig-team-screening +--- +def simulate_team_screening(n_teams, n_screen, π, μ=0.5, + seed=456): + """ + 使用贝叶斯更新模拟团队筛选。 + """ + rng = np.random.default_rng(seed) + + θ = rng.normal(μ, 1/np.sqrt(π), n_teams) + signals = (θ[:, None] + + rng.normal(0, 1, (n_teams, n_screen))) + z_bar = signals.mean(axis=1) + post_means = μ + n_screen * (z_bar - μ) / (π + n_screen) + post_prec = π + n_screen + + return { + 'theta': θ, + 'posterior_means': post_means, + 'posterior_precision': post_prec + } + + +fig, axes = plt.subplots(1, 3, figsize=(15, 5)) + +for idx, n_screen in enumerate([1, 5, 20]): + results = simulate_team_screening(500, n_screen, π=1.0, μ=0.5) + + ax = axes[idx] + ax.scatter(results['theta'], results['posterior_means'], + alpha=0.4, s=10) + lims = [-1.5, 2.5] + ax.plot(lims, lims, 'r--', alpha=0.5, lw=2, label='45° 线') + ax.set_xlabel(r'真实团队质量 $\theta$') + ax.set_ylabel('后验均值 $m$') + ax.set_xlim(lims) + ax.set_ylim(lims) + ax.legend() + ax.set_aspect('equal') + +plt.tight_layout() +plt.show() +``` + +与个人筛选一样,更多的观察改善了团队质量估计的精度。 + +快速增长迫使在团队分配必须最终确定之前进行更少的观察,从而导致更高的成本。 + + +## 企业专用人力资本 + +```{index} single: Organization Capital; Human Capital +``` + +第三个例子:组织资本由企业员工的**人力资本**构成。 + +组织作为生产单位有效运作的能力在很大程度上取决于员工技能的水平和协调程度。 + +```{note} +员工的人力资本作为企业资本存量一部分的论点已经确立(参见 {cite:t}`Becker_1975`)。 + +未来的生产率取决于未来的人力资本水平,但为了获得未来的人力资本,需要在当下牺牲实际资源。 +``` + +关键特征是: + +* 产出和技能提升是由拥有不同技能水平的劳动投入组合而产生的**联合产品** + +* 有经验和无经验的工人在几种可用技术过程之一中组合起来生成企业的产品,在此过程中,劳动力的整体能力得到提升 + +* 当前产出和未来人力资本之间的转换前沿是*凹的*且线性齐次的 + +这使技术集具有以原点为顶点的闭凸锥的结构——足以使企业实现最优的比例增长。 + +### 凹转换前沿 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 凹转换前沿 + name: fig-transformation-frontier +--- +def transformation_frontier(q, α=0.7): + """ + 产出与人力资本之间的凹转换前沿。 + """ + q = np.asarray(q, dtype=float) + return (1 - q**α)**(1/α) + + +fig, ax = plt.subplots(figsize=(8, 8)) + +q_vals = np.linspace(0, 1, 200) + +for α in [0.5, 0.7, 1.0, 1.5]: + hk = transformation_frontier(q_vals, α) + ax.plot(q_vals, hk, + label=fr'$\alpha = {α}$', lw=2) + +ax.set_xlabel('当前产出 $q$(产能的比例)') +ax.set_ylabel('未来人力资本增量 $\\Delta h$') +ax.legend() +ax.set_xlim(0, 1.05) +ax.set_ylim(0, 1.05) +ax.set_aspect('equal') +plt.tight_layout() +plt.show() +``` + +转换前沿的凹性意味着从极度不平衡的生产和学习活动组合转向更平衡的组合几乎不需要什么牺牲。 + +但是主要由学习组成的工作日也有收益递减,这产生了快速调整的成本。 + + +## 转移组织资本的成本 + +```{index} single: Organization Capital; Transfer Costs +``` + +如果将组织资本从一个企业转移到另一个企业没有成本,那么该模型就不会对企业的增长率施加约束。 + +那样,企业可以合并、剥离或挖走彼此的员工而不受成本惩罚,从而产生不受模型限制的增长模式。 + +然而,组织资本*不能*无成本地移动: + +1. *搬迁具有破坏性*:从一个地方搬到另一个地方对员工和家庭都具有破坏性 + +2. *信息是企业专用的*:使某人在一个组织中富有生产力的信息集可能不会使该人在另一个组织中同样富有生产力,即使两个企业生产相同的产出 + + * 在一家企业熟练使用计算机系统 + * 知道出现问题时该向谁求助 + * 与买家或卖家的融洽关系 + +这些都是一个企业中*无法无成本转移*到另一个企业的组织资本类型。 + + +## 总结与启示 + +普雷斯科特-维斯彻模型提供了一个统一的框架,其中: + +* 企业作为一个实体存在,因为它是积累、存储和使用信息的有效结构 + +* *规模报酬不变*的产生是因为一旦发现工人类型的最佳组合,就没有什么能阻止企业复制这些组合并按比例获得产品收益 + +* *调整成本递增*内生地产生于当前生产与组织资本投资之间的权衡 + +* *基布拉特定律*——增长率与企业规模无关——是一个自然的推论 + +* 大企业的增长率应显示出比小企业*更小的方差*,因为大企业本质上是较小生产单位的组合 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 按企业规模的增长率分布 + name: fig-growth-rate-dist +--- +def simulate_growth_rate_distribution(n_firms, n_subunits, γ, + σ, T=100, seed=789): + """ + 模拟不同规模企业的增长率分布。 + """ + rng = np.random.default_rng(seed) + subunit_growth = rng.normal(γ, σ, + (n_firms, n_subunits, T)) + firm_growth = subunit_growth.mean(axis=1) + return firm_growth.mean(axis=1) + + +fig, ax = plt.subplots(figsize=(10, 6)) + +sizes = {'小型(1 个单位)': 1, + '中型(5 个单位)': 5, + '大型(20 个单位)': 20} + +γ = 0.05 +σ = 0.10 + +for label, n_sub in sizes.items(): + rates = simulate_growth_rate_distribution( + 2000, n_sub, γ, σ) + ax.hist(rates, bins=50, alpha=0.5, density=True, + label=f'{label}: std={rates.std():.4f}') + +ax.set_xlabel('平均增长率') +ax.set_ylabel('密度') +ax.legend() +ax.axvline(γ, color='k', linestyle='--', + label=r'$\gamma$', alpha=0.5) +plt.tight_layout() +plt.show() +``` + +图表显示,尽管所有企业都有*相同的平均增长率*(基布拉特定律),大企业在实现的增长率中显示出*更小的方差*,因为它们实际上是独立子单位的组合。 + +这与 {cite:t}`Mansfield_1962` 和 {cite:t}`Hymer_Pashigian_1962` 的经验发现一致。 + +普雷斯科特-维斯彻理论的本质是企业的性质与*组织资本*相关联。 + +将企业与其他关系区分开来的是,它是一种结构,在这种结构中,代理人有激励以一种比可能的替代制度成本更低的方式来获取和揭示信息。 \ No newline at end of file diff --git a/lectures/os_egm.md b/lectures/os_egm.md new file mode 100644 index 0000000..ed6e363 --- /dev/null +++ b/lectures/os_egm.md @@ -0,0 +1,365 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 最优储蓄 V:内生网格法 + headings: + Overview: 概述 + Key Idea: 核心思想 + Key Idea::Theory: 理论 + Key Idea::Exogenous Grid: 外生网格 + Key Idea::Endogenous Grid: 内生网格 + Implementation: 实现 + Implementation::The Operator: 算子 + Implementation::Testing: 测试 +--- + +```{raw} jupyter + +``` + +# {index}`最优储蓄 V:内生网格法 ` + +```{contents} Contents +:depth: 2 +``` + +除了 Anaconda 中已有的库之外,本讲座还需要以下库: + +```{code-cell} python3 +:tags: [hide-output] + +!pip install quantecon +``` + +## 概述 + +之前,我们使用以下方法求解了最优储蓄问题: + +1. {doc}`价值函数迭代 ` +1. {doc}`基于欧拉方程的时间迭代 ` + +我们发现时间迭代明显更加精确和高效。 + +在本讲座中,我们将探讨一种巧妙的时间迭代变体,称为**内生网格法**(EGM)。 + +EGM 是一种用于实现策略迭代的数值方法,由 [Chris Carroll](https://econ.jhu.edu/directory/christopher-carroll/) 发明。 + +原始参考文献是 {cite}`Carroll2006`。 + +现在我们将专注于一个简洁且贴近底层数学的 EGM 实现。 + +然后,在 {doc}`os_egm_jax` 中,我们将基于 JAX 构建一个完全向量化和并行化的 EGM 版本。 + +让我们从一些标准导入开始: + +```{code-cell} python3 +import matplotlib.pyplot as plt +import numpy as np +import quantecon as qe +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 核心思想 + +首先我们回顾一下理论,然后转向数值方法。 + +### 理论 + +我们使用 {doc}`os_time_iter` 中提出的模型,遵循相同的术语和记号。 + +正如我们所见,Coleman-Reffett 算子是一个非线性算子 $K$,其设计使得最优策略 +$\sigma^*$ 是 $K$ 的一个不动点。 + +它以一个连续严格递增的消费策略 $\sigma \in \Sigma$ 作为参数。 + +它返回一个新函数 $K \sigma$,其中 $(K \sigma)(x)$ 是求解以下方程的 $c \in (0, \infty)$: + +```{math} +:label: egm_coledef + +u'(c) += \beta \int (u' \circ \sigma) (f(x - c) z ) f'(x - c) z \phi(dz) +``` + +### 外生网格 + +正如 {doc}`os_time_iter` 中所讨论的,为了在计算机上实现该方法,我们通过有限网格上的一组值来表示策略函数。 + +在必要时,通过插值或其他方法从这个表示中重构函数本身。 + +我们之前在 {doc}`os_time_iter` 中获取更新后的消费策略的有限表示的策略是: + +* 固定一个收入点网格 $\{x_i\}$ +* 使用 {eq}`egm_coledef` 和求根程序计算对应于每个 $x_i$ 的消费值 $c_i$ + +然后将每个 $c_i$ 解释为函数 $K \sigma$ 在 $x_i$ 处的值。 + +因此,有了 $\{(x_i, c_i)\}$ 这些点对,我们就可以通过近似来重构 $K \sigma$。 + +然后迭代继续…… + + +### 内生网格 + +上面讨论的方法需要一个求根程序来找到对应于给定收入值 $x_i$ 的 $c_i$。 + +求根的代价很高,因为它通常涉及大量的函数求值。 + +正如 Carroll {cite}`Carroll2006` 所指出的,如果 $x_i$ 是内生选择的,我们就可以避免这一步骤。 + +唯一需要的假设是 $u'$ 在 $(0, \infty)$ 上可逆。 + +设 $(u')^{-1}$ 为 $u'$ 的反函数。 + +思路如下: + +* 首先,我们为储蓄($s = x - c$)固定一个*外生*网格 $\{s_i\}$。 +* 然后我们通过以下方式获得 $c_i$: + +```{math} +:label: egm_getc + +c_i = +(u')^{-1} +\left\{ + \beta \int (u' \circ \sigma) (f(s_i) z ) \, f'(s_i) \, z \, \phi(dz) +\right\} +``` + +* 最后,对于每个 $c_i$,我们设 $x_i = c_i + s_i$。 + +重要的是,以这种方式构造的每个 $(x_i, c_i)$ 点对都满足 {eq}`egm_coledef`。 + +有了 $\{x_i, c_i\}$ 这些点后,我们可以像之前一样通过近似来重构 $K \sigma$。 + +EGM 这个名称源于网格 $\{x_i\}$ 是**内生**确定的这一事实。 + + +## 实现 + +与 {doc}`os_time_iter` 中一样,我们将从一个简单的设定开始,其中 + +* $u(c) = \ln c$, +* 函数 $f$ 具有科布-道格拉斯形式,并且 +* 冲击是对数正态的。 + +这将使我们能够与解析解进行比较。 + +```{code-cell} python3 +def v_star(x, α, β, μ): + """ + 真实价值函数 + """ + c1 = np.log(1 - α * β) / (1 - β) + c2 = (μ + α * np.log(α * β)) / (1 - α) + c3 = 1 / (1 - β) + c4 = 1 / (1 - α * β) + return c1 + c2 * (c3 - c4) + c4 * np.log(x) + +def σ_star(x, α, β): + """ + 真实最优策略 + """ + return (1 - α * β) * x +``` + +我们重用 {doc}`os_time_iter` 中的 `Model` 结构。 + +```{code-cell} python3 +from typing import NamedTuple, Callable + +class Model(NamedTuple): + u: Callable # 效用函数 + f: Callable # 生产函数 + β: float # 贴现因子 + μ: float # 冲击位置参数 + ν: float # 冲击尺度参数 + s_grid: np.ndarray # 外生储蓄网格 + shocks: np.ndarray # 冲击抽样 + α: float # 生产函数参数 + u_prime: Callable # 效用的导数 + f_prime: Callable # 生产的导数 + u_prime_inv: Callable # u_prime 的逆 + + +def create_model( + u: Callable, + f: Callable, + β: float = 0.96, + μ: float = 0.0, + ν: float = 0.1, + grid_max: float = 4.0, + grid_size: int = 120, + shock_size: int = 250, + seed: int = 1234, + α: float = 0.4, + u_prime: Callable = None, + f_prime: Callable = None, + u_prime_inv: Callable = None + ) -> Model: + """ + 创建最优储蓄模型的一个实例。 + """ + # 设置外生储蓄网格 + s_grid = np.linspace(1e-4, grid_max, grid_size) + + # 存储冲击(带种子,使结果可复现) + np.random.seed(seed) + shocks = np.exp(μ + ν * np.random.randn(shock_size)) + + return Model( + u, f, β, μ, ν, s_grid, shocks, α, u_prime, f_prime, u_prime_inv + ) +``` + +### 算子 + +这是使用上述 EGM 的 $K$ 的一个实现。 + +```{code-cell} python3 +def K( + c_in: np.ndarray, # 内生网格上的消费值 + x_in: np.ndarray, # 当前内生网格 + model: Model # 模型设定 + ): + """ + 使用 EGM 的 Coleman-Reffett 算子的一个实现。 + + """ + + # 简化名称 + u, f, β, μ, ν, s_grid, shocks, α, u_prime, f_prime, u_prime_inv = model + + # 在内生网格上对策略进行线性插值 + σ = lambda x: np.interp(x, x_in, c_in) + + # 为新的消费数组分配内存 + c_out = np.empty_like(s_grid) + + for i, s in enumerate(s_grid): + # 近似边际效用 ∫ u'(σ(f(s, α)z)) f'(s, α) z ϕ(z)dz + vals = u_prime(σ(f(s, α) * shocks)) * f_prime(s, α) * shocks + mu = np.mean(vals) + # 计算消费 + c_out[i] = u_prime_inv(β * mu) + + # 确定对应的内生网格 + x_out = s_grid + c_out # x_i = s_i + c_i + + return c_out, x_out +``` + +注意这里没有任何求根算法。 + +```{note} +该程序仍然不是特别快,因为我们使用的是纯 Python 循环。 + +但在下一讲({doc}`os_egm_jax`)中,我们将使用一个完全向量化且高效的解决方案。 +``` + +### 测试 + +首先我们创建一个实例。 + +```{code-cell} python3 +# 定义带导数的效用函数和生产函数 +u = lambda c: np.log(c) +u_prime = lambda c: 1 / c +u_prime_inv = lambda x: 1 / x +f = lambda k, α: k**α +f_prime = lambda k, α: α * k**(α - 1) + +model = create_model(u=u, f=f, u_prime=u_prime, + f_prime=f_prime, u_prime_inv=u_prime_inv) +s_grid = model.s_grid +``` + +这是我们的求解程序: + +```{code-cell} python3 +def solve_model_time_iter( + model: Model, # 模型细节 + c_init: np.ndarray, # EG 上消费的初始猜测 + x_init: np.ndarray, # 内生网格的初始猜测 + tol: float = 1e-5, # 误差容限 + max_iter: int = 1000, # K 的最大迭代次数 + verbose: bool = True # 若为 true 则打印输出 + ): + """ + 使用带 EGM 的时间迭代求解模型。 + """ + c, x = c_init, x_init + error = tol + 1 + i = 0 + + while error > tol and i < max_iter: + c_new, x_new = K(c, x, model) + error = np.max(np.abs(c_new - c)) + c, x = c_new, x_new + i += 1 + if verbose: + print(f"Iteration {i}, error = {error}") + + if i == max_iter: + print("Warning: maximum iterations reached") + + return c, x +``` + +让我们调用它: + +```{code-cell} python3 +c_init = np.copy(s_grid) +x_init = s_grid + c_init +c, x = solve_model_time_iter(model, c_init, x_init) +``` + +这是所得策略与真实策略的对比图: + +```{code-cell} python3 +fig, ax = plt.subplots() + +ax.plot(x, c, lw=2, + alpha=0.8, label='近似策略函数') + +ax.plot(x, σ_star(x, model.α, model.β), 'k--', + lw=2, alpha=0.8, label='真实策略函数') + +ax.legend() +plt.show() +``` + +两个策略之间的最大绝对偏差为 + +```{code-cell} python3 +np.max(np.abs(c - σ_star(x, model.α, model.β))) +``` + +这是执行时间: + +```{code-cell} python3 +with qe.Timer(): + c, x = solve_model_time_iter(model, c_init, x_init, verbose=False) +``` + +EGM 比时间迭代更快,因为它避免了数值求根。 + +相反,我们直接对边际效用函数求逆,这要高效得多。 + +在 {doc}`os_egm_jax` 中,我们将使用一个完全向量化且高效的 EGM 版本,它还使用 JAX 进行了并行化。 + +这为求解我们过去几讲一直在研究的最优消费问题提供了一种极其快速的方法。 \ No newline at end of file diff --git a/lectures/os_egm_jax.md b/lectures/os_egm_jax.md new file mode 100644 index 0000000..cf7b96e --- /dev/null +++ b/lectures/os_egm_jax.md @@ -0,0 +1,427 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 最优储蓄 VI:使用 JAX 的 EGM + headings: + Overview: 概述 + Implementation: 实现 + Exercises: 练习 +--- + +```{raw} jupyter + +``` + +# {index}`最优储蓄 VI:使用 JAX 的 EGM ` + +```{include} _admonition/gpu.md +``` + +```{contents} Contents +:depth: 2 +``` + +除了 Anaconda 中已有的内容外,本讲座还需要以下库: + +```{code-cell} python3 +:tags: [hide-output] + +!pip install quantecon jax +``` + +## 概述 + +在本讲座中,我们将使用 JAX 实现内生网格方法(EGM)。 + +本讲座建立在 {doc}`os_egm` 的基础上,该讲座使用 NumPy 介绍了 EGM。 + +通过转换为 JAX,我们可以利用快速线性代数、硬件加速器和 JIT 编译来提升性能。 + +我们还将使用 JAX 的 `vmap` 函数来完全向量化 Coleman-Reffett 算子。 + +让我们从一些标准导入开始: + +```{code-cell} python3 +import matplotlib.pyplot as plt +import jax +import jax.numpy as jnp +import quantecon as qe +from typing import NamedTuple +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 实现 + +关于储蓄问题和内生网格方法(EGM)的详细信息,请参见 {doc}`os_egm`。 + +这里我们专注于 EGM 的 JAX 实现。 + +我们使用与 {doc}`os_egm` 相同的设定: + +* $u(c) = \ln c$, +* 生产是科布-道格拉斯型的,并且 +* 冲击是对数正态的。 + +以下是用于比较的解析解。 + +```{code-cell} python3 +def v_star(x, α, β, μ): + """ + 真实值函数 + """ + c1 = jnp.log(1 - α * β) / (1 - β) + c2 = (μ + α * jnp.log(α * β)) / (1 - α) + c3 = 1 / (1 - β) + c4 = 1 / (1 - α * β) + return c1 + c2 * (c3 - c4) + c4 * jnp.log(x) + +def σ_star(x, α, β): + """ + 真实最优策略 + """ + return (1 - α * β) * x +``` + +`Model` 类仅存储数据(网格、冲击和参数)。 + +效用函数和生产函数将在全局定义,以便与 JAX 的 JIT 编译器协同工作。 + +```{code-cell} python3 +class Model(NamedTuple): + β: float # 贴现因子 + μ: float # 冲击位置参数 + s: float # 冲击尺度参数 + s_grid: jnp.ndarray # 外生储蓄网格 + shocks: jnp.ndarray # 冲击抽样 + α: float # 生产函数参数 + + +def create_model( + β: float = 0.96, + μ: float = 0.0, + s: float = 0.1, + grid_max: float = 4.0, + grid_size: int = 120, + shock_size: int = 250, + seed: int = 1234, + α: float = 0.4 + ) -> Model: + """ + 创建最优储蓄模型的一个实例。 + """ + # 设置外生储蓄网格 + s_grid = jnp.linspace(1e-4, grid_max, grid_size) + + # 存储冲击(使用种子,以便结果可复现) + key = jax.random.PRNGKey(seed) + shocks = jnp.exp(μ + s * jax.random.normal(key, shape=(shock_size,))) + + return Model(β, μ, s, s_grid, shocks, α) +``` + + +我们在全局定义效用函数和生产函数。 + +```{code-cell} python3 +# 定义效用函数和生产函数及其导数 +u = lambda c: jnp.log(c) +u_prime = lambda c: 1 / c +u_prime_inv = lambda x: 1 / x +f = lambda k, α: k**α +f_prime = lambda k, α: α * k**(α - 1) +``` +这是使用 EGM 的 Coleman-Reffett 算子。 + +这里的关键 JAX 特性是 `vmap`,它将计算向量化到各个网格点上。 + +```{code-cell} python3 +def K( + c_in: jnp.ndarray, # 内生网格上的消费值 + x_in: jnp.ndarray, # 当前内生网格 + model: Model # 模型规格 + ): + """ + 使用 EGM 的 Coleman-Reffett 算子 + + """ + β, μ, s, s_grid, shocks, α = model + σ = lambda x_val: jnp.interp(x_val, x_in, c_in) + + # 定义在单个网格点上计算消费的函数 + def compute_c(s): + # 近似边际效用 ∫ u'(σ(f(s, α)z)) f'(s, α) z ϕ(z)dz + vals = u_prime(σ(f(s, α) * shocks)) * f_prime(s, α) * shocks + mu = jnp.mean(vals) + # 计算消费 + return u_prime_inv(β * mu) + + # 向量化并在所有外生网格点上计算 + compute_c_vectorized = jax.vmap(compute_c) + c_out = compute_c_vectorized(s_grid) + + # 确定对应的内生网格 + x_out = s_grid + c_out # x_i = s_i + c_i + + return c_out, x_out +``` + + +现在我们创建一个模型实例。 + +```{code-cell} python3 +model = create_model() +s_grid = model.s_grid +``` + +求解器使用 JAX 的 `jax.lax.while_loop` 进行迭代,并且经过 JIT 编译以提高速度。 + +```{code-cell} python3 +@jax.jit +def solve_model_time_iter( + model: Model, + c_init: jnp.ndarray, + x_init: jnp.ndarray, + tol: float = 1e-5, + max_iter: int = 1000 + ): + """ + 使用带 EGM 的时间迭代求解模型。 + """ + + def condition(loop_state): + i, c, x, error = loop_state + return (error > tol) & (i < max_iter) + + def body(loop_state): + i, c, x, error = loop_state + c_new, x_new = K(c, x, model) + error = jnp.max(jnp.abs(c_new - c)) + return i + 1, c_new, x_new, error + + # 初始化循环状态 + initial_state = (0, c_init, x_init, tol + 1) + + # 运行循环 + i, c, x, error = jax.lax.while_loop(condition, body, initial_state) + + return c, x +``` + +我们从一个初始猜测开始求解模型。 + +```{code-cell} python3 +c_init = jnp.copy(s_grid) +x_init = s_grid + c_init +c, x = solve_model_time_iter(model, c_init, x_init) +``` + +让我们将得到的策略与解析解进行对比绘图。 + +```{code-cell} python3 +fig, ax = plt.subplots() + +ax.plot(x, c, lw=2, + alpha=0.8, label='近似策略函数') + +ax.plot(x, σ_star(x, model.α, model.β), 'k--', + lw=2, alpha=0.8, label='真实策略函数') + +ax.legend() +plt.show() +``` + +拟合效果非常好。 + +```{code-cell} python3 +max_dev = jnp.max(jnp.abs(c - σ_star(x, model.α, model.β))) +print(f"Maximum absolute deviation: {max_dev:.7}") +``` + +由于 JIT 编译和向量化,JAX 实现非常快。 + +```{code-cell} python3 +with qe.Timer(precision=8): + c, x = solve_model_time_iter(model, c_init, x_init) + jax.block_until_ready(c) +``` + +这种速度来自于: + +* 对整个求解器进行 JIT 编译 +* 通过 Coleman-Reffett 算子中的 `vmap` 进行向量化 +* 使用 `jax.lax.while_loop` 而非 Python 循环 +* 全程使用高效的 JAX 数组操作 + +## 练习 + +```{exercise} +:label: cake_egm_jax_ex1 + +求解具有 CRRA 效用的最优储蓄问题 + +$$ + u(c) = \frac{c^{1 - \gamma} - 1}{1 - \gamma} +$$ + +比较 $\gamma$ 从上方接近 1 时(例如 1.05、1.1、1.2)的最优策略。 + +证明当 $\gamma \to 1$ 时,最优策略收敛到使用对数效用($\gamma = 1$)得到的策略。 + +提示:使用接近 1 的 $\gamma$ 值以确保内生网格具有相似的覆盖范围,从而使可视化比较更容易。 +``` + +```{solution-start} cake_egm_jax_ex1 +:class: dropdown +``` + +我们需要创建一个能够处理 CRRA 效用的 Coleman-Reffett 算子和求解器版本。 + +关键在于将效用函数用 $\gamma$ 参数化。 + +```{code-cell} python3 +def u_crra(c, γ): + return (c**(1 - γ) - 1) / (1 - γ) + +def u_prime_crra(c, γ): + return c**(-γ) + +def u_prime_inv_crra(x, γ): + return x**(-1/γ) +``` + +现在我们创建一个以 $\gamma$ 作为参数的 Coleman-Reffett 算子版本。 + +```{code-cell} python3 +def K_crra( + c_in: jnp.ndarray, # 内生网格上的消费值 + x_in: jnp.ndarray, # 当前内生网格 + model: Model, # 模型规格 + γ: float # CRRA 参数 + ): + """ + 使用 EGM 和 CRRA 效用的 Coleman-Reffett 算子 + """ + # 简化名称 + β, α = model.β, model.α + s_grid, shocks = model.s_grid, model.shocks + + # 使用内生网格对策略进行线性插值 + σ = lambda x_val: jnp.interp(x_val, x_in, c_in) + + # 定义在单个网格点上计算消费的函数 + def compute_c(s): + vals = u_prime_crra(σ(f(s, α) * shocks), γ) * f_prime(s, α) * shocks + return u_prime_inv_crra(β * jnp.mean(vals), γ) + + # 使用 vmap 在网格上向量化 + compute_c_vectorized = jax.vmap(compute_c) + c_out = compute_c_vectorized(s_grid) + + # 确定对应的内生网格 + x_out = s_grid + c_out # x_i = s_i + c_i + + return c_out, x_out +``` + +我们还需要一个使用该算子的求解器。 + +```{code-cell} python3 +@jax.jit +def solve_model_crra(model: Model, + c_init: jnp.ndarray, + x_init: jnp.ndarray, + γ: float, + tol: float = 1e-5, + max_iter: int = 1000): + """ + 使用带 EGM 和 CRRA 效用的时间迭代求解模型。 + """ + + def condition(loop_state): + i, c, x, error = loop_state + return (error > tol) & (i < max_iter) + + def body(loop_state): + i, c, x, error = loop_state + c_new, x_new = K_crra(c, x, model, γ) + error = jnp.max(jnp.abs(c_new - c)) + return i + 1, c_new, x_new, error + + # 初始化循环状态 + initial_state = (0, c_init, x_init, tol + 1) + + # 运行循环 + i, c, x, error = jax.lax.while_loop(condition, body, initial_state) + + return c, x +``` + +现在我们对 $\gamma = 1$(对数效用)以及从上方接近 1 的值进行求解。 + +```{code-cell} python3 +γ_values = [1.0, 1.05, 1.1, 1.2] +policies = {} +endogenous_grids = {} + +model_crra = create_model() + +for γ in γ_values: + c_init = jnp.copy(model_crra.s_grid) + x_init = model_crra.s_grid + c_init + c_gamma, x_gamma = solve_model_crra(model_crra, c_init, x_init, γ) + jax.block_until_ready(c_gamma) + policies[γ] = c_gamma + endogenous_grids[γ] = x_gamma + print(f"Solved for γ = {γ}") +``` + +在各自的内生网格上绘制策略。 + +```{code-cell} python3 +fig, ax = plt.subplots() + +for γ in γ_values: + x = endogenous_grids[γ] + if γ == 1.0: + ax.plot(x, policies[γ], 'k-', linewidth=2, + label=f'γ = {γ:.2f} (对数效用)', alpha=0.8) + else: + ax.plot(x, policies[γ], label=f'γ = {γ:.2f}', alpha=0.8) + +ax.set_xlabel('状态 x') +ax.set_ylabel('消费 σ(x)') +ax.legend() +ax.set_title('最优策略:CRRA 效用接近对数情形') +plt.show() +``` + +注意,$\gamma > 1$ 的图形并未覆盖所示的整个 x 轴范围。 + +这是因为内生网格 $x = s + \sigma(s)$ 取决于消费策略,而消费策略随 $\gamma$ 变化。 + +让我们检查对数效用情形($\gamma = 1.0$)与从上方接近的值之间的最大偏差。 + +```{code-cell} python3 +for γ in [1.05, 1.1, 1.2]: + max_diff = jnp.max(jnp.abs(policies[1.0] - policies[γ])) + print(f"Max difference between γ=1.0 and γ={γ}: {max_diff:.6}") +``` + +正如预期,随着 $\gamma$ 从上方接近 1,差异逐渐减小,这证实了收敛性。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/os_time_iter.md b/lectures/os_time_iter.md new file mode 100644 index 0000000..a0158bd --- /dev/null +++ b/lectures/os_time_iter.md @@ -0,0 +1,559 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 最优储蓄 IV:时间迭代 + headings: + Overview: 概述 + The Euler Equation: 欧拉方程 + The Euler Equation::The Coleman-Reffett Operator: Coleman-Reffett 算子 + The Euler Equation::Is the Coleman-Reffett Operator Well Defined?: Coleman-Reffett 算子是良定义的吗? + The Euler Equation::Comparison with VFI (Theory): 与 VFI 的比较(理论) + Implementation: 实现 + Implementation::Testing: 测试 + Exercises: 练习 +--- + +```{raw} jupyter + +``` + +# {index}`最优储蓄 IV:时间迭代 ` + +```{contents} Contents +:depth: 2 +``` + +除了 Anaconda 中已有的内容之外,本讲座还需要以下库: + +```{code-cell} ipython +--- +tags: [hide-output] +--- +!pip install quantecon +``` + +## 概述 + +在本讲座中,我们将介绍**时间迭代**的核心思想:利用欧拉方程对最优策略的猜测进行迭代。 + +这种方法与我们在 {doc}`os_stochastic` 中使用的价值函数迭代不同,在那里我们对价值函数本身进行迭代。 + +时间迭代利用欧拉方程的结构直接求出最优策略,而不是将计算价值函数作为一个中间步骤。 + +其关键优势在于计算效率:通过直接处理策略函数,我们通常能够比价值函数迭代更快地求解问题。 + +然而,时间迭代并不是现有基于欧拉方程的方法中最高效的。 + +在 {doc}`os_egm` 中,我们将介绍**内生网格法**(EGM),它提供了一种更加高效的方式来求解该问题。 + +目前,我们的目标是理解时间迭代的基本机制以及它如何利用欧拉方程。 + +让我们从一些导入开始: + +```{code-cell} ipython +import matplotlib.pyplot as plt +import numpy as np +from scipy.optimize import brentq +from typing import NamedTuple, Callable +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 欧拉方程 + +我们的第一步是推导欧拉方程,它是我们在 {doc}`os` 中得到的欧拉方程的推广。 + +我们采用 {doc}`os_stochastic` 中给出的模型,并添加以下假设: + +1. $u$ 和 $f$ 是连续可微且严格凹的 +1. $f(0) = 0$ +1. $\lim_{c \to 0} u'(c) = \infty$ 且 $\lim_{c \to \infty} u'(c) = 0$ +1. $\lim_{k \to 0} f'(k) = \infty$ 且 $\lim_{k \to \infty} f'(k) = 0$ + +最后两个条件通常称为 **稻田条件(Inada conditions)**。 + +回顾贝尔曼方程 + +```{math} +:label: cpi_fpb30 + +v(x) = \max_{0 \leq c \leq x} + \left\{ + u(c) + \beta \int v(f(x - c) z) \phi(dz) + \right\} +\quad \text{for all} \quad +x \in \mathbb R_+ +``` + +设 $v^*$ 为价值函数,设 $\sigma^*$ 为最优消费策略。 + +我们知道 $\sigma^*$ 是一个 $v^*$-贪婪策略。 + +上述条件意味着 + +* $\sigma^*$ 是最优储蓄问题的唯一最优策略 +* 最优策略是连续的、严格递增的,并且是**内部的**,即对所有严格为正的 $x$,都有 $0 < \sigma^*(x) < x$,并且 +* 价值函数是严格凹的且连续可微的,满足 + +```{math} +:label: cpi_env + +(v^*)'(x) = u' (\sigma^*(x) ) := (u' \circ \sigma^*)(x) +``` + +由于其与[包络定理](https://en.wikipedia.org/wiki/Envelope_theorem)的关系,最后这个结果被称为**包络条件**。 + +为了理解 {eq}`cpi_env` 为何成立,将贝尔曼方程写成等价形式 + +$$ +v^*(x) = \max_{0 \leq k \leq x} + \left\{ + u(x-k) + \beta \int v^*(f(k) z) \phi(dz) + \right\}, +$$ + +对 $x$ 求导,然后在最优处求值即可得到 {eq}`cpi_env`。 + +([EDTC](https://johnstachurski.net/edtc.html) 的第 12.1 节包含了这些结果的完整证明,许多其他文献中也可以找到密切相关的讨论。) + +价值函数的可微性和最优策略的内部性意味着最优消费满足与 {eq}`cpi_fpb30` 相关的一阶条件,即 + +```{math} +:label: cpi_foc + +u'(\sigma^*(x)) = \beta \int (v^*)'(f(x - \sigma^*(x)) z) f'(x - \sigma^*(x)) z \phi(dz) +``` + +将 {eq}`cpi_env` 与一阶条件 {eq}`cpi_foc` 结合起来,得到**欧拉方程** + +```{math} +:label: cpi_euler + +(u'\circ \sigma^*)(x) += \beta \int (u'\circ \sigma^*)(f(x - \sigma^*(x)) z) f'(x - \sigma^*(x)) z \phi(dz) +``` + +我们可以把欧拉方程看作一个函数方程 + +```{math} +:label: cpi_euler_func + +(u'\circ \sigma)(x) += \beta \int (u'\circ \sigma)(f(x - \sigma(x)) z) f'(x - \sigma(x)) z \phi(dz) +``` + +它定义在内部消费策略 $\sigma$ 上,其中一个解就是最优策略 $\sigma^*$。 + +我们的目标是求解函数方程 {eq}`cpi_euler_func`,从而得到 $\sigma^*$。 + +### Coleman-Reffett 算子 + +回顾贝尔曼算子 + +```{math} +:label: fcbell20_coleman + +Tv(x) := \max_{0 \leq c \leq x} +\left\{ + u(c) + \beta \int v(f(x - c) z) \phi(dz) +\right\} +``` + +正如我们引入贝尔曼算子来求解贝尔曼方程一样,我们现在将引入一个作用于策略之上的算子,以帮助我们求解欧拉方程。 + +这个算子 $K$ 将作用于所有连续、严格递增且内部的 $\sigma \in \Sigma$ 构成的集合。 + +此后我们用 $\mathscr P$ 表示这个策略集合。 + +1. 算子 $K$ 以一个 $\sigma \in \mathscr P$ 作为其参数,并且 +1. 返回一个新函数 $K\sigma$,其中 $K\sigma(x)$ 是求解下式的 $c \in (0, x)$ + +```{math} +:label: cpi_coledef + +u'(c) += \beta \int (u' \circ \sigma) (f(x - c) z ) f'(x - c) z \phi(dz) +``` + +为了纪念 {cite}`Coleman1990` 和 {cite}`Reffett1996` 的工作,我们称这个算子为 **Coleman-Reffett 算子**。 + +本质上,$K\sigma$ 是当你未来的消费策略为 $\sigma$ 时,欧拉方程告诉你今天应该选择的消费策略。 + +关于 $K$ 的重要一点是,根据其构造,它的不动点与函数方程 {eq}`cpi_euler_func` 的解相一致。 + +特别地,最优策略 $\sigma^*$ 是一个不动点。 + +事实上,对于固定的 $x$,值 $K\sigma^*(x)$ 就是求解下式的 $c$ + +$$ +u'(c) += \beta \int (u' \circ \sigma^*) (f(x - c) z ) f'(x - c) z \phi(dz) +$$ + +根据欧拉方程,这恰好是 $\sigma^*(x)$。 + +### Coleman-Reffett 算子是良定义的吗? + +具体来说,是否总是存在唯一的 $c \in (0, x)$ 求解 {eq}`cpi_coledef`? + +在我们的假设下,答案是肯定的。 + +对于任何 $\sigma \in \mathscr P$,{eq}`cpi_coledef` 的右侧 + +* 在 $(0, x)$ 上关于 $c$ 连续且严格递增 +* 当 $c \uparrow x$ 时发散到 $+\infty$ + +{eq}`cpi_coledef` 的左侧 + +* 在 $(0, x)$ 上关于 $c$ 连续且严格递减 +* 当 $c \downarrow 0$ 时发散到 $+\infty$ + +绘制这些曲线并利用上述信息,你会相信当 $c$ 在 $(0, x)$ 范围内变化时,它们恰好相交一次。 + +再进行一些分析,还可以证明:只要 $\sigma \in \mathscr P$,就有 $K \sigma \in \mathscr P$。 + +### 与 VFI 的比较(理论) + +可以证明,$K$ 的迭代与贝尔曼算子的迭代之间存在着紧密的关系。 + +从数学上讲,$T$ 和 $K$ 在一个变换下是**拓扑共轭**的,该变换在一个方向上涉及微分,在另一个方向上涉及积分。 + +这种共轭性意味着,如果一个算子的迭代收敛,那么另一个算子的迭代也收敛,反之亦然。 + +此外,从某种意义上说,它们至少在理论上以*相同的速率*收敛。 + +然而,事实证明,算子 $K$ 在*数值上*更加稳定,因此在我们考虑的应用中更加高效。 + +这是因为 + +* $K$ 利用了额外的结构,因为它使用了一阶条件,并且 +* 接近最优策略的策略曲率较小,因此比接近最优价值函数的价值函数更容易近似。 + +下面给出示例。 + + +## 实现 + +让我们转向实现。 + +```{note} +在本讲座中,我们主要关注算法,在代码中优先考虑清晰性而非效率。 + +在后续讲座中,我们将同时优化算法和代码。 +``` + + + +与 {doc}`os_stochastic` 中一样,我们假设 + +* $u(c) = \ln c$ +* $f(x-c) = (x-c)^{\alpha}$ +* 当 $\zeta$ 为标准正态时,$\phi$ 是 $\xi := \exp(\mu + \nu \zeta)$ 的分布 + +这使我们能够将结果与我们在那个讲座中得到的解析解进行比较: + +```{code-cell} ipython +def v_star(x, α, β, μ): + """ + 真实价值函数 + """ + c1 = np.log(1 - α * β) / (1 - β) + c2 = (μ + α * np.log(α * β)) / (1 - α) + c3 = 1 / (1 - β) + c4 = 1 / (1 - α * β) + return c1 + c2 * (c3 - c4) + c4 * np.log(x) + +def σ_star(x, α, β): + """ + 真实最优策略 + """ + return (1 - α * β) * x +``` + +如上所述,我们的计划是使用时间迭代来求解模型,这意味着用算子 $K$ 进行迭代。 + +为此,我们需要访问函数 $u'$ 以及 $f, f'$。 + +我们使用来自 {doc}`os_stochastic` 的相同 `Model` 结构。 + +```{code-cell} ipython +class Model(NamedTuple): + u: Callable # 效用函数 + f: Callable # 生产函数 + β: float # 贴现因子 + μ: float # 冲击位置参数 + ν: float # 冲击尺度参数 + grid: np.ndarray # 状态网格 + shocks: np.ndarray # 冲击抽样 + α: float = 0.4 # 生产函数参数 + u_prime: Callable = None # 效用的导数 + f_prime: Callable = None # 生产的导数 + + +def create_model( + u: Callable, + f: Callable, + β: float = 0.96, + μ: float = 0.0, + ν: float = 0.1, + grid_max: float = 4.0, + grid_size: int = 120, + shock_size: int = 250, + seed: int = 1234, + α: float = 0.4, + u_prime: Callable = None, + f_prime: Callable = None + ) -> Model: + """ + 创建最优储蓄模型的一个实例。 + """ + # 设置网格 + grid = np.linspace(1e-4, grid_max, grid_size) + + # 存储冲击(使用种子,以便结果可复现) + np.random.seed(seed) + shocks = np.exp(μ + ν * np.random.randn(shock_size)) + + return Model(u, f, β, μ, ν, grid, shocks, α, u_prime, f_prime) +``` + +现在我们实现一个名为 `euler_diff` 的方法,它返回 + +```{math} +:label: euler_diff + +u'(c) - \beta \int (u' \circ \sigma) (f(x - c) z ) f'(x - c) z \phi(dz) +``` + +```{code-cell} ipython +def euler_diff(c: float, σ: np.ndarray, x: float, model: Model) -> float: + """ + 设置一个函数,使得给定 x 和 σ 时, + 关于 c 的根等于 Kσ(x)。 + + """ + + # 解包 + u, f, β, μ, ν, grid, shocks, α, u_prime, f_prime = model + + # 通过插值将 σ 转化为一个函数 + σ_func = lambda x: np.interp(x, grid, σ) + + # 现在设置我们需要求根的函数。 + vals = u_prime(σ_func(f(x - c, α) * shocks)) * f_prime(x - c, α) * shocks + return u_prime(c) - β * np.mean(vals) +``` + +函数 `euler_diff` 通过蒙特卡洛计算积分,并使用线性插值来近似函数。 + +我们将使用求根算法,在给定状态 $x$ 和当前策略猜测 $σ$ 的情况下求解 {eq}`euler_diff` 中的 $c$。 + +这是算子 $K$,它实现了求根步骤。 + +```{code-cell} ipython +def K(σ: np.ndarray, model: Model) -> np.ndarray: + """ + Coleman-Reffett 算子 + + """ + + # 解包 + u, f, β, μ, ν, grid, shocks, α, u_prime, f_prime = model + + σ_new = np.empty_like(σ) + for i, x in enumerate(grid): + # 求解 x 处的最优 c + c_star = brentq(euler_diff, 1e-10, x-1e-10, args=(σ, x, model)) + σ_new[i] = c_star + + return σ_new +``` + +### 测试 + +让我们生成一个实例,并从 $σ(x) = x$ 开始绘制 $K$ 的一些迭代结果。 + +```{code-cell} ipython +# 定义带导数的效用函数和生产函数 +α = 0.4 +u = lambda c: np.log(c) +u_prime = lambda c: 1 / c +f = lambda k, α: k**α +f_prime = lambda k, α: α * k**(α - 1) + +model = create_model(u=u, f=f, α=α, u_prime=u_prime, f_prime=f_prime) +grid = model.grid + +n = 15 +σ = grid.copy() # 设置初始条件 + +fig, ax = plt.subplots() +lb = r'初始条件 $\sigma(x) = x$' +ax.plot(grid, σ, color=plt.cm.jet(0), alpha=0.6, label=lb) + +for i in range(n): + σ = K(σ, model) + ax.plot(grid, σ, color=plt.cm.jet(i / n), alpha=0.6) + +# 再更新一次,并用黑色绘制最后一次迭代 +σ = K(σ, model) +ax.plot(grid, σ, color='k', alpha=0.8, label='最后一次迭代') + +ax.legend() + +plt.show() +``` + +我们看到迭代过程快速收敛到一个极限,该极限与我们在 {doc}`os_stochastic` 中得到的解相似。 + +这里有一个名为 `solve_model_time_iter` 的函数,它接受一个 `Model` 实例,并使用时间迭代返回最优策略的近似值。 + + +```{code-cell} ipython +def solve_model_time_iter( + model: Model, + σ_init: np.ndarray, + tol: float = 1e-5, + max_iter: int = 1000, + verbose: bool = True + ) -> np.ndarray: + """ + 使用时间迭代求解模型。 + + """ + σ = σ_init + error = tol + 1 + i = 0 + + while error > tol and i < max_iter: + σ_new = K(σ, model) + error = np.max(np.abs(σ_new - σ)) + σ = σ_new + i += 1 + if verbose: + print(f"Iteration {i}, error = {error}") + + if i == max_iter: + print("Warning: maximum iterations reached") + + return σ +``` + +让我们调用它: + +```{code-cell} ipython +# 解包 +grid = model.grid + +σ_init = np.copy(grid) +σ = solve_model_time_iter(model, σ_init) +``` + +这是所得策略与真实策略的对比图: + +```{code-cell} ipython +# 解包 +grid, α, β = model.grid, model.α, model.β + +fig, ax = plt.subplots() + +ax.plot(grid, σ, lw=2, + alpha=0.8, label='近似策略函数') + +ax.plot(grid, σ_star(grid, α, β), 'k--', + lw=2, alpha=0.8, label='真实策略函数') + +ax.legend() +plt.show() +``` + +同样,拟合效果非常好。 + +两个策略之间的最大绝对偏差为 + +```{code-cell} ipython +# 解包 +grid, α, β = model.grid, model.α, model.β + +np.max(np.abs(σ - σ_star(grid, α, β))) +``` + +正如在 {doc}`os_stochastic` 中所讨论的,时间迭代的运行速度比价值函数迭代更快。 + +这是因为时间迭代利用了可微性和一阶条件,而价值函数迭代没有使用这一可用的结构。 + +同时,还有一种运行速度更快的时间迭代变体。 + +那就是内生网格法,我们将在 {doc}`os_egm` 中介绍它。 + +## 练习 + +```{exercise} +:label: cpi_ex1 + +使用 CRRA 效用求解最优储蓄问题 + +$$ +u(c) = \frac{c^{1 - \gamma}} {1 - \gamma} +$$ + +设 `γ = 1.5`。 + +计算并绘制最优策略。 +``` + +```{solution-start} cpi_ex1 +:class: dropdown +``` + +我们定义 CRRA 效用函数及其导数。 + +```{code-cell} ipython +γ = 1.5 + +def u_crra(c): + return c**(1 - γ) / (1 - γ) + +def u_prime_crra(c): + return c**(-γ) + +# 使用与之前相同的生产函数 +model_crra = create_model(u=u_crra, f=f, α=α, + u_prime=u_prime_crra, f_prime=f_prime) +``` + +现在我们求解并绘制策略: + +```{code-cell} ipython +%%time +# 解包 +grid = model_crra.grid + +σ_init = np.copy(grid) +σ = solve_model_time_iter(model_crra, σ_init) + + +fig, ax = plt.subplots() + +ax.plot(grid, σ, lw=2, + alpha=0.8, label='近似策略函数') + +ax.legend() +plt.show() +``` + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/rational_learning_re.md b/lectures/rational_learning_re.md new file mode 100644 index 0000000..4a0a493 --- /dev/null +++ b/lectures/rational_learning_re.md @@ -0,0 +1,1083 @@ +--- +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 +translation: + title: 理性学习与理性预期 + headings: + Overview: 概述 + The economy: 经济 + The economy::Agents and assets: 主体与资产 + The economy::Preferences: 偏好 + The economy::Rational expectations equilibrium: 理性预期均衡 + The rational learning equilibrium: 理性学习均衡 + The rational learning equilibrium::Uninformed demand given beliefs: 给定信念的不知情需求 + The rational learning equilibrium::Market clearing: 市场出清 + The rational learning equilibrium::Bayesian update: 贝叶斯更新 + Computing the equilibrium: 计算均衡 + Posterior concentration: 后验集中 + Equilibrium trades and prices: 均衡交易与价格 + Convergence of posterior assessments: 后验评估的收敛 + Sharpening the convergence result: 锐化收敛结果 + Obstacles to convergence: 收敛的障碍 + 'Obstacles to convergence::Obstacle 1: failure of continuity': 障碍 1:连续性失效 + 'Obstacles to convergence::Obstacle 2: failure of identification': 障碍 2:识别失效 + 'Obstacles to convergence::Obstacle 3: misspecification': 障碍 3:错误设定 + Learning within versus learning about a rational expectations equilibrium: 在理性预期均衡内部学习 vs. 关于理性预期均衡的学习 + Learning within versus learning about a rational expectations equilibrium::The distinction: 区分 + Learning within versus learning about a rational expectations equilibrium::The trade-off: 权衡 + Summary: 小结 + Exercises: 练习 +--- + +(rational_learning_re)= +```{raw} jupyter + +``` + +# 理性学习与理性预期 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲座探讨经济理论中的一个重要问题:在理性预期均衡中,主体能够学到什么? + +这个问题与适应性学习问题相关,但又不同——后者关心的是理性预期均衡能否被证明为一个动态吸引子。 + +出发点是 {cite:t}`BrayKreps1987`,它给出了理性预期均衡内部贝叶斯学习的严格模型。 + +在理性预期均衡中,主体利用市场价格对其他主体的私人信息进行推断。 + +每个主体都知道价格与底层收益相关变量之间的*统计关系*,而在均衡下该关系是*正确的*。 + +但这引出了一个问题:这种知识从何而来? + +他们的**理性学习**方法回答了一个更狭窄的问题。 + +主体对结构参数不确定,状态空间被扩展,使得对于每个候选值,都包含相应的均衡价格和配置映射。 + +随后,当价格和回报被观察到时,主体使用贝叶斯法则对这些可能性进行更新。 + +本讲座通过一个资产市场模型来展开这种贝叶斯表述。 + +目标是在转向计算示例之前,看清理性学习能解释什么,以及它的局限出现在何处。 + +讨论还与 {cite:t}`Bray1982`、{cite:t}`BraySavin1986` 的早期工作,以及 {cite:t}`Radner1979`、{cite:t}`grossman1976` 和 {cite:t}`Jordan1982` 的理性预期文献相联系。 + +让我们从以下导入开始 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import brentq +``` + +## 经济 + +该模型是一个简单的资产市场,围绕 {cite:t}`GrossmanStiglitz1980` 的重复信息模型构建,在无限多个时期中重复进行。 + + +### 主体与资产 + +每个时期在经济上与其他时期互不相连,因此主体在每个时期都从头开始。 + +有两类主体和两种资产: + +* 一种**安全资产**,其净回报被标准化为零。 +* 一种**风险资产**,每个主体拥有一单位禀赋,在日期 $t$ 以现货价格 $p_t$ 交易。 + +在每个日期 $t = 0, 1, 2, \ldots$,风险资产在日期 $t+1/2$ 产生总回报率 $r_t$。 + +知情信号 $s_t$ 满足 + +$$ +r_t = s_t + \epsilon_t, +\qquad +s_t \sim N(\mu_s, \tau^2), +\qquad +\epsilon_t \sim N(0,\sigma^2), +$$ + +其中 $\{s_t\}$ 和 $\{\epsilon_t\}$ 是独立同分布的正态序列,且相互独立。 + +先验矩 $(\mu_s, \tau^2)$ 是共同知识,正是这一点使得价格观察对 $\theta^I$ 具有信息量,我们将在后面看到。 + +有两个代表性主体: + +* **主体 $I$(知情)** 在日期 $t$ 交易之前观察到 $s_t$。 +* **主体 $U$(不知情)** 在交易前观察到均衡价格 $p_t$,但观察不到 $s_t$。 + +两个主体在当前交易前都观察到上一期的回报。 + +### 偏好 + +主体 $n \in \{I, U\}$ 具有恒定绝对风险容忍度 $\theta^n$。 + +如果主体 $n$ 在日期 $t$ 和 $t+1/2$ 之间持有 $x^n$ 单位风险资产和 $y^n$ 单位安全资产,那么期间效用为 + +$$ +-\exp\left[-\frac{x^n r_t + y^n}{\theta^n}\right]. +$$ + +因此 $1/\theta^n$ 是绝对风险规避系数。 + +给定信号 $s_t$,知情主体的需求为 + +$$ +x^I_t += +\frac{\theta^I}{\sigma^2}(s_t - p_t). +$$ (eq:bk-informed-demand) + +由于两个主体各拥有一单位风险资产禀赋,市场出清为 + +$$ +x^I_t + x^U_t = 2. +$$ + +### 理性预期均衡 + +如果所有主体都知道 $s_t$,那么主体 $n$ 的需求为 + +$$ +x^n_t = \frac{\theta^n}{\sigma^2}(s_t - p_t). +$$ + +在有 $N$ 个主体、风险资产总供给为 $N$ 的情况下,市场出清给出**完全传播均衡价格** + +$$ +p_t += +s_t +- +\frac{N\sigma^2}{\sum_{n=1}^N \theta^n}. +$$ (eq:bk-full-communication-price) + +因此,如果 $\sum_n \theta^n$ 已知,则价格完全揭示 $s_t$。 + +遵循 {cite:t}`Radner1979`,这被称为完全传播理性预期均衡。 + +现在假设主体 $U$ 不知道 $\theta^I$。 + +遵循 {cite:t}`BrayKreps1987`,我们通过*扩展状态空间*来处理这种不确定性:我们让未知参数 $\theta^I$ 成为状态的一个坐标,与每期冲击 $(s_t, \epsilon_t)$ 并列。 + +形式上,状态空间为 $\Omega = \Theta \times \Phi^\infty$,其中 $\Theta = [a,b]$ 支撑未知的 $\theta^I$,而 $\Phi$ 支撑每个 $(s_t, \epsilon_t)$。 + +主体 $U$ 知道 $\sigma^2$ 和 $\theta^U$,并以关于 $\theta^I$ 在 $[a,b]$ 上的先验密度作为起点。 + +这种扩展将学习问题转化为在 $\Omega$ 上单一理性预期均衡内部的贝叶斯推断。 + +在某个日期,当主体 $U$ 对 $\theta^I$ 具有后验密度 $f$ 时,他自己的交易通过市场出清揭示了 $x^I_t=2-x^U_t$。 + +将这个推断出的 $x^I_t$ 与 {eq}`eq:bk-informed-demand` 结合,每个候选 $\theta^I$ 意味着 + +$$ +s_t += +p_t ++ +\frac{\sigma^2 x^I_t}{\theta^I}. +$$ (eq:bk-signal-implied) + +交易后,主体 $U$ 观察到 $r_t$。 + +然后贝叶斯法则使用由 {eq}`eq:bk-signal-implied` 所隐含的信号的正态密度(以实现的回报为条件)来更新关于 $\theta^I$ 的后验。 + +这是两主体示例中所学习的主要对象。 + +即使在这个简单情形中,均衡也可以递归地定义,但无法得到闭式价格。 + +## 理性学习均衡 + +该模型有两个部分,它们在每个日期相互作用。 + +第一个是给定不知情主体对 $\theta^I$ 当前后验的期内均衡。 + +第二个是该期结束后对该后验的贝叶斯更新。 + +### 给定信念的不知情需求 + +假设在日期 $t$,主体 $U$ 对 $\theta^I$ 具有后验密度 $f_t$,支撑在 $[a, b]$ 上。 + +假设均衡价格为 $p$,且均衡知情交易 $X^I = 2 - x^U$ 已从市场出清中推断出来。 + +以 $\theta$ 为条件,方程 {eq}`eq:bk-signal-implied` 将信号确定为 $s_t(\theta) = \sigma^2 X^I/\theta + p$。 + +因此,在日期 $t$ 交易开始时存在两个关于 $\theta$ 的信息来源:结转的后验 $f_t(\theta)$,以及关于 $s_t$ 的高斯先验 $\phi_s(\cdot;\mu_s,\tau^2)$,后者将某些隐含信号评估为比其他信号更可信。 + +贝叶斯法则将它们组合成*期内*后验 + +$$ +f_t^{(p, X^I)}(\theta) +\propto +f_t(\theta)\, +\phi_s\!\left(\frac{\sigma^2 X^I}{\theta} + p\, ;\, \mu_s, \tau^2\right), +$$ (eq:bk-intra-posterior) + +这是主体在观察到 $r_t$ 之前实际用于预测 $r_t$ 的关于 $\theta^I$ 的后验。 + +以候选值 $\theta$ 为条件,一单位风险资产的超额收益为 + +$$ +r_t - p += +\frac{\sigma^2 X^I}{\theta} + \epsilon_t, +\qquad \epsilon_t \sim N(0,\sigma^2). +$$ + +由于 CARA 偏好没有财富效应,主体 $U$ 的问题简化为 + +$$ +\max_{x^U}\, +\mathbb{E}[u^U(x^U, r_t, p)], +\qquad +u^U(x^U, r_t, p) += +-\exp\!\left(-\frac{x^U(r_t-p)}{\theta^U}\right), +$$ + +其中期望在 $\theta^I \sim f_t^{(p, X^I)}$ 和 $\epsilon_t$ 上积分。 + +代入条件超额收益并使用正态矩生成公式得到 + +$$ +\mathbb{E}[u^U] += +-\exp\!\left(\frac{(x^U)^2 \sigma^2}{2(\theta^U)^2}\right) +\int_a^b +f_t(\theta)\, +\phi_s\!\left(\tfrac{\sigma^2 X^I}{\theta} + p; \mu_s, \tau^2\right) +\exp\!\left(-\tfrac{x^U \sigma^2 X^I}{\theta\,\theta^U}\right) +d\theta, +$$ + +其中一个与 $\theta$ 无关的常数被吸收进归一化中。 + +定义倾斜权重 + +$$ +w(\theta;\, p, X^I, x^U) += +f_t(\theta)\, +\phi_s\!\left(\tfrac{\sigma^2 X^I}{\theta} + p; \mu_s, \tau^2\right) +\exp\!\left(-\tfrac{x^U \sigma^2 X^I}{\theta\,\theta^U}\right). +$$ (eq:bk-weight) + +一阶条件重新整理为 + +$$ +\frac{x^U}{\theta^U} += +X^I \; +\frac{\int_a^b \theta^{-1}\, w(\theta;\, p, X^I, x^U)\, d\theta} + {\int_a^b w(\theta;\, p, X^I, x^U)\, d\theta}. +$$ (eq:bk-foc) + +右边是 $X^I$ 乘以在 {eq}`eq:bk-weight` 中的加权下 $1/\theta^I$ 的倾斜期望。 + +方程 {eq}`eq:bk-foc` 隐式定义了 $x^U(p, X^I; f_t)$,即在观察价格 $p$、推测的知情交易 $X^I$ 和先前后验 $f_t$ 下,不知情主体的最优需求。 + +对 $p$ 的依赖通过先验权重 $\phi_s$ 进入:在更高价格时,那些隐含 $s_t$ 高于先验均值的候选 $\theta$ 值变得不那么可信,因此主体的需求曲线如预期般在 $p$ 上向下倾斜。 + +### 市场出清 + +均衡要求知情需求与不知情需求之和等于总禀赋。 + +代入 {eq}`eq:bk-informed-demand` 和隐函数 $x^U(p, X^I; f_t)$,均衡 $(p_t, X^I_t)$ 满足以下两个方程 + +$$ +X^I_t = \frac{\theta^I}{\sigma^2}(s_t - p_t), +\qquad +X^I_t + x^U(p_t, X^I_t; f_t) = 2. +$$ (eq:bk-mc) + +在两者之间消去 $X^I_t$,剩下关于 $p_t$ 的单一求根问题。 + +组合这两个方程,均衡价格的形式为 + +$$ +p_t = s_t - \frac{\sigma^2 X^I_t}{\theta^I}. +$$ (eq:bk-price) + +当 $f_t$ 坍缩为在真实 $\theta^I$ 处的点质量时,方程 {eq}`eq:bk-foc` 简化为 $x^U/\theta^U = X^I/\theta^I$,市场出清给出完全传播配置 + +$$ +X^I_t = \frac{2\theta^I}{\theta^I + \theta^U}, +\qquad +x^U_t = \frac{2\theta^U}{\theta^I + \theta^U}. +$$ (eq:bk-full-info-trade) + +这是我们将用来检验模拟的完全传播配置。 + +### 贝叶斯更新 + +交易后,主体 $U$ 观察到 $(p_t, x^U_t, r_t)$。 + +市场出清给出 $X^I_t = 2 - x^U_t$,方程 {eq}`eq:bk-signal-implied` 为每个 $\theta$ 分配一个候选 $s_t(\theta) = \sigma^2 X^I_t/\theta + p_t$。 + +由于 $s_t \sim N(\mu_s, \tau^2)$ 独立于 $\epsilon_t \sim N(0,\sigma^2)$,给定 $r_t$ 的 $s_t$ 的条件密度是高斯的: + +$$ +g(s\mid r) += +\phi\!\left(s;\, \frac{\sigma^2 \mu_s + \tau^2 r}{\sigma^2 + \tau^2},\, + \frac{\sigma^2 \tau^2}{\sigma^2 + \tau^2}\right), +$$ + +其中 $\phi(\cdot; m, v)$ 表示均值为 $m$、方差为 $v$ 的正态密度。 + +然后贝叶斯法则产生后验更新 + +$$ +f_{t+1}(\theta) +\propto +f_t(\theta)\; +g\!\left(\frac{\sigma^2 X^I_t}{\theta} + p_t \,\Big|\, r_t\right). +$$ (eq:bk-bayes) + +这就是我们下面模拟的法则。 + +## 计算均衡 + +我们在一个精细网格上离散化 $\theta^I$ 的支撑 $[a,b]$,并将 $f_t$ 表示为密度值的向量。 + +三个计算基元是: + +* `uninformed_demand` 通过求根求解 {eq}`eq:bk-foc` 中的一阶条件,得到 $x^U(p, X^I; f)$。 +* `equilibrium_price` 求解市场出清系统 {eq}`eq:bk-mc`,得到 $p_t$。 +* `bayes_update` 应用 {eq}`eq:bk-bayes` 并重新归一化。 + +```{code-cell} ipython3 +def uninformed_demand(p, XI, f, θ_grid, θ_U, σ2, μ_s, τ2): + """ + 求解一阶条件,得到 x^U(p, X^I; f),即不知情主体 + 在观察价格 p、推测的知情交易 XI 和结转的后验密度 f 下的 + 最优需求。 + """ + with np.errstate(divide='ignore'): + log_f = np.log(f) + s_implied = σ2 * XI / θ_grid + p + log_phi_s = -0.5 * (s_implied - μ_s)**2 / τ2 # s_t 的先验权重 + + def foc(xU): + z = xU * σ2 * XI / (θ_grid * θ_U) + log_w = log_f + log_phi_s - z + M = log_w.max() + w = np.exp(log_w - M) + num = np.sum(w / θ_grid) + den = np.sum(w) + return xU / θ_U - XI * num / den + + return brentq(foc, -50.0, 50.0, xtol=1e-10) +``` + +```{code-cell} ipython3 +def equilibrium_price(s_t, θ_I_true, f, θ_grid, θ_U, σ2, μ_s, τ2): + """ + 给定信号 s_t、真实的知情风险容忍度 θ_I_true 和后验 f, + 求解市场出清系统,得到均衡价格 p_t。 + """ + def mc_residual(p): + XI = θ_I_true * (s_t - p) / σ2 + xU = uninformed_demand(p, XI, f, θ_grid, θ_U, σ2, μ_s, τ2) + return XI + xU - 2.0 + + return brentq(mc_residual, s_t - 10.0, s_t, xtol=1e-8) +``` + +```{code-cell} ipython3 +def bayes_update(f, θ_grid, p_t, xU_t, r_t, σ2, τ2, μ_s): + """ + 给定日期 t 的观察 (p_t, x^U_t, r_t),对 θ^I 的后验进行 + 贝叶斯更新。 + """ + XI = 2.0 - xU_t + s_mean = (σ2 * μ_s + τ2 * r_t) / (σ2 + τ2) + s_var = σ2 * τ2 / (σ2 + τ2) + s_implied = σ2 * XI / θ_grid + p_t + + log_like = -0.5 * (s_implied - s_mean)**2 / s_var + log_like -= log_like.max() # 对数平移以保证数值稳定 + f_new = f * np.exp(log_like) + dθ = θ_grid[1] - θ_grid[0] + f_new /= np.sum(f_new) * dθ + return f_new +``` + +模拟循环通过这三个函数串联 $(s_t, \epsilon_t)$ 冲击。 + +```{code-cell} ipython3 +def simulate(θ_I_true, θ_U, σ2, μ_s, τ2, + a, b, n_grid, T, prior=None, seed=42): + """ + 模拟 T 个时期的 Bray-Kreps 理性学习均衡。 + """ + rng = np.random.default_rng(seed) + θ_grid = np.linspace(a, b, n_grid) + dθ = θ_grid[1] - θ_grid[0] + + if prior is None: + f = np.ones(n_grid) / (b - a) + else: + f = prior(θ_grid) + f /= np.sum(f) * dθ + + s_seq = rng.normal(μ_s, np.sqrt(τ2), T) + eps_seq = rng.normal(0.0, np.sqrt(σ2), T) + + XI_path = np.empty(T) + p_path = np.empty(T) + r_path = np.empty(T) + post_mean = np.empty(T + 1) + post_var = np.empty(T + 1) + post_mean[0] = np.sum(θ_grid * f) * dθ + post_var[0] = np.sum((θ_grid - post_mean[0])**2 * f) * dθ + + snap_times = {0, 5, 20, 50, 100, T} + snapshots = {0: f.copy()} + + for t in range(T): + p_t = equilibrium_price( + s_seq[t], θ_I_true, f, θ_grid, θ_U, σ2, μ_s, τ2 + ) + XI = θ_I_true * (s_seq[t] - p_t) / σ2 + xU = 2.0 - XI + r_t = s_seq[t] + eps_seq[t] + f = bayes_update(f, θ_grid, p_t, xU, r_t, σ2, τ2, μ_s) + + XI_path[t] = XI + p_path[t] = p_t + r_path[t] = r_t + post_mean[t + 1] = np.sum(θ_grid * f) * dθ + post_var[t + 1] = np.sum( + (θ_grid - post_mean[t + 1])**2 * f + ) * dθ + if (t + 1) in snap_times: + snapshots[t + 1] = f.copy() + + return dict( + θ_grid=θ_grid, + snapshots=snapshots, + XI_path=XI_path, + p_path=p_path, + r_path=r_path, + post_mean=post_mean, + post_var=post_var, + ) +``` + +## 后验集中 + +我们用 $[0.5, 4]$ 上的均匀先验和真实 $\theta^I = 2$ 运行模拟。 + +```{code-cell} ipython3 +params = dict( + θ_I_true=2.0, + θ_U=1.0, + σ2=1.0, + μ_s=1.0, + τ2=1.0, + a=0.5, + b=4.0, + n_grid=300, + T=200, + seed=42, +) + +res = simulate(**params) +``` + +第一幅图显示了在选定日期后验密度的快照。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 选定日期时关于 $\theta^I$ 的后验密度 + name: fig-rle-posterior-density + image: + alt: Posterior density on theta^I concentrating around the true value +--- +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +fig, ax = plt.subplots(figsize=(10, 5)) +for t, ft in sorted(res['snapshots'].items()): + ax.plot(res['θ_grid'], ft, lw=2, label=f't = {t}') +ax.axvline(params['θ_I_true'], color='black', ls='--', lw=1.5, + label=r'$\theta^I_{\rm true}$') +ax.set_xlabel(r'$\theta^I$') +ax.set_ylabel('后验密度') +ax.legend() +plt.tight_layout() +plt.show() +``` + +随着价格和回报数据的积累,后验在 $\theta^I_{\rm true} = 2$ 周围收紧。 + +下一幅图追踪后验均值和方差。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 后验均值和方差随时间的变化 + name: fig-rle-posterior-moments + image: + alt: Posterior mean of theta^I converging to the true value and posterior variance vanishing +--- +fig, axes = plt.subplots(1, 2, figsize=(13, 5)) + +ax = axes[0] +ax.plot(np.arange(params['T'] + 1), res['post_mean'], lw=2) +ax.axhline(params['θ_I_true'], color='red', ls='--', lw=2, + label=r'$\theta^I_{\rm true}$') +ax.set_xlabel('$t$') +ax.set_ylabel(r'$E_t[\theta^I]$') +ax.legend() + +ax = axes[1] +ax.plot(np.arange(params['T'] + 1), res['post_var'], lw=2) +ax.set_xlabel('$t$') +ax.set_ylabel(r'${\rm Var}_t[\theta^I]$') + +plt.tight_layout() +plt.show() +``` + +后验均值收敛到真值,后验方差消失。 + +这是后验弱收敛到 $\theta^I_{\rm true}$ 处点质量的具体表现,我们将在下面用一般术语描述。 + +## 均衡交易与价格 + +均衡知情交易 $X^I_t$ 依赖于当前信号 $s_t$、$\theta^I_{\rm true}$ 以及结转的后验 $f_t$,这一切都通过市场出清系统 {eq}`eq:bk-mc`。 + +随着 $f_t$ 在 $\theta^I_{\rm true}$ 周围收紧,平均 $X^I_t$ 逼近 {eq}`eq:bk-full-info-trade` 中的完全传播配置。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 均衡交易和价格随时间的变化 + name: fig-rle-trade-price + image: + alt: Equilibrium informed trade X^I_t and price p_t over time +--- +XI_full = 2 * params['θ_I_true'] / (params['θ_I_true'] + params['θ_U']) +p_mean_full = params['μ_s'] - params['σ2'] * XI_full / params['θ_I_true'] + +fig, axes = plt.subplots(1, 2, figsize=(13, 5)) + +ax = axes[0] +ax.plot(res['XI_path'], lw=2, label='$X^I_t$ (学习)') +ax.axhline(XI_full, color='red', ls='--', lw=2, + label='$X^I$ (完全信息)') +ax.set_xlabel('$t$') +ax.set_ylabel('$X^I_t$') +ax.legend() + +ax = axes[1] +ax.plot(res['p_path'], lw=1.5, alpha=0.7, label='$p_t$ (学习)') +ax.axhline(p_mean_full, color='red', ls='--', lw=2, + label='$E[p_t]$ (完全信息)') +ax.set_xlabel('$t$') +ax.set_ylabel('$p_t$') +ax.legend() + +plt.tight_layout() +plt.show() +``` + +左图显示随着信念集中,$X^I_t$ 逼近完全信息配置。 + +右图显示价格路径,它会波动,因为 $p_t$ 继承了 $s_t$ 的变化。 + +该模拟说明了这一均衡的三个特征。 + +关于 $\theta^I$ 的后验密度在真值周围集中,后验方差消失,且均衡知情交易 $X^I_t$ 收敛到其完全信息基准。 + +接下来的章节将识别这些结果背后的定理以及它们所要求的假设。 + +我们首先陈述 {cite:t}`BrayKreps1987` 对抽象模型的两个收敛结果,然后专注于两主体示例,以确定推动关于真实 $\theta^I$ 集中的假设,最后解释这些假设何时会失效。 + +## 后验评估的收敛 + +设 $(\Omega, \mathcal F)$ 为承载均衡的可测空间。 + +在两主体示例中,$\Omega = \Theta \times \Phi^{\infty}$,其中 $\Theta = [a,b] \times \{\theta^U\}$ 收集结构参数,$\Phi$ 收集每期冲击 $(s_t, \epsilon_t)$,$\mathcal F$ 是乘积博雷尔 $\sigma$-域。 + +主体 $n$ 在日期 $0$ 以 $(\Omega, \mathcal F)$ 上的先验概率测度 $P^n$ 进入。 + +设 $G_t^n \subseteq \mathcal F$ 表示由主体 $n$ 至日期 $t$ 的私人信息生成的 $\sigma$-域,并设 + +$$ +H_t^n(p) += +G_t^n \vee \sigma(p_0, p_1, \dots, p_t) +$$ + +为加入了至日期 $t$ 的均衡价格观察的 $\sigma$-域。 + +尾 $\sigma$-域为 + +$$ +H_\infty^n(p) += +\bigvee_{t \ge 0} H_t^n(p). +$$ + +第一个结果,归功于 {cite:t}`BrayKreps1987`,表明任何事件的条件概率几乎必然收敛。 + +```{prf:proposition} +:label: prop-bk-event-convergence + +固定一个主体 $n$ 和一个事件 $A \in \mathcal F$。 + +过程 $M_t = \mathbb{E}^n[\mathbf 1_A \mid H_t^n(p)]$ 是关于 $(H_t^n(p))_{t \ge 0}$ 的 $P^n$-有界鞅,且 + +$$ +\lim_{t\to\infty} +\mathbb{E}^n[\mathbf 1_A \mid H_t^n(p)] += +\mathbb{E}^n[\mathbf 1_A \mid H_\infty^n(p)], +\qquad P^n\text{-a.s.} +$$ +``` + +证明是有界鞅收敛定理,其中 $M_t \in [0,1]$ 提供了极限识别所需的一致可积性。 + +{prf:ref}`prop-bk-event-convergence` 是后验评估的收敛,而不是向"正确"信念的收敛。 + +有两点值得说明。 + +"几乎必然"陈述是相对于主体 $n$ 自身的先验 $P^n$ 而言的,因此如果两个先验 $P^n$ 和 $P^{n'}$ 相互奇异,则结论未必在共同的 $P$-正测度事件上同时成立。 + +如果先验共享一个共同的零测集族,则同时收敛在一个共同零测集之外成立。 + +{cite:t}`BrayKreps1987` 的第二个结果将收敛从个别事件锐化到参数空间上的整个后验测度,给定关于 $\Theta$ 的拓扑假设。 + +```{prf:assumption} +:label: assum-bk-borel + +参数空间 $\Theta$ 是一个完备可分度量(波兰)空间,且由其开集生成的 $\Theta$ 上的博雷尔 $\sigma$-域使得 $(\Theta, \mathcal B(\Theta))$ 成为一个博雷尔空间。 +``` + +在两主体示例中,$\Theta = [a,b]$ 平凡地满足这个假设。 + +在 {prf:ref}`assum-bk-borel` 下,可以固定条件概率的正则版本:映射 + +$$ +P_t^n: \Omega \to \mathcal P(\Theta), +\qquad +\omega \mapsto P_t^n(\omega), +$$ + +使得对每个可测 $A \subseteq \Theta$,$\omega \mapsto P_t^n(\omega)(A)$ 是 $\mathbb{E}^n[\mathbf 1_{A \times \Phi^\infty} \mid H_t^n(p)](\omega)$ 的一个版本,且 $P_t^n(\omega) \in \mathcal P(\Theta)$ 是 $P^n$-几乎必然的概率测度。 + +锐化后的收敛结果表明这些正则版本几乎必然弱收敛。 + +```{prf:proposition} +:label: prop-bk-measure-convergence + +在 {prf:ref}`assum-bk-borel` 下,正则版本 $P_t^n$ 弱收敛到正则版本 $P_\infty^n$,$P^n$-a.s. + +等价地,对于 $P^n$-几乎每个 $\omega$ 和每个有界连续 $f: \Theta \to \mathbb R$, + +$$ +\int_\Theta f \, dP_t^n(\omega) +\xrightarrow[t \to \infty]{} +\int_\Theta f \, dP_\infty^n(\omega). +$$ +``` + +{cite:t}`BrayKreps1987` 中的证明将 {prf:ref}`prop-bk-event-convergence` 应用于 $\Theta$ 的一个由 $1/k$-球构成的可数不相交划分(因为 $\Theta$ 是波兰空间所以该划分存在),然后调用有界连续函数上弱收敛的 Portmanteau 刻画。 + +因此,理性贝叶斯学习总是产生一个极限后验测度。 + +但 {prf:ref}`prop-bk-measure-convergence` 本身并不确定该极限是什么,在极限正确评估真值之前,还需要额外的结构。 + +## 锐化收敛结果 + +我们现在回到两主体示例,并识别使得 $P_\infty^U$ 是在真实 $\theta^I$ 处点质量的假设。 + +记 $F_t$ 为主体 $U$ 在观察 $(r_{t-1}, p_{t-1}, x^U_{t-1})$ 和所有更早数据后,在日期 $t$ 关于 $\theta^I$ 的后验的累积分布函数。 + +{prf:ref}`prop-bk-measure-convergence` 产生一个随机累积分布函数 $F_\infty$,使得 $F_t$ 弱收敛到 $F_\infty$,$P^U$-a.s. + +三个要素将其锐化为关于真值的集中,对应于 {cite:t}`BrayKreps1987` 中的三个步骤。 + +```{prf:assumption} +:label: assum-bk-continuity + +均衡不知情需求 $x^U(p, F)$ 关于弱收敛在 $F$ 上连续,且在一个 $P^U$-满测度价格集上关于 $p$ 一致连续。 +``` + +```{prf:assumption} +:label: assum-bk-identification + +对于固定的 $\theta^U$ 和极限后验 $F_\infty$,映射 + +$$ +\theta^I +\mapsto +\mathcal L\{p_\infty(s; F_\infty, \theta^I, \theta^U)\} +$$ + +是单射的,其中 $s$ 从其边缘分布中抽取。 + +一个充分条件是该边缘价格分布在 $\theta^I$ 上的严格随机单调性。 +``` + +在本讲座的 CARA-正态设置中,在隐式需求和价格方程所维持的唯一性和正则性下,这些假设是合理的。 + +连续性要求 {eq}`eq:bk-foc` 中一阶条件的根对 $F$ 的连续依赖,而不仅仅是积分的逐点连续性。 + +识别还使用了完整的均衡映射:方程 $p_t = s_t - \sigma^2 X^I_t / \theta^I$ 是有信息量的,但 $X^I_t$ 本身依赖于 $\theta^I$、$F_t$ 和均衡不动点。 + +关于 $\{s_t\}$ 的独立同分布假设(已经是模型的一部分)提供了下面步骤 2 中使用的遍历性。 + +在这三个假设和独立同分布信号序列下,两主体示例中的极限后验集中于真值。 + +```{prf:proposition} +:label: prop-bk-sharpening + +假设 $\theta^I_{\rm true} \in [a,b]$,且先验 $f_0$ 在 $\theta^I_{\rm true}$ 的每个邻域中放置正密度。 + +在 {prf:ref}`assum-bk-borel`、{prf:ref}`assum-bk-continuity` 和 {prf:ref}`assum-bk-identification` 下,并给定独立同分布信号序列 $\{s_t\}$,关于 $\theta^I$ 的极限后验满足 + +$$ +F_\infty += +\delta_{\theta^I_{\rm true}} +\qquad P^U\text{-a.s.} +$$ +``` + +证明有三个步骤。 + +*步骤 1:价格泛函收敛。* + +{prf:ref}`assum-bk-continuity` 和来自 {prf:ref}`prop-bk-measure-convergence` 的弱收敛 $F_t \Rightarrow F_\infty$ 意味着均衡需求 $x^U(p, F_t)$ 收敛到 $x^U(p, F_\infty)$。 + +与市场出清和价格方程 {eq}`eq:bk-price` 结合,得到在一个 $P^U$-满测度集上 $p_t - p_\infty(s_t; F_\infty, \theta^I, \theta^U) \to 0$。 + +*步骤 2:极限价格分布是可观察的。* + +由于偏差 $p_t - p_\infty(s_t; F_\infty, \theta^I, \theta^U) \to 0$ 几乎必然成立且 $\{s_t\}$ 是独立同分布的,观察到的价格的经验分布与极限价格泛函的经验分布具有相同的极限。 + +后者等于 $s \sim N(\mu_s, \tau^2)$ 时 $p_\infty(s; F_\infty, \theta^I, \theta^U)$ 的分布,而该极限作为一个可观察序列的长期频率是 $H_\infty^U(p)$-可测的。 + +*步骤 3:识别。* + +{prf:ref}`assum-bk-identification` 使得 $p_\infty$ 的边缘分布在给定 $(F_\infty, \theta^U)$ 下识别 $\theta^I$。 + +与步骤 2 结合,这意味着 $\theta^I$ 本身是 $H_\infty^U(p)$-可测的,因此对于任何子区间 $[c,d] \subseteq [a,b]$,极限后验满足 $P_\infty^U(\theta^I \in [c,d]) = \mathbf 1_{\{\theta^I_{\rm true} \in [c,d]\}}$。 + +组合步骤 1、2 和 3 得到 $F_\infty = \delta_{\theta^I_{\rm true}}$。 + +上面的数值模拟与这个结果一致。 + +关于 $\theta^I$ 的后验密度坍缩为在 $\theta^I_{\rm true}=2$ 处的尖峰,且均衡知情交易 $X^I_t$ 收敛到完全信息值 $2\theta^I_{\rm true}/(\theta^I_{\rm true} + \theta^U)$。 + +因此,连接 {prf:ref}`prop-bk-event-convergence`(鞅收敛)到 {prf:ref}`prop-bk-sharpening`(关于真值的集中)的路径依赖于三个模型特定的要素:连续性、遍历性和识别。 + +## 收敛的障碍 + +自然地要问,这些要素何时会失效,以及对学习有何后果。 + +### 障碍 1:连续性失效 + +如果 {prf:ref}`assum-bk-continuity` 失效,证明的步骤 1 就会失败。 + +当均衡价格泛函在 $F$ 上不连续时,信念的微小变化可能产生价格信息含量的巨大变化,且信念的弱收敛未必意味着价格的收敛。 + +{cite:t}`BrayKreps1987` 将此标记为其论证中最微妙的步骤。 + +$x^U(p, F)$ 在 $F$ 上的连续性在本讲座的正则 CARA-正态情形中是合理的,但它也要求一阶条件解的唯一性以及该解对 $F$ 的连续依赖。 + +在更丰富的市场结构中验证同一性质通常需要非平凡的正则性论证。 + +### 障碍 2:识别失效 + +如果 {prf:ref}`assum-bk-identification` 失效,即使步骤 1 和步骤 2 成功,步骤 3 也会失败。 + +考虑一个变体,有两个知情主体,风险容忍度 $\theta^{I1}, \theta^{I2}$ 都为不知情主体所未知。 + +在有三个主体、每个各拥有一单位风险资产的情况下,完全传播公式 {eq}`eq:bk-full-communication-price` 给出 + +$$ +p_t += +s_t +- +\frac{3\sigma^2}{\theta^{I1} + \theta^{I2} + \theta^U}, +$$ + +它仅通过和 $\theta^{I1}+\theta^{I2}$ 依赖于 $(\theta^{I1}, \theta^{I2})$。 + +{prf:ref}`prop-bk-measure-convergence` 仍然适用,但 $F_\infty$ 支撑在水平集 + +$$ +\{(\theta_1, \theta_2) \in [a,b]^2 : \theta_1 + \theta_2 = \theta^{I1}_{\rm true} + \theta^{I2}_{\rm true}\}, +$$ + +上,而不是单点集 $\{(\theta^{I1}_{\rm true},\theta^{I2}_{\rm true})\}$。 + +收敛发生了,但收敛到一个观察等价参数值的流形,而不是真值。 + +### 障碍 3:错误设定 + +如果真实的定价关系位于主体先验支撑之外,就会出现另一个障碍。 + +{cite:t}`BlumeEasley1982` 给出了这个障碍的一个风格化版本,而 {doc}`likelihood_ratio_process_2` 在本讲座系列中发展了 Blume-Easley 异质信念模型。 + +每个主体在给定自己的信息和价格下,对其他主体的信息持有相互竞争的条件似然。 + +可能存在一个均衡,其中主体对一个错误模型赋予渐近概率一,该模型给观察到的事件正似然,而真实的稳定价格关系接收零后验概率,因为该关系不存在于先验模型类中。 + +在严格的理性学习中,先验已经覆盖了真值:它支撑在扩展状态空间中贝叶斯一致的模型上,并对真实参数放置正权重。 + +贝叶斯法则只能重新加权那个初始模型类,因此一个先验概率为零的定价关系无论积累多少数据都保持为零。 + +## 在理性预期均衡内部学习 vs. 关于理性预期均衡的学习 + +上述框架指出了 {cite:t}`BrayKreps1987` 中一个重要的概念区分。 + +### 区分 + +在理性预期均衡*内部*学习是本讲座的主题。 + +它是在一个正确设定的模型内部的贝叶斯推断:{prf:ref}`assum-bk-borel`、{prf:ref}`assum-bk-continuity` 和 {prf:ref}`assum-bk-identification` 全部成立,且先验对真值放置正权重。 + +主体 $U$ 对 $\theta^I$ 不确定,但对于每个候选值,他已经知道均衡价格和配置映射。 + +扩展状态空间表述 $\Omega = \Theta \times \Phi^\infty$ 在更大的空间上嵌入了一个理性预期均衡,且推断简化为在 $\Theta$ 上的条件概率。 + +*关于*理性预期均衡的学习是一个根本不同的练习。 + +主体并不从他的概率模型中嵌入的均衡映射开始。 + +相反,他必须从在自己的信念和行为与数据共同演化时生成的数据中推断价格-状态关系。 + +### 权衡 + +这两个概念处于一个精确权衡的对立两侧。 + +一个正确设定的贝叶斯学习者享有 {prf:ref}`prop-bk-event-convergence` 和 {prf:ref}`prop-bk-measure-convergence` 中的收敛保证,但仅仅因为均衡从日期零起就已被内置到先验中。 + +一个将价格-状态关系视为需要估计的对象的适应性学习者,可以希望从数据中发现它,但他使用的估计量无法从应用于正确设定模型的贝叶斯法则中导出。 + +贝叶斯理性学习可以在主体先验中已经包含的均衡映射之间进行更新,但它并不解释主体最初如何获得这些映射。 + +关于*学习*理性预期均衡的文献,始于 {cite:t}`Bray1982` 和 {cite:t}`BraySavin1986`,并由 {cite:t}`MarcetSargent1989jet` 扩展,采取了权衡的第二侧,用**普通最小二乘法**或相关的递归估计量取代贝叶斯法则。 + +配套讲座 {doc}`ls_learning` 在自参照模型中发展了这个最小二乘学习框架,并通过相关的常微分方程追踪由此产生的动态。 + +那些法则在计算上易于处理,并在重要示例中收敛,但它们不是完全设定的理性学习均衡先验所隐含的贝叶斯更新。 + +## 小结 + +本讲座实现了 {cite:t}`BrayKreps1987` 的理性学习均衡。 + +后验评估通过有界鞅收敛而收敛({prf:ref}`prop-bk-event-convergence`),且后验测度在波兰-博雷尔假设下弱收敛({prf:ref}`prop-bk-measure-convergence`)。 + +关于真值的集中另外需要连续性({prf:ref}`assum-bk-continuity`)、遍历性和识别({prf:ref}`assum-bk-identification`);上面的每个障碍都是其中之一的失效。 + +模拟说明了两个结论:关于 $\theta^I$ 的后验朝 $\theta^I_{\rm true}$ 坍缩,且均衡知情交易逼近其完全信息值。 + +理性学习描述了*给定*均衡结构下贝叶斯推断的极限;在 {doc}`ls_learning` 中的适应性学习则描述了该结构最初如何能被学到。 + + +## 练习 + +````{exercise} +:label: rle_ex1 + +*偏离中心的先验* + +基线模拟使用 $\theta^I \in [0.5, 4]$ 上的均匀先验。 + +1. 用一个质量位于真值*之上*的先验重新运行模拟,例如 + +```python +prior = lambda θ: (θ - 0.5)**3 * (4 - θ) +``` + +它在 $\theta = 3.1$ 附近达到峰值。 + +2. 绘制后验均值随时间的变化,与均匀先验基线并列。 + +3. 后验最终是否集中于 $\theta^I_{\rm true}$,速度相比如何? +```` + +```{solution-start} rle_ex1 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +res_uniform = simulate(**params) + +params_biased = dict(params) +params_biased['prior'] = lambda θ: (θ - 0.5)**3 * (4 - θ) +res_biased = simulate(**params_biased) + +fig, ax = plt.subplots(figsize=(10, 5)) +ax.plot(res_uniform['post_mean'], lw=2, label='均匀先验') +ax.plot(res_biased['post_mean'], lw=2, label='偏离中心先验') +ax.axhline(params['θ_I_true'], color='black', ls='--', + label=r'$\theta^I_{\rm true}$') +ax.set_xlabel('$t$') +ax.set_ylabel(r'$E_t[\theta^I]$') +ax.legend() +plt.tight_layout() +plt.show() +``` + +偏离中心的先验使后验均值起点远高于 $\theta^I_{\rm true} = 2$,但贝叶斯更新将其向下驱动到真值。 + +这是理性学习收敛结果的实际体现:任何对 $\theta^I_{\rm true}$ 放置正密度的先验最终都会在其周围集中。 + +```{solution-end} +``` + +```{exercise} +:label: rle_ex2 + +*不同 $\theta^I$ 下的学习速度* + +一个时期关于 $\theta^I$ 的信息通过隐含信号 + +$$ +s_t(\theta) = \frac{\sigma^2 X^I_t}{\theta} + p_t. +$$ + +传递。 + +灵敏度 $|\partial s_t/\partial \theta| = \sigma^2 X^I_t/\theta^2$ 通过 $X^I_t$ 和 $\theta^{-2}$ 依赖于 $\theta^I_{\rm true}$ 的水平。 + +1. 对 $\theta^I_{\rm true} \in \{0.8, 2.0, 3.5\}$ 运行模拟,其他所有参数保持在基线。 + +2. 对每种情形在对数刻度上绘制后验方差。 + +3. 哪个 $\theta^I_{\rm true}$ 值产生最快的集中,结果是否与上面的灵敏度公式相符? +``` + +```{solution-start} rle_ex2 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +fig, ax = plt.subplots(figsize=(10, 5)) +for θ_val in [0.8, 2.0, 3.5]: + params_θ = dict(params) + params_θ['θ_I_true'] = θ_val + res_θ = simulate(**params_θ) + ax.semilogy(res_θ['post_var'], lw=2, + label=fr'$\theta^I_{{\rm true}} = {θ_val}$') +ax.set_xlabel('$t$') +ax.set_ylabel(r'${\rm Var}_t[\theta^I]$ (对数刻度)') +ax.legend() +plt.tight_layout() +plt.show() +``` + +最小的 $\theta^I_{\rm true}$ 产生后验方差最陡峭的下降。 + +原因是灵敏度 $\sigma^2 X^I_t/\theta^2$ 对固定的 $X^I_t$ 按 $\theta^{-2}$ 缩放,因此当 $\theta^I$ 较小时,相同的噪声水平传递关于 $\theta^I$ 的更多信息。 + +```{solution-end} +``` + +```{exercise} +:label: rle_ex3 + +*回报噪声的影响* + +较大的 $\sigma^2$ 加宽了给定 $r_t$ 的 $s_t$ 的条件密度,人们可能猜测这会减慢学习。 + +但 $\sigma^2$ 也缩放 {eq}`eq:bk-price` 中的价格截距,因此跨候选 $\theta$ 的价格分散度随 $\sigma^2$ 增长。 + +1. 用 $\sigma^2 \in \{0.25, 1.0, 4.0\}$ 运行模拟,保持 $\tau^2 = 1$ 固定。 + +2. 对每个 $\sigma^2$ 在对数刻度上绘制后验方差。 + +3. 就从价格推断 $\theta^I$ 的信噪比而言,解释哪种效应占主导。 +``` + +```{solution-start} rle_ex3 +:class: dropdown +``` + +这是一个解答: + +```{code-cell} ipython3 +fig, ax = plt.subplots(figsize=(10, 5)) +for σ2_val in [0.25, 1.0, 4.0]: + params_σ = dict(params) + params_σ['σ2'] = σ2_val + res_σ = simulate(**params_σ) + ax.semilogy(res_σ['post_var'], lw=2, + label=fr'$\sigma^2 = {σ2_val}$') +ax.set_xlabel('$t$') +ax.set_ylabel(r'${\rm Var}_t[\theta^I]$ (对数刻度)') +ax.legend() +plt.tight_layout() +plt.show() +``` + +对于较大的 $\sigma^2$,后验方差下降得*更快*。 + +要理解原因,记 $\nu=\sigma^2$ 并固定实现的交易 $X^I_t$。 + +两个相近的 $\theta$ 值所隐含的信号大约相差 + +$$ +\left|\frac{\partial s_t(\theta)}{\partial \theta}\right| += +\frac{\nu |X^I_t|}{\theta^2}. +$$ + +似然使用 $g(s\mid r_t)$ 比较这些隐含信号,其条件方差为 + +$$ +\operatorname{Var}(s_t\mid r_t) += +\frac{\nu \tau^2}{\nu+\tau^2}. +$$ + +因此,区分相近 $\theta$ 值的局部信噪比正比于 + +$$ +\frac{\nu |X^I_t|/\theta^2} + {\sqrt{\nu\tau^2/(\nu+\tau^2)}} += +\frac{|X^I_t|}{\theta^2} +\sqrt{\frac{\nu(\nu+\tau^2)}{\tau^2}}, +$$ + +当 $\tau^2$ 固定时,这个比率随 $\nu$ 上升。 + +因此,在这个实验中价格揭示效应主导了额外的回报噪声。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/robust_permanent_income.md b/lectures/robust_permanent_income.md new file mode 100644 index 0000000..9705282 --- /dev/null +++ b/lectures/robust_permanent_income.md @@ -0,0 +1,1028 @@ +--- +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 +translation: + title: 稳健永久收入与定价 + headings: + Overview: 概述 + Risk-sensitive recursive preferences: 风险敏感的递归偏好 + Risk-sensitive recursive preferences::The operator under Gaussian uncertainty: 高斯不确定性下的算子 + A preference for robustness: 对稳健性的偏好 + The permanent income economy: 永久收入经济 + The permanent income economy::The $\sigma = 0$ benchmark and the martingale: $\sigma = 0$ 基准与鞅 + Observational equivalence: 观测等价 + Estimation: 估计 + Estimation::The data and the likelihood: 数据与似然 + Estimation::Specification: 设定 + Estimation::Impulse responses and the permanent income mechanism: 脉冲响应与永久收入机制 + Asset pricing and the market price of risk: 资产定价与风险的市场价格 + Asset pricing and the market price of risk::Decentralization: 去中心化 + Asset pricing and the market price of risk::The twisting operator and distorted beliefs: 扭曲算子与扭曲信念 + Asset pricing and the market price of risk::Multi-period claims and the one-period stochastic discount factor: 多期债权与单期随机贴现因子 + Asset pricing and the market price of risk::The market price of risk: 风险的市场价格 + A risk-sensitive regulator: 一个风险敏感的调节者 + Exercises: 练习 + Related lectures: 相关讲座 +--- + +(robust_permanent_income)= +```{raw} jupyter + +``` + +# 稳健永久收入与定价 + +```{contents} 目录 +:depth: 2 +``` + +除了 Anaconda 中已有的库之外,本讲座还需要以下库: + +```{code-cell} ipython3 +:tags: [hide-output] +!pip install --upgrade quantecon +``` + +## 概述 + +本讲座研究 {cite:t}`HST_1999` 的模型。 + +这篇论文提出了一个简单的问题,却带来了令人惊讶的结论。 + +当一个经典的永久收入消费者不再信任其收入的单一概率模型,而是*担心其模型可能被误设*,并希望自己的决策在一*族*相近的模型上都能表现良好时,会发生什么? + +这样的消费者被称为**稳健**决策者。 + +核心发现如下: + +* 对稳健性的偏好隐藏在普通永久收入模型的数量含义之中。 +* 稳健性与风险敏感性是对*同一*决策规则的两种解读,两者都由单一参数 $\sigma$ 支配。 +* 对*微小*程度的模型误设的担忧可以表现为*巨大*的基于市场的风险厌恶度量。 +* 仅凭消费和储蓄数据无法识别稳健性参数:该模型与一个贴现因子更低的标准永久收入模型是**观测等价**的。 +* 但资产价格,特别是**风险的市场价格**,*可以*用来确定稳健性。 + +我们将学习 + +* 风险敏感的递归偏好以及算子 $\mathcal{R}_t$ +* 一个恶意的"第二个体"如何通过双人零和博弈来实现对稳健性的偏好 +* 稳健性与 {cite:t}`GilboaSchmeidler:1989` 和 {cite:t}`EpsteinWang1994` 意义下的**奈特不确定性**之间的联系 +* 一个我们将用数值方法重现的**观测等价**结果 +* 对条件均值的一个微小的最坏情形扭曲如何几乎一对一地转化为风险的市场价格 + +本讲座建立在 {doc}`perm_income`、{doc}`perm_income_cons` 和 {doc}`lqcontrol` 中的思想之上。 + +这里的稳健性机制在 {cite:t}`HansenSargent2008` 中以专著篇幅进行了发展,在 {cite:t}`AHS_2003` 中得到了扩展,并在 {cite:t}`BHS_2009` 中通过检测误差概率进行了重新诠释。 + +让我们从一些导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import brentq +from scipy.stats import norm +import quantecon as qe +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 风险敏感的递归偏好 + +该理论建立在一个递归的线性二次型优化问题之上,但在延续效用如何聚合方面有一个转折。 + +状态按如下方式演化 + +$$ +x_{t+1} = A x_t + B i_t + C w_{t+1}, +$$ (eq:hst_lom) + +其中 $i_t$ 是控制向量,$x_t$ 是状态向量,$w_{t+1}$ 是一个 IID 高斯向量,满足 $\mathbb{E} w_{t+1} = 0$ 和 $\mathbb{E} w_{t+1} w_{t+1}^\top = I$。 + +单期回报为 + +$$ +u(i_t, x_t) = -i_t^\top Q i_t - x_t^\top R x_t, +$$ (eq:hst_return) + +其中 $Q$ 正定,$R$ 半正定。 + +参照 {cite:t}`Epstein_Zin1989`、{cite:t}`Weil_1989` 和 {cite:t}`hansen1995discounted`,跨期偏好由如下递归导出 + +$$ +U_t = u(i_t, x_t) + \beta \, \mathcal{R}_t(U_{t+1}), +$$ (eq:hst_recursion) + +其中**风险敏感算子**为 + +$$ +\mathcal{R}_t(U_{t+1}) \equiv \frac{2}{\sigma} \log \mathbb{E}\!\left[ \exp\!\left( \frac{\sigma U_{t+1}}{2} \right) \Big| J_t \right]. +$$ (eq:hst_R) + +这里 $J_t$ 是在 $t$ 时刻可用的信息。 + +当 $\sigma = 0$ 时,我们设 $\mathcal{R}_t \equiv \mathbb{E}(\,\cdot \mid J_t)$,从而回到通常的冯·诺依曼-摩根斯坦、状态可加的设定。 + +当 $\sigma \neq 0$ 时,算子 $\mathcal{R}_t$ 在 $u$ 的曲率所带来的风险调整*之上*应用了一个额外的风险调整。 + +$\sigma < 0$ 的取值对应于比冯·诺依曼-摩根斯坦基准*更强*的风险厌恶,这也是整篇论文所研究的情形。 + +```{note} +{eq}`eq:hst_R` 中的效用指数形式源自由 {cite:t}`Jacobson_73` 开创、并由 {cite:t}`Whittle_1981` 和 {cite:t}`Whittle_1990` 扩展的*风险敏感控制*文献。 + +{cite:t}`HST_1999` 将其重新诠释为对*稳健性的偏好*这一经济学含义。 +``` + +### 高斯不确定性下的算子 + +当延续效用服从高斯分布时,算子 $\mathcal{R}_t$ 具有清晰的闭式表达。 + +设在给定 $J_t$ 的条件下 $U_{t+1} \sim N(\mu, s^2)$。利用高斯矩生成函数 $\mathbb{E}[\exp(a U_{t+1})] = \exp(a\mu + \tfrac{1}{2}a^2 s^2)$ 并取 $a = \sigma/2$, + +$$ +\mathcal{R}_t(U_{t+1}) += \frac{2}{\sigma} \log \mathbb{E}\!\left[ \exp\!\left( \frac{\sigma U_{t+1}}{2} \right) \Big| J_t \right] += \frac{2}{\sigma}\left( \frac{\sigma}{2}\mu + \frac{\sigma^2}{8} s^2 \right) += \mu + \frac{\sigma}{4} s^2. +$$ (eq:hst_R_gauss) + +对于 $\sigma < 0$,这个值*低于*条件均值 $\mu$:决策者以*悲观*的方式评估不确定的前景,而惩罚随条件方差 $s^2$ 增大。 + +这一确定性等价值有一个富有启发性的分解。 + +{eq}`eq:hst_R` 中的期望通过 $\exp(\sigma U_{t+1}/2)$ 对结果重新加权;对于高斯分布,这种**指数倾斜**产生了一个新的正态密度,其方差*仍为* $s^2$,但均值移动到了 $\mu + \frac{\sigma}{2} s^2$。 + +算子值 $\mu + \frac{\sigma}{4} s^2$ 恰好位于原均值 $\mu$ 与这个最坏情形均值之间的*正中*:它等于最坏情形的期望效用 $\mu + \frac{\sigma}{2}s^2$ *加上*相对熵惩罚 $-\frac{\sigma}{4}s^2$,后者约束着扭曲。 + +```{note} +这两个系数描述的是不同的对象。 + +$U_{t+1}$ 的**最坏情形均值**移动了 $\frac{\sigma}{2}s^2$,而**算子值**(确定性等价值)移动了 $\frac{\sigma}{4}s^2$。 + +两者都是正确的;$\mathcal{R}_t$ 较小的移动反映了恶意个体为扭曲所付出的熵代价。 + +{eq}`eq:hst_R_gauss` 的一个完整推导在 {ref}`hst_ex1` 中给出。 +``` + +让我们将这两个事实可视化,左边是确定性等价值,右边是延续效用的最坏情形(倾斜后的)密度。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 风险敏感算子与最坏情形密度 + name: fig-hst-operator +--- +μ, s = 0.0, 1.0 # 延续效用的条件均值和标准差 + +def R_operator(μ, s, σ): + "针对高斯分布 U ~ N(μ, s^2) 的风险敏感算子。" + if σ == 0: + return μ + return μ + σ * s**2 / 4 + +σ_vals = np.linspace(-1.5, 0.0, 200) +R_vals = [R_operator(μ, s, sg) for sg in σ_vals] + +fig, axes = plt.subplots(1, 2, figsize=(11, 4)) + +axes[0].plot(σ_vals, R_vals, lw=2) +axes[0].axhline(μ, color='k', ls='--', lw=1, label=r'$E[U_{t+1}]=\mu$') +axes[0].set_xlabel(r'风险敏感性 $\sigma$') +axes[0].set_ylabel(r'$\mathcal{R}_t(U_{t+1})$') +axes[0].set_title('确定性等价值') +axes[0].legend() + +# 倾斜后的密度 +grid = np.linspace(μ - 4*s, μ + 4*s, 400) +axes[1].plot(grid, norm.pdf(grid, μ, s), lw=2, + label=r'参考 $N(\mu, s^2)$') +for σ in [-0.5, -1.0]: + shift = σ * s**2 / 2 # U_{t+1} 的最坏情形均值移动 + axes[1].plot(grid, norm.pdf(grid, μ + shift, s), lw=2, ls='--', + label=f'最坏情形, $\\sigma={σ}$') + axes[1].axvline(μ + σ * s**2 / 4, color='C3', lw=0.8, ls=':') +axes[1].set_xlabel(r'延续效用 $U_{t+1}$') +axes[1].set_ylabel('密度') +axes[1].set_title('最坏情形密度') +axes[1].legend() +fig.tight_layout() +plt.show() +``` + +左图展示了随着 $\sigma$ 变得更负,确定性等价值 $\mathcal{R}_t$ 滑落到均值之下。 + +右图展示了相应的延续效用的最坏情形密度:一个稳健的个体*表现得仿佛* $U_{t+1}$ 是从一个悲观地重新居中的分布(均值 $\mu + \frac{\sigma}{2}s^2$,虚线)中抽取的,而算子值 $\mathcal{R}_t = \mu + \frac{\sigma}{4}s^2$(点线)则位于它与参考均值 $\mu$ 之间的中点。 + +## 对稳健性的偏好 + +上面右图中的悲观倾斜不仅仅是一个类比。 + +{cite:t}`HST_1999` 表明,风险敏感问题是一个**双人零和博弈**的值函数。 + +在这个博弈中,一个个体选择控制 $\{i_t\}$,而第二个恶意的个体选择对冲击条件均值的扭曲 $\{v_t\}$。 + +扭曲后的运动规律为 + +$$ +x_{t+1} = A x_t + B i_t + C (w_{t+1} + v_t). +$$ (eq:hst_distorted_lom) + +最小化的个体希望将状态推向令人痛苦的方向,但受到对扭曲大小的惩罚的约束。 + +以 $-1/\sigma \geq 0$ 作为约束扭曲序列的约束的拉格朗日乘子,马尔可夫完美均衡具有值函数 + +$$ +\tilde{W}(x) = \inf_v \sup_i \left\{ -i^\top Q i - x^\top R x + \beta \left[ -\frac{1}{\sigma} v^\top v + \mathbb{E}\,\tilde{W}(Ax + Bi + C(w + v)) \right] \right\}. +$$ (eq:hst_game) + +因为 $\sigma < 0$ 使得 $-1/\sigma > 0$,所以 $-\frac{1}{\sigma}v^\top v$ 这一项*惩罚*恶意个体的大扭曲。 + +较小的 $|1/\sigma|$(更负的 $\sigma$)意味着更便宜的扭曲预算,因而个体所防范的模型族更大,反映出*更强*的对稳健性的偏好。 + +这正是 {cite:t}`GilboaSchmeidler:1989` 的最大-最小期望效用结构:个体的"名义模型"设 $v_t = 0$,但他们考虑由 $\{v_t\}$ 索引的整整一族替代模型,并针对最坏情形采取行动。 + +参照 {cite:t}`EpsteinWang1994`,所隐含的概率测度的非唯一性是**奈特不确定性**的一种形式。 + +稳健问题与风险敏感问题共享同一个值函数矩阵 $\Omega$ 和同一个决策规则 $i_t = -F x_t$;它们仅在解读上有所不同。 + +## 永久收入经济 + +现在我们特殊化到永久收入模型的一个习惯持续性版本。 + +一个规划者通过服务流 $\{s_t\}$ 并使用如下递归来对消费流 $\{c_t\}$ 排序 + +$$ +U_t = -(s_t - b_t)^2 + \beta\, \mathcal{R}_t(U_{t+1}), +$$ (eq:hst_pi_pref) + +其中 $\{b_t\}$ 是一个外生的偏好(极乐点)冲击。 + +服务通过家庭技术从消费中产生 + +$$ +s_t = (1 + \lambda) c_t - \lambda h_{t-1}, +$$ (eq:hst_services) + +$$ +h_t = \delta_h h_{t-1} + (1 - \delta_h) c_t, +$$ (eq:hst_habit) + +其中 $\lambda > 0$ 且 $\delta_h \in (0, 1)$。 + +这里 $h_t$ 是当前和过去消费的几何平均,因此 {eq}`eq:hst_services` 使服务*负向地*依赖于过去消费的加权平均,这就是**习惯持续性**。 + +存在一个线性生产技术 + +$$ +c_t + i_t = \gamma k_{t-1} + d_t, +$$ + +且资本按 $k_t = \delta_k k_{t-1} + i_t$ 累积,其中 $\{d_t\}$ 是一个外生禀赋。 + +综合起来, + +$$ +c_t + k_t = (\delta_k + \gamma) k_{t-1} + d_t, +\qquad R \equiv \delta_k + \gamma, +$$ (eq:hst_budget) + +因此 $R$ 是资本的总物理回报,在一个去中心化经济中它等于总的**无风险利率**。 + +禀赋冲击和偏好冲击由一个共同的线性状态驱动, + +$$ +z_{t+1} = A_{22} z_t + C_2 w_{t+1}, +\qquad d_t = U_d z_t, \quad b_t = U_b z_t. +$$ (eq:hst_shocks) + +整个经济是控制问题 {eq}`eq:hst_lom`–{eq}`eq:hst_recursion` 的一个特例:将 $h_{t-1}$、$k_{t-1}$ 和 $z_t$ 堆叠进状态 $x_t$,并令控制为 $i_t = s_t - b_t$。 + +### $\sigma = 0$ 基准与鞅 + +为了建立直觉,设 $\sigma = 0$ 并施加永久收入约束 $\beta R = 1$,正如 {cite:t}`Hall1978` 中所做的那样。 + +一阶条件随后表明,消费服务的边际效用是一个**鞅**, + +$$ +\mathbb{E}_t \, \mu_{c,t+1} = \mu_{c,t}, +$$ (eq:hst_martingale) + +并且 $\mu_{s,t}$ 继承了如下表示 + +$$ +\mu_{s,t} = \mu_{s,t-1} + v^\top w_t +$$ (eq:hst_mu_rw) + +其中 $v$ 为某个载荷向量。 + +方程 {eq}`eq:hst_martingale` 是经典的表述,即在 $\beta R = 1$ 下,消费只对*新信息*作出反应,因此它是一个随机游走。 + +这正是 {cite:t}`Hall1978` 和 {cite:t}`Campbell1987` 在美国总量数据上检验的结果。 + +标量 + +$$ +\theta^2 \equiv v^\top v +$$ + +度量了边际效用鞅 {eq}`eq:hst_mu_rw` 的新息方差。 + +它将是我们下面所需的基准经济唯一的一个汇总统计量。 + +```{note} +在理性预期解读下,基准 $\sigma = 0$ 的永久收入模型*没有预防性储蓄*,正如 Zeldes 所强调的那样。 + +引入稳健性($\sigma < 0$)重新激活了一个预防性动机:消费者防范冲击条件均值中的最坏情形误差。 +``` + +## 观测等价 + +这是这篇论文的第一个重要结果。 + +```{prf:proposition} 观测等价 +:label: prop:hst_oe + +固定除 $\beta$ 和 $\sigma$ 之外的所有参数。假设 $\beta R = 1$。则存在 $\underline{\sigma} < 0$,使得当 $\sigma = 0$ 时最优的消费-投资计划*同样*对任何 $\sigma \in (\underline{\sigma}, 0)$ 都是最优的,前提是贴现因子被降低到一个随 $\sigma$ 直接变化的值 $\hat\beta(\sigma)$。 +``` + +换言之:就*数量* $\{c_t, k_t\}$ 而言,稳健($\sigma < 0$)的永久收入模型与贴现因子较小的标准($\sigma = 0$)模型是无法区分的。 + +增强对稳健性的偏好会刺激一个预防性储蓄动机;降低 $\beta$ 会使储蓄变得不那么有吸引力;沿着某条特定的轨迹,这两种效应恰好相互抵消。 + +证明是构造性的,并给出了观测等价的 $(\sigma, \hat\beta)$ 对的显式轨迹。定义 + +$$ +\Omega(\beta) = \frac{\beta - 1 + \sigma \theta^2 + \sqrt{(\beta - 1 + \sigma \theta^2)^2 + 4 \sigma \theta^2}}{-2 \sigma \theta^2}, +$$ (eq:hst_Omega_scalar) + +$$ +\hat\zeta(\beta) = 1 + \frac{\theta^2 \sigma\, \Omega(\beta)}{1 - \sigma \theta^2 \Omega(\beta)} . +$$ (eq:hst_zeta) + +等价贴现因子 $\hat\beta$ 解 + +$$ +\hat\beta \, R \, \hat\zeta(\hat\beta) = 1. +$$ (eq:hst_betahat) + +下界 $\underline{\sigma}$ 是 {eq}`eq:hst_Omega_scalar` 中的平方根保持为实数的最负的 $\sigma$。 + +让我们重现这条轨迹,它是 {cite:t}`HST_1999` 中图 1 的一个版本。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 等价的 $(\sigma, \hat\beta)$ 对 + name: fig-hst-oe +--- +β_bench = 0.9971 # 基准贴现因子(年利率约 2.5%) +Rf = 1 / β_bench # 由 β R = 1 确定的总无风险回报 +θ2 = 0.01 # 边际效用新息的方差, v^T v + +def Ω_scalar(β, σ, θ2): + disc = (β - 1 + σ * θ2)**2 + 4 * σ * θ2 + if disc < 0: + return np.nan # 低于 σ 下界:无实数解 + return (β - 1 + σ * θ2 + np.sqrt(disc)) / (-2 * σ * θ2) + +def ζ_hat(β, σ, θ2): + Ω = Ω_scalar(β, σ, θ2) + return 1 + (θ2 * σ * Ω) / (1 - σ * θ2 * Ω) + +def β_hat(σ, θ2, Rf): + "使 σ 与 σ=0 观测等价的贴现因子。" + if σ == 0: + return 1 / Rf + f = lambda b: b * Rf * ζ_hat(b, σ, θ2) - 1 + return brentq(f, 0.95, 1 / Rf - 1e-12) + +σ_vals = np.linspace(-1.2e-4, 0.0, 200) +β_vals = np.array([β_hat(sg, θ2, Rf) for sg in σ_vals]) + +fig, ax = plt.subplots() +ax.plot(β_vals, σ_vals, lw=2) +ax.set_xlabel(r'贴现因子 $\hat\beta$') +ax.set_ylabel(r'风险敏感性 $\sigma$') +ax.axhline(0, color='k', lw=0.8, ls='--') +fig.tight_layout() +plt.show() +``` + +这条曲线上的每一点都产生*完全相同*的消费和投资数据。 + +沿曲线向下移动(更负的 $\sigma$,即对稳健性更强的偏好)需要*更低*的贴现因子 $\hat\beta$ 才能保持数量不变。 + +这就是为什么仅凭消费和储蓄数据无法告诉我们消费者对模型误设的担忧程度。 + +## 估计 + +{cite:t}`HST_1999` 将观测等价结果转化为一种实证策略。 + +由于数量数据无法确定 $\sigma$,作者们首先估计模型的 $\sigma = 0$ 版本,*仅*以消费和投资为条件构建似然,然后利用 {prf:ref}`prop:hst_oe` 的轨迹描绘出与这些估计相符的 $(\sigma, \hat\beta)$ 对族。 + +资产价格(下一节)打破了这一僵局。 + +### 数据与似然 + +模型拟合到美国战后季度数据,1970 年第一季度至 1996 年第三季度。 + +* *消费*被度量为非耐用品加服务。 +* *投资*被度量为耐用品加私人投资总额。 + +两个序列都用确定性增长因子 $1.0033^{t}$ 平减,因此模型拟合到*去趋势*的数据。 + +似然是高斯的,递归构建(卡尔曼滤波器),初始状态的不可观测部分使用 Hansen 和 Sargent 的方法进行估计。 + +### 设定 + +偏好冲击是一个常数,$b_t = \mu_b$,固定为 $\mu_b = 32$;回顾 {eq}`eq:hst_budget` 的讨论,$b_t$ 的*水平*不影响决策规则,只影响价格。 + +禀赋是一个*持续*成分和一个*暂时*成分之和,每个成分都是由正交冲击驱动的二阶自回归, + +$$ +(1 - \phi_1 L)(1 - \phi_2 L)\, d^{*}_t = c_{d^{*}}\, w^{d^{*}}_t, +$$ (eq:hst_dstar) + +$$ +(1 - \alpha_1 L)(1 - \alpha_2 L)\, \hat d_t = c_{\hat d}\, w^{\hat d}_t, +$$ (eq:hst_dhat) + +其中 $d_t = \mu_d + d^{*}_t + \hat d_t$。 + +一个似然比较(从 AR(1) 到 AR(2) 有收益但再往后没有)促使作者们为暂时成分采用二阶设定。 + +支配内生动态的四个参数是 $(\gamma, \delta_k, \beta, \lambda)$。 + +折旧因子设为 $\delta_k = 0.975$,并施加永久收入约束 $\beta R = 1$(由无约束估计所证实),$\beta = 0.9971$,在增长调整后意味着 $2.5\%$ 的年实际利率。 + +带习惯持续性的最大似然估计如下重现,它是 {cite:t}`HST_1999` 中表 2 的一个版本。 + +| 参数 | 符号 | 估计值 | +|---|---|---| +| 贴现因子 | $\beta$ | 0.997 | +| 习惯折旧 | $\delta_h$ | 0.682 | +| 习惯权重 | $\lambda$ | 2.443 | +| 暂时 AR 根 | $\alpha_1, \alpha_2$ | 0.813, 0.189 | +| 持续 AR 根 | $\phi_1, \phi_2$ | 0.998, 0.704 | +| 禀赋均值 | $\mu_d$ | 13.710 | +| 暂时冲击尺度 | $c_{\hat d}$ | 0.155 | +| 持续冲击尺度 | $c_{d^{*}}$ | 0.108 | + +最引人注目的单个估计是持续禀赋成分的自回归根 $\phi_1 = 0.998$,这个数字几乎与单位根无法区分。 + +### 脉冲响应与永久收入机制 + +冲击的持续性决定了消费对其反应的强度。 + +在永久收入逻辑下($\beta R = 1$ 且,为清晰起见,*没有*习惯),消费在冲击时刻按财富变化的**年金价值**跳升,此后是一个鞅, + +$$ +\Delta c = \left(1 - \frac{1}{R}\right) \sum_{j \geq 0} R^{-j}\, \psi_j, +$$ (eq:hst_pi_mpc) + +其中 $\psi_j = \partial d_{t+j} / \partial w_t$ 是禀赋自身的脉冲响应。 + +一个近乎永久的冲击具有很大的现值并使消费大幅移动;一个暂时冲击具有很小的现值并几乎不使其移动。 + +让我们计算禀赋响应 {eq}`eq:hst_dstar`–{eq}`eq:hst_dhat` 以及隐含的消费响应。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 禀赋与消费的脉冲响应 + name: fig-hst-irf +--- +def ar2_irf(r1, r2, c, H): + "(1 - r1 L)(1 - r2 L) x = c w 对单位 w 冲击的脉冲响应。" + ψ = np.zeros(H) + ψ[0] = c + if H > 1: + ψ[1] = (r1 + r2) * ψ[0] + for j in range(2, H): + ψ[j] = (r1 + r2) * ψ[j-1] - r1 * r2 * ψ[j-2] + return ψ + +H = 50 +disc = Rf**(-np.arange(H)) # 来自上一个单元格的 Rf = 1/β + +ψ_p = ar2_irf(0.998, 0.704, 0.108, H) # 持续禀赋 d* +ψ_t = ar2_irf(0.813, 0.189, 0.155, H) # 暂时禀赋 d_hat + +# 平坦的消费响应 +dc_p = (1 - 1/Rf) * np.sum(disc * ψ_p) +dc_t = (1 - 1/Rf) * np.sum(disc * ψ_t) + +print(f"持续冲击: 消费响应于 " + f"{100*dc_p/ψ_p[0]:.0f}% 的冲击") +print(f"暂时冲击: 消费响应于 " + f"{100*dc_t/ψ_t[0]:.0f}% 的冲击") + +fig, axes = plt.subplots(1, 2, figsize=(11, 4), sharey=True) +for ax, ψ, dc, shock_label in [ + (axes[0], ψ_p, dc_p, '持续冲击 $d^{*}$'), + (axes[1], ψ_t, dc_t, '暂时冲击 $\\hat d$')]: + ax.plot(ψ, lw=2, label=fr'{shock_label}: 禀赋响应 $\psi_j$') + ax.axhline(dc, color='C3', ls='--', lw=2, + label=r'消费响应 $\Delta c$') + ax.set_title(shock_label) + ax.set_xlabel('时域 $j$(季度)') + ax.legend() +axes[0].set_ylabel('响应') +fig.tight_layout() +plt.show() +``` + +这一对比是 {cite:t}`Hall1978` 和 {cite:t}`Campbell1987` 所检验的永久收入假说的核心。 + +消费追踪持续冲击的很大一部分,其近乎单位根使其几乎成为永久收入,但只追踪暂时冲击的一小部分,后者的大部分被储蓄起来并表现为投资。 + +```{note} +在习惯持续性($\lambda > 0$)下,消费响应不再是平坦的:它们变成驼峰状,因为遵循鞅逻辑的是服务而非消费。 + +估计的 $\lambda = 2.443$ 和 $\delta_h = 0.682$ 意味着具有经济重要性的习惯效应,且一个似然比比较强烈地拒绝了 $\lambda = 0$。 + +{cite:t}`HST_1999` 将这些量级与时间不可分偏好文献中的习惯估计进行了比较。 +``` + +## 资产定价与风险的市场价格 + +{cite:t}`HST_1999` 展示了在数量数据中看起来完全相同的观测等价对,如何对资产价格有*不同*的含义。 + +### 去中心化 + +参照 {cite:t}`Lucas1978`,我们将稳健(或风险敏感)规划解视为一个由大量交易证券的相同个体所组成的竞争经济的配置。 + +均衡价格是使每个个体满足于消费规划者的配置的**影子价格**,将其视为一个禀赋过程。 + +状态的均衡运动规律为 + +$$ +x_{t+1} = A^{0} x_t + C w_{t+1}, +$$ (eq:hst_equil_lom) + +且最优处的值函数为 $U^{e}_t = x_t^\top \Omega x_t + \rho$。 + +为支持稳健配置,价格必须使用合理化规划者选择的*同一个*悲观的、扭曲的信念来计算。 + +这就是风险敏感性($\sigma < 0$)在价格上留下印记的地方,尽管由观测等价性,它在数量上不留任何痕迹。 + +### 扭曲算子与扭曲信念 + +在冯·诺依曼-摩根斯坦设定下,对下一期*效用*的债权定价是平凡的,但在风险敏感性下则并不平凡。 + +关键对象是**扭曲算子** + +$$ +\mathcal{T}_t U_{t+1} \equiv \frac{\mathbb{E}(V_{t+1} U_{t+1} \mid J_t)}{\mathbb{E}(V_{t+1} \mid J_t)}, +\qquad +V_{t+1} \equiv \exp\!\left(\frac{\sigma U^{e}_{t+1}}{2}\right), +$$ (eq:hst_twist) + +它通过均衡延续效用的指数对结果重新加权。 + +它满足次梯度不等式 + +$$ +\mathcal{R}_t(U_{t+1}) - \mathcal{R}_t(U^{e}_{t+1}) \leq \mathcal{T}_t U_{t+1} - \mathcal{T}_t U^{e}_{t+1}, +$$ (eq:hst_subgrad) + +因此 $\mathcal{T}_t$ 表现得像一个*扭曲的*条件期望,正是 {cite:t}`EpsteinWang1994` 中用来对衍生债权定价的测度变换。 + +具体地,$\mathcal{T}_t$ 是在一个**扭曲转移律**下的普通条件期望 + +$$ +x_{t+1} = \hat A x_t + \hat C w_{t+1}, +\qquad +\hat C \hat C^\top = C (I - \sigma C^\top \Omega C)^{-1} C^\top, +$$ (eq:hst_pricing_lom) + +其中 $\hat A$ 由 {eq}`eq:hst_D` 式风险修正给出。 + +因为 $\sigma < 0$ 且 $\Omega$ 半负定,$(I - \sigma C^\top\Omega C)^{-1}$ 超过单位矩阵:定价测度对下一期状态赋予一个*悲观移动的条件均值**以及*一个*膨胀的条件方差*。 + +这两种扭曲正是产生风险溢价的东西。 + +### 多期债权与单期随机贴现因子 + +流的价格通过迭代算子来构建。 + +定义 $\mathcal{S}_{t,\tau} = \mathcal{T}_t \mathcal{T}_{t+1} \cdots \mathcal{T}_{t+\tau-1}$。对消费流 $\{c_{t+\tau}\}$ 债权的 $t$ 时刻价格于是是扭曲的边际效用的贴现和,而具有收益 $p_{t+1}$ 的单期证券定价为 + +$$ +q_t = \mathcal{T}_t\!\left\{ \beta \frac{\mathcal{M}^{c}_{t+1}}{\mathcal{M}^{c}_{t}}\, p_{t+1} \right\} + = \mathbb{E}\!\left( m_{t+1,t}\, p_{t+1} \mid J_t \right), +$$ (eq:hst_oneperiod) + +其中 $\mathcal{M}^{c}_t$ 是消费的边际效用,$m_{t+1,t}$ 是单期**随机贴现因子**(跨期边际替代率)。 + +在风险敏感性下,$m_{t+1,t}$ 分解为两部分, + +$$ +m_{t+1,t} = m^{f}_{t+1,t}\; m^{r}_{t+1,t}, +$$ (eq:hst_sdf) + +其中 + +$$ +m^{f}_{t+1,t} = \beta \frac{\mathcal{M}^{c}_{t+1}}{\mathcal{M}^{c}_{t}} +$$ + +是*熟悉的*跨期边际替代率(当 $\sigma = 0$ 时唯一存在的项),而 + +$$ +m^{r}_{t+1,t} = \frac{\exp(\sigma U^{e}_{t+1}/2)}{\mathbb{E}[\exp(\sigma U^{e}_{t+1}/2) \mid J_t]} +$$ (eq:hst_mr) + +是一个条件均值为一的乘性调整。 + +因子 {eq}`eq:hst_mr` 是额外风险溢价的来源。 + +### 风险的市场价格 + +在*稳健性*解读下,同一个乘性因子等于最坏情形与参考冲击密度之间的**似然比**, + +$$ +m^{u}_{t+1,t} = \frac{\exp[-(w_{t+1} - \hat v_t)^\top(w_{t+1} - \hat v_t)/2]}{\exp(-w_{t+1}^\top w_{t+1}/2)}, +$$ (eq:hst_mu) + +其中 $\hat v_t$ 是恶意个体选择的最坏情形条件均值扭曲。 + +直接计算给出 + +$$ +\mathbb{E}_t(m^{u}_{t+1,t}) = 1, +\qquad +\mathbb{E}_t\big[(m^{u}_{t+1,t})^2\big] = \exp(\hat v_t^\top \hat v_t), +$$ + +从而,对于小扭曲, + +$$ +\operatorname{std}_t(m^{u}_{t+1,t}) = \big[\exp(\hat v_t^\top \hat v_t) - 1\big]^{1/2} \approx |\hat v_t|. +$$ (eq:hst_mpr) + +**风险的市场价格**是可达到的最大夏普比率,等于沿有效前沿的 $\operatorname{std}_t(m_{t+1,t}) / \mathbb{E}_t(m_{t+1,t})$({cite:t}`Hansen_Jagannathan_1991` 界)。 + +因此它近似等于*最坏情形扭曲的量级* $|\hat v_t|$。 + +这就是这篇论文的关键结论:一个单位范数方向上 $x\%$ 的条件均值误设,会使风险的市场价格提高大约 $x/100$。 + +一个*微小*的、统计上难以检测的对模型的怀疑,可以产生数据中所见的*巨大*的风险价格。 + +让我们通过蒙特卡洛来检验关键恒等式 {eq}`eq:hst_mpr`。 + +```{code-cell} ipython3 +rng = np.random.default_rng(12345) + +def mpr_check(v_hat, n=2_000_000): + """ + 模拟最坏情形似然比 m^u 并将其 + 条件标准差与 |v_hat| 进行比较。 + """ + k = len(v_hat) + w = rng.standard_normal((n, k)) + # N(v_hat, I) 相对于 N(0, I) 的对数似然比 + log_mu = w @ v_hat - 0.5 * v_hat @ v_hat + mu = np.exp(log_mu) + return mu.mean(), mu.std(), np.linalg.norm(v_hat) + +print(f"{'|v_hat|':>10}{'E[m^u]':>12}{'std(m^u)':>12}{'approx |v_hat|':>16}") +for scale in [0.05, 0.10, 0.20]: + v_hat = np.array([scale, 0.0]) # 一个方向上的扭曲 + mean, std, norm_v = mpr_check(v_hat) + print(f"{norm_v:10.3f}{mean:12.4f}{std:12.4f}{norm_v:16.3f}") +``` + +模拟得到的 $m^{u}$ 条件均值为一,其条件标准差紧密追踪 $|\hat v_t|$,证实了 {eq}`eq:hst_mpr`。 + +一个 10% 的扭曲带来接近 0.10 的风险市场价格。 + +## 一个风险敏感的调节者 + +为了具体看到稳健决策规则和最坏情形冲击,我们直接求解递归风险敏感控制问题 {eq}`eq:hst_lom`–{eq}`eq:hst_recursion`。 + +猜一个值函数 $W(x) = x^\top \Omega x + \rho$,其中 $\Omega$ 半负定。作用于这个二次型的风险敏感算子 {eq}`eq:hst_R` 引入了**风险调整** + +$$ +\mathcal{D}(\Omega) = \Omega + \sigma \Omega C (I - \sigma C^\top \Omega C)^{-1} C^\top \Omega, +$$ (eq:hst_D) + +因此,用 $\mathcal{D}(\Omega)$ 替换 $\Omega$,贝尔曼方程就变成了一个普通的线性二次型方程。 + +迭代 + +$$ +F = (Q - \beta B^\top \mathcal{D} B)^{-1}(N - \beta B^\top \mathcal{D} A), +$$ + +$$ +\Omega \leftarrow -R - F^\top Q F + (F^\top N + N^\top F) + \beta (A - BF)^\top \mathcal{D} (A - BF), +$$ + +至一个不动点,得到最优规则 $i_t = -F x_t$。 + +最坏情形均值扭曲随后关于状态是线性的,$\hat v_t = G x_t$,其中 + +$$ +G = \sigma (I - \sigma C^\top \Omega C)^{-1} C^\top \Omega (A - B F). +$$ (eq:hst_G) + +当 $\sigma = 0$ 时,我们有 $\mathcal{D}(\Omega) = \Omega$ 且 $G = 0$,恢复标准调节者。 + +```{code-cell} ipython3 +def solve_rslq(A, B, C, Q, R, β, σ, N=None, + tol=1e-12, max_iter=100_000): + """ + 求解递归风险敏感 LQ 问题 + + U_t = -(x^T R x + i^T Q i + 2 i^T N x) + β R_t(U_{t+1}) + x_{t+1} = A x_t + B i_t + C w_{t+1} + + 返回反馈规则 F (i = -F x)、值矩阵 Ω、 + 闭环矩阵 A - B F 和最坏情形载荷 G (v = G x)。 + """ + A, B, C, Q, R = map(np.atleast_2d, (A, B, C, Q, R)) + n, kw = A.shape[0], C.shape[1] + if N is None: + N = np.zeros((B.shape[1], n)) + Ω = -np.eye(n) # 负定起点 + Iw = np.eye(kw) + for it in range(max_iter): + M = Iw - σ * C.T @ Ω @ C + D = Ω + σ * Ω @ C @ np.linalg.solve(M, C.T @ Ω) + F = np.linalg.solve(Q - β * B.T @ D @ B, N - β * B.T @ D @ A) + Acl = A - B @ F + Ω_new = (-R - F.T @ Q @ F + (F.T @ N + N.T @ F) + + β * Acl.T @ D @ Acl) + if np.max(np.abs(Ω_new - Ω)) < tol: + Ω = Ω_new + break + Ω = Ω_new + M = Iw - σ * C.T @ Ω @ C + G = σ * np.linalg.solve(M, C.T @ Ω @ (A - B @ F)) + return F, Ω, A - B @ F, G +``` + +我们首先验证,在 $\sigma = 0$ 时我们的求解器重现了 QuantEcon 的普通 LQ 调节者。 + +```{code-cell} ipython3 +# 稳定的调节者 +A = np.array([[0.9, 0.0], + [0.0, 0.8]]) +B = np.array([[1.0], + [0.0]]) +C = np.array([[0.3], + [0.2]]) +Q = np.array([[1.0]]) +R = np.eye(2) +β = 0.95 + +# QuantEcon 普通 LQ +lq = qe.LQ(Q, R, A, B, C=C, beta=β) +P, F_qe, d = lq.stationary_values() + +# Sigma 为零的检查 +F0, Ω0, Acl0, G0 = solve_rslq(A, B, C, Q, R, β, σ=0.0) + +print("QuantEcon LQ 反馈规则 F :", F_qe.flatten()) +print("solve_rslq 反馈规则 F :", F0.flatten()) +print("最大 |差异| :", np.max(np.abs(F0 - F_qe))) +``` + +两者精确到机器精度地一致。 + +现在我们增强对稳健性的偏好,并检查控制规则和最坏情形冲击如何响应。 + +```{code-cell} ipython3 +σ_vals = [0.0, -0.3, -0.6] + +print(f"{'σ':>7}{'F[0]':>10}{'F[1]':>10}{'G[0]':>10}{'G[1]':>10}") +for σ in σ_vals: + F, Ω, Acl, G = solve_rslq(A, B, C, Q, R, β, σ) + print(f"{σ:7.2f}{F[0,0]:10.4f}{F[0,1]:10.4f}" + f"{G[0,0]:10.4f}{G[0,1]:10.4f}") +``` + +随着 $\sigma$ 变得更负: + +* 反馈增益 $F$ 增大,因为稳健个体对状态反应*更为激进*,担心最坏情形冲击会放大偏差; +* 最坏情形载荷 $G$ 偏离零,因为恶意个体将冲击推向伤害最大的方向。 + +最后,让我们通过在*参考*模型下模拟受控状态,同时显示稳健个体所防范的条件均值扭曲 $\hat v_t = G x_t$,来看看最坏情形扭曲的实际运作。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 受控状态与扭曲 + name: fig-hst-sim +--- +def simulate(A, B, C, F, G, T=60, seed=0): + rng = np.random.default_rng(seed) + n, kw = A.shape[0], C.shape[1] + x = np.zeros((T + 1, n)) + v = np.zeros((T, kw)) + x[0] = np.array([1.0, 1.0]) # 初始偏差 + for t in range(T): + v[t] = (G @ x[t]).flatten() + w = rng.standard_normal(kw) + x[t + 1] = A @ x[t] + (B @ (-F @ x[t])).flatten() + (C @ w).flatten() + return x, v + +fig, axes = plt.subplots(1, 2, figsize=(11, 4)) + +for σ, color in zip([0.0, -0.6], ['C0', 'C3']): + F, Ω, Acl, G = solve_rslq(A, B, C, Q, R, β, σ) + x, v = simulate(A, B, C, F, G, seed=42) + axes[0].plot(x[:, 0], color=color, lw=2, label=f'$\\sigma={σ}$') + axes[1].plot(v[:, 0], color=color, lw=2, label=f'$\\sigma={σ}$') + +axes[0].set_xlabel('$t$') +axes[0].set_ylabel(r'受控状态 $x_{1,t}$') +axes[0].axhline(0, color='k', lw=0.8, ls='--') +axes[0].set_title('受控状态') +axes[0].legend() + +axes[1].set_xlabel('$t$') +axes[1].set_ylabel(r'最坏情形均值扭曲 $\hat v_{1,t}$') +axes[1].axhline(0, color='k', lw=0.8, ls='--') +axes[1].set_title('均值扭曲') +axes[1].legend() +fig.tight_layout() +plt.show() +``` + +对于 $\sigma = 0$,扭曲恒等于零,因为个体完全信任模型。 + +对于 $\sigma < 0$,稳健个体的决策受到一个非零的最坏情形扭曲的塑造,该扭曲反馈到状态上,正是通过 {eq}`eq:hst_mpr` 抬高风险市场价格的机制。 + +## 练习 + +```{exercise} +:label: hst_ex1 + +高斯公式 {eq}`eq:hst_R_gauss` 表明,对于 $U_{t+1} \sim N(\mu, s^2)$, + +$$ +\mathcal{R}_t(U_{t+1}) = \mu + \frac{\sigma}{4} s^2 . +$$ + +请直接从定义 {eq}`eq:hst_R` 推导这一结果。 + +*提示:* 使用正态随机变量的矩生成函数,$\mathbb{E}[\exp(a U)] = \exp(a\mu + a^2 s^2 / 2)$。 +``` + +```{solution-start} hst_ex1 +:class: dropdown +``` + +这里是一个解法: + +从取 $a = \sigma/2$ 的定义出发: + +$$ +\mathcal{R}_t(U_{t+1}) = \frac{2}{\sigma} \log \mathbb{E}\!\left[\exp\!\left(\frac{\sigma}{2} U_{t+1}\right)\right]. +$$ + +由于 $U_{t+1} \sim N(\mu, s^2)$,矩生成函数给出 + +$$ +\mathbb{E}\!\left[\exp\!\left(\frac{\sigma}{2} U_{t+1}\right)\right] += \exp\!\left(\frac{\sigma}{2}\mu + \frac{1}{2}\frac{\sigma^2}{4} s^2\right). +$$ + +取对数并乘以 $2/\sigma$, + +$$ +\mathcal{R}_t(U_{t+1}) += \frac{2}{\sigma}\left(\frac{\sigma}{2}\mu + \frac{\sigma^2}{8} s^2\right) += \mu + \frac{\sigma}{4} s^2 . +$$ + +令 $\sigma \to 0$ 恢复 $\mathcal{R}_t(U_{t+1}) = \mu = \mathbb{E}_t U_{t+1}$,正如所预期。 + +```{solution-end} +``` + +```{exercise} +:label: hst_ex2 + +观测等价轨迹有一个左端点 $\underline{\sigma}$:使 {eq}`eq:hst_Omega_scalar` 有实数解的最负的 $\sigma$。 + +使用讲座中的代码,为 `theta2 = 0.01` 和 `theta2 = 0.02` 数值地求出 $\underline{\sigma}$,并解释为什么更大的 $\theta^2$ 会缩小 $\sigma$ 的可容许范围。 + +*提示:* 当判别式 $(\beta - 1 + \sigma\theta^2)^2 + 4\sigma\theta^2 \geq 0$(在相关的 $\hat\beta$ 处求值)时,平方根为实数。 +``` + +```{solution-start} hst_ex2 +:class: dropdown +``` + +这里是一个解法: + +边界 $\underline{\sigma}$ 是仍能找到有效 $\hat\beta$ 的最负的 $\sigma$。 + +我们向下扫描 $\sigma$,并在 `beta_hat` 不再能返回实数解时停止。 + +```{code-cell} ipython3 +def σ_underbar(θ2, Rf, grid=np.linspace(-1e-6, -5e-4, 5000)): + last_ok = 0.0 + for sg in grid: + try: + b = β_hat(sg, θ2, Rf) + if np.isnan(Ω_scalar(b, sg, θ2)): + break + last_ok = sg + except ValueError: + break + return last_ok + +for θ2 in [0.01, 0.02]: + sb = σ_underbar(θ2, Rf) + print(f"θ2 = {θ2}: σ_underbar ≈ {sb:.3e}") +``` + +更大的 $\theta^2$ 意味着边际效用鞅 {eq}`eq:hst_mu_rw` 携带更大的新息方差,因此每单位 $|\sigma|$ 产生更大的风险调整。 + +{eq}`eq:hst_Omega_scalar` 中的判别式包含 $4\sigma\theta^2 < 0$ 这一项,会在*较小*的 $|\sigma|$ 处变为负值。 + +因此可容许范围 $(\underline{\sigma}, 0)$ 随 $\theta^2$ 增大而缩小。 + +```{solution-end} +``` + +```{exercise} +:label: hst_ex3 + +风险市场价格近似 {eq}`eq:hst_mpr` 表明 +$\operatorname{std}_t(m^u_{t+1,t}) = [\exp(\hat v_t^\top \hat v_t) - 1]^{1/2} \approx |\hat v_t|$。 + +对于讲座中求解的风险敏感调节者(其中 $A$、$B$、$C$、$Q$、$R$、$\beta$ 如那里给定),计算*精确*的风险市场价格 $[\exp(\hat v_t^\top \hat v_t) - 1]^{1/2}$ 作为 $\sigma$ 的函数,在状态 $x = (1, 1)^\top$ 处求值,并将其与线性近似 $|\hat v_t|$ 一起绘制。 + +评论该近似准确的 $\sigma$ 范围。 +``` + +```{solution-start} hst_ex3 +:class: dropdown +``` + +这里是一个解法: + +我们为一组 $\sigma$ 值求解调节者,在 $x = (1,1)^\top$ 处求值 $\hat v_t = G x$,并比较精确的和近似的风险市场价格。 + +```{code-cell} ipython3 +x_eval = np.array([1.0, 1.0]) +σ_grid = np.linspace(-1.0, 0.0, 80) + +exact, approx = [], [] +for σ in σ_grid: + F, Ω, Acl, G = solve_rslq(A, B, C, Q, R, β, σ) + v_hat = (G @ x_eval).flatten() + nv2 = v_hat @ v_hat + exact.append(np.sqrt(np.exp(nv2) - 1)) + approx.append(np.sqrt(nv2)) # |v_hat| + +fig, ax = plt.subplots() +ax.plot(σ_grid, exact, lw=2, + label=r'精确 $[\exp(\hat v^\top \hat v)-1]^{1/2}$') +ax.plot(σ_grid, approx, lw=2, ls='--', label=r'近似 $|\hat v|$') +ax.set_xlabel(r'风险敏感性 $\sigma$') +ax.set_ylabel('风险的市场价格') +ax.legend() +fig.tight_layout() +plt.show() +``` + +对于小的 $|\hat v_t|$(即 $\sigma$ 接近零),这两条曲线几乎无法区分,因为当 $z$ 小时 $\exp(z) - 1 \approx z$。 + +它们只在对稳健性的偏好、因而最坏情形扭曲变大时才分离。 + +这正是 {cite:t}`HST_1999` 所强调的情形:*微小*的、难以检测的扭曲几乎线性地映射到风险的市场价格。 + +```{solution-end} +``` + +## 相关讲座 + +本讲座与 QuantEcon 系列中的其他几篇讲座相关联。 + +底层的消费平滑经济学在 {doc}`perm_income` 和 {doc}`perm_income_cons` 中发展,而线性二次型控制机制在 {doc}`lqcontrol` 中阐述。 + +将风险的市场价格重新诠释为*模型不确定性的价格*、并通过检测误差概率进行校准,是 {cite:t}`BHS_2009` 的主题;对稳健性、定价和模型检测的更广泛的半群处理在 {cite:t}`AHS_2003` 中。 + +两者都直接建立在 {cite:t}`HST_1999` 之上。 \ No newline at end of file diff --git a/lectures/ross_recovery.md b/lectures/ross_recovery.md new file mode 100644 index 0000000..2b9a177 --- /dev/null +++ b/lectures/ross_recovery.md @@ -0,0 +1,1228 @@ +--- +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 +translation: + title: 恢复定理 + headings: + Overview: 概述 + Model setup: 模型设置 + Model setup::Arrow–Debreu state prices: 阿罗-德布鲁状态价格 + Model setup::The pricing kernel: 定价核 + Model setup::The identification challenge: 识别挑战 + Model setup::Transition independence: 转移独立性 + The recovery theorem: 恢复定理 + The recovery theorem::Reduction to an eigenvalue problem: 化归为特征值问题 + The recovery theorem::Ross's recovery theorem: 罗斯的恢复定理 + The recovery theorem::Pricing kernel from the eigenvector: 从特征向量得到定价核 + The recovery theorem::Single crossing and the risk premium: 单交叉与风险溢价 + Numerical example: 数值示例 + Numerical example::Building a finite-state example: 构建一个有限状态示例 + Numerical example::Applying the recovery theorem: 应用恢复定理 + Natural vs. risk-neutral distributions: 自然分布与风险中性分布 + Effect of risk aversion: 风险厌恶的影响 + Recovering the discount rate: 恢复贴现率 + 'Tail risk: natural vs. risk-neutral probabilities of catastrophe': 尾部风险:灾难的自然概率与风险中性概率 + From option prices to transition prices: 从期权价格到转移价格 + Testing efficient markets: 检验有效市场 + Limitations and extensions: 局限性与扩展 + Exercises: 练习 +--- + +(ross_recovery)= +```{raw} jupyter + +``` + +# 恢复定理 + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +资产价格具有前瞻性:它们编码了投资者对未来经济状态的预期以及他们对不同风险的估值。 + +金融领域一个长期存在的问题是:能否仅从观察到的资产价格中*恢复*出投资者所使用的概率分布——即他们的主观信念。 + +期权价格揭示了**状态价格**;一旦这些价格被无风险贴现因子标准化,所得到的概率就是资产价格在纳入风险调整后所隐含的**风险中性概率**。 + +这些并不是投资者实际赋予未来世界状态的**自然概率**。 + +两者之所以不同,是因为风险中性概率将两个不同的对象混合在了一起:市场对未来的真实信念,以及投资者对风险的厌恶。 + +它们之间的联系是**定价核**,它对自然概率进行重新加权以得出状态价格。 + +将信念与风险厌恶分离,传统上需要对代表性投资者的偏好做出参数化假设。 + +{cite:t}`Ross2015` 表明情况并非如此。 + +罗斯的定理指出,在一个有限状态马尔可夫经济中,状态价格就足够了。 + +假设阿罗-德布鲁状态价格转移矩阵是无套利且不可约的。 + +如果定价核还满足一个称为**转移独立性**的结构性约束,那么状态价格就能唯一确定自然概率转移矩阵和转移定价核。 + +如果关于定价核结构的某些假设成立,那么就不需要历史收益数据或假设的效用函数。 + +这就是**恢复定理**。 + +它有几个重要的含义: + +* 它展示了当假设成立时,状态价格转移数据如何能够识别市场的前瞻性自然分布 +* 它提供了对有效市场假说的检验。 +* 它揭示了金融领域的"暗物质":市场价格中所蕴含的罕见灾难性事件的概率。 + +本讲座涵盖 + +* 将状态价格、风险中性概率、定价核和自然概率联系起来的阿罗-德布鲁框架, +* 罗斯的恢复定理及其通过佩龙-弗罗贝尼乌斯定理的证明, +* 一个从模拟的状态价格矩阵中恢复自然分布的实现,以及 +* 如何利用期权价格和前向方程来估计转移状态价格, +* 风险中性密度与恢复的自然密度之间的比较。 + +让我们导入所需的包。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from scipy.linalg import eig +from scipy.stats import norm +import matplotlib.cm as cm +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 模型设置 + +### 阿罗-德布鲁状态价格 + +考虑一个离散时间、离散状态的经济。 + +在每个日期,经济处于 $m$ 个状态 $\theta_1, \ldots, \theta_m$ 中的某一个。 + +一个**阿罗-德布鲁证券**在经济下一期处于状态 $\theta_j$ 时支付 \$1,否则不支付。 + +用 $p(\theta_i, \theta_j)$ 表示当当前状态为 $\theta_i$ 时,下一期在状态 $\theta_j$ 支付的阿罗-德布鲁证券今天的价格。 + +将这些价格收集到一个 $m \times m$ 的**状态价格转移矩阵**中 + +$$ +P = [p(\theta_i, \theta_j)]_{i,j=1}^m. +$$ + +正如在 {doc}`ge_arrow` 中所述,行和给出了状态相关的无风险贴现因子:$\sum_j p(\theta_i, \theta_j) = e^{-r(\theta_i)}$。 + +这里 $r(\theta_i)$ 是当前状态 $\theta_i$ 中的单期连续复利无风险利率。 + +更一般地,如果某资产下一期支付 $g(\theta_j)$,那么它在状态 $\theta_i$ 中的价格为 + +$$ +p_g(\theta_i) + = \sum_j p(\theta_i, \theta_j) g(\theta_j). +$$ + +令 + +$$ +b(\theta_i) \equiv \sum_j p(\theta_i, \theta_j) = e^{-r(\theta_i)} +$$ + +为状态 $\theta_i$ 中单期无风险债券的价格。 + +用这个债券价格标准化阿罗价格,得到**风险中性转移概率** + +$$ +q^*(\theta_i, \theta_j) + = \frac{p(\theta_i, \theta_j)}{b(\theta_i)} + = e^{r(\theta_i)} p(\theta_i, \theta_j). +$$ + +因此,同样的资产价格可以写成 + +$$ +p_g(\theta_i) + = b(\theta_i) \sum_j q^*(\theta_i, \theta_j) g(\theta_j) + = e^{-r(\theta_i)} E_i^*[g(\theta_{t+1})]. +$$ + +这里 $E_i^*$ 表示在 $q^*(\theta_i,\cdot)$ 下的条件期望。 + +星号标记风险中性测度,或称鞅测度。 + +将这个单期标准化与动态转移结构分开是有用的。 + +如果 $Q(\theta_i,\theta_j,T)$ 表示在 $T$ 期内从 $\theta_i$ 转移到 $\theta_j$ 的风险中性概率,且 $0 0$),并且 $F$ 必须具有非负项。 + +佩龙-弗罗贝尼乌斯定理保证恰好存在一个这样的对。 + +```{prf:theorem} 佩龙-弗罗贝尼乌斯 +:label: thm-perron-frobenius + +如果 $A$ 是一个非负不可约矩阵,那么 + +1. $A$ 有一个等于其谱半径的正实特征值 $r$(佩龙根)。 +2. 存在一个严格正的特征向量 $z \gg 0$,满足 $Az = rz$,在缩放意义下唯一。 +3. 没有其他特征向量是严格正的。 +``` + +当矩阵是非本原的时,其他特征值可以具有相同的模,但严格正的特征向量在缩放意义下是唯一的。 + +详见 {cite:t}`Sargent_Stachurski_2024` 的第1.2.3节。 + +另见 {doc}`intro:eigen_II` 中的完整陈述。 + +应用于恢复问题:佩龙根是 $\beta$(主观贴现因子),而佩龙向量 $z$ 通过 $D_{ii} = 1/z_i$ 确定 $D$。 + + +### 罗斯的恢复定理 + +定理中的三个假设各自承担着特定的角色。 + +假设阿罗-德布鲁状态价格已被识别,无套利保证 $P$ 具有非负项,并且状态价格编码了一个明确定义的定价测度。 + +不可约性确保经济没有被分割成互不相连的子经济——如果没有它,佩龙-弗罗贝尼乌斯定理会给出多个候选特征向量,恢复就会失效。 + +转移独立性是关键的经济约束。 + +它表明定价核可以分解为 $\beta h(\theta_j)/h(\theta_i)$,因此整个核由一个单一向量 $h$(或等价地 $z$)确定。 + +考虑到这些,恢复定理便由佩龙-弗罗贝尼乌斯定理得出。 + + +```{prf:theorem} 恢复定理 +:label: thm-ross-recovery + +假设价格不提供套利机会,状态价格转移矩阵 $P$ 是不可约的,并且定价核是转移独立的。 + +那么恢复问题存在一个正解 $(\beta, z, F)$,其中 $z$ 在标准化意义下唯一,并且所隐含的自然概率转移矩阵 $F$ 和转移定价核是唯一的。 +``` + +```{prf:proof} +因为 $P$ 是非负且不可约的,佩龙-弗罗贝尼乌斯定理给出一个唯一的正特征向量 $z \gg 0$,其正特征值 $\lambda > 0$ 满足 $Pz = \lambda z$。 + +设 + +$$ +\beta = \lambda, \qquad D_{ii} = \frac{1}{z_i}, +$$ + +自然概率转移矩阵唯一地恢复为 + +$$ +f_{ij} = \frac{1}{\beta} \frac{z_j}{z_i} \, p_{ij}. +$$ + +为确认 $F$ 是随机矩阵,注意所有项都是非负的(因为 $p_{ij} \geq 0$ 且 $z_i, z_j > 0$),并且 + +$$ +\sum_j f_{ij} += \frac{1}{\beta z_i} \sum_j z_j \, p_{ij} += \frac{[Pz]_i}{\beta z_i} += \frac{\beta z_i}{\beta z_i} = 1. +$$ + +唯一性由佩龙-弗罗贝尼乌斯特征向量的唯一性得出。 +``` + +### 从特征向量得到定价核 + +恢复的转移核值为 + +$$ +\phi(\theta_i, \theta_j) = \beta \frac{z_i}{z_j}, +\qquad h(\theta_i) = \frac{\beta}{z_i}, +$$ + +其中 $h(\theta_i) = \beta/z_i$ 由 $D_{ii} = h(\theta_i)/\beta = 1/z_i$ 得出。 + +区分**完整转移核** $\phi_{ij} = \beta z_i/z_j$(它依赖于起始状态和目标状态)和**相对核成分** $1/z_j$(它仅依赖于目标状态)是有用的。 + +罗斯的表I报告了目标状态形状 $1/z_j$,经标准化使得中间状态等于一。 + +具有高 $z_j$ 的目标状态具有*低*核值:对于固定的起始状态 $i$,核 $\beta z_i/z_j$ 随 $z_j$ 递减。 + +当 $h$ 表示边际效用且状态按消费或收益排序时,较大的 $z_j$ 对应较低的边际效用——即"好时光",它们需要较少的保险,因此每单位自然概率获得较少的定价权重。 + +同样的特征向量论证还给出一个有用的极限情形。 + +如果单期债券价格在每个当前状态中都相同,那么全一向量已经是佩龙向量,因此恢复没有需要执行的状态相关的测度变换。 + + +```{prf:corollary} +:label: cor-risk-neutral-recovery + +如果无风险利率在所有状态中都相同(对某个标量 $b$ 有 $Pe = b e$),那么与恢复一致的唯一自然分布就是风险中性(鞅)分布本身:$F = (1/b) P$。 +``` + +```{prf:proof} +当 $Pe = b e$ 时,全一向量 $e$ 是特征值为 $b$ 的佩龙特征向量。 + +由佩龙-弗罗贝尼乌斯定理的唯一性部分,$z = e$(在缩放意义下)且 $\beta = b$。 + +设 $z = e$ 得 $D = I$,因此 + +$$ +F = \frac{1}{\beta} D P D^{-1} = \frac{1}{b} P. \qquad \square +$$ +``` + +(ross-recovery-single-crossing)= +### 单交叉与风险溢价 + +罗斯还使用代表性主体公式直接比较自然密度和风险中性密度。 + +对于固定的当前状态 $\theta_i$, + +$$ +\frac{q^*(\theta_i,\theta_j)}{f(\theta_i,\theta_j)} + = e^{r(\theta_i)} \phi(\theta_i,\theta_j) + = e^{r(\theta_i)} \beta + \frac{U'(c(\theta_j))}{U'(c(\theta_i))}. +$$ (eq:rn-natural-ratio) + +如果 $U'$ 随消费递减,那么 {eq}`eq:rn-natural-ratio` 中的比率随下一期消费 $c(\theta_j)$ 递减。 + +由于 $q^*(\theta_i,\cdot)$ 和 $f(\theta_i,\cdot)$ 的积分都为一,存在一个由以下方程定义的交叉点 $v$ + +$$ +e^{r(\theta_i)} \beta U'(v) = U'(c(\theta_i)). +$$ + +在 $v$ 以下,风险中性概率超过自然概率;在 $v$ 以上,自然概率超过风险中性概率。 + +因此自然消费分布一阶随机占优于风险中性分布。 + +在一个终端消费即市场收益的单期模型中,这也给出了正的市场风险溢价。 + +设 $R$ 表示自然律下的市场收益,设 $R^*$ 表示风险中性律下的同一收益,设 $R_f$ 表示同一单期单位下的无风险收益。 + +随机占优结果可以表示为 + +$$ +R^* \sim R - Z + \epsilon, +$$ + +其中 $Z \geq 0$ 捕获风险调整所引起的向下移动,$\epsilon$ 是满足 $E[\epsilon \mid R-Z]=0$ 的残差。 + +取期望得 + +$$ +E[R] = R_f + E[Z] > R_f. +$$ + +## 数值示例 + +我们现在从数值上演示恢复定理。 + +### 构建一个有限状态示例 + +我们直接在一个有限的对数收益状态网格 $s_1, \ldots, s_m$ 上构建经济。 + +在这个网格上,我们选择三个基本要素: + +1. 一个行随机的不可约自然转移矩阵 $F$, +2. 一个主观贴现因子 $\beta = e^{-\rho T}$,以及 +3. 一个 CRRA 转移定价核 $\phi_{ij} = \beta e^{-\gamma(s_j-s_i)}$。 + +状态价格矩阵然后由以下构造 + +$$ +p_{ij} = \phi_{ij} f_{ij}. +$$ + +这意味着恢复定理的假设在构造上成立:$P$ 是非负的,$F$ 是一个马尔可夫转移矩阵,并且核是转移独立的,$z_i \propto e^{\gamma s_i}$。 + +为使示例接近罗斯的第IV节,我们选择 $F$ 具有对数正态形状的行。 + +连续基准是带有 CRRA 效用的对数正态收益: + +$$ +U(S_T) = \frac{S_T^{1-\gamma}}{1-\gamma}, +\qquad +S_T = S_0 + \exp\!\left((\mu-\tfrac{1}{2}\sigma^2)T + + \sigma \sqrt{T} \xi\right), +$$ + +其中 $\xi \sim N(0,1)$,$\mu$ 是预期增长率参数,$\sigma$ 是波动率,$T$ 是视界,$\gamma$ 是 CRRA 系数,$\rho$ 是连续复利主观贴现率。 + +$T$ 期定价核为 + +$$ +\phi_T + = e^{-\rho T}\left(\frac{S_T}{S_0}\right)^{-\gamma}. +$$ + +等价地,如果 $s=\log S_0$ 且 $s_T=\log S_T$,那么关于未来对数状态 $s_T$ 的状态价格密度为 + +$$ +p_T(s,s_T) + = e^{-\rho T} e^{-\gamma(s_T-s)} + \frac{1}{\sigma \sqrt{T}} + n\!\left( + \frac{s_T-s-(\mu-\frac{1}{2}\sigma^2)T} + {\sigma \sqrt{T}} + \right), +$$ + +其中 $n$ 是标准正态密度。 + +因此自然对数收益满足 + +$$ +\log(S_T/S_0) \sim \mathcal{N}\!\left((\mu - \tfrac{1}{2}\sigma^2)T, \sigma^2 T\right). +$$ + +遵循罗斯的表I,我们在一个有限的状态网格上表示分布。 + +这个示例受罗斯启发,而非罗斯表I的精确重现。 + +罗斯的表I使用固定的未来收益分布,因此其 $F$ 的行是相同的。 + +这里同样的 CRRA/对数正态定价逻辑被嵌入到一个有限马尔可夫转移矩阵中,其行随当前状态而移动。 + +罗斯使用从 $-5$ 到 $+5$ 个标准差的状态;我们在下面使用相同的范围。 + +截断是有限状态模型的一个基本组成部分:正是它将示例带入佩龙-弗罗贝尼乌斯设定中。 + +在无界连续对数正态增长模型中,罗斯表明恢复不是唯一的。 + +在有限网格上,自然转移概率和状态价格为 + +$$ +f_{ij} \propto + n\!\left(\frac{s_j - s_i - (\mu - \frac{1}{2}\sigma^2)T}{\sigma\sqrt{T}}\right) + \Delta s, +\qquad +p_{ij} = e^{-\rho T} e^{-\gamma(s_j - s_i)} f_{ij}, +$$ + +其中 $s_i = \ln S_i$,$s_j = \ln S_j$,$n(\cdot)$ 是标准正态密度,离散化概率 $f_{ij}$ 按行标准化。 + +下一个代码单元构造这个有限网格并构建 $P$。 + +```{code-cell} ipython3 +def build_state_price_matrix(μ, σ, γ, ρ, T=1.0, n_states=11, n_σ=5): + """构建一个离散化的对数正态/CRRA状态价格矩阵。""" + states = np.linspace(-n_σ * σ * np.sqrt(T), + n_σ * σ * np.sqrt(T), + n_states) + ds = states[1] - states[0] + + m = n_states + P = np.zeros((m, m)) + F = np.zeros((m, m)) + + drift = (μ - 0.5 * σ**2) * T + + # 首先在有界网格上构建一个行随机的自然转移矩阵 + for i in range(m): + s_i = states[i] + for j in range(m): + s_j = states[j] + log_return = s_j - s_i + F[i, j] = norm.pdf(log_return, loc=drift, + scale=σ * np.sqrt(T)) * ds + + F[i] = F[i] / F[i].sum() + + # 将每个阿罗债权定价为自然概率乘以CRRA核 + for j in range(m): + log_return = states[j] - s_i + kernel = np.exp(-ρ * T) * np.exp(-γ * log_return) + P[i, j] = kernel * F[i, j] + + return P, states +``` + +现在选择一个校准并构建状态价格矩阵。 + +```{code-cell} ipython3 +μ = 0.08 # 8%年预期收益 +σ = 0.20 # 20%年波动率 +γ = 3.0 # CRRA系数 +ρ = 0.02 # 2%年连续贴现率 +T = 1.0 # 一年视界 + +P, states = build_state_price_matrix(μ, σ, γ, ρ, T, + n_states=11, n_σ=5) + +print("State-price row sums:") +print(np.round(P.sum(axis=1), 4)) +print(f"Middle-state risk-free rate: {-np.log(P[5].sum()):.4f}") +``` + +行和是每个当前状态下模型隐含的单期债券价格。 + +它们在边界附近变化,因为有限网格截断并重新标准化了条件转移概率。 + +### 应用恢复定理 + +恢复定理要求计算 $P$ 的**佩龙特征向量**。 + +```{code-cell} ipython3 +def recover_natural_distribution(P, tol=1e-10): + """ + 从状态价格中恢复自然概率和相对定价核。 + """ + + m = P.shape[0] + + eigenvalues, eigenvectors = eig(P) + eigenvalues = np.real_if_close(eigenvalues, tol=1000) + eigenvectors = np.real_if_close(eigenvectors, tol=1000) + + # 罗斯恢复使用佩龙根及其严格正的特征向量 + real_mask = np.isreal(eigenvalues) + real_eigenvalues = np.asarray( + eigenvalues[real_mask].real, dtype=float) + real_eigenvectors = np.asarray( + eigenvectors[:, real_mask].real, dtype=float) + + order = np.argsort(real_eigenvalues)[::-1] + + for idx in order: + β_candidate = real_eigenvalues[idx] + z_candidate = real_eigenvectors[:, idx] + + if np.mean(z_candidate) < 0: + z_candidate = -z_candidate + + if β_candidate > 0 and np.all(z_candidate > tol): + β_recovered = β_candidate + z = z_candidate + break + else: + raise ValueError("No strictly positive real eigenvector found") + + z = z / z[m // 2] + + D = np.diag(1.0 / z) + D_inv = np.diag(z) + + # 将状态价格转换为概率 + F = (1.0 / β_recovered) * D @ P @ D_inv + + min_entry = F.min() + row_sum_error = np.max(np.abs(F.sum(axis=1) - 1.0)) + + if min_entry < -tol: + raise ValueError(f"Recovered F has negative entries: min={min_entry}") + + if row_sum_error > 1e-8: + raise ValueError( + f"Recovered F row sums are not one: max error={row_sum_error}" + ) + + # 相对于中间状态标准化的核 + φ_relative = 1.0 / z + + return F, z, β_recovered, φ_relative +``` + +佩龙向量还恢复了定价核的形状。 + +罗斯的表I以中间状态标准化为一的方式报告这个形状,在我们的标准化 $z_{\text{mid}}=1$ 下即为 $1/z_j$。 + +```{code-cell} ipython3 +F, z, β_rec, φ_relative = recover_natural_distribution(P) + +print("Ross-normalized kernel 1/z (middle state = 1):") +print(np.round(φ_relative, 4)) +``` + +因为我们知道用于构造 $P$ 的数据生成自然转移矩阵,所以我们可以验证恢复在此模拟中有效。 + +```{code-cell} ipython3 +def true_lognormal_transition_matrix(states, μ, σ, T): + """ + 构造模拟中使用的有界网格自然转移矩阵。 + """ + m = len(states) + ds = states[1] - states[0] + drift = (μ - 0.5 * σ**2) * T + F_true = np.zeros((m, m)) + + for i in range(m): + log_returns = states - states[i] + F_true[i] = norm.pdf(log_returns, loc=drift, + scale=σ * np.sqrt(T)) * ds + F_true[i] = F_true[i] / F_true[i].sum() + + return F_true + + +F_true = true_lognormal_transition_matrix(states, μ, σ, T) +P_reconstructed = β_rec * (z[:, None] / z[None, :]) * F + +print("Recovery numerical checks") +print(f"max |F - true F| = {np.max(np.abs(F - F_true)):.2e}") +print(f"max |P - recovered kernel times F| = " + f"{np.max(np.abs(P - P_reconstructed)):.2e}") +``` + +确实,差异处于数值舍入误差的水平。 + +## 自然分布与风险中性分布 + +{cite:t}`Ross2015` 的一个关键洞见是,自然分布可以系统性地不同于风险中性分布。 + +在这个 CRRA 示例中,状态从低收益到高收益排序,{ref}`ross-recovery-single-crossing` 中的单交叉论证意味着自然边缘密度**一阶随机占优**于风险中性密度:自然分布的累积分布函数位于风险中性分布累积分布函数的*下方*。 + +因为定价核是递减的(投资者害怕不好的结果),风险中性概率相对于自然测度过度加权坏状态而低估好状态。 + +我们首先绘制自然分布与风险中性分布以及恢复的相对定价核 + +```{code-cell} ipython3 +mid = len(states) // 2 + +row_sums = P.sum(axis=1, keepdims=True) + +# 用每个状态下的单期无风险债券价格标准化阿罗价格 +Q_rn = P / row_sums + +f_nat = F[mid, :] +f_rn = Q_rn[mid, :] + +gross_returns = np.exp(states) + +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +axes[0].plot(gross_returns, f_nat, label='自然(恢复)', lw=2) +axes[0].plot(gross_returns, f_rn, label='风险中性', lw=2) +axes[0].set_xlabel('总回报率 $S_T / S_0$') +axes[0].set_ylabel('概率') +axes[0].set_title('单期边缘分布') +axes[0].legend() + +axes[1].plot(gross_returns, φ_relative, 'g-^', lw=2) +axes[1].set_xlabel('总回报率 $S_T / S_0$') +axes[1].set_ylabel('相对核 $1/z$') +axes[1].set_title('恢复的相对定价核') +plt.show() +``` + +累积分布函数清楚地显示了一阶随机占优 + +```{code-cell} ipython3 +cdf_nat = np.cumsum(f_nat) +cdf_rn = np.cumsum(f_rn) + +fig, ax = plt.subplots(figsize=(9, 5)) +ax.plot(gross_returns, cdf_nat, lw=2, label='自然累积分布函数') +ax.plot(gross_returns, cdf_rn, lw=2, label='风险中性累积分布函数') +ax.set_xlabel('总回报率 $S_T / S_0$') +ax.set_ylabel('累积概率') +ax.legend() +plt.show() + +print(f"Natural CDF <= Risk-neutral CDF at all states: " + f"{np.all(cdf_nat <= cdf_rn + 1e-10)}") +``` + +两个累积分布函数之间的差距是由定价核的斜率产生的。 + +在 CRRA 基准中,这个斜率由风险厌恶系数 $\gamma$ 控制。 + +接下来我们变化 $\gamma$ 以观察恢复的核和自然/风险中性楔子如何变化。 + +## 风险厌恶的影响 + +定价核的形状,以及由此产生的自然概率与风险中性概率之间的差距,取决于风险厌恶系数 $\gamma$。 + +我们通过绘制相对定价核 $1/z$ 以及自然密度和风险中性密度之间的差距(对于一系列 $\gamma$ 值)来说明这一点。 + +```{code-cell} ipython3 +γs = [1.0, 2.0, 3.0, 5.0, 8.0] +colors = cm.viridis(np.linspace(0.1, 0.9, len(γs))) + +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +for γ_val, color in zip(γs, colors): + P_g, states_g = build_state_price_matrix(μ, σ, γ_val, ρ, T) + F_g, z_g, β_g, φ_relative_g = recover_natural_distribution(P_g) + mid_g = len(states_g) // 2 + + f_nat_g = F_g[mid_g, :] + row_sum = P_g[mid_g].sum() + f_rn_g = P_g[mid_g] / row_sum + + gross = np.exp(states_g) + + axes[0].plot(gross, φ_relative_g, color=color, lw=2, + label=f'$\\gamma={γ_val:.0f}$') + axes[1].plot(gross, f_nat_g - f_rn_g, color=color, lw=2, + label=f'$\\gamma={γ_val:.0f}$') + +axes[0].set_xlabel('总回报率') +axes[0].set_ylabel('相对核 $1/z$') +axes[0].set_title('相对定价核与风险厌恶') +axes[0].legend(fontsize=9) + +axes[1].axhline(0, color='k', lw=0.8, ls='--') +axes[1].set_xlabel('总回报率') +axes[1].set_ylabel('自然减风险中性概率') +axes[1].set_title('自然减风险中性密度') +axes[1].legend(fontsize=9) + +plt.show() +``` + +因为状态从低收益到高收益排序,这些图显示了 {ref}`ross-recovery-single-crossing` 中讨论的单交叉性质:对于低于某个阈值 $v$ 的收益,风险中性概率超过自然概率;在 $v$ 以上,自然概率占优。 + +较高的 $\gamma$ 放大了这个楔子。 + +## 恢复贴现率 + +恢复定理的一个有用副产品是*恢复的主观贴现因子* $\beta$,它等于 $P$ 的佩龙-弗罗贝尼乌斯特征值。 + +如果视界为 $T$,则对应的连续复利主观贴现率为 + +$$ +\rho = -\frac{\log \beta}{T}. +$$ + +在下面的数值示例中,$T=1$,因此这简化为 $\rho = -\log \beta$。 + +{cite:t}`Ross2015` 的推论1指出,$\beta$ 的上界是最大的状态相关单期贴现因子——等价地,是 $P$ 的最大行和: + +$$ +\beta \leq \max_i \sum_j p(\theta_i, \theta_j). +$$ + +在网格上扫描真实的 $\rho$ 并报告恢复值以及恢复误差,确认了特征值计算准确地确定了 $\beta$: + +```{code-cell} ipython3 +true_ρs = np.linspace(0.00, 0.06, 13) +recovered_ρs = np.empty_like(true_ρs) + +for k, rho in enumerate(true_ρs): + P_d, _ = build_state_price_matrix(μ, σ, γ=3.0, ρ=rho, T=1.0) + _, _, β_d, _ = recover_natural_distribution(P_d) + recovered_ρs[k] = -np.log(β_d) + +print( + f"max |true ρ - recovered ρ| = {np.max(np.abs(true_ρs - recovered_ρs)):.2e}") +np.column_stack([true_ρs, recovered_ρs]) +``` + +## 尾部风险:灾难的自然概率与风险中性概率 + +恢复定理最引人注目的应用之一是它能够将市场恢复的灾难自然概率与附加于这些灾难的风险溢价分离开来。 + +{cite:t}`barro2006rare` 和 {cite:t}`MehraPrescott1985` 讨论了罕见灾难如何可能解释股权溢价之谜。 + +大幅下跌的风险中性概率之所以升高,既是因为(a)市场对此类事件赋予了高的自然概率,也是因为(b)定价核上调了坏结果的权重。 + +罗斯的恢复机制让我们能够分解这两种力量。 + +下一个代码单元绘制从中间状态出发,在恢复的自然测度和风险中性测度下的左尾概率,因此曲线之间的差距分离出了定价核对崩盘概率的贡献。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 恢复的自然测度和风险中性测度下的尾部概率 + name: fig-tail-probs +--- +thresholds = np.linspace(-0.40, 0.10, 200) + +def tail_prob(f_dist, states, threshold): + """对数收益的左尾概率。""" + return float(np.sum(f_dist[states <= threshold])) + +P_base, states_base = build_state_price_matrix( + μ, σ, γ=3.0, ρ=0.02, T=1.0, + n_states=41, n_σ=5) +F_base, z_base, β_base, φ_relative_base = recover_natural_distribution(P_base) + +mid_b = len(states_base) // 2 +f_nat_base = F_base[mid_b] +f_rn_base = P_base[mid_b] / P_base[mid_b].sum() + +prob_nat = [tail_prob(f_nat_base, states_base, t) for t in thresholds] +prob_rn = [tail_prob(f_rn_base, states_base, t) for t in thresholds] + +fig, ax = plt.subplots(figsize=(10, 5)) +ax.plot(np.exp(thresholds), prob_nat, lw=2, label='自然(恢复)') +ax.plot(np.exp(thresholds), prob_rn, lw=2, label='风险中性') +ax.set_xlabel('总回报率阈值') +ax.set_ylabel('低于阈值下跌的概率') +ax.axvline(x=0.75, color='gray', ls=':', lw=1.5, label='25%下跌') +ax.axvline(x=0.70, color='silver', ls=':', lw=1.5, label='30%下跌') +ax.legend() +plt.show() +``` + +这是一个说明罗斯分解的模拟。 + +风险中性密度对大幅下跌赋予的概率高于恢复的自然密度。 + +在这个 CRRA 模拟中,增加风险厌恶会使风险中性崩盘概率比恢复的自然崩盘概率上升得更快。 + +我们将在 {ref}`rt_ex3` 中进行更多说明。 + +## 从期权价格到转移价格 + +上面的数值示例从一个已知的状态价格转移矩阵 $P$ 开始。 + +在经验上,罗斯从更早一步开始:期权价格揭示了从当前状态出发在不同到期日的状态价格密度,而转移矩阵必须从这些逐个到期日的状态价格中推断出来。 + +设 $C(K,T)$ 为行权价为 $K$、到期日为 $T$ 的看涨期权的价格。 + +如果 $p(S,T)$ 是终端指数水平 $S$ 的状态价格密度,那么 + +$$ +C(K,T) + = \int_K^\infty (S-K) p(S,T) \, dS. +$$ + +对行权价求两次微分给出 {cite:t}`BreedenLitzenberger1978` 公式 + +$$ +p(K,T) = \frac{\partial^2 C(K,T)}{\partial K^2}. +$$ + +在对行权价和到期日进行离散化后,设 + +$$ +p_t(c) = \big(p_t(c,1), \ldots, p_t(c,m)\big) +$$ + +为从今天状态 $c$ 观察到的视界 $t$ 处的状态价格向量。 + +这里 $c$ 索引当前状态,$t$ 计数离散到期步数。 + +第一个单期向量 $p_1(c)$ 识别对应于当前状态 $c$ 的 $P$ 的行,提供 $m$ 个方程。 + +如果单期状态价格转移矩阵 $P$ 是时间齐次的,那么这些向量满足前向递归 + +$$ +p_{t+1}(c) = p_t(c) P, +\qquad t=1,\ldots,m-1. +$$ + +按分量表示, + +$$ +p_{t+1}(c,j) = \sum_k p_t(c,k) p(k,j). +$$ + +其余 $m-1$ 个前向方程 $p_{t+1}(c)=p_t(c)P$,每个有 $m$ 个分量,提供其余的 $m(m-1)$ 个方程。 + +这些方程合在一起为 $m^2$ 个转移价格 $p(k,j)$ 给出 $m^2$ 个方程。 + +在实践中,这一步在数值上很微妙,因为期权价格公式中的二阶导数会放大测量误差,并且可能需要正性或单峰性等额外的形状约束来获得一个合理的转移矩阵。 + +## 检验有效市场 + +在恢复定理的假设下,恢复的定价核也可以用来检验市场有效性。 + +如果一个交易策略有非常高的夏普比率,那么某个定价核必须足够波动才能对该收益定价。 + +汉森-贾格纳坦界 {cite}`Hansen_Jagannathan_1991` 指出,对于任何均值为 $\mu_\text{excess}$、标准差为 $\sigma_\text{asset}$ 的超额收益, + +$$ +\frac{|\mu_\text{excess}|}{\sigma_\text{asset}} \leq e^{rT}\, \sigma(M), +$$ + +其中 $M$ 是单期随机贴现因子,$r$ 是视界 $T$ 上的连续复利无风险利率。 + +罗斯的观点是,恢复给出了相关波动率 $\sigma(M)$ 的估计。 + +因此它给出了基于恢复中使用的相同股市信息的任何策略的夏普比率的上界。 + +如果这样的策略的夏普比率高于该界限,那么在恢复定理的假设下,它就过于盈利而无法与有效性一致。 + +同样的逻辑给出了收益可预测性的界限。 + +假设超额收益分解为 + +$$ +x_{t+1} = \mu(I_t) + \epsilon_{t+1}, +$$ + +其中 $I_t$ 是股市信息集,$\epsilon_{t+1}$ 从 $I_t$ 无法预测。 + +那么基于 $I_t$ 的预测回归的 $R^2$ 上界为恢复核的方差: + +$$ +R^2 \leq e^{2rT} \, \sigma^2(M). +$$ + +只有投影到这个信息集上的核成分是相关的。 + +向候选定价核添加不相关的噪声会提高其方差,但不会为来自股市信息的更强收益可预测性提供依据。 + +## 局限性与扩展 + +恢复定理是一个了不起的理论结果,但在实践中有几个需要注意的地方。 + +*有限状态空间:* + +罗斯的定理是针对有限状态不可约马尔可夫链证明的;有界连续状态恢复需要 {doc}`misspecified_recovery` 中的额外结果。 + +在连续、无界的状态空间中(例如对数正态扩散),唯一性失效,因为任何指数 $e^{\alpha x}$ 都满足特征方程。 + +为看清这个问题,考虑上面的连续对数正态增长状态价格密度。 + +佩龙-弗罗贝尼乌斯问题的自然连续空间类比是 + +$$ +\int p_T(s,y) v(y) \, dy = \lambda v(s). +$$ + +这里 $y$ 是一个可能的未来对数状态,$v$ 是一个候选正特征函数,$\lambda$ 是它的特征值。 + +对于每个实数 $\alpha$,指数函数 $v_\alpha(s)=e^{\alpha s}$ 求解这个方程,特征值为 + +$$ +\lambda(\alpha) + = + \exp\!\left( + -\rho T + +(\alpha-\gamma)(\mu-\tfrac{1}{2}\sigma^2)T + +\tfrac{1}{2}\sigma^2T(\alpha-\gamma)^2 + \right). +$$ + +因此正特征函数不是唯一的。 + +这就是为什么截断或有界性假设很重要:它们把连续算子问题重新变回一个具有唯一正特征向量的佩龙-弗罗贝尼乌斯问题。 + +{cite:t}`CarrYu2012` 用有界扩散建立了恢复。 + +*转移独立性:* + +如果核不是转移独立的,恢复不能保证。 + +{cite:t}`BorovickaHansenScheinkman2016` 表明罗斯恢复可能将核的长期风险成分与自然概率分布混淆,从而产生错误的分解。 + +我们在后续讲座 {doc}`misspecified_recovery` 中讨论这一点。 + +*经验估计:* + +从观察到的期权价格中提取可靠的状态价格需要仔细的插值和外推。 + +通过 {cite:t}`BreedenLitzenberger1978` 公式从隐含波动率到状态价格的映射涉及二阶导数,这会放大测量误差。 + +## 练习 + +```{exercise} +:label: rt_ex1 + +**佩龙-弗罗贝尼乌斯向量与定价核。** + +考虑 $3 \times 3$ 状态价格矩阵 + +$$ +P = \begin{pmatrix} +0.5950 & 0.1700 & 0.0272 \\ +0.159375 & 0.5525 & 0.1360 \\ +0.06640625 & 0.31875 & 0.5525 +\end{pmatrix}. +$$ + +1. 计算 $P$ 的佩龙特征值 $\beta$ 和对应的特征向量 $z$。 + +2. 使用 $z$ 通过以下方式恢复自然概率转移矩阵 $F$ + +$$ +f_{ij} = \frac{1}{\beta} \frac{z_j}{z_i} p_{ij}. +$$ + +3. 验证 $F$ 的每一行和为一且所有项均为正。 + +4. 对于目标状态 $j$,相对核成分为 $1/z_j$;对于从状态 $i$ 到状态 $j$ 的转移,完整定价核为 $\beta z_i/z_j$。计算每个状态的 $1/z_j$。 + +当我们从状态1移动到状态3(即从坏状态到好状态)时,核是否递减? +``` + +```{solution-start} rt_ex1 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +P_ex = np.array([ + [0.5950, 0.1700, 0.0272], + [0.159375, 0.5525, 0.1360], + [0.06640625, 0.31875, 0.5525] +]) + +eigenvalues, eigenvectors = eig(P_ex) +real_mask = np.isreal(eigenvalues) +real_ev = eigenvalues[real_mask].real +real_evec = eigenvectors[:, real_mask].real + +idx = np.argmax(real_ev) +β_ex = real_ev[idx] +z_ex = real_evec[:, idx] +if z_ex.min() < 0: + z_ex = -z_ex +z_ex = z_ex / z_ex[1] + +print(f"β = {β_ex:.6f}") +print(f"z = {z_ex}") + +D_ex = np.diag(1.0 / z_ex) +D_inv_ex = np.diag(z_ex) +F_ex = (1.0 / β_ex) * D_ex @ P_ex @ D_inv_ex + +print("\nRecovered F:") +print(np.round(F_ex, 4)) + +print(f"\nRow sums: {np.round(F_ex.sum(axis=1), 8)}") +print(f"Nonnegative: {(F_ex >= -1e-10).all()}") + +φ_relative_ex = 1.0 / z_ex +print(f"\nrelative kernel 1/z = {np.round(φ_relative_ex, 4)}") +print(f"Decreasing: {φ_relative_ex[0] > φ_relative_ex[1] > φ_relative_ex[2]}") +``` + +```{solution-end} +``` + +```{exercise} +:label: rt_ex2 + +**随机占优。** + +使用上面练习中恢复的 $F$ 和标准化的风险中性矩阵 $Q = P / \text{行和}$: + +1. 从状态2(Python 中索引1)出发,计算单步边缘分布 $f_j = F_{2,j}$ 和 $q_j = Q_{2,j}$。 + +2. 为每个状态计算累积分布函数 $\hat F_k = \sum_{j \leq k} f_j$ 和 $\hat Q_k = \sum_{j \leq k} q_j$。 + +3. 数值验证对于每个 $k$ 都有 $\hat F_k \leq \hat Q_k$,确认这个有序三状态示例中的随机占优。 +``` + +```{solution-start} rt_ex2 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +eigenvalues, eigenvectors = eig(P_ex) +real_mask = np.isreal(eigenvalues) +real_ev = eigenvalues[real_mask].real +real_evec = eigenvectors[:, real_mask].real +idx = np.argmax(real_ev) +β_ex = real_ev[idx] +z_ex = real_evec[:, idx] +if z_ex.min() < 0: + z_ex = -z_ex +z_ex = z_ex / z_ex[1] + +D_ex = np.diag(1.0 / z_ex) +D_inv_ex = np.diag(z_ex) +F_ex = (1.0 / β_ex) * D_ex @ P_ex @ D_inv_ex + +start = 1 +f_marg = F_ex[start] +q_marg = P_ex[start] / P_ex[start].sum() + +print("One-step marginals from state 2:") +print(f"natural = {np.round(f_marg, 4)}") +print(f"risk-neutral = {np.round(q_marg, 4)}") + +cdf_nat = np.cumsum(f_marg) +cdf_rn = np.cumsum(q_marg) + +print("\nCDFs:") +for k in range(3): + print(f"state {k+1}: natural = {cdf_nat[k]:.4f}, risk-neutral = {cdf_rn[k]:.4f}") + +dominates = np.all(cdf_nat <= cdf_rn + 1e-10) +print(f"\nNatural CDF <= risk-neutral CDF: {dominates}") +``` + +```{solution-end} +``` + +```{exercise} +:label: rt_ex3 + +**风险厌恶与尾部风险。** + +编写一个函数 `tail_risk_ratio(γ, threshold, μ, σ, ρ, T)`,它: + +1. 使用 `build_state_price_matrix` 以给定参数和 `n_states=41` 构造状态价格矩阵 $P$。 +2. 应用 `recover_natural_distribution` 以获得 $F$。 +3. 从中间状态出发,计算在自然分布和风险中性分布下的 $P(\text{对数收益} \leq \text{阈值})$。 +4. 返回比率 $p_\text{risk-neutral} / p_\text{natural}$。 + +使用这个函数,对于30%的简单下跌,即 `threshold = np.log(0.70)`,绘制比率作为 $\gamma \in [1, 10]$ 的函数。 + +解释经济含义:为什么较高的 $\gamma$ 会提高这个比率? +``` + +```{solution-start} rt_ex3 +:class: dropdown +``` + +这是一个解法: + +```{code-cell} ipython3 +def tail_risk_ratio(γ, threshold, μ=0.08, σ=0.20, ρ=0.02, T=1.0): + """风险中性/自然左尾概率。""" + P_g, states_g = build_state_price_matrix( + μ, σ, γ, ρ, T, n_states=41, n_σ=5) + + F_g, _, _, _ = recover_natural_distribution(P_g) + + mid_g = len(states_g) // 2 + + f_nat_g = F_g[mid_g] + f_rn_g = P_g[mid_g] / P_g[mid_g].sum() + + p_nat = float(np.sum(f_nat_g[states_g <= threshold])) + p_rn = float(np.sum(f_rn_g[states_g <= threshold])) + + if p_nat < 1e-12: + return np.nan + return p_rn / p_nat + + +γs = np.linspace(1.0, 10.0, 20) +threshold_30 = np.log(0.70) +ratios = [tail_risk_ratio(g, threshold_30) for g in γs] + +plt.figure(figsize=(9, 5)) +plt.plot(γs, ratios, '-o', ms=5, lw=2) +plt.xlabel('风险厌恶系数 $\\gamma$') +plt.ylabel('风险中性/自然尾部概率') +plt.title('30%下跌的尾部风险比率与风险厌恶') +plt.show() +``` + +较高的风险厌恶系数 $\gamma$ 使定价核更陡峭:市场对坏状态收益每单位概率赋予更大的溢价。 + +风险中性概率纳入了这个溢价,因此在这个 CRRA 模拟中,风险中性崩盘概率随 $\gamma$ 上升得比恢复的自然崩盘概率更快。 + +恢复将市场估计的自然崩盘概率与附加于崩盘状态的定价核溢价分离开来。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/rs_inventory_q.md b/lectures/rs_inventory_q.md new file mode 100644 index 0000000..12463eb --- /dev/null +++ b/lectures/rs_inventory_q.md @@ -0,0 +1,750 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.18.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 通过 Q-Learning 进行风险敏感型库存管理 + headings: + Introduction: 引言 + The Model: 模型 + Solving via Value Function Iteration: 通过值函数迭代求解 + Solving via Value Function Iteration::Model specification: 模型设定 + Solving via Value Function Iteration::The Bellman operator: 贝尔曼算子 + Solving via Value Function Iteration::Computing the greedy policy: 计算贪婪策略 + Solving via Value Function Iteration::Value function iteration: 值函数迭代 + Solving via Value Function Iteration::Creating and solving an instance: 创建并求解一个实例 + Solving via Value Function Iteration::Effect of risk sensitivity on the optimal policy: 风险敏感性对最优策略的影响 + Solving via Value Function Iteration::Simulating the optimal policy: 模拟最优策略 + Interpreting the Outcomes: 解读结果 + Q-Learning: Q-Learning + Q-Learning::The Q-factor: Q 因子 + Q-Learning::Deriving the Q-factor Bellman equation: 推导 Q 因子贝尔曼方程 + Q-Learning::The Q-learning update rule: Q-learning 更新规则 + Q-Learning::Implementation plan: 实现方案 + Q-Learning::Optimistic initialization: 乐观初始化 + Q-Learning::Implementation: 实现 + Q-Learning::Running Q-learning: 运行 Q-learning + Q-Learning::Comparing with the exact solution: 与精确解进行比较 + Q-Learning::Visualizing learning over time: 可视化学习随时间的演变 + Conclusion: 结论 +--- + +(rs_inventory_q)= +```{raw} jupyter + +``` + +# 通过 Q-Learning 进行风险敏感型库存管理 + +```{contents} Contents +:depth: 2 +``` + +## 引言 + +在 {doc}`inventory_q` 中,我们研究了一个库存管理问题,并用值函数迭代和 Q-learning 两种方法进行了求解。 + +在本讲中,我们考虑一个风险敏感的变体。 + +引入风险敏感性反映了这样一个事实:在存在金融和信息摩擦的不完全市场中,企业在决策时通常会考虑风险。 + +换句话说,企业的行为一般来说并非风险中性的。 + +处理这一问题的一个自然方法是使用贝尔曼方程的风险敏感版本。 + +我们将展示如何用值函数迭代来求解该模型。 + +然后,我们研究风险敏感性如何影响最优策略。 + + + +```{code-cell} ipython3 +import numpy as np +import numba +import matplotlib.pyplot as plt +from typing import NamedTuple +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + + +## 模型 + +{doc}`inventory_q` 中库存管理问题的贝尔曼方程具有如下形式 + + +$$ + v(x) + = \max_{a \in \Gamma(x)} \mathbb E + \left[ + \pi(x, a, D) + + \beta v(h(x, a, D)) + \right]. +$$ + +这里 $D$ 是一个服从分布 $\phi$ 的随机变量。 + +(基本要素和定义与 {doc}`inventory_q` 相同。) + +该贝尔曼方程的风险敏感版本具有如下形式 + +$$ + v(x) + = \max_{a \in \Gamma(x)} + \psi^{-1} + \left\{ + \mathbb E \psi + \left[ + \pi(x, a, D) + + \beta v(h(x, a, D)) + \right] + \right\}, +$$ + +其中对于固定的 $\gamma > 0$,$\psi(t) = \exp(-\gamma t)$。 + +由于 $\psi^{-1}(y) = -\frac{1}{\gamma} \ln(y)$,贝尔曼方程变为 + +$$ + v(x) + = \max_{a \in \Gamma(x)} + \left( + -\frac{1}{\gamma} + \right) + \ln + \left\{ + \sum_d \phi(d) \exp + \left[ + -\gamma \left( \pi(x, a, d) + \beta \, v(h(x, a, d)) \right) + \right] + \right\}. +$$ + +这里 $\phi(d)$ 表示需求的概率质量函数,与 {doc}`inventory_q` 中相同。 + +参数 $\gamma$ 控制风险敏感性的程度。 + +当 $\gamma \to 0$ 时,确定性等价物退化为普通的期望,我们便恢复了风险中性的情形。 + +$\gamma$ 越大,意味着对下行风险的厌恶程度越高。 + +贝尔曼算子、贪婪策略和 VFI 算法都可以从风险中性的情形沿用过来,只需将期望替换为确定性等价物。 + + + +## 通过值函数迭代求解 + +### 模型设定 + +我们重用与 {doc}`inventory_q` 相同的模型基本要素,并加入 $\gamma$ 作为一个参数。 + +```{code-cell} ipython3 +class RSModel(NamedTuple): + x_values: np.ndarray # 库存值 + d_values: np.ndarray # 用于求和的需求值 + ϕ_values: np.ndarray # 需求概率 + p: float # 需求参数 + c: float # 单位成本 + κ: float # 固定成本 + β: float # 贴现因子 + γ: float # 风险敏感性参数 +``` + +```{code-cell} ipython3 +def create_rs_inventory_model( + K: int = 20, # 最大库存 + D_MAX: int = 21, # 用于求和的需求上界 + p: float = 0.7, + c: float = 0.2, + κ: float = 0.8, + β: float = 0.98, + γ: float = 1.0 + ) -> RSModel: + + def demand_pdf(p, d): + return (1 - p)**d * p + + d_values = np.arange(D_MAX) + ϕ_values = demand_pdf(p, d_values) + x_values = np.arange(K + 1) + + return RSModel(x_values, d_values, ϕ_values, p, c, κ, β, γ) +``` + +### 贝尔曼算子 + +风险敏感的贝尔曼算子用确定性等价物替换了期望值。 + +为了数值稳定性,我们使用 [log-sum-exp 技巧](https://en.wikipedia.org/wiki/LogSumExp):给定值 $z_i = \pi(x, a, d_i) + \beta \, v(h(x, a, d_i))$,我们计算 + +$$ + -\frac{1}{\gamma} \ln \sum_i \phi(d_i) \exp(-\gamma z_i) + \;=\; + -\frac{1}{\gamma} + \left( + m + \ln \sum_i \phi(d_i) \exp(-\gamma z_i - m) + \right), +$$ + +其中 $m = \max_i (-\gamma z_i)$。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def T_rs_kernel(v, d_values, ϕ_values, c, κ, β, γ, K): + new_v = np.empty(K + 1) + n_d = len(d_values) + for x in range(K + 1): + best = -np.inf + for a in range(K - x + 1): + # 为每个需求实现计算 -γ * z_i + exponents = np.empty(n_d) + for i in range(n_d): + d = d_values[i] + x_next = max(x - d, 0) + a + revenue = min(x, d) + cost = c * a + κ * (a > 0) + z_i = revenue - cost + β * v[x_next] + exponents[i] = -γ * z_i + # 用于数值稳定性的 log-sum-exp 技巧 + m = np.max(exponents) + weighted_sum = 0.0 + for i in range(n_d): + weighted_sum += ϕ_values[i] * np.exp(exponents[i] - m) + val = -(1.0 / γ) * (m + np.log(weighted_sum)) + if val > best: + best = val + new_v[x] = best + return new_v +``` + +```{code-cell} ipython3 +def T_rs(v, model): + """风险敏感的贝尔曼算子。""" + x_values, d_values, ϕ_values, p, c, κ, β, γ = model + K = len(x_values) - 1 + return T_rs_kernel(v, d_values, ϕ_values, c, κ, β, γ, K) +``` + + +### 计算贪婪策略 + +贪婪策略记录的是最大化的行动,而不是最大化的值。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def get_greedy_rs_kernel(v, d_values, ϕ_values, c, κ, β, γ, K): + σ = np.empty(K + 1, dtype=np.int32) + n_d = len(d_values) + for x in range(K + 1): + best = -np.inf + best_a = 0 + for a in range(K - x + 1): + exponents = np.empty(n_d) + for i in range(n_d): + d = d_values[i] + x_next = max(x - d, 0) + a + revenue = min(x, d) + cost = c * a + κ * (a > 0) + z_i = revenue - cost + β * v[x_next] + exponents[i] = -γ * z_i + m = np.max(exponents) + weighted_sum = 0.0 + for i in range(n_d): + weighted_sum += ϕ_values[i] * np.exp(exponents[i] - m) + val = -(1.0 / γ) * (m + np.log(weighted_sum)) + if val > best: + best = val + best_a = a + σ[x] = best_a + return σ +``` + +```{code-cell} ipython3 +def get_greedy_rs(v, model): + """获取风险敏感模型的 v-贪婪策略。""" + x_values, d_values, ϕ_values, p, c, κ, β, γ = model + K = len(x_values) - 1 + return get_greedy_rs_kernel(v, d_values, ϕ_values, c, κ, β, γ, K) +``` + +### 值函数迭代 + +```{code-cell} ipython3 +def solve_rs_inventory_model(v_init, model, max_iter=10_000, tol=1e-6): + v = v_init.copy() + i, error = 0, tol + 1 + + while i < max_iter and error > tol: + new_v = T_rs(v, model) + error = np.max(np.abs(new_v - v)) + i += 1 + v = new_v + + print(f"Converged in {i} iterations with error {error:.2e}") + + σ = get_greedy_rs(v, model) + return v, σ +``` + +### 创建并求解一个实例 + +```{code-cell} ipython3 +model = create_rs_inventory_model() +x_values = model.x_values +n_x = len(x_values) +v_init = np.zeros(n_x) +``` + +```{code-cell} ipython3 +v_star, σ_star = solve_rs_inventory_model(v_init, model) +``` + +### 风险敏感性对最优策略的影响 + +我们对 $\gamma$ 的若干个取值求解模型,并比较所得到的策略。 + +正如我们将看到的,风险敏感型企业的订货比风险中性型企业更为保守。 + +```{code-cell} ipython3 +γ_values = [0.01, 1.0, 2.0] +results = {} + +for γ in γ_values: + mod = create_rs_inventory_model(γ=γ) + v, σ = solve_rs_inventory_model(np.zeros(n_x), mod) + results[γ] = (v, σ) +``` + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(9.6, 3.2)) + +for γ in γ_values: + v, σ = results[γ] + axes[0].plot(x_values, v, label=f"$\\gamma = {γ}$") + axes[1].plot(x_values, σ, label=f"$\\gamma = {γ}$") + +axes[0].set_xlabel("库存") +axes[0].set_ylabel("值") +axes[0].legend() +axes[0].set_title("值函数") + +axes[1].set_xlabel("库存") +axes[1].set_ylabel("订货量") +axes[1].legend() +axes[1].set_title("策略") + +plt.tight_layout() +plt.show() +``` + +### 模拟最优策略 + +我们在基准 $\gamma$ 下,模拟最优策略下的库存动态。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def sim_inventories(ts_length, σ, p, X_init=0, seed=0): + """模拟策略 σ 下的库存动态。""" + np.random.seed(seed) + X = np.zeros(ts_length, dtype=np.int32) + X[0] = X_init + for t in range(ts_length - 1): + d = np.random.geometric(p) - 1 + X[t+1] = max(X[t] - d, 0) + σ[X[t]] + return X +``` + +```{code-cell} ipython3 +fig, axes = plt.subplots(len(γ_values), 1, + figsize=(8, 2.0 * len(γ_values)), + sharex=True) + +ts_length = 200 +sim_seed = 5678 +K = len(x_values) - 1 + +for i, γ in enumerate(γ_values): + v, σ = results[γ] + X = sim_inventories(ts_length, σ, model.p, X_init=K // 2, seed=sim_seed) + axes[i].plot(X, alpha=0.7) + axes[i].set_ylabel("库存") + axes[i].set_title(f"$\\gamma = {γ}$") + axes[i].set_ylim(0, K + 2) + +axes[-1].set_xlabel(r"$t$") +plt.tight_layout() +plt.show() +``` + +## 解读结果 + +上面的图表明,风险敏感性越强的企业($\gamma$ 越大),订货越少,维持的库存水平也越低。 + +乍一看这似乎令人惊讶:持有更多库存不是能确保企业总能满足需求,从而降低方差吗? + +关键在于要弄清利润中的随机性究竟来自何处。 + +回想一下,每期利润为 $\pi(x, a, d) = \min(x, d) - ca - \kappa +\mathbf{1}\{a > 0\}$。 + +订货成本 $ca + \kappa \mathbf{1}\{a > 0\}$ 是**确定性的**——它是在需求冲击实现之前就选定的。 + +因此,更多的订货会把利润的水平下移,但不会影响其方差。 + +方差来自**收入**:$\min(x, D)$。 + +当库存 $x$ 较高时,对于大多数需求实现,$\min(x, D) \approx D$——收入继承了需求的全部方差。 + +当库存 $x$ 较低时,对于大多数实现,$\min(x, D) \approx x$——收入几乎是确定性的,被库存水平所封顶。 + +因此,风险敏感型主体更偏好较低的库存,因为这样能**封顶收入的随机性**。 + +该主体接受较低的预期销售额,以换取更可预测的利润。 + +此外还有一个延续值的渠道:下一期库存 $\max(x - D, +0) + a$ 随 $D$ 变化,而更高的 $x$ 意味着 $x - D$ 更紧密地跟随 $D$,从而通过 $v$ 将该方差向前传播。 + + +## Q-Learning + +现在我们要问,能否像在 {doc}`inventory_q` 中风险中性的情形那样,在不了解模型的情况下学习到最优策略。 + +### Q 因子 + +第一步是以与风险敏感贝尔曼方程相容的方式定义 Q 因子。 + +我们定义 + +$$ + q(x, a) := \mathbb E + \left[ + \exp\!\left( + -\gamma \left( \pi(x, a, D) + \beta \, v^*(h(x, a, D)) \right) + \right) + \right]. +$$ + +用文字表述,$q(x, a)$ 在期望内部应用了风险敏感性变换 $\psi(t) = +\exp(-\gamma t)$,其求值对象为在状态 $x$ 中采取行动 $a$、此后遵循最优策略所得到的回报。 + +### 推导 Q 因子贝尔曼方程 + +我们的目标是获得一个仅关于 $q$ 的不动点方程,消去 $v^*$。 + +**第 1 步。** 用 $q$ 表示 $v^*$。 + +风险敏感贝尔曼方程表明 $v^*(x) = \max_{a \in \Gamma(x)} +\psi^{-1}(q(x, a))$。 + +由于 $\psi^{-1}(y) = -\frac{1}{\gamma} \ln(y)$ 是一个**递减**函数,$\psi^{-1}(q(x, a))$ 关于 $a$ 的最大值对应于 $q(x, a)$ 关于 $a$ 的**最小值**: + +$$ + v^*(x) + = \psi^{-1}\!\left(\min_{a \in \Gamma(x)} q(x, a)\right) + = -\frac{1}{\gamma} \ln\!\left(\min_{a \in \Gamma(x)} q(x, a)\right). +$$ + +等价地, + +$$ + \exp(-\gamma \, v^*(x)) = \min_{a \in \Gamma(x)} q(x, a). +$$ + +**第 2 步。** 代回 $q$ 的定义中以消去 $v^*$。 + +将 $q$ 定义中的指数展开, + +$$ + q(x, a) + = \mathbb E + \left[ + \exp(-\gamma \, \pi(x, a, D)) + \;\cdot\; + \exp\!\left(-\gamma \beta \, v^*(x')\right) + \right] +$$ + +其中 $x' = h(x, a, D)$。 + +由第 1 步,$\exp(-\gamma \, v^*(x')) = \min_{a' \in \Gamma(x')} q(x', a')$,所以 $\exp(-\gamma \beta \, v^*(x')) = \left[\min_{a' \in \Gamma(x')} q(x', +a')\right]^\beta$。 + +代入后, + +$$ + q(x, a) + = \mathbb E + \left[ + \exp(-\gamma \, \pi(x, a, D)) + \;\cdot\; + \left(\min_{a' \in \Gamma(x')} q(x', a')\right)^\beta + \right]. +$$ + +这是一个仅关于 $q$ 的不动点方程——$v^*$ 已被消去。 + +### Q-learning 更新规则 + +与风险中性的情形一样,我们使用随机逼近来近似该不动点。 + +在每一步,主体处于状态 $x$,采取行动 $a$,观测到利润 +$R_{t+1} = \pi(x, a, D_{t+1})$ 和下一状态 $X_{t+1} = h(x, a, D_{t+1})$,并更新 + +$$ + q_{t+1}(x, a) + = (1 - \alpha_t) \, q_t(x, a) + + \alpha_t + \left[ + \exp(-\gamma \, R_{t+1}) + \;\cdot\; + \left(\min_{a' \in \Gamma(X_{t+1})} q_t(X_{t+1}, a')\right)^\beta + \right]. +$$ + +方括号中的项是 Q 因子贝尔曼方程右端的单样本估计。 + +该更新将当前估计与这个新样本混合起来,正如标准 Q-learning 中一样。 + +请注意与风险中性情形的若干区别: + +- Q 值是**正的**(指数的期望),而不是带符号的。 +- 最优策略为 $\sigma(x) = \argmin_a q(x, a)$——我们**最小化**而不是最大化,因为 $\psi^{-1}$ 是递减的。 +- 观测到的利润通过 $\exp(-\gamma R_{t+1})$ 进入,而不是以加性方式进入。 +- 延续值以**幂** $(\min_{a'} q_t)^\beta$ 的形式进入,而不是以缩放后的求和 $\beta \cdot \max_{a'} q_t$ 的形式进入。 + +和之前一样,主体只需观测 $x$、$a$、$R_{t+1}$ 和 $X_{t+1}$——不需要任何模型知识。 + +### 实现方案 + +我们的实现遵循与 {doc}`inventory_q` 中风险中性 Q-learning 相同的结构,并加入上述修改: + +1. **乐观地初始化** Q 表 $q$(见下文),并将访问计数 $n$ 初始化为零。 +2. **在每一步:** + - 抽取需求 $D_{t+1}$,并计算观测到的利润 $R_{t+1}$ 和下一状态 $X_{t+1}$。 + - 在可行行动上计算 $\min_{a'} q_t(X_{t+1}, a')$(这是用于更新目标的一个标量,而 $\argmin$ 行动被 $\varepsilon$-贪婪行为策略所使用)。 + - 使用上面的规则更新 $q_t(x, a)$,学习率为 $\alpha_t = 1 / n_t(x, a)^{0.51}$。 + - 通过 $\varepsilon$-贪婪选择下一个行动:以概率 $\varepsilon$ 随机挑选一个可行行动,否则挑选 $\argmin$ 行动。 + - 衰减 $\varepsilon$。 +3. 通过 $\sigma(x) = \argmin_{a \in \Gamma(x)} q(x, a)$ 从最终的 Q 表中**提取贪婪策略**。 +4. 将学习到的策略与 VFI 解进行**比较**。 + +### 乐观初始化 + +与 {doc}`inventory_q` 中一样,我们使用乐观初始化来加速学习。 + +其逻辑相同——初始化 Q 表使得每个未尝试过的行动看起来都很有吸引力,从而促使主体广泛地探索——但方向是相反的。 + +由于最优策略是*最小化* $q$,"乐观"意味着将 Q 表初始化到低于真实值的水平。当主体尝试一个行动时,更新会将 $q$ 向着现实推高,使该条目看起来更差,从而促使主体去尝试那些仍然看起来乐观地好的其他行动。 + +真实的 Q 值大约在 $\exp(-\gamma \, v^*) \approx 10^{-8}$ 到 $10^{-6}$ 的量级。 +我们将 Q 表初始化为 $10^{-9}$,略低于这个范围。 + +### 实现 + +我们首先定义一个辅助函数,从 Q 表中提取贪婪策略。 + +由于最优策略是最小化 $q$,我们使用 $\argmin$ 而不是 $\argmax$。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def greedy_policy_from_q_rs(q, K): + """从风险敏感的 Q 表中提取贪婪策略(argmin)。""" + σ = np.empty(K + 1, dtype=np.int32) + for x in range(K + 1): + best_val = np.inf + best_a = 0 + for a in range(K - x + 1): + if q[x, a] < best_val: + best_val = q[x, a] + best_a = a + σ[x] = best_a + return σ +``` + +Q-learning 循环与风险中性版本相仿,关键变化在于:更新目标使用 $\exp(-\gamma R_{t+1}) +\cdot (\min_{a'} q_t)^\beta$,而行为策略遵循 $\argmin$。 + +```{code-cell} ipython3 +@numba.jit(nopython=True) +def q_learning_rs_kernel(K, p, c, κ, β, γ, n_steps, X_init, + ε_init, ε_min, ε_decay, q_init, snapshot_steps, seed): + np.random.seed(seed) + q = np.full((K + 1, K + 1), q_init) # 乐观初始化 + n = np.zeros((K + 1, K + 1)) # 用于学习率的访问计数 + ε = ε_init + + n_snaps = len(snapshot_steps) + snapshots = np.zeros((n_snaps, K + 1), dtype=np.int32) + snap_idx = 0 + + # 初始化状态和行动 + x = X_init + a = np.random.randint(0, K - x + 1) + + for t in range(n_steps): + # 如有需要则记录策略快照 + if snap_idx < n_snaps and t == snapshot_steps[snap_idx]: + snapshots[snap_idx] = greedy_policy_from_q_rs(q, K) + snap_idx += 1 + + # === 抽取 D_{t+1} 并观测结果 === + d = np.random.geometric(p) - 1 + reward = min(x, d) - c * a - κ * (a > 0) + x_next = max(x - d, 0) + a + + # === 对下一状态取最小值(用于更新目标的标量值)=== + # 同时记录 argmin 行动,供行为策略使用。 + best_next = np.inf + a_next = 0 + for aa in range(K - x_next + 1): + if q[x_next, aa] < best_next: + best_next = q[x_next, aa] + a_next = aa + + # === 风险敏感的 Q-learning 更新 === + target = np.exp(-γ * reward) * best_next ** β + n[x, a] += 1 + α = 1.0 / n[x, a] ** 0.51 + q[x, a] = (1 - α) * q[x, a] + α * target + + # === 行为策略:ε-贪婪(使用 a_next,即 argmin 行动)=== + x = x_next + if np.random.random() < ε: + a = np.random.randint(0, K - x + 1) + else: + a = a_next + ε = max(ε_min, ε * ε_decay) + + return q, snapshots +``` + +包装函数解包模型并提供默认超参数。 + +```{code-cell} ipython3 +def q_learning_rs(model, n_steps=20_000_000, X_init=0, + ε_init=1.0, ε_min=0.01, ε_decay=0.999999, + q_init=1e-9, snapshot_steps=None, seed=1234): + x_values, d_values, ϕ_values, p, c, κ, β, γ = model + K = len(x_values) - 1 + if snapshot_steps is None: + snapshot_steps = np.array([], dtype=np.int64) + return q_learning_rs_kernel(K, p, c, κ, β, γ, n_steps, X_init, + ε_init, ε_min, ε_decay, q_init, snapshot_steps, seed) +``` + +### 运行 Q-learning + +我们运行 $n$ = 500 万步,并在第 10,000 步、1,000,000 步以及第 $n$ 步拍摄策略快照。 + +```{code-cell} ipython3 +n = 5_000_000 +snap_steps = np.array([10_000, 1_000_000, n], dtype=np.int64) +q_table, snapshots = q_learning_rs(model, n_steps=n+1, snapshot_steps=snap_steps) +``` + +### 与精确解进行比较 + +我们从最终的 Q 表中提取值函数和策略。 + +由于 Q 值表示 $\mathbb{E}[\exp(-\gamma(\cdots))]$,我们通过 $v_Q(x) = -\frac{1}{\gamma} \ln(\min_{a} q(x, a))$ 恢复值函数,并通过 $\sigma_Q(x) = \argmin_a q(x, a)$ 恢复策略。 + +```{code-cell} ipython3 +K = len(x_values) - 1 +γ_base = model.γ +# 限制在可行行动 a ∈ {0, ..., K-x} 内 +v_q = np.array([-(1/γ_base) * np.log(np.min(q_table[x, :K - x + 1])) + for x in range(K + 1)]) +σ_q = np.array([np.argmin(q_table[x, :K - x + 1]) + for x in range(K + 1)]) +``` + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, 2, figsize=(9.6, 3.2)) + +axes[0].plot(x_values, v_star, label="VFI") +axes[0].plot(x_values, v_q, '--', label="Q-learning") +axes[0].set_xlabel("库存") +axes[0].set_ylabel("值") +axes[0].legend() +axes[0].set_title("值函数") + +axes[1].plot(x_values, σ_star, label="VFI") +axes[1].plot(x_values, σ_q, '--', label="Q-learning") +axes[1].set_xlabel("库存") +axes[1].set_ylabel("订货量") +axes[1].legend() +axes[1].set_title("策略") + +plt.tight_layout() +plt.show() +``` + +### 可视化学习随时间的演变 + +下面的面板展示了主体的策略在训练过程中如何演变。 + +每个面板使用从给定训练步骤的 Q 表中提取的贪婪策略来模拟一条库存路径,整个过程使用相同的需求序列。 + +顶部面板展示了来自 VFI 的最优策略以供参考。 + +```{code-cell} ipython3 +ts_length = 200 +n_snaps = len(snap_steps) +fig, axes = plt.subplots(n_snaps + 1, 1, figsize=(8, 2.0 * (n_snaps + 1)), + sharex=True) + +X_init = K // 2 +sim_seed = 5678 + +# 最优策略 +X_opt = sim_inventories(ts_length, σ_star, model.p, X_init, seed=sim_seed) +axes[0].plot(X_opt, alpha=0.7) +axes[0].set_ylabel("库存") +axes[0].set_title("最优 (VFI)") +axes[0].set_ylim(0, K + 2) + +# Q-learning 快照 +for i in range(n_snaps): + σ_snap = snapshots[i] + X = sim_inventories(ts_length, σ_snap, model.p, X_init, seed=sim_seed) + axes[i + 1].plot(X, alpha=0.7) + axes[i + 1].set_ylabel("库存") + axes[i + 1].set_title(f"第 {snap_steps[i]:,} 步") + axes[i + 1].set_ylim(0, K + 2) + +axes[-1].set_xlabel(r"$t$") +plt.tight_layout() +plt.show() +``` + +经过 10,000 步后,主体几乎还未进行探索,其策略是不稳定的。 + +到 1,000,000 步时,学习到的策略已有所改善,但仍与最优策略有明显差异。 + +到第 500 万步时,库存动态几乎与 VFI 解无法区分。 + +请注意,收敛后的策略维持的库存水平比风险中性情形更低(与 {doc}`inventory_q` 比较),这与上文讨论的机制一致:风险敏感型主体通过持有更少的库存来封顶其对需求方差的暴露。 + +## 结论 + +我们将 {doc}`inventory_q` 中的库存管理问题进行了扩展,通过确定性等价算子 $\psi^{-1}(\mathbb{E}[\psi(\cdot)])$(其中 $\psi(t) = \exp(-\gamma t)$)引入了风险敏感性。 + +值函数迭代证实,风险敏感型企业的订货更为保守,宁愿要可预测的利润,也不要更高但更为波动的回报。 + +然后,我们展示了通过处理经变换的 Q 因子 $q(x,a) = +\mathbb{E}[\exp(-\gamma(\pi + \beta v^*))]$,Q-learning 可以被适配到风险敏感的场景。 + +由此得到的更新规则将加法替换为乘法,将 max 替换为 min,但保留了无模型学习的关键特性:主体只需观测状态、行动和利润。 \ No newline at end of file diff --git a/lectures/survival_recursive_preferences.md b/lectures/survival_recursive_preferences.md new file mode 100644 index 0000000..75f8b76 --- /dev/null +++ b/lectures/survival_recursive_preferences.md @@ -0,0 +1,1279 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.11.1 +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 递归偏好下的生存与长期动态 + headings: + Overview: 概述 + Environment: 环境 + Environment::Aggregate endowment: 总禀赋 + Environment::Heterogeneous beliefs: 异质信念 + Environment::Recursive preferences: 递归偏好 + Planner's problem: 规划者问题 + Planner's problem::Modified discount factors: 修正贴现因子 + 'Planner''s problem::State variable: Pareto share': 状态变量:帕累托份额 + Planner's problem::HJB equation: HJB 方程 + Planner's problem::HJB equation::From discrete to continuous time: 从离散时间到连续时间 + Planner's problem::HJB equation::Exact reduced ODE: 精确的约化 ODE + Survival conditions: 生存条件 + Wealth dynamics decomposition: 财富动态分解 + Wealth dynamics decomposition::Portfolio returns: 组合收益 + Wealth dynamics decomposition::Consumption-wealth ratios: 消费-财富比 + Wealth dynamics decomposition::Two comparative statics: 两个比较静态分析 + Survival regions: 生存区域 + Three survival channels: 三个生存渠道 + Varying the IES: 改变 IES + Asymptotic results: 渐近结果 + The separable case: 可分情形 + Asset pricing implications: 资产定价含义 + Optimistic and pessimistic distortions: 乐观和悲观扭曲 + Long-run consumption distribution: 长期消费分布 + Summary: 总结 +--- + +(survival_recursive_preferences)= +```{raw} jupyter + +``` + +# 递归偏好下的生存与长期动态 + +```{index} single: Survival; Recursive Preferences +``` + +```{contents} Contents +:depth: 2 +``` + +## 概述 + +本讲座研究 {cite:t}`Borovicka2020` 中关于长期生存的理论。 + +经典的**市场选择假说**认为,信念较不准确的主体最终会被市场淘汰。 + +这一结果由 {cite:t}`Sandroni2000Markets` 和 {cite:t}`Blume_Easley2006` 针对具有可分 CRRA 偏好的经济体进行了严格证明。 + +Borovicka 表明,在 Epstein-Zin 递归偏好下,这一结论可能不成立。 + +在递归偏好下,具有扭曲信念的主体可以生存,甚至可以占据主导地位。 + +关键机制在于递归偏好将风险厌恶与跨期替代弹性(IES)分离开来。 + +这种分离产生了三个对生存至关重要的渠道: + +1. *风险溢价渠道*奖励更乐观的主体持有更多的风险资产。 +1. *投机波动率渠道*通过对数收益率波动率惩罚激进的头寸。 +1. *储蓄渠道*在 IES 不等于 1 时改变消费和储蓄决策。 + +在可分偏好下,只有前两个渠道存在。 + +在递归偏好下,储蓄渠道可以推翻市场选择。 + +```{note} +本文建立在 {cite:t}`Duffie_Epstein1992a` 的连续时间递归效用表述之上, +并采用 {cite:t}`Dumas_Uppal_Wang2000` 的规划者问题方法。 + +市场选择假说的重要基础由 +{cite:t}`DeLong_etal1991` 和 {cite:t}`Blume_Easley1992` 奠定。 +``` + +我们从一些导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 环境 + +该经济体包含两个无限期存活的主体,用 $n \in \{1, 2\}$ 索引。 + +这两个主体具有相同的递归偏好,但对总禀赋增长持有不同的信念。 + +我们将 Borovička 的信念扭曲 $u^n$ 记作 $\omega^n$。 + +### 总禀赋 + +在真实概率测度 $P$ 下,总禀赋满足 + +$$ +d \log Y_t = \mu_Y dt + \sigma_Y dW_t, \quad Y_0 > 0 +$$ (eq:srp_endowment) + +其中 $W$ 是标准布朗运动,$\mu_Y$ 是漂移,$\sigma_Y > 0$ 是波动率。 + +### 异质信念 + +主体 $n$ 认为漂移是 $\mu_Y + \omega^n \sigma_Y$ 而非 $\mu_Y$。 + +参数 $\omega^n$ 在 $\omega^n > 0$ 时衡量乐观程度,在 $\omega^n < 0$ 时衡量悲观程度。 + +主体 $n$ 的主观概率测度 $Q^n$ 由 Radon–Nikodym 导数定义 + +$$ +M_t^n = \frac{dQ^n}{dP}\bigg|_t = \exp\left(-\frac{1}{2} |\omega^n|^2 t + \omega^n W_t\right) +$$ (eq:radon_nikodym) + +在 $Q^n$ 下,过程 $W_t^n = W_t - \omega^n t$ 是一个布朗运动,主体 $n$ 感知到 + +$$ +d \log Y_t = (\mu_Y + \omega^n \sigma_Y) dt + \sigma_Y dW_t^n . +$$ + +$\omega^n > 0$ 的主体对禀赋增长持乐观态度,而 $\omega^n < 0$ 的主体则持悲观态度。 + +### 递归偏好 + +两个主体都具有 Epstein-Zin 递归偏好。 + +我们用 $\gamma > 0$ 表示相对风险厌恶,用 $\rho > 0$ 表示 IES 的倒数,用 $\beta > 0$ 表示时间偏好率。 + +Duffie-Epstein-Zin 幸福函数为 + +$$ +F(C, \nu) += \beta \frac{C^{1-\gamma}}{1-\gamma} +\cdot +\left(\frac{(1-\gamma) - (1-\rho)\nu / \beta}{\rho - \gamma}\right)^{(\gamma - \rho)/(1-\rho)} +$$ (eq:felicity) + +其中 $\nu$ 是内生的贴现率。 + +```{note} +在离散时间中,Epstein-Zin 偏好通过 CES 聚合器将当前消费与未来效用的确定性等价物聚合在一起(参见 {doc}`advanced:doubts_or_variability`)。 + +在连续时间中不存在"下一期 $V_{t+1}$",因此 {cite:t}`Duffie_Epstein1992a` 将该递归重新表述为一个依赖于主体自身延续值率 $\nu$ 的幸福函数 $F(C,\nu)$。 + +这两种表述编码了相同的风险厌恶 $\gamma$ 与 IES 倒数 $\rho$ 的分离。 + +当 $\gamma = \rho$ 时,偏好退化为标准的可分 CRRA 情形。 +``` + +## 规划者问题 + +遵循 {cite:t}`Dumas_Uppal_Wang2000`,我们通过社会规划者问题来研究均衡配置。 + +规划者为两个主体选择消费份额 $z^1$ 和 $z^2 = 1 - z^1$ 以及贴现率过程 $\nu^n$。 + +### 修正贴现因子 + +将信念扭曲吸收进修正贴现因子 $\tilde{\lambda}^n = \lambda^n M^n$ 是很方便的,其中 $M^n$ 是 Radon-Nikodym 导数 {eq}`eq:radon_nikodym`。 + +这些过程满足 + +$$ +d \log \tilde{\lambda}_t^n += -\left(\nu_t^n + \frac{1}{2} (\omega^n)^2\right) dt + \omega^n dW_t . +$$ (eq:modified_discount) + +```{exercise} +:label: ex_modified_discount + +推导 {eq}`eq:modified_discount`。 + +*提示:* 使用 $\log \tilde{\lambda}^n = \log \lambda^n + \log M^n$。帕累托权重 $\lambda^n$ 按 $d\log \lambda_t^n = -\nu_t^n \, dt$ 演化,而 $\log M_t^n$ 由 {eq}`eq:radon_nikodym` 给出。 +``` + +```{solution-start} ex_modified_discount +:class: dropdown +``` + +由定义 $\tilde{\lambda}^n = \lambda^n M^n$,我们有 + +$$ +\log \tilde{\lambda}_t^n = \log \lambda_t^n + \log M_t^n. +$$ + +帕累托权重满足 $d\log \lambda_t^n = -\nu_t^n \, dt$。 + +由 {eq}`eq:radon_nikodym`,$\log M_t^n = -\frac{1}{2}|\omega^n|^2 t + \omega^n W_t$,因此 + +$$ +d \log M_t^n = -\tfrac{1}{2}(\omega^n)^2 \, dt + \omega^n \, dW_t. +$$ + +将两者相加: + +$$ +d \log \tilde{\lambda}_t^n = -\nu_t^n \, dt - \tfrac{1}{2}(\omega^n)^2 \, dt + \omega^n \, dW_t = -\left(\nu_t^n + \tfrac{1}{2}(\omega^n)^2\right) dt + \omega^n \, dW_t. +$$ + +```{solution-end} +``` + +### 状态变量:帕累托份额 + +关键的状态变量是主体 1 的帕累托份额: + +$$ +\upsilon = \frac{\tilde{\lambda}^1}{\tilde{\lambda}^1 + \tilde{\lambda}^2} \in (0, 1) +$$ (eq:pareto_share) + +它刻画了主体 1 在规划者配置中的相对权重。 + +定义对数几率比 $\vartheta = \log(\upsilon / (1 - \upsilon))$。 + +其动态为 + +$$ +d\vartheta_t = \underbrace{\left[\nu_t^2 + \frac{1}{2}(\omega^2)^2 - \nu_t^1 - \frac{1}{2}(\omega^1)^2\right]}_{m_{\vartheta}(\upsilon_t)} dt + (\omega^1 - \omega^2) dW_t +$$ (eq:log_odds) + +漂移 $m_\vartheta(\upsilon)$ 决定了帕累托份额的长期行为。 + +```{exercise} +:label: ex_log_odds + +从 {eq}`eq:modified_discount` 和定义 $\vartheta = \log(\upsilon/(1-\upsilon))$ 推导 {eq}`eq:log_odds`。 + +*提示:* 首先证明 $\vartheta = \log \tilde{\lambda}^1 - \log \tilde{\lambda}^2$,然后将两个 SDE 相减。 +``` + +```{solution-start} ex_log_odds +:class: dropdown +``` + +由于 $\upsilon = \tilde{\lambda}^1 / (\tilde{\lambda}^1 + \tilde{\lambda}^2)$,我们有 $1 - \upsilon = \tilde{\lambda}^2 / (\tilde{\lambda}^1 + \tilde{\lambda}^2)$,因此 + +$$ +\vartheta = \log\frac{\upsilon}{1-\upsilon} = \log \tilde{\lambda}^1 - \log \tilde{\lambda}^2. +$$ + +由 {eq}`eq:modified_discount`,两个对数贴现因子的 SDE 为 + +$$ +d\log \tilde{\lambda}^1_t = -\left(\nu_t^1 + \tfrac{1}{2}(\omega^1)^2\right)dt + \omega^1 dW_t, +$$ + +$$ +d\log \tilde{\lambda}^2_t = -\left(\nu_t^2 + \tfrac{1}{2}(\omega^2)^2\right)dt + \omega^2 dW_t. +$$ + +用第一个减去第二个: + +$$ +d\vartheta_t = \left[\nu_t^2 + \tfrac{1}{2}(\omega^2)^2 - \nu_t^1 - \tfrac{1}{2}(\omega^1)^2\right]dt + (\omega^1 - \omega^2)dW_t. +$$ + +```{solution-end} +``` + +### HJB 方程 + +齐次性将规划者问题简化为关于单一状态变量 $\upsilon$ 的非线性 ODE。 + +因为每个主体的效用关于消费是 $1-\gamma$ 次齐次的,规划者的值函数可以分解为 $J(\upsilon, Y) = \tilde{J}(\upsilon) \cdot Y^{1-\gamma}/(1-\gamma)$,从而消除了 $Y$ 作为状态变量。 + +#### 从离散时间到连续时间 + +在离散时间中,规划者通过在每个日期选择配置来最大化主体效用的加权和。 + +贝尔曼方程为 + +$$ +\tilde{J}(\upsilon) = \max_{z^1, z^2} \left\{ \upsilon \, u(z^1) + (1-\upsilon) \, u(z^2) + \beta \, \mathbb{E}\left[\tilde{J}(\upsilon')\right] \right\}. +$$ + +在连续时间中,时期长度缩小为 $dt$。 + +$[t, t+dt)$ 上的"流量收益"变为 $\left[\upsilon F(z^1, \nu^1) + (1-\upsilon)F(z^2, \nu^2)\right] dt$,其中 $F$ 是 Duffie-Epstein-Zin 幸福函数 {eq}`eq:felicity`。 + +值函数在 $dt$ 上的期望变化由**无穷小生成元** $\mathcal{L}$ 捕获。 + +对于扩散过程 $d\upsilon = m \, dt + s \, dW$,伊藤引理给出 + +$$ +\mathcal{L}\tilde{J}(\upsilon) = m(\upsilon)\,\tilde{J}'(\upsilon) + \tfrac{1}{2} s(\upsilon)^2 \, \tilde{J}''(\upsilon), +$$ + +其中 $m$ 和 $s$ 是帕累托份额的漂移和扩散。 + +这是 $\beta \, \mathbb{E}[\tilde{J}(\upsilon')] - \tilde{J}(\upsilon)$ 的连续时间类比:它衡量随着 $\upsilon$ 演化,值函数如何漂移和波动。 + +令流量收益加上期望资本收益等于零,得到示意性的 HJB 方程: + +$$ +0 = \sup_{(z^1,z^2,\nu^1,\nu^2)} \left\{ \upsilon F(z^1, \nu^1) + (1-\upsilon) F(z^2, \nu^2) + \mathcal{L} \tilde{J}(\upsilon) \right\} +$$ (eq:hjb_sketch) + +满足约束 $z^1 + z^2 \leq 1$。 + +#### 精确的约化 ODE + +{cite:t}`Borovicka2020` 的命题 2.3 在代入齐次性约化 $J(\tilde{\lambda}, Y) = (\tilde{\lambda}^1 + \tilde{\lambda}^2) Y^{1-\gamma} \tilde{J}(\upsilon)$ 以及 $\upsilon$ 和 $Y$ 的动态后,给出了精确的 HJB 方程: + +$$ +0 = \sup_{(z^1, z^2, \nu^1, \nu^2)} \; +\upsilon \, F(z^1, \nu^1) + (1 - \upsilon) \, F(z^2, \nu^2) +$$ (eq:hjb) + +$$ ++ \left[ +-\upsilon \nu^1 - (1-\upsilon)\nu^2 ++ \bigl(\upsilon \omega^1 + (1-\upsilon)\omega^2\bigr)(1-\gamma)\sigma_Y ++ (1-\gamma)\mu_Y ++ \tfrac{1}{2}(1-\gamma)^2 \sigma_Y^2 +\right] \tilde{J}(\upsilon) +$$ + +$$ ++ \upsilon(1-\upsilon) +\left[\nu^2 - \nu^1 + (\omega^1 - \omega^2)(1-\gamma)\sigma_Y\right] +\tilde{J}'(\upsilon) +$$ + +$$ ++ \tfrac{1}{2}\upsilon^2(1-\upsilon)^2 (\omega^1 - \omega^2)^2 \, +\tilde{J}''(\upsilon) +$$ + +满足约束 $z^1 + z^2 \leq 1$。 + +第一行是来自两个主体幸福函数的流量收益。 + +第二行将 $\tilde{J}(\upsilon)$ 乘以一个结合了主体贴现率、信念加权的禀赋漂移以及方差修正的项——这些来自于通过伊藤引理吸收 $Y^{1-\gamma}$ 因子。 + +第三行将 $\tilde{J}'(\upsilon)$ 乘以帕累托份额的漂移,它取决于贴现率的差异以及对禀赋风险的信念加权响应。 + +第四行将 $\tilde{J}''(\upsilon)$ 乘以帕累托份额扩散的平方。 + +边界条件为 $\tilde{J}(0) = \tilde{V}^2$ 和 $\tilde{J}(1) = \tilde{V}^1$,其中 $\tilde{V}^n$ 是仅由主体 $n$ 单独构成的齐次经济体中的延续值。 + +这是 {cite:t}`Blume_Easley2006` 中离散时间规划者问题的连续时间对应(另见 {doc}`likelihood_ratio_process_2`)。 + + +## 生存条件 + +核心结果通过 $m_\vartheta(\upsilon)$ 的边界行为来刻画生存。 + +```{prf:proposition} +:label: survival_conditions + +定义以下排斥条件 (i) 和 (ii) 及其吸引对应条件 (i') 和 (ii'): + +$$ +\text{(i)} \lim_{\upsilon \searrow 0} m_\vartheta(\upsilon) > 0, \qquad +\text{(i')} \lim_{\upsilon \searrow 0} m_\vartheta(\upsilon) < 0 +$$ + +$$ +\text{(ii)} \lim_{\upsilon \nearrow 1} m_\vartheta(\upsilon) < 0, \qquad +\text{(ii')} \lim_{\upsilon \nearrow 1} m_\vartheta(\upsilon) > 0 +$$ + +那么: + +*(a)* 若 (i) 和 (ii) 成立,则两个主体在 $P$ 下都生存。 + +*(b)* 若 (i) 和 (ii') 成立,则主体 1 在 $P$ 下长期占据主导地位。 + +*(c)* 若 (i') 和 (ii) 成立,则主体 2 在 $P$ 下长期占据主导地位。 + +*(d)* 若 (i') 和 (ii') 成立,则每个主体都以严格正概率占据主导地位。 +``` + +该证明使用了扩散过程边界行为的 Feller 分类,如 {cite:t}`Karlin_Taylor1981` 所述。 + +条件 (i) 表明,当主体 1 接近消亡时,存在一种将其份额推回上升的力量。 + +条件 (ii) 表明,当主体 1 接近吸收整个经济体时,存在一种将其份额推回下降的力量。 + +当两种力量都存在时,帕累托份额是常返的,两个主体都生存。 + +## 财富动态分解 + +我们现在用均衡财富动态重写 {prf:ref}`survival_conditions` 中的生存条件。 + +当且仅当主体 1 在其规模微不足道时财富增长快于主体 2,主体 1 才能在接近消亡时生存下来。 + +当 $\upsilon \searrow 0$ 时,价格完全由主体 2 决定,仿佛经济体是齐次的。 + +主体 1 是主体 2 经济体中的价格接受者。 + +令 $m_A^n(\upsilon)$ 表示主体 $n$ 财富的期望对数增长率。 + +其差异分解为两个渠道: + +$$ +\lim_{\upsilon \searrow 0} [m_A^1(\upsilon) - m_A^2(\upsilon)] += \underbrace{\lim_{\upsilon \searrow 0} [m_R^1(\upsilon) - m_R^2(\upsilon)]}_{\text{组合收益}} ++ \underbrace{\lim_{\upsilon \searrow 0} [(y^2(\upsilon))^{-1} - (y^1(\upsilon))^{-1}]}_{\text{消费-财富比}} +$$ (eq:wealth_decomp) + +第一项衡量主体 1 的投资组合增长快多少。 + +第二项衡量主体 1 从财富中消费少多少——较低的消费-财富比意味着更多的储蓄和更快的财富积累。 + +当此总差异为正时,主体 1 生存;当为负时,她朝着消亡收缩。 + +```{exercise} +:label: ex_wealth_decomp + +推导 {eq}`eq:wealth_decomp`。 + +令 $A^n$ 表示主体 $n$ 的财富,$C^n$ 表示她的消费。 + +预算约束为 $dA^n = A^n dR^n - C^n dt$,其中 $dR^n$ 是主体 $n$ 投资组合的收益。 + +定义消费-财富比 $c^n = C^n / A^n = (y^n)^{-1}$。 + +证明 $d\log A^n = m_R^n \, dt - (y^n)^{-1} dt + \ldots$,因此期望对数财富增长之差为 $m_A^1 - m_A^2 = (m_R^1 - m_R^2) + [(y^2)^{-1} - (y^1)^{-1}]$。 +``` + +```{solution-start} ex_wealth_decomp +:class: dropdown +``` + +将预算约束除以 $A^n$: + +$$ +\frac{dA^n}{A^n} = dR^n - (y^n)^{-1} dt. +$$ + +由伊藤引理,$d\log A^n = \frac{dA^n}{A^n} - \frac{1}{2}\left(\frac{dA^n}{A^n}\right)^2$。 + +将 $dR^n = m_R^n \, dt + \sigma_R^n \, dW$ 写出($P$ 下的投资组合收益)。 + +那么 + +$$ +d\log A^n = \left(m_R^n - (y^n)^{-1} - \tfrac{1}{2}(\sigma_R^n)^2\right) dt + \sigma_R^n \, dW. +$$ + +对主体 1 和 2 取差: + +$$ +m_A^1 - m_A^2 = (m_R^1 - m_R^2) + \left[(y^2)^{-1} - (y^1)^{-1}\right] - \tfrac{1}{2}\left[(\sigma_R^1)^2 - (\sigma_R^2)^2\right]. +$$ + +当我们将 $m_R^n$ 定义为期望对数投资组合收益(即 $\log R^n$ 的漂移而非算术收益)时,波动率项 $\tfrac{1}{2}[(\sigma_R^1)^2 - (\sigma_R^2)^2]$ 被吸收进 $m_R^1 - m_R^2$,从而得到 {eq}`eq:wealth_decomp`。 + +```{solution-end} +``` + +### 组合收益 + +在边界 $\upsilon \searrow 0$ 处,期望对数投资组合收益之差为 + +$$ +\lim_{\upsilon \searrow 0} [m_R^1 - m_R^2] += \underbrace{\frac{\omega^1 - \omega^2}{\gamma \sigma_Y}}_{\text{风险份额之差}} +\cdot \underbrace{(\gamma \sigma_Y^2 - \omega^2 \sigma_Y)}_{\text{风险溢价}} +- \underbrace{\frac{\omega^1 - \omega^2}{\gamma} +\left(\sigma_Y + \frac{\omega^1 - \omega^2}{2\gamma}\right)}_{\text{波动率项}} +$$ (eq:portfolio_returns) + +乐观的主体($\omega^1 > \omega^2$)相对于主体 2 将风险资产超配 $(\omega^1 - \omega^2)/(\gamma \sigma_Y)$,并从这一额外敞口中赚取股权风险溢价。 + +被减去的*波动率惩罚*反映了持有更极端投资组合的成本:对数收益率的较高方差拖累了期望对数财富增长。 + +此项依赖于风险厌恶 $\gamma$,但不依赖于 IES,因为投资组合选择仅由风险厌恶决定。 + +```{exercise} +:label: ex_portfolio_returns + +推导 {eq}`eq:portfolio_returns`。 + +在边界 $\upsilon \searrow 0$ 处,主体 $n$ 的最优风险资产份额为 $\pi^n = 1 + (\omega^n - \omega^2)/(\gamma \sigma_Y)$(参见 {eq}`eq:portfolio`)。 + +令 $\bar{\mu}_R = \mu_Y + \gamma \sigma_Y^2 - \omega^2 \sigma_Y$ 表示 $P$ 下风险资产的期望收益,$r$ 表示无风险利率。 + +连续再平衡的投资组合具有期望对数收益 $m_R^n = r + \pi^n(\bar{\mu}_R - r) - \frac{1}{2}(\pi^n)^2 \sigma_Y^2$。 + +计算 $m_R^1 - m_R^2$ 并化简。 +``` + +```{solution-start} ex_portfolio_returns +:class: dropdown +``` + +使用 $m_R^n = r + \pi^n(\bar{\mu}_R - r) - \frac{1}{2}(\pi^n)^2 \sigma_Y^2$,差异为 + +$$ +m_R^1 - m_R^2 = (\pi^1 - \pi^2)(\bar{\mu}_R - r) - \tfrac{1}{2}[(\pi^1)^2 - (\pi^2)^2]\sigma_Y^2. +$$ + +风险份额之差为 $\pi^1 - \pi^2 = (\omega^1 - \omega^2)/(\gamma \sigma_Y)$。 + +算术股权溢价为 $\bar{\mu}_R - r = \gamma \sigma_Y^2 - \omega^2 \sigma_Y$,因此: + +$$ +(\pi^1 - \pi^2)(\bar{\mu}_R - r) = \frac{\omega^1 - \omega^2}{\gamma \sigma_Y} \cdot (\gamma \sigma_Y^2 - \omega^2 \sigma_Y). +$$ + +对于波动率项,写出 $(\pi^1)^2 - (\pi^2)^2 = (\pi^1 - \pi^2)(\pi^1 + \pi^2)$ 并注意 $\pi^1 + \pi^2 = 2 + (\omega^1 + \omega^2 - 2\omega^2)/(\gamma \sigma_Y)$。 + +化简后: + +$$ +\tfrac{1}{2}[(\pi^1)^2 - (\pi^2)^2]\sigma_Y^2 = \frac{\omega^1 - \omega^2}{\gamma}\left(\sigma_Y + \frac{\omega^1 - \omega^2}{2\gamma}\right). +$$ + +将两部分合并即得 {eq}`eq:portfolio_returns`。 + +```{solution-end} +``` + +### 消费-财富比 + +在边界处消费-财富比之差为 + +$$ +\lim_{\upsilon \searrow 0} [(y^2)^{-1} - (y^1)^{-1}] += \frac{1-\rho}{\rho} \left[(\omega^1 - \omega^2)\sigma_Y + \frac{(\omega^1 - \omega^2)^2}{2\gamma}\right] +$$ (eq:consumption_rates) + +括号中的项是*主观*期望投资组合收益之差——即主体 1 相对于主体 2 认为她所赚取的收益。 + +因子 $(1-\rho)/\rho$ 将这种感知到的收益优势转化为储蓄响应。 + +- 当 IES $> 1$($\rho < 1$)时,因子为正:更高的感知收益使主体储蓄更多,因为替代效应主导了收入效应。 +- 当 IES $< 1$($\rho > 1$)时,因子为负:收入效应占主导,主体储蓄更少,不利于生存。 +- 当 IES $= 1$($\rho = 1$)时,两种效应相互抵消,储蓄渠道完全消失。 + +这就是递归偏好通过将 $\gamma$ 与 $\rho$ 分离来改变生存结果的渠道。 + +```{exercise} +:label: ex_consumption_wealth + +推导 {eq}`eq:consumption_rates`。 + +在由主体 2 构成的齐次经济体中,消费-财富比为 $(y(0))^{-1} = \beta - (1-\rho)\mu_V^2$,其中 $\mu_V^2$ 是主体 2 财富的期望对数收益。 + +作为微不足道的价格接受者,主体 1 的消费-财富比为 $(y^1)^{-1} = \beta - (1-\rho)\mu_V^1$,其中 $\mu_V^1$ 是她自己的期望对数收益。 + +使用 $(y^2)^{-1} - (y^1)^{-1} = (1-\rho)(\mu_V^1 - \mu_V^2)$,并用主体 1 的*主观*期望超额收益表示 $\mu_V^1 - \mu_V^2$。 + +*提示:* 在主体 1 的信念下,她的投资组合在期望对数收益方面相对于主体 2 的投资组合多赚 $(\omega^1 - \omega^2)\sigma_Y + (\omega^1 - \omega^2)^2/(2\gamma)$。 +``` + +```{solution-start} ex_consumption_wealth +:class: dropdown +``` + +主体 $n$ 的消费-财富比满足 $(y^n)^{-1} = \beta - (1-\rho)\mu_V^n$,其中 $\mu_V^n$ 是主体 $n$ 在其自身主观测度下财富的期望对数收益。 + +取差: + +$$ +(y^2)^{-1} - (y^1)^{-1} = (1-\rho)(\mu_V^1 - \mu_V^2). +$$ + +主体 1 的主观期望对数投资组合收益超过主体 2 的部分,等于她认为通过向风险资产倾斜所获得的收益。 + +她额外的风险份额为 $\pi^1 - 1 = (\omega^1 - \omega^2)/(\gamma\sigma_Y)$,而在她的主观测度 $Q^1$ 下风险资产的期望超额对数收益为 $(\gamma\sigma_Y^2 + (\omega^1 - \omega^2)\sigma_Y - \omega^2\sigma_Y) - r - \frac{1}{2}\sigma_Y^2$。 + +化简后,主观期望对数收益之差为 + +$$ +\mu_V^1 - \mu_V^2 = (\omega^1 - \omega^2)\sigma_Y + \frac{(\omega^1 - \omega^2)^2}{2\gamma}. +$$ + +代入并整体除以 $\rho$(由 $(y^n)^{-1}$ 与 $\beta$ 之间的关系): + +$$ +(y^2)^{-1} - (y^1)^{-1} = \frac{1-\rho}{\rho}\left[(\omega^1 - \omega^2)\sigma_Y + \frac{(\omega^1 - \omega^2)^2}{2\gamma}\right]. +$$ + +```{solution-end} +``` + +### 两个比较静态分析 + +生存取决于 $\gamma$、$\rho$ 以及信噪比 $\omega^1 / \sigma_Y$ 和 $\omega^2 / \sigma_Y$,而非分别取决于 $\omega^1$、$\omega^2$ 和 $\sigma_Y$。 + +生存条件不依赖于 $\beta$ 或 $\mu_Y$,它们影响消费和价格的水平,但不影响边界处的相对财富动态。 + +```{code-cell} ipython3 +def portfolio_return_diff(ω_1, ω_2, γ, σ_y): + """ + 边界处期望对数投资组合收益之差。 + """ + Δω = ω_1 - ω_2 + risky_share_diff = Δω / (γ * σ_y) + risk_premium = γ * σ_y**2 - ω_2 * σ_y + volatility_term = (Δω / γ) * (σ_y + 0.5 * Δω / γ) + return risky_share_diff * risk_premium - volatility_term + + +def saving_channel(ω_1, ω_2, γ, ρ, σ_y): + """ + 边界处消费-财富比之差。 + """ + Δω = ω_1 - ω_2 + subjective_return_diff = Δω * σ_y + Δω**2 / (2 * γ) + return (1 - ρ) / ρ * subjective_return_diff + + +def boundary_drift(ω_1, ω_2, γ, ρ, σ_y): + """ + 当主体 1 变得微不足道时的边界漂移 m_ϑ。 + + 正漂移意味着主体 1 生存(排斥边界)。 + """ + return γ * ( + portfolio_return_diff(ω_1, ω_2, γ, σ_y) + + saving_channel(ω_1, ω_2, γ, ρ, σ_y) + ) +``` + +## 生存区域 + +{cite:t}`Borovicka2020` 的一个核心贡献是刻画了 $(\gamma, \rho)$ 平面中的生存区域。 + +在可分偏好下,$\gamma = \rho$,信念更准确的主体总是占据主导地位。 + +在递归偏好下,{prf:ref}`survival_conditions` 中的所有四种结果都可能出现。 + +文中的图 2 研究了主体 2 具有正确信念的情形,即 $\omega^2 = 0$。 + +下一个单元遵循该图。 + +```{code-cell} ipython3 +def compute_survival_boundary(ω_1, ω_2, σ_y, γ_grid, boundary="lower"): + """ + 计算 (γ, ρ) 空间中边界漂移为零的曲线。 + + 对于 boundary='lower',主体 1 是小主体。 + 对于 boundary='upper',主体 2 是小主体。 + """ + ρ_boundary = [] + + if boundary == "lower": + small_agent = (ω_1, ω_2) + else: + small_agent = (ω_2, ω_1) + + ω_small, ω_large = small_agent + + for γ in γ_grid: + pr = portfolio_return_diff(ω_small, ω_large, γ, σ_y) + Δω = ω_small - ω_large + subj_ret = Δω * σ_y + Δω**2 / (2 * γ) + + if abs(subj_ret) < 1e-14: + ρ_boundary.append(np.nan) + continue + + denom = subj_ret - pr + if abs(denom) < 1e-14: + ρ_boundary.append(np.nan) + else: + ρ_boundary.append(subj_ret / denom) + + return np.asarray(ρ_boundary) + + +def compute_limit_boundary(γ_grid, boundary="lower"): + """ + 极限 |ω_1| / σ_y -> ∞ 的边界曲线。 + + 这等价于文中讨论的常数禀赋情形。 + """ + if boundary == "lower": + return γ_grid / (1 + γ_grid) + + ρ = np.full_like(γ_grid, np.nan, dtype=float) + mask = γ_grid < 1 + ρ[mask] = γ_grid[mask] / (1 - γ_grid[mask]) + return ρ +``` + +```{code-cell} ipython3 +--- +tags: [hide-input] +mystnb: + figure: + caption: 对应于 Borovicka (2020) 图 2 的生存区域 + name: fig-survival-regions +--- +σ_y = 0.02 +γ_vals = np.linspace(0.01, 6.0, 500) +ρ_vals = np.linspace(0.01, 2.0, 400) +G, R = np.meshgrid(γ_vals, ρ_vals) + +panel_specs = [ + ("finite", 0.10, r"$\omega^1 = 0.10$"), + ("finite", 0.20, r"$\omega^1 = 0.20$"), + ("limit", None, r"$|\omega^1| / \sigma_Y \to \infty$"), + ("finite", -0.25, r"$\omega^1 = -0.25$"), +] + +fig, axes = plt.subplots(2, 2, figsize=(13, 10), sharex=True, sharey=True) + +for idx, (case, value, label) in enumerate(panel_specs): + ax = axes.flat[idx] + + if case == "limit": + ρ_1 = compute_limit_boundary(γ_vals, boundary="lower") + ρ_2 = compute_limit_boundary(γ_vals, boundary="upper") + # 极限边界漂移:使用闭式表达式 + # 当 ρ < γ/(1+γ) 时 m0 > 0(主体 1 生存) + m0 = G - (1 + G) * R + # 当 γ<1 时 ρ < γ/(1-γ) 时 m1 < 0(主体 2 生存),γ>=1 时总成立 + m1 = (1 - G) * R - G + else: + ρ_1 = compute_survival_boundary(value, 0.0, σ_y, γ_vals, + boundary="lower") + ρ_2 = compute_survival_boundary(value, 0.0, σ_y, γ_vals, + boundary="upper") + # 在网格上评估边界漂移 + m0 = boundary_drift(value, 0.0, G, R, σ_y) + m1 = -boundary_drift(0.0, value, G, R, σ_y) + + # 对所有四个区域进行分类 + both = (m0 > 0) & (m1 < 0) + ag1_dom = (m0 > 0) & (m1 > 0) + ag2_dom = (m0 < 0) & (m1 < 0) + either = (m0 < 0) & (m1 > 0) + + # 对共存区域着色 + ax.contourf(G, R, both.astype(float), levels=[0.5, 1.5], + colors=["C2"], alpha=0.18) + if idx == 0: + ax.fill_between([], [], color="C2", alpha=0.18, + label="两者都生存") + + # 绘制边界曲线 + ax.contour(G, R, m0, levels=[0], colors=["C0"], + linestyles="--", linewidths=2) + ax.contour(G, R, m1, levels=[0], colors=["C3"], + linestyles="-", linewidths=2) + if idx == 0: + ax.plot([], [], "--", color="C0", lw=2, label="主体 1 边界") + ax.plot([], [], "-", color="C3", lw=2, label="主体 2 边界") + + ax.plot( + γ_vals, γ_vals, ":", color="black", lw=2, + label=r"$\gamma = \rho$" if idx == 0 else None + ) + + tkw = dict(ha="center", va="center", style="italic", color="0.15") + if case == "finite" and value == 0.10: + ax.text(0.31, 1.05, "任一主体占主导", rotation=90, + fontsize=10, **tkw) + ax.text(1.8, 1.55, "主体 2\n占主导", fontsize=11, **tkw) + ax.text(3.5, 0.75, "两者\n都生存", fontsize=11, **tkw) + if ag1_dom.any(): + ax.text(5.0, 0.25, "主体 1\n占主导", fontsize=11, **tkw) + elif case == "finite" and value == 0.20: + ax.text(0.31, 1.05, "任一主体占主导", rotation=90, + fontsize=10, **tkw) + ax.text(2.5, 1.55, "主体 2\n占主导", fontsize=11, **tkw) + ax.text(3.8, 0.55, "两者\n都生存", fontsize=11, **tkw) + if ag1_dom.any(): + ax.text(5.2, 0.08, "主体 1\n占主导", fontsize=9, **tkw) + elif case == "limit": + ax.text(0.31, 1.05, "任一主体占主导", rotation=90, + fontsize=10, **tkw) + ax.text(3.0, 1.40, "主体 2\n占主导", fontsize=11, **tkw) + ax.text(3.5, 0.30, "两者\n都生存", fontsize=11, **tkw) + elif case == "finite" and value == -0.25: + ax.text(0.31, 1.05, "任一主体占主导", rotation=90, + fontsize=10, **tkw) + ax.text(3.5, 1.20, "主体 2\n占主导", fontsize=11, **tkw) + ax.text(2.5, 0.18, "两者\n都生存", fontsize=11, **tkw) + + ax.set_title(label, fontsize=12) + ax.set_xlim(0, 6) + ax.set_ylim(0, 2) + ax.set_xlabel(r"$\gamma$") + ax.set_ylabel(r"$\rho$") + +axes[0, 0].legend(loc="upper left", fontsize=9) +plt.tight_layout() +plt.show() +``` + +每个面板针对主体 1 的信念扭曲 $\omega^1$ 的不同取值(主体 2 具有正确信念,$\omega^2 = 0$)绘制 $(\gamma, \rho)$ 平面中的两条曲线。 + +- 虚线(蓝色)是 $\upsilon = 0$ 处边界漂移等于零的地方——{prf:ref}`survival_conditions` 中的条件 (i)。 +- 实线(红色)是 $\upsilon = 1$ 处边界漂移等于零的地方——条件 (ii)。 +- 两条曲线之间的阴影区域是两个主体都生存的地方。 +- 虚线对角线 $\gamma = \rho$ 是可分 CRRA 情形,沿此线信念更准确的主体总是占据主导地位。 + +适度乐观($\omega^1 = 0.10$)产生了一个宽阔的共存区域,横跨大部分 $\gamma$ 范围。 + +较强的乐观($\omega^1 = 0.20$)缩小了该区域:主体 2 边界对于中等和较大的 $\gamma$ 移出了绘图范围,缩小了两个主体共存的 $(\gamma, \rho)$ 对的集合。 + +在极限 $|\omega^1|/\sigma_Y \to \infty$(左下)中,边界简化为闭式表达式。 + +共存区域变窄,但在主体 2 边界曲线下方延伸到较大的 $\gamma$ 值。 + +悲观的扭曲($\omega^1 = -0.25$,右下)也可以生存,但仅在参数空间中窄得多的部分。 + +## 三个生存渠道 + +上述分解可以直接可视化。 + +```{code-cell} ipython3 +def decompose_survival(ω_1, ω_2, γ_grid, ρ, σ_y): + """ + 分解命题 3.4 中的财富增长差异。 + """ + Δω = ω_1 - ω_2 + risk_premium_term = Δω * (γ_grid * σ_y - ω_2) / γ_grid + volatility_term = -(Δω / γ_grid) * (σ_y + 0.5 * Δω / γ_grid) + saving_term = (1 - ρ) / ρ * (Δω * σ_y + Δω**2 / (2 * γ_grid)) + total = risk_premium_term + volatility_term + saving_term + return risk_premium_term, volatility_term, saving_term, total + + +ω_1 = 0.25 +ω_2 = 0.0 +ρ = 0.67 +σ_y = 0.02 +γ_grid = np.linspace(0.5, 15.0, 300) + +risk_term, vol_term, save_term, total = decompose_survival( + ω_1, ω_2, γ_grid, ρ, σ_y +) + +fig, ax = plt.subplots(figsize=(11, 6)) +ax.plot(γ_grid, risk_term, color="C0", lw=2, label="风险溢价项") +ax.plot(γ_grid, vol_term, "--", color="C3", lw=2, label="波动率项") +ax.plot(γ_grid, save_term, "-.", color="C2", lw=2, label="储蓄项") +ax.plot(γ_grid, total, color="black", lw=2, label="总计") +ax.axhline(0, color="gray", lw=1) +ax.set_xlabel(r"风险厌恶 $\gamma$") +ax.set_ylabel("对财富增长差异的贡献") +ax.legend() +plt.tight_layout() +plt.show() +``` + +此图将 $\upsilon = 0$ 处的边界漂移分解为三项,针对一个乐观主体($\omega^1 = {0.25}$,$\omega^2 = 0$),其 IES $= 1/\rho \approx 1.49$,$\sigma_Y = 0.02$。 + +- 风险溢价项(蓝色)始终为正,因为乐观主体超配了风险资产并赚取了股权溢价。 +- 波动率项(红色虚线)为负且在低 $\gamma$ 时较大,反映了持有波动投资组合的成本。 +- 储蓄项(绿色点划线)在 IES $> 1$ 时为正,因为乐观主体感知到财富的高收益并更激进地储蓄。 +- 总计(黑色)在临界 $\gamma$ 处穿过零点,低于此值波动率惩罚占主导,主体无法生存。 + +## 改变 IES + +储蓄项的符号由 IES 确定。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 不同 IES 值的边界分解 + name: fig-survival-ies-panels +--- +fig, axes = plt.subplots(1, 3, figsize=(16, 4.5), sharey=True) + +ω_1 = 0.25 +ω_2 = 0.0 +σ_y = 0.02 +γ_grid = np.linspace(0.5, 25.0, 300) + +ies_values = [0.5, 1.0, 1.5] + +for idx, ies in enumerate(ies_values): + ρ = 1.0 / ies + risk_term, vol_term, save_term, total = decompose_survival( + ω_1, ω_2, γ_grid, ρ, σ_y + ) + + ax = axes[idx] + ax.plot(γ_grid, risk_term, color="C0", lw=2, label="风险溢价") + ax.plot(γ_grid, vol_term, "--", color="C3", lw=2, label="波动率") + ax.plot(γ_grid, save_term, "-.", color="C2", lw=2, label="储蓄") + ax.plot(γ_grid, total, color="black", lw=2, label="总计") + ax.axhline(0, color="gray", lw=1) + ax.set_title(f"IES = {ies:.1f}", fontsize=12) + ax.set_xlabel(r"风险厌恶 $\gamma$") + ax.set_ylabel("贡献") + +axes[0].legend(fontsize=9) +plt.tight_layout() +plt.show() +``` + +每个面板显示与前一图相同的三项分解,但现在针对三种不同的 IES 值($\omega^1 = 0.25$,$\omega^2 = 0$,$\sigma_Y = 0.02$)。 + +- 左面板(IES $= 0.5$):储蓄项为负,因此乐观主体实际上储蓄更少,不利于生存。 +- 中面板(IES $= 1.0$):储蓄项完全消失,因此只剩下投资组合收益和波动率渠道。 + + - 这消除了储蓄渠道,但本身并不能重现完整的可分 CRRA 基准,后者要求 $\gamma = \rho$(即 IES $= 1/\gamma$),而不仅仅是 $\rho = 1$。 +- 右面板(IES $= 1.5$):储蓄项为正并将总漂移向上移动,扩大了乐观主体生存的 $\gamma$ 值范围。 + +## 渐近结果 + +Borovicka 推导了几个有用的渐近结果。 + +1. 当 $\gamma \searrow 0$ 时,每个主体都以严格正概率占据主导地位。 +1. 当 $\gamma \nearrow \infty$ 时,相对更乐观的主体占据主导地位。 +1. 当 $\rho \searrow 0$ 时,相对更乐观的主体总是生存。 + - 当风险厌恶足够低时,相对更悲观的主体也可以生存。 +1. 当 $\rho \nearrow \infty$ 时,非退化的长期均衡不可能存在。 + +下一个图通过绘制 $\gamma$ 变小时的两个边界漂移来说明第一个结果。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 小风险厌恶下的边界漂移 + name: fig-boundary-drifts-small-gamma +--- +ω_1 = 0.25 +ω_2 = 0.0 +ρ = 0.67 +σ_y = 0.02 +γ_grid = np.linspace(0.05, 5.0, 300) + +drift_at_0 = np.array([boundary_drift(ω_1, ω_2, γ, ρ, σ_y) for γ in γ_grid]) +drift_at_1 = np.array([-boundary_drift(ω_2, ω_1, γ, ρ, σ_y) for γ in γ_grid]) + +fig, ax = plt.subplots(figsize=(10, 5)) +ax.plot(γ_grid, drift_at_0, color="C0", lw=2, label=r"$\upsilon \to 0$") +ax.plot(γ_grid, drift_at_1, "--", color="C3", lw=2, label=r"$\upsilon \to 1$") +ax.axhline(0, color="gray", lw=1) +ax.set_xlabel(r"风险厌恶 $\gamma$") +ax.set_ylabel("边界漂移") +ax.legend() +plt.tight_layout() +plt.show() +``` + +此图将两个边界漂移绘制为 $\gamma$ 的函数($\omega^1 = 0.25$,$\omega^2 = 0$,IES $\approx 1.49$)。 + +- 实线蓝色曲线是 $\upsilon \to 0$ 处的漂移 $m_\vartheta$(主体 1 接近消亡);共存要求这为正(条件 (i))。 +- 虚线红色曲线是 $\upsilon \to 1$ 处的漂移 $m_\vartheta$(主体 2 接近消亡);共存要求这为负(条件 (ii))。 + +此图说明了渐近结果 1。 + +对于小 $\gamma$,蓝色曲线为负,红色曲线为正。 + +两个边界都是吸引的:在 $\upsilon = 0$ 附近负漂移将 $\upsilon$ 拉向 0,在 $\upsilon = 1$ 附近正漂移将 $\upsilon$ 推向 1。 + +这是 {prf:ref}`survival_conditions` 中的结果 (d):两个边界都不是排斥的,因此无论哪个主体碰巧早期领先都将占据主导地位,每个主体都有严格正概率占据主导地位,这取决于实现的布朗路径。 + +随着 $\gamma$ 增大超过大约 1,蓝色曲线穿过零点变为正,而红色曲线保持为负。 + +现在两个边界都是排斥的,我们进入共存区域——结果 (a)。 + +## 可分情形 + +当 $\gamma = \rho$ 时,模型退化为可分 CRRA 基准。 + +在这种情形下,对数几率过程变为 + +$$ +d\vartheta_t = \frac{1}{2}\left[(\omega^2)^2 - (\omega^1)^2\right] dt + (\omega^1 - \omega^2) dW_t . +$$ + +漂移是常数,且仅取决于两个信念扭曲的相对熵。 + +$|\omega^n|$ 较小的主体在 $P$ 下占据主导地位。 + +如果两个主体的信念扭曲幅度相等,则几乎必然没有一个主体会消亡,但不存在非退化的平稳财富分布。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 可分基准中的帕累托份额路径 + name: fig-crra-pareto-paths +--- +def simulate_crra_pareto(ω_1, ω_2, T, dt, n_paths, seed=42): + """ + 模拟可分基准中的帕累托份额动态。 + """ + rng = np.random.default_rng(seed) + n_steps = int(T / dt) + t_grid = np.linspace(0, T, n_steps + 1) + + drift = 0.5 * (ω_2**2 - ω_1**2) + volatility = ω_1 - ω_2 + + θ = np.zeros((n_paths, n_steps + 1)) + dW = rng.normal(0.0, np.sqrt(dt), size=(n_paths, n_steps)) + + for t in range(n_steps): + θ[:, t + 1] = θ[:, t] + drift * dt + volatility * dW[:, t] + + υ_paths = 1.0 / (1.0 + np.exp(-θ)) + return t_grid, υ_paths + + +ω_1 = 0.10 +ω_2 = 0.0 +t_grid, υ_paths = simulate_crra_pareto(ω_1, ω_2, T=200, dt=0.01, n_paths=50) + +fig, ax = plt.subplots(figsize=(11, 5)) + +for i in range(20): + ax.plot(t_grid, υ_paths[i], color="C0", alpha=0.25, lw=1) + +ax.axhline(0.5, color="gray", linestyle=":", lw=1) +ax.set_xlabel("时间") +ax.set_ylabel(r"帕累托份额 $\upsilon_t$") +ax.set_ylim(0, 1) +plt.tight_layout() +plt.show() +``` + +此图模拟了在可分 CRRA 偏好($\gamma = \rho$)下帕累托份额 $\upsilon_t$ 的 20 条样本路径,其中 $\omega^1 = 0.10$ 且 $\omega^2 = 0$。 + +主体 2 具有正确信念,因此对数几率漂移为负,所有路径都趋向于 $\upsilon = 0$。 + +主体 1 被驱向消亡——这是 {cite:t}`Blume_Easley2006` 的经典市场选择结果。 + +## 资产定价含义 + +随着一个主体变得微不足道,当前价格收敛于由大主体构成的齐次经济体的价格。 + +当主体 2 是大主体时,{cite:t}`Borovicka2020` 中的命题 5.1 意味着 + +$$ +\lim_{\upsilon \searrow 0} r(\upsilon) += \beta + \rho \left(\mu_Y + \omega^2 \sigma_Y ++ \frac{1}{2} (1 - \gamma) \sigma_Y^2\right) +- \frac{1}{2} \gamma \sigma_Y^2 +$$ (eq:riskfree) + +以及 + +$$ +\lim_{\upsilon \searrow 0} y(\upsilon) += \left[ +\beta - (1 - \rho) +\left( +\mu_Y + \omega^2 \sigma_Y + \frac{1}{2} (1 - \gamma) \sigma_Y^2 +\right) +\right]^{-1} . +$$ (eq:wc_ratio) + +总财富动态也收敛于齐次经济体的动态: + +$$ +\lim_{\upsilon \searrow 0} m_A(\upsilon) = \mu_Y, +\qquad +\lim_{\upsilon \searrow 0} \sigma_A(\upsilon) = \sigma_Y . +$$ + +命题 5.3 随后给出了微不足道主体自己的消费-储蓄和投资组合选择。 + +她的消费-财富比收敛于 + +$$ +\lim_{\upsilon \searrow 0} (y^1(\upsilon))^{-1} += (y(0))^{-1} +- \frac{1-\rho}{\rho} +\left[ +(\omega^1 - \omega^2)\sigma_Y ++ \frac{(\omega^1 - \omega^2)^2}{2 \gamma} +\right] . +$$ + +小主体的风险资产份额收敛于 + +$$ +\lim_{\upsilon \searrow 0} \pi^1(\upsilon) += 1 + \frac{\omega^1 - \omega^2}{\gamma \sigma_Y} . +$$ (eq:portfolio) + +因此乐观意味着杠杆,而足够强的悲观意味着做空。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 小主体的极限风险资产份额 + name: fig-limiting-portfolio-shares +--- +ω_2 = 0.0 +σ_y = 0.02 +ω_grid = np.linspace(-0.5, 1.0, 300) + +fig, ax = plt.subplots(figsize=(10, 5)) + +for γ in [2, 5, 10, 20]: + π_1 = 1 + (ω_grid - ω_2) / (γ * σ_y) + ax.plot(ω_grid, π_1, lw=2, label=rf"$\gamma = {γ}$") + +ax.axhline(1.0, color="gray", linestyle=":", lw=1) +ax.axhline(0.0, color="gray", linestyle=":", lw=1) +ax.axvline(0.0, color="gray", linestyle=":", lw=1) +ax.set_xlabel(r"信念扭曲 $\omega^1$") +ax.set_ylabel(r"风险份额 $\pi^1$") +ax.legend() +plt.tight_layout() +plt.show() +``` + +此图将微不足道主体的极限风险资产份额 $\pi^1$ 绘制为她的信念扭曲 $\omega^1$ 的函数($\omega^2 = 0$,$\sigma_Y = 0.02$),针对四个风险厌恶水平。 + +在 $\omega^1 = 0$ 处,主体与主体 2 意见一致并持有市场投资组合($\pi^1 = 1$)。 + +乐观($\omega^1 > 0$)导致杠杆($\pi^1 > 1$),而足够的悲观($\omega^1 < 0$)导致做空($\pi^1 < 0$)。 + +较高的风险厌恶将这些偏离压缩至接近 1。 + +## 乐观和悲观扭曲 + +乐观和悲观信念对生存的影响是不对称的。 + +乐观主体从风险溢价项中获益,并且当 IES $> 1$ 时,也从储蓄项中获益。 + +悲观主体放弃了风险溢价,只有当储蓄效应足够强以抵消该损失时才能生存。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 乐观和悲观扭曲的总边界漂移 + name: fig-optimistic-pessimistic-drifts +--- +fig, axes = plt.subplots(1, 2, figsize=(14, 5), sharey=True) + +σ_y = 0.02 +ω_2 = 0.0 +ρ = 0.67 +γ_grid = np.linspace(0.5, 25.0, 300) + +ax = axes[0] +for ω_1 in [0.1, 0.25, 0.5, 1.0]: + _, _, _, total = decompose_survival(ω_1, ω_2, γ_grid, ρ, σ_y) + ax.plot(γ_grid, total, lw=2, label=rf"$\omega^1 = {ω_1}$") +ax.axhline(0, color="gray", lw=1) +ax.set_title("乐观", fontsize=12) +ax.set_xlabel(r"风险厌恶 $\gamma$") +ax.set_ylabel("边界漂移") +ax.legend(fontsize=9) + +ax = axes[1] +for ω_1 in [-0.1, -0.25, -0.5, -1.0]: + _, _, _, total = decompose_survival(ω_1, ω_2, γ_grid, ρ, σ_y) + ax.plot(γ_grid, total, lw=2, label=rf"$\omega^1 = {ω_1}$") +ax.axhline(0, color="gray", lw=1) +ax.set_title("悲观", fontsize=12) +ax.set_xlabel(r"风险厌恶 $\gamma$") +ax.legend(fontsize=9) + +plt.tight_layout() +plt.show() +``` + +两个面板都将 $\upsilon = 0$ 处的总边界漂移绘制为 $\gamma$ 的函数(IES $\approx 1.49$,$\omega^2 = 0$)。 + +曲线为正的地方,主体 1 在接近消亡时生存。 + +- 左面板(乐观主体):较大的 $\omega^1$ 意味着对风险资产更大的押注,因此波动率惩罚在低 $\gamma$ 时占主导,但一旦 $\gamma$ 足够大漂移转为正。 +- 右面板(悲观主体):悲观主体通过低配风险资产放弃了风险溢价,因此漂移在大部分参数空间内为负,生存需要足够强的储蓄动机以抵消投资组合损失。 + +## 长期消费分布 + +当两个主体都生存时,帕累托份额持续在整个区间 $(0, 1)$ 中移动。 + +下一个模拟只是一个玩具近似。 + +它在两个边界值之间插值漂移,因此在不求解完整均衡 ODE 的情况下说明了常返逻辑。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 一个玩具平稳帕累托份额模拟 + name: fig-toy-stationary-pareto-share +--- +def simulate_pareto_share_toy(ω_1, ω_2, γ, ρ, σ_y, T, dt, n_paths=20, seed=42): + """ + 通过插值边界漂移模拟玩具帕累托份额过程。 + """ + rng = np.random.default_rng(seed) + n_steps = int(T / dt) + t_grid = np.linspace(0, T, n_steps + 1) + + volatility = ω_1 - ω_2 + m_0 = boundary_drift(ω_1, ω_2, γ, ρ, σ_y) + m_1 = -boundary_drift(ω_2, ω_1, γ, ρ, σ_y) + + θ = np.zeros((n_paths, n_steps + 1)) + dW = rng.normal(0.0, np.sqrt(dt), size=(n_paths, n_steps)) + + for t in range(n_steps): + υ = 1.0 / (1.0 + np.exp(-θ[:, t])) + drift = m_0 * (1 - υ) + m_1 * υ + θ[:, t + 1] = θ[:, t] + drift * dt + volatility * dW[:, t] + + υ_paths = 1.0 / (1.0 + np.exp(-θ)) + return t_grid, υ_paths + + +ω_1 = 0.25 +ω_2 = 0.0 +γ = 5.0 +ρ = 0.67 +σ_y = 0.02 + +t_grid, υ_paths = simulate_pareto_share_toy( + ω_1, ω_2, γ, ρ, σ_y, T=500, dt=0.05, n_paths=50, seed=42 +) + +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +ax = axes[0] +for i in range(20): + ax.plot(t_grid, υ_paths[i], color="C0", alpha=0.25, lw=1) +ax.axhline(0.5, color="gray", linestyle=":", lw=1) +ax.set_title("样本路径", fontsize=12) +ax.set_xlabel("时间") +ax.set_ylabel(r"帕累托份额 $\upsilon_t$") +ax.set_ylim(0, 1) + +ax = axes[1] +_, υ_long = simulate_pareto_share_toy( + ω_1, ω_2, γ, ρ, σ_y, T=2000, dt=0.05, n_paths=5, seed=123 +) +υ_stationary = υ_long[:, υ_long.shape[1] // 2:].ravel() +ax.hist(υ_stationary, bins=80, density=True, color="steelblue", + edgecolor="white", alpha=0.7) +ax.set_title("近似平稳密度", fontsize=12) +ax.set_xlabel(r"帕累托份额 $\upsilon$") +ax.set_ylabel("密度") +ax.set_xlim(0, 1) + +plt.tight_layout() +plt.show() +``` + +左面板显示了在共存区域内的参数下帕累托份额 $\upsilon_t$ 的 20 条样本路径($\omega^1 = 0.25$,$\omega^2 = 0$,$\gamma = 5$,IES $\approx 1.49$)。 + +与 {numref}`fig-crra-pareto-paths` 中的可分情形不同,这些路径不会漂向零——它们反复访问广泛的取值范围,在两个排斥边界之间来回弹跳。 + +右面板通过汇集较长模拟的后半部分来近似平稳密度。 + +内部模态与两个主体都不被驱向消亡相一致。 + +然而,这个玩具插值仅仅说明了常返逻辑;它并不重现 {cite:t}`Borovicka2020` 图 4 中定量的平稳消费份额密度,后者需要求解完整的内部均衡 ODE。 + +## 总结 + +递归偏好削弱了经典的市场选择结果。 + +投资组合收益渠道仍然奖励更乐观的信念。 + +波动率渠道仍然惩罚激进的头寸。 + +但当 IES $> 1$ 时,储蓄渠道可以足够强以使具有扭曲信念的主体存活。 + +这就是为什么递归偏好经济体可以支持在信念和投资组合头寸方面具有持续异质性的平稳长期财富分布。 \ No newline at end of file diff --git a/lectures/theil_1.md b/lectures/theil_1.md new file mode 100644 index 0000000..3a4d8f5 --- /dev/null +++ b/lectures/theil_1.md @@ -0,0 +1,411 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 确定性等价 + headings: + Overview: 概述 + A central problem of empirical economics: 实证经济学的一个核心问题 + A formal setup: 形式化的设定 + Estimated rules are not enough: 仅有估计的规则是不够的 + An optimization problem: 一个优化问题 + A linear-quadratic DP problem and certainty equivalence: 一个线性二次动态规划问题与确定性等价 + A linear-quadratic DP problem and certainty equivalence::Decomposition of $h$: $h$ 的分解 + A linear-quadratic DP problem and certainty equivalence::The separation principle: 分离原理 + A linear-quadratic DP problem and certainty equivalence::Certainty equivalence and perfect foresight: 确定性等价与完全预见 + A linear-quadratic DP problem and certainty equivalence::Cross-equation restrictions: 跨方程约束 + A trouble with ad hoc expectations: 特设预期的一个问题 + Exercises: 练习 + Concluding remarks: 结束语 +--- + +(certainty_equiv_theil1)= +```{raw} jupyter + +``` + +# 确定性等价 + +```{index} single: Certainty Equivalence; Robustness +``` + +```{index} single: LQ Control; Permanent Income +``` + +```{contents} Contents +:depth: 2 +``` + + +除了 Anaconda 中已有的库之外,本讲座还需要以下库: + +```{code-cell} ipython3 +--- +tags: [hide-output] +--- +!pip install quantecon +``` + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from quantecon import LQ +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 概述 + +{cite:t}`simon1956dynamic` 和 {cite:t}`theil1957note` 为线性二次(LQ)动态规划问题建立了著名的*确定性等价*(CE)性质。 + +他们的结果证明了一种便捷的两步算法是合理的: + +1. **优化**——在完全预见下进行优化(将未来外生变量视为已知)。 +2. **预测**——用最优预测替代未知的未来值。 + +其惊人的洞见在于,这两个步骤是完全可分离的。 + +从第 1 步得出的决策规则与原始随机问题的决策规则*完全相同*,只要在第 2 步中代入最优预测即可。 + +决策规则不依赖于冲击的方差,但最优值函数的*水平*却依赖于它。 + +在详细描述确定性等价性质的结构之后,本讲座将描述其在理性预期建模中的作用。 + +我们在此大量借鉴了 {cite:t}`lucas1981rational` 的引言。 + +除了学习确定性等价原理外,本讲座还描述了 {cite:t}`lucas1976econometric` 所述的前理性预期计量经济政策评估程序所存在的问题。 + +```{note} +该卷收录了关于理性预期建模与计量经济学的早期论文。 +``` + +## 实证经济学的一个核心问题 + +为了铺垫背景,{cite:t}`lucas1981rational` 陈述了由 Leonid Hurwicz({cite}`Hurwicz:1962`)提出的实证经济学核心问题: + + * 给定对某个特定经济环境中某主体行为的观测,如果环境发生了改变,我们能推断出该行为*会有何不同*吗? + +```{note} +Hurwicz 将"因果关系"的概念表述为一个依赖于具体情境的概念,并将其置于一个良好定义的决策问题的框架下加以阐述。 +``` + +这就是在以下情境中的策略不变结构推断问题。 + + * 观测是在一种环境或"制度"下产生的 + * 我们想要预测在另一种"制度"下的行为 + * 除非我们理解主体在历史制度中*为何*如此行事,即他们的目的,否则我们无法预测他们在新制度所面临约束下的行为。 + +为了面对 Hurwicz 提出的问题,{cite:t}`lucas1981rational` 构建了以下决策框架。 + +## 形式化的设定 + +考虑一个单一的决策者,其在日期 $t$ 的状况由两个状态变量 $(x_t, z_t)$ 完全描述。 + +**环境** $z_t \in S_1$ 由"自然"选定,并按照以下方式外生地演化 + +```{math} +:label: eq:z_transition_v3 +z_{t+1} = f(z_t,\, \epsilon_{t+1}), +``` + +其中创新项 $\{\epsilon_t\}$ 是从固定 CDF $\Phi(\cdot) : \mathcal{E} \to [0,1]$ 中独立同分布抽取的。 + +函数 $f : S_1 \times \mathcal{E} \to S_1$ 被称为**决策者的环境**。 + +**内生状态** $x_t \in S_2$ 部分处于主体的控制之下。 + +每一期主体选择一个动作 $u_t \in U$。 + +一个固定的技术 $g : S_1 \times S_2 \times U \to S_2$ 支配着转移 + +```{math} +:label: eq:x_transition_v3 +x_{t+1} = g(z_t,\, x_t,\, u_t). +``` + +**决策规则** $h : S_1 \times S_2 \to U$ 将主体的当前状况映射为一个动作: + +```{math} +:label: eq:decision_rule_v3 +u_t = h(z_t,\, x_t). +``` + +计量经济学家观测到过程 $\{z_t, x_t, u_t\}$(的部分或全部),其联合运动由 {eq}`eq:z_transition_v3`、{eq}`eq:x_transition_v3` 和 {eq}`eq:decision_rule_v3` 决定。 + + +## 仅有估计的规则是不够的 + +假设我们已从一个在固定环境 $f_0$ 下生成的长时间序列中估计出了 $f$、$g$ 和 $h$。 + +这给出了 $h_0 = T(f_0)$,其中 $T$ 是将环境映射到最优决策规则的(未知)泛函映射。 + +但无论这个单一估计多么精确,它都*无法揭示*关于 $T(f)$ 如何随 $f$ 变化的任何信息。 + +策略评估需要了解整个映射 $f \mapsto T(f)$。 + +在环境变化 $f_0 \to f_1$ 下,主体通常会修正他们的决策规则 $h_0 \to h_1 = T(f_1)$,从而使估计出的规则 $h_0$ 无法用于预测 $f_1$ 下的行为。 + +{cite:t}`lucas1976econometric` 和 {cite:t}`lucas1981rational` 的引言得出结论:唯一可行的非实验路径是恢复**回报函数** $V$——$h$ 是作为该优化问题的解从中推导出来的——然后在反事实环境 $f_1$ 下重新求解该问题。 + + +## 一个优化问题 + +假设主体选择 $h$ 以最大化当期回报 $V : S_1 \times S_2 \times U \to \mathbb{R}$ 的期望贴现总和: + +```{math} +:label: eq:objective_v3 +E_0\!\left\{\sum_{t=0}^{\infty} \beta^t\, V(z_t,\, x_t,\, u_t)\right\}, \qquad 0 < \beta < 1, +``` + +给定初始条件 $(z_0, x_0)$、环境 $f$ 和技术 $g$。 + +这里 $E_0\{\cdot\}$ 表示在给定 $(z_0, x_0)$ 的条件下,关于由 {eq}`eq:z_transition_v3` 所诱导的 $\{z_1, z_2, \ldots\}$ 分布的期望。 + +原则上,对 $V$ 的了解(连同 $g$ 和 $f$)使人们能够在理论上计算 $h = T(f)$,从而对任何反事实的 $f$ 追踪出 $T(f)$。 + +本质的问题在于,$V$ 本身能否从对 $\{f, g, h\}$ 的观测中恢复出来。 + +```{note} +决策规则一般是一个泛函 $h = T(f, g, V)$。 +在正文中对 $g$ 和 $V$ 的依赖被略去了,但在需要时会显式表明。 +``` + + +## 一个线性二次动态规划问题与确定性等价 + +要超越上一节的一般性水平取得进展,需要对基本要素加以限制。 + +在 {cite:t}`lucas1981rational` 所收录的论文中所采用的一种富有成效的限制是,令 $V$ 为*二次的*、$g$ 为*线性的*,这就迫使 $h$ 成为线性的。 + +作为其计算易处理性的一部分,这种特殊化给出了一个惊人的结构性结果: + +* {cite:t}`simon1956dynamic` 和 {cite:t}`theil1957note` 的**确定性等价**定理。 + +### $h$ 的分解 + +在二次 $V$ 和线性 $g$ 的条件下,最优决策规则 $h$ 分解为按顺序应用的两个组成部分。 + +**第 1 步——预测。** 定义对所有当前及未来自然状态的最优点预测的无穷序列: + +```{math} +:label: eq:forecast_sequence_v3 +\tilde{z}_t \;=\; \bigl(z_t,\;\; {}_{t+1}z_t^e,\;\; {}_{t+2}z_t^e,\;\ldots\bigr) \;\in\; S_1^\infty, +``` + +其中 ${}_{t+j}z_t^e$ 表示在时刻 $t$ 形成的对 $z_{t+j}$ 的最小均方误差预测。 + +最优预测序列是当前状态的一个(通常是非线性的)函数: + +```{math} +:label: eq:forecast_rule_v3 +\tilde{z}_t = h_2(z_t). +``` + +函数 $h_2 : S_1 \to S_1^\infty$ 完全依赖于环境 $(f, \Phi)$,并且作为一个**纯预测问题**的解而获得,与偏好或技术无关。 + +**第 2 步——优化。** 给定预测序列 $\tilde{z}_t$,最优动作是 $\tilde{z}_t$ 和 $x_t$ 的一个**线性**函数: + +```{math} +:label: eq:optimization_rule_v3 +u_t = h_1(\tilde{z}_t,\, x_t). +``` + +函数 $h_1 : S_1^\infty \times S_2 \to U$ 完全依赖于偏好 $(V)$ 和技术 $(g)$,而**不**依赖于随机环境 $(f, \Phi)$。 + +因此,最终的决策规则是**复合**: + +```{math} +:label: eq:composite_rule_v3 +\boxed{h(z_t, x_t) \;=\; h_1\!\bigl[h_2(z_t),\; x_t\bigr].} +``` + +### 分离原理 + +{eq}`eq:composite_rule_v3` 体现了 $h$ 中两个依赖来源的清晰**分离**: + +| 组成部分 | 依赖于 | 独立于 | +|-----------|-----------|----------------| +| $h_1$(优化) | $V$、$g$ | $f$、$\Phi$ | +| $h_2$(预测) | $f$、$\Phi$ | $V$、$g$ | + +由于策略分析关注的是 $f$ 的变化,而 $h_1$ 对 $f$ 保持不变,策略分析者只需在新环境下重新求解预测问题 $h_2 = S(f)$,同时保持 $h_1$ 固定。 + +最初关注的关系 $h = T(f)$ 随后即可直接由 {eq}`eq:composite_rule_v3` 得出。 + +### 确定性等价与完全预见 + +"确定性等价"这一名称反映了 LQ 结构的一个进一步含义:函数 $h_1$ 可以像主体**确定地知道未来路径 $z_{t+1}, z_{t+2}, \ldots$** 那样推导出来——即通过求解确定性问题,其中 $\tilde{z}_t$ 被视为实现的路径而非预测。 + +环境的随机性仅通过预测 $\tilde{z}_t$ 影响动作;给定 $\tilde{z}_t$,优化问题就是确定性的。 + +这意味着 LQ 问题解耦为: + + * **完全预见下的动态优化**——通过将 $\tilde{z}_t$ 视为已知,从 $(V, g)$ 求解 $h_1$,得到一个标准的确定性 LQ 调节器问题,它独立于环境 $(f, \Phi)$。 + + * **最优线性预测**——使用最小二乘预测理论从 $(f, \Phi)$ 求解 $h_2 = S(f)$,当 $f$ 本身是线性的时,这就归结为标准的卡尔曼/维纳预测公式。 + +### 跨方程约束 + +理性预期假设在此框架中呈现的一个标志性特征是,它将本来在不同方程中会是自由参数的东西联系在一起。 + +$\tilde{z}_t = h_2(z_t) = S(f)(z_t)$ 的要求——即主体的预测相对于*实际的*运动规律 $f$ 是*最优的*——在预测规则 $h_2$ 的参数与环境 $f$ 的参数之间强加了**跨方程约束**。 + +正是这些约束,而非任何关于单个方程内分布滞后的条件,才是理性预期起作用的经验内容。 + +```{note} +这是 {cite:t}`lucas1976econometric` 和 {cite:t}`sargent1981interpreting` 所传达的信息。 +``` + +以下代码在数值上验证了 CE 原理。 + +我们考虑一个简单的标量 LQ 问题: + +$$y_{t+1} = a\, y_t + b\, u_t + \sigma\, \varepsilon_{t+1}, \qquad r(y_t, u_t) = -(q\, y_t^2 + r\, u_t^2)$$ + +并在一个宽泛的范围内改变噪声标准差 $\sigma$。 + +CE 定理预测: + +* **策略增益** $F$(即 $u_t = -F y_t$ 中的系数)独立于 $\sigma$,并且 +* **值常数** $d$(即 $V(y) = -y^\top P y - d$ 中的加性项)随 $\sigma$ 增长。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "CE:策略不依赖于噪声" + name: fig-ce-policy-noise +--- +a, b_coeff = 0.9, 1.0 +q, r = 1.0, 1.0 +β = 0.95 + +A = np.array([[a]]) +B = np.array([[b_coeff]]) +R_mat = np.array([[q]]) # 状态成本 +Q_mat = np.array([[r]]) # 控制成本 + +σ_vals = np.linspace(0.0, 3.0, 80) +F_vals, d_vals = [], [] + +for σ in σ_vals: + C = np.array([[σ]]) + lq = LQ(Q_mat, R_mat, A, B, C=C, beta=β) + P, F, d = lq.stationary_values() + F_vals.append(float(F[0, 0])) + d_vals.append(float(d)) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].plot(σ_vals, F_vals, lw=2) +axes[0].set_xlabel('噪声水平 $\\sigma$') +axes[0].set_ylabel('策略增益 $F$') +axes[0].set_title('策略增益') +axes[0].set_ylim(0, 2 * max(F_vals) + 0.1) + +axes[1].plot(σ_vals, d_vals, lw=2, color='C1') +axes[1].set_xlabel('噪声水平 $\\sigma$') +axes[1].set_ylabel('值常数 $d$') +axes[1].set_title('值常数') +fig.tight_layout() +plt.show() +``` + +正如图所证实的那样,$F$(策略增益)在所有噪声水平上都是*平坦的*,而值常数 $d$ 随 $\sigma$ 单调增加。 + +这就是 CE 原理的实际体现:不确定性改变了问题的值,但没有改变最优决策规则。 + + +## 特设预期的一个问题 + +先前的做法,以 {cite:t}`Friedman1956` 和 {cite:t}`Cagan` 的适应性预期机制为例,直接假设了 {eq}`eq:forecast_rule_v3` 的一种特定形式: + +```{math} +:label: eq:adaptive_expectations_v3 +\theta_t^e = \lambda \sum_{i=0}^{\infty} (1-\lambda)^i\, \theta_{t-i}, \qquad 0 < \lambda < 1, +``` + +将系数 $\lambda$ 视为一个待从数据中估计的自由参数,而不参考底层环境 $f$。 + +其缺陷不在于 {eq}`eq:adaptive_expectations_v3` 是一个分布滞后——线性预测规则是完全可以接受的简化。 + +缺陷在于分布滞后的**系数**未受理论约束。 + +映射 $h_2 = S(f)$ 表明,最优预测系数是由 $f$ *决定*的:当 $f$ 改变时,$h_2$ 改变,$h$ 也随之改变。 + +因此,在 $f_0$ 下校准的估计 $\lambda$ 是非结构性的,只要 $f$ 发生改变,它就会给出不正确的预测。 + +这就是 {cite:t}`Muth1960` 所发表批评的计量经济学内容。 + +理性预期将主体在形成 $\tilde{z}_t$ 时所使用的主观分布等同于实际生成数据的客观分布 $f$,从而闭合模型并消除 $h_2$ 中的自由参数。 + + +## 练习 + +```{exercise-start} +:label: theil1_ex1 +``` + +使用上面代码单元中的标量 LQ 设定(其中 $a = 0.9$、$b = 1$、 +$q = r = 1$、$\beta = 0.95$),在数值上验证值常数 $d$ +满足 $d \propto \sigma^2$。 + +*提示:* 从 CE 分析来看,值常数满足 +$d = \tfrac{\beta}{1-\beta}\,\mathrm{tr}(C^\top P C)$, +并且由于在标量情况下 $C = \sigma$,这给出 +$d = \tfrac{\beta}{1-\beta}\, P\, \sigma^2$。 + +确认 $d$ 关于 $\sigma^2$ 的图是线性的,并计算理论 +斜率 $\tfrac{\beta}{1-\beta} P$。 + +```{exercise-end} +``` + +```{solution-start} theil1_ex1 +:class: dropdown +``` + +```{code-cell} ipython3 +σ_sq_vals = σ_vals ** 2 + +fig, ax = plt.subplots() +ax.plot(σ_sq_vals, d_vals, lw=2) +ax.set_xlabel('$\\sigma^2$') +ax.set_ylabel('值常数 $d$') + +coeffs = np.polyfit(σ_sq_vals, d_vals, 1) +ax.plot(σ_sq_vals, np.polyval(coeffs, σ_sq_vals), + 'r--', lw=2, label=f'线性拟合:斜率 = {coeffs[0]:.3f}') +ax.legend() +fig.tight_layout() +plt.show() + +P_scalar = float(LQ(Q_mat, R_mat, A, B, C=np.zeros((1, 1)), + beta=β).stationary_values()[0].item()) +theoretical_slope = β / (1 - β) * P_scalar +print(f"经验斜率: {coeffs[0]:.4f}") +print(f"理论斜率 β/(1-β)*P = {theoretical_slope:.4f}") +``` + +斜率确实是 $\tfrac{\beta}{1-\beta} P$,从而证实了这个解析公式。 + +值矩阵 $P$ 完全由偏好和技术决定,而不由噪声水平决定——这是确定性等价原理的一个直接结果。 + +```{solution-end} +``` + +## 结束语 + +本讲座的续篇 [确定性等价与模型不确定性](theil_2) 描述了如何将确定性等价原理扩展到一个线性二次的设定中,在该设定中决策者不信任其基准模型所设定的转移动态。 \ No newline at end of file diff --git a/lectures/theil_2.md b/lectures/theil_2.md new file mode 100644 index 0000000..4011581 --- /dev/null +++ b/lectures/theil_2.md @@ -0,0 +1,781 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +translation: + title: 确定性等价与模型不确定性 + headings: + Overview: 概述 + Overview::Model features: 模型特征 + 'Recap: ordinary certainty equivalence': 回顾:普通确定性等价 + Model uncertainty and robustness: 模型不确定性与稳健性 + Model uncertainty and robustness::Setup and the multiplier problem: 设定与乘数问题 + Model uncertainty and robustness::Stackelberg timing and the modified CE: Stackelberg 时序与修正后的 CE + Model uncertainty and robustness::Modified separation principle: 修正后的分离原理 + Value function under robustness: 稳健性下的值函数 + Risk-sensitive preferences: 风险敏感偏好 + 'Application: permanent income model': 应用:永久收入模型 + 'Application: permanent income model::Model setup': 模型设定 + 'Application: permanent income model::Without robustness: Hall''s martingale': 无稳健性:Hall 的鞅 + 'Application: permanent income model::With robustness: precautionary savings': 有稳健性:预防性储蓄 + 'Application: permanent income model::Observational equivalence: robustness acts like patience': 观测等价性:稳健性表现得像耐心 + Summary: 小结 + Exercises: 练习 +--- + +(certainty_equiv_robustness)= +```{raw} jupyter + +``` + +# 确定性等价与模型不确定性 + +```{index} single: Certainty Equivalence; Robustness +``` + +```{index} single: LQ Control; Permanent Income +``` + +```{contents} Contents +:depth: 2 +``` + + + +## 概述 + + +本讲是 [关于确定性等价的这一讲](theil_1) 的续篇,该讲为线性二次型(LQ)动态规划问题建立了一个重要的*确定性等价*(CE)性质。 + +该性质证明了一个用于计算最优决策规则的两步算法是合理的: + +1. 在完全预见下*优化*(将未来外生变量视为已知)。 +2. *预测* —— 用最优预测替换未知的未来值。 + +本讲受 {cite}`hansen2004certainty` 的启发,从两个方向扩展了确定性等价性质: + +- *模型不确定性与稳健性。* 当决策者不信任自己的模型时会发生什么?CE 的一个显著版本依然成立,但现在"预测"步骤使用一个*扭曲的*概率分布,决策者为了实现稳健性而故意将其向不利于自己的方向倾斜。 + +- *风险敏感偏好。* 一个数学上等价的重新表述通过递归风险敏感偏好来解释同样的决策规则。 + + 稳健性参数 $\theta$ 与风险敏感性参数 $\sigma$ 通过 $\theta = -\sigma^{-1}$ 相联系。 + +我们用 `quantecon` 的 Python 代码来说明所有这三种设定 —— 普通 CE、稳健 CE 以及永久收入应用。 + +### 模型特征 + +* 线性转移律与二次目标(LQ 框架)。 +* 普通 CE:最优策略与噪声方差无关。 +* 稳健 CE:扭曲的预测取代基准模型的预测;策略函数取决于 $\theta$。 +* 永久收入应用:Hall 的鞅、稳健性下的预防性储蓄,以及稳健性与耐心之间的观测等价性。 + + +本讲借鉴了 {cite}`hansen2004certainty` 和 {cite}`HansenSargent2008`。 + +除了 Anaconda 中已有的库之外,本讲还需要以下库: + +```{code-cell} ipython3 +--- +tags: [hide-output] +--- +!pip install quantecon +``` + + +我们使用以下导入: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from quantecon import LQ, RBLQ +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + + +## 回顾:普通确定性等价 + +{ref}`配套讲座 ` 详细地建立了 CE 性质。 + +这里我们只收集下面稳健性扩展所需的要素。 + +状态向量 $y_t = \begin{bmatrix} x_t \\ z_t \end{bmatrix}$ 有一个外生分量 $z_t$,其转移律为 + +```{math} +:label: eq:z_transition_o +z_{t+1} = f(z_t,\, \epsilon_{t+1}) +``` + +和一个内生分量 $x_t$,服从 + +```{math} +:label: eq:x_transition_o +x_{t+1} = g(x_t,\, z_t,\, u_t). +``` + +在 LQ 假设下(二次收益 $r(y,u) = -y^\top Qy - u^\top Ru$,线性的 $f$ 和 $g$,高斯冲击),最优决策规则 $h$ 分解为 $u_t = h_1(x_t,\, h_2 \cdot z_t)$,其中 $h_1$ 求解一个非随机控制问题,$h_2$ 求解一个最优预测问题。 + +最优值函数为 $V(y_0) = -y_0^\top P\, y_0 - p$,其中,写 $z_{t+1} = f_1 z_t + f_2 \epsilon_{t+1}$: + +- $P$ 是算子 $T(P; r, g, f_1)$ 的不动点,该算子*不*涉及波动率矩阵 $f_2$,因此 $P$ 和决策规则 $h$ 都不依赖于噪声载荷。 + +- 常数 $p = \beta/(1-\beta)\,\mathrm{tr}(f_2^\top P f_2)$ 随波动率增大。 + +不确定性降低了值(更大的 $p$),但不改变行为。 + +以下代码设置了一个标量 LQ 问题,并确认策略增益 $F$ 对噪声水平 $\sigma$ 不变,而 $d$ 随其增大。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: CE principle -- policy vs. value + name: fig-ce-policy-value +--- +a, b_coeff = 0.9, 1.0 +q, r = 1.0, 1.0 +β = 0.95 + +A = np.array([[a]]) +B = np.array([[b_coeff]]) +Q_mat = np.array([[q]]) # 状态成本 +R_mat = np.array([[r]]) # 控制成本 + +σ_vals = np.linspace(0.0, 3.0, 80) +F_vals, d_vals = [], [] + +for σ in σ_vals: + C = np.array([[σ]]) + lq = LQ(R_mat, Q_mat, A, B, C=C, beta=β) + P, F, d = lq.stationary_values() + F_vals.append(float(F[0, 0])) + d_vals.append(float(d)) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].plot(σ_vals, F_vals, lw=2) +axes[0].set_xlabel('噪声水平 $\\sigma$') +axes[0].set_ylabel('策略增益 $F$') +axes[0].set_ylim(0, 2 * max(F_vals) + 0.1) + +axes[1].plot(σ_vals, d_vals, lw=2, color='darkorange') +axes[1].set_xlabel('噪声水平 $\\sigma$') +axes[1].set_ylabel('值常数 $d$') + +plt.tight_layout() +plt.show() +``` + + +## 模型不确定性与稳健性 + +### 设定与乘数问题 + +在 Simon 和 Theil 的设定中,决策者精确地知道自己的模型 —— 他对转移律 {eq}`eq:z_transition_o` 毫无疑问。 + +现在假设他怀疑真实的数据生成过程是 + +```{math} +:label: eq:distorted_law +z_{t+1} = f(z_t,\; \epsilon_{t+1} + w_{t+1}) +``` + +其中 $w_{t+1} = \omega_t(x^t, z^t)$ 是由对抗性的"自然"所选择的误设项。 + +决策者相信他的近似模型是一个良好的近似,其含义是 + +```{math} +:label: eq:misspec_budget +\hat{\mathbb{E}}\!\left[\sum_{t=0}^{\infty} \beta^t\, w_{t+1}^\top w_{t+1} + \,\Big|\, y_0\right] \leq \eta_0, +``` + +其中 $\eta_0$ 参数化了容许的误设预算,$\hat{\mathbb{E}}$ 是在扭曲律 {eq}`eq:distorted_law` 下的期望。 + +为了构造一个*稳健*的决策规则,决策者求解**乘数问题** —— 一个双人零和动态博弈: + +```{math} +:label: eq:multiplier +\min_{\{w_{t+1}\}}\, \max_{\{u_t\}}\; +\hat{\mathbb{E}}\!\left[\sum_{t=0}^{\infty} \beta^t + \Bigl\{r(y_t, u_t) + \theta\beta\, w_{t+1}^\top w_{t+1}\Bigr\}\, + \Big|\, y_0\right] +``` + +其中 $\theta > 0$ 惩罚大的扭曲。 + +更大的 $\theta$ 会收缩可行的误设集合;当 $\theta \to \infty$ 时,问题退化为普通 LQ。 + +{eq}`eq:multiplier` 的马尔可夫完美均衡给出一个*稳健*规则 $u_t = h(x_t, z_t)$ 以及一个最坏情形扭曲过程 $w_{t+1} = W(x_t, z_t)$。 + +### Stackelberg 时序与修正后的 CE + +马尔可夫完美均衡*隐藏*了一种形式的 CE。 + +为了揭示它,{cite:t}`HansenSargent2001` 施加了一个 **Stackelberg 时序协议**:在时刻 0,*最小化*方一劳永逸地承诺一个计划 $\{w_{t+1}\}$,之后*最大化*方顺序地选择 $u_t$。 + +这使得最小化方成为 Stackelberg 领导者。 + +为了描述领导者所承诺的计划,引入"大写字母"状态变量 $(X_t, Z_t)$(维数与 $(x_t, z_t)$ 相同),用于编码领导者预先承诺的策略: + +```{math} +:label: eq:stackelberg_plan +\begin{aligned} +w_{t+1} &= W(X_t, Z_t), \\ +X_{t+1} &= g(X_t, Z_t,\, h(X_t, Z_t)), \\ +Z_{t+1} &= f(Z_t,\, W(X_t, Z_t) + \epsilon_{t+1}). +\end{aligned} +``` + +用 $Y_t = \begin{bmatrix} X_t \\ Z_t \end{bmatrix}$ 概括为: + +```{math} +:label: eq:stackelberg_law +Y_{t+1} = M Y_t + N \epsilon_{t+1}, \qquad w_{t+1} = W(Y_t). +``` + +然后最大化方面对一个*普通*动态规划问题,服从他自身的动态 {eq}`eq:x_transition_o`、扭曲的 $z$ 律 {eq}`eq:distorted_law` 以及外生过程 {eq}`eq:stackelberg_law`。 + +他的最优规则取如下形式 + +```{math} +:label: eq:max_rule +u_t = \tilde{H}(x_t, z_t, Y_t). +``` + +{cite:t}`bacsar2008h` 和 {cite:t}`HansenSargent2008` 证明了,在均衡处(施加"大 $K$ = 小 $k$"),这退化为 + +```{math} +:label: eq:equilibrium_rule +\tilde{H}(X_t, Z_t, Y_t) = h(Y_t), +``` + +即与 {eq}`eq:multiplier` 的马尔可夫完美均衡*相同*的规则。 + +### 修正后的分离原理 + +Stackelberg 时序允许采用欧拉方程方法。 + +两步算法变为: + +第一步不变:求解与之前相同的非随机控制问题,将 $\mathbf{z}_t = (z_t, z_{t+1}, \ldots)$ 视为已知,得到 $u_t = h_1(x_t, \mathbf{z}_t)$。 + +第二步被修改:使用*扭曲的*运动律 {eq}`eq:stackelberg_law` 来形成预测。由于系统的线性性和高斯性, + +```{math} +:label: eq:distorted_forecast +\hat{\mathbb{E}}[\mathbf{z}_t \mid z^t, Y^t] + = \hat{h}_2 \begin{bmatrix} z_t \\ Y_t \end{bmatrix} +``` + +其中 $\hat{\mathbb{E}}$ 使用扭曲的模型。 + +将 {eq}`eq:distorted_forecast` 代入 $h_1$ 并施加 $Y_t = y_t$,得到稳健规则 + +```{math} +:label: eq:robust_ce_rule +u_t = h_1\!\left(x_t,\; \hat{h}_2 \cdot y_t\right) = h(x_t, z_t). +``` + +这就是修正后的 CE:*第一步与非稳健情形完全相同*;只有第二步改变,使用扭曲的而非理性的预测。 + +与普通 CE 相反,稳健策略*确实*随 $\theta$ 变化而改变。 + +当 $\theta \to \infty$(无稳健性)时,稳健策略收敛到标准 LQ 策略。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Robust policy varies with θ + name: fig-robust-policy-theta +--- +σ_fixed = 1.0 +C_fixed = np.array([[σ_fixed]]) + +lq_std = LQ(R_mat, Q_mat, A, B, C=C_fixed, beta=β) +P_std, F_std_arr, d_std = lq_std.stationary_values() +F_standard = float(F_std_arr[0, 0]) +P_standard = float(P_std[0, 0]) + +θ_vals = np.linspace(2.0, 30.0, 120) # 将注意力限制在数值稳定的范围内 +F_rob_vals, P_rob_vals = [], [] + +for θ in θ_vals: + rblq = RBLQ(R_mat, Q_mat, A, B, C_fixed, β, θ) + F_rob, K_rob, P_rob = rblq.robust_rule() + F_rob_vals.append(float(F_rob[0, 0])) + P_rob_vals.append(float(P_rob[0, 0])) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].plot(θ_vals, F_rob_vals, lw=2, label='稳健 $F(\\theta)$') +axes[0].axhline(F_standard, color='r', linestyle='--', lw=2, + label=f'标准 LQ ($F = {F_standard:.3f}$)') +axes[0].set_xlabel('稳健性参数 $\\theta$') +axes[0].set_ylabel('策略增益 $F$') +axes[0].legend() + +axes[1].plot(θ_vals, P_rob_vals, lw=2, color='purple', + label='稳健 $P(\\theta)$') +axes[1].axhline(P_standard, color='r', linestyle='--', lw=2, + label=f'标准 LQ ($P = {P_standard:.3f}$)') +axes[1].set_xlabel('稳健性参数 $\\theta$') +axes[1].set_ylabel('值矩阵 $P$') +axes[1].legend() + +plt.tight_layout() +plt.show() +``` + +观察到,对于较小的 $\theta$(对稳健性有强烈偏好),$F$ 和 $P$ 都显著偏离它们的非稳健对应值,并随 $\theta \to \infty$ 收敛到标准值。 + +这与普通 CE 形成鲜明对比:在稳健性下,*策略增益和值矩阵都依赖于稳健性参数 $\theta$ 和噪声载荷矩阵 $C$*。 + + +## 稳健性下的值函数 + +在对稳健性有偏好的情况下,{eq}`eq:multiplier` 的最优值再次是二次的, + +```{math} +:label: eq:robust_value +V(y_0) = -y_0^\top P\, y_0 - p, +``` + +但现在 $P$ *和* $p$ *都*依赖于波动率参数 $f_2$。 + +具体而言,$P$ 是复合算子 $T \circ \mathcal{D}$ 的不动点,其中 $T$ 是与非稳健情形相同的贝尔曼算子,$\mathcal{D}$ 是**扭曲算子**: + +```{math} +:label: eq:distortion_op +\mathcal{D}(P) = \mathcal{D}(P;\, f_2,\, \theta). +``` + +给定不动点 $P = T(\mathcal{D}(P))$,常数为 + +```{math} +:label: eq:constant_p +p = p(P;\, f_2,\, \beta,\, \theta). +``` + +尽管 $P$ 现在依赖于 $f_2$,但一种形式的 CE 仍然成立:相同的决策规则 {eq}`eq:robust_ce_rule` 也从*非随机*博弈中产生,该博弈在服从 {eq}`eq:x_transition_o` 和 + +```{math} +:label: eq:nonstoch_z +z_{t+1} = f(z_t,\, w_{t+1}), +``` + +即设 $\epsilon_{t+1} \equiv 0$ 的条件下最大化 {eq}`eq:multiplier`。 + +随机性的存在降低了值(常数 $p$),但不改变决策规则。 + + +## 风险敏感偏好 + +在 {cite:t}`Jacobson_73` 和 {cite:t}`Whittle_1990` 的基础上,{cite:t}`hansen2004certainty` 证明了同样的决策规则可以通过**风险敏感偏好**来重新解释。 + +假设决策者*完全信任*他的模型 + +```{math} +:label: eq:rs_transition +y_{t+1} = A\, y_t + B\, u_t + C\, \epsilon_{t+1} +``` + +但根据以下递归来评估随机过程 + +```{math} +:label: eq:rs_utility +U_t = r(y_t, u_t) + \beta\, \mathcal{R}_t(U_{t+1}) +``` + +其中*风险调整后*的延续算子为 + +```{math} +:label: eq:rs_operator +\mathcal{R}_t(U_{t+1}) = \frac{2}{\sigma} + \log \mathbb{E}\!\left[\exp\!\left(\frac{\sigma U_{t+1}}{2}\right) + \,\Big|\, y^t\right], \qquad \sigma \leq 0. +``` + +当 $\sigma = 0$ 时,洛必达法则恢复标准的期望算子。 + +当 $\sigma < 0$ 时,$\mathcal{R}_t$ 惩罚延续效用 $U_{t+1}$ 中的右尾风险。 + +对于候选的二次延续值 $U_{t+1}^e = -y_{t+1}^\top \Omega\, y_{t+1} - \rho$,令 $\hat{y}_{t+1} \equiv A y_t + B u_t$ 表示 $y_{t+1}$ 的条件均值。 + +通过高斯分布的对数矩生成函数评估 $\mathcal{R}_t$,得到 + +```{math} +:label: eq:rs_eval +\mathcal{R}_t U_{t+1}^e + = -\hat{y}_{t+1}^\top \mathcal{D}(\Omega)\, \hat{y}_{t+1} - \hat{\rho} +``` + +其中 $\mathcal{D}$ 是与 {eq}`eq:distortion_op` *相同*的扭曲算子,其中 $\theta = -\sigma^{-1}$,而 $\hat{\rho}$ 是相应的标量调整项。 + +因此,风险敏感的贝尔曼方程与稳健控制问题有*相同*的不动点 $P$,从而有*相同的决策规则* $u_t = -F y_t$。 + +> **关键等价性:** 参数为 $\theta$ 的稳健控制与参数为 $\sigma = -\theta^{-1}$ 的风险敏感控制产生相同的决策规则。 + + +## 应用:永久收入模型 + +我们现在在一个具体的线性二次型永久收入模型中说明上述所有内容。 + +### 模型设定 + +一个消费者接收一个外生的禀赋过程 $\{z_t\}$,并将其在消费 $c_t$ 和储蓄 $x_t$ 之间进行分配,以最大化 + +```{math} +:label: eq:pi_objective +-\mathbb{E}_0 \sum_{t=0}^{\infty} \beta^t (c_t - b)^2, \qquad \beta \in (0,1) +``` + +其中 $b$ 是消费的至福水平。 + +定义**消费的边际效用** $\mu_{ct} \equiv b - c_t$(控制变量),预算约束和禀赋过程为 + +```{math} +:label: eq:pi_budget +x_{t+1} = R\, x_t + z_t - b + \mu_{ct} +``` + +```{math} +:label: eq:endowment +z_{t+1} = \mu_d(1-\rho) + \rho\, z_t + c_d(\epsilon_{t+1} + w_{t+1}) +``` + +其中 $R > 1$ 是储蓄的总回报率,$|\rho| < 1$,$w_{t+1}$ 是一个可选的表示模型误设的冲击均值扭曲。 + +在通过扩充状态向量吸收了常数 $-b$ 和 $\mu_d(1-\rho)$ 之后,或等价地通过处理相对稳态的偏差,设 $w_{t+1} \equiv 0$ 并取 $Q = 0$(收益仅依赖于控制 $\mu_{ct}$)和 $R_{\text{ctrl}} = 1$,将其纳入标准 LQ 形式 + +```{math} +:label: eq:pi_lq_matrices +y_t = \begin{bmatrix} x_t \\ z_t \end{bmatrix}, +\quad +A = \begin{bmatrix} R & 1 \\ 0 & \rho \end{bmatrix}, +\quad +B = \begin{bmatrix} 1 \\ 0 \end{bmatrix}, +\quad +C = \begin{bmatrix} 0 \\ c_d \end{bmatrix}. +``` + +在下面的数值代码中,我们向状态成本矩阵添加一个可忽略的 `1e-8 I` 正则化项,以在 Hall 的单位根情形 $\beta R = 1$ 下保持 Riccati 计算的良态。 + +我们校准到 {cite:t}`HST_1999` 从二战后美国数据估计的参数: + +```{code-cell} ipython3 +β_hat = 0.9971 +R_rate = 1.0 / β_hat # β*R = 1 (Hall 的情形) +ρ = 0.9992 +c_d = 5.5819 +σ_rs = -2e-7 # σ_hat < 0 +θ_pi = -1.0 / σ_rs # θ = -1/σ_hat + +A_pi = np.array([[R_rate, 1.0], + [0.0, ρ]]) +B_pi = np.array([[1.0], + [0.0]]) +C_pi = np.array([[0.0], + [c_d]]) +Q_pi = 1e-8 * np.eye(2) # 为 β*R = 1 进行正则化 +R_pi = np.array([[1.0]]) +``` + +### 无稳健性:Hall 的鞅 + +设 $\sigma = 0$(无稳健性偏好),消费者的欧拉方程为 + +```{math} +:label: eq:euler +\mathbb{E}_t[\mu_{c,t+1}] = (\beta R)^{-1} \mu_{ct}. +``` + +当 $\beta R = 1$(Hall 的情形)时,这就是 $\mathbb{E}_t[\mu_{c,t+1}] = \mu_{ct}$,即**消费的边际效用是一个鞅** —— 等价地,消费遵循随机游走。 + +最优策略是 $\mu_{ct} = -F y_t$,其中,由向前求解的欧拉方程,$F = [(R-1),\ (R-1)/(R - \rho)]$。 + +由此得到的到 $\mu_{ct}$ 一维方向上的闭环投影给出标量 AR(1) 表示 + +```{math} +:label: eq:std_ar1 +\mu_{c,t+1} = \varphi\, \mu_{ct} + \nu\, \epsilon_{t+1}. +``` + +```{code-cell} ipython3 +F_pi = np.array([[(R_rate - 1.0), (R_rate - 1.0) / (R_rate - ρ)]]) +A_cl_std = A_pi - B_pi @ F_pi + +φ_std = 1.0 / (β_hat * R_rate) +ν_std = (R_rate - 1.0) * c_d / (R_rate - ρ) + +print(f"φ = {φ_std:.6f}, ν = {ν_std:.4f}") +``` + +### 有稳健性:预防性储蓄 + +在对稳健性有偏好的情况下($\sigma < 0$,$\theta < \infty$),消费者使用在最坏情形模型下评估的扭曲预测 $\hat{\mathbb{E}}_t[\cdot]$。 + +消费规则取确定性等价形式 + +```{math} +:label: eq:robust_consumption +\mu_{ct} = -(1 - R^{-2}\beta^{-1}) + \!\left(R\, x_t + \hat{\mathbb{E}}_t\!\left[ + \sum_{j=0}^{\infty} R^{-j}(z_{t+j} - b)\right]\right) +``` + +其中 $h_1$ —— CE 算法的第一步 —— 与非稳健情形*完全相同*。 + +只有期望算子改变。 + +由此得到的 $\mu_{ct}$ 的 AR(1) 动态变为: + +```{math} +:label: eq:robust_ar1 +\mu_{c,t+1} = \tilde{\varphi}\, \mu_{ct} + \tilde{\nu}\, \epsilon_{t+1} +``` + +其中 $\tilde{\varphi} < 1$,这意味着在近似模型下 $\mathbb{E}_t[c_{t+1}] > c_t$ —— 这是一种**预防性储蓄**。 + +观测等价性公式 {eq}`eq:oe_locus`(下面推导)立即给出稳健 AR(1) 系数:$\tilde{\varphi} = 1/(\tilde{\beta} R)$,其中 $\tilde{\beta} = \tilde{\beta}(\sigma)$。 + +创新尺度 $\tilde{\nu}$ 由带有扭曲持续性的稳健永久收入公式得出;{cite:t}`HST_1999` 报告他们的校准中 $\tilde{\nu} \approx 8.0473$。 + +```{code-cell} ipython3 +def beta_tilde(σ, β_hat_val, α_sq_val): + """观测等价轨迹:β_tilde(σ)。""" + denom = 2.0 * (1.0 + σ * α_sq_val) + numer = β_hat_val * (1.0 + β_hat_val) + disc = 1.0 - 4.0 * β_hat_val * (1.0 + σ * α_sq_val) / \ + (1.0 + β_hat_val) ** 2 + return (numer / denom) * (1.0 + np.sqrt(np.maximum(disc, 0.0))) + +ν_rob = 8.0473 +α_sq = ν_rob ** 2 +bt = beta_tilde(σ_rs, β_hat, α_sq) +φ_rob = 1.0 / (bt * R_rate) + +print(f"β_tilde = {bt:.5f}, φ_tilde = {φ_rob:.4f}, ν_tilde = {ν_rob:.4f}") +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Standard vs robust consumption paths + name: fig-std-vs-robust-paths +--- +np.random.seed(0) +T_sim = 100 + +def simulate_ar1(φ, ν, shocks, mu0=0.0): + path = np.empty(len(shocks) + 1) + path[0] = mu0 + for t, ε in enumerate(shocks, start=1): + path[t] = φ * path[t-1] + ν * ε + return path + +shock_path = np.random.randn(T_sim - 1) +mu0_init = 10.0 +mu_std_path = simulate_ar1(φ_std, ν_std, shock_path, mu0=mu0_init) +mu_rob_path = simulate_ar1(φ_rob, ν_rob, shock_path, mu0=mu0_init) + +fig, axes = plt.subplots(2, 1, figsize=(11, 6), sharex=True) +t_grid = np.arange(T_sim) + +axes[0].plot(t_grid, mu_std_path, lw=2, label=f'$\\mu_{{ct}}$ (标准, $\\varphi={φ_std:.4f}$)') +axes[0].axhline(0, color='k', lw=0.8, linestyle='--') +axes[0].set_ylabel('$\\mu_{ct}$') +axes[0].legend(loc='upper right') + +axes[1].plot(t_grid, mu_rob_path, lw=2, color='darkorange', + label=f'$\\mu_{{ct}}$ (稳健, $\\tilde{{\\varphi}}={φ_rob:.4f}$)') +axes[1].axhline(0, color='k', lw=0.8, linestyle='--') +axes[1].set_xlabel('期 $t$') +axes[1].set_ylabel('$\\mu_{ct}$') +axes[1].legend(loc='upper right') + +plt.tight_layout() +plt.show() +``` + +### 观测等价性:稳健性表现得像耐心 + +{cite:t}`HansenSargent2001` 的一个关键洞见是,在永久收入模型中,对稳健性的偏好($\sigma < 0$)*观测等价于*将贴现因子从 $\hat{\beta}$ 增加到一个更大的值 $\tilde{\beta}(\sigma)$,同时将 $\sigma$ 设回零。 + +等价轨迹由下式给出 + +```{math} +:label: eq:oe_locus +\tilde{\beta}(\sigma) = + \frac{\hat{\beta}(1 + \hat{\beta})}{2(1 + \sigma\alpha^2)} + \left[1 + \sqrt{1 - \frac{4\hat{\beta}(1+\sigma\alpha^2)}{(1+\hat{\beta})^2}}\right] +``` + +其中 $\alpha^2 = \tilde{\nu}^2$ 是稳健 AR(1) 表示 {eq}`eq:robust_ar1` 中的创新载荷平方。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Observational equivalence locus + name: fig-oe-locus +--- +σ_range = np.linspace(-3e-7, 0.0, 200) +bt_vals = [beta_tilde(s, β_hat, α_sq) for s in σ_range] +bt_check = beta_tilde(σ_rs, β_hat, α_sq) + +fig, ax = plt.subplots(figsize=(9, 5)) +ax.plot(-σ_range * 1e7, bt_vals, lw=2, color='steelblue', + label='$\\tilde{\\beta}(\\sigma)$') +ax.axhline(β_hat, color='r', linestyle='--', lw=2, + label=f'$\\hat{{\\beta}} = {β_hat}$') +ax.scatter([-σ_rs * 1e7], [bt_check], zorder=5, color='darkorange', s=80, + label=f'$(\\hat{{\\sigma}},\\, \\tilde{{\\beta}}) ' + f'= ({σ_rs:.0e},\\, {bt_check:.4f})$') +ax.set_xlabel('风险敏感性 $-\\sigma$ ($\\times 10^{-7}$)') +ax.set_ylabel('观测等价的贴现因子 $\\tilde{\\beta}$') +ax.legend() +plt.tight_layout() +plt.show() +``` + +该图证实了论文的关键发现:*激活对稳健性的偏好,就消费和储蓄行为而言,观测等价于增加贴现因子*。 + +然而,{cite:t}`HST_1999` 表明这两种参数化*并不*意味着相同的资产价格。 + +这是因为对稳健性的偏好通过进入随机贴现因子的 $\mathcal{D}(P)$ 矩阵生成了不同的状态价格。 + + +## 小结 + +下表浓缩了主要结果: + +| 设定 | 策略依赖于噪声? | 使用的预测 | CE 是否成立? | +|---------|:------------------------:|:--------------:|:------------:| +| Simon–Theil(普通 LQ) | 否 | 理性 | 是 | +| 稳健控制(乘数) | 是($P$ 随 $f_2$ 和 $\theta$ 变化) | 扭曲(最坏情形) | 是(修正) | +| 风险敏感偏好 | 是(与稳健相同) | 扭曲(相同) | 是(相同) | + +在所有这三种情形中,决策者都可以被描述为遵循一个两步流程:首先求解一个非随机控制问题,然后形成信念。 + +差异在于第二步中形成的是哪种信念。 + + +## 练习 + +```{exercise-start} +:label: ce_ex2 +``` + +数值地证明,当 $\theta \to \infty$ 时,稳健策略 $F(\theta)$ 收敛到标准 LQ 策略 $F_{\text{std}}$,且收敛速率为 $1/\theta$ 阶。在对数-对数尺度上绘制 $|F(\theta) - F_{\text{std}}|$ 对 $1/\theta$ 的图。 + +```{exercise-end} +``` + +```{solution-start} ce_ex2 +:class: dropdown +``` + +```{code-cell} ipython3 +θ_large = np.logspace(0.5, 3.0, 100) +gap_vals = [] + +for θ in θ_large: + rblq = RBLQ(R_mat, Q_mat, A, B, C_fixed, β, θ) + F_r, _, _ = rblq.robust_rule() + gap_vals.append(abs(float(F_r[0, 0]) - F_standard)) + +fig, ax = plt.subplots(figsize=(8, 5)) +ax.loglog(1.0 / θ_large, gap_vals, lw=2) +ax.set_xlabel('$1/\\theta$') +ax.set_ylabel('$|F(\\theta) - F_{\\mathrm{std}}|$') +ax.set_title('稳健策略以 $1/\\theta$ 速率收敛到标准 LQ') + +x_ref = 1.0 / θ_large +ax.loglog(x_ref, x_ref * gap_vals[0] / x_ref[0], + 'r--', lw=2, label='斜率 1 参考线') +ax.legend() +plt.tight_layout() +plt.show() +``` + +对数-对数图揭示了一种近似线性的关系,证实了 $O(1/\theta)$ 收敛。 + +```{solution-end} +``` + +```{exercise-start} +:label: ce_ex3 +``` + +选取三个值 $\sigma_i < 0$,并数值地验证带有 $(\sigma_i, \hat{\beta})$ 的稳健永久收入模型产生与带有 $(0, \tilde{\beta}_i)$ 的适当选择的非稳健模型相同的策略矩阵 $F$。 + +为了求出 $\tilde{\beta}_i$,从稳健闭环动态中提取 $\mu_{ct}$ 的 AR(1) 系数 $\varphi_i$,并设 $\tilde{\beta}_i = 1/(\varphi_i R)$。 + +证明在每种情形下 $\tilde{\beta}_i > \hat{\beta}$,从而确认稳健性表现得像增加的耐心。 + +```{exercise-end} +``` + +```{solution-start} ce_ex3 +:class: dropdown +``` + +对于每个 $\sigma_i$,我们用 `RBLQ` 求解稳健问题,并从闭环动态 $A_{\text{cl}} = A - B F_{\text{rob}}$ 中提取 $\mu_{ct}$ 的 AR(1) 系数 $\varphi$。 + +如果 $F$ 是 $A_{\text{cl}}$ 的一个左特征向量,特征值为 $\varphi$,那么 $\mu_{ct} = -F y_t$ 满足 $\mu_{c,t+1} = \varphi\, \mu_{ct} + \nu\, \epsilon_{t+1}$。 + +设 $\tilde{\beta} = 1/(\varphi R)$ 并求解一个贴现因子为 $\tilde{\beta}$ 的标准(非稳健)LQ 问题应重现 $F$。 + +```{code-cell} ipython3 +σ_trio = np.array([-5e-8, -1e-7, -2e-7]) + +for s in σ_trio: + # 稳健模型:(σ, β_hat) + θ_val = -1.0 / s + rblq = RBLQ(R_pi, Q_pi, A_pi, B_pi, C_pi, β_hat, θ_val) + F_rob, K_rob, P_rob = rblq.robust_rule() + + # 从近似模型下的闭环中提取 φ + A_cl = A_pi - B_pi @ F_rob + φ_rob = float((F_rob @ A_cl)[0, 1] / F_rob[0, 1]) + + # 隐含的贴现因子 + bt = 1.0 / (φ_rob * R_rate) + + # 带有 β_tilde 的非稳健模型 + lq_nr = LQ(R_pi, Q_pi, A_pi, B_pi, C=C_pi, beta=bt) + P_nr, F_nr, d_nr = lq_nr.stationary_values() + + print(f"σ = {s:.1e}, θ = {θ_val:.1e}, β̃ = {bt:.6f} (> β̂ = {β_hat})") + print(f" φ_rob = {φ_rob:.8f}") + print(f" F_robust = [{F_rob[0,0]:.6f}, {F_rob[0,1]:.6f}]") + print(f" F_non-rob = [{F_nr[0,0]:.6f}, {F_nr[0,1]:.6f}]") + print(f" |F_rob - F_nr| = {np.max(np.abs(F_rob - F_nr)):.2e}") + print(f" K (最坏情形扭曲): [{K_rob[0,0]:.2e}, {K_rob[0,1]:.2e}]") + print() +``` + +策略矩阵 $F$ 高精度地匹配,证实了消费和储蓄决策的观测等价性。 + +在每种情形下 $\tilde{\beta} > \hat{\beta}$:对稳健性的偏好使得主体表现得好像他更有耐心。 + +稳健模型中非零的最坏情形扭曲 $K$ 在非稳健模型中没有对应物。 + +正如 {cite:t}`HST_1999` 所表明的,这就是为什么即使储蓄计划一致,这两种参数化仍然意味着不同的资产价格。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/two_computation.md b/lectures/two_computation.md new file mode 100644 index 0000000..148322c --- /dev/null +++ b/lectures/two_computation.md @@ -0,0 +1,3020 @@ +--- +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 +translation: + title: 为社会保障融资的两种计算方法 + headings: + Overview: 概述 + Model: 模型 + Model::Environment: 环境 + Model::Demographics: 人口结构 + Model::Distributions and aggregates: 分布与总量 + Model::Resource constraint: 资源约束 + Model::Factor prices: 要素价格 + Model::Consumers' problems: 消费者的问题 + Model::Government: 政府 + Model::Equilibrium: 均衡 + Model::Transition dynamics: 转型动态 + Model::Transition dynamics::Small open economy: 小型开放经济 + Model::Transition dynamics::Closed economy: 封闭经济 + Two experiments: 两个实验 + Computation strategy: 计算策略 + Computation strategy::Dynamic program: 动态规划 + Computation strategy::State space preparation: 状态空间准备 + Computation strategy::Means and covariances: 均值和协方差 + Computation strategy::Computing transitions: 计算转型 + Calibration: 校准 + Calibration::Preference parameters: 偏好参数 + Calibration::Technology parameters: 技术参数 + Individual optimality: 个人最优性 + Individual optimality::Steady-state computation: 稳态计算 + Individual optimality::Initial and terminal steady states: 初始和终端稳态 + Transition path computation: 转型路径计算 + Transition path computation::Shooting method: 打靶法 + 'Experiment 1: compensation through debt': 实验 1:通过债务进行补偿 + 'Experiment 1: compensation through debt::Fixed prices': 固定价格 + 'Experiment 1: compensation through debt::Endogenous prices': 内生价格 + 'Experiment 2: government capital accumulation': 实验 2:政府资本积累 + Distribution surfaces: 分布曲面 +--- + +(two_computation)= +```{raw} jupyter + +``` + +# 为社会保障融资的两种计算方法 + +```{contents} Contents +:depth: 2 +``` + +```{include} _admonition/gpu.md +``` + + +除了 Anaconda 中已有的库之外,本讲座还需要以下库 + +```{code-cell} ipython3 +:tags: [skip-execution] + +!pip install jax +``` + +## 概述 + +本讲座遵循 {cite:t}`huang1997two`,描述了关于如何从非融资(现收现付)制逐步转向完全融资制社会保障系统的两种计算实验。 + +随着人口老龄化,现收现付制社会保障系统面临着财务困难。 + +这种情况使得当今的一些政策制定者和政策顾问认为,如果早期的政策制定者建立了一个完全融资的退休系统,今天的公民会过得更好。 + +但是从我们今天的处境出发,向完全融资制系统转型会带来分配上的挑战,因为为非融资制系统做出贡献的老一代人可能会失去福利。 + +为了定量研究各种可能性,本讲座采用了一个一般均衡世代交叠模型,该模型通过纳入以下要素修改了 {cite:t}`auerbach1987dynamic` 的环境: + +* 风险敏感偏好 +* 寿命的不确定性 +* 不可保的劳动收入风险 +* 同一世代内以及跨世代的消费分布理论 + +通过采用 {cite:t}`hansen1995discounted` 的贴现风险敏感线性二次偏好,该模型为个人消费和储蓄提供了线性决策规则。 + +这使得在计算上可以追踪跨世代消费与财富的联合分布。 + +本讲座与另外两个讲座相关: + +- {doc}`ak2` 研究了在两期 OLG 模型中,税收、转移支付和债务如何影响资本积累,介绍了本讲座所扩展的 {cite:t}`auerbach1987dynamic` 框架。 + +- {doc}`ak_aiyagari` 研究了在长寿命 OLG 模型中财政政策如何与预防性储蓄相互作用,使用的是离散动态规划而非本讲座采用的线性二次方法。 + +我们使用以下导入和配置 + +```{code-cell} ipython3 +import jax +import jax.numpy as jnp +from jax import jit, vmap +import jax.lax as lax +import numpy as np +import matplotlib.pyplot as plt +from collections import namedtuple +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n + +# 启用 64 位精度 +jax.config.update("jax_enable_x64", True) +``` + +## 模型 + +### 环境 + +该经济体由有限寿命个人的世代交叠组成,个人最多可存活 $T_0+1$ 年,还有一个无限寿命的政府。 + +个人消费者和政府可以按恒定的无风险总回报率进行投资。 + +在生命的前 $T_1+1$ 期,消费者获得劳动收入,并将其分配于消费、税收和资产积累。 + +在生命的最后 $T_0-T_1$ 期(退休期),消费者获得社会保障福利,并通过动用其资产进行负储蓄。 + +政府对资本和劳动收入征税、发行债务、购买商品并支付退休福利。 + +对于任何变量 $z$,我们用下标 $t$ 表示年龄,用括号中的参数 $s$ 表示日历时间,用上标 $s-t$ 表示出生日期,因此 $z^{s-t}(s) \equiv z_t(s) \equiv z^{s-t}_t(s)$。 + +### 人口结构 + +在日期 $s$,出生一批规模为 $N_0(s)$ 的消费者队列,他们在 $s, s+1, \ldots, s+T_0$ 各期存活。 + +随着一个队列年龄增长,其成员根据年龄间的存活概率 $\{\alpha_t\}^{T_0}_{t=0}$ 面临随机存活,其中 $\alpha_t$ 是从年龄 $t$ 存活到 $t+1$ 的概率。 + +设 $N_t(s)$ 为在时间 $s$ 存活的年龄为 $t$ 的人数,设 $n$ 为恒定的人口总增长率。 + +在时间 $s$,年龄组 $t$ 的规模满足 + +$$ +N_t(s) = \lambda_t \cdot N_0(s-t) +$$ + +其中 $\lambda_t = \prod^{t-1}_{j=0} \alpha_j$,$t = 0,\ldots,T_0$,$\lambda_0 = 1$,出生遵循 $N_0(s) = n^s \cdot N_0(0)$。 + +在每个时间 $s$,队列 $t$ 的人口占比为 + +$$ +f_t = \frac{\lambda_t \cdot n^{-t}}{\sum^{T_0}_{\tau=0} \lambda_\tau \cdot n^{-\tau}} +$$ + +在时间 $s$ 的总人口为 + +$$ +N(s) = N_0(0) \cdot n^s \cdot \sum^{T_0}_{t=0} n^{-t} \cdot \lambda_t. +$$ + +### 分布与总量 + +个人面临寿命不确定性和劳动收入冲击。 + +他们通过积累无风险资产(政府债券和实物资本)来进行自我保险,同时适当考虑他们预期将获得的社会保障福利。 + +设 $\epsilon^t_0$ 表示个人从出生到年龄 $t$ 所接受的随机冲击的历史。 + +状态向量 $x_t(s) = x_t(s; \epsilon^t_0, x_0)$ 度量资产存量以及消费者用来预测未来偏好或机会的信息变量。 + +该模型给出的消费是状态向量的一个依赖于时间和年龄的线性函数 + +$$ +c_t(s; \epsilon^t_0, x_0) = \eta_{ct}(s) \cdot x_t(s; \epsilon^t_0, x_0) +$$ + +其中状态向量遵循线性运动定律 + +$$ +x_{t+1}(s+1; \epsilon^{t+1}_0, x_0) = A_t(s) \cdot x_t(s; \epsilon^t_0, x_0) + C_t(s) \cdot \epsilon_{t+1} +$$ + +其中 $\epsilon_{t+1}$ 是满足 $E(\epsilon_{t+1}|J_t) = 0$、$E(\epsilon_{t+1} \cdot \epsilon'_{t+1}|J_t) = I$ 且 $J_t = (\epsilon^t_0, x_0)$ 的鞅差序列。 + +该模型给出状态向量的概率分布。 + +设 $\mu_t(s) = E[x_t(s)]$ 且 $\Sigma_t(s) = E[(x_t(s)-\mu_t(s))(x_t(s)-\mu_t(s))']$。 + +这些矩满足 + +$$ +\mu_{t+1}(s+1) = A_t(s) \cdot \mu_t(s) +$$ + +$$ +\Sigma_{t+1}(s+1) = A_t(s) \cdot \Sigma_t(s) \cdot A_t(s)' + C_t(s) \cdot C_t(s)' +$$ + +人均总消费为 + +$$ +c(s)/N(s) = \sum^{T_0}_{t=0} \mu_{ct}(s) \cdot f_t +$$ + +其中 $\mu_{ct}(s)$ 是时间 $s$ 年龄为 $t$ 的人的平均消费。 + +年龄队列 $t$ 内的消费分布具有均值 $\mu_{ct}(s) = \eta_{ct}(s) \cdot \mu_t(s)$ 和方差 $\Sigma_{ct}(s) = \eta_{ct}(s) \cdot \Sigma_t(s) \cdot \eta_{ct}(s)'$。 + +### 资源约束 + +全经济范围的实物资源约束为 + +$$ +g(s) \cdot N(s) + \sum^{T_0}_{t=0} c_t(s) \cdot N^{s-t}_t + K(s) = R(s-1) \cdot K(s-1) + w(s) \cdot \sum^{T_1}_{t=0} \varepsilon_t \cdot N^{s-t}_t + N_0(s) \cdot k_{-1}(s) +$$ + +其中 $g(s)$ 是人均政府购买,$K(s-1)$ 是实物资本,$R(s-1) = 1 + r(s-1) - \delta$ 是资产总回报,$\varepsilon_t$ 是年龄为 $t$ 的人的外生效率禀赋,$w(s)$ 是基础工资率,$N_0(s) \cdot k_{-1}(s)$ 是新生儿带来的资本,$\delta$ 是折旧率。 + +### 要素价格 + +我们考虑关于要素价格的两种备选假设: + +* *小型开放经济:* $r(s-1) = r$ 和 $w(s) = w$ 是外生且恒定的。 +* *封闭经济:* 要素价格由科布-道格拉斯生产函数的边际产量决定: + +$$ +r(s-1) = \tilde{A} \cdot \tilde{\alpha} \cdot (K(s-1)/\tilde{N}(s))^{\tilde{\alpha}-1}, \qquad +w(s) = (1-\tilde{\alpha}) \cdot \tilde{A} \cdot (K(s-1)/\tilde{N}(s))^{\tilde{\alpha}} +$$ + +其中 $\tilde{N}(s) = \sum^{T_1}_{t=0} \varepsilon_t \cdot N^{s-t}_t$ 是以效率单位计的总劳动投入,$\tilde{\alpha}$ 是资本的收入份额。 + +### 消费者的问题 + +个人消费者面临一个经典消费-储蓄问题的世代交叠版本(参见 {doc}`perm_income`)。 + +工作年龄的消费者($t \leq T_1$)获得劳动收入 $w(s) \cdot \varepsilon_t + d_t$,其中 $d_t$ 是一个 AR(1)过程 + +$$ +d_t = \rho_d \cdot d_{t-1} + \xi_t +$$ + +其中 $\xi_t$ 是方差为 $\sigma^2_d$ 的高斯白噪声。 + +年龄 $t$ 和时间 $s$ 的预算约束为 + +```{math} +:label: two_comp_budget + +c_t(s) + a_t(s) = R(s-1) \cdot a_{t-1}(s-1) + w(s) \cdot \varepsilon_t + S_t(s) - T_t(s) + d_t +``` + +其中 $a_{t-1}(s-1)$ 是年龄 $t$ 开始时的资产持有量,$S_t(s)$ 是社会保障福利(工作时为零,退休时为 $S(s)$),税收为 $T_t(s) = \tau_0(s) + \tau_{\ell}(s)(w(s) \cdot \varepsilon_t + d_t) + \tau_a(s)(R(s-1)-1) \cdot a_{t-1}(s-1)$。 + +遵循 {cite:t}`hansen1995discounted`,对随机消费过程的偏好由以下递归方式定义 + +$$ +U_t = -(\pi \cdot c_t - \gamma_t)^2/2 + \beta_t \cdot \mathcal{R}_t(U_{t+1}) +$$ + +其中 $\mathcal{R}_t(U_{t+1}) = (2/\sigma) \cdot \log E[\exp(\sigma \cdot U_{t+1}/2) | J_t]$,$\sigma$ 是风险敏感性参数,$\beta_t = \bar{\beta} \cdot \alpha_t$ 是经存活率调整的贴现因子。 + +这种偏好设定给出线性决策规则,同时允许一种诱导某类预防性储蓄的风险敏感性形式。 + +当 $\sigma < 0$ 时,消费者偏好尽早消除不确定性,决策规则部分依赖于噪声统计量。 + +### 政府 + +政府购买商品、支付社会保障福利、对资本和劳动收入征税、没收意外遗产,并发行一期债券。 + +政府预算约束为 + +$$ +\begin{aligned} +g(s) \cdot N(s) + \sum^{T_0}_{t=T_1+1} S_t(s) \cdot N^{s-t}_t + R(s-1) \cdot \sum^{T_0}_{t=1} b_{t-1}(s-1) \cdot N^{s-t}_t = \\ +\sum^{T_0}_{t=0} N^{s-t}_t\{\tau_a(s)[R(s-1)-1] \cdot a_{t-1}(s-1) + \tau_{\ell}(s) \cdot w(s) \cdot \varepsilon_t\} + \tau_0 \cdot N(s) + \\ +\sum^{T_0}_{t=0} b_t(s) \cdot N^{s-t}_t + R(s-1) \cdot \sum^{T_0}_{t=0} (1-\alpha_t) \cdot k_t(s-1) \cdot N^{s-t-1}_t +\end{aligned} +$$ + +其中 $b_t(s)$ 是时间 $s$ 由年龄为 $t$ 的个人持有的政府债务,最后一项表示遗产税。 + +财政制度之间的转型由日期 $0 \leq s_1 < s_2 < s_3$ 描述: + +* 在 $s = 0$ 之前:初始平稳均衡 +* 在 $s = 0$ 时:政府宣布政策变化 +* $s \in [s_1, s_2)$:财政参数和社会保障系统发生变化 +* $s \geq s_2$:新的恒定政策参数 +* $s \geq s_3$:最终平稳均衡 + +### 均衡 + +我们定义以下对象: + +- **配置** 是 $t = 0,\ldots,T_0$ 时 $\{c_t(s), a_t(s)\}^{s_3}_{s=0}$ 的随机过程,以及序列 $\{K(s)\}^{s_3}_{s=0}$。 + +- **政府政策** 是序列 $\{b(s), g(s), \tau_{\ell}(s), S(s), \tau_a(s)\}^{s_3}_{s=0}$。 + +- **价格系统** 是序列 $\{w(s), r(s-1)\}^{s_3}_{s=0}$。 + +**均衡** 是一个配置、一个价格系统和一个政府政策,使得 + +1. 给定价格序列和政府政策,该配置求解了家庭的最优问题,并且 + +2. 该配置和政府政策在每个日期 $s$ 满足政府预算约束。 + +在 **平稳均衡** 中,所有变量都与日历时间 $s$ 无关,这将政府预算约束简化为 + +$$ +g + \sum^{T_0}_{t=T_1+1} S_t \cdot f_t + [R/n - 1] \cdot \bar{b} = \tau_a(R-1) \cdot \sum^{T_0}_{t=0} a_{t-1} \cdot f_t + \tau_{\ell} \cdot \sum^{T_1}_{t=0} w \cdot \varepsilon_t \cdot f_t + \frac{R}{n} \cdot \sum^{T_0}_{t=0} (1-\alpha_t) \cdot a_t \cdot f_t +$$ + +其中 $\bar{b}$ 是稳态下的人均政府债务。 + +### 转型动态 + +下图显示了转型过程中的年龄-时间结构。 + +每条水平线表示一个队列的生命周期,垂直虚线标记政策变化日期 $s_1$ 和 $s_2$。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 世代交叠的年龄-时间图 + name: two_comp_age_time +--- +fig, ax = plt.subplots(figsize=(8, 5)) + +birth_range = np.arange(-60, 41, 5) + +ax.hlines(birth_range, birth_range, birth_range + 60, 'k', linewidth=1) +ax.vlines([0, 40], -60, 40, 'k', linestyle='--', linewidth=0.5) + +ax.set_ylabel("出生日期") +ax.set_xlabel("时间") + +ax.text(-20, 25, r"$s_1=0$") +ax.text(43, -50, r"$s_2$") + +ax.invert_yaxis() +plt.show() +``` + +#### 小型开放经济 + +在要素价格固定的情况下,转型具有清晰的结构: + +- 在 $s_1 - T_0$ 之前出生的队列在政策变化之前死亡,不受影响。 +- 在 $s_1$ 时存活的队列必须为其剩余寿命重新计算其消费-储蓄计划。 +- 在 $s_1$ 和 $s_2$ 之间出生的队列面临时变的税率和福利率,而在 $s_2$ 之后出生的队列面临恒定参数。 +- 转型在 $s_3 = s_2 + T_0$ 时结束,此时经历了政策变化的最后一个队列已经死亡。 + +由于要素价格固定,我们可以通过求解在日期 $s_1 - T_0 - 1, \ldots, s_2$ 出生的队列的决策规则来计算转型。 + +对于任何日期 $s$,总消费是通过对所有存活队列求和(沿年龄-时间图中的一条垂直线)计算得出的,并按其人口占比加权。 + +#### 封闭经济 + +在要素价格内生的情况下,转型更为复杂: + +- 要素价格在政策参数于 $s_2$ 稳定后仍继续演变,因此我们遵循 {cite:t}`auerbach1987dynamic`,在 $s_3 = s_2 + 2T_0$ 处截断。 +- 计算需要嵌套迭代:内循环确定劳动收入税率,外循环调整利率以出清要素市场。 +- 储蓄行为的变化会影响资本积累,这会改变边际产量并反馈到家庭决策中。 +- 较低的利率通过提高工资使年轻工人受益,但通过降低储蓄回报使退休人员受损。 + +## 两个实验 + +我们探索向完全融资制社会保障系统转型的两种策略。 + +在实验 1 中,政府终止社会保障福利,但通过一次性增加政府债务来补偿有资格的世代。 + +在实验 2 中,政府保留社会保障福利,但暂时提高税收以积累实物资本,其回报最终为社会保障支付提供资金。 + +两种方案都在维持跨世代福利的同时为向完全融资制社会保障的转型提供资金,但它们涉及不同数量的跨世代风险分担。 + +我们在固定和内生要素价格下计算两个实验,并在下文比较结果。 + +## 计算策略 + +### 动态规划 + +个人消费者的问题可以表述为一个贴现风险敏感线性控制问题(参见 {doc}`lqcontrol`)。 + +设 $x_t = [a_{t-1}, z_t]'$,其中 $z_t$ 是冲击向量。 + +最优值函数具有 $U_t = x'_t \cdot P_t \cdot x_t + \xi_t$ 的形式。 + +递归问题为 + +$$ +U_t = \max_{u_t} \left\{ u'_t Q_t u_t + x'_t R_t x_t + \frac{2 \beta_t}{\sigma} \log E_t[\exp(\sigma U_{t+1}/2)] \right\} +$$ + +服从约束 $x_{t+1} = A_t x_t + B_t u_t + C_t w_{t+1}$。 + +我们部署两个算子 + +$$ +\begin{gathered} +T_t(P)=P+\sigma P C_t\left(I-\sigma C_t^{\prime} P C_t\right)^{-1} C_t^{\prime} P \\ +D_t(W)=R_t+A_t^{\prime}\left[\beta_t W-\beta_t^2 W B_t\left(Q_t+\beta_t B_t^{\prime} W B_t\right)^{-1} B_t^{\prime} W\right] A_t \\ +\mathcal{S}_t(k, P)=\beta_t k-\left(\beta_t / \sigma\right) \log \operatorname{det}\left(I-\sigma C_t^{\prime} P C_t\right) +\end{gathered} +$$ + +我们用它们构造值函数递归 $P_t = (D_t \circ T_t) P_{t+1}$,$\xi_t = \mathcal{S}_t(\xi_{t+1}, P_{t+1})$,以及最优控制 + +$$ +u_t = -F_t x_t, \qquad +F_t = \beta_t \left[Q_t + \beta_t B'_t T_t(P_{t+1}) B_t \right]^{-1} B'_t T_t(P_{t+1}) A_t. +$$ + +算子 $T_t$、$D_t$、$\mathcal{S}_t$ 和决策规则 $F_t$ 在 `solve_riccati_step` 中构造。 + +给定下一年龄的值函数参数 $(P_{t+1}, \xi_{t+1})$,它构造状态空间矩阵 $A_t$,应用叉积技巧,评估里卡蒂算子,并返回最优决策规则 $F_t$、闭环矩阵 $A^o_t = A_t - B F_t$ 以及更新后的 $(P_t, \xi_t)$ + +```{code-cell} ipython3 +def solve_riccati_step( + ε_t, β_t, Ind_work_t, + RR, w, τ_l, τ_a, τ_0, benef, + P_next, ξ_next, + ρ_d, σ, B, C, R, Q, H): + """风险敏感里卡蒂递归的一个后向步骤。""" + + A = jnp.array([ + [RR * (1.0 - τ_a) + τ_a, + (1.0 - τ_l) * w * ε_t + - τ_0 + benef * (1.0 - Ind_work_t), + (1.0 - τ_l) * Ind_work_t], + [0.0, 1.0, 0.0], + [0.0, 0.0, ρ_d] + ]) + + Q_scalar = Q[0, 0] + Q_inv_scalar = 1.0 / Q_scalar + Q_inv = jnp.array([[Q_inv_scalar]]) + + # 叉积技巧:A* = A - B Q^{-1} H + A = A - B @ Q_inv @ H + + # T_t 算子 + CTP = C.T @ P_next @ C + PP_scalar = 1.0 - σ * CTP[0, 0] + PP_inv_scalar = 1.0 / PP_scalar + PC = P_next @ C + CP = C.T @ P_next + TP = P_next + σ * PP_inv_scalar * (PC @ CP) + + # D_t 算子和决策规则 F_t + BTB_scalar = (B.T @ TP @ B)[0, 0] + Q_BTB_scalar = Q_scalar + β_t * BTB_scalar + Q_BTB_inv_scalar = 1.0 / Q_BTB_scalar + BT_TP = B.T @ TP + BT_TP_A = BT_TP @ A + F = β_t * Q_BTB_inv_scalar * BT_TP_A + + TP_B = TP @ B + middle = (β_t * TP + - β_t**2 * Q_BTB_inv_scalar + * (TP_B @ BT_TP)) + P = R + A.T @ middle @ A + + # S_t 算子 + log_det_PP = jnp.log(PP_scalar) + ξ = jnp.where( + σ != 0.0, + β_t * (ξ_next - log_det_PP / σ), + β_t * (ξ_next + CTP[0, 0]) + ) + + Ao = A - B @ F + F = F + Q_inv @ H + + return F.squeeze(), Ao, P, ξ +``` + +### 状态空间准备 + +预算约束 {eq}`two_comp_budget` 和收入过程可以写成状态空间形式。 + +设 $x_t = [a_{t-1}(s-1),\ 1,\ d_t]'$、$u_t = c_t(s)$、$w_{t+1} = \epsilon_{t+1}$,则有 + +$$ +x_{t+1} = A_t x_t + B u_t + C w_{t+1} +$$ + +其中 + +$$ +\begin{aligned} +A_t = \begin{bmatrix} +R(s\!-\!1)(1-\tau^a_t(s))+\tau^a_t(s) & (1-\tau_\ell(s))w(s)\varepsilon_t - \tau_0(s) + S_t(s) & \mathbf{1}^{\text{work}}_t(1-\tau_\ell(s)) \\ +0 & 1 & 0 \\ +0 & 0 & \rho_d +\end{bmatrix}, +\end{aligned} +$$ +$$ +\begin{aligned} +B &= \begin{bmatrix} -1 \\ 0 \\ 0 \end{bmatrix},\\ +C &= \begin{bmatrix} 0 \\ 0 \\ \sigma_d \end{bmatrix} +\end{aligned} +$$ + +且 $\mathbf{1}^{\text{work}}_t$ 表示行为主体是否处于工作年龄。 + +每期回报 $-\tfrac{1}{2}(\pi c_t - \gamma)^2$ 在控制变量与状态变量之间引入一个叉积项 $H$。 + +这可以使用叉积技巧消除(参见 {doc}`cross_product_trick`): + +$$ +A^* = A - BQ^{-1}H, \qquad R^* = R - H'Q^{-1}H. +$$ + +### 均值和协方差 + +定义 $A_o = A - BF$ 为闭环转移矩阵,使得 $x_{t+1} = A_o x_t + C w_{t+1}$ 且无条件矩满足 + +$$ +\mu_{t+1} = A_{o,t} \mu_t, \qquad +\Sigma_{t+1} = A_{o,t} \Sigma_t A_{o,t}' + CC'. +$$ + +矩递归实现为 `forward_moment_step`,它按一个年龄步长传播均值向量和协方差矩阵,并将消费统计量作为副产品计算。 + +```{code-cell} ipython3 +def forward_moment_step(μx_t, Σx_t, Ao_t, F_t, CCT): + """前向矩递归的一个步骤。""" + + μx_next = Ao_t @ μx_t + μc_t = -F_t @ μx_t + Σx_next = CCT + Ao_t @ Σx_t @ Ao_t.T + Vc_t = F_t @ Σx_t @ F_t.T + return μx_next, μc_t, Σx_next, Vc_t +``` + +### 计算转型 + +在 $s$ 出生的队列在 $s, s+1, \ldots, s+T_0$ 各期存活,在 $s, s+1, \ldots, s+T_1$ 各期工作。 + +设 $0 \leq s_1 < s_2 < s_3$。 + +- 在 $s = 0$ 时,政府宣布在 $s = s_1$ 和 $s = s_2$ 之间的政策变化。 +- 从 $s = s_2$ 起,政府政策永久保持恒定。 +- 从 $s = s_3$ 起,实现向最终平稳均衡的收敛(在小型开放经济中,$s_3 = s_2 + T_0$)。 + +受影响的队列是那些在 $s = s_1 - T_0, s_1 - T_0 + 1, \ldots, s_2$ 出生的队列。 + +在所有练习中,我们设置 $T_0 = 65$、$T_1 = 43$、$s_1 = 0$ 和 $s_2 = 40$。 + +## 校准 + +模型参数设置如下。 + +### 偏好参数 + +| 参数 | 描述 | 值 | +|-----------|-------------|-------| +| $\{\alpha_t\}_{t=0}^{T_0}$ | 年龄间存活概率 | {cite:t}`faber1982life` | +| $\pi$ | 消费偏好参数 | 1.0 | +| $\sigma$ | 风险敏感性参数 | $-0.05$ | +| $\bar{\gamma}$ | 偏好冲击参数 | 7.0 | +| $\tilde{\beta}$ | 贴现因子 | 0.986 | +| $T_0$ | 最大年龄 | 65 | +| $T_1$ | 退休年龄 | 43 | +| $n$ | 人口总增长率 | 1.012 | + +### 技术参数 + +| 参数 | 描述 | 值 | +|-----------|-------------|-------| +| $k_{-1}$ | 初始资本禀赋 | 4.0 | +| $\sigma_d$ | 收入冲击的标准差 | 0.85 | +| $\rho_d$ | 收入冲击的持续性 | 0.8 | +| $\delta$ | 折旧率 | 0.06 | +| $\{\varepsilon_t\}_{t=0}^{T_1}$ | 年龄-效率剖面 | {cite:t}`hansen1993cyclical` | +| $w$ | 基础工资率(外生) | 5.0147 | +| $r$ | 资本回报(外生) | 0.1275 | +| $\tilde{A}$ | 生产函数缩放系数(内生) | 2.2625 | +| $\tilde{\alpha}$ | 资本份额(内生) | 0.40 | + +```{code-cell} ipython3 +N_GRID_SS = 10 +TOL_SS = 1e-10 + +T0 = 65 # 最大寿命(年龄 21 到 86) +T1 = 43 # 工作生涯长度(65 岁退休) + +UNIT_GRID = jnp.linspace(0.0, 1.0, N_GRID_SS) +AGE_INDICES = jnp.arange(T0 + 2) +``` + +下面隐藏的代码单元基于 {cite:t}`faber1982life` 和 {cite:t}`hansen1993cyclical` 定义了年龄-效率剖面 $\{\varepsilon_t\}$ 和存活概率 $\{\alpha_t\}$。 + +```{code-cell} ipython3 +:tags: [hide-cell] + +ε_arr = jnp.array([ + 0.59031284, 0.62902188, 0.66773093, 0.70643996, 0.745149, + 0.78385804, 0.82256708, 0.86127611, 0.89998515, 0.92861368, + 0.94716179, 0.9657099, 0.98425792, 1.002806, 1.0211928, + 1.0399022, 1.0584503, 1.0769984, 1.0955465, 1.1056269, + 1.1072398, 1.1088527, 1.1104656, 1.1120784, 1.1136913, + 1.1153042, 1.116917, 1.1185299, 1.1201428, 1.1185299, + 1.1136913, 1.1088527, 1.1040141, 1.0991755, 1.0943368, + 1.0894981, 1.0846595, 1.0798209, 1.0749823, 1.0611115, + 1.0382087, 1.0153058, 0.99240301, 0.96958081 +]) + +α_arr = jnp.array([ + 1.0, 0.99851, 0.99844, 0.99838, 0.99832, 0.99826, 0.9982, + 0.99816, 0.99815, 0.99819, 0.99826, 0.99834, 0.9984, 0.99843, + 0.99841, 0.99835, 0.99828, 0.99818, 0.99807, 0.99794, 0.99778, + 0.99759, 0.99737, 0.99712, 0.99684, 0.99653, 0.99619, 0.9958, + 0.99535, 0.99481, 0.99419, 0.9935, 0.99278, 0.99209, 0.99148, + 0.99088, 0.99021, 0.98942, 0.98851, 0.98746, 0.98625, 0.98495, + 0.9835, 0.98178, 0.97974, 0.97743, 0.97489, 0.97226, 0.96965, + 0.96715, 0.96466, 0.962, 0.95907, 0.9559, 0.95246, 0.94872, + 0.9446, 0.94017, 0.93555, 0.93077, 0.9257, 0.9203, 0.91431, + 0.90742, 0.89948 +]) +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 年龄-效率剖面和存活概率 + name: two_comp_profiles +--- + +fig, axs = plt.subplots(1, 2, figsize=(10, 6)) + +axs[0].plot(ε_arr) +axs[0].set_title("工作效率") +axs[0].set_xlabel("年龄") + +axs[1].plot(α_arr) +axs[1].set_title("存活概率") +axs[1].set_xlabel("年龄") + +plt.tight_layout() +plt.show() +``` + +我们对终端资产持有量施加较大的惩罚以强制执行生命终结条件,并将初始状态设置为 $x_0 = [k_{-1},\ 1,\ 0]'$。 + +```{code-cell} ipython3 +P_end = jnp.zeros((3, 3)) +P_end = P_end.at[0, 0].set(-2000000.0) +ξ_end = 0.0 + +x0 = jnp.array([4.0, 1.0, 0.0]) +Σ0 = jnp.zeros((3, 3)) +``` + +所有家庭参数被收集到一个命名元组中。 + +```{code-cell} ipython3 +Household = namedtuple('Household', ( + 'α_arr', 'frac', 'n', 'π', 'σ', 'k_init', 'ε_arr', 'Ind_work', + 'σ_d', 'ρ_d', 'γ_bar', 'β_arr', + 'T0', 'T1', 'T2', 'n_x', 'n_w', + 'P_end', 'ξ_end', 'x0', 'Σ0', + 'B', 'C', 'R', 'Q', 'H' +)) + +def create_household(α_arr=α_arr, # 年龄间存活概率 + n=1.012, # 人口总增长率 + π=1, # 消费偏好参数 + σ=-0.05, # 风险敏感性参数 + k_init=4, # 初始资本禀赋 + ε_arr=ε_arr, # 年龄-效率剖面 + σ_d=0.85, # 收入冲击的标准差 + ρ_d=0.8, # 收入冲击的持续性 + γ_bar=7, # 偏好冲击参数 + β_tilde=0.986, # 贴现因子 + T0=65, # 最大年龄 + T1=43, # 退休年龄 + n_x=3, # 状态数 + n_w=1, # 冲击数 + P_end=P_end, # 终端值 + ξ_end=ξ_end, # 终端值 + x0=x0, # 初始均值 + Σ0=Σ0): # 初始方差 + """创建带有派生数组的 Household 命名元组。""" + + α_arr = np.concatenate([α_arr, np.array([0])]) + T2 = T0 - T1 + + frac = np.ones(T0 + 1) + frac[1:] = np.cumprod(α_arr / n)[:-1] + frac = frac / frac.sum() + + ε_arr = np.concatenate([ε_arr, np.zeros(T0 + 1 - ε_arr.size)]) + + # 工作年龄指示器:工作时(ε > 0)为 1,退休时为 0 + Ind_work = (ε_arr != 0).astype(np.float64) + + β_arr = β_tilde * α_arr + β_arr[-1] = β_tilde + + B = jnp.array([[-1.0, 0.0, 0.0]]).T + C = jnp.array([[0.0, 0.0, σ_d]]).T + + Q = jnp.array([[-0.5 * π**2]]) + H = jnp.array([[0.0, 0.5 * π * γ_bar, 0.0]]) + + # 应用叉积技巧:R* = R - H'Q^{-1}H + R_base = np.array([[0.0, 0.0, 0.0], + [0.0, -0.5 * γ_bar**2, 0.0], + [0.0, 0.0, 0.0]]) + H_np = np.array([[0.0, 0.5 * π * γ_bar, 0.0]]) + Q_inv_np = np.array([[1.0 / (-0.5 * π**2)]]) + R = jnp.array(R_base - H_np.T @ Q_inv_np @ H_np) + + return Household( + α_arr=jnp.array(α_arr), frac=jnp.array(frac), n=n, π=π, σ=σ, + k_init=k_init, ε_arr=jnp.array(ε_arr), Ind_work=jnp.array(Ind_work), + σ_d=σ_d, ρ_d=ρ_d, γ_bar=γ_bar, β_arr=jnp.array(β_arr), + T0=T0, T1=T1, T2=T2, n_x=n_x, n_w=n_w, + P_end=P_end, ξ_end=ξ_end, x0=x0, Σ0=Σ0, + B=B, C=C, R=R, Q=Q, H=H + ) +``` + +```{code-cell} ipython3 +hh = create_household() +``` + +平稳人口分布如下。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 按年龄的平稳人口分布 + name: two_comp_pop_dist +--- +fig, ax = plt.subplots() +ax.plot(hh.frac) +ax.set_xlabel("年龄") +ax.set_ylabel("人口占比") +ax.set_title("按年龄的人口分布") +plt.show() +``` + +死亡率导致人口占比随年龄下降,这种人口模式是社会保障改革所涉及的跨世代再分配的核心。 + +在小型开放经济假设下,要素价格固定于校准值;在封闭经济假设下,它们由科布-道格拉斯边际产量决定 + +```{code-cell} ipython3 +Tech = namedtuple('Tech', ('δ', 'w', 'r', 'RR', 'A', 'α_tilde')) + +def create_Tech(δ=0.06, w=5.0147, r=0.1275, + A=2.2625, α_tilde=0.40): + """创建带有要素价格参数的 Tech 命名元组。""" + + RR = 1 + r - δ + + return Tech(δ=δ, w=w, r=r, RR=RR, A=A, α_tilde=α_tilde) +``` + +```{code-cell} ipython3 +tech = create_Tech() +``` + +## 个人最优性 + +### 稳态计算 + +有了 `solve_riccati_step` 和 `forward_moment_step`,稳态计算分三个阶段进行。 + +```{prf:algorithm} 稳态计算 +1. **后向递归:** 从年龄 $T_0$ 向下扫描到 $0$。 + 在每个年龄 $t$,调用 `solve_riccati_step` 获得 + 决策规则 $F_t$、闭环矩阵 $A^o_t$、 + 值函数矩阵 $P_t$ 和确定性等价 $\xi_t$。 + +2. **前向模拟:** 从年龄 $0$ 向上扫描到 $T_0$。 + 在每个年龄 $t$,调用 `forward_moment_step` 传播 + 状态向量的均值 $\mu_{x,t}$ 和协方差 $\Sigma_{x,t}$, + 并记录平均消费 $\mu_{c,t}$ 及其方差 $V_{c,t}$。 + +3. **预算失衡:** 跨队列汇总。 + 对税收(劳动、资本、总额)求和, + 减去福利支付,加上意外遗产, + 并返回政府预算缺口。 +``` + +*阶段 1。* 后向递归从年龄 $T_0$ 扫描到 $0$,在每个年龄应用 `solve_riccati_step` + +```{code-cell} ipython3 +def _ss_backward_recursion( + ε_arr, β_arr, Ind_work, + RR, w, τ_l, τ_a, τ_0, benef, + P_end, ξ_end, + ρ_d, σ, B, C, R, Q, H): + """在所有年龄上的后向里卡蒂扫描。""" + + ε_rev = ε_arr[::-1] + β_rev = β_arr[::-1] + Ind_work_rev = Ind_work[::-1] + + def backward_step(carry, inputs): + P_next, ξ_next = carry + ε_t, β_t, Ind_work_t = inputs + F, Ao, P, ξ = solve_riccati_step( + ε_t, β_t, Ind_work_t, + RR, w, τ_l, τ_a, τ_0, benef, + P_next, ξ_next, + ρ_d, σ, B, C, R, Q, H + ) + return (P, ξ), (F, Ao, P, ξ) + + init_carry = (P_end, ξ_end) + _, (F_rev, Ao_rev, P_rev, ξ_rev) = lax.scan( + backward_step, init_carry, + (ε_rev, β_rev, Ind_work_rev) + ) + + F_arr = F_rev[::-1] + Ao_arr = Ao_rev[::-1] + P_inner = P_rev[::-1] + ξ_inner = ξ_rev[::-1] + + P_arr = jnp.concatenate( + [P_inner, P_end[None, :, :]], axis=0 + ) + ξ_arr = jnp.concatenate( + [ξ_inner, jnp.array([ξ_end])] + ) + + return F_arr, Ao_arr, P_arr, ξ_arr +``` + +*阶段 2。* 前向递归将均值和协方差从年龄 $0$ 传播到 $T_0$ + +```{code-cell} ipython3 +def _ss_forward_simulation( + Ao_arr, F_arr, x0, Σ0, C): + """使用 forward_moment_step 的前向矩扫描。""" + + CCT = C @ C.T + + def forward_step(carry, inputs): + μx_t, Σx_t = carry + Ao_t, F_t = inputs + result = forward_moment_step( + μx_t, Σx_t, Ao_t, F_t, CCT + ) + μx_next, μc_t, Σx_next, Vc_t = result + return (μx_next, Σx_next), \ + (μx_next, μc_t, Σx_next, Vc_t) + + init_carry = (x0, Σ0) + _, (μx_scn, μc_arr, Σx_scn, Vc_arr) = lax.scan( + forward_step, init_carry, (Ao_arr, F_arr) + ) + + μx_arr = jnp.concatenate( + [x0[None, :], μx_scn], axis=0 + ) + Σx_arr = jnp.concatenate( + [Σ0[None, :, :], Σx_scn], axis=0 + ) + + return μx_arr, μc_arr, Σx_arr, Vc_arr +``` + +*阶段 3。* 跨队列汇总税收、福利支付和意外遗产给出政府预算缺口 + +```{code-cell} ipython3 +def _ss_budget_imbalance( + μx_arr, ε_arr, frac, n, α_arr, + RR, w, τ_l, τ_a, τ_0, benef, + G, Gb, Ind_work): + """汇总税收和支出。""" + + μa_arr = μx_arr[1:, 0] + μa_last_arr = μx_arr[:-1, 0] + + τ_l_tot = jnp.sum(τ_l * ε_arr * w * frac) + τ_a_tot = jnp.sum( + τ_a * (RR - 1.0) * μa_last_arr * frac + ) + τ_0_tot = jnp.sum(τ_0 * frac) + + retired_mask = 1.0 - Ind_work + benef_tot = jnp.sum(benef * frac * retired_mask) + + Beq = jnp.sum( + RR * (1.0 - α_arr) * frac * μa_arr / n + ) + + T_tot = τ_l_tot + τ_a_tot + τ_0_tot + Beq + diff = (G + benef_tot - T_tot + + (RR / n - 1.0) * Gb) + + return diff +``` + +当预算缺口等于零时,就找到了稳态。 + +`ss_imbalance` 将三个阶段链接成一个 JIT 编译的函数:后向递归、前向模拟和预算缺口 + +```{code-cell} ipython3 +@jit +def ss_imbalance(price, policy, α_arr, ε_arr, frac, + n, β_arr, ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, Ind_work): + """后向求解、前向模拟,并返回预算缺口。""" + + RR, w = price + τ_l, τ_a, τ_0, benef, G, Gb = policy + + F_arr, Ao_arr, P_arr, ξ_arr = \ + _ss_backward_recursion( + ε_arr, β_arr, Ind_work, + RR, w, τ_l, τ_a, τ_0, benef, + P_end, ξ_end, + ρ_d, σ, B, C, R, Q, H + ) + + μx_arr, μc_arr, Σx_arr, Vc_arr = \ + _ss_forward_simulation( + Ao_arr, F_arr, x0, Σ0, C + ) + + diff = _ss_budget_imbalance( + μx_arr, ε_arr, frac, n, α_arr, + RR, w, τ_l, τ_a, τ_0, benef, + G, Gb, Ind_work + ) + + return (diff, P_arr, ξ_arr, Ao_arr, F_arr, + μx_arr, μc_arr, Σx_arr, Vc_arr) +``` + +一个命名元组 `SteadyState` 将值函数参数、决策规则、矩和总量统计量收集到一个对象中,转型求解器可以将其解包 + +```{code-cell} ipython3 +SteadyState = namedtuple("SteadyState", ( + "P_arr", # 按年龄的值函数矩阵 + "ξ_arr", # 按年龄的确定性等价调整 + "Ao_arr", # 按年龄的闭环转移矩阵 + "F_arr", # 按年龄的决策规则矩阵 + "μx_arr", # 按年龄的均值状态向量 + "μc_arr", # 按年龄的平均消费 + "Σx_arr", # 按年龄的协方差矩阵 + "Vc_arr", # 按年龄的消费方差 + "debt2gdp", # 政府债务与GDP之比 + "τ_l", # 劳动收入税率 + "benef", # 社会保障福利水平 + "Gb", # 人均政府债务 + "k_bar", # 人均资本存量 + "RR", # 资产总回报 + "w", # 工资率 + "r", # 利率(折旧前) + "k2gdp" # 资本与GDP之比 +)) +``` + +给定所有其他财政工具,均衡 $\tau_\ell$ 是使预算缺口归零的值。 + +我们通过迭代网格细化找到它:在粗网格上评估缺口,放大到最佳区间,然后重复 + +```{code-cell} ipython3 +def _grid_refine(eval_fn, a_init, b_init, unit_grid, tol, max_iter): + """迭代网格细化根搜索。 + + 必须在 @jit 函数内部调用。 + """ + + n_grid = unit_grid.shape[0] + + def cond_fn(state): + a, b, best_val, i = state + return (jnp.abs(best_val) > tol) & (i < max_iter) + + def body_fn(state): + a, b, _, i = state + grid = a + (b - a) * unit_grid + diffs = vmap(eval_fn)(grid) + best_idx = jnp.argmin(jnp.abs(diffs)) + best_val = diffs[best_idx] + idx_lo = jnp.maximum(best_idx - 1, 0) + idx_hi = jnp.minimum(best_idx + 1, n_grid - 1) + return (grid[idx_lo], grid[idx_hi], best_val, i + 1) + + grid = a_init + (b_init - a_init) * unit_grid + diffs = vmap(eval_fn)(grid) + best_idx = jnp.argmin(jnp.abs(diffs)) + best_val = diffs[best_idx] + idx_lo = jnp.maximum(best_idx - 1, 0) + idx_hi = jnp.minimum(best_idx + 1, n_grid - 1) + + init_state = (grid[idx_lo], grid[idx_hi], best_val, 0) + final_state = lax.while_loop(cond_fn, body_fn, init_state) + a_final, b_final, _, _ = final_state + return (a_final + b_final) / 2.0 +``` + +`_ss_diff_for_tau_l` 在给定 $\tau_\ell$ 处评估预算缺口,`_find_ss_tau_l` 将其包装在网格细化循环内。 + +```{code-cell} ipython3 +def _ss_diff_for_tau_l(τ_l, price_arr, policy_no_τl, α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, P_end, ξ_end, x0, Σ0, + Ind_work): + """给定 τ_l 的预算失衡。""" + + τ_a, τ_0, benef, G, Gb = policy_no_τl + policy_arr = jnp.array([τ_l, τ_a, τ_0, benef, G, Gb]) + diff, *_ = ss_imbalance( + price_arr, policy_arr, + α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, P_end, ξ_end, x0, Σ0, + Ind_work + ) + return diff +``` + +```{code-cell} ipython3 +@jit +def _find_ss_tau_l(price_arr, policy_no_τl, α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, P_end, ξ_end, x0, Σ0, + Ind_work, unit_grid): + """找到使稳态预算平衡的 τ_l。""" + + def compute_diff(τ_l): + return _ss_diff_for_tau_l( + τ_l, price_arr, policy_no_τl, α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, P_end, ξ_end, x0, Σ0, + Ind_work + ) + + return _grid_refine(compute_diff, -0.5, 1.0 - 1e-5, unit_grid, TOL_SS, 10) +``` + +GDP 是资本和劳动收入份额之和 + +```{code-cell} ipython3 +def _compute_gdp(μa_arr, frac, ε_arr, Gb, r, w, n, x0_0, frac_0): + """从总量计算 GDP。""" + + ε_agg = jnp.sum(frac * ε_arr) + a_agg = jnp.sum(frac * μa_arr) + k_agg = a_agg - Gb + k_share = r * (k_agg / n + frac_0 * x0_0) + l_share = w * ε_agg + return k_agg, k_share + l_share +``` + +`find_ss_exo` 将各部分组合起来:它求解 $\tau_\ell$、评估完整稳态,并返回一个 `SteadyState` 命名元组 + +```{code-cell} ipython3 +def find_ss_exo(price, policy_target, hh, tech): + """通过求解 τ_l 找到外生价格下的稳态。""" + + frac, ε_arr, n, x0 = hh.frac, hh.ε_arr, hh.n, hh.x0 + RR, w = price + r = RR - 1 + tech.δ + + τ_a, τ_0, benef, G, Gb = policy_target + + price_arr = jnp.array([RR, w]) + policy_no_τl = jnp.array([τ_a, τ_0, benef, G, Gb]) + + τ_l = _find_ss_tau_l( + price_arr, policy_no_τl, + hh.α_arr, hh.ε_arr, hh.frac, hh.n, + hh.β_arr, hh.ρ_d, hh.σ, hh.B, hh.C, hh.R, hh.Q, hh.H, + hh.P_end, hh.ξ_end, hh.x0, hh.Σ0, + hh.Ind_work, UNIT_GRID + ) + + price_arr = jnp.array([RR, w]) + policy_arr = jnp.array([float(τ_l), τ_a, τ_0, benef, G, Gb]) + diff, P_arr, ξ_arr, Ao_arr, F_arr, μx_arr, μc_arr, Σx_arr, Vc_arr = \ + ss_imbalance( + price_arr, policy_arr, + hh.α_arr, hh.ε_arr, hh.frac, hh.n, + hh.β_arr, hh.ρ_d, hh.σ, + hh.B, hh.C, hh.R, hh.Q, hh.H, + hh.P_end, hh.ξ_end, hh.x0, hh.Σ0, + hh.Ind_work + ) + + k_agg, gdp = _compute_gdp( + μx_arr[1:, 0], frac, ε_arr, + Gb, r, w, n, x0[0], frac[0] + ) + debt2gdp = Gb / gdp + k2gdp = k_agg / gdp + + return SteadyState( + P_arr=P_arr, ξ_arr=ξ_arr, Ao_arr=Ao_arr, F_arr=F_arr, + μx_arr=μx_arr, μc_arr=μc_arr, Σx_arr=Σx_arr, Vc_arr=Vc_arr, + debt2gdp=float(debt2gdp), τ_l=float(τ_l), benef=benef, Gb=Gb, + k_bar=float(k_agg), RR=RR, w=w, r=float(r), k2gdp=float(k2gdp) + ) +``` + +初始财政政策设定社会保障替代率为 $\theta = 0.6$ + +```{code-cell} ipython3 +aveinc = tech.w * sum(hh.ε_arr) / (hh.T1 + 1) +θ = 0.6 +benef_0 = aveinc * θ + +G_0 = 1.44 # 政府购买 +Gb_0 = 2.8 * G_0 # 政府债务 +τ_l_0 = 0.3385 # 劳动收入税 +τ_a_0 = 0.30 # 资本收入税 +τ_0_0 = 0 # 总额税 + +RR, w = tech.RR, tech.w +``` + +### 初始和终端稳态 + +初始稳态具有校准的替代率($\theta = 0.6$)、正的社会保障福利,以及为匹配目标而设置的政府支出和债务。 + +转型日期为 $s_1 = 0$ 和 $s_2 = 40$,视界为 $S = 140$(外生价格)和 $S = 200$(内生价格)。 + +```{code-cell} ipython3 +S_exo = 140 +S_endo = 200 +S1, S2 = 0, 40 +S3 = S2 + 2 * hh.T0 + +RR_exo, w_exo = tech.RR, tech.w +``` + +两个辅助函数构建转型求解器所期望的价格和政策数组。 + +在小型开放经济假设下,价格随时间恒定。 + +```{code-cell} ipython3 +def make_exo_price_seq(S, RR, w): + """为小型开放经济构造恒定价格序列。""" + + return jnp.column_stack([jnp.full(S + 2, RR), jnp.full(S + 2, w)]) +``` + +政策序列在 $s_1$ 之前将 $\tau_\ell$ 设为初始稳态值,在 $s_2$ 之后设为终端值,同时保持所有其他财政工具恒定。 + +```{code-cell} ipython3 +def make_policy_seq(S, ss0_τl, ss1_τl, S1, S2, τ_a, τ_0, benef, G, Gb): + """构造带有初始/终端 + τ_l 和恒定其他政策的政策序列。""" + + policy_seq = jnp.empty((S + 2, 6)) + policy_seq = policy_seq.at[:S1 + 1, 0].set(ss0_τl) + policy_seq = policy_seq.at[S2 + 1:, 0].set(ss1_τl) + policy_seq = policy_seq.at[:, 1].set(τ_a) + policy_seq = policy_seq.at[:, 2].set(τ_0) + policy_seq = policy_seq.at[:, 3].set(benef) + policy_seq = policy_seq.at[:, 4].set(G) + policy_seq = policy_seq.at[:, 5].set(Gb) + return policy_seq +``` + +```{code-cell} ipython3 +ss0 = find_ss_exo((RR, w), (τ_a_0, τ_0_0, benef_0, G_0, Gb_0), hh, tech) + +print(f"初始稳态 (s < 0):") +print(f" 劳动税 τ_l = {ss0.τ_l:.4f}") +print(f" 利率 r - δ = {ss0.r - tech.δ:.4f}") +print(f" 资本/GDP = {ss0.k2gdp:.4f}") +print(f" 债务/GDP = {ss0.debt2gdp:.4f}") +``` + +下图追踪了均衡劳动税率在终端稳态(无社会保障)下如何随政府债务变化 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 债务与GDP之比作为劳动税率的函数 + name: two_comp_debt_tau +--- +Gb_arr = np.linspace(0.5 * Gb_0, 1.5 * Gb_0, 20) +τl_arr = np.empty_like(Gb_arr) +debt2gdp_arr = np.empty_like(Gb_arr) + +for i, Gb in enumerate(Gb_arr): + ss = find_ss_exo((RR, w), (τ_a_0, τ_0_0, 0, G_0, Gb), hh, tech) + τl_arr[i] = ss.τ_l + debt2gdp_arr[i] = ss.debt2gdp + +fig, ax = plt.subplots() +ax.plot(τl_arr, debt2gdp_arr) +ax.hlines(ss0.debt2gdp, τl_arr.min(), + np.maximum(τl_arr.max(), ss0.τ_l), linestyle='--', color='r') +ax.scatter(ss0.τ_l, ss0.debt2gdp) +ax.text(ss0.τ_l * 0.95, ss0.debt2gdp * 0.95, "ss0") +ax.text(0.07, 0.4, r"ss1($G_b$)") +ax.set_xlabel(r'$\tau_\ell$') +ax.set_ylabel('债务/GDP') +plt.show() +``` + +较高的政府债务需要更大的利息支付,因此均衡劳动税上升。 + +标记点显示了初始稳态。 + +为了设定终端稳态,我们需要反转这个关系:给定目标债务与GDP之比,找到债务水平 $\bar{b}$ 和相关的 $\tau_\ell$。 + +```{code-cell} ipython3 +def _compute_debt2gdp_for_Gb( + Gb, price_arr, policy_no_Gb, + α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, + δ, Ind_work, unit_grid): + """计算给定 Gb 的债务与GDP之比。""" + + RR, w = price_arr + τ_a, τ_0, benef, G = policy_no_Gb + r = RR - 1 + δ + + policy_no_τl = jnp.array([τ_a, τ_0, benef, G, Gb]) + + # 重用 _find_ss_tau_l 而不是重复网格搜索 + τ_l = _find_ss_tau_l( + price_arr, policy_no_τl, α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, P_end, ξ_end, x0, Σ0, + Ind_work, unit_grid + ) + + policy_arr = jnp.array([τ_l, τ_a, τ_0, benef, G, Gb]) + _, _, _, _, _, μx_arr, _, _, _ = ss_imbalance( + price_arr, policy_arr, + α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, P_end, ξ_end, x0, Σ0, + Ind_work + ) + + _, gdp = _compute_gdp( + μx_arr[1:, 0], frac, ε_arr, + Gb, r, w, n, x0[0], frac[0] + ) + return Gb / gdp +``` + +`_find_Gb_for_debt2gdp` 通过网格细化搜索 $\bar{b}$ 值以匹配目标债务与GDP之比。 + +```{code-cell} ipython3 +@jit +def _find_Gb_for_debt2gdp( + debt2gdp_target, price_arr, policy_no_Gb, + α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, + δ, Ind_work, unit_grid, unit_grid_tau): + """找到与目标债务与GDP之比一致的 Gb。""" + + RR, w = price_arr + τ_a, τ_0, benef, G = policy_no_Gb + + def compute_diff_coarse(Gb): + debt2gdp = _compute_debt2gdp_for_Gb( + Gb, price_arr, policy_no_Gb, α_arr, ε_arr, frac, n, + β_arr, ρ_d, σ, B, C, R, Q, H, P_end, ξ_end, x0, Σ0, + δ, Ind_work, unit_grid_tau + ) + return debt2gdp - debt2gdp_target + + return _grid_refine(compute_diff_coarse, -40.0, 20.0, unit_grid, TOL_SS, 5) +``` + +`ss_target_debt2gdp_exo` 找到与目标比率一致的债务水平,然后计算完整稳态。 + +```{code-cell} ipython3 +def ss_target_debt2gdp_exo(debt2gdp_target, policy_target, price, hh, tech): + """找到具有目标债务与GDP之比的稳态。""" + + τ_a, τ_0, benef, G = policy_target + RR, w = price + + price_arr = jnp.array([RR, w]) + policy_no_Gb = jnp.array([τ_a, τ_0, benef, G]) + + Gb = _find_Gb_for_debt2gdp( + float(debt2gdp_target), price_arr, policy_no_Gb, + hh.α_arr, hh.ε_arr, hh.frac, hh.n, + hh.β_arr, hh.ρ_d, hh.σ, hh.B, hh.C, hh.R, hh.Q, hh.H, + hh.P_end, hh.ξ_end, hh.x0, hh.Σ0, tech.δ, + hh.Ind_work, UNIT_GRID, UNIT_GRID + ) + + return find_ss_exo((RR, w), (τ_a, τ_0, benef, G, float(Gb)), hh, tech) +``` + +终端稳态消除社会保障($\theta = 0$),同时匹配初始债务与GDP之比 + +```{code-cell} ipython3 +ss1 = ss_target_debt2gdp_exo( + ss0.debt2gdp, (τ_a_0, τ_0_0, 0, G_0), (RR_exo, w_exo), hh, tech +) + +print(f"\n终端稳态 (s >= s3):") +print(f" 劳动税 τ_l = {ss1.τ_l:.4f}") +print(f" 福利 θ = 0") +print(f" 资本/GDP = {ss1.k2gdp:.4f}") +print(f" 债务/GDP = {ss1.debt2gdp:.4f}") +``` + +## 转型路径计算 + +转型路径描述经济体如何从初始稳态(有社会保障)转向终端稳态(改革后)。 + +这比稳态计算更复杂,因为价格和政策随时间变化,因此每个队列面临独特的税收和福利率的生命周期序列。 + +`solve_backwards` 在转型期间随时间后向求解家庭问题,计算每个日历日期 $s$ 和年龄 $t$ 的最优决策规则 $F_t(s)$ 和闭环转移矩阵 $A^o_t(s)$。 + +```{code-cell} ipython3 +@jit +def solve_backwards( + price_seq, policy_seq, + P_arr_ss1, ξ_arr_ss1, + ε_arr, β_arr, Ind_work, + ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, + s_indices, ages): + """在所有日期和年龄上的后向里卡蒂扫描。""" + + # 从输入数组推断维度 + n_x = P_end.shape[0] + S = s_indices.shape[0] - 1 + + def solve_all_ages(P_next_all, ξ_next_all, RR_s, w_s, τ_l, τ_a, τ_0, benef): + def solve_one_age(t, P_next, ξ_next): + ε_t = ε_arr[t] + β_t = β_arr[t] + Ind_work_t = Ind_work[t] + F, Ao, P, ξ = solve_riccati_step( + ε_t, β_t, Ind_work_t, RR_s, w_s, τ_l, τ_a, τ_0, benef, + P_next, ξ_next, ρ_d, σ, B, C, R, Q, H + ) + return F, Ao, P, ξ + + P_next_shifted = P_next_all[1:] + ξ_next_shifted = ξ_next_all[1:] + + F_all, Ao_all, P_all, ξ_all = vmap( + solve_one_age + )(ages, P_next_shifted, ξ_next_shifted) + return F_all, Ao_all, P_all, ξ_all + + def scan_body(carry, s_inv): + P_next_seq, ξ_next_seq = carry + s = S - s_inv + + RR_s = price_seq[s, 0] + w_s = price_seq[s, 1] + τ_l = policy_seq[s, 0] + τ_a = policy_seq[s, 1] + τ_0 = policy_seq[s, 2] + benef = policy_seq[s, 3] + + F_s, Ao_s, P_s, ξ_s = solve_all_ages( + P_next_seq, ξ_next_seq, RR_s, w_s, τ_l, τ_a, τ_0, benef + ) + + # 使用输入数组的已知形状构建 P_curr 和 ξ_curr + P_curr = jnp.zeros_like(P_arr_ss1) + P_curr = P_curr.at[:T0+1].set(P_s) + P_curr = P_curr.at[-1].set(P_end) + + ξ_curr = jnp.zeros_like(ξ_arr_ss1) + ξ_curr = ξ_curr.at[:T0+1].set(ξ_s) + ξ_curr = ξ_curr.at[-1].set(ξ_end) + + output = (F_s, Ao_s, P_s, ξ_s) + new_carry = (P_curr, ξ_curr) + + return new_carry, output + + init_carry = (P_arr_ss1, ξ_arr_ss1) + + # s_indices 已经具有正确的长度 + _, outputs = lax.scan(scan_body, init_carry, s_indices) + + F_seq, Ao_seq, P_seq_inner, ξ_seq_inner = outputs + + F_seq = jnp.flip(F_seq, axis=0) + Ao_seq = jnp.flip(Ao_seq, axis=0) + + # 使用 price_seq 的形状构建输出数组 + P_seq = jnp.zeros((price_seq.shape[0], P_arr_ss1.shape[0], n_x, n_x)) + ξ_seq = jnp.zeros((price_seq.shape[0], ξ_arr_ss1.shape[0])) + + P_seq_inner = jnp.flip(P_seq_inner, axis=0) + ξ_seq_inner = jnp.flip(ξ_seq_inner, axis=0) + P_seq = P_seq.at[:S+1, :T0+1].set(P_seq_inner) + ξ_seq = ξ_seq.at[:S+1, :T0+1].set(ξ_seq_inner) + + P_seq = P_seq.at[:, -1].set(P_end) + ξ_seq = ξ_seq.at[:, -1].set(ξ_end) + P_seq = P_seq.at[-1, :].set(P_arr_ss1) + ξ_seq = ξ_seq.at[-1, :].set(ξ_arr_ss1) + + return F_seq, Ao_seq, P_seq, ξ_seq +``` + +`simulate_forwards` 采用计算出的决策规则,从初始分布前向模拟经济体,追踪转型期间资产均值和方差跨队列的演变。 + +```{code-cell} ipython3 +@jit +def simulate_forwards( + Ao_seq, F_seq, μx_init, Σx_init, + C, x0, Σ0, s_indices, ages): + """在所有日期和年龄上的前向矩扫描。""" + + # 从输入数组推断维度 + n_x = x0.shape[0] + CCT = C @ C.T + S = s_indices.shape[0] - 1 + + def simulate_all_ages(μx_curr, Σx_curr, Ao_s, F_s): + def simulate_one_age(t, μx_t, Σx_t, Ao_t, F_t): + return forward_moment_step( + μx_t, Σx_t, Ao_t, F_t, CCT + ) + + μx_next_all, μc_all, Σx_next_all, Vc_all = vmap(simulate_one_age)( + ages, μx_curr[:T0+1], Σx_curr[:T0+1], Ao_s, F_s + ) + return μx_next_all, μc_all, Σx_next_all, Vc_all + + def scan_body(carry, s): + μx_curr, Σx_curr = carry + + Ao_s = Ao_seq[s] + F_s = F_seq[s] + + μx_next_inner, μc_s, Σx_next_inner, Vc_s = simulate_all_ages( + μx_curr, Σx_curr, Ao_s, F_s + ) + + # 使用 μx_init 的形状 + μx_next = jnp.zeros_like(μx_init) + μx_next = μx_next.at[0].set(x0) + μx_next = μx_next.at[1:T0+2].set(μx_next_inner) + + Σx_next = jnp.zeros_like(Σx_init) + Σx_next = Σx_next.at[0].set(Σ0) + Σx_next = Σx_next.at[1:T0+2].set(Σx_next_inner) + + output = (μx_curr, μc_s, Σx_curr, Vc_s) + new_carry = (μx_next, Σx_next) + + return new_carry, output + + init_carry = (μx_init, Σx_init) + final_carry, outputs = lax.scan(scan_body, init_carry, s_indices) + + μx_seq_inner, μc_seq, Σx_seq_inner, Vc_seq = outputs + + # 使用推断的大小构建输出数组 + μx_seq = jnp.zeros((S + 2, T0 + 2, n_x)) + Σx_seq = jnp.zeros((S + 2, T0 + 2, n_x, n_x)) + + μx_seq = μx_seq.at[:S+1].set(μx_seq_inner) + Σx_seq = Σx_seq.at[:S+1].set(Σx_seq_inner) + + μx_seq = μx_seq.at[S+1].set(final_carry[0]) + Σx_seq = Σx_seq.at[S+1].set(final_carry[1]) + + return μx_seq, μc_seq, Σx_seq, Vc_seq +``` + +给定候选转型税率 $\tau_\ell^{\text{trans}}$,函数 `transition_paths` 构造完整的政策序列、后向求解、前向模拟、通过跨队列汇总计算资本和债务路径,并返回我们试图驱使为零的终端债务结转。 + +```{code-cell} ipython3 +@jit +def _transition_paths( + τ_l_trans, price_seq, policy_seq, + ss1_P_arr, ss1_ξ_arr, ss1_Gb, + μx_init, Σx_init, k_bar_init, + s_indices, age_range, S1, S2, + ε_arr, β_arr, Ind_work, + ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, + frac, n): + """为给定 τ_l_trans 后向求解并前向模拟。""" + + # 从输入数组推断维度 + n_x = x0.shape[0] + S = s_indices.shape[0] - 2 + + # 通过切片派生变体 + s_indices_scan = s_indices[:-1] # arange(S+1) + ages = age_range[:-1] # arange(T0+1) + capital_indices = s_indices[1:-1] # arange(1, S+1) + + # 使用动态索引用转型税更新政策序列 + mask = (s_indices >= S1 + 1) & (s_indices <= S2) + τ_l_col = jnp.where(mask, τ_l_trans, policy_seq[:, 0]) + policy_seq = policy_seq.at[:, 0].set(τ_l_col) + + # 后向求解 + F_seq, Ao_seq, P_seq, ξ_seq = solve_backwards( + price_seq, policy_seq, ss1_P_arr, ss1_ξ_arr, + ε_arr, β_arr, Ind_work, + ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, + s_indices_scan, ages + ) + + # 前向模拟 + μx_seq, μc_seq, Σx_seq, Vc_seq = simulate_forwards( + Ao_seq, F_seq, μx_init, Σx_init, C, x0, Σ0, s_indices_scan, ages + ) + + # 计算资本路径 + ε_agg = jnp.sum(ε_arr * frac) + frac0_x0 = frac[0] * x0[0] + + def capital_step(k_prev, s): + RR = price_seq[s, 0] + w = price_seq[s, 1] + G = policy_seq[s, 4] + c_agg = jnp.sum(μc_seq[s] * frac) + k_new = RR * (frac0_x0 + k_prev / n) - G - c_agg + w * ε_agg + return k_new, k_new + + # capital_indices 是预先创建的 arange(1, S+1) + _, k_path = lax.scan(capital_step, k_bar_init, capital_indices) + k_seq = jnp.concatenate([jnp.array([k_bar_init]), k_path]) + + # 计算债务路径 + a_seq = jnp.sum(μx_seq[1:, 1:, 0] * frac, axis=1) + Gb_seq = a_seq - k_seq + + carryover = Gb_seq[-1] - ss1_Gb + + return carryover, μx_seq, μc_seq, k_seq, Gb_seq, F_seq, Ao_seq +``` + +`transition_paths` 解包稳态和家庭对象,并调用 JIT 编译的内部函数。 + +```{code-cell} ipython3 +def transition_paths( + τ_l_trans, price_seq, policy_seq, + ss0, ss1, hh, tech, + S, S1, S2, μx_init, Σx_init): + """计算转型路径。""" + + policy_seq = jnp.asarray(policy_seq) + price_seq = jnp.asarray(price_seq) + + # 预先创建迭代数组(对变体使用切片) + s_indices = jnp.arange(S + 2) + + carryover, μx_seq, μc_seq, k_seq, Gb_seq, F_seq, Ao_seq = _transition_paths( + float(τ_l_trans), price_seq, policy_seq, + ss1.P_arr, ss1.ξ_arr, float(ss1.Gb), + μx_init, Σx_init, float(ss0.k_bar), + s_indices, AGE_INDICES, + S1, S2, + hh.ε_arr, hh.β_arr, hh.Ind_work, + hh.ρ_d, hh.σ, hh.B, hh.C, hh.R, hh.Q, hh.H, + hh.P_end, hh.ξ_end, hh.x0, hh.Σ0, + hh.frac, hh.n + ) + + return (float(carryover), μx_seq, μc_seq, + k_seq, Gb_seq, F_seq, Ao_seq) +``` + +### 打靶法 + +为了找到正确的转型税率,我们使用打靶法。 + +如果税率太低,债务会爆炸;如果太高,债务会低于目标。 + +均衡税率是终端债务恰好达到目标的地方。 + +我们首先计算两条具有不同试验税率的转型路径来说明打靶法 + +```{code-cell} ipython3 +price_seq = make_exo_price_seq(S_exo, RR, w) +policy_seq_base = make_policy_seq(S_exo, ss0.τ_l, ss1.τ_l, S1, S2, + τ_a_0, τ_0_0, 0, G_0, Gb_0) + +τ_l_low = 0.14 +τ_l_high = 0.17 + +_, μx_seq1, μc_seq1, k_seq1, Gb_seq1, _, _ = transition_paths( + τ_l_low, price_seq, policy_seq_base, ss0, ss1, hh, tech, + S_exo, S1, S2, ss0.μx_arr, ss0.Σx_arr) + +_, μx_seq2, μc_seq2, k_seq2, Gb_seq2, _, _ = transition_paths( + τ_l_high, price_seq, policy_seq_base, ss0, ss1, hh, tech, + S_exo, S1, S2, ss0.μx_arr, ss0.Σx_arr) +``` + +我们可以绘制得到的债务路径,看看它们在两个试验税率下如何不同 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 寻找转型税率的打靶法 + name: two_comp_shooting +--- +fig, ax = plt.subplots(figsize=(10, 5)) +ax.plot(Gb_seq1, 'b-', linewidth=2, + label=f'$\\tau_\\ell$ = {τ_l_low:.2f} (太低)') +ax.plot(Gb_seq2, 'r-', linewidth=2, + label=f'$\\tau_\\ell$ = {τ_l_high:.2f} (太高)') +ax.axhline(ss1.Gb, color='k', linestyle='--', + label=f'目标 $G_b$ = {ss1.Gb:.2f}') +ax.axvspan(S1, S2, alpha=0.1, color='yellow', label='转型期') +ax.set_xlabel('时间') +ax.set_ylabel('政府债务') +ax.legend() +plt.show() +``` + +蓝色曲线显示当税率太低时政府债务随时间增加,而红色曲线显示当税率太高时债务低于目标。 + +均衡转型税率位于这两个极端之间,处于终端债务恰好匹配目标 $G_b$ 的值。 + +二分法自动执行这个打靶过程。 + +对于实验 1,每个在 $s_1$ 时存活的队列还必须以其在原系统下本应获得的社会保障福利的现值进行补偿。 + +`_compute_compensation` 为由其剩余寿命标识的单个队列评估这个现值。 + +```{code-cell} ipython3 +def _compute_compensation( + death_time, τ_l_seq, τ_a_seq, + benef_diff, RR_seq, w_seq, + ε_arr, indices, ss0_τ_l): + """一个队列失去福利的现值。""" + + n_periods = death_time + 1 + age_at_0 = T0 - death_time + + time_mask = indices < n_periods + age_mask = indices >= age_at_0 + + τ_l_cohort = jnp.where(time_mask, τ_l_seq[:T0 + 1], 0.0) + τ_a_cohort = jnp.where(time_mask, τ_a_seq[:T0 + 1], 0.0) + RR_cohort = jnp.where(time_mask, RR_seq[:T0 + 1], 1.0) + w_cohort = jnp.where(time_mask, w_seq[:T0 + 1], 0.0) + + ε_masked = jnp.where(age_mask, ε_arr, 0.0) + benef_masked = jnp.where(age_mask, benef_diff, 0.0) + benef_masked = jnp.where(ε_masked != 0, 0.0, benef_masked) + + age_idx = jnp.clip(age_at_0 + indices, 0, T0) + ε_cohort = jnp.where( + time_mask, ε_arr[age_idx], 0.0 + ) + benef_cohort = jnp.where( + time_mask, benef_diff[age_idx], 0.0 + ) + benef_cohort = jnp.where(ε_cohort != 0, 0.0, benef_cohort) + + RR_tilde_seq = RR_cohort - τ_a_cohort * (RR_cohort - 1) + RR_tilde_seq = jnp.where(time_mask, RR_tilde_seq, 1.0) + discount_factors = jnp.cumprod(RR_tilde_seq) + + labor_loss = w_cohort * ε_cohort * (τ_l_cohort - ss0_τ_l) + + pv_seq = jnp.where( + time_mask, + (benef_cohort + labor_loss) / discount_factors, + 0.0 + ) + + valid = (death_time >= 0) & (death_time < T0) + return jnp.where(valid, jnp.sum(pv_seq), 0.0) +``` + +`apply_compensation` 用 `vmap` 将此计算向量化到所有队列,并将结果加到每个队列的初始资产持有量上。 + +```{code-cell} ipython3 +@jit +def apply_compensation( + μx_arr_ss0, Σx_arr_ss0, + τ_l_seq, τ_a_seq, benef_diff, + RR_seq, w_seq, ε_arr, ss0_τ_l, + ages_full, ages, x0, Σ0, + comp_mult): + """跨队列向量化补偿并调整初始资产。""" + + def compute_comp_for_age(age): + death_time = T0 - age + comp = _compute_compensation( + death_time, + τ_l_seq, τ_a_seq, benef_diff, + RR_seq, w_seq, ε_arr, + ages, ss0_τ_l + ) + valid = (age >= 1) & (age <= T0) + return jnp.where(valid, comp, 0.0) + + compensations = vmap(compute_comp_for_age)(ages_full) + + μx_init = jnp.zeros_like(μx_arr_ss0) + Σx_init = jnp.zeros_like(Σx_arr_ss0) + + μx_init = μx_init.at[0].set(x0) + Σx_init = Σx_init.at[0].set(Σ0) + μx_init = μx_init.at[-1].set(x0) + Σx_init = Σx_init.at[-1].set(Σ0) + + μx_init = μx_init.at[1:-1].set(μx_arr_ss0[1:-1]) + Σx_init = Σx_init.at[1:-1].set(Σx_arr_ss0[1:-1]) + + # comp_mult: 0.0 = 无补偿, 1.0 = 完全补偿 + μx_init = μx_init.at[:, 0].add(comp_mult * compensations) + + return μx_init, Σx_init +``` + +`_transition_carryover` 应用补偿、求解转型,并返回终端债务结转——二分法驱使为零的标量。 + +```{code-cell} ipython3 +def _transition_carryover( + τ_l_trans, price_seq, policy_seq, + ss1_P_arr, ss1_ξ_arr, ss1_Gb, + ss0_μx_arr, ss0_Σx_arr, k_bar_init, + benef_diff, ss0_τ_l, comp_mult, + s_indices, age_range, S1, S2, + ε_arr, β_arr, Ind_work, + ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, + frac, n): + """给定转型 τ_l 的终端债务结转。""" + + ages = age_range[:-1] # arange(T0+1) + + # 用转型税更新政策序列 + mask = (s_indices >= S1 + 1) & (s_indices <= S2) + τ_l_col = jnp.where(mask, τ_l_trans, policy_seq[:, 0]) + policy_seq_updated = policy_seq.at[:, 0].set(τ_l_col) + + # 计算初始条件(当 comp_mult=0.0 时补偿归零) + μx_init, Σx_init = apply_compensation( + ss0_μx_arr, ss0_Σx_arr, + policy_seq_updated[:, 0], policy_seq_updated[:, 1], benef_diff, + price_seq[:, 0], price_seq[:, 1], + ε_arr, ss0_τ_l, + age_range, ages, x0, Σ0, + comp_mult + ) + + carryover, *_ = _transition_paths( + τ_l_trans, price_seq, policy_seq, + ss1_P_arr, ss1_ξ_arr, ss1_Gb, + μx_init, Σx_init, k_bar_init, + s_indices, age_range, S1, S2, + ε_arr, β_arr, Ind_work, + ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, + frac, n + ) + return carryover +``` + +我们在 `_find_transition_tau_l` 中实现二分搜索,它在收缩区间的中点反复评估 `_transition_carryover`,直到结转被驱使为零。 + +```{code-cell} ipython3 +@jit +def _find_transition_tau_l( + price_seq, policy_seq, bounds, + ss1_P_arr, ss1_ξ_arr, ss1_Gb, + ss0_μx_arr, ss0_Σx_arr, k_bar_init, + benef_diff, ss0_τ_l, comp_mult, + s_indices, age_range, S1, S2, + ε_arr, β_arr, Ind_work, + ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, + frac, n): + """使用二分法找到转型 τ_l。 + + comp_mult 控制补偿(0 或 1)。 + """ + + a, b = bounds[0], bounds[1] + + def compute_carryover(τ_l_trans): + return _transition_carryover( + τ_l_trans, price_seq, policy_seq, + ss1_P_arr, ss1_ξ_arr, ss1_Gb, + ss0_μx_arr, ss0_Σx_arr, k_bar_init, + benef_diff, ss0_τ_l, comp_mult, + s_indices, age_range, + S1, S2, + ε_arr, β_arr, Ind_work, + ρ_d, σ, B, C, R, Q, H, + P_end, ξ_end, x0, Σ0, + frac, n + ) + + def cond_fn(state): + a, b, fa, fb, i = state + return (jnp.abs(b - a) > 1e-10) & (i < 100) + + def body_fn(state): + a, b, fa, fb, i = state + c = (a + b) / 2.0 + fc = compute_carryover(c) + a_new = jnp.where(fa * fc > 0, c, a) + b_new = jnp.where(fa * fc > 0, b, c) + fa_new = jnp.where(fa * fc > 0, fc, fa) + fb_new = jnp.where(fa * fc > 0, fb, fc) + return (a_new, b_new, fa_new, fb_new, i + 1) + + fa, fb = compute_carryover(a), compute_carryover(b) + init_state = (a, b, fa, fb, 0) + final_state = lax.while_loop(cond_fn, body_fn, init_state) + a_final, b_final, _, _, _ = final_state + + return (a_final + b_final) / 2.0 +``` + +顶层包装器 `find_transition_exo` 设置补偿参数并调用二分求解器,然后在均衡税率处重新计算完整转型路径。 + +```{code-cell} ipython3 +def find_transition_exo(price_seq, policy_seq_base, ss0, ss1, + hh, tech, S, S1, S2, + compensation_data=None, + τl_bounds=(0.01, 0.6)): + """找到外生价格下的转型税率。""" + + policy_seq = jnp.asarray(policy_seq_base) + price_seq = jnp.asarray(price_seq) + bounds = jnp.array([τl_bounds[0], τl_bounds[1]]) + s_indices = jnp.arange(S + 2) + + # 设置补偿参数(不使用补偿时默认为零) + if compensation_data is not None: + benef_diff, ss0_τ_l = compensation_data + comp_mult = 1.0 + else: + benef_diff = jnp.zeros(hh.T0 + 1) + ss0_τ_l = ss0.τ_l + comp_mult = 0.0 + + # 使用统一函数找到转型税 + τ_l_trans = _find_transition_tau_l( + price_seq, policy_seq, bounds, + ss1.P_arr, ss1.ξ_arr, float(ss1.Gb), + ss0.μx_arr, ss0.Σx_arr, float(ss0.k_bar), + benef_diff, float(ss0_τ_l), comp_mult, + s_indices, AGE_INDICES, + S1, S2, + hh.ε_arr, hh.β_arr, hh.Ind_work, + hh.ρ_d, hh.σ, hh.B, hh.C, + hh.R, hh.Q, hh.H, + hh.P_end, hh.ξ_end, hh.x0, hh.Σ0, + hh.frac, hh.n + ) + τ_l_trans = float(τ_l_trans) + + # 用初始条件计算最终结果 + mask = (s_indices >= S1 + 1) & (s_indices <= S2) + τ_l_col = jnp.where( + mask, τ_l_trans, policy_seq[:, 0] + ) + policy_seq_final = policy_seq.at[:, 0].set( + τ_l_col + ) + + μx_init, Σx_init = apply_compensation( + ss0.μx_arr, ss0.Σx_arr, + policy_seq_final[:, 0], + policy_seq_final[:, 1], + benef_diff, + price_seq[:, 0], price_seq[:, 1], + hh.ε_arr, float(ss0_τ_l), + AGE_INDICES, AGE_INDICES[:-1], + hh.x0, hh.Σ0, comp_mult + ) + + results = transition_paths( + τ_l_trans, price_seq, policy_seq, + ss0, ss1, hh, tech, S, S1, S2, + μx_init, Σx_init + ) + + return τ_l_trans, results +``` + +对转型税率进行二分产生均衡路径。 + +```{code-cell} ipython3 +τ_l_trans, results = find_transition_exo( + price_seq, policy_seq_base, ss0, ss1, + hh, tech, S_exo, S1, S2) + +carryover, μx_seq, μc_seq, k_seq, Gb_seq, F_seq, Ao_seq = results +``` + +在基准情形(无补偿)中,社会保障福利被直接终止。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 基准转型路径(无补偿) + name: two_comp_baseline_transition +--- +τ_l_seq = np.zeros(S_exo + 1) +τ_l_seq[:S1 + 1] = ss0.τ_l +τ_l_seq[S1 + 1:S2 + 1] = τ_l_trans +τ_l_seq[S2 + 1:] = ss1.τ_l + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +axes[0].plot(τ_l_seq, 'b-', linewidth=2) +axes[0].axhline(ss0.τ_l, color='r', linestyle=':', + label=f'初始 $\\tau_\\ell$ = {ss0.τ_l:.4f}') +axes[0].axhline(ss1.τ_l, color='g', linestyle=':', + label=f'终端 $\\tau_\\ell$ = {ss1.τ_l:.4f}') +axes[0].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[0].set_xlabel('时间') +axes[0].set_ylabel('劳动税率') +axes[0].set_title('劳动税率路径') +axes[0].legend() + + +axes[1].plot(Gb_seq, 'b-', linewidth=2) +axes[1].axhline(ss0.Gb, color='r', linestyle=':', + label=f'初始 $G_b$ = {ss0.Gb:.2f}') +axes[1].axhline(ss1.Gb, color='g', linestyle=':', + label=f'终端 $G_b$ = {ss1.Gb:.2f}') +axes[1].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[1].set_xlabel('时间') +axes[1].set_ylabel('政府债务') +axes[1].set_title('政府债务路径') +axes[1].legend() + + +plt.tight_layout() +plt.show() +``` + +左图显示劳动税率在转型期间下降,因为政府不再需要为社会保障福利提供资金。 + +右图显示政府债务从其初始水平收敛到新的稳态水平,阴影区域标记转型期 $[s_1, s_2)$。 + +## 实验 1:通过债务进行补偿 + +在这个实验中,政府终止社会保障福利,但补偿受影响的世代。 + +每个队列获得等于其本应获得福利现值的转移支付——一次精算公平的买断。 + +```{prf:algorithm} 固定要素价格 —— 实验 1(买断) +:label: two_comp_algo_buyout + +这里 $s_3 = s_2 + T_0 = 105$。 + +*步骤 1。* 设置参数。 + +*步骤 2。* 求解具有恒定社会保障福利 $S$ 的初始平稳均衡:固定 $\tau_a, \tau_0, S, G, \bar{b}$,并求解 $\tau_\ell = \tau_{\ell,0}$,使得政府预算平衡: + + F(τ_ℓ) = 政府预算失衡 + 找到 F(τ_ℓ) = 0 的根。 + +*步骤 3。* 求解无社会保障的终端平稳均衡:搜索 $\bar{b}$,使债务与GDP之比匹配目标: + + H(Gb) = 给定 Gb 的债务与GDP之比 + (内部求解 F(τ_ℓ; Gb) = 0) + 找到 H(Gb) = 目标的根。 + +相关的劳动税为 $\tau_{\ell,2}$。 + +*步骤 4。* 求解转型路径:在 $s = 0 = s_1$,所有存活的队列失去福利,年龄为 $t$ 的队列获得一次性补偿,等于失去福利的现值,以税后回报 $\tilde{R}(s) = R(s)[1-\tau_a(s)]+\tau_a(s)$ 贴现: + +$$ +\operatorname{comp}_t = S \sum_{j=\max(T_1-t,\,0)}^{T_0-t} + \prod_{i=0}^{j} \tilde{R}(s+i)^{-1}. +$$ + +政府在 $[s_1, s_2)$ 期间设定 $\tau_{\ell,1}$,从 $s_2$ 起设定 $\tau_{\ell,2}$,在 $s_1$ 时有一次性支出增加 $\sum f_t \operatorname{comp}_t$。 + +找到 $\tau_{\ell,1}$,使得终端政府债务匹配目标: + + J(τ_ℓ) = 终端债务结转 + 找到 J(τ_ℓ) = Gb_terminal 的根。 +``` + +### 固定价格 + +我们保持要素价格固定,并为转型构造价格和政策序列。 + +福利差异向量 `benef_diff_exp1` 记录每个年龄的每期福利损失:退休人员失去其旧制度福利,而工人不受影响。 + +```{code-cell} ipython3 +ss1_exp1_exo = ss1 + +price_seq_exp1_exo = make_exo_price_seq(S_exo, RR_exo, w_exo) +policy_seq_exp1_exo = make_policy_seq(S_exo, ss0.τ_l, ss1.τ_l, S1, S2, + τ_a_0, τ_0_0, 0, G_0, Gb_0) + +benef_diff_exp1 = jnp.zeros(hh.T0 + 1) +benef_diff_exp1 = benef_diff_exp1.at[hh.T1 + 1:].set(ss0.benef) +``` + +函数 `buyout_compensation_exp1_exo` 为每个在改革日期存活的队列计算现值补偿,并将其加到其初始资产上。 + +然后我们求解带买断和不带买断的转型税率,以便比较两条路径。 + +```{code-cell} ipython3 +def buyout_compensation_exp1_exo(τ_l_trans, policy_seq_base, price_seq): + """计算外生价格下的买断补偿。""" + + policy_seq = policy_seq_base.copy() + policy_seq[S1 + 1:S2 + 1, 0] = τ_l_trans + return apply_compensation( + ss0.μx_arr, ss0.Σx_arr, + policy_seq[:, 0], policy_seq[:, 1], benef_diff_exp1, + price_seq[:, 0], price_seq[:, 1], hh.ε_arr, ss0.τ_l, + AGE_INDICES, AGE_INDICES[:-1], + hh.x0, hh.Σ0, + 1.0 # comp_mult = 1.0 表示完全补偿 + ) + +# 带买断求解 +τ_l_exp1_exo_bo, results_exp1_exo_bo = find_transition_exo( + price_seq_exp1_exo, policy_seq_exp1_exo, ss0, ss1_exp1_exo, + hh, tech, S_exo, S1, S2, + compensation_data=(benef_diff_exp1, ss0.τ_l) +) + +# 不带买断求解(用于比较) +τ_l_exp1_exo_nb, results_exp1_exo_nb = find_transition_exo( + price_seq_exp1_exo, policy_seq_exp1_exo, ss0, ss1_exp1_exo, + hh, tech, S_exo, S1, S2 +) +``` + +我们比较带买断补偿和不带买断补偿的转型路径。 + +```{code-cell} ipython3 +exp1_exo = { + 'ss0': ss0, 'ss1': ss1_exp1_exo, + 'τ_l_buyout': τ_l_exp1_exo_bo, 'τ_l_no_buyout': τ_l_exp1_exo_nb, + 'results_buyout': results_exp1_exo_bo, + 'results_no_buyout': results_exp1_exo_nb, + 'hh': hh, 'tech': tech +} +``` + +下图显示买断如何重塑跨队列的初始资产持有量。 + +```{code-cell} ipython3 +# 提取结果 +_, μx_seq_bo, μc_seq_bo, k_seq_bo, Gb_seq_bo, _, _ = exp1_exo['results_buyout'] +results_nb = exp1_exo['results_no_buyout'] +_, μx_seq_nb, μc_seq_nb, k_seq_nb, Gb_seq_nb, _, _ = results_nb + +# 时间 s=0 时按年龄的平均资产(带买断 vs 不带买断) +μa_bo = μx_seq_bo[0, 1:, 0] # s=0 时带买断的资产 +μa_nb = μx_seq_nb[0, 1:, 0] # s=0 时不带买断的资产 + +# 补偿 = 初始资产的差异 +compensation_by_age = μa_bo - μa_nb + +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +# 资产剖面 +ages = np.arange(1, hh.T0 + 2) +axes[0].plot(ages, μa_bo, 'b-', linewidth=2, label='带买断') +axes[0].plot(ages, μa_nb, 'r--', linewidth=2, label='不带买断') +axes[0].axvline(hh.T1 + 1, color='gray', linestyle=':', label='退休') +axes[0].set_xlabel('年龄 (t)') +axes[0].set_ylabel('平均资产') +axes[0].set_title('s=0 时按年龄的资产持有') +axes[0].legend() + + +# 补偿直方图 +working_ages = ages[ages <= hh.T1 + 1] +retired_ages = ages[ages > hh.T1 + 1] +comp_working = compensation_by_age[:hh.T1 + 1] +comp_retired = compensation_by_age[hh.T1 + 1:] + +axes[1].bar(working_ages, comp_working, + color='blue', alpha=0.7, label='工人') +axes[1].bar(retired_ages, comp_retired, + color='red', alpha=0.7, label='退休人员') +axes[1].axhline(0, color='k', linewidth=0.5) +axes[1].axvline(hh.T1 + 1, color='gray', linestyle=':', label='退休') +axes[1].set_xlabel('年龄 (t)') +axes[1].set_ylabel('补偿金额') +axes[1].set_title('按年龄的补偿(加到初始资产)') +axes[1].legend() + + +plt.tight_layout() +plt.show() +``` + +退休人员获得最大的补偿,因为他们本预期在余生中获得福利。 + +年长工人获得可观的补偿,而年轻工人获得很少,因为他们有整个工作生涯来调整。 + +退休人员中递减的剖面反映了精算计算:年长的退休人员剩余的预期福利年数更少。 + +我们现在绘制两种方案下劳动税、政府债务、资本和消费的总量转型路径。 + +```{code-cell} ipython3 +# hh, tech, ss0, ss1 已在作用域中——只是为了可读性从字典中别名 +ss0_exp1 = exp1_exo['ss0'] +ss1_exp1 = exp1_exo['ss1'] + +# 构造 τ_l 序列 +τ_l_seq_bo = np.zeros(S_exo + 1) +τ_l_seq_bo[:S1 + 1] = ss0_exp1.τ_l +τ_l_seq_bo[S1 + 1:S2 + 1] = exp1_exo['τ_l_buyout'] +τ_l_seq_bo[S2 + 1:] = ss1_exp1.τ_l + +τ_l_seq_nb = np.zeros(S_exo + 1) +τ_l_seq_nb[:S1 + 1] = ss0_exp1.τ_l +τ_l_seq_nb[S1 + 1:S2 + 1] = exp1_exo['τ_l_no_buyout'] +τ_l_seq_nb[S2 + 1:] = ss1_exp1.τ_l + +fig, axes = plt.subplots(2, 2, figsize=(14, 10)) + +# τ_l 比较 +axes[0, 0].plot(τ_l_seq_bo, 'b-', linewidth=2, label='带买断') +axes[0, 0].plot(τ_l_seq_nb, 'r--', linewidth=2, label='不带买断') +axes[0, 0].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[0, 0].set_xlabel('时间 (s)') +axes[0, 0].set_ylabel('劳动税率') +axes[0, 0].set_title('劳动税率路径') +axes[0, 0].legend() + +# Gb 比较 +axes[0, 1].plot(Gb_seq_bo, 'b-', linewidth=2, label='带买断') +axes[0, 1].plot(Gb_seq_nb, 'r--', linewidth=2, label='不带买断') +axes[0, 1].axhline(ss1_exp1.Gb, color='k', linestyle=':', alpha=0.7) +axes[0, 1].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[0, 1].set_xlabel('时间 (s)') +axes[0, 1].set_ylabel('政府债务') +axes[0, 1].set_title('政府债务路径') +axes[0, 1].legend() + +# 资本路径 +axes[1, 0].plot(k_seq_bo, 'b-', linewidth=2, label='带买断') +axes[1, 0].plot(k_seq_nb, 'r--', linewidth=2, label='不带买断') +axes[1, 0].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[1, 0].set_xlabel('时间 (s)') +axes[1, 0].set_ylabel('资本存量') +axes[1, 0].set_title('资本积累路径') +axes[1, 0].legend() + +# 总消费 +c_agg_bo = np.array(μc_seq_bo[:S_exo + 1]) @ np.array(hh.frac) +c_agg_nb = np.array(μc_seq_nb[:S_exo + 1]) @ np.array(hh.frac) + +axes[1, 1].plot(c_agg_bo, 'b-', linewidth=2, label='带买断') +axes[1, 1].plot(c_agg_nb, 'r--', linewidth=2, label='不带买断') +axes[1, 1].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[1, 1].set_xlabel('时间 (s)') +axes[1, 1].set_ylabel('总消费') +axes[1, 1].set_title('总消费路径') +axes[1, 1].legend() + +plt.suptitle( + '实验 1:补偿对转型路径的影响', + fontsize=14, y=1.02 +) +plt.show() +``` + +买断方案导致私人资本初期上升较慢,因为政府必须进行大量转移支付。 + +两种方案都收敛到相同的终端稳态。 + +我们现在检查改革发生时不同年龄队列的消费路径。 + +```{code-cell} ipython3 +fig, axes = plt.subplots(2, 2, figsize=(14, 10)) + +selected_ages = [0, 20, 40, 60] # s=0 时不同年龄的队列 + +for idx, age_at_0 in enumerate(selected_ages): + ax = axes[idx // 2, idx % 2] + + remaining_life = hh.T0 - age_at_0 + max_time = min(remaining_life + 1, S_exo + 1) + + c_bo = [μc_seq_bo[s, age_at_0 + s] + for s in range(max_time) + if age_at_0 + s <= hh.T0] + c_nb = [μc_seq_nb[s, age_at_0 + s] + for s in range(max_time) + if age_at_0 + s <= hh.T0] + + ax.plot(c_bo, 'b-', linewidth=2, label='带买断') + ax.plot(c_nb, 'r--', linewidth=2, label='不带买断') + ax.set_xlabel('自 s=0 起的时间') + ax.set_ylabel('平均消费') + ax.set_title(f's=0 时年龄 {age_at_0} 的队列') + ax.legend(fontsize=9) + + +plt.suptitle( + '按队列的消费路径(实验 1)', + fontsize=14, y=1.02 +) +plt.show() +``` + +年轻工人(年龄 0)显示几乎相同的消费路径,因为他们获得很少补偿,且有几十年时间来调整他们的储蓄。 + +接近退休的工人(年龄 40)表现出更明显的差异,因为买断补偿部分抵消了他们失去的福利。 + +退休人员(年龄 60)显示出最戏剧性的差异:没有补偿时,他们的消费在福利结束时急剧下降,而买断方案通过替代失去的收入维持了较高的消费。 + +### 内生价格 + +在要素价格内生的情况下,储蓄行为的变化会影响资本积累,这会改变边际产量并反馈到家庭决策中。 + +```{prf:algorithm} 内生要素价格 +:label: two_comp_algo_endo + +这里 $s_3 = s_2 + 2T_0 = 170$。 + +步骤 1--3 与 {prf:ref}`two_comp_algo_buyout` 相同,并带有一个关于要素价格的外部不动点循环以在稳态出清要素市场。 + +*步骤 4。* 要素价格序列现在是内生的。 + +将固定价格转型求解器包装在松弛循环中: + + T(R_seq): + 1. 通过科布-道格拉斯从 R_seq 计算工资序列。 + 2. 将价格视为给定,找到 J(τ_ℓ) = Gb_terminal 的根。 + 3. 计算隐含的资本路径,然后计算隐含的 R*。 + 返回 R* − R_seq。 + + 带松弛迭代 T(R_seq) = 0 直到收敛。 +``` + +我们迭代价格序列直到要素市场出清。 + +```{code-cell} ipython3 +@jit +def compute_factor_prices(k_prod, ε_bar, A, α, δ): + """从科布-道格拉斯计算要素价格。""" + + k_per_eff = k_prod / ε_bar + r = A * α * (k_per_eff ** (α - 1)) + w = A * (1 - α) * (k_per_eff ** α) + RR = 1 + r - δ + return r, w, RR +``` + +在内生价格下,寻找稳态需要一个外部不动点循环:在给定价格下求解家庭问题、计算隐含的资本存量、通过科布-道格拉斯边际产量更新价格,并重复直到收敛。 + +```{code-cell} ipython3 +def find_ss_endo( + debt2gdp_target, policy_target, + hh, tech, RR_init=None, w_init=None, + max_iter=50, tol=1e-5, verbose=False): + """找到具有内生要素价格的稳态。""" + + τ_a, τ_0, benef, G = policy_target + ε_bar = float(jnp.sum(hh.frac * hh.ε_arr)) + + RR = RR_init if RR_init else tech.RR + w = w_init if w_init else tech.w + + relaxation = 0.3 + + for iteration in range(max_iter): + try: + ss = ss_target_debt2gdp_exo( + debt2gdp_target, + (τ_a, τ_0, benef, G), + (RR, w), hh, tech + ) + except ValueError: + RR = RR * 0.99 + continue + + K_eff = ss.k_bar / hh.n + float(hh.frac[0] * hh.x0[0]) + r_new, w_new, RR_new = compute_factor_prices( + K_eff, ε_bar, + tech.A, tech.α_tilde, tech.δ + ) + r_new = float(r_new) + w_new = float(w_new) + RR_new = float(RR_new) + price_diff = abs(RR_new - RR) + abs(w_new - w) + + if verbose and iteration % 5 == 0: + print(f" SS 迭代 {iteration}: " + f"RR={RR:.6f}, w={w:.4f}, " + f"k_bar={ss.k_bar:.4f}") + + if price_diff < tol: + if verbose: + print(f" 在迭代 {iteration} 收敛") + break + + RR = RR + relaxation * (RR_new - RR) + w = w + relaxation * (w_new - w) + + return ss_target_debt2gdp_exo( + debt2gdp_target, + (τ_a, τ_0, benef, G), + (RR, w), hh, tech + ) +``` + +价格迭代还需要转型价格路径的初始猜测,以及在每次内部求解后更新它的方法。 + +函数 `init_price_seq_interp` 在两个稳态价格向量之间线性插值,而 `_update_prices_from_capital` 通过科布-道格拉斯边际产量从资本路径重新计算要素价格。 + +```{code-cell} ipython3 +def init_price_seq_interp(S, S1, S3, ss0_RR, ss0_w, ss1_RR, ss1_w): + """在稳态之间线性插值价格序列。""" + + s_indices = jnp.arange(S + 2) + t_frac = jnp.clip((s_indices - S1) / (S3 - S1), 0.0, 1.0) + + RR_seq = ss0_RR + t_frac * (ss1_RR - ss0_RR) + w_seq = ss0_w + t_frac * (ss1_w - ss0_w) + + RR_seq = jnp.where(s_indices <= S1, ss0_RR, RR_seq) + w_seq = jnp.where(s_indices <= S1, ss0_w, w_seq) + RR_seq = jnp.where(s_indices >= S3, ss1_RR, RR_seq) + w_seq = jnp.where(s_indices >= S3, ss1_w, w_seq) + + return jnp.column_stack([RR_seq, w_seq]) + + +@jit +def _update_prices_from_capital( + k_seq, k_bar_ss0, n, frac0_x0, + ε_bar, A, α, δ, + s_indices_full, ss1_RR, ss1_w, S3): + """从资本路径计算新的价格序列。""" + + k_prev = jnp.concatenate([jnp.array([k_bar_ss0]), k_seq[:-1]]) + K_eff = k_prev / n + frac0_x0 + + k_per_eff = K_eff / ε_bar + r_new = A * α * (k_per_eff ** (α - 1)) + w_new = A * (1 - α) * (k_per_eff ** α) + RR_new = 1 + r_new - δ + + price_seq_new = jnp.column_stack([RR_new, w_new]) + price_seq_new = jnp.concatenate([price_seq_new, price_seq_new[-1:]], axis=0) + + terminal_prices = jnp.array([[ss1_RR, ss1_w]]) + mask = s_indices_full >= S3 + price_seq_new = jnp.where(mask[:, None], terminal_prices, price_seq_new) + + return price_seq_new +``` + +顶层函数 `find_transition_endo` 将所有内容包装在松弛循环中:在每次迭代中它在当前价格下求解转型、计算隐含的资本路径、更新价格并检查收敛。 + +```{code-cell} ipython3 +def find_transition_endo(price_seq, policy_seq_base, + ss0, ss1, hh, tech, S, S1, S2, S3, + compensation_data=None, + max_iter=50, tol=1e-3, + relaxation=0.5, verbose=False): + """找到内生价格下的转型。""" + + ε_bar = float(jnp.sum(hh.frac * hh.ε_arr)) + frac0_x0 = float(hh.frac[0] * hh.x0[0]) + + price_seq = jnp.asarray(price_seq) + policy_seq_base = jnp.asarray(policy_seq_base) + + # 为价格更新预先创建迭代数组 + s_indices_full = jnp.arange(S + 2) + + if verbose: + print(" 开始价格迭代...") + + for iteration in range(max_iter): + try: + τ_l_trans, results = find_transition_exo( + price_seq, policy_seq_base, ss0, ss1, + hh, tech, S, S1, S2, + compensation_data=compensation_data + ) + except ValueError: + τ_l_trans = 0.35 + results = transition_paths( + τ_l_trans, price_seq, policy_seq_base, + ss0, ss1, hh, tech, S, S1, S2, + ss0.μx_arr, ss0.Σx_arr + ) + + _, μx_seq, μc_seq, k_seq, Gb_seq, F_seq, Ao_seq = results + + price_seq_new = _update_prices_from_capital( + k_seq, float(ss0.k_bar), hh.n, float(frac0_x0), float(ε_bar), + tech.A, tech.α_tilde, tech.δ, + s_indices_full, + float(ss1.RR), float(ss1.w), S3 + ) + + price_diff = float(jnp.max(jnp.abs(price_seq_new - price_seq))) + + if verbose: + print(f" 迭代 {iteration}: " + f"τ_l={τ_l_trans:.4f}, " + f"price_diff={price_diff:.6f}") + + if price_diff < tol: + if verbose: + print(f" 在迭代 {iteration} 收敛") + break + + price_seq = price_seq + relaxation * (price_seq_new - price_seq) + + return τ_l_trans, price_seq, results +``` + +我们现在计算内生价格下的初始和终端稳态,并用价格迭代求解转型。 + +```{code-cell} ipython3 +# 为初始 SS 计算内生价格 +ε_bar = float(jnp.sum(hh.frac * hh.ε_arr)) +K_eff_0 = ss0.k_bar / hh.n + float(hh.frac[0] * hh.x0[0]) +r0_endo, w0_endo, RR0_endo = compute_factor_prices( + K_eff_0, ε_bar, + tech.A, tech.α_tilde, tech.δ +) +r0_endo = float(r0_endo) +w0_endo = float(w0_endo) +RR0_endo = float(RR0_endo) + +ss0_exp1_endo = SteadyState( + P_arr=ss0.P_arr, ξ_arr=ss0.ξ_arr, Ao_arr=ss0.Ao_arr, F_arr=ss0.F_arr, + μx_arr=ss0.μx_arr, μc_arr=ss0.μc_arr, Σx_arr=ss0.Σx_arr, Vc_arr=ss0.Vc_arr, + debt2gdp=ss0.debt2gdp, τ_l=ss0.τ_l, benef=ss0.benef, Gb=ss0.Gb, + k_bar=ss0.k_bar, RR=RR0_endo, w=w0_endo, r=r0_endo, k2gdp=ss0.k2gdp +) + +ss1_exp1_endo = find_ss_endo( + ss0.debt2gdp, (τ_a_0, τ_0_0, 0, G_0), hh, tech, + RR_init=tech.RR, w_init=tech.w, verbose=True +) +``` + +初始价格猜测在两个稳态之间线性插值。 + +```{code-cell} ipython3 +# 初始化价格序列 +price_seq_exp1_endo = init_price_seq_interp( + S_endo, S1, S3, + float(ss0_exp1_endo.RR), float(ss0_exp1_endo.w), + float(ss1_exp1_endo.RR), float(ss1_exp1_endo.w) +) + +# 政策序列 +policy_seq_exp1_endo = make_policy_seq( + S_endo, + ss0_exp1_endo.τ_l, ss1_exp1_endo.τ_l, + S1, S2, + τ_a_0, τ_0_0, 0, G_0, + ss0_exp1_endo.Gb +) +``` + +福利差异向量记录每个年龄的福利损失,价格迭代找到带买断补偿的均衡转型路径。 + +```{code-cell} ipython3 +# 买断补偿 +benef_diff_exp1_endo = jnp.zeros(hh.T0 + 1) +benef_diff = ss0_exp1_endo.benef - ss1_exp1_endo.benef +benef_diff_exp1_endo = benef_diff_exp1_endo.at[ + hh.T1 + 1: +].set(benef_diff) + +# 用价格迭代求解 +print("\n 用内生价格求解转型...") +endo_result = find_transition_endo( + price_seq_exp1_endo, policy_seq_exp1_endo, + ss0_exp1_endo, ss1_exp1_endo, + hh, tech, S_endo, S1, S2, S3, + compensation_data=( + benef_diff_exp1_endo, + ss0_exp1_endo.τ_l + ), + verbose=True +) +τ_l_exp1_endo_bo = endo_result[0] +price_seq_exp1_endo_conv = endo_result[1] +results_exp1_endo = endo_result[2] +(_, μx_seq_exp1_endo, μc_seq_exp1_endo, + k_seq_exp1_endo, Gb_seq_exp1_endo, + _, _) = results_exp1_endo +``` + +存储内生价格结果以便与固定价格情形比较。 + +```{code-cell} ipython3 +exp1_endo = { + 'ss0': ss0_exp1_endo, 'ss1': ss1_exp1_endo, + 'τ_l_buyout': τ_l_exp1_endo_bo, + 'price_seq': price_seq_exp1_endo_conv, + 'k_seq': k_seq_exp1_endo, 'Gb_seq': Gb_seq_exp1_endo, + 'results': results_exp1_endo, + 'μc_seq': μc_seq_exp1_endo, 'μx_seq': μx_seq_exp1_endo +} +``` + +下图比较固定和内生要素价格下的转型路径,显示一般均衡效应如何改变税收、债务、利率和工资路径。 + +```{code-cell} ipython3 +# 获取内生价格序列 +price_seq_endo = exp1_endo['price_seq'] +S_endo = price_seq_endo.shape[0] - 2 + +# 构造固定价格序列用于比较 +RR_fixed = tech.RR +w_fixed = tech.w + +# 对于固定价格,构造 τ_l 序列 +τ_l_seq_fixed = np.zeros(S_exo + 1) +τ_l_seq_fixed[:S1 + 1] = ss0_exp1.τ_l +τ_l_seq_fixed[S1 + 1:S2 + 1] = exp1_exo['τ_l_buyout'] +τ_l_seq_fixed[S2 + 1:] = ss1_exp1.τ_l + +# 对于内生价格 +τ_l_seq_endo = np.zeros(S_endo + 1) +τ_l_seq_endo[:S1 + 1] = exp1_endo['ss0'].τ_l +τ_l_seq_endo[S1 + 1:S2 + 1] = exp1_endo['τ_l_buyout'] +τ_l_seq_endo[S2 + 1:] = exp1_endo['ss1'].τ_l + +fig, axes = plt.subplots(2, 2, figsize=(14, 10)) + +# 劳动税比较 +axes[0, 0].plot(τ_l_seq_fixed, 'b-', linewidth=2, label='固定价格') +axes[0, 0].plot(τ_l_seq_endo[:len(τ_l_seq_fixed)], + 'r--', linewidth=2, + label='内生价格') +axes[0, 0].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[0, 0].set_xlabel('时间 (s)') +axes[0, 0].set_ylabel('劳动税率 (τ_l)') +axes[0, 0].set_title('劳动税率路径') +axes[0, 0].legend() + +# 政府债务比较 +Gb_seq_fixed = Gb_seq_bo +Gb_seq_endo_exp1 = exp1_endo['Gb_seq'] +axes[0, 1].plot(Gb_seq_fixed, 'b-', linewidth=2, label='固定价格') +axes[0, 1].plot( + Gb_seq_endo_exp1[:len(Gb_seq_fixed)], + 'r--', linewidth=2, + label='内生价格' +) +axes[0, 1].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[0, 1].set_xlabel('时间 (s)') +axes[0, 1].set_ylabel('政府债务 (Gb)') +axes[0, 1].set_title('政府债务路径') +axes[0, 1].legend() + +# 利率比较 +r_fixed = np.full(S_exo + 1, tech.r - tech.δ) +r_endo = price_seq_endo[:-1, 0] - 1 # RR - 1 = r - δ +axes[1, 0].plot(r_fixed, 'b-', linewidth=2, label='固定价格') +axes[1, 0].plot( + r_endo[:len(r_fixed)], + 'r--', linewidth=2, + label='内生价格' +) +axes[1, 0].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[1, 0].set_xlabel('时间 (s)') +axes[1, 0].set_ylabel('利率 (r - δ)') +axes[1, 0].set_title('利率路径') +axes[1, 0].legend() + +# 工资率比较 +w_fixed_seq = np.full(S_exo + 1, tech.w) +w_endo = price_seq_endo[:-1, 1] +axes[1, 1].plot(w_fixed_seq, 'b-', linewidth=2, label='固定价格') +axes[1, 1].plot( + w_endo[:len(w_fixed_seq)], + 'r--', linewidth=2, + label='内生价格' +) +axes[1, 1].axvspan(S1, S2, alpha=0.1, color='yellow') +axes[1, 1].set_xlabel('时间 (s)') +axes[1, 1].set_ylabel('工资率 (w)') +axes[1, 1].set_title('工资率路径') +axes[1, 1].legend() + +plt.suptitle( + '实验 1:固定 vs 内生价格', + fontsize=14, y=1.02 +) +plt.show() +``` + +左上图显示两种价格假设下的转型税率相似,但下方两图揭示了要素价格的重要差异。 + +随着资本存量在转型期间上升,在内生定价下利率下降而工资上升,而在小型开放经济假设下它们保持恒定。 + +这些价格效应产生了超出政策变化预期之外的额外再分配后果:较低的利率通过更高的工资使年轻工人受益,但通过较低的储蓄回报使退休人员受损。 + +## 实验 2:政府资本积累 + +在实验 2 中,政府维持社会保障福利,但暂时提高税收以积累实物资本。 + +这笔资本的回报最终为社会保障支付提供资金,因此在终端稳态中政府是净债权人而非债务人。 + +与消除福利的实验 1 不同,这种方法保留了社会保障的社会保险功能——即针对寿命风险的保险和针对劳动收入波动的部分保险。 + +通过让政府代表家庭进行储蓄,经济体可以在维持社会保障所提供的跨世代保险的同时实现更高的资本积累。 + +```{prf:algorithm} 固定要素价格 —— 实验 2(政府融资) +:label: two_comp_algo_govfund + +这里 $s_3 = s_2 + T_0 = 105$。 + +步骤 1--3 与 {prf:ref}`two_comp_algo_buyout` 相同,只是社会保障福利被维持,且目标债务与GDP之比为负(政府成为净债权人)。 + +正确的目标促使政府积累足够的资本以从资产回报为福利提供资金。 + +步骤 4 是关于 $\tau_{\ell,1}$ 的相同根搜索过程,但没有补偿支付。 +``` + +我们首先计算固定价格下的终端稳态,目标是使政府成为净债权人的负债务与GDP之比。 + +```{code-cell} ipython3 +debt2gdp_target_exp2_exo = -1.1785 +ss1_exp2_exo = ss_target_debt2gdp_exo( + debt2gdp_target_exp2_exo, + (τ_a_0, τ_0_0, benef_0, G_0), + (RR_exo, w_exo), hh, tech +) +``` + +有了终端稳态,对转型税率进行二分给出固定价格下的均衡路径。 + +```{code-cell} ipython3 +# 价格和政策序列 +price_seq_exp2_exo = make_exo_price_seq(S_exo, RR_exo, w_exo) +policy_seq_exp2_exo = make_policy_seq( + S_exo, ss0.τ_l, ss1_exp2_exo.τ_l, + S1, S2, + τ_a_0, τ_0_0, benef_0, G_0, Gb_0 +) + +# 求解(无补偿) +τ_l_exp2_exo, results_exp2_exo = find_transition_exo( + price_seq_exp2_exo, policy_seq_exp2_exo, ss0, ss1_exp2_exo, + hh, tech, S_exo, S1, S2 +) +``` + +结果被打包以用于下面的跨实验比较。 + +```{code-cell} ipython3 +(carryover_exp2, μx_seq_exp2_exo, + μc_seq_exp2_exo, k_seq_exp2_exo, + Gb_seq_exp2_exo, F_seq_exp2_exo, + Ao_seq_exp2_exo) = results_exp2_exo +exp2_exo = { + 'ss0': ss0, 'ss1': ss1_exp2_exo, + 'τ_l_trans': τ_l_exp2_exo, + 'results': results_exp2_exo, + 'k_seq': k_seq_exp2_exo, 'Gb_seq': Gb_seq_exp2_exo, + 'μc_seq': μc_seq_exp2_exo, 'μx_seq': μx_seq_exp2_exo +} +``` + +我们在内生要素价格下重复计算,使用与实验 1 相同的初始稳态。 + +```{code-cell} ipython3 +# 为初始 SS 计算内生价格(重用实验 1 的) +ss0_exp2_endo = ss0_exp1_endo # 相同初始 SS + +# 内生价格的终端稳态 +ss1_exp2_endo = find_ss_endo( + debt2gdp_target=-1.925, + policy_target=(τ_a_0, τ_0_0, benef_0, G_0), + hh=hh, tech=tech, + RR_init=tech.RR, w_init=tech.w, + verbose=True +) +``` + +价格迭代产生内生价格转型路径。 + +```{code-cell} ipython3 +# 初始化价格序列 +price_seq_exp2_endo = init_price_seq_interp( + S_endo, S1, S3, + float(ss0_exp2_endo.RR), float(ss0_exp2_endo.w), + float(ss1_exp2_endo.RR), float(ss1_exp2_endo.w) +) + +# 政策序列 +policy_seq_exp2_endo = make_policy_seq( + S_endo, + ss0_exp2_endo.τ_l, ss1_exp2_endo.τ_l, + S1, S2, + τ_a_0, τ_0_0, benef_0, G_0, + ss0_exp2_endo.Gb +) + +# 用价格迭代求解(无补偿) +endo2 = find_transition_endo( + price_seq_exp2_endo, policy_seq_exp2_endo, + ss0_exp2_endo, ss1_exp2_endo, + hh, tech, S_endo, S1, S2, S3, + verbose=True +) +τ_l_exp2_endo = endo2[0] +price_seq_exp2_endo_conv = endo2[1] +results_exp2_endo = endo2[2] +(_, μx_seq_exp2_endo, μc_seq_exp2_endo, + k_seq_exp2_endo, Gb_seq_exp2_endo, + _, _) = results_exp2_endo +``` + +```{code-cell} ipython3 +exp2_endo = { + 'ss0': ss0_exp2_endo, 'ss1': ss1_exp2_endo, + 'τ_l_trans': τ_l_exp2_endo, + 'price_seq': price_seq_exp2_endo_conv, + 'k_seq': k_seq_exp2_endo, 'Gb_seq': Gb_seq_exp2_endo, + 'results': results_exp2_endo, + 'μc_seq': μc_seq_exp2_endo, 'μx_seq': μx_seq_exp2_endo +} +``` + +我们现在比较所有四种改革方案:买断方案和政府融资方案,每种都在固定和内生要素价格下。 + +```{code-cell} ipython3 +# 获取所有情形的债务序列 +Gb_buyout_fixed = Gb_seq_bo +Gb_buyout_endo = exp1_endo['Gb_seq'] +Gb_accum_fixed = exp2_exo['Gb_seq'] +Gb_accum_endo = exp2_endo['Gb_seq'] + +# 获取资本序列 +k_buyout_fixed = k_seq_bo +k_buyout_endo = exp1_endo['k_seq'] +k_accum_fixed = exp2_exo['k_seq'] +k_accum_endo = exp2_endo['k_seq'] + +# 绘图的公共时间视界 +T_plot = min(len(Gb_buyout_fixed), len(Gb_buyout_endo), + len(Gb_accum_fixed), len(Gb_accum_endo)) + +fig, axes = plt.subplots(2, 3, figsize=(18, 10)) + +# 四种方案的标签 +lb = ['买断(固定)', '买断(内生)', + '政府融资(固定)', '政府融资(内生)'] +ls = ['b-', 'b--', 'r-', 'r--'] + +# 政府债务路径 +ax = axes[0, 0] +for d, s, l in zip( + [Gb_buyout_fixed, Gb_buyout_endo, + Gb_accum_fixed, Gb_accum_endo], + ls, lb +): + ax.plot(d[:T_plot], s, linewidth=2, label=l) +ax.axhline(0, color='k', linestyle=':', alpha=0.5) +ax.axvspan(0, 40, alpha=0.1, color='yellow') +ax.set_xlabel('时间 (s)') +ax.set_ylabel('政府债务 (Gb)') +ax.set_title('政府债务路径') +ax.legend(fontsize=9) + + +# 资本路径 +ax = axes[0, 1] +for d, s, l in zip( + [k_buyout_fixed, k_buyout_endo, + k_accum_fixed, k_accum_endo], + ls, lb +): + ax.plot(d[:T_plot], s, linewidth=2, label=l) +ax.axvspan(0, 40, alpha=0.1, color='yellow') +ax.set_xlabel('时间 (s)') +ax.set_ylabel('资本存量 (K)') +ax.set_title('资本积累路径') +ax.legend(fontsize=9) + + +# 总消费 +res2_exo = exp2_exo['results'] +res1_endo = exp1_endo['results'] +res2_endo = exp2_endo['results'] +_, _, μc_exp2_exo, _, _, _, _ = res2_exo +_, _, μc_exp1_endo, _, _, _, _ = res1_endo +_, _, μc_exp2_endo, _, _, _, _ = res2_endo + +def _agg_c(μc, T): + """跨队列汇总人均消费。""" + + n = min(T, μc.shape[0]) + return np.array([ + np.sum(μc[s] * hh.frac) for s in range(n) + ]) + +c_agg_buyout_fixed = c_agg_bo[:T_plot] +c_agg_buyout_endo = _agg_c(μc_exp1_endo, T_plot) +c_agg_accum_fixed = _agg_c(μc_exp2_exo, T_plot) +c_agg_accum_endo = _agg_c(μc_exp2_endo, T_plot) + +ax = axes[0, 2] +for d, s, l in zip( + [c_agg_buyout_fixed, c_agg_buyout_endo, + c_agg_accum_fixed, c_agg_accum_endo], + ls, lb +): + ax.plot(d[:T_plot], s, linewidth=2, label=l) +axes[0, 2].axvspan(0, 40, alpha=0.1, color='yellow') +axes[0, 2].set_xlabel('时间 (s)') +axes[0, 2].set_ylabel('总消费') +axes[0, 2].set_title('总消费路径') +axes[0, 2].legend(fontsize=9) + +# 条形图:转型税率 +cases = ['买断\n(固定)', '买断\n(内生)', + '政府融资\n(固定)', '政府融资\n(内生)'] +τ_l_values = [exp1_exo['τ_l_buyout'], exp1_endo['τ_l_buyout'], + exp2_exo['τ_l_trans'], exp2_endo['τ_l_trans']] +colors = ['blue', 'lightblue', 'red', 'lightcoral'] +axes[1, 0].bar(cases, τ_l_values, color=colors, edgecolor='black') +axes[1, 0].set_ylabel('转型税率 (τ_l)') +axes[1, 0].set_title('转型劳动税率') +axes[1, 0].grid(True, alpha=0.3, axis='y') +for i, v in enumerate(τ_l_values): + axes[1, 0].text(i, v + 0.005, f'{v:.4f}', ha='center', fontsize=9) + +# 条形图:终端债务/GDP +debt2gdp_values = [exp1_exo['ss1'].debt2gdp, exp1_endo['ss1'].debt2gdp, + exp2_exo['ss1'].debt2gdp, exp2_endo['ss1'].debt2gdp] +axes[1, 1].bar(cases, debt2gdp_values, color=colors, edgecolor='black') +axes[1, 1].axhline(0, color='k', linestyle='-', linewidth=0.5) +axes[1, 1].set_ylabel('终端债务/GDP') +axes[1, 1].set_title('终端稳态债务/GDP') +axes[1, 1].grid(True, alpha=0.3, axis='y') +for i, v in enumerate(debt2gdp_values): + y = v + 0.05 if v > 0 else v - 0.15 + axes[1, 1].text( + i, y, f'{v:.4f}', + ha='center', fontsize=9 + ) + +# 条形图:终端利率 +r_values = [exp1_exo['ss1'].r - tech.δ, exp1_endo['ss1'].r - tech.δ, + exp2_exo['ss1'].r - tech.δ, exp2_endo['ss1'].r - tech.δ] +axes[1, 2].bar(cases, r_values, color=colors, edgecolor='black') +axes[1, 2].set_ylabel('终端利率 (r - δ)') +axes[1, 2].set_title('终端稳态利率') +axes[1, 2].grid(True, alpha=0.3, axis='y') +for i, v in enumerate(r_values): + axes[1, 2].text(i, v + 0.002, f'{v:.4f}', ha='center', fontsize=9) + +plt.suptitle('所有四种改革方案的比较', fontsize=14, y=1.02) +plt.show() +``` + +顶行比较转型动态:买断方案(蓝色)由于补偿支付在转型期间积累更高的债务,而政府融资方案(红色)导致大额负债务,因为政府成为净债权人。 + +左下条形图显示政府融资需要比买断方案更高的转型税率,因为福利支付与资本积累同时进行。 + +在内生定价下,更大的资本存量降低了资本的边际产量从而降低了利率,如右下图所示。 + +政府融资方案(实验 2)带来更大的长期效率增益,因为它保留了针对寿命风险和劳动收入波动的保险,而这些在私有化下将会丧失。 + +转型期间较高的劳动收入税率也针对收入风险提供隐性保险,在内生价格下放大了效率优势。 + +## 分布曲面 + +下面的 3D 曲面图显示资产和消费如何在年龄维度和日历时间两个维度上演变。 + +```{code-cell} ipython3 +# 计算用于 3D 绘图的方差 +def compute_variances(results, ss0, hh): + """从转型结果计算方差序列。""" + + _, μx_seq, μc_seq, k_seq, Gb_seq, F_seq, Ao_seq = results + + # 转换为 numpy + μx_seq = np.array(μx_seq) + μc_seq_full = np.array(μc_seq) + F_seq = np.array(F_seq) + Ao_seq = np.array(Ao_seq) + Σx_arr_ss0 = np.array(ss0.Σx_arr) + Σ0 = np.array(hh.Σ0) + C = np.array(hh.C) + + # 从数据获取实际维度 + S_plus_1 = Ao_seq.shape[0] # S+1 + T0_plus_1 = Ao_seq.shape[1] # T0+1 + + Σx_seq = np.empty((S_plus_1 + 1, T0_plus_1 + 1, hh.n_x, hh.n_x)) + Vc_seq = np.empty((S_plus_1, T0_plus_1)) + Va_seq = np.empty((S_plus_1, T0_plus_1)) + + Σx_seq[:, 0] = Σ0 + Σx_seq[0, :] = Σx_arr_ss0[:T0_plus_1 + 1] + + CCT = C @ C.T + for s in range(S_plus_1): + Ao_s = Ao_seq[s] # (T0+1, n_x, n_x) + Σx_s = Σx_seq[s, :T0_plus_1] # (T0+1, n_x, n_x) + F_s = F_seq[s] # (T0+1, n_x) + Σx_seq[s + 1, 1:] = CCT + Ao_s @ Σx_s @ Ao_s.transpose(0, 2, 1) + Vc_seq[s] = np.einsum('ti,tij,tj->t', F_s, Σx_s, F_s) + Va_seq[s] = Σx_s[:, 0, 0] + + # 提取平均资产 - 与 Ao_seq 匹配维度 + μa_seq = μx_seq[:S_plus_1, :T0_plus_1, 0] + μc_seq_out = μc_seq_full[:S_plus_1, :T0_plus_1] + + return μa_seq, Va_seq, μc_seq_out, Vc_seq + +# 为每种情形计算方差 +μa_bf, Va_bf, μc_bf, Vc_bf = compute_variances( + exp1_exo['results_buyout'], exp1_exo['ss0'], hh +) +μa_be, Va_be, μc_be, Vc_be = compute_variances( + exp1_endo['results'], exp1_endo['ss0'], hh +) +μa_af, Va_af, μc_af, Vc_af = compute_variances( + exp2_exo['results'], exp2_exo['ss0'], hh +) +μa_ae, Va_ae, μc_ae, Vc_ae = compute_variances( + exp2_endo['results'], exp2_endo['ss0'], hh +) + +case_names = [ + '买断(固定)', '买断(内生)', + '政府融资(固定)', '政府融资(内生)' +] + + +def plot_surface_grid( + data_cases, case_names, zlabel, + suptitle, cmap='viridis', + transform=None): + """为年龄-时间数据绘制 2x2 的 3D 曲面网格。""" + + fig = plt.figure(figsize=(16, 12)) + for i, (data, name) in enumerate(zip(data_cases, case_names)): + Z = transform(data) if transform is not None else data + n_time, n_age = Z.shape + X, Y = np.meshgrid(np.arange(n_age), np.arange(n_time)) + ax = fig.add_subplot(2, 2, i + 1, projection='3d') + ax.plot_surface(X, Y, Z, cmap=cmap, edgecolor='none', alpha=0.8) + ax.set_xlabel('年龄 (t)') + ax.set_ylabel('时间 (s)') + ax.set_zlabel(zlabel) + ax.set_title(name) + plt.suptitle(suptitle, fontsize=14, y=1.02) + plt.tight_layout() + plt.show() +``` + +每个曲面显示跨年龄($t$)和日历时间($s$)的联合分布,揭示生命周期模式、转型动态和跨队列异质性。 + +平均资产曲面显示资产持有的驼峰形生命周期剖面,随着工作世代响应改革增加储蓄,峰值资产发生移动。 + +```{code-cell} ipython3 +plot_surface_grid( + [μa_bf, μa_be, μa_af, μa_ae], + case_names, '平均资产', + '按年龄和时间的平均资产持有' +) +``` + +资产方差曲面显示累积收入冲击如何导致离散度随年龄增加,转型可能改变离散度增长的速率。 + +```{code-cell} ipython3 +plot_surface_grid( + [Va_bf, Va_be, Va_af, Va_ae], + case_names, '资产标准差', + '按年龄和时间的资产标准差', + cmap='plasma', transform=np.sqrt +) +``` + +平均消费曲面反映最优消费路径,由于模型基础的持久收入假设,该路径应在各年龄间平滑。 + +```{code-cell} ipython3 +plot_surface_grid( + [μc_bf, μc_be, μc_af, μc_ae], + case_names, '平均消费', + '按年龄和时间的平均消费', + cmap='coolwarm' +) +``` + +消费方差曲面揭示 LQ 框架的确定性等价性质如何随时间塑造队列内的消费分布。 + +```{code-cell} ipython3 +plot_surface_grid( + [Vc_bf, Vc_be, Vc_af, Vc_ae], + case_names, '消费标准差', + '按年龄和时间的消费标准差', + cmap='magma', transform=np.sqrt +) +``` \ No newline at end of file diff --git a/lectures/unemployment_linear.md b/lectures/unemployment_linear.md new file mode 100644 index 0000000..f9f7d96 --- /dev/null +++ b/lectures/unemployment_linear.md @@ -0,0 +1,595 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 失业的线性模型 + headings: + Overview: 概述 + The natural rate versus hysteresis: 自然率与滞后效应 + The data: 数据 + A linear model of unemployment: 失业的线性模型 + A linear model of unemployment::The model: 模型 + A linear model of unemployment::Priors: 先验 + A linear model of unemployment::Estimation: 估计 + A random walk would wander off: 随机游走会漂离 + Monthly versus annual: 月度与年度 + What the model misses: 模型遗漏了什么 + What the model misses::What the model assumes about the shocks: 模型对冲击的假设 + What the model misses::Recovering the shocks: 恢复冲击 + What the model misses::Comparing with the Gaussian: 与高斯分布比较 + What the model misses::A note on the plug-in: 关于代入法的说明 + Exercises: 练习 +--- + +# 失业的线性模型 + +```{include} _admonition/gpu.md +``` + +除了 Anaconda 中已有的内容外,本讲座还需要以下库。 + +我们首先安装 `numpyro` 和 `jax`: + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install numpyro jax +``` + +我们还要安装 `pandas_datareader`,用它从 FRED 下载数据: + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install pandas_datareader +``` + +## 概述 + +本讲座将贝叶斯估计应用于美国失业率的线性 AR(1)过程模型。 + +我们在 {doc}`ar1_bayes` 中已经接触过相关机制,但那里的数据是模拟的,重点也偏理论。 + +在这里,我们将仔细研究真实数据,围绕一个在 20 世纪 80 年代和 90 年代分裂了宏观经济学家的问题来组织本讲座:失业是否是一个*随机游走*? + +在这个过程中,我们会观察到一种模型无法捕捉的非对称性。 + +这将引出题为 {doc}`unemployment_shocks` 的后续讲座。 + +与 {doc}`ar1_bayes` 和 {doc}`bayes_nonconj` 一样,我们通过 [NumPyro](https://num.pyro.ai/en/stable/) 中的 NUTS 采样器对后验进行采样来完成估计。 + +(关于其工作原理的简要介绍,参见 {doc}`bayes_nonconj` 中的 {ref}`NUTS 介绍 `。) + +让我们从一些导入开始。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +import datetime as dt +from pandas_datareader import data as web + +import jax.numpy as jnp +from jax import random +import numpyro +import numpyro.distributions as dist +from numpyro.infer import MCMC, NUTS +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +``` + +## 自然率与滞后效应 + +在 20 世纪 80 年代初,{cite:t}`nelson_plosser1982` 开启了单位根文献。 + +他们检验了 14 个宏观经济时间序列,发现只有其中一个能够拒绝随机游走。 + +粗略地说,这意味着对于大多数宏观经济序列而言,冲击的影响看起来是永久的,而不是暂时的。 + +对于失业而言,这一观点体现在 {cite}`blanchard_summers1986` 的**滞后效应假说(hysteresis hypothesis)**中。 + +该假说认为,对失业的冲击可能或多或少是永久性的,因为失业期会侵蚀技能以及对劳动力市场的依附。 + +相反,{cite}`friedman1968role` 的**自然率假说(natural rate hypothesis)**认为,失业率围绕一个稳定的均衡率波动——因此冲击是暂时的,而非永久的。 + +这场辩论之所以重要,是因为这两种观点意味着不同的政策。 + +具体来说,如果冲击是永久性的,那么一场严重的衰退会留下持久的创伤,从而促使人们采取补救行动。 + +在这里,我们用贝叶斯估计重新审视这个问题。 + + + +```{note} +上述历史中有一个讽刺之处。 + +虽然 {cite:t}`nelson_plosser1982` 点燃了单位根之争,从而引出了滞后效应假说,但他们所拒绝了单位根的那个宏观经济序列 +恰恰就是失业率。 +``` + + +## 数据 + +我们使用美国民用失业率,即来自 FRED 的 `UNRATE` 序列,月度且经过季节性调整。 + +```{code-cell} ipython3 +start, end = dt.datetime(1948, 1, 1), dt.datetime(2024, 12, 31) +unrate = web.DataReader("UNRATE", "fred", start, end)["UNRATE"] +``` + +2020 年 COVID-19 引起的峰值是一个极端异常值,由我们的模型一无所知的事件驱动,所以我们把它剔除。 + +```{code-cell} ipython3 +pre_covid = unrate[unrate.index < "2020-01-01"] +u_monthly = pre_covid.to_numpy() +print(f"{len(u_monthly)} monthly observations") +``` + +这是月度序列。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 美国月度失业率,1948–2019 + name: fig-unrate-monthly +--- +fig, ax = plt.subplots() +ax.plot(pre_covid.index, u_monthly, lw=2) +ax.set_xlabel('年份') +ax.set_ylabel('失业率 (%)') +plt.show() +``` + +如 {numref}`fig-unrate-monthly` 所示,失业率在衰退中急剧上升,在复苏中缓慢下降,但它始终保持在一个区间内——在整个战后时期大致为 3% 到 11%。 + +(请记住这个区间,因为它与单位根之争相关联,我们将在下文讨论。) + + +## 失业的线性模型 + +现在让我们使用月度数据来设置并估计模型。 + +### 模型 + +我们设失业率被拉回到一个正常水平 $\bar u$: + +$$ +u_{t+1} = \bar u + \phi\,(u_t - \bar u) + \varepsilon_{t+1}, +\qquad \varepsilon_{t+1} \sim N(0, \sigma^2), +$$ (eq:linear) + +其中 $0 \le \phi < 1$。 + +这是一个线性 AR(1)过程模型,写成这种形式使得 $\bar u$ 是序列所回归的水平,而 $\phi$ 度量持续性。 + +$\phi$ 越接近 1,序列在冲击后返回 $\bar u$ 的速度就越慢;随机游走是极限情形 $\phi = 1$。 + +### 先验 + +我们把 $\bar u$、$\phi$ 和 $\sigma$ 视为未知,并对它们施加弱信息先验。 + +我们给 $\phi$ 一个 $[0, 1)$ 上的均匀先验。 + +上端点被有意排除,因为这样做可以将我们限制在*平稳*区域内。 + +这是必要的,我们将在下文看到原因。 + +同时,这个先验仍然允许 $\phi$ 在数据要求下尽可能地接近 1。 + +我们将 $\bar u$ 以一个合理的自然率为中心,并配以相当宽的正态先验,并给冲击尺度 $\sigma$ 一个半正态先验。 + +我们把模型写成一个 NumPyro 函数:每个 `numpyro.sample` 引入一个随机变量,关键字 `obs=` 将最后一个变量与数据绑定,从而提供似然。 + +```{code-cell} ipython3 +def linear_model(u): + ubar = numpyro.sample("ubar", dist.Normal(5.5, 2.0)) # 自然率先验 + φ = numpyro.sample("phi", dist.Uniform(0.0, 1.0)) # 持续性先验 + σ = numpyro.sample("sigma", dist.HalfNormal(1.0)) # 波动率先验 + μ = ubar + φ * (u[:-1] - ubar) + numpyro.sample("u_obs", dist.Normal(μ, σ), obs=u[1:]) +``` + +向量 `μ` 保存了条件均值 $\bar u + \phi(u_t - \bar u)$,而 `obs=u[1:]` 表示每个下一个值都是从 $N(\mu_t, \sigma^2)$ 中抽取的。 + +这一条语句就编码了整个似然。(关于编写 NumPyro 模型的更多内容,参见 {doc}`bayes_nonconj`。) + +### 估计 + +我们用 NUTS 对后验进行采样,运行四条链以便检查收敛性。 + +我们使用 `chain_method="vectorized"`,它在单个设备上同时对所有链进行评估,因此相同的代码在 CPU 或 GPU 上都能不变地运行。 + +```{code-cell} ipython3 +def run_nuts(model, data, seed=0, num_warmup=1000, num_samples=2000, num_chains=4): + "使用 NUTS 采样器对 NumPyro 模型进行采样。" + mcmc = MCMC(NUTS(model), + num_warmup=num_warmup, num_samples=num_samples, + num_chains=num_chains, chain_method="vectorized", + progress_bar=False) + mcmc.run(random.PRNGKey(seed), jnp.asarray(data)) + return mcmc +``` + +我们将模型拟合到月度数据。 + +```{code-cell} ipython3 +:tags: [hide-output] + +mcmc_monthly = run_nuts(linear_model, u_monthly) +``` + +现在我们检查输出。 + +```{code-cell} ipython3 +mcmc_monthly.print_summary() +``` + +每一行总结了一个参数的后验。 + +`mean`、`median` 以及 `5.0%`/`95.0%` 列给出后验均值、中位数和 90% 可信区间;`std` 是后验标准差。 + +最后两列是收敛诊断:`n_eff` 是有效独立抽样数,`r_hat` 比较链内和链间的变化——一个非常接近 $1.0$ 的值意味着各链一致,采样器已经收敛。 + +这里 `r_hat` 基本上为 1,`n_eff` 也很大,所以我们可以信任这些抽样。 + +对我们而言重要的数值是 $\phi$ 的后验:它的质量紧紧地贴向 1。 + +具体来说,均值和中位数都非常接近 1,而标准差非常小。 + +换句话说,在月度频率上,美国失业率*几乎*是一个随机游走。 + +这就是滞后效应的边界。 + +因此,我们发现自然率观点和滞后效应观点在月度数据中几乎无法区分——估计结果与两者都一致。 + +这就是为什么那个时代的单位根检验难以平息这场辩论 {cite}`roed1997hysteresis`。 + + +## 随机游走会漂离 + +虽然上面的估计似乎为单位根假说提供了合理的支持,但有一个充分的理由认为它是错误的。 + +要看到这个论证,假设失业率真的是一个纯粹的随机游走,其中 $\phi = 1$: + +$$ +u_{t+1} = u_t + \varepsilon_{t+1}, \qquad \varepsilon_{t+1} \sim N(0, \sigma^2). +$$ + +那么 $u_t = u_0 + \sum_{s=1}^t \varepsilon_s$,因此其方差无界增长:$\operatorname{Var}(u_t) = t\sigma^2$。 + +分布会永远扩散,最终概率质量会离开*每一个*有界区间。 + +我们可以通过模拟许多随机游走路径来观察这一点,用观测到的单月变化来设定冲击大小,并观察它们的扩散。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 随机游走离开观测范围 + name: fig-rw-escape +--- +rng = np.random.default_rng(0) +T = len(u_monthly) +σ_rw = np.diff(u_monthly).std() +paths = u_monthly[0] + np.cumsum(rng.normal(0, σ_rw, size=(400, T)), axis=1) + +u_min, u_max = u_monthly.min(), u_monthly.max() + +fig, ax = plt.subplots() +ax.plot(paths[:60].T, color='C0', lw=0.5, alpha=0.3) +ax.axhspan(u_min, u_max, color='C1', alpha=0.15, label='观测范围') +ax.axhline(u_min, color='C1', ls='--', lw=1.5) +ax.axhline(u_max, color='C1', ls='--', lw=1.5) +ax.set_xlabel('自 1948 年起的月数') +ax.set_ylabel('失业率 (%)') +ax.legend() +plt.show() +``` + +在 {numref}`fig-rw-escape` 中,虚线标记了数据中曾出现过的最低和最高失业率,阴影区域是它们之间的区间。 + +模拟路径像 $\sqrt{t}$ 一样扩散,并迅速蔓延到这个区间之外,甚至包括负的失业率。 + +随机游走没有锚点,但失业率显然有——它在七十年里一直保持在一个狭窄的区间内。 + +所以我们已经可以排除精确的随机游走。 + +当我们检查年度数据时,这一点会更加清楚。 + + + +## 月度与年度 + +月度数据把 $\phi$ 钉在了 1 上。 + +不同的频率能否让我们看到更多东西? + +我们用年末值构造一个年度序列,并对它拟合相同的模型。 + +```{code-cell} ipython3 +u_annual = pre_covid.resample("YE").last().to_numpy() +print(f"{len(u_annual)} annual observations") +``` + +我们对这个更短的序列拟合相同的模型。 + +```{code-cell} ipython3 +:tags: [hide-output] + +mcmc_annual = run_nuts(linear_model, u_annual) +``` + +现在我们比较两个频率下 $\phi$ 的后验。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 持续性参数的后验 + name: fig-phi-post +--- +φ_m = np.asarray(mcmc_monthly.get_samples()["phi"]) +φ_a = np.asarray(mcmc_annual.get_samples()["phi"]) + +fig, ax = plt.subplots() +ax.hist(φ_m, bins=50, density=True, alpha=0.6, label='月度') +ax.hist(φ_a, bins=50, density=True, alpha=0.6, label='年度') +ax.set_xlabel('$\\phi$') +ax.legend() +plt.show() +``` + +{numref}`fig-phi-post` 说明了我们的主要发现:年度的 $\phi$ 后验明显低于 1,具有清晰的回归,而月度的后验则紧贴边界。 + +这并不矛盾。 + +如果月度持续性是 $\phi$,那么对于年末值而言,持续性大约是 $\phi^{12}$,而将一个接近 1 的数字提升到十二次方会把它明显拉到 1 以下——这与我们的年度估计一致。 + + + +## 模型遗漏了什么 + +再次审视 {numref}`fig-unrate-monthly`,我们注意到失业率在衰退中迅速跳升,在复苏中缓慢下降。 + +这是一种我们当前模型无法复制的*非对称性*。 + +要弄清楚原因,我们仔细审视模型中唯一随机的部分——冲击。 + +我们分三步进行:陈述模型对冲击的假设,从数据中恢复冲击,并比较两者。 + +### 模型对冲击的假设 + + +给定上一期的失业率 $u_t$ 和参数,下一期的失业率是一个确定性的条件均值加上一个冲击: + +$$ +u_{t+1} = \underbrace{\bar u + \phi\,(u_t - \bar u)}_{\text{条件均值}} + \varepsilon_{t+1}, +\qquad \varepsilon_{t+1} \sim N(0, \sigma^2). +$$ + +重新整理,冲击就是实际发生的值与模型预期值之间的差距: + +$$ +\varepsilon_{t+1} = u_{t+1} - \big(\bar u + \phi\,(u_t - \bar u)\big). +$$ + +模型对这些冲击提出了一个强烈且可检验的断言:它们是从一个*对称的*正态分布中独立抽取的。 + +如果这个断言成立,我们从数据中恢复的冲击应该看起来像一条钟形曲线。 + +如果它失败,它失败的方式将告诉我们模型遗漏了什么。 + +### 恢复冲击 + +我们无法直接读出冲击,因为我们不知道参数 $\bar u$ 和 $\phi$。 + +所以我们对它们进行估计,为每个参数代入一个单一的代表性值。 + +我们使用后验中位数——对于快速诊断而言这是一个合理的选择。 + +```{code-cell} ipython3 +med = {k: np.median(np.asarray(mcmc_monthly.get_samples()[k])) + for k in ("ubar", "phi", "sigma")} +resid = u_monthly[1:] - (med["ubar"] + med["phi"] * (u_monthly[:-1] - med["ubar"])) +``` + +`resid` 数组保存了我们估计的冲击,每一个对应一个月度到月度的转移——即模型的**残差**。 + +切片就是把每个月与它前面的那个月对齐。 + +`resid` 的每个元素是 $u_{t+1} - \big(\hat{\bar u} + \hat\phi\,(u_t - \hat{\bar u})\big)$,即模型的向前一步预测误差,其中带帽子的符号表示中位数估计。 + +(因为我们的估计 $\hat\phi$ 非常接近 1,所以这几乎就是月度变化 $u_{t+1} - u_t$。) + + +### 与高斯分布比较 + +现在我们来问,这些残差看起来是否是高斯的。 + +我们叠加一个正态密度,其标准差被设置为等于残差本身的标准差。 + +这是有意为之的:残差的均值已经接近零,所以匹配方差就使得均值和扩散都一致。 + +剩下的任何差异就是*形状*上的差异——这正是我们想要分离出来的。 + +度量形状的一种方式是**偏度(skewness)**,即三阶标准化矩: + +$$ +\text{skew} = \frac{\frac1n \sum_i (\varepsilon_i - \bar\varepsilon)^3}{\Big(\frac1n \sum_i (\varepsilon_i - \bar\varepsilon)^2\Big)^{3/2}}. +$$ + +对于任何对称分布,这个度量为零;当右尾更长时,它为正。 + +现在我们绘制残差并计算它们的偏度: + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 模型残差呈右偏 + name: fig-resid-skew +--- +def skewness(x): + x = x - x.mean() + return (x**3).mean() / x.std()**3 + +fig, ax = plt.subplots() +ax.hist(resid, bins=60, density=True, alpha=0.6, label='残差') +grid = np.linspace(resid.min(), resid.max(), 200) +gauss = np.exp(-grid**2 / (2 * resid.std()**2)) / (resid.std() * np.sqrt(2 * np.pi)) +ax.plot(grid, gauss, 'C1', lw=2, label='对称高斯') +ax.set_xlabel('模型无法解释的单月变化') +ax.legend() +plt.show() + +print(f"residual skewness = {skewness(resid):.2f}") +``` + +{numref}`fig-resid-skew` 中的残差在两个方面偏离了高斯分布。 + +它们是*重尾的*且*尖峰的*:比钟形曲线所允许的有更多微小变化,也有更多大幅变化。 + +此外,它们是*右偏的*,最大的意外出现在上行方向(衰退)。 + +对称高斯分布(橙色)无法匹配这两个特征:它把向上和向下的冲击视为等可能,也无法容纳偶尔出现的非常大的跳跃。 + +所以我们的模型注定会误读数据,把罕见的向上跳跃和长期温和的下滑视为*同一种*冲击。 + + +### 关于代入法的说明 + +一个贝叶斯纯粹主义者会反对说,这里并不存在单一的残差序列。 + +$(\bar u, \phi)$ 的每一次后验抽样都意味着它自己的残差序列,而我们只是选择了中位数。 + +这个反对是合理的,而这个检验的完全贝叶斯版本——从后验中模拟整个数据集并比较某个汇总统计量——正是我们在 {doc}`unemployment_shocks` 中所做的。 + +这个代入法检验是那个更完整测试的一个快速预览。 + +捕捉这种非对称性是下一讲座的任务,在那里我们对冲击本身而非回归曲线进行建模。 + +## 练习 + +讲座 {doc}`ar1_turningpts` 通过模拟未来路径来预测一个 AR(1)过程,既考虑一个**以**固定参数值**为条件**的预测分布,也考虑一个**对**参数后验不确定性**进行积分**的预测分布。 + +以下练习将这些思想应用到我们拟合的失业模型上。 + +```{exercise} +:label: unemp_lin_ex1 + +使用拟合的**年度**模型,从最后观测到的值开始,用两种方式预测未来 $H = 15$ 年的失业率: + +1. **代入法**:将参数固定在其后验中位数上,并模拟许多未来路径; +2. **扩展法**:对于每条未来路径,从后验中抽取一组新的 $(\bar u, \phi, \sigma)$。 + +在同一坐标轴上绘制各自的 90% 预测区间并进行比较。 + +哪个区间更宽,为什么? +``` + +```{solution-start} unemp_lin_ex1 +:class: dropdown +``` + +我们使用年度后验抽样,并从最后一个观测值向前模拟。 + +我们使用年度模型,因为它的持续性 $\phi$ 远比月度频率下更不确定, +所以参数不确定性更有话可说。 + +```{code-cell} ipython3 +post = mcmc_annual.get_samples() +ubar_s = np.asarray(post["ubar"]) +φ_s = np.asarray(post["phi"]) +σ_s = np.asarray(post["sigma"]) + +def sim_future(u_last, ubar, φ, σ, H, rng): + "从 u_last 开始向前模拟线性模型 H 步。" + u = np.empty(H) + prev = u_last + for h in range(H): + prev = ubar + φ * (prev - ubar) + rng.normal(0, σ) + u[h] = prev + return u + +H, N = 15, 2000 +u_last = u_annual[-1] +rng = np.random.default_rng(0) + +# 代入法:参数固定在后验中位数上 +ub0, φ0, σ0 = np.median(ubar_s), np.median(φ_s), np.median(σ_s) +plug = np.array([sim_future(u_last, ub0, φ0, σ0, H, rng) for _ in range(N)]) + +# 扩展法:为每条路径抽取一组新的后验样本 +idx = rng.integers(0, len(φ_s), N) +ext = np.array([sim_future(u_last, ubar_s[i], φ_s[i], σ_s[i], H, rng) + for i in idx]) + +fig, ax = plt.subplots() +horizon = np.arange(1, H + 1) +for data, c, lab in [(plug, 'C0', '代入法'), (ext, 'C1', '扩展法')]: + lo, hi = np.percentile(data, [5, 95], axis=0) + ax.fill_between(horizon, lo, hi, alpha=0.3, color=c, label=lab) +ax.axhline(u_last, color='k', lw=0.5) +ax.set_xlabel('未来年数') +ax.set_ylabel('失业率 (%)') +ax.legend() +plt.show() +``` + +两种预测都从较低的起始值向回归水平 $\bar u$ 上升,且区间随着我们展望得更远而变宽。 + +扩展法的区间明显更宽,因为它在未来冲击的不确定性之上,还加入了对参数的不确定性——而这里持续性 $\phi$ 和水平 $\bar u$ 都确实是不确定的。 + +```{solution-end} +``` + +```{exercise} +:label: unemp_lin_ex2 + +沿用 Wecker 的方法(参见 {doc}`ar1_turningpts`),我们也可以为一个**路径统计量**——整条未来路径的非线性函数——构造一个预测分布。 + +将**未来 $H = 8$ 年内的最高失业率**作为统计量:一个衡量未来几年可能有多糟糕的简单指标。 + +使用扩展模拟(每条路径抽取一组后验样本),为每条路径计算这个最大值,并绘制它的预测分布。 + +在未来八年内的某个时点失业率达到至少 $7\%$——即衰退区间——的后验预测概率是多少? +``` + +```{solution-start} unemp_lin_ex2 +:class: dropdown +``` + +我们重用上一练习中的 `sim_future` 和后验抽样。 + +```{code-cell} ipython3 +H2, M = 8, 5000 +idx = rng.integers(0, len(φ_s), M) +peak = np.array([sim_future(u_last, ubar_s[i], φ_s[i], σ_s[i], H2, rng).max() + for i in idx]) + +fig, ax = plt.subplots() +ax.hist(peak, bins=50, density=True, alpha=0.6) +ax.axvline(u_last, color='C3', lw=2, label='当前失业率') +ax.set_xlabel('未来 8 年内的最高失业率 (%)') +ax.legend() +plt.show() + +prob = (peak > 7.0).mean() +print(f"P(unemployment reaches 7% within 8 years) = {prob:.2f}") +``` + +预测分布总结了未来几年里可能出现的"最坏情形",同时对冲击和参数不确定性进行了积分。 + +从一个周期性低点出发,模型认为在这个视界内失业率相当有可能回到衰退级别。 + +```{solution-end} +``` \ No newline at end of file diff --git a/lectures/unemployment_shocks.md b/lectures/unemployment_shocks.md new file mode 100644 index 0000000..ba5746f --- /dev/null +++ b/lectures/unemployment_shocks.md @@ -0,0 +1,569 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.17.2 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +translation: + title: 具有非对称冲击的失业动态 + headings: + The data: 数据 + A model with asymmetric shocks: 具有非对称冲击的模型 + Bayesian estimation: 贝叶斯估计 + Comparing models with cross-validation: 用交叉验证比较模型 + 'Comparing models with cross-validation::The guiding principle: out-of-sample predictions': 指导原则:样本外预测 + Comparing models with cross-validation::Leave-one-out cross-validation: 留一交叉验证 + Comparing models with cross-validation::Computational methods: 计算方法 + Comparing models with cross-validation::ArviZ implementation: ArviZ 实现 + Comparing models with cross-validation::Accommodating the time series structure: 适应时间序列结构 + Conclusion: 结论 + Exercises: 练习 +--- + +# 具有非对称冲击的失业动态 + +```{include} _admonition/gpu.md +``` + + +本讲座是 {doc}`unemployment_linear` 的续篇。 + +在那里,我们对美国失业率拟合了一个线性 AR(1) 模型,并考察了持续性。 + +我们发现但未加以处理的一点是:模型的残差既是*重尾的,又是右偏的*。 + +失业率在衰退中急剧上升,而在复苏中缓慢回落。 + +采用对称高斯冲击的模型无法重现这些特征。 + +在本讲座中,我们允许扰动为右偏,并在一定程度上具有重尾特征。 + +我们还借本讲座介绍一种非常有用的贝叶斯技术:通过留一交叉验证进行*模型比较*。 + +我们用它来判断一个模型是否真的比另一个模型预测得更好。 + +我们的计划是: + +1. 构建一个具有线性均值但冲击非对称、偶尔较大的模型, +2. 在年度数据上对其进行估计, +3. 通过交叉验证将其与原始的高斯模型进行比较。 + +除了 Anaconda 中已有的库之外,本讲座还需要以下库。 + +```{code-cell} ipython3 +:tags: [hide-output] + +!pip install numpyro jax pandas_datareader arviz +``` + +我们将使用以下导入。 + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib as mpl # i18n +FONTPATH = "fonts/SourceHanSerifSC-SemiBold.otf" # i18n +mpl.font_manager.fontManager.addfont(FONTPATH) # i18n +mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n +import datetime as dt +from pandas_datareader import data as web + +import jax.numpy as jnp +from jax import random +import numpyro +import numpyro.distributions as dist +from numpyro.infer import MCMC, NUTS, log_likelihood +``` + +## 数据 + +我们使用与 {doc}`unemployment_linear` 中相同的序列——美国失业率(来自 FRED 的 `UNRATE`),排除 COVID-19 期间的激增——并以年度频率进行处理。 + +```{code-cell} ipython3 +start, end = dt.datetime(1948, 1, 1), dt.datetime(2024, 12, 31) +unrate = web.DataReader("UNRATE", "fred", start, end)["UNRATE"] +pre_covid = unrate[unrate.index < "2020-01-01"] +u_annual = pre_covid.resample("YE").last().to_numpy() +years = pre_covid.resample("YE").last().index.year +``` + +我们希望捕捉的形态在年度序列中显而易见。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 美国年度失业率 + name: fig-annual-data +--- +fig, ax = plt.subplots() +ax.plot(years, u_annual, lw=2, marker='o', ms=3) +ax.set_xlabel('年份') +ax.set_ylabel('失业率 (%)') +plt.show() +``` + +在 {numref}`fig-annual-data` 中,每次衰退都表现为急剧上升,随后是漫长、缓慢的下降——上升快,下降慢。 + +## 具有非对称冲击的模型 + +我们保留 {doc}`unemployment_linear` 中的线性结构: + +$$ +u_{t+1} = \bar u + \rho\,(u_t - \bar u) + \eta_{t+1}, +\qquad 0 \le \rho < 1, +$$ (eq:shocks) + +然而在这里,扰动 $\eta_{t+1}$ 是从*两个正态分布的混合*中抽取的: + +$$ +\eta_{t+1} \sim +\begin{cases} +N(0, \sigma_s^2) & \text{以概率 } 1-p \quad\text{(平静年份)},\\[4pt] +N(\mu_J, \sigma_J^2) & \text{以概率 } p \quad\text{(衰退跳跃)}, +\end{cases} +\qquad \mu_J > 0 . +$$ + +该模型有六个参数: + +| 符号 | 名称 | 作用 | +| --- | --- | --- | +| $\bar u$ | 底线 | 序列回归到的低水平 | +| $\rho$ | 持续性 | 回归速度(如线性讲座中所述) | +| $p$ | 跳跃概率 | 大冲击到来的频率 | +| $\mu_J$ | 跳跃幅度 | 衰退平均向上的推动 | +| $\sigma_s,\ \sigma_J$ | 冲击幅度 | 平静与跳跃时的波动率 | + +这一机制导致失业率呈现锯齿状动态。 + +大多数年份是平静的,只有小的噪声。 + +偶尔一个正向跳跃将失业率大幅推高。 + +然后,在大多数情况下,线性回归会将其缓慢拉回到 $\bar u$。 + +因此,激增在一步内到来,而恢复需要时间——这正是我们在数据中观察到的非对称动态。 + +从精神上讲,这就是米尔顿·弗里德曼的"拨弦模型":一条接近充分就业的底线,坏冲击从这条底线向上拨动序列。 + +下一个单元格展示了冲击的密度及其两个组成部分。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 作为混合分布的冲击分布 + name: fig-shock-density +--- +def normal_pdf(x, m, s): + return np.exp(-(x - m)**2 / (2 * s**2)) / (s * np.sqrt(2 * np.pi)) + +η = np.linspace(-3, 6, 400) +p_, μJ_, σs_, σJ_ = 0.25, 2.0, 0.4, 1.2 +quiet = (1 - p_) * normal_pdf(η, 0.0, σs_) +jump = p_ * normal_pdf(η, μJ_, σJ_) + +fig, ax = plt.subplots() +ax.plot(η, quiet + jump, lw=2, label='冲击密度') +ax.fill_between(η, quiet, alpha=0.3, label='平静年份') +ax.fill_between(η, jump, alpha=0.3, label='衰退跳跃') +ax.set_xlabel('扰动 $\\eta$') +ax.legend() +plt.show() +``` + +{numref}`fig-shock-density` 展示了一个在零点处又高又窄的峰值,对应普通年份,加上一个位于正侧的低而宽的隆起,对应衰退跳跃。 + + + +## 贝叶斯估计 + +我们对六个参数施加弱信息先验。 + +该混合分布使用 NumPyro 的 `MixtureSameFamily` 编写,它会解析地对两个组成部分求和。 + +```{code-cell} ipython3 +def jump_model(u): + # 设置先验 + ubar = numpyro.sample("ubar", dist.Normal(4.5, 1.5)) + ρ = numpyro.sample("rho", dist.Uniform(0.0, 1.0)) + p = numpyro.sample("p", dist.Beta(2.0, 8.0)) + μ_J = numpyro.sample("mu_J", dist.HalfNormal(2.0)) + σ_s = numpyro.sample("sigma_s", dist.HalfNormal(0.5)) + σ_J = numpyro.sample("sigma_J", dist.HalfNormal(1.5)) + # 构建模型 + n = u.shape[0] - 1 + base = ubar + ρ * (u[:-1] - ubar) + locs = jnp.stack([base, base + μ_J], axis=-1) + scales = jnp.stack([jnp.broadcast_to(σ_s, (n,)), + jnp.broadcast_to(σ_J, (n,))], axis=-1) + probs = jnp.broadcast_to(jnp.stack([1 - p, p]), (n, 2)) + mix = dist.MixtureSameFamily(dist.Categorical(probs=probs), + dist.Normal(locs, scales)) + numpyro.sample("u_obs", mix, obs=u[1:]) +``` + +我们使用 NUTS 进行采样,四条链,向量化处理,因此代码可在 CPU 或 GPU 上运行。 + +```{code-cell} ipython3 +def run_nuts(model, data, seed=0, num_warmup=2000, num_samples=4000, num_chains=4): + "使用 NUTS 采样器对 NumPyro 模型进行采样。" + mcmc = MCMC(NUTS(model), + num_warmup=num_warmup, num_samples=num_samples, + num_chains=num_chains, chain_method="vectorized", + progress_bar=False) + mcmc.run(random.PRNGKey(seed), jnp.asarray(data)) + return mcmc +``` + +我们将模型拟合到年度数据。 + +```{code-cell} ipython3 +:tags: [hide-output] + +mcmc_jump = run_nuts(jump_model, u_annual) +``` + +让我们看看后验分布。 + +```{code-cell} ipython3 +mcmc_jump.print_summary() +``` + +`r_hat` 值基本上都是 1,因此各条链已经收敛。 + +注意其中明显的跳跃成分:正常年份的幅度 $\sigma_s$ 很小,而跳跃幅度 $\sigma_J$ 很大,且均值 $\mu_J$ 为正。 + +让我们做一个快速检查,将拟合的冲击密度叠加到模型的实际残差上,就像我们在 {doc}`unemployment_linear` 中所做的那样。 + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: 拟合的冲击密度与残差对比 + name: fig-jump-fit +--- +m = {k: np.median(np.asarray(mcmc_jump.get_samples()[k])) + for k in ("ubar", "rho", "p", "mu_J", "sigma_s", "sigma_J")} +resid = u_annual[1:] - (m["ubar"] + m["rho"] * (u_annual[:-1] - m["ubar"])) + +η = np.linspace(resid.min() - 0.5, resid.max() + 0.5, 400) +quiet = (1 - m["p"]) * normal_pdf(η, 0.0, m["sigma_s"]) +jump = m["p"] * normal_pdf(η, m["mu_J"], m["sigma_J"]) + +fig, ax = plt.subplots() +ax.hist(resid, bins=25, density=True, alpha=0.5, label='残差') +ax.plot(η, quiet + jump, lw=2, label='拟合密度') +ax.fill_between(η, jump, alpha=0.3, color='C2', label='跳跃成分') +ax.set_xlabel('扰动 $\\eta$') +ax.legend() +plt.show() +``` + +拟合看起来相当不错(尽管我们仍难以捕捉右尾中的某些大冲击)。 + + +## 用交叉验证比较模型 + +跳跃模型看起来合理,但它真的比线性模型更好吗? + +为了回答这个问题,我们将使用一种*贝叶斯模型比较*的方法。 + +我们分阶段构建它:指导原则、留一估计,以及计算的实际执行方式。 + + +### 指导原则:样本外预测 + +我们很容易通过询问哪个模型更好地拟合观测数据来比较两个模型。 + +但这并不是正确的标准:更复杂的模型总是可以调整得更好地匹配它们所拟合的数据。 + +正确的问题反而是:哪个模型更好地预测它未曾见过的数据? + +换句话说,我们关心的标准是样本外预测精度。 + +我们没有用于样本外测试的新数据,因此使用*交叉验证*来制造一些。 + + +### 留一交叉验证 + +其思想是留出一个观测值,将模型拟合到其余数据,然后使用由数据集其余部分构建的预测分布对留出的点进行评分。 + +给定其余数据 $u_{-i}$,数据点 $u_i$ 的预测分布为 + +$$ +p(u_i \mid u_{-i}) = \int p(u_i \mid \theta)\, p(\theta \mid u_{-i})\, d\theta . +$$ + +这里 $p(\theta \mid u_{-i})$ 是从 $u_{-i}$ 中的数据获得的后验。 + +我们用这个密度的*对数*对每个留出的点进行评分。 + +这会奖励那些对实际发生的事件赋予高概率的模型。 + +将所有数据点的这些分数相加,就得到了**期望对数预测密度**(elpd),这里是其留一(LOO)形式: + +$$ +\text{elpd}_{\text{loo}} = \sum_{i=1}^{n} \log p(u_i \mid u_{-i}). +$$ + + +### 计算方法 + +elpd 的定义表明,我们需要重新拟合模型 $n$ 次,每次对应一个被省略的点。 + +这将非常耗时。 + +这里我们讨论一种方法,只保留第一次拟合,使用我们已经采样过的完整后验。 + + +关于记号:设 $u = (u_1, \dots, u_n)$,用 $u_{-i}$ 表示删除了 $u_i$ 后的样本。 + +该方法依赖于以下独立性类型的假设: + + +```{prf:assumption} +:label: assm-cond-ind + +给定 $\theta$,观测值是条件独立的: + +$$ +p(u \mid \theta) = \prod_{j=1}^{n} p(u_j \mid \theta) . +$$ +``` + +对于我们的自回归数据,这个假设是错误的,因为每个 $u_i$ 都通过转移动态依赖于早先的观测值。 + +尽管如此,我们仍然采用它,因为 + +* 它使得留一计算变得可处理,并且 +* 它是一个非常标准的、需要理解的过程。 + +我们将在下面关于时间序列结构的部分讨论其后果。 + +在我们的假设条件下,下面的命题是精确的。 + +```{prf:proposition} +:label: prop-loo-identity + +在 {prf:ref}`assm-cond-ind` 下,我们有 + +$$ +\frac{1}{p(u_i \mid u_{-i})} +\;=\; +\int \frac{1}{p(u_i \mid \theta)}\, p(\theta \mid u)\, d\theta +\qquad (i = 1, \dots, n). +$$ + +``` + +```{prf:proof} +根据贝叶斯法则,$p(\theta \mid u) = p(u \mid \theta)\, p(\theta) / p(u)$ 且 $p(\theta \mid u_{-i}) = p(u_{-i} \mid \theta)\, p(\theta) / p(u_{-i})$。 + +根据 {prf:ref}`assm-cond-ind`,$p(u \mid \theta) = p(u_i \mid \theta)\, p(u_{-i} \mid \theta)$。 + +将两个后验相除并代入这个因式分解, + +$$ +\frac{p(\theta \mid u)}{p(\theta \mid u_{-i})} +\;=\; +\frac{p(u \mid \theta)}{p(u_{-i} \mid \theta)} \cdot \frac{p(u_{-i})}{p(u)} +\;=\; +p(u_i \mid \theta) \cdot \frac{p(u_{-i})}{p(u)} , +$$ + +因此,重新整理后, + +$$ +\frac{p(\theta \mid u)}{p(u_i \mid \theta)} +\;=\; +\frac{p(u_{-i})}{p(u)}\, p(\theta \mid u_{-i}) . +$$ + +现在对两边关于 $\theta$ 积分。 + +在右边,$\int p(\theta \mid u_{-i})\, d\theta = 1$,只剩下常数因子 $p(u_{-i}) / p(u)$,因此 + +$$ +\int \frac{1}{p(u_i \mid \theta)}\, p(\theta \mid u)\, d\theta +\;=\; +\frac{p(u_{-i})}{p(u)} +\;=\; +\frac{1}{p(u_i \mid u_{-i})} , +$$ + +最后一个等式源于 $p(u) = p(u_i \mid u_{-i})\, p(u_{-i})$。 +``` + +留-$i$-出的后验已经消失;只剩下完整后验,而我们对它有 $S$ 个抽样 $\theta^1, \dots, \theta^S$。 + +用这些抽样上的平均值替换 {prf:ref}`prop-loo-identity` 中的积分,得到 + +$$ +\frac{1}{p(u_i \mid u_{-i})} +\;\approx\; +\frac{1}{S} \sum_{s=1}^{S} \frac{1}{p(u_i \mid \theta^s)}, +\qquad\text{因此}\qquad +p(u_i \mid u_{-i}) +\;\approx\; +\frac{S}{\sum_{s=1}^{S} 1 / p(u_i \mid \theta^s)} , +$$ + +这是 $u_i$ 的每个抽样似然的调和平均数。 + +被积函数具有有限的均值,等于 $1/p(u_i \mid u_{-i})$ 本身,因此大数定律适用。 + +当 $S \to \infty$ 时,该平均值因此收敛到那个均值,并且在极限处,近似以概率一成为精确的。 + +其唯一的成分是每个观测值在每个抽样下的似然——**逐点对数似然**——这就是我们一直小心保留它的原因。 + +为了数值稳定性,我们在对数尺度上计算,此时调和平均数变为 + +$$ +\log p(u_i \mid u_{-i}) +\;\approx\; +\log S - \log \sum_{s=1}^{S} e^{-\ell_i^s}, +\qquad \ell_i^s = \log p(u_i \mid \theta^s), +$$ + +这就是我们下面使用的 `jnp.log(S) - logsumexp(-ll)`。 + +为了与线性模型进行比较,我们首先在相同的数据上拟合它。 + +```{code-cell} ipython3 +def linear_model(u): + ubar = numpyro.sample("ubar", dist.Normal(5.5, 2.0)) + ρ = numpyro.sample("rho", dist.Uniform(0.0, 1.0)) + σ = numpyro.sample("sigma", dist.HalfNormal(1.0)) + numpyro.sample("u_obs", dist.Normal(ubar + ρ * (u[:-1] - ubar), σ), obs=u[1:]) +``` + +我们在相同的年度数据上对其采样。 + +```{code-cell} ipython3 +:tags: [hide-output] + +mcmc_lin = run_nuts(linear_model, u_annual) +``` + +现在我们可以用几行代码手动完成整个留一计算。 + +```{code-cell} ipython3 +from jax.scipy.special import logsumexp + +def pointwise_loo(mcmc, model): + "每个观测值的留一对数预测密度。" + ll = log_likelihood(model, mcmc.get_samples(), + u=jnp.asarray(u_annual))["u_obs"] # (抽样, 观测) + S = ll.shape[0] + # 每个观测值的每抽样似然的调和平均数的对数 + return jnp.log(S) - logsumexp(-ll, axis=0) + +elpd_jump = pointwise_loo(mcmc_jump, jump_model) +elpd_lin = pointwise_loo(mcmc_lin, linear_model) + +print(f"jump elpd_loo = {elpd_jump.sum():.1f}") +print(f"linear elpd_loo = {elpd_lin.sum():.1f}") +``` + +跳跃模型得分更高(更接近零),因此在样本外预测上它获胜。 + +为了帮助理解这个差距是否真实,我们计算其标准误差: + +```{code-cell} ipython3 +diff = elpd_jump - elpd_lin +n = diff.size +print(f"elpd difference = {diff.sum():.1f}") +print(f"standard error = {jnp.sqrt(n) * diff.std():.1f}") +``` + +跳跃模型领先约十二个点,而标准误差接近六——略超过两个标准误差,因此是一个真实的改进。 + +### ArviZ 实现 + +在实践中,大多数人使用像 ArviZ 这样的库来进行这个计算。 + +我们将相同的逐点对数似然以其数据格式打包交给它。 + +```{code-cell} ipython3 +import arviz as az +import xarray as xr + +def to_arviz(mcmc, model, u): + "为 ArviZ 打包 NumPyro 拟合结果,附带逐点对数似然。" + idata = az.from_numpyro(mcmc) + ll = np.asarray(log_likelihood(model, mcmc.get_samples(), + u=jnp.asarray(u))["u_obs"]) + ll = ll.reshape(mcmc.num_chains, -1, ll.shape[-1]) + idata["log_likelihood"] = xr.Dataset( + {"u_obs": (("chain", "draw", "obs"), ll)}) + return idata + +az.compare({ + "linear": to_arviz(mcmc_lin, linear_model, u_annual), + "jump": to_arviz(mcmc_jump, jump_model, u_annual), +}) +``` + +这里 `az.compare` 确认了手工计算,并将跳跃模型排在第一位(其表格为了显示对分数进行了取整)。 + + + +### 适应时间序列结构 + +留一法每次删除一个转移,但它并不尊重时间的顺序。 + +当它对从 $u_t$ 到 $u_{t+1}$ 的步骤进行评分时,进行评分的模型是在位于该步骤*两侧*的数据上拟合的——包括相邻值 $u_t$ 和 $u_{t+1}$ 本身。 + +因此,留出的点从未真正未被看见。 + +形式上正确的度量是**留未来交叉验证**。 + +它只向前预测:在 $u_1, \dots, u_t$ 上拟合模型,对其提前一步预测 $u_{t+1}$ 进行评分,然后将窗口扩展一步并重复。 + +现在模型对它被要求预测的未来是真正盲目的,这正如真实的预测。 + +代价是计算量。 + +留一法通过其重要性采样的捷径重用了单次拟合,但留未来法没有这样的技巧。 + +对于我们这条短的年度序列,留未来交叉验证仍然可行,但对于长序列,它可能变得难以承受。 + +(我们在此处未纳入的情况下运行了它,结论依然成立:在留未来法下,跳跃模型仍然击败线性模型,且优势幅度更大。) + + + +## 结论 + + +在 {doc}`unemployment_linear` 中,我们对失业率应用了带高斯冲击的线性 AR(1) 模型,并在月度数据中发现了高水平的持续性。 + +我们还论证了该模型过于简单。 + +在这里,我们发现线性模型最明显遗漏的特征——衰退的非对称性——可以通过对冲击的分布进行建模来解决。 + +带有大的、单侧扰动的线性回归匹配了高斯模型无法捕捉的右偏、重尾冲击。 + +交叉验证更偏好它。 + +一个比上面所考虑的更好的模型将允许经济在持续扩张和衰退状态之间切换。 + +这就是马尔可夫切换方法,我们将其留作进一步阅读。 + +## 练习 + +```{exercise} +:label: unemp_shocks_ex1 + +这里的跳跃成分本身是对称的,$N(\mu_J, \sigma_J^2)$。 + +将两成分混合替换为单一的**偏正态**(或带偏度的 Student-$t$)扰动,重新拟合,并使用 `az.compare` 与混合模型进行比较。 + +更简单的偏斜冲击表现得和混合模型一样好吗? +``` \ No newline at end of file