03 결과 도출 — 전망 표·그림, 이전 판 대비 변화, 전달 산출물, 검증¶

02_분석.ipynb의 산출물로 5장의 표·그림을 만들고, 이전 판(2026-09-03 공표)과 비교하며, 한국고용정보원 전달 엑셀 형식의 재현본(62분류 부가가치, 2025–2035)과 비교 카드 자료(02 10절의 산업별 성장 요인 분해 포함)를 작성한다. 전달 엑셀은 패키지 output/에만 만들며, 전달문서 폴더의 _신규.xlsx(사용자가 서식을 정리한 전달본)는 읽기만 한다. 마지막 셀은 정비판 기록 산출물(data/published/)·핵심 수치와 계산 결과를 대조하고, 이전 판 전달본이 이전 판 전망으로 재현되는지도 확인한다.

In [1]:
import os
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")   # numpy보다 먼저 지정한다(config.py 주석 참조)
import json
import numpy as np, pandas as pd
import config as C
import gva_results as R
pd.set_option("display.float_format", lambda v: f"{v:,.3f}")
C.setup()
import matplotlib.pyplot as plt
import koreanize_matplotlib  # noqa: F401  (한글 글꼴)
rec = {r: R.read_long(os.path.join(C.OUTPUT, f"forecast_annual_{r}.csv")) for r in C.RES}
bu = {r: R.read_long(os.path.join(C.OUTPUT, f"bottomup_annual_{r}.csv")) for r in C.RES}
bu_raw = {r: R.read_long(os.path.join(C.OUTPUT, f"bottomup_raw_annual_{r}.csv")) for r in C.RES}
agg = R.read_long(os.path.join(C.OUTPUT, "topdown_annual.csv"))
prevrec = {r: R.read_long(os.path.join(C.PREV_DIR, f"forecast_annual_{r}.csv")) for r in C.RES}
prev = pd.read_csv(C.PREV_KEIS, encoding="utf-8-sig")
fac = pd.read_csv(os.path.join(C.OUTPUT, "reconcile_factors.csv"), encoding="utf-8-sig")
bench = pd.read_csv(os.path.join(C.OUTPUT, "benchmark_only_totals.csv"), encoding="utf-8-sig")
wcur = pd.read_csv(os.path.join(C.OUTPUT, "shrink_w_validation.csv"), encoding="utf-8-sig")
wj = json.load(open(os.path.join(C.OUTPUT, "wstar.json"), encoding="utf-8"))
T = {r: R.totals(rec[r]) / 1e3 for r in C.RES}            # 조원
TB = {r: R.totals(bu[r]) / 1e3 for r in C.RES}
TBR = {r: R.totals(bu_raw[r]) / 1e3 for r in C.RES}
TP = {r: R.totals(prevrec[r]) / 1e3 for r in C.RES}
a25 = T[62].loc[C.BASE_YEAR, "실적"]
LBL = {s: f"{s} {C.SCN_NAME[s]}" for s in C.SCENARIOS}
UNIT = "조 원(2020년 연쇄가격)"
Python 3.12.10 · pandas 2.2.3 · numpy 2.4.6 · openpyxl 3.1.5 · matplotlib 3.11.0
  드리프트 재설정 목표 1.8% · 수축 가중치 w=0.4(이전 판 0.45) · 원본 엑셀 대조: 없음
  기존 전망 62     있음  data\inputs\prev_keis_va_62.csv
  전달 템플릿       있음  data\inputs\template_62_VA_v1.xlsx
  분기 자료(상류)    있음  data\inputs\upstream
  정비판 기록       있음  data\published
  이전 판 공표      있음  data\published_prev

표 1. 시나리오별 전산업 실질부가가치 전망(62분류 합, 정합화 후) — 정비판과 이전 판¶

In [2]:
t1 = pd.DataFrame([{"시나리오": LBL[s], "2025(조원)": a25, "2030(조원)": T[62].loc[2030, s], "2035(조원)": T[62].loc[2035, s],
                    "연평균 2025–35(%)": R.cagr(a25, T[62].loc[2035, s], 10),
                    "이전 판 2035(조원)": TP[62].loc[2035, s], "이전 판 연평균(%)": R.cagr(a25, TP[62].loc[2035, s], 10),
                    "2035 변화(%)": (T[62].loc[2035, s] / TP[62].loc[2035, s] - 1) * 100} for s in C.SCENARIOS])
t1.to_csv(os.path.join(C.OUTPUT, "table1_scenarios.csv"), index=False, encoding="utf-8-sig")
t1.style.format({c: ("{:,.0f}" if "조원" in c else "{:.2f}") for c in t1.columns if c != "시나리오"}).hide(axis="index")
Out[2]:
시나리오 2025(조원) 2030(조원) 2035(조원) 연평균 2025–35(%) 이전 판 2035(조원) 이전 판 연평균(%) 2035 변화(%)
S1 기준 2,178 2,393 2,609 1.82 2,689 2.13 -2.96
S2 공급제약 2,178 2,391 2,606 1.81 2,650 1.98 -1.68
S3 제약완화 2,178 2,394 2,612 1.83 2,709 2.20 -3.56
S4 기술도약 2,178 2,400 2,608 1.81 2,741 2.32 -4.85
S5 지정학 2,178 2,394 2,610 1.82 2,664 2.03 -2.03

정비판의 시나리오 간 차이는 이전 판보다 훨씬 작다. 이전 판에서 시나리오를 가른 것은 주로 실질금리 수준 경로였다(6장 진단: 실질금리가 오르는 시나리오일수록 성장률이 높게 계산되었다). 실질금리를 차분으로 넣으면 금리 경로의 일시적 차이는 일시적 효과만 남기고, 충격이 감쇠하는 레버 설계에서는 2035년의 수준 차이가 작다. 영구적인 차이는 인구 레버(노동공급)와 유가 수준에서 생긴다.

그림 1. 전산업 경로 — 실적, 바텀업(재설정 전·후), 최종 전망, 이전 판, 기존 전망¶

In [3]:
fig, ax = plt.subplots(figsize=(9, 5))
h = T[62]["실적"].dropna()
ax.plot(h.index, h.values, color="black", lw=2, label="실적")
def joined(s):
    x = s.copy(); x.loc[C.BASE_YEAR] = a25; return x.sort_index().loc[C.BASE_YEAR:]
ax.plot(joined(TBR[62]["S1"]).index, joined(TBR[62]["S1"]).values, color="#bbbbbb", ls="--", label="바텀업(재설정 전, S1)")
ax.plot(joined(TB[62]["S1"]).index, joined(TB[62]["S1"]).values, color="#777777", ls="--", label="바텀업(드리프트 재설정, S1)")
ax.plot(joined(TP[62]["S1"]).index, joined(TP[62]["S1"]).values, color="#7aa6c2", ls=":", lw=2, label="이전 판 최종(S1)")
cols = {"S1": "#1f4e79", "S2": "#c0504d", "S3": "#9bbb59", "S4": "#a9781f", "S5": "#8064a2"}
for s in C.SCENARIOS:
    ax.plot(joined(T[62][s]).index, joined(T[62][s]).values, color=cols[s], lw=1.6 if s != "S1" else 2.4, label=f"최종 {LBL[s]}")
