02 분석 — 산업 배분, Λ 보정, 산업별 경로, 취업계수¶

부가가치 프리미엄. 산업 $i$의 연도 $t$ AI 부가가치 프리미엄(연 %p)은

$$p_{i,t} = k \cdot a_i \cdot r(t), \qquad a_i = s_i^{2040} - 1,$$

이다. $s_i^{2040}$은 E4-1(성장에 대한 AI 영향의 정도) 2040년 점수, 1은 척도 최저점('매우 낮음'), $r(t)$는 전체 응답 평균 궤적으로 만든 시점 램프(2025=0, 2040=1)이다. 배율 $k$는 2035년 실질부가가치 가중평균 프리미엄이 $\Lambda$(중심 0.5%p)가 되도록 정한다. AI 확산 경로는 기준 성장률에 프리미엄을 더해 누적한다.

$$VA^{AI}_{i,t} = VA^{AI}_{i,t-1} \times \frac{VA^{기준}_{i,t}}{VA^{기준}_{i,t-1}} \times \left(1 + \frac{p_{i,t}}{100}\right)$$

취업계수. AI 확산에 따른 취업계수 연변화는 $(\varepsilon - 1)\,p_{i,t}$이다. 중심은 고용 중립($\varepsilon=0$)으로, AI가 만드는 추가 부가가치가 고용을 늘리지 않는다고 보아 취업계수가 프리미엄만큼 내려간다. E4·E5 기대 증감률로 구한 업종별 탄력성 $\varepsilon_i = \ln(1+\Delta L_i)/\ln(1+\Delta Y_i)$는 대부분 0 이하이므로 고용 중립은 고용 측 상한이다. 다만 이 탄력성에는 고령화·해외 이전 같은 AI 외 요인이 섞여 있으므로, 그대로 적용한 값은 하방 민감도로 둔다.

2026-10 정비판. 보고서1의 기준 시나리오가 정비되었다. BOKDPM 장기 정상상태를 고치고(잠재성장률 1.8%, 물가안정목표 2%, 실질유가 불변), 실질금리를 1차 차분으로 투입하며, 시나리오 외생 경로의 레버를 연결한 뒤 산업 전망과 정합화를 다시 실행한 결과이다. 이 판은 그 기준 시나리오(data/inputs/base_va_62.csv·base_va_69.csv)만 교체하였고, AI 확산 층(산업 배분 A1, Λ 보정, 고용 중립 취업계수)은 이전 판과 같다. 이전 판 기준 시나리오는 data/published_prev/에 두고 정비 전후 비교와 이전 판 재현 점검에만 쓴다. 8절은 같은 AI 확산 층을 이전 판 기준 시나리오에 적용해 정비 전후를 비교한다.

산출물. output/ai_index_62.csv(비공개), lambda_sensitivity.csv, ai_va_62.csv, ai_va_69.csv, ai_premium_labor_62.csv, ai_premium_labor_69.csv, elasticity_62.csv, allocation_variants.csv, compare_prev.csv

In [1]:
import os, hashlib
import numpy as np, pandas as pd
import config as C
import ai_forecast as F
pd.set_option("display.float_format", lambda v: f"{v:,.3f}")
C.setup()
signal = pd.read_csv(os.path.join(C.INTERIM, "survey_signal_21.csv"), index_col=0)
expect = pd.read_csv(os.path.join(C.INTERIM, "change_expect_21.csv"), index_col=0)
cw = pd.read_csv(C.CROSSWALK)
carve = dict(pd.read_csv(C.CARVEOUT)[["69분화산업", "모산업_62번"]].values)
base62, base69 = F.read_base(C.BASE_62), F.read_base(C.BASE_69)
tot_g = signal.loc["전체", [f"AI성장_{t}" for t in F.TIME_POINTS]].tolist()
print("배분 방식:", C.ALLOCATION)
Python 3.12.10 · pandas 2.2.3 · numpy 2.4.6 · openpyxl 3.1.5 · matplotlib 3.11.0
  판: 2026-10 정비판 · 배분 A1 · 취업계수 neutral · Λ 중심 0.5
  기준 62          있음  data\inputs\base_va_62.csv
  기준 69          있음  data\inputs\base_va_69.csv
  이전 판 기준 62     있음  data\published_prev\base_va_62_prev.csv
  이전 판 기준 69     있음  data\published_prev\base_va_69_prev.csv
  크로스워크          있음  data\crosswalk_21_62.csv
  분화표            있음  data\carveout_69.csv
  설문 통계표(비공개)    있음  data\private\AI수용도조사_통계표_260417.xlsx
