02 분석 — AI 확산 지수, 대안 1(고정 계수), 대안 2(재추정)¶

구성. 1절 총량 지수와 갭 → 2절 산업별 노출 지수 → 3절 기존 산업모형 적합(보고서1 선택 모형) → 4절 대안 1 → 5절 파급 진단 → 6절 대안 2 → 7절 산출물 저장.

공통 규칙. 모든 사양은 2035년 부가가치 가중평균 AI 프리미엄이 Λ = 0.5%p가 되도록 크기를 맞춘다. 따라서 사양 간 차이는 산업 간 배분과 파급에서만 생긴다. 시간 경로는 4장과 같다: 설문 전체 평균 점수의 시점 가중치 r(t)(2025년 0 → 2040년 1)를 분기로 보간한다.

In [1]:
import os, hashlib
import numpy as np, pandas as pd
import config as C
import ai_index as I, ai_varx as X, ai_forecast as F, varx_engine as V, alt_run as R
pd.set_option("display.float_format", lambda v: f"{v:,.3f}")
pd.set_option("display.width", 200)
C.setup()
Python 3.12.10 · pandas 2.2.3 · numpy 2.4.6 · matplotlib 3.11.0
  판: 2026-10 정비판 기준 · Λ 0.5 · 드리프트 목표 1.8% · ONLINE=0(스냅샷) · Event Registry 키 없음
  설문 통계표(비공개)    있음  data\private\AI수용도조사_통계표_260417.xlsx
  설문 원자료(비공개)    있음  data\private\AI수용도조사_원자료_n2297.xlsx
In [2]:
L, gdp, exo, B, _ = X.fit_existing(C.LEVELS_62, C.EXOG_HIST, C.IO_62)
Wio = V.load(C.LEVELS_62, C.EXOG_HIST, C.IO_62)[3]
names = list(L.columns); n = len(names)
base = F.read_base(C.BASE_62)[names]           # 산업 순서를 산업모형과 맞춘다
grp = R.survey_groups(names, C.CROSSWALK)
sig = pd.read_csv(os.path.join(C.INTERIM, "survey_signal_21.csv"), index_col=0)
se_tab = pd.read_csv(os.path.join(C.INTERIM, "survey_se_21.csv"), index_col=0)
a = R.survey_shape(sig, grp)
ramp = F.ramp_factory(sig.loc["전체", [f"AI성장_{t}" for t in F.TIME_POINTS]].tolist())
xq = X.quarterly_ramp(ramp)
print(f"산업 {n}개, 표본 {L.index[0]}–{L.index[-1]}({len(L)}분기), 전망 {xq.index[0]}–{xq.index[-1]}")
print(f"시점 가중치 r(t): 2030년 {ramp(2030):.3f}, 2035년 {ramp(2035):.3f}")
산업 62개, 표본 2000Q1–2025Q4(104분기), 전망 2026Q1–2035Q4
시점 가중치 r(t): 2030년 0.495, 2035년 0.793

1. AI 확산 총량 지수(분기)¶

세 자료원의 로그 수준에서 각자의 2015–2024년 평균을 뺀 값(로그 편차)을 분기로 맞추고 평균한다. 연간 자료(특허·논문)는 연 중앙에 로그 수준을 두고 선형보간한 뒤 해마다 분기 합이 연간 값과 같도록 비례 조정한다. AI 확산 갭은 총량 지수에서 HP 추세(λ = 1600)를 뺀 값이다. 추세보다 빨리 퍼진 분기는 양(+), 느린 분기는 음(−)이다. 뉴스 자료가 시작되기 전인 2015년 이전은 0으로 둔다(AI 확산 이전 시기).

