01 데이터 입수 — 국민계정 36개 산업, 산업연관표, 신산업 대용지표¶

목적. 62·69개 산업 분기 실질부가가치 패널과 연쇄가중 총량 재현에 필요한 공개 자료를 불러오고 검증한다. 기본 실행은 data/inputs/의 스냅샷(2026년 6–8월 수집, 2026-10-08 원천 재수집 대조 — 6절 참조)만 읽으므로 인증키와 인터넷 연결이 필요 없다.

입력 내용 원천(통계표·항목) 기간
bok36_va_q.csv 36개 산업 분기 실질·명목 부가가치(계절조정, 십억원) 한국은행 ECOS 200Y104(실질)·200Y103(명목) 1980Q1–2025Q4
gva_total_q.csv 총부가가치(기초가격, 실질, 계절조정) ECOS 200Y104 항목 1200 1980Q1–2025Q4
gdp_quarterly_sa.csv 국내총생산(지출, 계절조정, 명목·실질) ECOS 200Y107·200Y108 항목 10601 1980Q1–2025Q4
io_benchmark_va_83ind.csv 상품중분류(83) 부가가치(백만원) ECOS 271Y120 부가가치계(9690) 2015·2020
io_M_mid_2020.csv 중분류 생산유발계수(85×85) ECOS 271Y122 2020
io_small_37x_va.csv 통합소분류 37x(전기장비) 부가가치(백만원) 한국은행 산업연관표 2020 실측표·2021–2023 연장표(xlsx) 2020–2023
mfg_prod_c28_c282.csv 생산지수(원지수) 전기장비(C28)·일차전지 및 축전지(C282) KOSIS 101/DT_1F02001 항목 T10 2000.01–2026.04
power_gen_kpx.csv 발전량: 신재생 및 기타·합계(GWh) KOSIS 388/TX_38803_A016A(한국전력거래소) 2006–2016
power_gen_kepco.csv 발전원별 발전량 6종(GWh) 한국전력공사 전력통계(e-나라지표 1339) 2016–2025

설계표 data/crosswalk_62.json(KEIT62 ↔ BOK36 ↔ IO 상품중분류 83)과 data/carveout_rules.csv(62→69 분화 규칙)는 본 연구가 작성한 표이다.

산출물. data/interim/va36_real_q.csv, va36_nominal_q.csv(36개 산업 광형), snapshot_check.csv, (ONLINE=1일 때) online_diff.csv

스위치. 환경변수 ONLINE=1이면 6절에서 ECOS·KOSIS를 다시 조회해 스냅샷과 비교한다. 인증키는 API_KEY_BOK, API_KEY_KOSIS 환경변수에서만 읽는다.

In [1]:
import os, glob
import numpy as np, pandas as pd
import config as C
import gva_data as F
pd.set_option("display.float_format", lambda v: f"{v:,.4f}")
pd.set_option("display.width", 160)
C.setup()
Python 3.12.10 · pandas 2.2.3 · numpy 2.4.6
  ONLINE=0 (원천 재수집)  FULL=0  ECOS 키 없음 · KOSIS 키 없음
  36개 산업 분기      있음  data\inputs\bok36_va_q.csv
  총부가가치          있음  data\inputs\gva_total_q.csv
  실질 GDP         있음  data\inputs\gdp_quarterly_sa.csv
  IO 중분류 부가가치    있음  data\inputs\io_benchmark_va_83ind.csv
  IO 생산유발계수      있음  data\inputs\io_M_mid_2020.csv
  IO 소분류 37x     있음  data\inputs\io_small_37x_va.csv
  생산지수 C28·C282  있음  data\inputs\mfg_prod_c28_c282.csv
  발전량 KPX        있음  data\inputs\power_gen_kpx.csv
  발전량 KEPCO      있음  data\inputs\power_gen_kepco.csv
  대조표 62         있음  data\crosswalk_62.json
  분화 규칙 69       있음  data\carveout_rules.csv

1. 스냅샷 무결성¶

각 입력 파일의 SHA-256을 config.INPUT_SHA256에 기록한 값과 대조한다. 하나라도 다르면 이후 계산 결과가 공표본과 달라질 수 있으므로 여기서 멈춘다.