배분 방식: A1

1. 21→62 크로스워크 적용¶

설문 21개 업종을 62개 산업에 대응시킨다. 대응 업종이 없는 7개 산업(농업·임업·어업·공공행정은 전체 평균, 목재·펄프종이·인쇄는 제조업 평균)은 상위 평균으로 대체한다.

In [2]:
idx62 = F.apply_crosswalk(signal, cw)
idx62.to_csv(os.path.join(C.OUTPUT, "ai_index_62.csv"), encoding="utf-8-sig")
print(idx62["대응유형"].value_counts().to_string())
idx62[["62산업", "설문업종", "AI성장_2040"]].sort_values("AI성장_2040", ascending=False).head(8)
(비공개 설문 집계를 보여주는 셀이다. 공개 화면에서는 출력을 생략했다. 자료를 가진 경우 직접 실행하면 표시된다.)

2. 시점 램프 r(t)¶

전체 응답 평균 성장 영향(E4-1)의 4시점 값을 연간 선형보간하고 2025년 0, 2040년 1로 정규화한다. 2035년 값이 Λ 보정의 기준 시점이다.

In [3]:
ramp = F.ramp_factory(tot_g)
pd.Series({y: ramp(y) for y in range(C.START, C.END + 1)}, name="r(t)").to_frame().T
Out[3]:
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035
r(t) 0.000 0.108 0.215 0.323 0.431 0.495 0.559 0.624 0.688 0.752 0.793

3. Λ 보정과 민감도¶

Λ는 문헌의 AI 생산성 추정 범위(보수적 약 0.1%p/년 ~ 낙관적 약 1.5%p/년)의 중도인 0.5%p를 중심으로 하고 0.3·0.8을 민감도로 둔다. 목표는 2035년 실질부가가치 가중평균 프리미엄이다.

In [4]:
fn = F.central_premium_fn(idx62, tot_g, C.ALLOCATION)
b25, b35 = base62.loc[C.START].sum() / 1e3, base62.loc[C.END].sum() / 1e3
rows, paths, prems = [], {}, {}
for tgt in C.LAMBDA_SENSITIVITY:
    ai, prem = F.project_variant(base62, fn, tgt)
    paths[tgt], prems[tgt] = ai, prem
    a35 = ai.loc[C.END].sum() / 1e3
    rows.append({"Λ(%p)": tgt, "2035 AI확산(조원)": a35, "CAGR(%)": F.cagr(b25, a35, 10),
                 "기준 대비(%p)": F.cagr(b25, a35, 10) - F.cagr(b25, b35, 10), "수준 차이(조원)": a35 - b35})
sens = pd.DataFrame(rows)
sens.to_csv(os.path.join(C.OUTPUT, "lambda_sensitivity.csv"), index=False, encoding="utf-8-sig")
print(f"기준: {b25:,.1f}조 → {b35:,.1f}조, CAGR {F.cagr(b25, b35, 10):.2f}%")
sens
기준: 2,178.5조 → 2,609.0조, CAGR 1.82%
Out[4]:
Λ(%p) 2035 AI확산(조원) CAGR(%) 기준 대비(%p) 수준 차이(조원)
0 0.300 2,658.662 2.012 0.192 49.634
1 0.500 2,692.217 2.140 0.320 83.189
2 0.800 2,743.259 2.332 0.512 134.231

4. 고용 탄력성¶

E4·E5 기대 증감률로 업종별 탄력성을 구한다. 기대 매출 증가율이 5% 미만인 업종은 분모가 0에 가까워 비율이 불안정하므로 제조업·비제조업 평균 탄력성으로 대체한다. 69분류의 분화 산업은 모산업의 탄력성을 따른다.