In [3]:
comp = R.build_index(C.PATENT_YEAR, C.PAPER_YEAR, C.NEWS_DAILY)
gap = I.gap_series(comp, list(L.index))
comp.to_csv(os.path.join(C.OUTPUT, "ai_index_quarterly.csv"), encoding="utf-8-sig")
display(comp.iloc[::4])
print(f"총량 지수: 2015Q1 {comp['총량지수'].iloc[0]:+.2f} → 2025Q4 {comp['총량지수'].iloc[-1]:+.2f}(로그 편차, 10년간 약 {np.exp(comp['총량지수'].iloc[-1] - comp['총량지수'].iloc[0]):.0f}배)")
print(f"갭 표준편차 {comp['갭'].std():.3f}, 최대 {comp['갭'].max():+.3f}({comp['갭'].idxmax()}), 최소 {comp['갭'].min():+.3f}({comp['갭'].idxmin()})")
print(f"세 자료원 상관(분기 로그 편차): ", comp[["특허", "논문", "뉴스"]].corr().round(2).values[np.triu_indices(3, 1)].tolist())
특허 논문 뉴스 총량지수 추세 갭
분기
2015Q1 -2.119 -0.299 -2.183 -1.534 -1.465 -0.069
2016Q1 -1.633 -0.278 -1.237 -1.049 -1.079 0.030
2017Q1 -1.004 -0.265 -0.717 -0.662 -0.705 0.043
2018Q1 -0.423 -0.183 -0.305 -0.304 -0.362 0.059
2019Q1 0.101 -0.074 0.098 0.042 -0.067 0.109
2020Q1 0.516 0.005 0.255 0.259 0.174 0.085
2021Q1 0.767 0.084 0.369 0.407 0.368 0.039
2022Q1 0.808 0.078 0.281 0.389 0.540 -0.151
2023Q1 0.806 0.158 0.901 0.622 0.714 -0.092
2024Q1 0.982 0.462 1.645 1.030 0.899 0.130
2025Q1 NaN 0.514 1.732 1.123 1.086 0.037
총량 지수: 2015Q1 -1.53 → 2025Q4 +1.24(로그 편차, 10년간 약 16배)
갭 표준편차 0.101, 최대 +0.170(2019Q4), 최소 -0.248(2022Q3)
세 자료원 상관(분기 로그 편차):  [0.85, 0.94, 0.93]

2. 산업별 AI 노출 지수(설문 21개 업종)¶

자료원마다 지표의 로그값을 업종 간 표준화(z)하고, 쓸 수 있는 자료원의 평균을 노출 지수로 둔다. 특허 지표는 업종 부가가치 1조 원당 AI 특허 동시분류 건수이다. 대응표가 없어 지표를 만들 수 없는 업종·자료원 조합은 빈칸으로 두고 나머지 자료원의 평균을 쓴다(자료원수 열). 62개 산업 가운데 설문 업종이 없는 산업(농림어업·공공행정 등)은 21개 업종의 부가가치 가중평균('전체'), 일부 제조업은 제조 9개 업종의 가중평균('제조업')을 쓴다.

In [4]:
ex, zg = R.build_exposure(C.NEWS_IND, C.PAPER_FIELD, C.MAP_FIELD, C.PATENT_COIPC, C.PATENT_COIPC_SUP, C.MAP_IPC,
                          base.loc[C.START], grp)
ex.to_csv(os.path.join(C.OUTPUT, "ai_exposure_21.csv"), encoding="utf-8-sig")
display(ex.sort_values("노출지수_z", ascending=False))
a21 = sig.loc[ex.index, "AI성장_2040"]
rho = {"노출 지수": I.spearman(ex["노출지수_z"], a21)} | {k: I.spearman(ex[k], a21) for k in ["뉴스", "논문", "특허"]}
rho_tab = pd.DataFrame({"설문 E4-1과의 순위상관": rho})
rho_tab.to_csv(os.path.join(C.OUTPUT, "exposure_rank_corr.csv"), encoding="utf-8-sig")
display(rho_tab)
뉴스 논문 특허 노출지수_z 자료원수
설문업종
13. 정보통신 11.576 45.679 12,851.163 2.023 3
02. 정밀기기 9.318 NaN 1,794.228 0.928 2
17. 연구개발업 10.515 12.470 NaN 0.820 2
01. 전기전자 25.984 12.671 100.438 0.598 3
08. 자동차 7.379 18.187 472.451 0.462 3
10. 에너지 7.462 6.504 899.722 0.218 3
18. 사업지원서비스 9.316 8.266 315.767 0.153 3
07. 기계장비 4.287 18.187 460.674 0.145 3
12. 운수 7.091 NaN 383.531 0.050 2
09. 식료품 2.868 19.391 NaN -0.014 2
20. 보건사회 7.451 4.298 494.368 -0.123 3
14. 도소매 5.003 NaN 391.333 -0.240 2
16. 금융 5.829 3.976 523.925 -0.279 3
19. 교육 4.977 4.666 NaN -0.436 2
04. 석유화학 6.016 3.024 127.528 -0.769 3
11. 건설 3.423 NaN NaN -0.850 1
05. 비금속광물 3.314 3.617 NaN -0.944 2
06. 금속제품 3.067 3.617 NaN -1.010 2
21. 문화/예술 2.745 3.833 NaN -1.069 2
03. 섬유가죽 2.638 NaN NaN -1.295 1
15. 음식숙박 2.623 NaN NaN -1.305 1
설문 E4-1과의 순위상관
노출 지수 0.491
뉴스 0.353
논문 0.546
특허 0.238