In [2]:
files = {"36개 산업 분기": C.VA36, "총부가가치": C.GVA_TOTAL, "실질 GDP": C.GDP_Q, "IO 중분류 부가가치": C.IO_VA83,
         "IO 생산유발계수": C.IO_M, "IO 소분류 37x": C.IO_SMALL, "생산지수 C28·C282": C.MFG_PROD,
         "발전량 KPX": C.POWER_KPX, "발전량 KEPCO": C.POWER_KEPCO, "대조표 62": C.CROSSWALK, "분화 규칙 69": C.CARVE_RULES}
snap = F.snapshot_table(files, C.INPUT_SHA256)
snap.to_csv(os.path.join(C.INTERIM, "snapshot_check.csv"), index=False, encoding="utf-8-sig")
assert snap["기록값과 일치"].all(), "스냅샷 SHA-256이 기록값과 다르다 — data/inputs/ 파일을 확인한다"
snap
Out[2]:
파일 내용 바이트 행수 SHA-256(앞 16자) 기록값과 일치
0 bok36_va_q.csv 36개 산업 분기 377192 6624 be93329c14b1ea65 True
1 gva_total_q.csv 총부가가치 3135 184 4087e14e8d461c59 True
2 gdp_quarterly_sa.csv 실질 GDP 6242 184 3adbc832b93488c3 True
3 io_benchmark_va_83ind.csv IO 중분류 부가가치 7463 206 24a07dfdbc388f6e True
4 io_M_mid_2020.csv IO 생산유발계수 111783 7225 af8a6514e0ddd90c True
5 io_small_37x_va.csv IO 소분류 37x 3081 24 46f72bff6388a9ee True
6 mfg_prod_c28_c282.csv 생산지수 C28·C282 33618 632 1af50c079edd888e True
7 power_gen_kpx.csv 발전량 KPX 249 11 4c05ae3809eb8879 True
8 power_gen_kepco.csv 발전량 KEPCO 490 10 81fb52b2499a2ce3 True
9 crosswalk_62.json 대조표 62 4674 <NA> 09c137303ab59970 True
10 carveout_rules.csv 분화 규칙 69 879 7 59b7fb2688cec105 True

2. 36개 산업 분기 실질·명목 부가가치¶

한국은행 「경제활동별 GDP 및 GNI」(계절조정, 분기)의 말단 산업 36개이다. 실질은 2020년 기준 연쇄가격이다. 상위 집계(제조업·서비스업 등)와 소득 항목(총부가가치·GDP·GNI)은 제외하였다. 36개 산업이 모두 존재하는 첫 분기가 1980Q1이므로 결측이 없는 균형 패널을 이룬다. 수집 당시 2026Q1 계절조정 명목 GDP가 직전 분기보다 10.5% 높은 비정상값을 보여 표본을 2025Q4에서 끊었다(원 수집 코드 fetch_gdp_quarterly.py의 기록). 62·69 패널은 이 가운데 2000Q1–2025Q4(104분기)의 실질값만 쓰고, 연쇄가중 재현(02의 7절)은 1980Q1부터의 실질·명목을 모두 쓴다.

In [3]:
real, nom, names = F.read_va36(C.VA36)
print(f"실질 {real.shape} · 명목 {nom.shape} · 기간 {real.index[0]}–{real.index[-1]} · 결측 {int(real.isna().sum().sum() + nom.isna().sum().sum())}")
assert real.shape == (184, 36) and nom.shape == (184, 36) and not real.isna().any().any()
real.to_csv(os.path.join(C.INTERIM, "va36_real_q.csv"), encoding="utf-8-sig")
nom.to_csv(os.path.join(C.INTERIM, "va36_nominal_q.csv"), encoding="utf-8-sig")
last = pd.DataFrame({"산업명": pd.Series(names), "실질 2025Q4": real.loc["2025Q4"], "명목 2025Q4": nom.loc["2025Q4"],
                     "실질 2000Q1": real.loc["2000Q1"]})