gp = pd.Series(R.prior_factors(prev)) * a25
ax.plot(gp.index, gp.values, color="#555555", lw=1, marker="o", ms=3, label="기존 전망 성장률(2025 실적에 접합)")
ax.axvline(C.BASE_YEAR + 0.5, color="gray", lw=0.8, ls="--")
ax.set_ylabel(UNIT); ax.set_xlim(2010, 2035.5); ax.set_ylim(1300, 3400); ax.grid(alpha=.3)
ax.legend(fontsize=8, ncol=2, frameon=False, loc="upper left")
ax.set_title("62분류 전산업 실질부가가치: 바텀업·최종 전망과 이전 판", loc="left")
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig1_total_paths.png"), dpi=150)
No description has been provided for this image

표 2. 정합화 단계별 2035년 전산업과 연평균(62분류)¶

In [4]:
rows = []
for s in C.SCENARIOS:
    v0r, v0 = TBR[62].loc[2035, s], TB[62].loc[2035, s]
    v1 = bench[(bench["분류"] == 62) & (bench["시나리오"] == s) & (bench["연도"] == 2035)]["합계_십억원"].iloc[0] / 1e3
    v2 = T[62].loc[2035, s]
    rows.append({"시나리오": LBL[s], "바텀업 재설정 전(조원)": v0r, "재설정 전(%)": R.cagr(a25, v0r, 10),
                 "바텀업(조원)": v0, "바텀업(%)": R.cagr(a25, v0, 10),
                 "총량 벤치마킹 w=0(조원)": v1, "총량 벤치마킹 w=0(%)": R.cagr(a25, v1, 10),
                 f"최종 w={C.W_PRIOR}(조원)": v2, f"최종 w={C.W_PRIOR}(%)": R.cagr(a25, v2, 10)})
t2 = pd.DataFrame(rows)
t2.to_csv(os.path.join(C.OUTPUT, "table2_reconcile_steps.csv"), index=False, encoding="utf-8-sig")
t2.style.format({c: ("{:,.0f}" if "조원" in c else "{:.2f}") for c in t2.columns if c != "시나리오"}).hide(axis="index")
Out[4]:
시나리오 바텀업 재설정 전(조원) 재설정 전(%) 바텀업(조원) 바텀업(%) 총량 벤치마킹 w=0(조원) 총량 벤치마킹 w=0(%) 최종 w=0.4(조원) 최종 w=0.4(%)
S1 기준 3,223 4.00 2,794 2.52 2,633 1.91 2,609 1.82
S2 공급제약 3,223 3.99 2,793 2.52 2,628 1.89 2,606 1.81
S3 제약완화 3,222 3.99 2,793 2.52 2,638 1.93 2,612 1.83
S4 기술도약 3,220 3.99 2,791 2.51 2,631 1.90 2,608 1.81
S5 지정학 3,232 4.02 2,801 2.55 2,635 1.92 2,610 1.82

그림 2. 성장인자 — 통제 총량, 기존 전망, 결합(2025=1)¶

In [5]:
fig, ax = plt.subplots(figsize=(8, 4.2))
f62 = fac[fac["분류"] == 62]
def from25(x):                                    # 2025년(=1)을 앞에 붙인다
    return pd.concat([pd.Series({C.BASE_YEAR: 1.0}), x])
for s in C.SCENARIOS:
    x = f62[f62["시나리오"] == s].set_index("연도")
    ax.plot(from25(x["총량모형_gM"]), color=cols[s], ls="--", lw=1, label=f"통제 총량 $g^M$ {s}")
    ax.plot(from25(x["결합_g"]), color=cols[s], lw=2 if s == "S1" else 1.2, label=f"결합 $g$ {s}")
x = f62[f62["시나리오"] == "S1"].set_index("연도")
ax.plot(from25(x["기존전망_gP"]), color="black", marker="o", ms=3, lw=1.2, label="기존 전망 $g^P$")
ax.set_ylabel("2025년 = 1"); ax.grid(alpha=.3); ax.legend(fontsize=7, ncol=3, frameon=False)
ax.set_title(r"통제 총량의 성장인자: $g=\exp\,[\,w\ln g^P+(1-w)\ln g^M\,]$, $w=" + str(C.W_PRIOR) + "$", loc="left")
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig2_growth_factors.png"), dpi=150)
No description has been provided for this image

표 3. 36·62·69 분류 간 일관성¶

세 분류는 같은 통제 총량에 맞추므로 정합화 후 전산업 합계가 같다. 반면 개별 산업 값은 분류마다 별도의 VARX로 전망되므로 같은 산업이라도 다를 수 있다. 62분류와 69분류에 공통인 55개 산업(이름이 같은 산업)과, 69분류에서 분화된 산업 쌍의 합을 62분류 모산업과 비교한다(S1, 2035년).

In [6]:
rows = [{"구분": f"{r}분류 전산업 2035 S1(조원)", "정합화 전": TB[r].loc[2035, "S1"], "정합화 후": T[r].loc[2035, "S1"]} for r in C.RES]
t3a = pd.DataFrame(rows)
x62 = rec[62][(rec[62]["시나리오"] == "S1") & (rec[62]["연도"] == 2035)].set_index("산업")[R.VAL]
x69 = rec[69][(rec[69]["시나리오"] == "S1") & (rec[69]["연도"] == 2035)].set_index("산업")[R.VAL]
common = sorted(set(x62.index) & set(x69.index))
rel = (x69[common] / x62[common] - 1) * 100
PAIRS = {"20.1차 금속": ["철강", "20.1차 금속(잔여)"],
         "22.전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비": ["반도체", "22.전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비(잔여)"],
         "24.전기장비": ["이차전지", "24.전기장비(잔여)"], "27.기타 운송장비": ["조선업", "27.기타 운송장비(잔여)"],
         "29.전기ㆍ가스ㆍ증기ㆍ공기조절공급업": ["신재생에너지", "29.전기ㆍ가스ㆍ증기ㆍ공기조절공급업(잔여)"],
         "33.건설업": ["건물건설건축보수", "토목건설"], "38.창고ㆍ운송보조서비스업": ["택배", "38.창고ㆍ운송보조서비스업(잔여)"]}
assert len(common) == 55 and set(x69.index) == set(common) | {c for v in PAIRS.values() for c in v}
t3b = pd.DataFrame([{"62분류 모산업": p, "62분류(조원)": x62[p] / 1e3, "69분류 분화 합(조원)": x69[c].sum() / 1e3,
                     "차이(%)": (x69[c].sum() / x62[p] - 1) * 100} for p, c in PAIRS.items()])
pd.concat([t3a.assign(표="전산업"), t3b.assign(표="분화 산업")]).to_csv(os.path.join(C.OUTPUT, "table3_consistency.csv"), index=False, encoding="utf-8-sig")
print(f"공통 55개 산업의 69/62 차이(S1 2035): 중앙값 {rel.median():+.2f}%, 범위 {rel.min():+.2f}% ~ {rel.max():+.2f}%"
      f" (최대: {rel.abs().idxmax()})")