In [5]:
el = F.employment_elasticity(expect)
eps62 = {c: float(el.loc[idx62.loc[int(c.split(".")[0]), "설문업종"], "탄력성_ε"]) for c in base62.columns}
pd.DataFrame({"산업": list(eps62), "고용탄력성_ε": list(eps62.values())}).to_csv(
    os.path.join(C.OUTPUT, "elasticity_62.csv"), index=False, encoding="utf-8-sig")
print("대체 업종:", ", ".join(el.index[el["탄력성_출처"] != "업종 값"].drop(["전체", "제조업", "비제조업"], errors="ignore")))
print(f"전체 평균 ε = {el.loc['전체', '탄력성_ε']:.2f} · 제조업 {el.loc['제조업', '탄력성_ε']:.2f} · 비제조업 {el.loc['비제조업', '탄력성_ε']:.2f}")
대체 업종: 12. 운수, 18. 사업지원서비스, 21. 문화/예술
전체 평균 ε = -0.62 · 제조업 -0.47 · 비제조업 -0.87

5. 62분류 산업별 경로(중심 Λ=0.5)와 취업계수¶

In [6]:
def to_long(base, ai, label):
    b = base.loc[C.START:C.END].stack().rename("실질VA_십억원").reset_index().assign(시나리오="기준(S1)")
    a = ai.stack().rename("실질VA_십억원").reset_index().assign(시나리오=label)
    return pd.concat([b, a])[["시나리오", "연도", "산업", "실질VA_십억원"]]

ai62, prem62v = paths[C.LAMBDA_CENTRAL], prems[C.LAMBDA_CENTRAL]
to_long(base62, ai62, "AI확산(Λ=0.5)").to_csv(os.path.join(C.OUTPUT, "ai_va_62.csv"), index=False, encoding="utf-8-sig")
lab62 = F.labor_coef_change(prem62v, eps62, C.EMPLOYMENT)
lab62.to_csv(os.path.join(C.OUTPUT, "ai_premium_labor_62.csv"), encoding="utf-8-sig")
lab62.sort_values("VA프리미엄_2035_%p", ascending=False).head(6)
Out[6]:
VA프리미엄_2035_%p 고용탄력성_ε(설문) 취업계수변화_2035_%p 취업계수변화_고용중립_%p 취업계수변화_설문탄력성_%p
산업
44.컴퓨터 프로그래밍ㆍ시스템통합관리업 0.620 -0.154 -0.620 -0.620 -0.716
45.정보서비스업 0.620 -0.154 -0.620 -0.620 -0.716
40.출판업 0.620 -0.154 -0.620 -0.620 -0.716
41.영상ㆍ오디오기록물제작 배급업 0.620 -0.154 -0.620 -0.620 -0.716
42.방송업 0.620 -0.154 -0.620 -0.620 -0.716
43.통신업 0.620 -0.154 -0.620 -0.620 -0.716

6. 69분류 — 분화 산업은 모산업의 점수와 탄력성을 이어받는다¶

분화 산업 8개(반도체·이차전지·신재생에너지·조선업·철강·택배·건물건설·토목건설)는 모산업(62분류)의 설문 점수와 탄력성을 그대로 쓴다. 배율은 69분류 가중치로 다시 보정한다.

In [7]:
def proxy62(c):
    p = F.parent_of(c, carve)
    return [x for x in base62.columns if int(x.split(".")[0]) == p][0]

