03 결과 도출 — 표·그림과 검증¶
02_분석.ipynb의 산출물로 포털 카드 「여섯 외생을 나란히 놓고 보니」(exog-deepdive.html)와 「유가 한 변수를 파보니」(oil-deepdive.html)의
표·그림을 다시 만든다. 공표 문구 가운데 계산과 맞지 않거나 근거가 달라진 항목은 별도 표로 정리한다. 표 7은 정비 전후의 외생 반사실(참고),
표 8–11·그림 4는 2026-10 정비판의 선형 SHAP·유가 진단·시나리오 폭(02 10절)이다. 마지막 셀은 이전 판 공표 수치와 정비판 기록 수치를 계산 결과와 대조한다
(반올림 범위 안에서 일치해야 통과).
import os, json
import config as C # BLAS 스레드 설정이 적용되도록 numpy보다 먼저 불러온다
import numpy as np, pandas as pd
import exog_diagnosis as F
pd.set_option("display.float_format", lambda v: f"{v:,.3f}")
pd.set_option("display.width", 200)
C.setup()
import matplotlib.pyplot as plt
import koreanize_matplotlib # noqa: F401 (한글 글꼴)
plt.rcParams["axes.unicode_minus"] = False
rd = lambda name, **kw: pd.read_csv(os.path.join(C.OUTPUT, name), encoding="utf-8-sig", **kw) # noqa: E731
eff = rd("exog_effects.csv", index_col=0)
tot = rd("model_totals.csv", index_col=0)
paths = rd("exog_paths_summary.csv", index_col=0)
per = rd("exog_persistence.csv", index_col=0)
orank = rd("oil_rank.csv", dtype={"분류": str})
oil_cmp = rd("oil_effect_compare.csv", index_col=0)
dollars = rd("oil_dollar_paths.csv", index_col=0)
gap = rd("oil_level_gap.csv", index_col=0)
var = rd("oil_source_variants.csv", index_col=0)
src_chk = rd("oil_source_check.csv", index_col=0)
bm = rd("oil_benchmark.csv", index_col=0)
dub = rd("dubai_sim.csv", index_col=0)
shap_chk = rd("shap_check.csv", index_col=0)
bat = rd("battery_parent_check.csv", index_col=0)
SH = {r: rd(f"shap_{r}.csv", index_col=0) for r in ("36", "62", "69")}
NAME = {"유가": "유가", "세계수요": "세계수요", "실질금리": "실질금리", "실질환율": "실질환율", "고용_취업자": "고용(취업자)", "우리경기": "우리경기"}
INK, MUTED, S1C, S2C = "#1a1f26", "#5c6570", "#2a78d6", "#eb6834" # 글자색·보조 글자색·계열 1·계열 2
Python 3.12.10 · pandas 2.2.3 · numpy 2.4.6 ONLINE=0 (FRED 유가 재수집) FULL=0 (확장 점검) FRED 키 없음(공개 CSV 사용) 외생 과거(정상형) 있음 data\inputs\exog_hist_v2.csv 외생 시나리오(정상형) 있음 data\inputs\exog_scen_v2.csv 외생 수준 있음 data\inputs\exog_scenarios_v2.csv 시나리오 충격 있음 data\inputs\dsge_exog_paths.csv BOKDPM 관측 있음 data\inputs\bokdpm_obs_2000_2025.csv FRED WTI 있음 data\inputs\fred_POILWTIUSDM.csv FRED 두바이 있음 data\inputs\fred_POILDUBUSDM.csv 동결 계수 있음 data\inputs\varx_coef_frozen.npz 패널 총량 있음 data\inputs\levels_agg.csv 패널 36 있음 data\inputs\levels_sa.csv 패널 62 있음 data\inputs\levels_62.csv 패널 69 있음 data\inputs\levels_69.csv
표 1. 외생 6종의 실질부가가치 순효과(2035년, S1) — 반사실(해당 외생 고정) 재전망¶
t1 = eff.copy()
t1["장기"] = per["판정"]
t1 = t1.sort_values("총량_CAGR기여_%p", ascending=False)
t1.index = [NAME[k] for k in t1.index]
t1 = t1[["변환", "장기", "총량_효과_조원", "총량_CAGR기여_%p", "바텀업_효과_조원", "바텀업_CAGR기여_%p"]]
t1.to_csv(os.path.join(C.OUTPUT, "table1_exog_effects.csv"), encoding="utf-8-sig")
print(f"기준 전망(S1): 총량 {tot.loc['총량', '2025(조원)']:,.0f} → {tot.loc['총량', '2035_S1(조원)']:,.0f}조원(연 {tot.loc['총량', 'CAGR(%)']:.2f}%), "
f"62 바텀업 {tot.loc['62', '2025(조원)']:,.0f} → {tot.loc['62', '2035_S1(조원)']:,.0f}조원(연 {tot.loc['62', 'CAGR(%)']:.2f}%)")
t1.style.format({"총량_효과_조원": "{:+,.0f}", "바텀업_효과_조원": "{:+,.0f}", "총량_CAGR기여_%p": "{:+.2f}", "바텀업_CAGR기여_%p": "{:+.2f}"})
기준 전망(S1): 총량 2,326 → 2,970조원(연 2.47%), 62 바텀업 2,178 → 3,507조원(연 4.88%)
| 변환 | 장기 | 총량_효과_조원 | 총량_CAGR기여_%p | 바텀업_효과_조원 | 바텀업_CAGR기여_%p | |
|---|---|---|---|---|---|---|
| 실질금리 | level | 일시 | +162 | +0.57 | +354 | +1.11 |
| 고용(취업자) | dlog | 일시 | +62 | +0.22 | +32 | +0.10 |
| 유가 | diff | 영구 | +15 | +0.05 | +65 | +0.20 |
| 실질환율 | diff | 일시 | +5 | +0.02 | +10 | +0.03 |
| 세계수요 | level | 일시 | +2 | +0.01 | -12 | -0.04 |
| 우리경기 | level | 일시 | -1 | -0.00 | +8 | +0.02 |
그림 1. 외생별 10년 CAGR 기여 — 총량 모형과 62 바텀업¶
o = eff.sort_values("바텀업_CAGR기여_%p")
y = np.arange(len(o))
fig, ax = plt.subplots(figsize=(8, 4.2))
ax.barh(y + 0.19, o["총량_CAGR기여_%p"], height=0.36, color=S1C, label="총량 예측모형")
ax.barh(y - 0.19, o["바텀업_CAGR기여_%p"], height=0.36, color=S2C, label="62 바텀업")
for yi, (a, b) in enumerate(zip(o["총량_CAGR기여_%p"], o["바텀업_CAGR기여_%p"])):
ax.text(max(a, 0) + 0.02, yi + 0.19, f"{a:+.2f}", va="center", fontsize=8, color=MUTED)
ax.text(max(b, 0) + 0.02, yi - 0.19, f"{b:+.2f}", va="center", fontsize=8, color=MUTED)
ax.set_yticks(y, [NAME[k] for k in o.index], color=INK)
ax.axvline(0, color="#9aa3ad", lw=0.8)
ax.set_xlabel("2026–2035 연평균 성장률 기여(%p)", color=MUTED)
ax.grid(axis="x", alpha=.25); ax.spines[["top", "right"]].set_visible(False)
ax.legend(frameon=False, loc="lower right")
ax.set_title("외생별 실질부가가치 CAGR 기여(2035, S1)", loc="left", color=INK)
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig1_exog_effects.png"), dpi=150)
표 2. 시나리오 폭(max−min, 연평균) — 2026년과 2035년¶
t2 = per.copy()
t2.index = [NAME[k] for k in t2.index]
t2.to_csv(os.path.join(C.OUTPUT, "table2_persistence.csv"), encoding="utf-8-sig")
t2.style.format({"폭_2026": "{:,.2f}", "폭_2035": "{:,.3f}"})
| 폭_2026 | 폭_2035 | 판정 | |
|---|---|---|---|
| 유가 | 25.16 | 51.750 | 영구 |
| 세계수요 | 1.79 | 0.000 | 일시 |
| 실질금리 | 4.80 | 0.000 | 일시 |
| 실질환율 | 11.87 | 0.004 | 일시 |
| 고용(취업자) | 531.61 | 8.630 | 일시 |
| 우리경기 | 2.94 | 0.000 | 일시 |
그림 2. 유가 경로와 시나리오 충격의 누적¶
왼쪽은 연평균 유가(달러/배럴)이다. 과거 구간은 VARX에 들어간 값(BOKDPM 평활 LOIL_us)으로, 두바이유 기준이다.
오른쪽은 S2·S3·S5의 유가 충격(oil_g 편차, 분기)과 그 누적합인 수준차(S − S1, 100·ln)를 나눠 보인다. 충격은 8분기 뒤 사라지지만 수준차는 남는다.
dsge = pd.read_csv(C.DSGE_EXOG, encoding="utf-8-sig")
SC = {"S1": S1C, "S2": S2C, "S3": "#1baf7a", "S4": "#eda100", "S5": "#e87ba4"}
fig, axes = plt.subplots(1, 3, figsize=(12, 4.0), gridspec_kw={"width_ratios": [1.6, 1, 1]})
ax = axes[0]
h = dollars.loc[:2025, "S1"]
ax.plot(h.index, h.values, color=INK, lw=2, label="과거(두바이 기준)")
for s in ["S1", "S2", "S3", "S4", "S5"]:
f = dollars.loc[2025:, s]
ax.plot(f.index, f.values, color=SC[s], lw=2, ls="--" if s == "S4" else "-", label=s)
for s, dy in [("S5", 0), ("S1", 4), ("S3", -4), ("S2", 0)]:
v = dollars.loc[2035, s]
ax.text(2035.4, v + dy, ("S1·S4" if s == "S1" else s) + f" ${v:.0f}", va="center", fontsize=8, color=INK)
ax.set_xlim(2000, 2039); ax.set_ylabel("달러/배럴(연평균)", color=MUTED)
ax.grid(alpha=.25); ax.spines[["top", "right"]].set_visible(False); ax.legend(frameon=False, fontsize=8, loc="upper left")
ax.set_title("(가) 유가 수준", loc="left", color=INK)
q = np.arange(1, 41)
g1 = dsge[dsge["시나리오"] == "S1"]["oil_g"].to_numpy()[:40]
for s in ["S2", "S3", "S5"]:
dev = dsge[dsge["시나리오"] == s]["oil_g"].to_numpy()[:40] - g1
axes[1].plot(q, dev, color=SC[s], lw=2, label=s)
axes[2].plot(q, np.cumsum(dev), color=SC[s], lw=2, label=s)
for a, t, yl in [(axes[1], "(나) 충격: oil_g 편차", "분기 성장률 편차(100·Δln)"), (axes[2], "(다) 수준차: 편차 누적합", "S - S1(100·ln)")]:
a.axhline(0, color="#9aa3ad", lw=0.8); a.set_xlabel("2026Q1 이후 분기", color=MUTED); a.set_ylabel(yl, color=MUTED)
a.grid(alpha=.25); a.spines[["top", "right"]].set_visible(False); a.legend(frameon=False, fontsize=8); a.set_title(t, loc="left", color=INK)
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig2_oil_paths.png"), dpi=150)
표 3. 유가의 실질부가가치 순효과(2035년, S1) — 총량 모형과 62 바텀업¶
oil_cmp.to_csv(os.path.join(C.OUTPUT, "table3_oil_effect.csv"), encoding="utf-8-sig")
oil_cmp.style.format({c: "{:,.0f}" for c in ["2025(조원)", "2035(조원)", "유가 고정 2035(조원)"]} |
{"유가 효과(조원)": "{:+,.1f}", "유가 효과(%)": "{:+.2f}", "CAGR(%)": "{:.2f}", "유가 고정 CAGR(%)": "{:.2f}", "CAGR 기여(%p)": "{:+.3f}"})
| 2025(조원) | 2035(조원) | 유가 고정 2035(조원) | 유가 효과(조원) | 유가 효과(%) | CAGR(%) | 유가 고정 CAGR(%) | CAGR 기여(%p) | |
|---|---|---|---|---|---|---|---|---|
| 모형 | ||||||||
| 총량 예측모형 | 2,326 | 2,970 | 2,956 | +14.6 | +0.49 | 2.47 | 2.42 | +0.050 |
| 62 바텀업 | 2,178 | 3,507 | 3,442 | +65.5 | +1.87 | 4.88 | 4.68 | +0.197 |
표 4. 유가에 가장 민감한 산업 — 36·62·69분류(10년 로그성장 기여, %p)¶
rows = []
for r in ("36", "62", "69"):
g = orank[orank["분류"] == r]
top = g[g["|기여| 최대"]].iloc[0]
plus = g[(g["구분"] == "상위(+)") & ~g["|기여| 최대"]].head(3)
minus = g[g["구분"] == "하위(−)"].head(3)
rows.append({"분류": r, "유가 영향 1위": top["산업"], "기여(%p)": top["유가 기여(%p)"],
"수혜(+) 상위 3": " · ".join(f"{a}({v:+.1f})" for a, v in zip(plus["산업"], plus["유가 기여(%p)"])),
"피해(−) 상위 3": " · ".join(f"{a}({v:+.1f})" for a, v in zip(minus["산업"], minus["유가 기여(%p)"]))})
t4 = pd.DataFrame(rows).set_index("분류")
t4.to_csv(os.path.join(C.OUTPUT, "table4_oil_sensitive.csv"), encoding="utf-8-sig")
t4.style.format({"기여(%p)": "{:+.2f}"})
| 유가 영향 1위 | 기여(%p) | 수혜(+) 상위 3 | 피해(−) 상위 3 | |
|---|---|---|---|---|
| 분류 | ||||
| 36 | 코크스 및 석유정제품 제조업 | +41.06 | 기계 및 장비 제조업(+14.0) · 예술, 스포츠 및 여가관련 서비스업(+12.1) · 운송장비 제조업(+10.8) | 주거용 건물 건설업(-6.1) · 토목건설업(-6.0) · 통신업(-4.7) |
| 62 | 14.석탄ㆍ석유제품 | +31.36 | 25.기타기계ㆍ장비(+11.3) · 59.문화서비스업(+11.2) · 27.기타 운송장비(+10.8) | 43.통신업(-4.4) · 29.전기ㆍ가스ㆍ증기ㆍ공기조절공급업(-4.0) · 33.건설업(-3.9) |
| 69 | 14.석탄ㆍ석유제품 | +30.83 | 이차전지(+15.8) · 25.기타기계ㆍ장비(+12.0) · 27.기타 운송장비(잔여)(+10.7) | 토목건설(-5.1) · 건물건설건축보수(-4.8) · 43.통신업(-4.2) |
그림 3. 62개 산업의 유가 기여(S1, 10년 로그성장 %p) — 상·하위 10개¶
s = SH["62"]["유가"].sort_values()
s = pd.concat([s.head(10), s.tail(10)])
fig, ax = plt.subplots(figsize=(8, 6.2))
ax.barh(range(len(s)), s.values, color=[S1C if v > 0 else S2C for v in s.values], height=0.7)
ax.set_yticks(range(len(s)), [i.split(".", 1)[1] for i in s.index], fontsize=8, color=INK)
for i, v in enumerate(s.values):
ax.text(v + (0.4 if v > 0 else -0.4), i, f"{v:+.1f}", va="center", ha="left" if v > 0 else "right", fontsize=7.5, color=MUTED)
ax.axvline(0, color="#9aa3ad", lw=0.8)
ax.set_xlim(s.min() - 3, s.max() + 4)
ax.set_xlabel("유가 기여(10년 로그성장, %p) — 파랑: 상승 기여, 주황: 하락 기여", color=MUTED)
ax.grid(axis="x", alpha=.25); ax.spines[["top", "right"]].set_visible(False)
ax.set_title("62분류 산업별 유가 기여(선형 SHAP, S1)", loc="left", color=INK)
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig3_oil_shap_62.png"), dpi=150)
표 5. 유가 과거값의 원천별 결과 — 공표 입력·FRED 두바이·FRED WTI¶
공표 입력의 유가 과거값은 두바이유와 일치하므로 첫째·둘째 행이 같다. 셋째 행은 문서상 정의(WTI)대로 추정했을 때의 결과이다.
var.to_csv(os.path.join(C.OUTPUT, "table5_oil_source.csv"), encoding="utf-8-sig")
var.style.format("{:,.2f}")
| 총량 2035(조원) | 총량 유가효과(조원) | 총량 유가효과(%) | 62 2035(조원) | 62 유가효과(조원) | 62 유가효과(%) | 62 실질금리효과(조원) | 석유제품 유가 SHAP(%p) | |
|---|---|---|---|---|---|---|---|---|
| 유가 과거값 | ||||||||
| 공표 입력(exog_hist) | 2,970.38 | 14.60 | 0.49 | 3,507.00 | 65.47 | 1.87 | 354.21 | 31.36 |
| FRED 두바이 100·Δln | 2,970.38 | 14.60 | 0.49 | 3,507.00 | 65.47 | 1.87 | 354.21 | 31.36 |
| FRED WTI 100·Δln | 2,923.70 | 5.73 | 0.20 | 3,511.48 | 57.11 | 1.63 | 342.82 | 34.71 |
표 6. 두바이유 교체 시산(축약 OLS, 원 시산 재현)¶
t6 = dub.copy()
t6.to_csv(os.path.join(C.OUTPUT, "table6_dubai.csv"), encoding="utf-8-sig")
print(f"로그차분 상관 corr(ΔWTI, Δ두바이): 원 시산 표본 {bm.loc['원 시산 표본(파일 전체)', 'corr']:.4f} "
f"({bm.loc['원 시산 표본(파일 전체)', '첫분기']}–{bm.loc['원 시산 표본(파일 전체)', '끝분기']}) · "
f"2000Q1–2025Q4 {bm.loc['2000Q1–2025Q4', 'corr']:.4f}")
t6.style.format({"WTI계수": "{:.3f}", "DUB계수": "{:.3f}", "WTI기여": "{:+.1f}", "DUB기여": "{:+.1f}", "변화": "{:+.1f}"})
로그차분 상관 corr(ΔWTI, Δ두바이): 원 시산 표본 0.9540 (2000Q1–2026Q3) · 2000Q1–2025Q4 0.9610
| WTI계수 | DUB계수 | WTI기여 | DUB기여 | 변화 | |
|---|---|---|---|---|---|
| 산업 | |||||
| 14.석탄ㆍ석유제품 | 0.290 | 0.308 | +24.9 | +26.5 | +1.6 |
| 25.기타기계ㆍ장비 | 0.104 | 0.109 | +8.9 | +9.3 | +0.4 |
| 27.기타 운송장비 | 0.085 | 0.086 | +7.3 | +7.4 | +0.1 |
| 33.건설업 | -0.012 | -0.003 | -1.0 | -0.3 | +0.7 |
| 43.통신업 | -0.001 | -0.010 | -0.1 | -0.9 | -0.8 |
| 46.금융업 | 0.016 | 0.011 | +1.4 | +0.9 | -0.5 |
공표 문구 점검 — 정정·쟁점¶
카드 본문의 서술 가운데 계산과 맞지 않거나 근거가 달라진 항목이다. 아래 검증 셀에는 계산과 일치하는 공표 수치만 넣고, 이 표의 '불일치'·'쟁점' 항목은 README의 정정 기록에 같은 내용으로 적었다.
e = eff
rr_tot, rr_bu = e.loc["실질금리", "총량_효과_조원"] / e.loc["유가", "총량_효과_조원"], e.loc["실질금리", "바텀업_효과_조원"] / e.loc["유가", "바텀업_효과_조원"]
amp_oil, amp_rr = e.loc["유가", "바텀업_효과_조원"] / e.loc["유가", "총량_효과_조원"], e.loc["실질금리", "바텀업_효과_조원"] / e.loc["실질금리", "총량_효과_조원"]
g36 = orank[(orank["분류"] == "36") & (orank["구분"] == "상위(+)")]
g69 = orank[(orank["분류"] == "69") & (orank["구분"] == "하위(−)")]
b_full, b_25 = bm.loc["원 시산 표본(파일 전체)"], bm.loc["2000Q1–2025Q4"]
claims = pd.DataFrame([
("유가 원천(유가 카드 ①·각주, 그림 축)", "유가 = LOIL_us = FRED POILWTIUSDM(WTI)",
f"VARX 유가 과거값 = 100·ln(두바이유), 최대 차이 {src_chk.loc['VARX 유가 − 100·ln(두바이)', '최대 |차이|']:.4f}; WTI와는 {src_chk.loc['VARX 유가 − 100·ln(WTI)', '최소']:+.1f}~{src_chk.loc['VARX 유가 − 100·ln(WTI)', '최대']:+.1f}(100·ln) 차이",
"불일치(정정)"),
("두바이유 교체 권고(유가 카드 ⑧-5)", "POILWTIUSDM → POILDUBUSDM 한 줄 교체",
f"추정 입력이 이미 두바이유이다. WTI로 추정하면 총량 유가효과 {var.iloc[0]['총량 유가효과(조원)']:+.1f} → {var.iloc[2]['총량 유가효과(조원)']:+.1f}조원",
"전제 불성립(정정)"),
("유가 과거 수준(유가 카드 ② 부제)", "2008년 $109 → 2025년 $69",
f"연평균 2008년 ${dollars.loc[2008, 'S1']:.1f}, $109는 2012년(${dollars.loc[2012, 'S1']:.1f}); 2025년 ${dollars.loc[2025, 'S1']:.1f}", "불일치(연도 표기)"),
("바텀업 증폭(외생 카드 ⑤)", "유가·실질금리는 바텀업이 총량의 약 2배(유가 65 vs 15조)",
f"실질금리 {amp_rr:.1f}배, 유가 {amp_oil:.1f}배", "유가 부분 불일치"),
("바텀업 증폭(유가 카드 ④)", "바텀업이 유가 효과를 약 4배 증폭", f"{amp_oil:.2f}배", "부합"),
("실질금리 대 유가(외생 카드 ②)", "실질금리가 유가의 열 배", f"총량 {rr_tot:.1f}배, 바텀업 {rr_bu:.1f}배", "총량 기준 부합"),
("WTI·두바이 상관(유가 카드 ⑥)", "로그성장 상관 0.954",
f"{b_full['corr']:.4f}({b_full['첫분기']}–{b_full['끝분기']}, 끝 분기는 7월 한 달); 원 출력 표기 기간 2000Q1–2025Q4로는 {b_25['corr']:.4f}",
"값 재현, 기간 표기 쟁점"),
("스프레드(유가 카드 ⑥)", "최근 스프레드 약 $3",
f"2026년 7월 WTI ${b_full['WTI_$']:.1f} − 두바이 ${b_full['DUB_$']:.1f} = ${b_full['WTI_$'] - b_full['DUB_$']:.1f}; 2025Q4는 두바이가 ${b_25['DUB_$'] - b_25['WTI_$']:.1f} 높음",
"시점 의존(쟁점)"),
("36 수혜(+) 산업(유가 카드 ③)", "기계·운송·전기장비",
"상위(+) 2–5위: " + " · ".join(f"{a}({v:+.1f})" for a, v in zip(g36["산업"].iloc[1:], g36["유가 기여(%p)"].iloc[1:])), "선택 표기(예술·스포츠 생략)"),
("69 피해(−) 산업(유가 카드 ③)", "토목·통신·전기가스",
"하위(−) 1–4위: " + " · ".join(f"{a}({v:+.1f})" for a, v in zip(g69["산업"].iloc[:4], g69["유가 기여(%p)"].iloc[:4])), "선택 표기(건물건설 생략)"),
("69 이차전지(유가 카드 ③)", "모산업(전기장비) 계수를 IO 몫으로 물려받은 결과",
f"별도 방정식으로 추정; 유가 기여 {bat.loc['이차전지', '유가 기여(%p)']:+.1f} vs 전기장비(잔여) {bat.loc['24.전기장비(잔여)', '유가 기여(%p)']:+.1f}, 분기 성장률 상관 {bat.loc['24.전기장비(잔여)', '분기 성장률 상관(이차전지와)']:.2f}",
"근거 미확인(쟁점)"),
("실질금리 비중(외생 카드 ②)", "실질금리 하나가 바텀업 성장(연 4.88%)의 약 1/4",
f"{e.loc['실질금리', '바텀업_CAGR기여_%p']:.2f} / {tot.loc['62', 'CAGR(%)']:.2f} = {e.loc['실질금리', '바텀업_CAGR기여_%p'] / tot.loc['62', 'CAGR(%)']:.2f}", "부합"),
], columns=["항목", "공표 문구", "계산 결과", "판정"])
claims.to_csv(os.path.join(C.OUTPUT, "claims_check.csv"), index=False, encoding="utf-8-sig")
claims.style.hide(axis="index")
| 항목 | 공표 문구 | 계산 결과 | 판정 |
|---|---|---|---|
| 유가 원천(유가 카드 ①·각주, 그림 축) | 유가 = LOIL_us = FRED POILWTIUSDM(WTI) | VARX 유가 과거값 = 100·ln(두바이유), 최대 차이 0.0001; WTI와는 -30.3~+19.6(100·ln) 차이 | 불일치(정정) |
| 두바이유 교체 권고(유가 카드 ⑧-5) | POILWTIUSDM → POILDUBUSDM 한 줄 교체 | 추정 입력이 이미 두바이유이다. WTI로 추정하면 총량 유가효과 +14.6 → +5.7조원 | 전제 불성립(정정) |
| 유가 과거 수준(유가 카드 ② 부제) | 2008년 $109 → 2025년 $69 | 연평균 2008년 $89.1, $109는 2012년($109.0); 2025년 $69.2 | 불일치(연도 표기) |
| 바텀업 증폭(외생 카드 ⑤) | 유가·실질금리는 바텀업이 총량의 약 2배(유가 65 vs 15조) | 실질금리 2.2배, 유가 4.5배 | 유가 부분 불일치 |
| 바텀업 증폭(유가 카드 ④) | 바텀업이 유가 효과를 약 4배 증폭 | 4.49배 | 부합 |
| 실질금리 대 유가(외생 카드 ②) | 실질금리가 유가의 열 배 | 총량 11.1배, 바텀업 5.4배 | 총량 기준 부합 |
| WTI·두바이 상관(유가 카드 ⑥) | 로그성장 상관 0.954 | 0.9540(2000Q1–2026Q3, 끝 분기는 7월 한 달); 원 출력 표기 기간 2000Q1–2025Q4로는 0.9610 | 값 재현, 기간 표기 쟁점 |
| 스프레드(유가 카드 ⑥) | 최근 스프레드 약 $3 | 2026년 7월 WTI $79.7 − 두바이 $77.1 = $2.6; 2025Q4는 두바이가 $3.9 높음 | 시점 의존(쟁점) |
| 36 수혜(+) 산업(유가 카드 ③) | 기계·운송·전기장비 | 상위(+) 2–5위: 기계 및 장비 제조업(+14.0) · 예술, 스포츠 및 여가관련 서비스업(+12.1) · 운송장비 제조업(+10.8) · 전기장비 제조업(+9.9) | 선택 표기(예술·스포츠 생략) |
| 69 피해(−) 산업(유가 카드 ③) | 토목·통신·전기가스 | 하위(−) 1–4위: 토목건설(-5.1) · 건물건설건축보수(-4.8) · 43.통신업(-4.2) · 29.전기ㆍ가스ㆍ증기ㆍ공기조절공급업(잔여)(-3.8) | 선택 표기(건물건설 생략) |
| 69 이차전지(유가 카드 ③) | 모산업(전기장비) 계수를 IO 몫으로 물려받은 결과 | 별도 방정식으로 추정; 유가 기여 +15.8 vs 전기장비(잔여) +10.0, 분기 성장률 상관 0.12 | 근거 미확인(쟁점) |
| 실질금리 비중(외생 카드 ②) | 실질금리 하나가 바텀업 성장(연 4.88%)의 약 1/4 | 1.11 / 4.88 = 0.23 | 부합 |
표 7. 정비 전후의 외생 기여(참고, 검증 대상 아님)¶
02 9절의 결과이다. 2035년 S1 순효과(조 원)로, 이전 판은 공표 진단(표 1)과 같고 정비판은 2026-10 정비 외생으로 다시 계산한 값이다.
t7 = pd.read_csv(os.path.join(C.OUTPUT, "exog_effects_before_after.csv"), header=[0, 1], index_col=0, encoding="utf-8-sig")
t7.style.format("{:+.1f}")
| 이전 판 | 정비판 | |||
|---|---|---|---|---|
| 총량_효과_조원 | 바텀업_효과_조원 | 총량_효과_조원 | 바텀업_효과_조원 | |
| 외생 | ||||
| 유가 | +14.6 | +65.5 | +1.1 | +4.7 |
| 세계수요 | +1.6 | -12.0 | +3.2 | -1.3 |
| 실질금리 | +162.5 | +354.2 | +0.4 | +1.4 |
| 실질환율 | +4.8 | +9.9 | -4.5 | -13.2 |
| 고용_취업자 | +62.3 | +31.8 | -0.9 | -0.1 |
| 우리경기 | -0.8 | +7.6 | -3.5 | +0.6 |
표 8. 정비판 선형 SHAP 요약 — 36·62·69분류(S1, 10년 로그성장 기여 %p)¶
02 10절의 결과이다. 정비판은 정비 외생(실질금리 1차 차분 등)과 드리프트 재설정 계수로 분해하였고, 이전 판은 4절(표 4·그림 3의 근거)이다. 평균 절대 기여는 산업별 기여의 절댓값 평균이며, 외생은 여섯 외생 기여의 절댓값 합의 산업 평균이다.
ancj = rd("drift_anchor_jeongbi.csv", index_col=0)
scj = rd("shap_check_jeongbi.csv", index_col=0, dtype={"분류": str})
ssj = rd("shap_summary_jeongbi.csv", index_col=[0, 1], dtype={"분류": str})
orj = rd("oil_rank_jeongbi.csv", dtype={"분류": str})
ofj = rd("oil_factor_jeongbi.csv", index_col=0, dtype={"분류": str})
svj = rd("oil_shap_vs_cf_62_jeongbi.csv", index_col=0)
ocj = rd("oil_effect_compare_jeongbi.csv", index_col=0)
SHJ = {r: rd(f"shap_{r}_jeongbi.csv", index_col=0) for r in ("36", "62", "69")}
t8 = ssj.unstack("판").swaplevel(axis=1)[["이전 판", "정비판"]]
t8.insert(0, ("정비판", "δ(연 %p)"), ancj.loc[["36", "62", "69"], "δ(연 %p)"].values)
t8.to_csv(os.path.join(C.OUTPUT, "table8_shap_jeongbi.csv"), encoding="utf-8-sig")
print(f"62분류 정비판 분해 = 5장 분해(전망 갱신 카드): 최대 |차이| {scj.loc['62', '(라) 5장 기록과 최대 |차이|']:.1e}")
t8.style.format("{:.2f}")
62분류 정비판 분해 = 5장 분해(전망 갱신 카드): 최대 |차이| 1.4e-14
| 판 | 정비판 | 이전 판 | 정비판 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| δ(연 %p) | 합계 산업 평균 | 과거추세 | 산업 동학 | 외생(6종 절댓값 합) | 실질금리 최대 |기여| | 유가 최대 |기여| | 합계 산업 평균 | 과거추세 | 산업 동학 | 외생(6종 절댓값 합) | 실질금리 최대 |기여| | 유가 최대 |기여| | |
| 분류 | |||||||||||||
| 36 | 1.52 | 29.08 | 24.61 | 8.27 | 34.62 | 56.84 | 41.06 | 4.14 | 21.04 | 5.00 | 3.88 | 0.25 | 8.47 |
| 62 | 1.52 | 34.79 | 29.02 | 18.61 | 33.42 | 53.81 | 31.36 | 10.37 | 23.53 | 14.21 | 3.30 | 0.16 | 6.21 |
| 69 | 1.52 | 37.15 | 30.76 | 22.48 | 33.23 | 54.02 | 30.83 | 12.57 | 25.75 | 15.74 | 3.39 | 0.16 | 6.08 |
표 9. 정비판 유가에 가장 민감한 산업 — 36·62·69분류(10년 로그성장 기여, %p)¶
rows = []
for r in ("36", "62", "69"):
g = orj[orj["분류"] == r]
top = g[g["|기여| 최대"]].iloc[0]
plus = g[(g["구분"] == "상위(+)") & ~g["|기여| 최대"]].head(3)
minus = g[g["구분"] == "하위(−)"].head(3)
rows.append({"분류": r, "유가 영향 1위": top["산업"], "기여(%p)": top["유가 기여(%p)"], "이전 판 기여(%p)": ofj.loc[r, "이전 판 유가 기여(%p)"],
"수혜(+) 상위 3": " · ".join(f"{a}({v:+.2f})" for a, v in zip(plus["산업"], plus["유가 기여(%p)"])),
"피해(−) 상위 3": " · ".join(f"{a}({v:+.2f})" for a, v in zip(minus["산업"], minus["유가 기여(%p)"]))})
t9 = pd.DataFrame(rows).set_index("분류")
t9.to_csv(os.path.join(C.OUTPUT, "table9_oil_sensitive_jeongbi.csv"), encoding="utf-8-sig")
r0 = ofj.loc["62"]
print(f"S1 유가 누적 변화(100·ln) {r0['이전 판 유가 누적(100·ln)']:.2f} → {r0['정비판 유가 누적(100·ln)']:.2f}, "
f"석유제품(62) 유가 계수 합 {r0['이전 판 유가 계수 합']:.3f} → {r0['정비판 유가 계수 합']:.3f}")
t9.style.format({"기여(%p)": "{:+.2f}", "이전 판 기여(%p)": "{:+.2f}"})
S1 유가 누적 변화(100·ln) 98.05 → 22.43, 석유제품(62) 유가 계수 합 0.337 → 0.339
| 유가 영향 1위 | 기여(%p) | 이전 판 기여(%p) | 수혜(+) 상위 3 | 피해(−) 상위 3 | |
|---|---|---|---|---|---|
| 분류 | |||||
| 36 | 코크스 및 석유정제품 제조업 | +8.47 | +41.06 | 기계 및 장비 제조업(+2.69) · 예술, 스포츠 및 여가관련 서비스업(+2.31) · 운송장비 제조업(+2.25) | 토목건설업(-1.31) · 통신업(-0.92) · 주거용 건물 건설업(-0.81) |
| 62 | 14.석탄ㆍ석유제품 | +6.21 | +31.36 | 25.기타기계ㆍ장비(+2.28) · 27.기타 운송장비(+2.17) · 26.자동차(+1.95) | 43.통신업(-0.90) · 52.사업관련전문서비스업(-0.83) · 53.과학기술관련전문서비스업(-0.68) |
| 69 | 14.석탄ㆍ석유제품 | +6.08 | +30.83 | 25.기타기계ㆍ장비(+2.43) · 이차전지(+2.26) · 27.기타 운송장비(잔여)(+2.14) | 43.통신업(-0.87) · 52.사업관련전문서비스업(-0.87) · 토목건설(-0.76) |
그림 4. 62개 산업의 유가 기여 — 정비판(S1, 10년 로그성장 %p, 상·하위 10개)¶
s = SHJ["62"]["유가"].sort_values()
s = pd.concat([s.head(10), s.tail(10)])
fig, ax = plt.subplots(figsize=(8, 6.2))
ax.barh(range(len(s)), s.values, color=[S1C if v > 0 else S2C for v in s.values], height=0.7)
ax.set_yticks(range(len(s)), [i.split(".", 1)[1] for i in s.index], fontsize=8, color=INK)
for i, v in enumerate(s.values):
ax.text(v + (0.08 if v > 0 else -0.08), i, f"{v:+.2f}", va="center", ha="left" if v > 0 else "right", fontsize=7.5, color=MUTED)
ax.axvline(0, color="#9aa3ad", lw=0.8)
ax.set_xlim(s.min() - 0.8, s.max() + 1.0)
ax.set_xlabel("유가 기여(10년 로그성장, %p) — 파랑: 상승 기여, 주황: 하락 기여", color=MUTED)
ax.grid(axis="x", alpha=.25); ax.spines[["top", "right"]].set_visible(False)
ax.set_title("62분류 산업별 유가 기여(선형 SHAP, S1, 정비판)", loc="left", color=INK)
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig4_oil_shap_62_jeongbi.png"), dpi=150)
표 10. 정비판 유가의 실질부가가치 순효과(2035년, S1) — 총량 모형과 62 바텀업¶
반사실(유가 고정 재전망)으로 계산한다. 정비판 62 바텀업은 드리프트 재설정 모형이며, 재설정 전 모형(02 9절)과 이전 판(표 3)을 함께 둔다.
t10 = pd.concat({"정비판": ocj, "이전 판": oil_cmp})
t10.to_csv(os.path.join(C.OUTPUT, "table10_oil_effect_jeongbi.csv"), encoding="utf-8-sig")
print(f"62 유가 SHAP(직접)·반사실(총효과) 산업 간 상관: 정비판 {svj.iloc[:, 0].corr(svj.iloc[:, 1]):.3f}")
t10.style.format({c: "{:,.1f}" for c in ["2025(조원)", "2035(조원)", "유가 고정 2035(조원)"]} |
{"유가 효과(조원)": "{:+,.2f}", "유가 효과(%)": "{:+.3f}", "CAGR(%)": "{:.2f}", "유가 고정 CAGR(%)": "{:.2f}", "CAGR 기여(%p)": "{:+.4f}"})
62 유가 SHAP(직접)·반사실(총효과) 산업 간 상관: 정비판 0.898
| 2025(조원) | 2035(조원) | 유가 고정 2035(조원) | 유가 효과(조원) | 유가 효과(%) | CAGR(%) | 유가 고정 CAGR(%) | CAGR 기여(%p) | ||
|---|---|---|---|---|---|---|---|---|---|
| 모형 | |||||||||
| 정비판 | 총량 예측모형 | 2,326.3 | 2,671.4 | 2,670.3 | +1.07 | +0.040 | 1.39 | 1.39 | +0.0041 |
| 62 바텀업(드리프트 재설정) | 2,178.5 | 2,793.7 | 2,789.8 | +3.97 | +0.142 | 2.52 | 2.50 | +0.0146 | |
| 62 바텀업(재설정 전, 9절) | 2,178.5 | 3,223.4 | 3,218.7 | +4.67 | +0.145 | 4.00 | 3.98 | +0.0151 | |
| 이전 판 | 총량 예측모형 | 2,326.3 | 2,970.4 | 2,955.8 | +14.60 | +0.491 | 2.47 | 2.42 | +0.0505 |
| 62 바텀업 | 2,178.5 | 3,507.0 | 3,441.5 | +65.47 | +1.867 | 4.88 | 4.68 | +0.1975 |
표 11. 정비판 시나리오 폭(max−min, 연평균)과 유가 경로 — 2026년과 2035년¶
per_j = rd("exog_persistence_jeongbi.csv", index_col=0)
dol_j = rd("oil_dollar_paths_jeongbi.csv", index_col=0)
pth_j = rd("exog_paths_summary_jeongbi.csv", index_col=0)
t11 = per_j.join(per[["폭_2026", "폭_2035", "판정"]].add_prefix("이전 판 "))
t11.index = [NAME[k] for k in t11.index]
t11.to_csv(os.path.join(C.OUTPUT, "table11_persistence_jeongbi.csv"), encoding="utf-8-sig")
display(t11.style.format({"폭_2026": "{:,.2f}", "폭_2035": "{:,.3f}", "이전 판 폭_2026": "{:,.2f}", "이전 판 폭_2035": "{:,.3f}"}))
pd.concat({"정비판": dol_j.loc[[2025, 2030, 2035]], "이전 판": dollars.loc[[2025, 2030, 2035]]}, axis=1).style.format("{:.1f}")
| 폭_2026 | 폭_2035 | 판정 | 이전 판 폭_2026 | 이전 판 폭_2035 | 이전 판 판정 | |
|---|---|---|---|---|---|---|
| 유가 | 25.16 | 51.750 | 영구 | 25.16 | 51.750 | 영구 |
| 세계수요 | 1.79 | 0.000 | 일시 | 1.79 | 0.000 | 일시 |
| 실질금리 | 5.63 | 0.000 | 일시 | 4.80 | 0.000 | 일시 |
| 실질환율 | 13.65 | 0.004 | 일시 | 11.87 | 0.004 | 일시 |
| 고용(취업자) | 681.87 | 943.421 | 영구 | 531.61 | 8.630 | 일시 |
| 우리경기 | 3.44 | 0.000 | 일시 | 2.94 | 0.000 | 일시 |
| 정비판 | 이전 판 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| S1 | S2 | S3 | S4 | S5 | S1 | S2 | S3 | S4 | S5 | |
| 연도 | ||||||||||
| 2025 | 69.2 | 69.2 | 69.2 | 69.2 | 69.2 | 69.2 | 69.2 | 69.2 | 69.2 | 69.2 |
| 2030 | 70.4 | 58.8 | 65.8 | 70.4 | 98.6 | 99.7 | 83.3 | 93.2 | 99.7 | 139.7 |
| 2035 | 78.9 | 65.9 | 73.8 | 78.9 | 110.6 | 163.4 | 136.5 | 152.7 | 163.4 | 228.9 |
검증 — 공표 수치와 대조¶
외생 카드의 표·본문 수치, 유가 카드의 표·본문 수치, 공표 SHAP 산출물(shap_36/62/69.json)을 계산 결과와 대조한다(이전 판).
이어서 정비판(02 10절)의 분해 점검, 5장 기록(62분류 분해·드리프트 재설정 δ·바텀업 연평균)과의 대조, 정비판 진단 기록 수치(config.JEONGBI)를 대조한다.
허용오차는 공표·기록 자릿수의 반올림 폭이다(정수 조원 ±0.5, 소수 둘째 자리 ±0.005 등). 범주 항목은 일치 여부를 본다.
P = C.PUBLISHED
norm = lambda s: str(s).replace(" ", "").replace("·", "").replace("ㆍ", "").replace("및", "") # noqa: E731
checks = []
def num(item, calc, pub, tol):
checks.append({"항목": item, "계산": round(float(calc), 6), "공표": pub, "허용오차": f"±{tol:g}", "통과": abs(float(calc) - pub) <= tol + 1e-12})
def same(item, calc, pub, how="일치"):
ok = (norm(pub) in norm(calc)) if how == "포함" else (calc == pub)
checks.append({"항목": item, "계산": calc, "공표": pub, "허용오차": how, "통과": bool(ok)})
def le(item, calc, pub):
checks.append({"항목": item, "계산": round(float(calc), 6), "공표": pub, "허용오차": "이하", "통과": float(calc) <= pub})
for k in F.EXOG:
num(f"[외생] 총량 순효과 {NAME[k]}(조원)", eff.loc[k, "총량_효과_조원"], P["총량_조원"][k], 0.5)
for k in F.EXOG:
num(f"[외생] 총량 CAGR 기여 {NAME[k]}(%p)", eff.loc[k, "총량_CAGR기여_%p"], P["총량_%p"][k], 0.005)
for k in F.EXOG:
num(f"[외생] 바텀업 순효과 {NAME[k]}(조원)", eff.loc[k, "바텀업_효과_조원"], P["바텀업_조원"][k], 0.5)
for k in F.EXOG:
num(f"[외생] 바텀업 CAGR 기여 {NAME[k]}(%p)", eff.loc[k, "바텀업_CAGR기여_%p"], P["바텀업_%p"][k], 0.005)
same("[외생] 지배 변수(총량·바텀업 모두 1위)",
eff["총량_효과_조원"].abs().idxmax() if eff["총량_효과_조원"].abs().idxmax() == eff["바텀업_효과_조원"].abs().idxmax() else "불일치", P["지배_외생"])
same("[외생] 총량 CAGR 기여 순위", " > ".join(eff.sort_values("총량_CAGR기여_%p", ascending=False).index), " > ".join(P["총량_순위"]))
num("[외생] 실질금리 2025 연평균(%)", paths.loc["실질금리", "2025 연평균"], P["실질금리_2025"], 0.005)
num("[외생] 실질금리 2035 연평균(S1, %)", paths.loc["실질금리", "2035 연평균(S1)"], P["실질금리_2035"], 0.005)
num("[외생] 바텀업 CAGR 2025–2035(%)", tot.loc["62", "CAGR(%)"], P["바텀업_CAGR"], 0.005)
for k in ["유가", "고용_취업자", "실질환율", "실질금리", "우리경기", "세계수요"]:
num(f"[외생] 시나리오 폭 2026 {NAME[k]}", per.loc[k, "폭_2026"], P["폭_2026"][k], 0.05)
for k in ["유가", "고용_취업자", "실질금리", "우리경기", "세계수요"]:
num(f"[외생] 시나리오 폭 2035 {NAME[k]}", per.loc[k, "폭_2035"], P["폭_2035"][k], 0.05)
num("[외생] 시나리오 폭 2035 실질환율", per.loc["실질환율", "폭_2035"], P["폭_2035"]["실질환율"], 0.0005)
same("[외생] 영구 수준차 외생", " · ".join(per.index[per["판정"] == "영구"]), P["영구_외생"])
o_agg, o_bu = oil_cmp.loc["총량 예측모형"], oil_cmp.loc["62 바텀업"]
num("[유가] 총량 2035(조원)", o_agg["2035(조원)"], P["총량_2035_조"], 0.5)
num("[유가] 총량 유가 고정 2035(조원)", o_agg["유가 고정 2035(조원)"], P["총량_유가없음_조"], 0.5)
num("[유가] 총량 유가 효과(%)", o_agg["유가 효과(%)"], P["총량_유가효과_%"], 0.05)
num("[유가] 총량 CAGR 기여(%p)", o_agg["CAGR 기여(%p)"], P["총량_유가_%p"], 0.005)
num("[유가] 바텀업 2035(조원)", o_bu["2035(조원)"], P["바텀업_2035_조"], 0.5)
num("[유가] 바텀업 유가 고정 2035(조원)", o_bu["유가 고정 2035(조원)"], P["바텀업_유가없음_조"], 0.5)
num("[유가] 바텀업 유가 효과(%)", o_bu["유가 효과(%)"], P["바텀업_유가효과_%"], 0.05)
num("[유가] 바텀업 CAGR 기여(%p)", o_bu["CAGR 기여(%p)"], P["바텀업_유가_%p"], 0.005)
for r in ("36", "62", "69"):
g = orank[(orank["분류"] == r) & orank["|기여| 최대"]].iloc[0]
same(f"[유가] {r}분류 유가 영향 1위 산업", g["산업"], P["유가1위"][r][0], "포함")
num(f"[유가] {r}분류 1위 기여(%p)", g["유가 기여(%p)"], P["유가1위"][r][1], 0.05)
num("[유가] 2025 연평균($/배럴)", dollars.loc[2025, "S1"], P["유가_2025_$"], 0.5)
num("[유가] S1 2035 연평균($/배럴)", dollars.loc[2035, "S1"], P["유가_S1_2035_$"], 0.5)
num("[유가] 2035 시나리오 최저($/배럴)", dollars.loc[2035].min(), P["유가_2035_최저_$"], 0.5)
num("[유가] 2035 시나리오 최고($/배럴)", dollars.loc[2035].max(), P["유가_2035_최고_$"], 0.5)
num("[두바이] WTI·두바이 로그차분 상관(원 시산 표본)", bm.loc["원 시산 표본(파일 전체)", "corr"], P["WTI_두바이_상관"], 0.0005)
num("[두바이] 최근 스프레드($, 2026-07)", bm.loc["원 시산 표본(파일 전체)", "WTI_$"] - bm.loc["원 시산 표본(파일 전체)", "DUB_$"], P["스프레드_$"], 0.5)
num("[두바이] 석유제품 기여 변화(%p)", dub.loc["14.석탄ㆍ석유제품", "변화"], P["정유_변화_%p"], 0.05)
le("[두바이] 나머지 5개 산업 |변화| 최대(%p)", dub.drop(index="14.석탄ㆍ석유제품")["변화"].abs().max(), P["나머지_변화_한도_%p"])
for r in ("36", "62", "69"):
num(f"[SHAP] shap_{r}.json {int(shap_chk.loc[int(r), '공표 대조 값 수'])}개 값 최대 |차이|", shap_chk.loc[int(r), "반올림 전 최대 |차이|"], 0.0, 0.005)
n_prev = len(checks)
# 정비판(02 10절): 5장 기록과의 대조, 정비판 진단 기록 수치(C.JEONGBI)
J = C.JEONGBI
da5 = pd.read_csv(C.S5_DRIFT, index_col=0, encoding="utf-8-sig")
da5.index = da5.index.astype(str)
for r in ("36", "62", "69"):
le(f"[정비판] {r}분류 SHAP 점검 (가)–(다) 최대 오차", scj.loc[r, ["(가) 성분 합 − 합계", "(나) 합계 − 전망 로그성장", "(다) 재설정분 − (−10(1−ΣA)δ)"]].max(), 1e-8)
le("[정비판] 62분류 SHAP − 5장 분해(shap_62_s5.csv) 최대 |차이|", scj.loc["62", "(라) 5장 기록과 최대 |차이|"], 1e-8)
for r in ("36", "62", "69"):
num(f"[정비판] {r}분류 δ(연 %p) — 5장 drift_anchor", ancj.loc[r, "δ(연 %p)"], float(da5.loc[r, "δ(연 %p)"]), 1e-9)
num(f"[정비판] {r}분류 바텀업 S1 연평균(%) — 5장 drift_anchor", ancj.loc[r, "S1 연평균 재설정 후(%)"], float(da5.loc[r, "바텀업 S1 연평균 — 재설정 후(%)"]), 1e-6)
num("[정비판] S1 유가 누적 변화 2025Q4→2035Q4(100·ln)", ofj.loc["62", "정비판 유가 누적(100·ln)"], J["유가_누적_S1"], 0.005)
for r in ("36", "62", "69"):
g = orj[(orj["분류"] == r) & orj["|기여| 최대"]].iloc[0]
same(f"[정비판] {r}분류 유가 영향 1위 산업", g["산업"], J["유가1위"][r][0], "포함")
num(f"[정비판] {r}분류 1위 유가 기여(%p)", g["유가 기여(%p)"], J["유가1위"][r][1], 0.005)
for c, key in (("과거추세", "과거추세"), ("산업 동학", "산업 동학"), ("외생(6종 절댓값 합)", "외생")):
num(f"[정비판] {r}분류 평균 절대 기여 {key}(%p)", ssj.loc[(r, "정비판"), c], J["평균절대"][r][key], 0.005)
num(f"[정비판] {r}분류 실질금리 최대 |기여|(%p)", ssj.loc[(r, "정비판"), "실질금리 최대 |기여|"], J["실질금리_최대절대"][r], 0.005)
num("[정비판] 62 유가 SHAP·반사실 산업 간 상관", svj.iloc[:, 0].corr(svj.iloc[:, 1]), J["유가_SHAP_반사실_상관"], 0.0005)
o_agg_j, o_bu_j = ocj.loc["총량 예측모형"], ocj.loc["62 바텀업(드리프트 재설정)"]
for tag, o in (("총량", o_agg_j), ("바텀업", o_bu_j)):
num(f"[정비판] {tag} 2035(조원)", o["2035(조원)"], J[f"{tag}_2035_조"], 0.005)
num(f"[정비판] {tag} 유가 효과(조원)", o["유가 효과(조원)"], J[f"{tag}_유가효과_조"], 0.005)
num(f"[정비판] {tag} 유가 효과(%)", o["유가 효과(%)"], J[f"{tag}_유가효과_%"], 0.0005)
num(f"[정비판] {tag} 유가 CAGR 기여(%p)", o["CAGR 기여(%p)"], J[f"{tag}_유가_%p"], 0.00005)
num("[정비판] 바텀업/총량 유가 효과 배율", o_bu_j["유가 효과(조원)"] / o_agg_j["유가 효과(조원)"], J["배율"], 0.005)
same("[정비판] 영구 수준차 외생(2035 시나리오 폭)", " · ".join(per_j.index[per_j["판정"] == "영구"]), J["영구_외생"])
num("[정비판] 시나리오 폭 2035 유가(100·ln)", per_j.loc["유가", "폭_2035"], J["유가_폭_2035"], 0.005)
num("[정비판] 유가 S1 2025 연평균($/배럴)", dol_j.loc[2025, "S1"], J["유가_2025_$"], 0.05)
num("[정비판] 유가 S1 2035 연평균($/배럴)", dol_j.loc[2035, "S1"], J["유가_S1_2035_$"], 0.05)
num("[정비판] 유가 2035 시나리오 최저($/배럴)", dol_j.loc[2035].min(), J["유가_2035_최저_$"], 0.05)
num("[정비판] 유가 2035 시나리오 최고($/배럴)", dol_j.loc[2035].max(), J["유가_2035_최고_$"], 0.05)
num("[정비판] 실질금리 S1 2035 연평균(%)", pth_j.loc["실질금리", "2035 연평균(S1)"], J["실질금리_2035"], 0.005)
res = pd.DataFrame(checks)
res.to_csv(os.path.join(C.OUTPUT, "verification.csv"), index=False, encoding="utf-8-sig")
with pd.option_context("display.max_rows", 200, "display.float_format", lambda v: f"{v:,.4f}"):
display(res)
assert res["통과"].all(), "공표·기록 수치와 계산 결과가 다르다 — 위 표에서 통과=False 항목을 확인한다"
print(f"검증 통과: 이전 판 공표 수치 {n_prev}개(외생 카드·유가 카드·SHAP 산출물)와 정비판 항목 {len(res) - n_prev}개"
f"(5장 분해 대조·정비판 기록 수치)를 반올림 범위 안에서 재현했다(합계 {len(res)}개).")
| 항목 | 계산 | 공표 | 허용오차 | 통과 | |
|---|---|---|---|---|---|
| 0 | [외생] 총량 순효과 유가(조원) | 14.5957 | 15 | ±0.5 | True |
| 1 | [외생] 총량 순효과 세계수요(조원) | 1.5975 | 2 | ±0.5 | True |
| 2 | [외생] 총량 순효과 실질금리(조원) | 162.4946 | 162 | ±0.5 | True |
| 3 | [외생] 총량 순효과 실질환율(조원) | 4.7973 | 5 | ±0.5 | True |
| 4 | [외생] 총량 순효과 고용(취업자)(조원) | 62.3091 | 62 | ±0.5 | True |
| 5 | [외생] 총량 순효과 우리경기(조원) | -0.8160 | -1 | ±0.5 | True |
| 6 | [외생] 총량 CAGR 기여 유가(%p) | 0.0505 | 0.0500 | ±0.005 | True |
| 7 | [외생] 총량 CAGR 기여 세계수요(%p) | 0.0055 | 0.0100 | ±0.005 | True |
| 8 | [외생] 총량 CAGR 기여 실질금리(%p) | 0.5749 | 0.5700 | ±0.005 | True |
| 9 | [외생] 총량 CAGR 기여 실질환율(%p) | 0.0166 | 0.0200 | ±0.005 | True |
| 10 | [외생] 총량 CAGR 기여 고용(취업자)(%p) | 0.2170 | 0.2200 | ±0.005 | True |
| 11 | [외생] 총량 CAGR 기여 우리경기(%p) | -0.0028 | -0.0000 | ±0.005 | True |
| 12 | [외생] 바텀업 순효과 유가(조원) | 65.4734 | 65 | ±0.5 | True |
| 13 | [외생] 바텀업 순효과 세계수요(조원) | -12.0228 | -12 | ±0.5 | True |
| 14 | [외생] 바텀업 순효과 실질금리(조원) | 354.2112 | 354 | ±0.5 | True |
| 15 | [외생] 바텀업 순효과 실질환율(조원) | 9.9489 | 10 | ±0.5 | True |
| 16 | [외생] 바텀업 순효과 고용(취업자)(조원) | 31.7926 | 32 | ±0.5 | True |
| 17 | [외생] 바텀업 순효과 우리경기(조원) | 7.6240 | 8 | ±0.5 | True |
| 18 | [외생] 바텀업 CAGR 기여 유가(%p) | 0.1975 | 0.2000 | ±0.005 | True |
| 19 | [외생] 바텀업 CAGR 기여 세계수요(%p) | -0.0359 | -0.0400 | ±0.005 | True |
| 20 | [외생] 바텀업 CAGR 기여 실질금리(%p) | 1.1107 | 1.1100 | ±0.005 | True |
| 21 | [외생] 바텀업 CAGR 기여 실질환율(%p) | 0.0298 | 0.0300 | ±0.005 | True |
| 22 | [외생] 바텀업 CAGR 기여 고용(취업자)(%p) | 0.0955 | 0.1000 | ±0.005 | True |
| 23 | [외생] 바텀업 CAGR 기여 우리경기(%p) | 0.0228 | 0.0200 | ±0.005 | True |
| 24 | [외생] 지배 변수(총량·바텀업 모두 1위) | 실질금리 | 실질금리 | 일치 | True |
| 25 | [외생] 총량 CAGR 기여 순위 | 실질금리 > 고용_취업자 > 유가 > 실질환율 > 세계수요 > 우리경기 | 실질금리 > 고용_취업자 > 유가 > 실질환율 > 세계수요 > 우리경기 | 일치 | True |
| 26 | [외생] 실질금리 2025 연평균(%) | 0.9945 | 0.9900 | ±0.005 | True |
| 27 | [외생] 실질금리 2035 연평균(S1, %) | 2.7760 | 2.7800 | ±0.005 | True |
| 28 | [외생] 바텀업 CAGR 2025–2035(%) | 4.8765 | 4.8800 | ±0.005 | True |
| 29 | [외생] 시나리오 폭 2026 유가 | 25.1560 | 25.2000 | ±0.05 | True |
| 30 | [외생] 시나리오 폭 2026 고용(취업자) | 531.6052 | 531.6000 | ±0.05 | True |
| 31 | [외생] 시나리오 폭 2026 실질환율 | 11.8690 | 11.9000 | ±0.05 | True |
| 32 | [외생] 시나리오 폭 2026 실질금리 | 4.8030 | 4.8000 | ±0.05 | True |
| 33 | [외생] 시나리오 폭 2026 우리경기 | 2.9428 | 2.9000 | ±0.05 | True |
| 34 | [외생] 시나리오 폭 2026 세계수요 | 1.7900 | 1.8000 | ±0.05 | True |
| 35 | [외생] 시나리오 폭 2035 유가 | 51.7500 | 51.8000 | ±0.05 | True |
| 36 | [외생] 시나리오 폭 2035 고용(취업자) | 8.6302 | 8.6000 | ±0.05 | True |
| 37 | [외생] 시나리오 폭 2035 실질금리 | 0.0000 | 0.0000 | ±0.05 | True |
| 38 | [외생] 시나리오 폭 2035 우리경기 | 0.0000 | 0.0000 | ±0.05 | True |
| 39 | [외생] 시나리오 폭 2035 세계수요 | 0.0000 | 0.0000 | ±0.05 | True |
| 40 | [외생] 시나리오 폭 2035 실질환율 | 0.0043 | 0.0040 | ±0.0005 | True |
| 41 | [외생] 영구 수준차 외생 | 유가 | 유가 | 일치 | True |
| 42 | [유가] 총량 2035(조원) | 2,970.3786 | 2970 | ±0.5 | True |
| 43 | [유가] 총량 유가 고정 2035(조원) | 2,955.7830 | 2956 | ±0.5 | True |
| 44 | [유가] 총량 유가 효과(%) | 0.4914 | 0.5000 | ±0.05 | True |
| 45 | [유가] 총량 CAGR 기여(%p) | 0.0505 | 0.0500 | ±0.005 | True |
| 46 | [유가] 바텀업 2035(조원) | 3,506.9957 | 3507 | ±0.5 | True |
| 47 | [유가] 바텀업 유가 고정 2035(조원) | 3,441.5224 | 3442 | ±0.5 | True |
| 48 | [유가] 바텀업 유가 효과(%) | 1.8669 | 1.9000 | ±0.05 | True |
| 49 | [유가] 바텀업 CAGR 기여(%p) | 0.1975 | 0.2000 | ±0.005 | True |
| 50 | [유가] 36분류 유가 영향 1위 산업 | 코크스 및 석유정제품 제조업 | 코크스·석유정제품 | 포함 | True |
| 51 | [유가] 36분류 1위 기여(%p) | 41.0629 | 41.1000 | ±0.05 | True |
| 52 | [유가] 62분류 유가 영향 1위 산업 | 14.석탄ㆍ석유제품 | 석탄·석유제품 | 포함 | True |
| 53 | [유가] 62분류 1위 기여(%p) | 31.3593 | 31.4000 | ±0.05 | True |
| 54 | [유가] 69분류 유가 영향 1위 산업 | 14.석탄ㆍ석유제품 | 석탄·석유제품 | 포함 | True |
| 55 | [유가] 69분류 1위 기여(%p) | 30.8334 | 30.8000 | ±0.05 | True |
| 56 | [유가] 2025 연평균($/배럴) | 69.2274 | 69 | ±0.5 | True |
| 57 | [유가] S1 2035 연평균($/배럴) | 163.3638 | 163 | ±0.5 | True |
| 58 | [유가] 2035 시나리오 최저($/배럴) | 136.4529 | 136 | ±0.5 | True |
| 59 | [유가] 2035 시나리오 최고($/배럴) | 228.9445 | 229 | ±0.5 | True |
| 60 | [두바이] WTI·두바이 로그차분 상관(원 시산 표본) | 0.9540 | 0.9540 | ±0.0005 | True |
| 61 | [두바이] 최근 스프레드($, 2026-07) | 2.5777 | 3 | ±0.5 | True |
| 62 | [두바이] 석유제품 기여 변화(%p) | 1.5852 | 1.6000 | ±0.05 | True |
| 63 | [두바이] 나머지 5개 산업 |변화| 최대(%p) | 0.7853 | 1.0000 | 이하 | True |
| 64 | [SHAP] shap_36.json 324개 값 최대 |차이| | 0.0050 | 0.0000 | ±0.005 | True |
| 65 | [SHAP] shap_62.json 558개 값 최대 |차이| | 0.0050 | 0.0000 | ±0.005 | True |
| 66 | [SHAP] shap_69.json 621개 값 최대 |차이| | 0.0050 | 0.0000 | ±0.005 | True |
| 67 | [정비판] 36분류 SHAP 점검 (가)–(다) 최대 오차 | 0.0000 | 0.0000 | 이하 | True |
| 68 | [정비판] 62분류 SHAP 점검 (가)–(다) 최대 오차 | 0.0000 | 0.0000 | 이하 | True |
| 69 | [정비판] 69분류 SHAP 점검 (가)–(다) 최대 오차 | 0.0000 | 0.0000 | 이하 | True |
| 70 | [정비판] 62분류 SHAP − 5장 분해(shap_62_s5.csv) 최대 |차이| | 0.0000 | 0.0000 | 이하 | True |
| 71 | [정비판] 36분류 δ(연 %p) — 5장 drift_anchor | 1.5240 | 1.5240 | ±1e-09 | True |
| 72 | [정비판] 36분류 바텀업 S1 연평균(%) — 5장 drift_anchor | 2.4570 | 2.4570 | ±1e-06 | True |
| 73 | [정비판] 62분류 δ(연 %p) — 5장 drift_anchor | 1.5240 | 1.5240 | ±1e-09 | True |
| 74 | [정비판] 62분류 바텀업 S1 연평균(%) — 5장 drift_anchor | 2.5187 | 2.5187 | ±1e-06 | True |
| 75 | [정비판] 69분류 δ(연 %p) — 5장 drift_anchor | 1.5240 | 1.5240 | ±1e-09 | True |
| 76 | [정비판] 69분류 바텀업 S1 연평균(%) — 5장 drift_anchor | 2.5250 | 2.5250 | ±1e-06 | True |
| 77 | [정비판] S1 유가 누적 변화 2025Q4→2035Q4(100·ln) | 22.4299 | 22.4300 | ±0.005 | True |
| 78 | [정비판] 36분류 유가 영향 1위 산업 | 코크스 및 석유정제품 제조업 | 코크스·석유정제품 | 포함 | True |
| 79 | [정비판] 36분류 1위 유가 기여(%p) | 8.4737 | 8.4700 | ±0.005 | True |
| 80 | [정비판] 36분류 평균 절대 기여 과거추세(%p) | 21.0409 | 21.0400 | ±0.005 | True |
| 81 | [정비판] 36분류 평균 절대 기여 산업 동학(%p) | 4.9958 | 5.0000 | ±0.005 | True |
| 82 | [정비판] 36분류 평균 절대 기여 외생(%p) | 3.8793 | 3.8800 | ±0.005 | True |
| 83 | [정비판] 36분류 실질금리 최대 |기여|(%p) | 0.2493 | 0.2500 | ±0.005 | True |
| 84 | [정비판] 62분류 유가 영향 1위 산업 | 14.석탄ㆍ석유제품 | 석탄·석유제품 | 포함 | True |
| 85 | [정비판] 62분류 1위 유가 기여(%p) | 6.2084 | 6.2100 | ±0.005 | True |
| 86 | [정비판] 62분류 평균 절대 기여 과거추세(%p) | 23.5288 | 23.5300 | ±0.005 | True |
| 87 | [정비판] 62분류 평균 절대 기여 산업 동학(%p) | 14.2144 | 14.2100 | ±0.005 | True |
| 88 | [정비판] 62분류 평균 절대 기여 외생(%p) | 3.2986 | 3.3000 | ±0.005 | True |
| 89 | [정비판] 62분류 실질금리 최대 |기여|(%p) | 0.1572 | 0.1600 | ±0.005 | True |
| 90 | [정비판] 69분류 유가 영향 1위 산업 | 14.석탄ㆍ석유제품 | 석탄·석유제품 | 포함 | True |
| 91 | [정비판] 69분류 1위 유가 기여(%p) | 6.0811 | 6.0800 | ±0.005 | True |
| 92 | [정비판] 69분류 평균 절대 기여 과거추세(%p) | 25.7494 | 25.7500 | ±0.005 | True |
| 93 | [정비판] 69분류 평균 절대 기여 산업 동학(%p) | 15.7439 | 15.7400 | ±0.005 | True |
| 94 | [정비판] 69분류 평균 절대 기여 외생(%p) | 3.3945 | 3.3900 | ±0.005 | True |
| 95 | [정비판] 69분류 실질금리 최대 |기여|(%p) | 0.1557 | 0.1600 | ±0.005 | True |
| 96 | [정비판] 62 유가 SHAP·반사실 산업 간 상관 | 0.8979 | 0.8980 | ±0.0005 | True |
| 97 | [정비판] 총량 2035(조원) | 2,671.4229 | 2,671.4200 | ±0.005 | True |
| 98 | [정비판] 총량 유가 효과(조원) | 1.0742 | 1.0700 | ±0.005 | True |
| 99 | [정비판] 총량 유가 효과(%) | 0.0402 | 0.0400 | ±0.0005 | True |
| 100 | [정비판] 총량 유가 CAGR 기여(%p) | 0.0041 | 0.0041 | ±5e-05 | True |
| 101 | [정비판] 바텀업 2035(조원) | 2,793.7447 | 2,793.7400 | ±0.005 | True |
| 102 | [정비판] 바텀업 유가 효과(조원) | 3.9658 | 3.9700 | ±0.005 | True |
| 103 | [정비판] 바텀업 유가 효과(%) | 0.1420 | 0.1420 | ±0.0005 | True |
| 104 | [정비판] 바텀업 유가 CAGR 기여(%p) | 0.0146 | 0.0146 | ±5e-05 | True |
| 105 | [정비판] 바텀업/총량 유가 효과 배율 | 3.6917 | 3.6900 | ±0.005 | True |
| 106 | [정비판] 영구 수준차 외생(2035 시나리오 폭) | 유가 · 고용_취업자 | 유가 · 고용_취업자 | 일치 | True |
| 107 | [정비판] 시나리오 폭 2035 유가(100·ln) | 51.7500 | 51.7500 | ±0.005 | True |
| 108 | [정비판] 유가 S1 2025 연평균($/배럴) | 69.2274 | 69.2000 | ±0.05 | True |
| 109 | [정비판] 유가 S1 2035 연평균($/배럴) | 78.9022 | 78.9000 | ±0.05 | True |
| 110 | [정비판] 유가 2035 시나리오 최저($/배럴) | 65.9046 | 65.9000 | ±0.05 | True |
| 111 | [정비판] 유가 2035 시나리오 최고($/배럴) | 110.5766 | 110.6000 | ±0.05 | True |
| 112 | [정비판] 실질금리 S1 2035 연평균(%) | 1.3119 | 1.3100 | ±0.005 | True |
검증 통과: 이전 판 공표 수치 67개(외생 카드·유가 카드·SHAP 산출물)와 정비판 항목 46개(5장 분해 대조·정비판 기록 수치)를 반올림 범위 안에서 재현했다(합계 113개).