display(t3a.style.format({"정합화 전": "{:,.1f}", "정합화 후": "{:,.1f}"}).hide(axis="index"))
t3b.style.format({"62분류(조원)": "{:,.1f}", "69분류 분화 합(조원)": "{:,.1f}", "차이(%)": "{:+.2f}"}).hide(axis="index")
공통 55개 산업의 69/62 차이(S1 2035): 중앙값 -0.01%, 범위 -1.86% ~ +1.19% (최대: 14.석탄ㆍ석유제품)
구분 정합화 전 정합화 후
36분류 전산업 2035 S1(조원) 2,777.0 2,609.0
62분류 전산업 2035 S1(조원) 2,793.7 2,609.0
69분류 전산업 2035 S1(조원) 2,795.5 2,609.0
Out[6]:
62분류 모산업 62분류(조원) 69분류 분화 합(조원) 차이(%)
20.1차 금속 17.3 17.3 -0.30
22.전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 417.1 415.1 -0.49
24.전기장비 38.6 40.6 +5.11
27.기타 운송장비 16.5 16.4 -0.61
29.전기ㆍ가스ㆍ증기ㆍ공기조절공급업 45.1 47.0 +4.10
33.건설업 78.8 79.6 +1.11
38.창고ㆍ운송보조서비스업 59.5 59.2 -0.48

표 4. 62분류 산업별 연평균 증가율(S1, 2025–2035) — 상·하위 10개, 이전 판 병기¶

In [7]:
r62 = rec[62]                                    # 요약표(소수 셋째 자리)가 아니라 반올림 전 값으로 계산한다
v25 = r62[(r62["시나리오"] == "실적") & (r62["연도"] == C.BASE_YEAR)].set_index("산업")[R.VAL]
v35 = r62[(r62["시나리오"] == "S1") & (r62["연도"] == C.END_YEAR)].set_index("산업")[R.VAL]
p35 = prevrec[62][(prevrec[62]["시나리오"] == "S1") & (prevrec[62]["연도"] == C.END_YEAR)].set_index("산업")[R.VAL]
s1 = pd.DataFrame({"2025(조원)": v25 / 1e3, "2035(조원)": v35 / 1e3, "연평균(%)": ((v35 / v25) ** 0.1 - 1) * 100,
                   "이전 판 연평균(%)": ((p35 / v25) ** 0.1 - 1) * 100})
s1["변화(%p)"] = s1["연평균(%)"] - s1["이전 판 연평균(%)"]
s1 = s1.sort_values("연평균(%)", ascending=False)
t4 = pd.concat([s1.head(10).assign(구분="상위"), s1.tail(10).assign(구분="하위")])[["구분", "2025(조원)", "2035(조원)", "연평균(%)", "이전 판 연평균(%)", "변화(%p)"]]
t4.to_csv(os.path.join(C.OUTPUT, "table4_industry_top_bottom.csv"), encoding="utf-8-sig")
t4.style.format({"2025(조원)": "{:,.2f}", "2035(조원)": "{:,.2f}", "연평균(%)": "{:+.2f}", "이전 판 연평균(%)": "{:+.2f}", "변화(%p)": "{:+.2f}"})
Out[7]:
  구분 2025(조원) 2035(조원) 연평균(%) 이전 판 연평균(%) 변화(%p)
산업            
23.의료ㆍ정밀ㆍ광학기기ㆍ시계 상위 26.45 52.64 +7.12 +8.33 -1.21
22.전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 상위 209.91 417.11 +7.11 +8.37 -1.26
58.사회복지 서비스업 상위 34.15 51.12 +4.12 +3.87 +0.25
57.의료ㆍ보건업 상위 101.03 150.25 +4.05 +3.85 +0.20
47.보험ㆍ연금업 상위 17.88 26.51 +4.02 +4.14 -0.12
48.금융ㆍ보험관련서비스업 상위 36.29 53.16 +3.89 +4.00 -0.11
46.금융업 상위 77.47 113.36 +3.88 +3.96 -0.07
43.통신업 상위 29.88 40.65 +3.13 +1.57 +1.55
40.출판업 상위 3.54 4.77 +3.04 +2.91 +0.12
41.영상ㆍ오디오기록물제작 배급업 상위 4.57 6.16 +3.03 +2.99 +0.04
11.목재ㆍ목제품 하위 2.09 1.68 -2.18 -1.31 -0.87
12.펄프ㆍ종이제품 하위 7.52 6.03 -2.19 -1.35 -0.84
13.인쇄ㆍ복제 하위 3.79 3.04 -2.19 -1.45 -0.74
19.비금속광물제품 하위 9.62 7.55 -2.39 -1.93 -0.46
20.1차 금속 하위 24.09 17.34 -3.23 -2.80 -0.44
9.섬유ㆍ의복 하위 13.83 9.37 -3.82 -2.18 -1.63
10.가죽제품 하위 1.12 0.76 -3.86 -2.23 -1.63
5.금속ㆍ비금속광업 하위 1.38 0.90 -4.19 -5.49 +1.30
4.석탄ㆍ원유ㆍ천연가스 하위 0.02 0.01 -4.19 -5.60 +1.41
14.석탄ㆍ석유제품 하위 9.52 5.05 -6.14 -3.43 -2.71

그림 3. 62개 산업 연평균 증가율(S1, 2025–2035) — 정비판과 이전 판¶

In [8]:
q = s1.sort_values("연평균(%)")
fig, ax = plt.subplots(figsize=(8, 11))
yl = [s.split(".", 1)[1] for s in q.index]
ax.barh(yl, q["연평균(%)"].values, color=["#c0504d" if v < 0 else "#1f4e79" for v in q["연평균(%)"].values], label="정비판")
ax.scatter(q["이전 판 연평균(%)"].values, yl, color="#a9781f", s=10, zorder=3, label="이전 판")
ax.axvline(R.cagr(a25, T[62].loc[2035, "S1"], 10), color="#1f4e79", lw=1, ls="--", label=f"전산업 {R.cagr(a25, T[62].loc[2035, 'S1'], 10):.2f}%")
ax.set_xlabel("연 %"); ax.grid(axis="x", alpha=.3); ax.tick_params(axis="y", labelsize=7); ax.legend(frameon=False)
ax.set_title("62개 산업 실질부가가치 연평균 증가율(S1, 정합화 후)", loc="left")
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig3_industry_cagr_62.png"), dpi=150)
No description has been provided for this image

전달 엑셀 형식 — 62분류 부가가치(2025–2035, VA만)¶

KEIS 전달 템플릿(2000–2034)을 복사해 2024–2035년을 채운다. 각 산업의 값은 템플릿 2023년 수준 × (정합화 S1 전망의 t년 값 / 2023년 실적) 이다. 즉 수준은 템플릿을, 성장은 이 연구의 전망을 따른다. 2035년 열(AM)을 새로 만들고 전산업 행(65행)은 62개 산업의 합으로, 대분류 소계(68–76행)는 2034년 수식을 복제한다. 결과는 output/sector62_VA_2025-2035_재현.xlsx이며, 전달문서 폴더의 전달본(_신규.xlsx)을 바꾸지 않는다(전달본 교체는 사용자 확인 후).