last.index.name = "ECOS 코드"
last.head(12)
실질 (184, 36) · 명목 (184, 36) · 기간 1980Q1–2025Q4 · 결측 0
Out[3]:
산업명 실질 2025Q4 명목 2025Q4 실질 2000Q1
ECOS 코드
1101 농림어업 8,373.6000 9,686.2000 7,369.2000
1102 광업 339.3000 402.3000 778.0000
110301 음식료품 제조업 7,990.9000 9,148.5000 4,215.3000
110302 섬유 및 가죽제품 제조업 3,732.1000 4,073.9000 4,651.3000
110303 목재, 종이, 인쇄 및 복제업 3,273.7000 3,952.5000 2,868.4000
110304 코크스 및 석유정제품 제조업 2,427.6000 4,780.0000 6,051.7000
110305 화학물질 및 화학제품 제조업 24,256.2000 27,003.9000 9,878.1000
110306 비금속광물제품 제조업 2,271.9000 3,051.3000 1,822.3000
110307 1차금속 제조업 5,973.8000 9,942.3000 4,991.5000
110308 금속가공제품 제조업 6,310.6000 11,815.7000 4,579.5000
110309 컴퓨터, 전자 및 광학기기 제조업 61,268.0000 72,310.8000 5,389.9000
110310 전기장비 제조업 8,512.3000 10,015.8000 3,233.5000

3. 총량 계열 — 총부가가치와 국내총생산¶

연쇄가중 실질값은 가법성이 없다. 36개 산업 실질값을 단순히 더한 값은 기준연도(2020) 부근에서만 총부가가치와 같고, 기준연도에서 멀어질수록 차이가 커진다. 국내총생산은 총부가가치에 순생산물세를 더한 값이다. 실질 GDP는 총량 모형의 입력 패널(levels_agg.csv)이 된다.

In [4]:
gva = F.read_gva_total(C.GVA_TOTAL)
gdp = F.read_gdp(C.GDP_Q)
show = ["1980Q1", "2000Q1", "2010Q1", "2020Q1", "2025Q4"]
pd.DataFrame({"36개 단순합": real.sum(axis=1), "총부가가치(1200)": gva, "실질 GDP(10601)": gdp["실질GDP_십억원"]}).loc[show]
Out[4]:
36개 단순합 총부가가치(1200) 실질 GDP(10601)
분기
1980Q1 52,579.1000 43,120.7000 47,272.0000
2000Q1 233,441.0000 220,819.8000 243,573.1000
2010Q1 358,568.4000 354,510.9000 386,238.5000
2020Q1 475,917.8000 475,788.6000 517,226.9000
2025Q4 549,415.1000 543,908.0000 585,964.0000

4. 산업연관표(2020 실측표)¶

  • 상품중분류 83개 부가가치(271Y120): 36→62 배분과 62→69 고정 몫의 기준이다. 표의 열(수요부문 1–83)별 '부가가치계'(9690) 행 값이다.
  • 중분류 생산유발계수(271Y122): 산업모형의 산업연관 사전(prior)에 쓰는 62·69 연계강도 행렬의 원자료이다.
  • 통합소분류 37x 부가가치: 전기장비(37) 안의 전지(373) 비중을 구해 이차전지 몫의 수준을 맞춘다. ECOS Open API는 소분류 표를 제공하지 않으므로 한국은행 산업연관표 xlsx에서 추출한 값을 스냅샷으로 둔다.
In [5]:
io = F.read_io_va83(C.IO_VA83)
M = pd.read_csv(C.IO_M)
small = pd.read_csv(C.IO_SMALL, dtype={"소분류코드": str})
print(f"IO83 부가가치(2020): {len(io)}개 상품 · 합계 {io.sum()/1e6:,.1f}조원 · 0인 상품 {list(io[io == 0].index)}")
print(f"생산유발계수: {M['i'].nunique()}×{M['j'].nunique()} · 대각 평균 {M[M.i == M.j]['v'].mean():.3f}")
small.pivot(index=["소분류코드", "소분류명"], columns="연도", values="부가가치_백만원")
IO83 부가가치(2020): 83개 상품 · 합계 2,036.2조원 · 0인 상품 [83]
생산유발계수: 85×85 · 대각 평균 1.071
Out[5]:
연도 2020 2021 2022 2023
소분류코드 소분류명
371 발전기 및 전동기 2553718 2928477 3467250 3272707
372 전기변환.공급제어장치 8899299 8782292 9408848 10641695
373 전지 5752407 6424953 7674703 7441610
374 전선 및 케이블 2241154 2706742 2845949 2641273
375 가정용 전기기기 4954564 4490541 5012941 5278263
379 기타 전기장비 7272675 6803946 7329982 8389264