ai69, prem69v = F.project_variant(base69, lambda c, t: fn(proxy62(c), t), C.LAMBDA_CENTRAL)
to_long(base69, ai69, "AI확산(Λ=0.5)").to_csv(os.path.join(C.OUTPUT, "ai_va_69.csv"), index=False, encoding="utf-8-sig")
lab69 = F.labor_coef_change(prem69v, {c: eps62[proxy62(c)] for c in base69.columns}, C.EMPLOYMENT)
lab69.to_csv(os.path.join(C.OUTPUT, "ai_premium_labor_69.csv"), encoding="utf-8-sig")
print(f"2035 AI확산 전산업: 62분류 {ai62.loc[C.END].sum()/1e3:,.1f}조 · 69분류 {ai69.loc[C.END].sum()/1e3:,.1f}조")
lab69.loc[list(carve)]
2035 AI확산 전산업: 62분류 2,692.2조 · 69분류 2,692.2조
Out[7]:
VA프리미엄_2035_%p 고용탄력성_ε(설문) 취업계수변화_2035_%p 취업계수변화_고용중립_%p 취업계수변화_설문탄력성_%p
산업
반도체 0.559 -0.216 -0.559 -0.559 -0.681
이차전지 0.559 -0.216 -0.559 -0.559 -0.681
신재생에너지 0.440 -0.056 -0.440 -0.440 -0.465
조선업 0.503 -1.144 -0.503 -0.503 -1.077
철강 0.479 -0.646 -0.479 -0.479 -0.788
택배 0.458 -0.874 -0.458 -0.458 -0.858
건물건설건축보수 0.425 -1.275 -0.425 -0.425 -0.966
토목건설 0.425 -1.275 -0.425 -0.425 -0.966

7. 배분 방식 민감도 — 기준점 선택¶

네 방식 모두 2035년 VA 가중평균 프리미엄을 0.5%p로 보정하므로 전산업 총량은 거의 같다. 산업 간 배분만 달라진다.

방식 산식(보정 전) 해석
A1 중심 $(s_i^{2040}-1)\,r(t)$ 척도 최저점 '매우 낮음'을 영향 최소로 둔다
A 이전 $(s_i^{2040}-5)\,r(t)$ 중간값 '보통'을 0으로 둔다. 정도 척도를 방향 척도로 읽은 방식이다
B 증가분 $s_i(t)-s_i(2025)$ 2025년 영향은 기준선에 반영되었다고 보고 이후 증가분만 쓴다
C 상대강도 $s_i^{2040}/\bar s^{2040}\,r(t)$ 전체 평균 대비 비율
In [8]:
variants = F.allocation_variants(idx62, tot_g)
rows = {}
for name, vfn in variants.items():
    ai_v, prem_v = F.project_variant(base62, vfn, C.LAMBDA_CENTRAL)
    rows[name] = prem_v
    a35 = ai_v.loc[C.END].sum() / 1e3
    print(f"{name:<14} 2035 {a35:,.1f}조 · 기준 대비 {F.cagr(b25, a35, 10) - F.cagr(b25, b35, 10):+.3f}%p · 최대/최소 {prem_v.max() / prem_v.min():5.1f}배")
var = pd.DataFrame(rows)
var.to_csv(os.path.join(C.OUTPUT, "allocation_variants.csv"), encoding="utf-8-sig")
pick = [c for c in var.index if c.split(".")[0] in ("44", "56", "23", "22", "6", "46", "33", "39", "59")]
var.loc[pick]
A 현행(s−5)      2035 2,692.5조 · 기준 대비 +0.321%p · 최대/최소  36.4배
A1 앵커1(s−1)    2035 2,692.2조 · 기준 대비 +0.320%p · 최대/최소   1.6배
B 증가분          2035 2,691.5조 · 기준 대비 +0.318%p · 최대/최소   1.8배
C 상대강도         2035 2,692.2조 · 기준 대비 +0.320%p · 최대/최소   1.4배
Out[8]:
A 현행(s−5) A1 앵커1(s−1) B 증가분 C 상대강도
22.전자부품ㆍ컴퓨터ㆍ영상ㆍ음향ㆍ통신장비 0.780 0.559 0.591 0.550
23.의료ㆍ정밀ㆍ광학기기ㆍ시계 0.800 0.564 0.649 0.553
33.건설업 0.146 0.425 0.385 0.437
39.음식점ㆍ숙박업 0.180 0.432 0.434 0.443
44.컴퓨터 프로그래밍ㆍ시스템통합관리업 1.067 0.620 0.534 0.600
46.금융업 0.334 0.465 0.403 0.471
56.교육서비스업 0.897 0.584 0.471 0.570
59.문화서비스업 0.029 0.400 0.536 0.417
6.식료품 0.639 0.530 0.595 0.525