이전 판 전달본의 재현도 함께 확인한다. 이전 판 공표 전망으로 같은 논리를 실행하면 전달본(_신규.xlsx)의 값과 일치해야 한다.

In [9]:
XLSX = os.path.join(C.OUTPUT, "sector62_VA_2025-2035_재현.xlsx")
fill = R.fill_template(C.TEMPLATE, rec[62], XLSX)
fv = R.read_filled_values(XLSX)
our = R.s1_with_actuals(rec[62]); our.columns = [int(c.split(".")[0]) for c in our.columns]
w = fv[fv["번호"] > 0].pivot(index="연도", columns="번호", values="VA_백만원")
g_x = (w.loc[2024:2035] / w.loc[2023]); g_f = (our.loc[2024:2035] / our.loc[2023])[w.columns]
d_growth = float((g_x - g_f).abs().max().max())
d_sum = float((fv[fv["번호"] == 0].set_index("연도")["VA_백만원"] - w.sum(axis=1)).abs().max() / 1e6)
print(f"채운 파일의 성장인자 대 전망 성장인자 최대 절대차 {d_growth:.1e} · 전산업 행 − 산업 합 최대차 {d_sum:.1e}조 원")

fill_p = R.fill_template(C.TEMPLATE, prevrec[62], os.path.join(C.INTERIM, "fill_check_prev.xlsx"), copy_style=False)
deliv = pd.read_csv(os.path.join(C.PREV_DIR, "delivered_62_VA_2025-2035.csv"), encoding="utf-8-sig")
m = R.read_filled_values(os.path.join(C.INTERIM, "fill_check_prev.xlsx")).merge(deliv, on=["번호", "연도"], suffixes=("_계산", "_전달"))
assert len(m) == len(deliv) and (m["산업_계산"] == m["산업_전달"]).all()
d_deliv_prev = float(((m["VA_백만원_계산"] - m["VA_백만원_전달"]).abs() / m["VA_백만원_전달"].abs()).max())
print(f"이전 판 전망으로 채운 값 대 이전 판 전달본(_신규.xlsx): 최대 상대차 {d_deliv_prev:.1e}")

names = {int(c.split(".")[0]): c.split(".", 1)[1] for c in rec[62]["산업"].unique()}
card = R.card_data(fill, names); R.json_dump(card, os.path.join(C.OUTPUT, "card_2025_2035.json"))
shap62 = json.load(open(os.path.join(C.OUTPUT, "shap_62.json"), encoding="utf-8"))     # 02 10절 성장 요인 분해
detail = R.va_detail(C.TEMPLATE, XLSX, shap62); R.json_dump(detail, os.path.join(C.OUTPUT, "va_detail_62.json"))
card_prev = json.load(open(os.path.join(C.PREV_DIR, "card_2025_2035.json"), encoding="utf-8"))
채운 파일의 성장인자 대 전망 성장인자 최대 절대차 8.9e-16 · 전산업 행 − 산업 합 최대차 9.5e-13조 원
이전 판 전망으로 채운 값 대 이전 판 전달본(_신규.xlsx): 최대 상대차 2.1e-16

표 5. 기존 전망(2024–2034판)·이전 판 대비 — 전달 템플릿 수준¶

전달 엑셀은 템플릿의 수준(2023년 전산업 2,247조 원)을 쓰므로 전망 파일(2023년 2,090조 원)과 수준이 다르다. 비교는 같은 수준의 기존 전망·이전 판 전달본과 한다. 산업별 상·하위는 신규 − 기존 연평균(2024–2034) 차이를 기준으로 6개씩 고른다.

In [10]:
ag, agp = card["agg"], card_prev["agg"]
t5a = pd.DataFrame([{"구분": "기존 전망(2024–2034판)", "2024(조원)": ag["old_path"]["2024"], "2034(조원)": ag["old_2034"], "2035(조원)": np.nan,
                     "연평균 2024–34(%)": ag["old_cagr_24_34"], "연평균 2025–35(%)": np.nan},
                    {"구분": "이전 판 전달본(2026-09)", "2024(조원)": agp["new_path"]["2024"], "2034(조원)": agp["new_2034"], "2035(조원)": agp["new_2035"],
                     "연평균 2024–34(%)": agp["new_cagr_24_34"], "연평균 2025–35(%)": agp["new_cagr_25_35"]},
                    {"구분": "정비판(정합화 S1)", "2024(조원)": ag["new_path"]["2024"], "2034(조원)": ag["new_2034"], "2035(조원)": ag["new_2035"],
                     "연평균 2024–34(%)": ag["new_cagr_24_34"], "연평균 2025–35(%)": ag["new_cagr_25_35"]}])
ind = pd.DataFrame(card["inds"]).assign(차이=lambda d: d["new_cagr"] - d["old_cagr"]).sort_values("차이", ascending=False)
t5b = pd.concat([ind.head(6).assign(구분="상위"), ind.tail(6).assign(구분="하위")])[["구분", "num", "name", "old_cagr", "new_cagr", "차이"]]
t5b.columns = ["구분", "번호", "산업", "기존 연평균(%)", "신규 연평균(%)", "차이(%p)"]
pd.concat([t5a.assign(표="전산업"), t5b.assign(표="산업별")]).to_csv(os.path.join(C.OUTPUT, "table5_vs_previous.csv"), index=False, encoding="utf-8-sig")
display(t5a.style.format({c: "{:,.2f}" for c in t5a.columns if c != "구분"}, na_rep="—").hide(axis="index"))
t5b.style.format({"기존 연평균(%)": "{:+.2f}", "신규 연평균(%)": "{:+.2f}", "차이(%p)": "{:+.2f}"}).hide(axis="index")
구분 2024(조원) 2034(조원) 2035(조원) 연평균 2024–34(%) 연평균 2025–35(%)
기존 전망(2024–2034판) 2,292.20 2,694.46 — 1.63 —
이전 판 전달본(2026-09) 2,305.83 2,823.58 2,880.25 2.05 2.10
정비판(정합화 S1) 2,305.83 2,751.46 2,797.26 1.78 1.80
Out[10]:
구분 번호 산업 기존 연평균(%) 신규 연평균(%) 차이(%p)
상위 23 의료ㆍ정밀ㆍ광학기기ㆍ시계 +1.94 +7.45 +5.51
상위 22 전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 +2.68 +7.44 +4.77
상위 16 화학섬유 -2.75 +0.24 +2.99
상위 47 보험ㆍ연금업 +1.81 +4.20 +2.39
상위 48 금융ㆍ보험관련서비스업 +1.70 +4.08 +2.38
상위 57 의료ㆍ보건업 +2.30 +4.27 +1.97
하위 33 건설업 +0.78 -2.69 -3.47
하위 9 섬유ㆍ의복 +0.16 -3.35 -3.51
하위 20 1차 금속 +0.50 -3.03 -3.52
하위 19 비금속광물제품 +0.62 -3.02 -3.65
하위 5 금속ㆍ비금속광업 +0.10 -4.41 -4.51
하위 14 석탄ㆍ석유제품 -0.01 -5.63 -5.62