설문 순위와 객관 지표 순위를 나란히 보면 두 자료가 어디에서 갈리는지 알 수 있다(업종 평균 점수가 드러나므로 출력은 공개 화면에서 숨긴다).

In [5]:
cmp = pd.DataFrame({"설문_순위": a21.rank(ascending=False), "노출_순위": ex["노출지수_z"].rank(ascending=False)})
cmp["차이(설문−노출)"] = cmp["설문_순위"] - cmp["노출_순위"]
display(cmp.sort_values("차이(설문−노출)"))
(비공개 설문 집계를 보여주는 셀이다. 공개 화면에서는 출력을 생략했다. 자료를 가진 경우 직접 실행하면 표시된다.)

한국고용정보원(2017) 혁신 시나리오(대안 1c). 8장 세부 산업의 (혁신 − 기준) 차이를 세 구간 평균해 설문 업종별로 단순평균하고(KIET), 11장 인력수급 산업의 2016~2030년 차이(KEIS)와 평균한다. 이 값은 이미 부가가치 증가율 차이(%p)이므로 척도를 옮기지 않고 그대로 배분 형태로 쓴다. 세 자료(설문·객관 지표·이전 전망)의 업종 순위가 얼마나 일치하는지 함께 본다.

In [6]:
keis_tab, kg, keis_tot = R.build_keis(C.KEIS_R14, C.MAP_KEIS11, C.SHORT_NAMES, base.loc[C.START], grp)
keis_tab.to_csv(os.path.join(C.OUTPUT, "keis_r14_dva_21.csv"), encoding="utf-8-sig")
display(keis_tab)
print("전 산업 혁신 − 기준(8장, 세 구간 평균): %.2f%%p, 구간별 %s, 11장 2016~2030: %.2f%%p"
      % (keis_tot["전산업_KIET_3구간평균"], keis_tot["구간별_KIET"], keis_tot["전산업_KEIS_2016_2030"]))
tri = pd.DataFrame({"설문 E4-1": a21, "객관 노출 지수": ex["노출지수_z"], "고용정보원(2017) ΔVA": keis_tab["ΔVA_평균"]})
tri_rho = tri.rank().corr()
tri_rho.to_csv(os.path.join(C.OUTPUT, "triangulation_rank_corr.csv"), encoding="utf-8-sig")
pd.Series(keis_tot | {"구간별_KIET": str(keis_tot["구간별_KIET"])}).to_frame("값").to_csv(os.path.join(C.OUTPUT, "keis_r14_total.csv"), encoding="utf-8-sig")
display(tri_rho.round(2))
k62 = np.array([kg[g] for g in grp])
ΔVA_KIET ΔVA_KEIS ΔVA_평균
설문업종
01. 전기전자 0.717 0.800 0.758
02. 정밀기기 0.300 0.280 0.290
03. 섬유가죽 0.217 0.260 0.238
04. 석유화학 0.380 0.500 0.440
05. 비금속광물 0.267 0.270 0.268
06. 금속제품 0.183 NaN 0.183
07. 기계장비 0.917 0.440 0.678
08. 자동차 0.567 0.840 0.703
09. 식료품 0.111 0.290 0.201
10. 에너지 NaN 0.420 0.420
11. 건설 NaN 0.410 0.410
12. 운수 0.442 0.420 0.431
13. 정보통신 0.772 0.980 0.876
14. 도소매 0.433 0.410 0.422
15. 음식숙박 0.400 0.420 0.410
16. 금융 0.433 0.420 0.427
17. 연구개발업 1.100 0.800 0.950
18. 사업지원서비스 0.450 0.800 0.625
19. 교육 0.000 -0.050 -0.025
20. 보건사회 0.550 0.600 0.575
21. 문화/예술 0.433 0.420 0.427
전 산업 혁신 − 기준(8장, 세 구간 평균): 0.47%p, 구간별 {'2017~21': 0.2, '2022~26': 0.5, '2027~30': 0.7}, 11장 2016~2030: 0.47%p
설문 E4-1 객관 노출 지수 고용정보원(2017) ΔVA
설문 E4-1 1.000 0.490 0.050
객관 노출 지수 0.490 1.000 0.610
고용정보원(2017) ΔVA 0.050 0.610 1.000