8. 정비 전후 비교 — 같은 AI 확산 층을 이전 판 기준 시나리오에 적용¶

설문 점수·크로스워크·시점 램프·배분 방식(A1)·Λ·탄력성은 그대로 두고 기준 시나리오만 이전 판(data/published_prev/)으로 바꾸어 같은 계산을 한다. 이전 판 열은 이전 판 공표 수치를 재현해야 하며, 03의 검증 셀이 이를 확인한다(이전 판 재현 점검).

Λ 보정은 2035년 기준 시나리오의 산업 구성을 가중치로 쓰므로, 기준 시나리오가 바뀌면 배율 $k$가 다시 정해진다. $p_{i,t}=k\,a_i\,r(t)$에서 $a_i$와 $r(t)$는 설문에서 오므로 그대로이고, 산업별 프리미엄은 모든 산업에서 같은 비율 $k^{정비}/k^{이전}$만큼 바뀐다.

In [9]:
prev62, prev69 = F.read_base(C.BASE_62_PREV), F.read_base(C.BASE_69_PREV)
fn69 = lambda c, t: fn(proxy62(c), t)
eps69 = {c: eps62[proxy62(c)] for c in base69.columns}
args = (fn, fn69, eps62, eps69, list(carve), C.LAMBDA_SENSITIVITY, C.LAMBDA_CENTRAL, C.EMPLOYMENT)
new = F.scenario_summary(base62, base69, *args)
old = F.scenario_summary(prev62, prev69, *args)
cmp = new.rename(columns={"값": "정비판"}).merge(old.rename(columns={"값": "이전 판"}), on=["구분", "항목"], validate="one_to_one")
cmp["차이"] = cmp["정비판"] - cmp["이전 판"]
cmp.to_csv(os.path.join(C.OUTPUT, "compare_prev.csv"), index=False, encoding="utf-8-sig")

# 정비판 열은 1–6절의 결과와 같아야 한다(같은 함수·같은 입력)
assert abs(F.lookup(cmp, "정비판", "총량", "AI_2035_조") - ai62.loc[C.END].sum() / 1e3) < 1e-9
assert abs(F.lookup(cmp, "정비판", "62 프리미엄(%p)", 44) - lab62.loc[[c for c in lab62.index if c.startswith("44.")][0], "VA프리미엄_2035_%p"]) < 1e-12
assert abs(F.lookup(cmp, "정비판", "69 분화 AI 2035(조원)", "반도체") - ai69.loc[C.END, "반도체"] / 1e3) < 1e-9

sub = cmp[cmp["구분"] == "62 프리미엄(%p)"]
ratio = sub["정비판"] / sub["이전 판"]
print(f"62분류 산업별 프리미엄 비율(정비판/이전 판): 최소 {ratio.min():.6f} · 최대 {ratio.max():.6f}")
cmp[cmp["구분"] == "총량"].set_index("항목")[["이전 판", "정비판", "차이"]]
62분류 산업별 프리미엄 비율(정비판/이전 판): 최소 1.002474 · 최대 1.002474
Out[9]:
이전 판 정비판 차이
항목
기준_2025_조 2,178.489 2,178.489 0.000
기준_2035_조 2,688.518 2,609.028 -79.490
기준_CAGR 2.126 1.820 -0.306
L03_2035_조 2,739.664 2,658.662 -81.002
L03_CAGR 2.319 2.012 -0.307
L03_차이_%p 0.193 0.192 -0.001
L03_수준차이_조 51.146 49.634 -1.512
L03_수준차이_% 1.902 1.902 0.000
AI_2035_조 2,774.242 2,692.217 -82.024
AI_CAGR 2.447 2.140 -0.307
AI_차이_%p 0.321 0.320 -0.001
AI_수준차이_조 85.724 83.189 -2.534
AI_수준차이_% 3.189 3.189 0.000
L08_2035_조 2,826.838 2,743.259 -83.579
L08_CAGR 2.640 2.332 -0.308
L08_차이_%p 0.514 0.512 -0.002
L08_수준차이_조 138.320 134.231 -4.089
L08_수준차이_% 5.145 5.145 0.000