표 6. 이전 판 대비 변화 요약 — 전산업·바텀업·총량·가중치¶

변경 전후의 핵심 수치를 한 표로 모은다. 이전 판 값은 data/published_prev/와 config.PREVIOUS에서 읽는다.

In [11]:
pv = pd.read_csv(os.path.join(C.PREV_DIR, "topdown_annual_AGG.csv"), encoding="utf-8-sig")
tpv = R.totals(pv)
tpb = R.totals(R.read_long(os.path.join(C.PREV_DIR, "bottomup_annual_62.csv"))) / 1e3
tagg = R.totals(agg)
rows = [
    ("전산업 S1 2035(조원, 62분류 합)", T[62].loc[2035, "S1"], TP[62].loc[2035, "S1"]),
    ("전산업 S1 연평균 2025–35(%)", R.cagr(a25, T[62].loc[2035, "S1"], 10), R.cagr(a25, TP[62].loc[2035, "S1"], 10)),
    ("시나리오 범위 2035(조원, 최대−최소)", T[62].loc[2035, C.SCENARIOS].max() - T[62].loc[2035, C.SCENARIOS].min(),
     TP[62].loc[2035, C.SCENARIOS].max() - TP[62].loc[2035, C.SCENARIOS].min()),
    ("바텀업 62 S1 연평균(%)", R.cagr(a25, TB[62].loc[2035, "S1"], 10), R.cagr(a25, tpb.loc[2035, "S1"], 10)),
    ("바텀업 62 S1 연평균, 드리프트 재설정 전(%)", R.cagr(a25, TBR[62].loc[2035, "S1"], 10), R.cagr(a25, tpb.loc[2035, "S1"], 10)),
    ("통제 총량 S1 연평균(%)", R.cagr(tagg.loc[2025, "실적"], tagg.loc[2035, "S1"], 10), R.cagr(tpv.loc[2025, "실적"], tpv.loc[2035, "S1"], 10)),
    ("비례계수 62 S1 2035", float(fac[(fac["분류"] == 62) & (fac["시나리오"] == "S1") & (fac["연도"] == 2035)]["비례계수"].iloc[0]),
     (TP[62].loc[2035, "S1"] / tpb.loc[2035, "S1"])),
    ("결합 가중치 w", C.W_PRIOR, C.PREVIOUS["w"]),
    ("전달 템플릿 수준 2035(조원)", ag["new_2035"], agp["new_2035"]),
    ("전달 템플릿 수준 연평균 2025–35(%)", ag["new_cagr_25_35"], agp["new_cagr_25_35"]),
]
t6 = pd.DataFrame(rows, columns=["항목", "정비판", "이전 판"]).set_index("항목")
t6["변화"] = t6["정비판"] - t6["이전 판"]
t6.to_csv(os.path.join(C.OUTPUT, "table6_change_summary.csv"), encoding="utf-8-sig")
t6.style.format("{:,.3f}")
Out[11]:
  정비판 이전 판 변화
항목      
전산업 S1 2035(조원, 62분류 합) 2,609.028 2,688.518 -79.490
전산업 S1 연평균 2025–35(%) 1.820 2.126 -0.306
시나리오 범위 2035(조원, 최대−최소) 6.321 90.404 -84.083
바텀업 62 S1 연평균(%) 2.519 4.880 -2.362
바텀업 62 S1 연평균, 드리프트 재설정 전(%) 3.996 4.880 -0.885
통제 총량 S1 연평균(%) 1.913 2.492 -0.579
비례계수 62 S1 2035 0.934 0.766 0.168
결합 가중치 w 0.400 0.450 -0.050
전달 템플릿 수준 2035(조원) 2,797.257 2,880.248 -82.991
전달 템플릿 수준 연평균 2025–35(%) 1.799 2.097 -0.298

그림 4. 결합 가중치 검증 — 검증·시험 RMSE¶

In [12]:
fig, ax = plt.subplots(figsize=(7, 3.8))
v, t = wcur["검증 RMSE(2020–22)"], wcur["시험 RMSE(2023–25)"]
ax.plot(wcur["w"], v / v.iloc[0] * 100, marker="o", ms=3, color="#1f4e79", label=f"검증 2020–22 (w=0: {v.iloc[0]:,.0f}십억 원)")
ax.plot(wcur["w"], t / t.iloc[0] * 100, marker="s", ms=3, color="#a9781f", label=f"시험 2023–25 (w=0: {t.iloc[0]:,.0f}십억 원)")
ax.axvline(wj["wstar"], color="gray", ls="--", lw=0.8)
ax.annotate(f"w* = {wj['wstar']}", (wj["wstar"], 100), xytext=(6, 4), textcoords="offset points", fontsize=8)
ax.set_xlabel("기존 전망(추세) 가중치 w"); ax.set_ylabel("RMSE(w=0 = 100)"); ax.grid(alpha=.3); ax.legend(frameon=False, fontsize=8)
ax.set_title("결합 가중치의 유사표본외 선택(62분류)", loc="left")
fig.tight_layout(); fig.savefig(os.path.join(C.OUTPUT, "fig4_shrink_w.png"), dpi=150)
No description has been provided for this image

표 7. 산업별 성장 요인 분해(S1, 62분류) — 10년 로그 성장 상·하위 8개¶

02 10절의 분해(정합화 이전 바텀업, 드리프트 재설정 후, 2025Q4→2035Q4, %p)이다. 전망 갱신 카드의 요인 분해 막대와 자동 해설이 같은 값(va_detail_62.json의 shap)을 쓴다. 통제 총량 맞춤은 모든 산업에 같은 값으로 더해지므로(shap_62.json의 meta.reconcile_2035) 산업 간 순위를 바꾸지 않는다.

In [13]:
sh62 = pd.read_csv(os.path.join(C.OUTPUT, "shap_62.csv"), index_col=0, encoding="utf-8-sig", float_precision="round_trip")
EXN = {"고용_취업자": "취업자 수", "우리경기": "국내 경기"}
t7 = sh62.rename(columns={"total": "합계", "drift": "과거추세", "dynamics": "산업 동학", **EXN}).sort_values("합계", ascending=False)
t7 = pd.concat([t7.head(8).assign(구분="상위"), t7.tail(8).assign(구분="하위")])
t7 = t7[["구분"] + [c for c in t7.columns if c != "구분"]]
t7.to_csv(os.path.join(C.OUTPUT, "table7_growth_factors.csv"), encoding="utf-8-sig")
print(f"통제 총량 맞춤(모든 산업 공통): {shap62['meta']['reconcile_2035']:+.2f}%p · 드리프트 재설정 δ = 연 {shap62['meta']['delta']:.3f}%p")
t7.style.format({c: "{:+.2f}" for c in t7.columns if c != "구분"})
통제 총량 맞춤(모든 산업 공통): -6.84%p · 드리프트 재설정 δ = 연 1.524%p
Out[13]:
  구분 합계 과거추세 산업 동학 유가 세계수요 실질금리 실질환율 취업자 수 국내 경기