설문 척도로 옮기기(대안 1b). 객관 지표는 업종 간 차이가 설문보다 훨씬 크다(정보통신의 특허 밀도는 다른 업종의 수십 배). 그대로 배분에 쓰면 효과가 한두 산업에 몰리므로, 설문이 말하는 효과의 평균과 산업 간 표준편차(부가가치 가중)는 유지하고 순위·간격만 노출 지수로 바꾼다: $a'_i = \bar a + s_a (z_i - \bar z)/s_z$.

In [7]:
z62 = np.array([zg[g] for g in grp])
a1b = I.survey_scale_shape(z62, a, base.loc[C.START].values)
print(f"62개 산업 순위상관(설문 a, 노출 a'): {R.rank_corr(a, a1b):.3f}")
62개 산업 순위상관(설문 a, 노출 a'): 0.381

3. 기존 산업모형 — 보고서1 선택 모형¶

62분류·로그차분·산업연관표 사전분포·외생 6종의 베이지언 VARX(P = 4, Q = 2, λ = 0.2)를 2000Q1–2025Q4로 적합한다(보고서1 5장 패키지와 같은 계산). 같은 모형으로 기준 시나리오(S1)를 다시 내면 드리프트 재설정 후 바텀업 합계가 보고서1 5장 표의 값(2035년 2,794조 원)과 같아야 한다.

In [8]:
s1 = pd.read_csv(C.EXOG_SCEN, encoding="utf-8-sig"); s1 = s1[s1["시나리오"] == "S1"].set_index("분기")
f_old = X.forecast_s1(L, gdp, exo, B, s1, C.ANCHOR_GROWTH, False)
bu35 = f_old.sum(axis=1).loc[C.END] / 1e3
A = X.lag_blocks(B, n)
comp_mat = np.block([[np.hstack([Al.T for Al in A])], [np.eye(n * (len(A) - 1), n * len(A))]])
eig = max(abs(np.linalg.eigvals(comp_mat)))
S = sum(A); off = ~np.eye(n, dtype=bool)
print(f"바텀업(드리프트 재설정 후) 2035년: {bu35:,.1f}조 원(보고서1 5장 표: 2,794조 원)")
print(f"동반행렬 최대 고유값 절댓값 {eig:.3f}(1보다 작아 안정), 교차 시차계수 합의 음수 비율 {(S[off] < 0).mean():.2f}, 자기 시차계수 합 평균 {np.diag(S).mean():+.3f}")
바텀업(드리프트 재설정 후) 2035년: 2,793.7조 원(보고서1 5장 표: 2,794조 원)
동반행렬 최대 고유값 절댓값 0.781(1보다 작아 안정), 교차 시차계수 합의 음수 비율 0.46, 자기 시차계수 합 평균 -0.057

4. 대안 1 — 기존 계수 고정, AI 외생 항 추가¶

기존 계수 $A_l$은 그대로 두고 AI 항 $\gamma_i x_t$만 더한다. 기준 시나리오에서는 $x_t = 0$이므로 기존 전망은 정의상 바뀌지 않는다. AI 확산 시나리오의 효과는 $\delta_t = \sum_l A_l^\top \delta_{t-l} + \gamma x_t$로 퍼지며, 누적 $D_t$를 기준 경로에 곱한다.

사전 정보를 어디에 두는가. 설문 E4-1은 2040년까지 AI가 매출에 미칠 누적 영향을 묻는다. 그래서 설문 정보는 동시항 $\gamma$가 아니라 모형의 장기 반응 $M\gamma$ ($M = (I - \sum_l A_l^\top)^{-1}$)에 둔다. 장기 반응이 설문 형태가 되도록 동시항을 $\gamma = (I - \sum_l A_l^\top)\,a$로 정하는 것이 중심 사양('장기')이다. 비교를 위해 파급 없는 현행 4장 방식('직접')과, 설문 형태를 동시항에 그대로 넣은 사양('동시항', 5절 진단)도 계산한다.

In [9]:
specs = [("현행(직접)", a, "직접", A), ("대안1a 설문·장기", a, "장기", A), ("대안1b 노출·장기", a1b, "장기", A),
         ("대안1c 고용정보원·장기", k62, "장기", A), ("참고 노출·직접", a1b, "직접", A), ("진단 설문·동시항", a, "동시항", A)]
rows, prem, paths = [], {}, {}
for lab, shape, mode, AA in specs:
    ai, p = R.scenario(base, AA, shape, xq, C.LAMBDA, mode)
    rows.append(R.summarize(lab, base, ai, p)); prem[lab] = p; paths[lab] = ai.sum(axis=1) / 1e3
summ = pd.DataFrame(rows).set_index("사양")
display(summ)
AI_2035_조 기준_2035_조 AI_CAGR 기준_CAGR 차이_%p 수준차이_조 프리미엄_최소 프리미엄_최대 음의_산업수
사양
현행(직접) 2,692.703 2,609.028 2.142 1.820 0.322 83.675 0.400 0.620 0
대안1a 설문·장기 2,690.796 2,609.028 2.135 1.820 0.315 81.768 0.393 0.624 0
대안1b 노출·장기 2,690.588 2,609.028 2.134 1.820 0.314 81.560 0.385 0.652 0
대안1c 고용정보원·장기 2,690.570 2,609.028 2.134 1.820 0.314 81.542 -0.040 0.856 1
참고 노출·직접 2,692.702 2,609.028 2.142 1.820 0.322 83.674 0.388 0.647 0
진단 설문·동시항 2,689.780 2,609.028 2.131 1.820 0.311 80.752 -0.405 0.906 9
In [10]:
P62 = pd.DataFrame(prem, index=names)
d1b = (P62["대안1b 노출·장기"] - P62["현행(직접)"]).sort_values()
print("대안1a − 현행: 최대 절댓값 %.3f%%p" % (P62["대안1a 설문·장기"] - P62["현행(직접)"]).abs().max())
print("대안1b − 현행(하향 큰 5개):", d1b.head(5).round(2).to_dict())
print("대안1b − 현행(상향 큰 5개):", d1b.tail(5).round(2).to_dict())
d1c = (P62["대안1c 고용정보원·장기"] - P62["현행(직접)"]).sort_values()
print("대안1c − 현행(하향 큰 5개):", d1c.head(5).round(2).to_dict())
print("대안1c − 현행(상향 큰 5개):", d1c.tail(5).round(2).to_dict())
대안1a − 현행: 최대 절댓값 0.052%p
대안1b − 현행(하향 큰 5개): {'56.교육서비스업': -0.14, '21.금속가공제품': -0.09, '10.가죽제품': -0.08, '9.섬유ㆍ의복': -0.08, '17.의료ㆍ의약품': -0.07}
대안1b − 현행(상향 큰 5개): {'38.창고ㆍ운송보조서비스업': 0.06, '37.항공운송업': 0.06, '49.부동산업': 0.06, '51.연구개발업': 0.07, '53.과학기술관련전문서비스업': 0.08}
대안1c − 현행(하향 큰 5개): {'56.교육서비스업': -0.62, '21.금속가공제품': -0.35, '8.담배': -0.33, '7.음료품': -0.33, '6.식료품': -0.33}
대안1c − 현행(상향 큰 5개): {'45.정보서비스업': 0.17, '42.방송업': 0.18, '40.출판업': 0.18, '51.연구개발업': 0.38, '53.과학기술관련전문서비스업': 0.38}

5. 진단 — 설문 형태를 동시항에 그대로 넣으면¶

동시항 사양에서는 효과가 기존 VARX의 교차 시차계수를 따라 퍼진다. 이 계수는 분기 성장률 사이의 단기 공행을 요약한 축약형 계수이며, 공급망 관계를 뜻하지 않는다. 교차계수 합은 산업연관 연계의 강약과 관계없이 거의 절반이 음(−)이다. 장기 배수 $M$으로 산업별 효과를 자기 몫과 다른 산업에서 온 몫으로 나누면, 음(−)의 효과가 어디에서 오는지 보인다. 분해는 현행 프리미엄(%p)과 같은 척도로 맞추었다.

In [11]:
Wt = Wio.values.T
sign =pd.DataFrame([{"산업연관 연계 분위": f"{lo:.0%}–{hi:.0%}", "교차계수 합 평균": S[m].mean(), "음수 비율": (S[m] < 0).mean()}
                     for lo, hi in [(0, .25), (.25, .5), (.5, .75), (.75, .9), (.9, 1)]
                     for m in [off & (Wt >= np.quantile(Wio.values, lo)) & (Wt <= np.quantile(Wio.values, hi))]])
display(sign)
scale = float(P62["현행(직접)"].mean() / a.mean())
dec = X.spillover_decomp(A, a * scale, names)
dec.to_csv(os.path.join(C.OUTPUT, "spillover_diag.csv"), encoding="utf-8-sig")
neg = dec[dec["합계_장기"] < 0]
display(dec.sort_values("합계_장기").head(10))
print(f"동시항 사양에서 장기 효과가 음(−)인 산업 {len(neg)}개. 가장 큰 음의 파급원:", neg["가장_큰_음의_파급원"].value_counts().to_dict())
산업연관 연계 분위 교차계수 합 평균 음수 비율
0 0%–25% 0.001 0.473
1 25%–50% 0.001 0.469
2 50%–75% 0.007 0.434
3 75%–90% 0.007 0.453
4 90%–100% -0.006 0.468
직접 자기몫_장기 파급몫_장기 합계_장기 가장_큰_음의_파급원 그_크기 가장_큰_양의_파급원
37.항공운송업 0.458 0.476 -1.111 -0.635 55.공공행정ㆍ국방 -0.411 38.창고ㆍ운송보조서비스업
14.석탄ㆍ석유제품 0.490 0.446 -1.039 -0.593 55.공공행정ㆍ국방 -1.206 9.섬유ㆍ의복
38.창고ㆍ운송보조서비스업 0.458 0.523 -1.055 -0.531 49.부동산업 -0.365 62.수리ㆍ개인서비스업
36.수상운송업 0.458 0.473 -0.888 -0.415 49.부동산업 -0.260 38.창고ㆍ운송보조서비스업
35.육상운송업 0.458 0.508 -0.873 -0.365 49.부동산업 -0.341 62.수리ㆍ개인서비스업
6.식료품 0.529 0.462 -0.650 -0.188 49.부동산업 -0.137 28.가구ㆍ기타제품
7.음료품 0.529 0.521 -0.663 -0.142 49.부동산업 -0.132 21.금속가공제품
9.섬유ㆍ의복 0.480 0.465 -0.567 -0.102 55.공공행정ㆍ국방 -0.225 46.금융업
28.가구ㆍ기타제품 0.495 0.512 -0.576 -0.064 55.공공행정ㆍ국방 -0.422 54.사업지원서비스업
10.가죽제품 0.480 0.477 -0.481 -0.004 55.공공행정ㆍ국방 -0.201 18.고무ㆍ플라스틱제품
동시항 사양에서 장기 효과가 음(−)인 산업 10개. 가장 큰 음의 파급원: {'49.부동산업': 5, '55.공공행정ㆍ국방': 5}

6. 대안 2 — AI 확산 갭을 일곱째 외생으로 넣어 다시 추정¶

6-1. 자료만으로는 얼마나 알 수 있는가. AI 동시항 계수에 정보가 없는 사전(평균 0, 분산 10⁶)을 두고 추정한 계수 $\hat g_i$와 그 정밀도를 본다. 정밀도는 방정식별 사후공분산의 AI 대각원소에서 구하므로 AI 갭과 다른 설명변수의 상관을 반영한다.

6-2. 사전분포. $\gamma_i \sim N(\beta a_i,\ \tau_i^2)$. 공통 척도 $\beta$는 $\hat g_i \approx \beta a_i$의 정밀도 가중 최소제곱(경험적 베이즈)으로 정한다. 폭은 두 가지로 둔다. ① 설문 표본오차만: $\tau_i = |\beta|\,SE_i$. ② 계층: $\tau_i^2 = (\beta SE_i)^2 + \hat\tau^2$, $\hat\tau^2$은 설문으로 설명되지 않는 산업별 차이의 적률 추정치이다. 사후평균에서 자료가 차지하는 비중은 정밀도 / (정밀도 + 1/사전분산)이다.

In [12]:
se_i = np.array([se_tab.loc[g, "se"] for g in grp])
r2 = R.alt2_estimate(L, exo, Wio, gap, a, se_i)
t_i = r2["g_data"] * np.sqrt(r2["prec"])
diag2 = {"자료_표준오차_중앙값": float(np.median(1 / np.sqrt(r2["prec"]))),
         "유의(|t|>1.96)_산업수": int((np.abs(t_i) > 1.96).sum()), "우연_기대_산업수": 0.05 * n,
         "자료계수_양수_산업수": int((r2["g_data"] > 0).sum()),
         "순위상관(자료계수,설문)": R.rank_corr(r2["g_data"], a),
         "beta": r2["beta"], "beta_표준오차": r2["beta_se"], "beta_t": r2["beta"] / r2["beta_se"], "tau2_계층": r2["tau2"]}
for nm, sp in r2["specs"].items():
    diag2[f"자료비중_최대[{nm}]"] = float(sp["data_weight"].max())
    diag2[f"사후/사전_순위상관[{nm}]"] = R.rank_corr(sp["post"], a)
diag2 = pd.Series(diag2)
display(diag2.to_frame("값"))
값
자료_표준오차_중앙값 5.657
유의(|t|>1.96)_산업수 1.000
우연_기대_산업수 3.100
자료계수_양수_산업수 31.000
순위상관(자료계수,설문) 0.354
beta 0.080
beta_표준오차 0.089
beta_t 0.902
tau2_계층 0.000
자료비중_최대[설문 표본오차] 0.000
사후/사전_순위상관[설문 표본오차] 0.998
자료비중_최대[계층(경험적 베이즈)] 0.000
사후/사전_순위상관[계층(경험적 베이즈)] 0.998
In [13]:
coef = pd.DataFrame({"설문업종": grp, "자료계수": r2["g_data"], "자료_표준오차": 1 / np.sqrt(r2["prec"]), "t": t_i,
                     "사전평균": r2["specs"]["설문 표본오차"]["prior_mean"], "사후평균": r2["specs"]["설문 표본오차"]["post"]}, index=names)
display(coef.sort_values("t"))
(비공개 설문 집계를 보여주는 셀이다. 공개 화면에서는 출력을 생략했다. 자료를 가진 경우 직접 실행하면 표시된다.)

6-3. 기존 전망은 얼마나 바뀌는가. 재추정 모형으로 기준 시나리오(미래 AI 갭 0)를 다시 내고, 보고서1 5장과 같은 비례 벤치마킹(해마다 모든 산업에 같은 배율)을 거친 뒤의 산업별 변화를 본다. 벤치마킹 후 산업별 변화는 2035년 구성비의 변화와 같다.

6-4. AI 확산 시나리오. 사후평균을 장기 효과의 형태로 두고, 재추정 계수의 동학으로 대안 1과 같은 방식('장기')으로 계산한다.

In [14]:
bc_rows, bc_ind = [], {}
for nm, sp in r2["specs"].items():
    bc, ch = R.baseline_change(L, gdp, exo, B, sp["B"], gap, s1, C.ANCHOR_GROWTH)
    bc_rows.append({"사전분포": nm} | bc); bc_ind[nm] = ch
    A2 = X.lag_blocks(sp["B"], n)
    ai, p = R.scenario(base, A2, sp["post"], xq, C.LAMBDA, "장기")
    lab = f"대안2 {nm}"
    rows.append(R.summarize(lab, base, ai, p)); prem[lab] = p; paths[lab] = ai.sum(axis=1) / 1e3
bct = pd.DataFrame(bc_rows).set_index("사전분포")
display(bct)
bci = pd.DataFrame(bc_ind)
display(bci.iloc[:, 0].sort_values().iloc[[0, 1, 2, -3, -2, -1]].to_frame("벤치마킹 후 변화(%)"))
바텀업_기존_조 바텀업_재추정_조 바텀업_변화_% 벤치마킹후_최대_% 벤치마킹후_최소_% 벤치마킹후_절대중앙_%
사전분포
설문 표본오차 2,793.745 2,786.618 -0.255 0.864 -0.298 0.120
계층(경험적 베이즈) 2,793.745 2,786.618 -0.255 0.864 -0.298 0.120
벤치마킹 후 변화(%)
4.석탄ㆍ원유ㆍ천연가스 -0.298
56.교육서비스업 -0.263
43.통신업 -0.248
38.창고ㆍ운송보조서비스업 0.554
37.항공운송업 0.656
14.석탄ㆍ석유제품 0.864

7. 산출물 저장¶

In [15]:
summ = pd.DataFrame(rows).set_index("사양")
summ.to_csv(os.path.join(C.OUTPUT, "summary_variants.csv"), encoding="utf-8-sig")
P62 = pd.DataFrame(prem, index=names)
P62.insert(0, "설문업종", grp)
P62.to_csv(os.path.join(C.OUTPUT, "premium_62_variants.csv"), encoding="utf-8-sig")
pd.DataFrame(paths).to_csv(os.path.join(C.OUTPUT, "paths_total_variants.csv"), encoding="utf-8-sig")
diag2.to_frame("값").to_csv(os.path.join(C.OUTPUT, "alt2_diagnostics.csv"), encoding="utf-8-sig")
bct.to_csv(os.path.join(C.OUTPUT, "alt2_baseline_change.csv"), encoding="utf-8-sig")
bci.to_csv(os.path.join(C.OUTPUT, "alt2_baseline_change_62.csv"), encoding="utf-8-sig")
pd.Series({"바텀업_2035_조": bu35, "최대고유값": eig, "교차계수_음수비율": float((S[off] < 0).mean())}).to_frame("값").to_csv(
    os.path.join(C.OUTPUT, "model_check.csv"), encoding="utf-8-sig")
display(summ)
print("저장:", sorted(f for f in os.listdir(C.OUTPUT) if f.endswith(".csv")))
AI_2035_조 기준_2035_조 AI_CAGR 기준_CAGR 차이_%p 수준차이_조 프리미엄_최소 프리미엄_최대 음의_산업수
사양
현행(직접) 2,692.703 2,609.028 2.142 1.820 0.322 83.675 0.400 0.620 0
대안1a 설문·장기 2,690.796 2,609.028 2.135 1.820 0.315 81.768 0.393 0.624 0
대안1b 노출·장기 2,690.588 2,609.028 2.134 1.820 0.314 81.560 0.385 0.652 0
대안1c 고용정보원·장기 2,690.570 2,609.028 2.134 1.820 0.314 81.542 -0.040 0.856 1
참고 노출·직접 2,692.702 2,609.028 2.142 1.820 0.322 83.674 0.388 0.647 0
진단 설문·동시항 2,689.780 2,609.028 2.131 1.820 0.311 80.752 -0.405 0.906 9
대안2 설문 표본오차 2,690.798 2,609.028 2.135 1.820 0.315 81.770 0.393 0.624 0
대안2 계층(경험적 베이즈) 2,690.798 2,609.028 2.135 1.820 0.315 81.770 0.393 0.624 0
저장: ['ai_exposure_21.csv', 'ai_index_quarterly.csv', 'alt2_baseline_change.csv', 'alt2_baseline_change_62.csv', 'alt2_diagnostics.csv', 'exposure_rank_corr.csv', 'keis_r14_dva_21.csv', 'keis_r14_total.csv', 'model_check.csv', 'paths_total_variants.csv', 'premium_62_variants.csv', 'spillover_diag.csv', 'summary_variants.csv', 'table1_variants.csv', 'table2_baseline_change.csv', 'table3_premium_diff.csv', 'triangulation_rank_corr.csv', 'verification.csv']