5. 신산업 대용지표 — 생산지수와 발전량¶

이차전지와 신재생에너지는 산업연관표 상품중분류에 독립 코드가 없어 시계열 몫을 따로 만든다.

  • 이차전지: 광업제조업동향조사 생산지수(원지수) C282(일차전지 및 축전지)/C28(전기장비) 비율이 시간적 형태를 준다.
  • 신재생에너지: 신재생 발전량/총발전량. 2006–2015년은 한국전력거래소(KOSIS 388/TX_38803_A016A)의 '신재생 및 기타'/'합계', 2016–2025년은 한국전력공사 전력통계(e-나라지표 1339)의 발전원별 발전량 6종 합계를 쓴다. 두 원천은 2016년 신재생 25,837 GWh(KPX)와 25,836 GWh(KEPCO)로 거의 같다.
In [6]:
mfg = F.read_mfg_prod(C.MFG_PROD)
kpx, kepco = pd.read_csv(C.POWER_KPX), pd.read_csv(C.POWER_KEPCO)
print(f"생산지수: {mfg.index[0]}–{mfg.index[-1]} ({len(mfg)}개월) · 결측 {int(mfg.isna().sum().sum())}")
k16, e16 = kpx.set_index("연도").loc[2016], kepco.set_index("연도").loc[2016]
print(f"2016년 접합 점검: KPX 신재생 {k16['신재생및기타_GWh']:,} / 합계 {k16['합계_GWh']:,} GWh · "
      f"KEPCO 신재생 {e16['신재생']:,} / 합계 {int(e16[['원자력','양수','석탄','유류','가스','신재생']].sum()):,} GWh")
mfg.loc[["2000-01-01", "2010-01-01", "2020-01-01", "2025-12-01"]]
생산지수: 2000-01-01–2026-04-01 (316개월) · 결측 0
2016년 접합 점검: KPX 신재생 25,837 / 합계 540,441 GWh · KEPCO 신재생 25,836 / 합계 540,440 GWh
Out[6]:
ksic C28 C282
date
2000-01-01 59.0560 8.9690
2010-01-01 86.6710 75.0080
2020-01-01 92.6000 96.4000
2025-12-01 114.3000 95.1000

6. 원천 재수집과 대조(ONLINE=1)¶

ECOS·KOSIS Open API로 같은 통계표를 다시 받아 스냅샷과 공통 관측을 비교한다. 한국은행·통계청은 과거 계열을 수정 공표하므로 차이가 생길 수 있으며, 차이는 보고만 하고 실행을 멈추지 않는다. 전력통계(e-나라지표 1339)는 Open API가 없어 대조 대상에서 제외한다. 재수집 자료는 data/interim/online_*.csv로 저장하며, 02의 8절이 이 자료로 62 패널과 이차전지 몫을 다시 계산해 차이를 보인다.

In [7]:
if not C.ONLINE:
    print("ONLINE=0 — 스냅샷만 사용한다. 원천과 대조하려면 ONLINE=1과 API_KEY_BOK·API_KEY_KOSIS 환경변수를 설정한 뒤 다시 실행한다.")