산업                    
23.의료ㆍ정밀ㆍ광학기기ㆍ시계 상위 +74.96 +97.78 -24.45 +1.14 +0.50 +0.03 -0.57 -0.01 +0.53
22.전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 상위 +74.79 +78.00 -3.88 +0.85 +0.20 +0.07 -0.86 -0.01 +0.41
58.사회복지 서비스업 상위 +45.46 +52.72 -7.65 +0.17 -0.33 -0.08 +0.45 -0.03 +0.20
57.의료ㆍ보건업 상위 +44.80 +51.46 -7.06 +0.21 -0.35 -0.07 +0.42 -0.02 +0.22
47.보험ㆍ연금업 상위 +44.54 +30.15 +15.73 -0.54 +0.19 +0.14 -0.22 +0.02 -0.92
48.금융ㆍ보험관련서비스업 상위 +43.32 +24.77 +19.71 -0.60 +0.22 +0.16 -0.26 +0.02 -0.70
46.금융업 상위 +43.20 +24.43 +19.98 -0.64 +0.25 +0.14 -0.32 +0.03 -0.67
43.통신업 상위 +37.59 +13.02 +27.59 -0.90 +0.14 -0.04 -1.34 +0.00 -0.88
13.인쇄ㆍ복제 하위 -13.56 -43.63 +28.43 +1.17 -1.08 -0.04 +0.96 -0.01 +0.63
39.음식점ㆍ숙박업 하위 -13.56 -7.80 -8.29 +0.95 +0.43 -0.06 +1.13 -0.01 +0.07
20.1차 금속 하위 -25.95 -3.12 -16.17 -0.35 -1.73 -0.02 -3.11 -0.02 -1.43
9.섬유ㆍ의복 하위 -33.15 -30.67 -4.30 +1.78 -0.42 +0.05 -0.58 -0.03 +1.02
10.가죽제품 하위 -33.59 -32.81 -2.54 +1.80 -0.49 +0.05 -0.57 -0.03 +1.00
5.금속ㆍ비금속광업 하위 -34.12 -48.83 +11.40 +0.06 +0.38 -0.01 +1.62 -0.01 +1.25
4.석탄ㆍ원유ㆍ천연가스 하위 -34.15 -61.67 +23.77 +0.18 +0.34 -0.00 +1.55 -0.01 +1.68
14.석탄ㆍ석유제품 하위 -60.60 -46.44 -19.62 +6.21 -2.07 -0.00 -0.27 -0.00 +1.60

검증 — 정비판 기록 산출물·핵심 수치, 이전 판 전달본 재현¶

정비판 기록 산출물(data/published/)은 2026-10 정비 실행의 output/ 사본이다. 파일은 행 단위로 대조하며 허용오차는 파일의 반올림 단위(소수 셋째 자리 0.0005십억 원 등)이다. 핵심 수치는 정수 조 원, 소수 둘째 자리 %의 반올림 범위를 허용오차로 둔다. 이전 판 전달본(_신규.xlsx)은 이전 판 전망으로 같은 채움 논리를 실행해 재현되는지 확인한다.

In [14]:
P = C.PUBLISHED
g = lambda s, y: (T[62].loc[y, s] / T[62].loc[y - 1, s] - 1) * 100
tagg = R.totals(agg)
checks = [
    ("S1 2025 전산업(조원)", a25, P["S1_2025_조"], 0.5),
    ("S1 2035 전산업(조원)", T[62].loc[2035, "S1"], P["S1_2035_조"], 0.5),
    ("S1 연평균 2025–35(%)", R.cagr(a25, T[62].loc[2035, "S1"], 10), P["S1_CAGR"], 0.005),
]
for s in ["S2", "S3", "S4", "S5"]:
    checks += [(f"{s} 2035 전산업(조원)", T[62].loc[2035, s], P[f"{s}_2035_조"], 0.5),
               (f"{s} 연평균(%)", R.cagr(a25, T[62].loc[2035, s], 10), P[f"{s}_CAGR"], 0.005)]
checks += [("S1 2030년 증가율(%)", g("S1", 2030), P["S1_증가율_2030"], 0.005),
           ("S1 2035년 증가율(%)", g("S1", 2035), P["S1_증가율_2035"], 0.005)]
checks += [(f"정합화 후 {r}분류 S1 2035(조원)", T[r].loc[2035, "S1"], P["S1_2035_조"], 0.5) for r in C.RES]
checks += [("분류 간 전산업 합계 최대차(십억원)", max((T[r] - T[62]).abs().max().max() for r in C.RES) * 1e3, 0.0, 0.035)]
checks += [(f"바텀업 {r}분류 S1 연평균(%)", R.cagr(a25, TB[r].loc[2035, "S1"], 10), P["바텀업_CAGR"][r], 0.005) for r in C.RES]
checks += [(f"바텀업(재설정 전) {r}분류 S1 연평균(%)", R.cagr(a25, TBR[r].loc[2035, "S1"], 10), P["바텀업원값_CAGR"][r], 0.005) for r in C.RES]
checks += [
    ("통제 총량 S1 연평균(%)", R.cagr(tagg.loc[2025, "실적"], tagg.loc[2035, "S1"], 10), P["통제총량_CAGR"], 0.005),
    ("비례계수 62 S1 2035", float(fac[(fac["분류"] == 62) & (fac["시나리오"] == "S1") & (fac["연도"] == 2035)]["비례계수"].iloc[0]), P["비례계수_2035"], 0.0005),
    ("결합 가중치 w*", wj["wstar"], P["w"], 1e-9),
    ("검증 RMSE(w*)", min(wj["val"]), P["검증RMSE_w"], 0.05),
    ("시험 RMSE 모형만", wj["test"]["model"], P["시험RMSE_모형"], 0.05),
    ("시험 RMSE 결합", wj["test"]["shrink"], P["시험RMSE_수축"], 0.05),
    ("기존 전망 연평균 2024–34(%)", card["agg"]["old_cagr_24_34"], C.PREVIOUS["기존_CAGR_24_34"], 0.005),
    ("전달 템플릿 수준 2034(조원)", card["agg"]["new_2034"], P["전달_2034_조"], 0.5),
    ("전달 템플릿 수준 2035(조원)", card["agg"]["new_2035"], P["전달_2035_조"], 0.5),
    ("전달 템플릿 수준 연평균 2024–34(%)", card["agg"]["new_cagr_24_34"], P["전달_CAGR_24_34"], 0.005),
    ("전달 템플릿 수준 연평균 2025–35(%)", card["agg"]["new_cagr_25_35"], P["전달_CAGR_25_35"], 0.005),
    ("전달 엑셀 성장인자 = 전망 성장인자(최대차)", d_growth, 0.0, 1e-12),
    ("이전 판 전망 → 이전 판 전달본 _신규.xlsx 재현(최대 상대차)", d_deliv_prev, 0.0, 1e-9),
]
def file_check(name, keys, cols, tol):
    c = pd.read_csv(os.path.join(C.OUTPUT, name), encoding="utf-8-sig"); p = pd.read_csv(os.path.join(C.PUB_DIR, name), encoding="utf-8-sig")
    d = R.compare_long(c, p, keys, cols)
    assert d["키불일치"] == 0 and d["행_계산"] == d["행_공표"], name
    return max(d[k] for k in cols), d["행_계산"]
