03 결과 도출 — 3장 표·그림, 이전 판 대비 변화, 검증¶
02_분석.ipynb의 산출물로 3장의 표와 그림을 만들고, 이전 판(2026-10-08 패키지가 재현한 공표 산출물, data/reference_prev/)과 비교한다.
마지막 셀은 계산 결과를 정비판 기록 산출물(data/reference/, 2026-10 정비 실행에서 동결)과 config.PUBLISHED의 핵심 수치에 대조한다. 허용오차는 기록 파일의 반올림 자릿수(소수 셋째·넷째·여섯째 자리)에 맞춘다.
import os, time
import numpy as np, pandas as pd
import config as C
import bokdpm_macro as B
pd.set_option("display.float_format", lambda v: f"{v:,.4f}")
pd.set_option("display.width", 160)
env = C.setup()
import matplotlib.pyplot as plt
import koreanize_matplotlib # noqa: F401 (한글 글꼴)
post = pd.read_csv(os.path.join(C.OUTPUT, "posterior_summary.csv"), encoding="utf-8-sig")
ann = pd.read_csv(os.path.join(C.OUTPUT, "baseline_annual.csv"), index_col=0, encoding="utf-8-sig")
ann_prev = pd.read_csv(C.REF_PREV["baseline_annual"], index_col=0, encoding="utf-8-sig")
fc = B.read_exact(os.path.join(C.OUTPUT, "baseline_forecast_70.csv"), index_col=0)
fc_prev = B.read_exact(C.REF_PREV["forecast_70"], index_col=0)
sm = B.read_exact(os.path.join(C.INTERIM, "bokdpm_smoothed_2000_2025.csv") if C.FULL else C.SMOOTHED, index_col=0)
mac = pd.read_csv(os.path.join(C.OUTPUT, "dsge_macro_paths.csv"), encoding="utf-8-sig")
ex = pd.read_csv(os.path.join(C.OUTPUT, "dsge_exog_paths.csv"), encoding="utf-8-sig")
lev = pd.read_csv(os.path.join(C.OUTPUT, "exog_levels_2000_2035.csv"), encoding="utf-8-sig")
lev_prev = B.read_levels_xlsx(C.REF_PREV["exog_levels_xlsx"])
hist = pd.read_csv(os.path.join(C.OUTPUT, "exog_hist_v2.csv"), encoding="utf-8-sig")
scen = pd.read_csv(os.path.join(C.OUTPUT, "exog_scen_v2.csv"), encoding="utf-8-sig")
reach = pd.read_csv(os.path.join(C.OUTPUT, "lever_reach.csv"), index_col=0, encoding="utf-8-sig")
pop = pd.read_csv(C.POP, encoding="utf-8-sig")
lab = pd.read_csv(C.LABOR, index_col=0, encoding="utf-8-sig")
CLR = {"S1": "#333333", "S2": "#c0392b", "S3": "#1f4e79", "S4": "#2e7d32", "S5": "#b8892f"}
Python 3.12.10 · pandas 2.2.3 · numpy 2.4.6 · scipy 1.18.0 · matplotlib 3.11.0 실행 방식 ONLINE=0 (ECOS·FRED 재수집) · FULL=0 (Dynare 재추정) ECOS 키 없음 · FRED 키 없음 (ONLINE=0이면 쓰지 않는다) Octave 있음 · Dynare 있음 (FULL=0이면 쓰지 않는다) BOKDPM_data_2025.m 있음 23,440 bytes bokdpm_forecast_2026_2035.csv 있음 56,135 bytes bokdpm_posterior_draws.csv.gz 있음 5,426,716 bytes bokdpm_posterior_mode.csv 있음 2,909 bytes bokdpm_smoothed_2000_2025.csv 있음 142,828 bytes cpi_kor_1999_2000.csv 있음 146 bytes ecos_labor_force.csv 있음 2,620 bytes keis_labor_supply_2024_2034.csv 있음 353 bytes kosis_생산연령인구.csv 있음 735 bytes
표 0. 정상상태 정비 — 이전 값·새 값·근거¶
t0 = pd.read_csv(os.path.join(C.OUTPUT, "steady_state_revision.csv"), index_col=0, encoding="utf-8-sig")
t0.to_csv(os.path.join(C.OUTPUT, "table0_steady_state.csv"), encoding="utf-8-sig")
t0
| 의미 | 이전 값 | 새 값 | 근거 | |
|---|---|---|---|---|
| 파라미터 | ||||
| growth_kor_ss | 한국 잠재성장률(%) | 4.2925 | 1.8000 | 한국은행(2024.12) 「우리 경제의 잠재성장률과 향후 전망」: 2024–2026... |
| pietar_kor_ss | 한국 물가목표(CPI, %) | 3.0000 | 2.0000 | 한국은행 물가안정목표 2%(2016년 이후) |
| def_kor_ss | GDP 디플레이터 상승률(%) | 2.1943 | 2.0000 | 물가목표와 같게(최근 10년 평균 2.08%) |
| rr_kor_bar_ss | 한국 중립 실질 정책금리(%) | 1.5000 | 0.5500 | 한국은행(2024.11) BOK 경제연구 「한국의 중립금리 추정」: 명목 1.8–3... |
| tprem_kor_ss | CD(91일) − 콜금리(%p) | 0.3900 | 0.1800 | 최근 10년 평균 |
| tprem_tb_kor_ss | 국고채(3년) − 콜금리(%p) | 0.7645 | 0.3000 | 최근 10년 평균 |
| tprem_cb_kor_ss | 회사채(3년, AA−) − 국고채(3년)(%p) | 0.7419 | 0.6700 | 최근 10년 평균 |
| house_kor_ss | 주택가격 상승률(%) | 4.2000 | 2.3300 | 최근 10년 평균 |
| ge_kor_ss | 통합재정 총지출 증가율(%) | 7.5885 | 6.5700 | 최근 10년 평균 |
| growth_us_ss | 미국 잠재성장률(%) | 2.3000 | 1.8000 | 미 의회예산처(CBO, 2025.1) 잠재GDP 증가율 2027–2035년 1.8%... |
| pietar_us_ss | 미국 물가목표(CPI, %) | 2.4982 | 2.3000 | CBO 소비자물가(CPI-U) 장기 전망 2.3%(PCE 목표 2%에 CPI 괴리를... |
| rr_us_bar_ss | 미국 중립 실질 정책금리(%) | 2.0000 | 0.9000 | FOMC 경제전망(2026.9) 장기 연방기금금리 중간값 3.2% − 미국 CPI ... |
| oil_g_us_ss | 유가 상승률(달러 기준, %) | 9.8763 | 2.3000 | 장기 실질유가 불변(= 미국 CPI 목표 2.3%) |
표 1. 재추정 행태계수 20개 — 사전분포와 사후분포¶
t1 = post[post["구분"] == "parameters"].set_index("파라미터").drop(columns="구분")
t1.insert(0, "의미", [B.PARAM_LABEL.get(n, "") for n in t1.index])
t1["이전 판 사후평균"] = pd.read_csv(C.REF_PREV["estimation_results"]).set_index("파라미터")["사후평균"].reindex(t1.index)
t1.to_csv(os.path.join(C.OUTPUT, "table1_posterior_params.csv"), encoding="utf-8-sig")
t1.style.format({"사전평균": "{:.2f}", "사전표준편차": "{:.2f}", "사후평균": "{:.3f}", "표준편차": "{:.3f}",
"HPD_low": "{:.3f}", "HPD_high": "{:.3f}", "이전 판 사후평균": "{:.3f}"})
| 의미 | 사전분포 | 사전평균 | 사전표준편차 | 사후평균 | 표준편차 | HPD_low | HPD_high | 이전 판 사후평균 | |
|---|---|---|---|---|---|---|---|---|---|
| 파라미터 | |||||||||
| gamma_kor1 | 한국 테일러 준칙 — 금리 평활 | beta | 0.50 | 0.15 | 0.841 | 0.021 | 0.808 | 0.876 | 0.883 |
| gamma_kor3 | 한국 테일러 준칙 — 산출갭 반응 | gamma | 0.50 | 0.20 | 0.466 | 0.118 | 0.269 | 0.654 | 0.574 |
| beta_kor1 | 한국 IS — 산출갭 지속성 | beta | 0.50 | 0.15 | 0.211 | 0.059 | 0.113 | 0.306 | 0.203 |
| beta_kor2 | 한국 IS — 산출갭 기대(선행항) | beta | 0.10 | 0.07 | 0.021 | 0.015 | 0.001 | 0.043 | 0.019 |
| beta_kor3 | 한국 IS — 실질 회사채금리갭 반응 | gamma | 0.10 | 0.05 | 0.081 | 0.041 | 0.018 | 0.142 | 0.086 |
| lambda_kor1 | 한국 필립스 — 기대물가 가중 | beta | 0.55 | 0.15 | 0.306 | 0.114 | 0.128 | 0.493 | 0.321 |
| lambda_kor2 | 한국 필립스 — 산출갭 기울기 | gamma | 0.15 | 0.08 | 0.083 | 0.041 | 0.021 | 0.143 | 0.092 |
| lambda_kor3 | 한국 필립스 — 물가목표 가중 | beta | 0.65 | 0.15 | 0.766 | 0.028 | 0.725 | 0.813 | 0.753 |
| alpha_kor1 | 한국 오쿤 — 실업갭 지속성 | beta | 0.80 | 0.10 | 0.579 | 0.097 | 0.421 | 0.738 | 0.611 |
| alpha_kor2 | 한국 오쿤 — 산출갭 계수 | gamma | 0.30 | 0.12 | 0.070 | 0.015 | 0.046 | 0.094 | 0.072 |
| gamma_us1 | 미국 테일러 준칙 — 금리 평활 | beta | 0.50 | 0.15 | 0.887 | 0.017 | 0.860 | 0.917 | 0.916 |
| gamma_us2 | 미국 테일러 준칙 — 기대물가 반응 | gamma | 1.50 | 0.25 | 1.721 | 0.273 | 1.263 | 2.153 | 1.677 |
| gamma_us3 | 미국 테일러 준칙 — 산출갭 반응 | gamma | 0.20 | 0.10 | 0.462 | 0.154 | 0.208 | 0.707 | 0.349 |
| beta_us1 | 미국 IS — 산출갭 지속성 | beta | 0.70 | 0.12 | 0.452 | 0.058 | 0.359 | 0.547 | 0.446 |
| beta_us2 | 미국 IS — 산출갭 기대(선행항) | beta | 0.15 | 0.08 | 0.039 | 0.021 | 0.006 | 0.070 | 0.041 |
| lambda_us1 | 미국 필립스 — 기대물가 가중 | beta | 0.45 | 0.15 | 0.378 | 0.098 | 0.219 | 0.543 | 0.340 |
| lambda_us2 | 미국 필립스 — 산출갭 기울기 | gamma | 0.05 | 0.03 | 0.090 | 0.024 | 0.049 | 0.128 | 0.077 |
| lambda_us3 | 미국 필립스 — 물가목표 가중 | beta | 0.50 | 0.15 | 0.431 | 0.037 | 0.368 | 0.490 | 0.439 |
| rho_oil1 | 유가 상승률 — 정상상태 회귀 가중 | beta | 0.90 | 0.05 | 0.880 | 0.049 | 0.798 | 0.958 | 0.881 |
| gamma_kor2 | 한국 테일러 준칙 — 기대물가 반응 | gamma | 1.50 | 0.10 | 1.539 | 0.101 | 1.368 | 1.702 | 1.595 |
표 2. 구조충격 표준편차 34개 — 사전평균과 사후분포¶
t2 = post[post["구분"] == "shocks_std"].set_index("파라미터")[["사전평균", "사후평균", "표준편차", "HPD_low", "HPD_high"]]
t2.to_csv(os.path.join(C.OUTPUT, "table2_posterior_shocks.csv"), encoding="utf-8-sig")
t2.style.format("{:.3f}")
| 사전평균 | 사후평균 | 표준편차 | HPD_low | HPD_high | |
|---|---|---|---|---|---|
| 파라미터 | |||||
| RES_RR_kor_BAR | 0.200 | 1.142 | 0.157 | 0.892 | 1.400 |
| RES_RS_kor | 0.300 | 0.117 | 0.022 | 0.083 | 0.151 |
| RES_UNR_kor_GAP | 0.200 | 0.138 | 0.020 | 0.104 | 0.172 |
| RES_UNR_kor_BAR | 0.100 | 0.083 | 0.031 | 0.036 | 0.130 |
| RES_UNR_G_kor | 0.100 | 0.056 | 0.014 | 0.034 | 0.076 |
| RES_Y_kor | 0.500 | 1.835 | 0.143 | 1.582 | 2.050 |
| RES_LGDP_kor_BAR | 0.400 | 0.059 | 0.005 | 0.051 | 0.068 |
| RES_G_kor | 0.200 | 0.245 | 0.021 | 0.210 | 0.278 |
| RES_BLT_kor | 10.000 | 2.447 | 0.192 | 2.150 | 2.764 |
| RES_BLT_kor_BAR | 5.000 | 3.716 | 1.314 | 1.730 | 5.563 |
| RES_PIE_kor | 0.300 | 0.447 | 0.031 | 0.394 | 0.495 |
| RES_PIE_E_kor4 | 0.300 | 0.210 | 0.081 | 0.101 | 0.334 |
| RES_CA_kor | 2.000 | 4.252 | 0.399 | 3.592 | 4.862 |
| RES_LS_kor_BAR | 1.000 | 1.691 | 0.878 | 0.353 | 2.973 |
| RES_S_G_kor | 0.500 | 1.212 | 1.045 | 0.145 | 2.940 |
| RES_S_kor | 2.000 | 3.114 | 0.679 | 1.972 | 4.203 |
| RES_DEF_kor | 0.300 | 0.706 | 0.052 | 0.618 | 0.789 |
| RES_RR_us_BAR | 0.200 | 0.221 | 0.139 | 0.065 | 0.413 |
| RES_RS_us | 0.300 | 0.396 | 0.028 | 0.349 | 0.442 |
| RES_Y_us | 0.500 | 1.602 | 0.121 | 1.410 | 1.806 |
| RES_LGDP_us_BAR | 0.400 | 0.056 | 0.005 | 0.048 | 0.063 |
| RES_G_us | 0.200 | 0.167 | 0.016 | 0.142 | 0.193 |
| RES_BLT_us | 10.000 | 2.529 | 0.271 | 2.071 | 2.974 |
| RES_BLT_us_BAR | 5.000 | 5.010 | 1.189 | 3.051 | 6.898 |
| RES_PIE_us | 0.300 | 0.336 | 0.023 | 0.298 | 0.373 |
| RES_CD_kor | 0.300 | 0.508 | 0.037 | 0.447 | 0.568 |
| RES_RCD_kor_BAR | 0.200 | 0.204 | 0.118 | 0.065 | 0.390 |
| RES_HOUSE_kor | 1.000 | 1.279 | 0.087 | 1.144 | 1.432 |
| RES_OIL_us | 5.000 | 15.193 | 1.039 | 13.526 | 16.889 |
| RES_RCB_kor_BAR | 0.200 | 0.166 | 0.073 | 0.061 | 0.268 |
| RES_GE_kor | 10.000 | 12.115 | 0.776 | 10.817 | 13.339 |
| RES_TB_kor | 0.300 | 0.347 | 0.025 | 0.308 | 0.386 |
| RES_RTB_kor_BAR | 0.200 | 0.428 | 0.527 | 0.053 | 1.500 |
| RES_RES_CB_kor | 0.300 | 0.574 | 0.041 | 0.508 | 0.639 |
표 3. 기준선 전망 — 연간 요약(2024–2035), 정비판과 이전 판¶
2024–2025년은 평활값(관측변수는 실측치와 같다), 2026년 이후는 사후최빈값 모수의 무충격 전망이다. 정비판은 잠재성장률 1.8%, 물가목표 2%, 실질유가 불변으로 수렴하고, 이전 판은 2000년대 정상상태(4.29%, 3.0%, 연 9.88%)로 수렴한다.
ann.to_csv(os.path.join(C.OUTPUT, "table3_baseline_annual.csv"), encoding="utf-8-sig")
cols = [c for c in ann.columns if c != "구분"]
t3 = pd.concat({"정비판": ann[cols], "이전 판": ann_prev[cols]}, axis=1)
t3.to_csv(os.path.join(C.OUTPUT, "table3b_baseline_vs_prev.csv"), encoding="utf-8-sig")
t3.style.format("{:.2f}")
| 정비판 | 이전 판 | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 실질GDP 성장률(%) | CPI 상승률(%) | 콜금리(%) | 실업률(%) | 산출갭(%) | 두바이유(달러/배럴) | 미국 산출갭(%) | 실질GDP 성장률(%) | CPI 상승률(%) | 콜금리(%) | 실업률(%) | 산출갭(%) | 두바이유(달러/배럴) | 미국 산출갭(%) | |
| 연도 | ||||||||||||||
| 2024 | 1.56 | 2.32 | 3.40 | 2.77 | -0.01 | 80.99 | 1.32 | 1.56 | 2.32 | 3.40 | 2.77 | -0.01 | 80.99 | 1.32 |
| 2025 | 1.83 | 2.12 | 2.60 | 2.78 | -0.31 | 69.39 | 1.00 | 1.83 | 2.12 | 2.60 | 2.78 | -0.31 | 69.39 | 1.00 |
| 2026 | 2.19 | 1.72 | 2.42 | 2.86 | -0.19 | 63.86 | 1.18 | 2.39 | 2.15 | 2.78 | 2.89 | -0.37 | 66.78 | 0.99 |
| 2027 | 1.73 | 1.79 | 2.24 | 2.91 | -0.45 | 65.62 | 0.56 | 3.15 | 2.71 | 3.24 | 2.91 | -0.33 | 74.00 | 0.69 |
| 2028 | 2.24 | 1.87 | 2.27 | 2.87 | -0.15 | 67.24 | -0.03 | 3.92 | 2.94 | 3.71 | 2.84 | 0.03 | 81.85 | 0.10 |
| 2029 | 1.90 | 1.92 | 2.30 | 2.86 | -0.14 | 68.78 | -0.08 | 3.80 | 3.01 | 4.01 | 2.83 | -0.01 | 90.36 | 0.00 |
| 2030 | 1.89 | 1.92 | 2.33 | 2.85 | -0.11 | 70.36 | -0.05 | 4.00 | 3.00 | 4.17 | 2.84 | -0.03 | 99.74 | -0.00 |
| 2031 | 1.86 | 1.93 | 2.35 | 2.85 | -0.10 | 71.98 | -0.03 | 4.13 | 2.99 | 4.25 | 2.84 | -0.05 | 110.10 | -0.00 |
| 2032 | 1.84 | 1.93 | 2.36 | 2.85 | -0.09 | 73.65 | -0.01 | 4.22 | 2.98 | 4.30 | 2.84 | -0.06 | 121.52 | -0.00 |
| 2033 | 1.83 | 1.93 | 2.37 | 2.85 | -0.09 | 75.36 | -0.01 | 4.28 | 2.97 | 4.32 | 2.84 | -0.07 | 134.14 | -0.00 |
| 2034 | 1.83 | 1.93 | 2.38 | 2.85 | -0.09 | 77.11 | -0.00 | 4.31 | 2.97 | 4.33 | 2.84 | -0.07 | 148.06 | -0.00 |
| 2035 | 1.82 | 1.93 | 2.38 | 2.85 | -0.09 | 78.90 | -0.00 | 4.34 | 2.97 | 4.33 | 2.85 | -0.07 | 163.43 | -0.00 |
그림 1. 기준선 전망 — 주요 변수(2015–2035, 분기), 정비판과 이전 판¶
q, qp = pd.concat([sm, fc]), pd.concat([sm, fc_prev])
t = pd.PeriodIndex(q.index, freq="Q").to_timestamp(how="end")
spec = [("실질GDP 성장률(전년동기, %)", lambda d: d["LGDP_kor"].diff(4)), ("CPI 상승률(전년동기, %)", lambda d: d["LCPI_kor"].diff(4)),
("콜금리(%)", lambda d: d["RS_kor"]), ("실질금리(회사채 − CPI, %)", lambda d: d["CB_kor"] - d["LCPI_kor"].diff(4)),
("산출갭(%)", lambda d: d["Y_kor"]), ("두바이유(달러/배럴)", lambda d: np.exp(d["LOIL_us"] / 100))]
fig, axes = plt.subplots(2, 3, figsize=(13, 6.4))
sel = t >= pd.Timestamp("2015-01-01")
for ax, (title, f) in zip(axes.ravel(), spec):
ax.plot(t[sel], f(qp).values[sel], color="#b0b0b0", lw=1.4, ls="--", label="이전 판")
ax.plot(t[sel], f(q).values[sel], color="#1f4e79", lw=1.7, label="정비판")
ax.axvline(pd.Timestamp("2025-12-31"), color="grey", ls=":", lw=1)
ax.set_title(title, loc="left", fontsize=11); ax.grid(alpha=.3)
axes[0, 0].legend(frameon=False, fontsize=9)
fig.suptitle("기준선 전망(점선 오른쪽이 2026Q1 이후 전망)", x=0.01, ha="left", fontweight="bold")
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig1_baseline.png"), dpi=150)
C:\Users\meals\AppData\Local\Temp\ipykernel_18692\2431658101.py:15: UserWarning: Glyph 8722 (\N{MINUS SIGN}) missing from font(s) NanumGothic.
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig1_baseline.png"), dpi=150)
C:\Users\meals\AppData\Local\Programs\Python\Python312\Lib\site-packages\IPython\core\events.py:96: UserWarning: Glyph 8722 (\N{MINUS SIGN}) missing from font(s) NanumGothic.
func(*args, **kwargs)
C:\Users\meals\AppData\Local\Programs\Python\Python312\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 8722 (\N{MINUS SIGN}) missing from font(s) NanumGothic.
fig.canvas.print_figure(bytes_io, **kw)
표 4. 시나리오 설계 레버 — 인구 가정과 감쇠 충격(최고치, 감쇠 분기)¶
t4 = pd.read_csv(os.path.join(C.OUTPUT, "scenario_levers.csv"), index_col=0, encoding="utf-8-sig")
t4.to_csv(os.path.join(C.OUTPUT, "table4_scenario_levers.csv"), encoding="utf-8-sig")
t4
| 인구(생산연령인구 추계) | 미국수요 yus | 유가 oil | 교역비용 tcost | 내수 dshk | |
|---|---|---|---|---|---|
| 시나리오 | |||||
| S1 기준 | 중위 | — | — | — | — |
| S2 공급제약+충격 | 저위 | -1.2 (12분기) | -8.0 (8분기) | +1.5 (12분기) | -1.0 (12분기) |
| S3 제약완화 | 고위 | +0.6 (12분기) | -3.0 (8분기) | -1.0 (12분기) | +0.5 (12분기) |
| S4 기술도약 | 중위 | +0.8 (20분기) | — | — | +0.6 (28분기) |
| S5 지정학 | 중위 | -0.6 (10분기) | +15.0 (8분기) | +2.0 (10분기) | -0.8 (10분기) |
그림 2. 거시 블록 경로 — 산출갭·실질금리·실질환율갭·실업갭(2026–2035)¶
tt = pd.PeriodIndex(B.quarters("2026Q1", B.H), freq="Q").to_timestamp(how="end")
fig, axes = plt.subplots(2, 2, figsize=(12, 6.6))
for ax, (c, title) in zip(axes.ravel(), [("산출갭Y", "산출갭(%)"), ("실질금리RR", "실질금리(%)"),
("실질환율갭S", "실질환율갭(%)"), ("실업갭UNR", "실업갭(%p)")]):
for s in B.SCENARIOS:
ax.plot(tt, mac[mac["시나리오"] == s][c].values, color=CLR[s], lw=1.6, label=f"{s} {B.SCN_KO[s]}")
ax.axhline(0, color="grey", lw=.6); ax.set_title(title, loc="left"); ax.grid(alpha=.3)
axes[0, 0].legend(frameon=False, fontsize=9)
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig2_macro_paths.png"), dpi=150)
표 5. 산업 외생 6종 — 2035년 4분기 수준(정비판, 괄호 안 이전 판 S1)¶
유가는 두바이유 가격(달러/배럴)으로, 실질환율은 로그 수준(100·ln)으로 표시한다. 정비판에서 취업자 수는 인구 레버에 따라 S2·S3가 S1과 영구적으로 다르고, 유가는 유가 증가율 편차를 누적하므로 수준 차이가 남는다. 나머지 네 외생은 충격이 감쇠하여 2035년에 시나리오 간 차이가 거의 사라진다.
def lvl35(d):
x = d[d["분기"] == "2035Q4"].set_index("시나리오")[B.EXOG_COLS].copy()
x["유가"] = np.exp(x["유가"] / 100)
return x.rename(columns={"유가": "두바이유(달러/배럴)", "세계수요": "세계수요(%)", "실질금리": "실질금리(%)",
"실질환율": "실질환율(100·ln)", "고용_취업자": "취업자 수(천 명)", "우리경기": "국내 경기(%)"})
t5 = lvl35(lev)
t5.loc["이전 판 S1"] = lvl35(lev_prev).loc["S1"]
t5.index = [f"{s} {B.SCN_KO[s]}" if s in B.SCN_KO else s for s in t5.index]
t5.to_csv(os.path.join(C.OUTPUT, "table5_exog_2035.csv"), encoding="utf-8-sig")
t5.style.format("{:,.2f}")
| 두바이유(달러/배럴) | 세계수요(%) | 실질금리(%) | 실질환율(100·ln) | 취업자 수(천 명) | 국내 경기(%) | |
|---|---|---|---|---|---|---|
| S1 기준 | 79.59 | -0.00 | 1.31 | 833.46 | 28,762.75 | -0.09 |
| S2 공급제약+충격 | 66.48 | -0.00 | 1.31 | 833.46 | 28,267.54 | -0.09 |
| S3 제약완화 | 74.39 | -0.00 | 1.31 | 833.46 | 29,249.70 | -0.09 |
| S4 기술도약 | 79.59 | -0.00 | 1.31 | 833.46 | 28,767.78 | -0.09 |
| S5 지정학 | 111.53 | -0.00 | 1.31 | 833.46 | 28,762.45 | -0.09 |
| 이전 판 S1 | 169.53 | -0.00 | 2.78 | 824.93 | 31,464.06 | -0.07 |
그림 3. 산업 외생 6종 수준 경로(2000–2035, S1–S5와 이전 판 S1)¶
ta = pd.PeriodIndex(B.quarters("2000Q1", 144), freq="Q").to_timestamp(how="end")
fig, axes = plt.subplots(2, 3, figsize=(14, 7))
for ax, c in zip(axes.ravel(), B.EXOG_COLS):
yp = lev_prev[lev_prev["시나리오"] == "S1"][c].values
ax.plot(ta[104:], yp[104:], color="#b0b0b0", lw=1.3, ls="--", label="이전 판 S1")
for s in B.SCENARIOS:
y = lev[lev["시나리오"] == s][c].values
ax.plot(ta[104:], y[104:], color=CLR[s], lw=1.8 if s == "S1" else 1.2, label=f"{s} {B.SCN_KO[s]}")
ax.plot(ta[:105], lev[lev["시나리오"] == "S1"][c].values[:105], color="#777777", lw=1.1)
ax.axvline(pd.Timestamp("2025-12-31"), color="grey", ls=":", lw=1)
ax.set_title(f"{B.EXOG_LABEL[c]} — {B.EXOG_DEF[c][1]} 투입", loc="left", fontsize=11); ax.grid(alpha=.3)
axes[0, 0].legend(frameon=False, fontsize=8)
fig.suptitle("산업 외생 6종(수준): 회색 실선 = 과거 공통, 색 = 시나리오(2026Q1 이후), 회색 점선 = 이전 판 S1", x=0.01, ha="left", fontweight="bold")
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig3_exog_levels.png"), dpi=150)
설계 일관성 점검 — 레버가 외생 6종에 전달되는가¶
이전 판에서 확인한 세 가지 차이(인구 레버 미전달, 교역비용 레버 미전달, S3 세계수요 누락)가 정비판에서 해소되었는지 확인한다.
- 인구 레버. 외생 취업자 수의 2035Q4 시나리오 차이가 인구 레버의 크기와 같은 방향·크기여야 한다(첫 표).
- S3의 미국수요 레버. 세계수요 외생에 더한 편차가 모든 시나리오에서 설계 레버
yus와 같아야 한다(둘째 표). - 교역비용 레버. 레버를 껐을 때 외생 6종이 달라져야 한다(셋째 표의
tcost행).
pt = B.population_transmission(pop, ex, lev, lev_prev)
display(pt.style.format("{:+.3f}", subset=pd.IndexSlice[:, [c for c in pt.columns if c != "인구 가정"]]))
dc = B.design_consistency()
assert dc["일치"].all()
display(dc)
reach.rename(columns=B.EXOG_LABEL).style.set_caption("레버를 끌 때 외생 6종의 최대 변화폭(2026–2035)").format("{:.3f}")
| 인구 가정 | 생산연령인구 2035, 중위 대비(%) | 인구 레버 2035Q4(100·ln) | 거시 블록 10년 누적 고용, S1 대비(%p) | 외생 취업자 2035Q4, S1 대비(%) | 이전 판 외생 취업자 2035Q4, S1 대비(%) | |
|---|---|---|---|---|---|---|
| 시나리오 | ||||||
| S1 기준 | 중위 | +0.000 | +0.000 | +0.000 | +0.000 | +0.000 |
| S2 공급제약+충격 | 저위 | -2.067 | -1.735 | -1.756 | -1.722 | -0.002 |
| S3 제약완화 | 고위 | +2.052 | +1.678 | +1.661 | +1.693 | +0.001 |
| S4 기술도약 | 중위 | +0.000 | +0.000 | -0.002 | +0.017 | +0.017 |
| S5 지정학 | 중위 | +0.000 | +0.000 | -0.018 | -0.001 | -0.001 |
| 레버 yus 2026Q1 | 세계수요 편차 2026Q1 | 이전 판 편차 2026Q1 | 40분기 최대 차이 | 일치 | |
|---|---|---|---|---|---|
| 시나리오 | |||||
| S1 기준 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | True |
| S2 공급제약+충격 | -1.2000 | -1.2000 | -1.2000 | 0.0000 | True |
| S3 제약완화 | 0.6000 | 0.6000 | 0.0000 | 0.0000 | True |
| S4 기술도약 | 0.8000 | 0.8000 | 0.8000 | 0.0000 | True |
| S5 지정학 | -0.6000 | -0.6000 | -0.6000 | 0.0000 | True |
| 유가 | 세계수요 | 실질금리 | 실질환율 | 취업자 수 | 국내 경기 | |
|---|---|---|---|---|---|---|
| 끈 레버 | ||||||
| 인구 | 0.000 | 0.000 | 0.000 | 0.000 | 494.622 | 0.000 |
| yus | 0.000 | 1.200 | 0.959 | 2.503 | 138.569 | 0.539 |
| oil | 33.750 | 0.000 | 0.366 | 0.862 | 50.137 | 0.216 |
| tcost | 0.000 | 0.000 | 1.145 | 2.902 | 162.872 | 0.663 |
| dshk | 0.000 | 0.000 | 2.664 | 6.954 | 384.914 | 1.496 |
이전 판 대비 변화 — 외생 6종(투입형)¶
산업모형에 들어가는 투입형 외생을 이전 판과 비교한다. 과거 구간에서는 실질금리 한 열만 달라지고(수준 → 1차 차분), 나머지 다섯 외생은 같아야 한다(관측자료가 같다. 평활값의 수치 오차 때문에 소수 넷째 자리 한 단위까지는 같은 값으로 본다). 미래 구간은 기준선·레버·노동공급이 모두 바뀌었다.
hp = pd.read_csv(C.REF_PREV["exog_hist_v2"], encoding="utf-8-sig"); spv = pd.read_csv(C.REF_PREV["exog_scen_v2"], encoding="utf-8-sig")
ch = B.compare_versions(hist, hp, ["분기"], B.EXOG_COLS)
# 소수 넷째 자리 반올림 값이고 평활값이 수치 오차(10⁻⁹) 수준에서 다를 수 있으므로 마지막 자리 한 단위(10⁻⁴)까지 같은 값으로 본다
assert (ch.drop(index="실질금리")["최대 절대차"] <= 1.0001e-4).all(), "실질금리 밖의 과거 외생이 이전 판과 다르다"
display(ch.rename(index=B.EXOG_LABEL).style.set_caption("과거 2000Q1–2025Q4(투입형)").format({c: "{:.4f}" for c in ["최대 절대차", "평균 절대차", "새 값", "이전 값"]}))
s1n, s1p = scen[scen["시나리오"] == "S1"], spv[spv["시나리오"] == "S1"]
cmp = pd.DataFrame({"정비판 S1 40분기 평균": s1n[B.EXOG_COLS].mean(), "이전 판 S1 40분기 평균": s1p[B.EXOG_COLS].mean()})
cmp.index = [f"{B.EXOG_LABEL[c]}({B.EXOG_DEF[c][1]})" for c in cmp.index]
cmp.to_csv(os.path.join(C.OUTPUT, "table6_exog_vs_prev.csv"), encoding="utf-8-sig")
cmp.style.format("{:.3f}")
| 최대 절대차 | 평균 절대차 | 최대차 위치 | 새 값 | 이전 값 | |
|---|---|---|---|---|---|
| 항목 | |||||
| 유가 | 0.0001 | 0.0000 | 2023Q1 | -4.9567 | -4.9568 |
| 세계수요 | 0.0000 | 0.0000 | 2000Q1 | 1.6680 | 1.6680 |
| 실질금리 | 8.2946 | 2.0087 | 2000Q3 | -2.1900 | 6.1046 |
| 실질환율 | 0.0000 | 0.0000 | 2000Q1 | 0.8177 | 0.8177 |
| 취업자 수 | 0.0000 | 0.0000 | 2000Q1 | 0.8011 | 0.8011 |
| 국내 경기 | 0.0000 | 0.0000 | 2000Q1 | -0.8543 | -0.8543 |
| 정비판 S1 40분기 평균 | 이전 판 S1 40분기 평균 | |
|---|---|---|
| 유가(1차 차분) | 0.561 | 2.451 |
| 세계수요(수준) | 0.153 | 0.177 |
| 실질금리(1차 차분) | 0.009 | 2.350 |
| 실질환율(1차 차분) | 0.104 | -0.109 |
| 취업자 수(로그 차분(×100)) | -0.003 | 0.221 |
| 국내 경기(수준) | -0.150 | -0.103 |
검증 — 정비판 기록 산출물과 핵심 수치¶
계산 결과가 2026-10 정비 실행에서 동결한 기록 산출물(data/reference/)과 반올림 범위 안에서 같아야 통과한다. 표 단위 비교는 최대 절대차를 계산 열에 적고 기록 열을 0으로 둔다. 허용오차는 사후분포 요약·기준선 전망 5×10⁻⁷(소수 여섯째 자리), 거시 블록 경로 5×10⁻⁴(셋째 자리), 외생 6종 5×10⁻⁵(넷째 자리), 핵심 수치는 표기 자릿수의 절반이다.
P = C.PUBLISHED
checks = []
def add(item, calc, pub, tol):
checks.append({"항목": item, "계산": calc, "기록": pub, "허용오차": tol})
# (1) 입력·모형
obs = B.read_dynare_data(C.DATAFILE)
add("관측자료 SHA-256(앞 12자리)", B.sha256(C.DATAFILE)[:12], P["관측자료_SHA256"][:12], "일치")
add("관측자료 분기 수", obs.shape[0], P["관측자료_분기"], 0)
add("관측변수 수", obs.shape[1], P["관측변수"], 0)
add("평활값 − 관측자료(최대절대차)", float(max((sm[v] - obs[v]).abs().max() for v in B.VAROBS)), 0.0, 1e-6)
mod = B.parse_mod(C.MODFILE)
add("방정식 수", mod["방정식"], P["방정식"], 0)
add("구조충격 수", mod["외생충격"], P["구조충격"], 0)
add("추정 행태계수 수", int((mod["사전분포"]["구분"] == "parameters").sum()), P["추정계수"], 0)
ss = B.calibrated_values(C.MODFILE, [r[0] for r in B.SS_REVISION])
for n, _, new, _, _ in B.SS_REVISION:
add(f"정상상태 {n}", ss[n], new, 1e-9)
# (2) 사후분포 요약 54개 × 4통계
pub = pd.read_csv(C.REF["estimation_results"], encoding="utf-8-sig")
m = post.merge(pub, on=["구분", "파라미터"], suffixes=("", "_기록"), how="outer", indicator=True)
assert (m["_merge"] == "both").all() and len(m) == 54
for c in ["사후평균", "표준편차", "HPD_low", "HPD_high"]:
add(f"사후 {c} 54개(최대절대차)", float((m[c] - m[c + "_기록"]).abs().max()), 0.0, 5e-7)
pm = post.set_index("파라미터")["사후평균"]
for k in ["gamma_kor1", "gamma_kor2", "gamma_kor3", "beta_kor1", "lambda_kor3", "alpha_kor2", "rho_oil1", "RES_OIL_us", "RES_Y_kor"]:
add(f"사후평균 {k}", pm[k], P[k], 5e-7)
# (3) 기준선 전망과 연간 요약
bf = pd.read_csv(C.REF["baseline_forecast"], encoding="utf-8-sig")
add("기준선 전망 11변수 × 40분기(최대절대차)", float(max(np.abs(fc[c].values - bf[c].values).max() for c in bf.columns[1:])), 0.0, 5e-7)
for y in (2030, 2035):
add(f"기준선 실질GDP 성장률 {y}(%)", ann.loc[y, "실질GDP 성장률(%)"], P[f"GDP성장_{y}"], 0.005)
add(f"기준선 CPI 상승률 {y}(%)", ann.loc[y, "CPI 상승률(%)"], P[f"CPI_{y}"], 0.005)
add("기준선 두바이유 2035(달러, 연평균)", ann.loc[2035, "두바이유(달러/배럴)"], P["두바이유_2035"], 0.05)
# (4) 거시 블록
rmac = pd.read_csv(C.REF["dsge_macro_paths"], encoding="utf-8-sig"); rex = pd.read_csv(C.REF["dsge_exog_paths"], encoding="utf-8-sig")
add("거시경로 6열 × 200행(최대절대차)", float(B.max_abs_diff(mac, rmac, ["시나리오", "분기"], list(rmac.columns[2:])).max()), 0.0, 5e-4)
add("거시 블록 성장경로 5열 × 200행(최대절대차)", float(B.max_abs_diff(ex, rex, ["시나리오", "분기"], list(rex.columns[2:])).max()), 0.0, 5e-4)
cum = ex.groupby("시나리오")["lab_g"].sum()
for s in B.SCENARIOS:
add(f"10년 누적 고용 증가율 {s}(%)", cum[s], P[f"누적고용_{s}"], 0.005)
add("S4 2030Q1 산출갭(%)", mac[(mac["시나리오"] == "S4") & (mac["분기"] == "2030Q1")]["산출갭Y"].iloc[0], P["산출갭2030_S4"], 0.005)
# (5) 수준 외생 — 외생별, 5개 시나리오 × 144분기
rlev = pd.read_csv(C.REF["exog_levels"], encoding="utf-8-sig")
dl = B.max_abs_diff(lev, rlev, ["시나리오", "분기"], B.EXOG_COLS)
for c in B.EXOG_COLS:
add(f"수준 외생 {B.EXOG_LABEL[c]} S1–S5(최대절대차)", float(dl[c]), 0.0, 5e-5)
emp = lev[(lev["시나리오"] == "S1") & (lev["분기"] == "2025Q4")]["고용_취업자"].iloc[0]
add("취업자 수 구성값 2025Q4(천 명)", emp, P["고용구성_2025Q4"], 0.5)
add("관측 취업자 2025Q4(천 명)", float(lab.loc["2025Q4", "취업자"]), P["관측취업자_2025Q4"], 0.5)
e35 = lev[lev["분기"] == "2035Q4"].set_index("시나리오")
add("취업자 수 2035Q4 S1(천 명)", e35.loc["S1", "고용_취업자"], P["취업자_2035_S1"], 0.5)
add("취업자 수 2035Q4 S2/S1 − 1(%)", 100 * (e35.loc["S2", "고용_취업자"] / e35.loc["S1", "고용_취업자"] - 1), P["취업자_2035_S2대비"], 0.005)
add("두바이유 2035Q4 S1(달러)", float(np.exp(e35.loc["S1", "유가"] / 100)), P["유가_2035Q4_S1"], 0.05)
add("실질금리 2035Q4 S1(%)", e35.loc["S1", "실질금리"], P["실질금리_2035Q4_S1"], 0.005)
# (6) 산업모형 투입 외생 — 과거(외생별), 미래(시나리오 × 외생별)
rh = pd.read_csv(C.REF["exog_hist_v2"], encoding="utf-8-sig"); rs = pd.read_csv(C.REF["exog_scen_v2"], encoding="utf-8-sig")
dh = B.max_abs_diff(hist, rh, ["분기"], B.EXOG_COLS)
for c in B.EXOG_COLS:
add(f"exog_hist_v2 {B.EXOG_LABEL[c]}(104분기)", float(dh[c]), 0.0, 5e-5)
for s in B.SCENARIOS:
ds = B.max_abs_diff(scen[scen["시나리오"] == s], rs[rs["시나리오"] == s], ["시나리오", "분기"], B.EXOG_COLS)
for c in B.EXOG_COLS:
add(f"exog_scen_v2 {s} {B.EXOG_LABEL[c]}(40분기)", float(ds[c]), 0.0, 5e-5)
# (7) 레버 전달
for lever in reach.index:
add(f"레버 전달 {lever}(최대 변화폭 > 0)", bool((reach.loc[lever] > 0).any()), True, "일치")
def passed(r):
if r["허용오차"] == "일치":
return r["계산"] == r["기록"]
return abs(float(r["계산"]) - float(r["기록"])) <= float(r["허용오차"])
res = pd.DataFrame(checks)
res["통과"] = res.apply(passed, axis=1)
res.to_csv(os.path.join(C.OUTPUT, "verification.csv"), index=False, encoding="utf-8-sig")
show = res.copy()
for c in ["계산", "기록", "허용오차"]:
show[c] = show[c].map(lambda v: v if isinstance(v, (str, bool)) else f"{v:.6g}")
with pd.option_context("display.max_rows", 200):
display(show)
assert res["통과"].all(), "기록 산출물과 계산 결과가 다르다 — 위 표에서 통과=False 항목을 확인한다"
print(f"검증 통과: {len(res)}개 항목에서 정상상태·사후분포 요약·기준선·거시경로·외생 6종(S1–S5)·레버 전달을 재현했다.")
same = [f for f in ("exog_hist_v2.csv", "exog_scen_v2.csv", "dsge_macro_paths.csv", "dsge_exog_paths.csv", "exog_levels_2000_2035.csv")
if B.sha256(os.path.join(C.OUTPUT, f)) == B.sha256(os.path.join(C.REFERENCE, f))]
print(f"참고(통과 조건 아님): 파일 단위로도 기록본과 바이트가 같은 산출물 {len(same)}/5개 — {', '.join(same)}")
| 항목 | 계산 | 기록 | 허용오차 | 통과 | |
|---|---|---|---|---|---|
| 0 | 관측자료 SHA-256(앞 12자리) | 79c7586814e9 | 79c7586814e9 | 일치 | True |
| 1 | 관측자료 분기 수 | 104 | 104 | 0 | True |
| 2 | 관측변수 수 | 20 | 20 | 0 | True |
| 3 | 평활값 − 관측자료(최대절대차) | 2.88287e-09 | 0 | 1e-06 | True |
| 4 | 방정식 수 | 70 | 70 | 0 | True |
| 5 | 구조충격 수 | 34 | 34 | 0 | True |
| 6 | 추정 행태계수 수 | 20 | 20 | 0 | True |
| 7 | 정상상태 growth_kor_ss | 1.8 | 1.8 | 1e-09 | True |
| 8 | 정상상태 pietar_kor_ss | 2 | 2 | 1e-09 | True |
| 9 | 정상상태 def_kor_ss | 2 | 2 | 1e-09 | True |
| 10 | 정상상태 rr_kor_bar_ss | 0.55 | 0.55 | 1e-09 | True |
| 11 | 정상상태 tprem_kor_ss | 0.18 | 0.18 | 1e-09 | True |
| 12 | 정상상태 tprem_tb_kor_ss | 0.3 | 0.3 | 1e-09 | True |
| 13 | 정상상태 tprem_cb_kor_ss | 0.67 | 0.67 | 1e-09 | True |
| 14 | 정상상태 house_kor_ss | 2.33 | 2.33 | 1e-09 | True |
| 15 | 정상상태 ge_kor_ss | 6.57 | 6.57 | 1e-09 | True |
| 16 | 정상상태 growth_us_ss | 1.8 | 1.8 | 1e-09 | True |
| 17 | 정상상태 pietar_us_ss | 2.3 | 2.3 | 1e-09 | True |
| 18 | 정상상태 rr_us_bar_ss | 0.9 | 0.9 | 1e-09 | True |
| 19 | 정상상태 oil_g_us_ss | 2.3 | 2.3 | 1e-09 | True |
| 20 | 사후 사후평균 54개(최대절대차) | 0 | 0 | 5e-07 | True |
| 21 | 사후 표준편차 54개(최대절대차) | 0 | 0 | 5e-07 | True |
| 22 | 사후 HPD_low 54개(최대절대차) | 0 | 0 | 5e-07 | True |
| 23 | 사후 HPD_high 54개(최대절대차) | 0 | 0 | 5e-07 | True |
| 24 | 사후평균 gamma_kor1 | 0.841458 | 0.841458 | 5e-07 | True |
| 25 | 사후평균 gamma_kor2 | 1.53946 | 1.53946 | 5e-07 | True |
| 26 | 사후평균 gamma_kor3 | 0.466217 | 0.466217 | 5e-07 | True |
| 27 | 사후평균 beta_kor1 | 0.211223 | 0.211223 | 5e-07 | True |
| 28 | 사후평균 lambda_kor3 | 0.765561 | 0.765561 | 5e-07 | True |
| 29 | 사후평균 alpha_kor2 | 0.0702645 | 0.070265 | 5e-07 | True |
| 30 | 사후평균 rho_oil1 | 0.879517 | 0.879517 | 5e-07 | True |
| 31 | 사후평균 RES_OIL_us | 15.1934 | 15.1934 | 5e-07 | True |
| 32 | 사후평균 RES_Y_kor | 1.83497 | 1.83497 | 5e-07 | True |
| 33 | 기준선 전망 11변수 × 40분기(최대절대차) | 4.96344e-07 | 0 | 5e-07 | True |
| 34 | 기준선 실질GDP 성장률 2030(%) | 1.89091 | 1.89 | 0.005 | True |
| 35 | 기준선 CPI 상승률 2030(%) | 1.92217 | 1.92 | 0.005 | True |
| 36 | 기준선 실질GDP 성장률 2035(%) | 1.82258 | 1.82 | 0.005 | True |
| 37 | 기준선 CPI 상승률 2035(%) | 1.9342 | 1.93 | 0.005 | True |
| 38 | 기준선 두바이유 2035(달러, 연평균) | 78.9038 | 78.9 | 0.05 | True |
| 39 | 거시경로 6열 × 200행(최대절대차) | 0 | 0 | 0.0005 | True |
| 40 | 거시 블록 성장경로 5열 × 200행(최대절대차) | 0 | 0 | 0.0005 | True |
| 41 | 10년 누적 고용 증가율 S1(%) | -0.169 | -0.17 | 0.005 | True |
| 42 | 10년 누적 고용 증가율 S2(%) | -1.925 | -1.93 | 0.005 | True |
| 43 | 10년 누적 고용 증가율 S3(%) | 1.492 | 1.49 | 0.005 | True |
| 44 | 10년 누적 고용 증가율 S4(%) | -0.171 | -0.17 | 0.005 | True |
| 45 | 10년 누적 고용 증가율 S5(%) | -0.187 | -0.19 | 0.005 | True |
| 46 | S4 2030Q1 산출갭(%) | 0.463 | 0.46 | 0.005 | True |
| 47 | 수준 외생 유가 S1–S5(최대절대차) | 0 | 0 | 5e-05 | True |
| 48 | 수준 외생 세계수요 S1–S5(최대절대차) | 0 | 0 | 5e-05 | True |
| 49 | 수준 외생 실질금리 S1–S5(최대절대차) | 0 | 0 | 5e-05 | True |
| 50 | 수준 외생 실질환율 S1–S5(최대절대차) | 0 | 0 | 5e-05 | True |
| 51 | 수준 외생 취업자 수 S1–S5(최대절대차) | 0 | 0 | 5e-05 | True |
| 52 | 수준 외생 국내 경기 S1–S5(최대절대차) | 0 | 0 | 5e-05 | True |
| 53 | 취업자 수 구성값 2025Q4(천 명) | 28800.8 | 28801 | 0.5 | True |
| 54 | 관측 취업자 2025Q4(천 명) | 28792 | 28792 | 0.5 | True |
| 55 | 취업자 수 2035Q4 S1(천 명) | 28762.7 | 28762.7 | 0.5 | True |
| 56 | 취업자 수 2035Q4 S2/S1 − 1(%) | -1.72172 | -1.72 | 0.005 | True |
| 57 | 두바이유 2035Q4 S1(달러) | 79.5853 | 79.6 | 0.05 | True |
| 58 | 실질금리 2035Q4 S1(%) | 1.3132 | 1.31 | 0.005 | True |
| 59 | exog_hist_v2 유가(104분기) | 0 | 0 | 5e-05 | True |
| 60 | exog_hist_v2 세계수요(104분기) | 0 | 0 | 5e-05 | True |
| 61 | exog_hist_v2 실질금리(104분기) | 0 | 0 | 5e-05 | True |
| 62 | exog_hist_v2 실질환율(104분기) | 0 | 0 | 5e-05 | True |
| 63 | exog_hist_v2 취업자 수(104분기) | 0 | 0 | 5e-05 | True |
| 64 | exog_hist_v2 국내 경기(104분기) | 0 | 0 | 5e-05 | True |
| 65 | exog_scen_v2 S1 유가(40분기) | 0 | 0 | 5e-05 | True |
| 66 | exog_scen_v2 S1 세계수요(40분기) | 0 | 0 | 5e-05 | True |
| 67 | exog_scen_v2 S1 실질금리(40분기) | 0 | 0 | 5e-05 | True |
| 68 | exog_scen_v2 S1 실질환율(40분기) | 0 | 0 | 5e-05 | True |
| 69 | exog_scen_v2 S1 취업자 수(40분기) | 0 | 0 | 5e-05 | True |
| 70 | exog_scen_v2 S1 국내 경기(40분기) | 0 | 0 | 5e-05 | True |
| 71 | exog_scen_v2 S2 유가(40분기) | 0 | 0 | 5e-05 | True |
| 72 | exog_scen_v2 S2 세계수요(40분기) | 0 | 0 | 5e-05 | True |
| 73 | exog_scen_v2 S2 실질금리(40분기) | 0 | 0 | 5e-05 | True |
| 74 | exog_scen_v2 S2 실질환율(40분기) | 0 | 0 | 5e-05 | True |
| 75 | exog_scen_v2 S2 취업자 수(40분기) | 0 | 0 | 5e-05 | True |
| 76 | exog_scen_v2 S2 국내 경기(40분기) | 0 | 0 | 5e-05 | True |
| 77 | exog_scen_v2 S3 유가(40분기) | 0 | 0 | 5e-05 | True |
| 78 | exog_scen_v2 S3 세계수요(40분기) | 0 | 0 | 5e-05 | True |
| 79 | exog_scen_v2 S3 실질금리(40분기) | 0 | 0 | 5e-05 | True |
| 80 | exog_scen_v2 S3 실질환율(40분기) | 0 | 0 | 5e-05 | True |
| 81 | exog_scen_v2 S3 취업자 수(40분기) | 0 | 0 | 5e-05 | True |
| 82 | exog_scen_v2 S3 국내 경기(40분기) | 0 | 0 | 5e-05 | True |
| 83 | exog_scen_v2 S4 유가(40분기) | 0 | 0 | 5e-05 | True |
| 84 | exog_scen_v2 S4 세계수요(40분기) | 0 | 0 | 5e-05 | True |
| 85 | exog_scen_v2 S4 실질금리(40분기) | 0 | 0 | 5e-05 | True |
| 86 | exog_scen_v2 S4 실질환율(40분기) | 0 | 0 | 5e-05 | True |
| 87 | exog_scen_v2 S4 취업자 수(40분기) | 0 | 0 | 5e-05 | True |
| 88 | exog_scen_v2 S4 국내 경기(40분기) | 0 | 0 | 5e-05 | True |
| 89 | exog_scen_v2 S5 유가(40분기) | 0 | 0 | 5e-05 | True |
| 90 | exog_scen_v2 S5 세계수요(40분기) | 0 | 0 | 5e-05 | True |
| 91 | exog_scen_v2 S5 실질금리(40분기) | 0 | 0 | 5e-05 | True |
| 92 | exog_scen_v2 S5 실질환율(40분기) | 0 | 0 | 5e-05 | True |
| 93 | exog_scen_v2 S5 취업자 수(40분기) | 0 | 0 | 5e-05 | True |
| 94 | exog_scen_v2 S5 국내 경기(40분기) | 0 | 0 | 5e-05 | True |
| 95 | 레버 전달 인구(최대 변화폭 > 0) | True | True | 일치 | True |
| 96 | 레버 전달 yus(최대 변화폭 > 0) | True | True | 일치 | True |
| 97 | 레버 전달 oil(최대 변화폭 > 0) | True | True | 일치 | True |
| 98 | 레버 전달 tcost(최대 변화폭 > 0) | True | True | 일치 | True |
| 99 | 레버 전달 dshk(최대 변화폭 > 0) | True | True | 일치 | True |
검증 통과: 100개 항목에서 정상상태·사후분포 요약·기준선·거시경로·외생 6종(S1–S5)·레버 전달을 재현했다. 참고(통과 조건 아님): 파일 단위로도 기록본과 바이트가 같은 산출물 5/5개 — exog_hist_v2.csv, exog_scen_v2.csv, dsge_macro_paths.csv, dsge_exog_paths.csv, exog_levels_2000_2035.csv