else:
    rows = []
    def attempt(label, fn):
        try:
            rows.append(fn())
        except Exception as e:
            rows.append({"항목": label, "비고": f"재수집 실패: {str(e)[:80]}"})
    if not C.API_KEY_BOK:
        rows.append({"항목": "ECOS 전체", "비고": "API_KEY_BOK 없음 — 건너뜀"})
    else:
        def va36():
            r2, n2, g2 = F.fetch_va36_online(C.API_KEY_BOK, list(real.columns))
            r2.to_csv(os.path.join(C.INTERIM, "online_va36_real_q.csv"), encoding="utf-8-sig")
            rows.append(F.diff_summary("36개 산업 명목(200Y103)", nom, n2))
            rows.append(F.diff_summary("총부가가치(200Y104·1200)", gva.to_frame("v"), g2.to_frame("v")))
            return F.diff_summary("36개 산업 실질(200Y104)", real, r2)
        attempt("36개 산업(200Y103·200Y104)", va36)
        attempt("실질 GDP(200Y108)", lambda: F.diff_summary("실질 GDP(200Y108)", gdp[["실질GDP_십억원"]], F.fetch_gdp_online(C.API_KEY_BOK).to_frame()))
        attempt("IO83 부가가치(271Y120)", lambda: F.diff_summary("IO83 부가가치(271Y120)", io.to_frame("v"), F.fetch_io_va83_online(C.API_KEY_BOK).to_frame("v")))
        attempt("생산유발계수(271Y122)", lambda: F.diff_summary("생산유발계수(271Y122)", M.pivot(index="i", columns="j", values="v"),
                                                          F.fetch_io_M_online(C.API_KEY_BOK).pivot(index="i", columns="j", values="v")))
    if not C.API_KEY_KOSIS:
        rows.append({"항목": "KOSIS 전체", "비고": "API_KEY_KOSIS 없음 — 건너뜀"})
    else:
        def mfg_online():
            m2 = F.fetch_mfg_prod_online(C.API_KEY_KOSIS)
            m2.to_csv(os.path.join(C.INTERIM, "online_mfg_prod.csv"), encoding="utf-8-sig")
            return F.diff_summary("생산지수 C28·C282(DT_1F02001)", mfg, m2)
        attempt("생산지수(DT_1F02001)", mfg_online)
        attempt("발전량 KPX(TX_38803_A016A)", lambda: F.diff_summary("발전량 KPX(TX_38803_A016A)", kpx.set_index("연도"),
                                                                  F.fetch_kpx_online(C.API_KEY_KOSIS).set_index("연도")))
    diff = pd.DataFrame(rows)
    diff.to_csv(os.path.join(C.INTERIM, "online_diff.csv"), index=False, encoding="utf-8-sig")
    display(diff)
ONLINE=0 — 스냅샷만 사용한다. 원천과 대조하려면 ONLINE=1과 API_KEY_BOK·API_KEY_KOSIS 환경변수를 설정한 뒤 다시 실행한다.

7. (선택) 산업연관표 통합소분류 원본 재추출¶

한국은행 산업연관표 「투입산출표(생산자가격) 통합소분류」 xlsx 4개(2020 실측, 2021–2023 연장)를 data/external/에 두면 37x 부가가치를 다시 추출해 스냅샷과 대조한다. 파일이 없으면 이 절을 건너뛴다. 파일명 형식은 config.IO_SMALL_XLSX에 있다.

In [8]:
found = {y: sorted(glob.glob(os.path.join(C.EXTERNAL, pat))) for y, pat in C.IO_SMALL_XLSX.items()}
if not all(found.values()):
    print("data/external/ 에 통합소분류 xlsx가 없어 건너뛴다(스냅샷 io_small_37x_va.csv 사용).")
else:
    ext = F.extract_io_small_xlsx({y: f[0] for y, f in found.items()})
    m = ext.merge(small, on=["연도", "소분류코드"], suffixes=("_원본", "_스냅샷"))
    print(f"대조 {len(m)}행 · 최대 차이 {(m['부가가치_백만원_원본'] - m['부가가치_백만원_스냅샷']).abs().max()} 백만원")
data/external/ 에 통합소분류 xlsx가 없어 건너뛴다(스냅샷 io_small_37x_va.csv 사용).

8. 산출물¶

다음 노트북(02_분석.ipynb)은 data/interim/의 36개 산업 광형 파일과 data/inputs/의 나머지 스냅샷을 읽는다.

In [9]:
for f in sorted(os.listdir(C.INTERIM)):
    p = os.path.join(C.INTERIM, f)
    print(f"{f:<28} {os.path.getsize(p):>9,d} bytes")
snapshot_check.csv                 830 bytes
va36_nominal_q.csv              47,341 bytes
va36_real_q.csv                 48,741 bytes