for r in C.RES:
    for f, tol in [(f"forecast_annual_{r}.csv", 0.0005), (f"bottomup_annual_{r}.csv", 0.0005), (f"bottomup_raw_annual_{r}.csv", 0.0005)]:
        v, n = file_check(f, ["시나리오", "연도", "산업"], [R.VAL], tol)
        checks.append((f"{f} {n:,}행 최대차(십억원)", v, 0.0, tol + 1e-9))
    v, n = file_check(f"forecast_summary_{r}.csv", ["시나리오", "산업"], ["VA2025", "VA2035", "CAGR_26_35(%)"], 0.0)
    checks.append((f"forecast_summary_{r}.csv 최대차", v, 0.0, 1e-9))
    tc = pd.read_csv(os.path.join(C.OUTPUT, f"forecast_total_{r}.csv"), index_col=0, encoding="utf-8-sig")
    tp = pd.read_csv(os.path.join(C.PUB_DIR, f"forecast_total_{r}.csv"), index_col=0, encoding="utf-8-sig")
    checks.append((f"forecast_total_{r}.csv 최대차(조원)", float((tc - tp).abs().max().max()), 0.0, 1e-9))
for f in ["topdown_annual.csv", "topdown_varx_annual.csv", "base_va_62.csv", "base_va_69.csv"]:
    v, n = file_check(f, ["시나리오", "연도", "산업"], [R.VAL], 0.0)
    checks.append((f"{f} {n:,}행 최대차", v, 0.0, 1e-6))
for f, tol in [("card_2025_2035.json", 1e-9), ("va_detail_62.json", 1e-9)]:              # va_detail은 성장 요인 분해(shap)까지 대조
    checks.append((f"{f} 최대차", R.max_abs_json_diff(json.load(open(os.path.join(C.OUTPUT, f), encoding="utf-8")),
                                                        json.load(open(os.path.join(C.PUB_DIR, f), encoding="utf-8")), skip=()), 0.0, tol))
by_num = {int(i.split(".")[0]): i for i in s1.index}
checks += [(f"산업 연평균 S1 {by_num[k].split('.', 1)[1]}(%)", s1.loc[by_num[k], "연평균(%)"], v, 0.005) for k, v in P["산업_CAGR_S1"].items()]
# 성장 요인 분해(02 10절): 기록 파일 대조, 분해 점검 4종, 카드가 쓰는 대표 수치
sh_p = pd.read_csv(os.path.join(C.PUB_DIR, "shap_62.csv"), index_col=0, encoding="utf-8-sig", float_precision="round_trip")
assert list(sh62.index) == list(sh_p.index) and list(sh62.columns) == list(sh_p.columns), "shap_62.csv 행·열이 기록과 다르다"
checks.append((f"shap_62.csv {sh62.shape[0]}개 산업 × {sh62.shape[1]}항목 최대차(%p)", float((sh62 - sh_p).abs().max().max()), 0.0, 1e-6))
sc = pd.read_csv(os.path.join(C.OUTPUT, "shap_check.csv"), encoding="utf-8-sig")
checks += [(f"성장 요인 분해 점검 {r['점검']}", r["값"], 0.0, r["허용오차"]) for _, r in sc.iterrows()]
SP = P["성장요인"]
checks.append(("성장 요인 분해 통제 총량 맞춤 2035(%p)", shap62["meta"]["reconcile_2035"], SP["통제총량_맞춤_2035"], 1e-9))
for k, d in SP["산업"].items():
    checks += [(f"성장 요인 분해 {by_num[k].split('.', 1)[1]} {c}(%p)", sh62.loc[by_num[k], c], v, 0.005) for c, v in d.items()]
checks.append(("성장 요인 분해 실질금리 최대 절대 기여(%p)", sh62["실질금리"].abs().max(), SP["실질금리_최대절대"], 0.005))
d_card = max(abs(x["shap"][c] - round(float(sh62.loc[by_num[x["num"]], c]), 2)) for x in detail["inds"] for c in ("total", "drift", "dynamics")) +          max(abs(x["shap"]["exog"][k] - round(float(sh62.loc[by_num[x["num"]], k]), 2)) for x in detail["inds"] for k in shap62["exog"])
checks.append(("카드 자료(va_detail_62.json)의 분해 = shap_62.csv 반올림값(최대차)", d_card, 0.0, 1e-12))
res = pd.DataFrame([{"항목": k, "계산": float(v), "기록": float(p), "허용오차": tol, "통과": abs(float(v) - float(p)) <= tol}
                    for k, v, p, tol in checks])
res.to_csv(os.path.join(C.OUTPUT, "verification.csv"), index=False, encoding="utf-8-sig")
with pd.option_context("display.max_rows", 120, "display.float_format", lambda v: f"{v:,.6g}"):
    display(res)
assert res["통과"].all(), "기록 수치와 계산 결과가 다르다 — 위 표에서 통과=False 항목을 확인한다"
print(f"검증 통과: {len(res)}개 항목 — 정비판 전망(바텀업·통제 총량·정합화·요약·총계·전달 형식·카드 자료·산업별 성장 요인 분해)과 이전 판 전달본 재현.")
항목 계산 기록 허용오차 통과
0 S1 2025 전산업(조원) 2,178.49 2,178 0.5 True
1 S1 2035 전산업(조원) 2,609.03 2,609 0.5 True
2 S1 연평균 2025–35(%) 1.81982 1.82 0.005 True
3 S2 2035 전산업(조원) 2,605.86 2,606 0.5 True
4 S2 연평균(%) 1.80746 1.81 0.005 True
5 S3 2035 전산업(조원) 2,612.18 2,612 0.5 True
6 S3 연평균(%) 1.83213 1.83 0.005 True
7 S4 2035 전산업(조원) 2,607.7 2,608 0.5 True
8 S4 연평균(%) 1.81463 1.81 0.005 True
9 S5 2035 전산업(조원) 2,610.23 2,610 0.5 True
10 S5 연평균(%) 1.82453 1.82 0.005 True
11 S1 2030년 증가율(%) 1.84637 1.85 0.005 True
12 S1 2035년 증가율(%) 1.69119 1.69 0.005 True
13 정합화 후 36분류 S1 2035(조원) 2,609.03 2,609 0.5 True
14 정합화 후 62분류 S1 2035(조원) 2,609.03 2,609 0.5 True
15 정합화 후 69분류 S1 2035(조원) 2,609.03 2,609 0.5 True
16 분류 간 전산업 합계 최대차(십억원) 0.008 0 0.035 True
17 바텀업 36분류 S1 연평균(%) 2.45703 2.46 0.005 True
18 바텀업 62분류 S1 연평균(%) 2.51871 2.52 0.005 True
19 바텀업 69분류 S1 연평균(%) 2.52502 2.53 0.005 True
20 바텀업(재설정 전) 36분류 S1 연평균(%) 3.96517 3.97 0.005 True
21 바텀업(재설정 전) 62분류 S1 연평균(%) 3.99576 4 0.005 True
22 바텀업(재설정 전) 69분류 S1 연평균(%) 4.00208 4 0.005 True
23 통제 총량 S1 연평균(%) 1.9134 1.91 0.005 True
24 비례계수 62 S1 2035 0.933882 0.934 0.0005 True
25 결합 가중치 w* 0.4 0.4 1e-09 True
26 검증 RMSE(w*) 3,195.3 3,195.3 0.05 True
27 시험 RMSE 모형만 6,552.6 6,552.6 0.05 True
28 시험 RMSE 결합 6,866.8 6,866.8 0.05 True
29 기존 전망 연평균 2024–34(%) 1.62997 1.63 0.005 True
30 전달 템플릿 수준 2034(조원) 2,751.46 2,751 0.5 True
31 전달 템플릿 수준 2035(조원) 2,797.26 2,797 0.5 True
32 전달 템플릿 수준 연평균 2024–34(%) 1.7826 1.78 0.005 True
33 전달 템플릿 수준 연평균 2025–35(%) 1.79894 1.8 0.005 True
34 전달 엑셀 성장인자 = 전망 성장인자(최대차) 8.88178e-16 0 1e-12 True
35 이전 판 전망 → 이전 판 전달본 _신규.xlsx 재현(최대 상대차) 2.06563e-16 0 1e-09 True
36 forecast_annual_36.csv 2,736행 최대차(십억원) 0 0 0.000500001 True
37 bottomup_annual_36.csv 2,736행 최대차(십억원) 0 0 0.000500001 True
38 bottomup_raw_annual_36.csv 2,736행 최대차(십억원) 0 0 0.000500001 True
39 forecast_summary_36.csv 최대차 0 0 1e-09 True
40 forecast_total_36.csv 최대차(조원) 0 0 1e-09 True
41 forecast_annual_62.csv 4,712행 최대차(십억원) 0 0 0.000500001 True
42 bottomup_annual_62.csv 4,712행 최대차(십억원) 0 0 0.000500001 True
43 bottomup_raw_annual_62.csv 4,712행 최대차(십억원) 0 0 0.000500001 True
44 forecast_summary_62.csv 최대차 0 0 1e-09 True
45 forecast_total_62.csv 최대차(조원) 0 0 1e-09 True
46 forecast_annual_69.csv 5,244행 최대차(십억원) 0 0 0.000500001 True
47 bottomup_annual_69.csv 5,244행 최대차(십억원) 0 0 0.000500001 True
48 bottomup_raw_annual_69.csv 5,244행 최대차(십억원) 0 0 0.000500001 True
49 forecast_summary_69.csv 최대차 0 0 1e-09 True
50 forecast_total_69.csv 최대차(조원) 0 0 1e-09 True
51 topdown_annual.csv 76행 최대차 0 0 1e-06 True
52 topdown_varx_annual.csv 76행 최대차 0 0 1e-06 True
53 base_va_62.csv 682행 최대차 0 0 1e-06 True
54 base_va_69.csv 759행 최대차 0 0 1e-06 True
55 card_2025_2035.json 최대차 0 0 1e-09 True
56 va_detail_62.json 최대차 0 0 1e-09 True
57 산업 연평균 S1 의료ㆍ정밀ㆍ광학기기ㆍ시계(%) 7.12451 7.12 0.005 True
58 산업 연평균 S1 전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비(%) 7.10782 7.11 0.005 True
59 산업 연평균 S1 사회복지 서비스업(%) 4.11543 4.12 0.005 True
60 산업 연평균 S1 의료ㆍ보건업(%) 4.04915 4.05 0.005 True
61 산업 연평균 S1 보험ㆍ연금업(%) 4.01668 4.02 0.005 True
62 산업 연평균 S1 금융ㆍ보험관련서비스업(%) 3.89181 3.89 0.005 True
63 산업 연평균 S1 금융업(%) 3.8805 3.88 0.005 True
64 산업 연평균 S1 통신업(%) 3.12505 3.13 0.005 True
65 산업 연평균 S1 1차 금속(%) -3.23348 -3.23 0.005 True
66 산업 연평균 S1 섬유ㆍ의복(%) -3.81665 -3.82 0.005 True
67 산업 연평균 S1 가죽제품(%) -3.85814 -3.86 0.005 True
68 산업 연평균 S1 금속ㆍ비금속광업(%) -4.19051 -4.19 0.005 True
69 산업 연평균 S1 석탄ㆍ원유ㆍ천연가스(%) -4.19181 -4.19 0.005 True
70 산업 연평균 S1 석탄ㆍ석유제품(%) -6.14113 -6.14 0.005 True
71 shap_62.csv 62개 산업 × 9항목 최대차(%p) 0 0 1e-06 True
72 성장 요인 분해 점검 (가) 성분 합 − 합계, 최대 절대차(%p) 0 0 1e-09 True
73 성장 요인 분해 점검 (나) 합계 − 100·ln(경로 2035Q4/2025Q4),... 3.89022e-13 0 1e-09 True
74 성장 요인 분해 점검 (다) 분해 경로 연간 합 − 바텀업 S1(bottomup_a... 0.000499155 0 0.000500001 True
75 성장 요인 분해 점검 (라) 과거추세 재설정분 − (−10(1−ΣA)δ), 최대 절... 8.17124e-14 0 1e-09 True
76 성장 요인 분해 통제 총량 맞춤 2035(%p) -6.84 -6.84 1e-09 True
77 성장 요인 분해 전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 total(%p) 74.7876 74.79 0.005 True
78 성장 요인 분해 전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 drift(%p) 78.0049 78 0.005 True
79 성장 요인 분해 전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 dynamics(%p) -3.87526 -3.88 0.005 True
80 성장 요인 분해 의료ㆍ정밀ㆍ광학기기ㆍ시계 total(%p) 74.9586 74.96 0.005 True
81 성장 요인 분해 의료ㆍ정밀ㆍ광학기기ㆍ시계 drift(%p) 97.7768 97.78 0.005 True
82 성장 요인 분해 의료ㆍ정밀ㆍ광학기기ㆍ시계 dynamics(%p) -24.4451 -24.45 0.005 True
83 성장 요인 분해 석탄ㆍ석유제품 total(%p) -60.5991 -60.6 0.005 True
84 성장 요인 분해 석탄ㆍ석유제품 drift(%p) -46.4373 -46.44 0.005 True
85 성장 요인 분해 석탄ㆍ석유제품 유가(%p) 6.20835 6.21 0.005 True
86 성장 요인 분해 실질금리 최대 절대 기여(%p) 0.157161 0.16 0.005 True
87 카드 자료(va_detail_62.json)의 분해 = shap_62.csv 반올림... 0 0 1e-12 True
검증 통과: 88개 항목 — 정비판 전망(바텀업·통제 총량·정합화·요약·총계·전달 형식·카드 자료·산업별 성장 요인 분해)과 이전 판 전달본 재현.