{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 논문 1 · 챕터 2 — 산업연관표(I-O) 프라이어 설계\n",
    "\n",
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/sdkparkforbi/gva-scenario-2025-2035/blob/main/ch2/code/ch2_io_prior.ipynb)\n",
    "\n",
    "> **Google Colab에서 바로 실행**됩니다. 배지를 누른 뒤 `런타임 → 모두 실행`.\n",
    "> 데이터는 아래 셀에서 자동으로 내려받고, 그림은 셀 실행 시 바로 표시됩니다.\n",
    "\n",
    "각 셀에는 **셀 번호 · 셀 제목**이 달려 있고, 코드에는 줄별 **주석**을 넣었습니다."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 0. 준비 — Colab 환경과 데이터"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 1 · 한글 폰트 (koreanize-matplotlib) =====\n",
    "# 그림의 한글이 깨지지 않도록 koreanize-matplotlib 를 설치하고 불러옵니다.\n",
    "# import 하는 순간 matplotlib 한글 폰트가 자동 설정됩니다.\n",
    "_font_ok = False\n",
    "try:\n",
    "    import koreanize_matplotlib                       # 이미 설치돼 있으면 바로 사용\n",
    "    _font_ok = True\n",
    "except Exception:\n",
    "    try:\n",
    "        import subprocess, sys\n",
    "        subprocess.run([sys.executable,'-m','pip','install','-q','koreanize-matplotlib'], check=False)\n",
    "        import koreanize_matplotlib                   # 설치 후 다시 불러오기\n",
    "        _font_ok = True\n",
    "    except Exception:\n",
    "        _font_ok = False\n",
    "if not _font_ok:                                      # 폴백: 나눔폰트 직접 설치·등록\n",
    "    import subprocess\n",
    "    subprocess.run(['apt-get','-qq','-y','install','fonts-nanum'], check=False)\n",
    "    import matplotlib.font_manager as fm, matplotlib.pyplot as plt\n",
    "    _p = '/usr/share/fonts/truetype/nanum/NanumGothic.ttf'\n",
    "    try:\n",
    "        fm.fontManager.addfont(_p)\n",
    "        plt.rcParams['font.family'] = fm.FontProperties(fname=_p).get_name()  # 실제 등록 이름 사용\n",
    "    except Exception: pass\n",
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams['axes.unicode_minus'] = False           # 마이너스 기호 깨짐 방지\n",
    "print('한글 폰트 준비 완료')"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 2 · 데이터 다운로드 =====\n",
    "# 이 챕터의 입력 데이터를 서버에서 로컬 data/ 폴더로 내려받습니다.\n",
    "import os, urllib.request, urllib.parse\n",
    "BASE = \"https://aiforalab.com/gva-scenario-2025-2035/ch2/data/\"          # 서버의 이 챕터 데이터 폴더\n",
    "FILES = [\"dlog_rates_sa.csv\", \"io_linkage_W.csv\", \"io_mapping.csv\", \"io_prior_omega.csv\", \"io_production_inducement_long.csv\"]\n",
    "os.makedirs(\"data\", exist_ok=True)\n",
    "for f in FILES:                                      # 한글 파일명은 URL 인코딩 후 요청\n",
    "    urllib.request.urlretrieve(BASE + urllib.parse.quote(f), os.path.join('data', f))\n",
    "print('다운로드 완료:', len(FILES), '개 ->', sorted(os.listdir('data')))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 방법 구현과 계산"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 3 · 라이브러리 임포트·설정 =====\n",
    "import os\n",
    "import numpy as np, pandas as pd\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.colors import LogNorm, TwoSlopeNorm"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 4 · Colab 경로: 데이터=data/, 그림=figures/ =====\n",
    "# ----- Colab 경로: 데이터=data/, 그림=figures/ -----\n",
    "import os\n",
    "DATA = \"data\"; PREP = \"data\"; FIG = \"figures\"; OUT = \"figures\"\n",
    "os.makedirs(\"data\", exist_ok=True); os.makedirs(\"figures\", exist_ok=True)\n",
    "\n",
    "plt.rcParams[\"axes.unicode_minus\"] = False\n",
    "plt.rcParams[\"savefig.dpi\"] = 130"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 5 · 36 GDP 산업 순서 =====\n",
    "# --- 36 GDP 산업 순서 ---\n",
    "rate = pd.read_csv(os.path.join(DATA, \"dlog_rates_sa.csv\"), encoding=\"utf-8-sig\", index_col=0)\n",
    "inds = [c for c in rate.columns if c != \"총량GDP\"]\n",
    "assert len(inds) == 36"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 6 · 부문 매핑 (GDP 산업 → I-O 코드) =====\n",
    "# --- 부문 매핑 (GDP 산업 → I-O 코드) ---\n",
    "MAP = {\n",
    " \"농림어업\": [\"A\"], \"광업\": [\"B\"],\n",
    " \"음식료품 제조업\": [\"C01\"], \"섬유 및 가죽제품 제조업\": [\"C02\"],\n",
    " \"목재, 종이, 인쇄 및 복제업\": [\"C03\"], \"코크스 및 석유정제품 제조업\": [\"C04\"],\n",
    " \"화학물질 및 화학제품 제조업\": [\"C05\"], \"비금속광물제품 제조업\": [\"C06\"],\n",
    " \"1차금속 제조업\": [\"C07\"], \"금속가공제품 제조업\": [\"C08\"],\n",
    " \"컴퓨터, 전자 및 광학기기 제조업\": [\"C09\"], \"전기장비 제조업\": [\"C10\"],\n",
    " \"기계 및 장비 제조업\": [\"C11\"], \"운송장비 제조업\": [\"C12\"],\n",
    " \"기타 제조업 및 산업용 장비 수리업\": [\"C13\", \"C14\"],\n",
    " \"전기업\": [\"D\"], \"가스, 증기 및 공기조절 공급업\": [\"D\"],\n",
    " \"수도, 하수 및 폐기물 처리, 원료 재생업\": [\"E\"],\n",
    " \"주거용 건물 건설업\": [\"F\"], \"비주거용 건물 건설업\": [\"F\"], \"토목건설업\": [\"F\"], \"건축보수업\": [\"F\"],\n",
    " \"도소매업\": [\"G\"], \"숙박 및 음식점업\": [\"I\"], \"운수업\": [\"H\"],\n",
    " \"금융 및 보험업\": [\"K\"], \"부동산업\": [\"L\"],\n",
    " \"통신업\": [\"J\"], \"출판, 방송, 영상, 정보서비스\": [\"J\"],\n",
    " \"전문, 과학 및 기술관련 서비스업\": [\"M\"], \"사업지원 서비스업\": [\"N\"],\n",
    " \"공공행정, 국방 및 사회보장\": [\"O\"], \"교육서비스업\": [\"P\"],\n",
    " \"의료, 보건업 및 사회복지서비스업\": [\"Q\"],\n",
    " \"예술, 스포츠 및 여가관련 서비스업\": [\"R\"], \"기타 서비스업\": [\"S\"],\n",
    "}\n",
    "missing = [i for i in inds if i not in MAP]\n",
    "assert not missing, f\"매핑 누락: {missing}\""
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 7 · 생산유발계수 행렬 M (최신연도) =====\n",
    "# --- 생산유발계수 행렬 M (최신연도) ---\n",
    "io = pd.read_csv(os.path.join(DATA, \"io_production_inducement_long.csv\"), encoding=\"utf-8-sig\")\n",
    "yr = io[\"연도\"].max()\n",
    "io = io[io[\"연도\"] == yr]\n",
    "M = io.pivot_table(index=\"행코드_i\", columns=\"열코드_j\", values=\"값\", aggfunc=\"mean\")"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 8 · 36x36 연계강도 W  (W[a,b] = j(=b) 가 i(=a) 를 유발하는 강 =====\n",
    "# --- 36x36 연계강도 W  (W[a,b] = j(=b) 가 i(=a) 를 유발하는 강도) ---\n",
    "n = 36\n",
    "W = np.zeros((n, n))\n",
    "for a, ia in enumerate(inds):\n",
    "    for b, ib in enumerate(inds):\n",
    "        vals = [M.loc[ri, cj] for ri in MAP[ia] for cj in MAP[ib]\n",
    "                if ri in M.index and cj in M.columns]\n",
    "        W[a, b] = np.mean(vals) if vals else 0.0\n",
    "Wdf = pd.DataFrame(W, index=inds, columns=inds)"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 9 · ω : 미네소타 차등화 계수 (오프대각 평균 1, 하한 0.05) =====\n",
    "# --- ω : 미네소타 차등화 계수 (오프대각 평균 1, 하한 0.05) ---\n",
    "off = ~np.eye(n, dtype=bool)\n",
    "omega = W / W[off].mean()          # 오프대각 평균 = 1\n",
    "omega = np.clip(omega, 0.2, 5.0)   # 극단치 제한(안정)·순위 보존\n",
    "np.fill_diagonal(omega, 1.0)        # 자기항은 표준 미네소타\n",
    "Odf = pd.DataFrame(omega, index=inds, columns=inds)"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 10 · 저장 =====\n",
    "# --- 저장 ---\n",
    "Wdf.round(4).to_csv(os.path.join(DATA, \"io_linkage_W.csv\"), encoding=\"utf-8-sig\")\n",
    "Odf.round(4).to_csv(os.path.join(DATA, \"io_prior_omega.csv\"), encoding=\"utf-8-sig\")\n",
    "pd.DataFrame({\"GDP산업\": list(MAP), \"IO코드\": [\",\".join(v) for v in MAP.values()]}).to_csv(\n",
    "    os.path.join(DATA, \"io_mapping.csv\"), index=False, encoding=\"utf-8-sig\")"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 11 · 검증 출력 =====\n",
    "# --- 검증 출력 ---\n",
    "def short(s): return (s.replace(\" 제조업\", \"\").replace(\" 및 \", \"·\").replace(\"서비스업\", \"서비스\"))[:9]"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 12 · 결과 출력 =====\n",
    "print(f\"생산유발계수 기준연도: {yr}  | 부문 매핑 36/36 완료 (누락 없음)\")\n",
    "Woff = Wdf.where(off)\n",
    "top = Woff.stack().sort_values(ascending=False).head(8)\n",
    "print(\"\\n[연계강도 상위 8쌍  (j → i)]\")\n",
    "for (i, j), v in top.items():\n",
    "    print(f\"  {v:6.2f}   {short(j)}  →  {short(i)}\")\n",
    "ce = Wdf.loc[\"전기장비 제조업\", \"컴퓨터, 전자 및 광학기기 제조업\"]\n",
    "print(f\"\\n검증) 컴퓨터·전자 → 전기장비 연계 = {ce:.2f}  (챕터1 예제쌍, 상호 강함 기대)\")\n",
    "print(f\"ω 범위: {omega[off].min():.3f} ~ {omega[off].max():.3f}  (오프대각 평균 {omega[off].mean():.3f})\")\n",
    "print(f\"ω<0.5(강수축) 쌍 비율: {(omega[off]<0.5).mean()*100:.0f}%   ω>2(느슨) 쌍 비율: {(omega[off]>2).mean()*100:.0f}%\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 결과와 그림"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ===== 셀 13 · 그림: (a) 연계강도 W  (b) prior 차등화 ω =====\n",
    "# --- 그림: (a) 연계강도 W  (b) prior 차등화 ω ---\n",
    "lab = [short(s) for s in inds]\n",
    "fig, ax = plt.subplots(1, 2, figsize=(16, 8))\n",
    "fig.suptitle(f\"그림 1. I-O prior 설계 — 산업연관표(생산유발계수 {yr})로 미네소타 수축을 차등화\",\n",
    "             fontsize=14, fontweight=\"bold\")\n",
    "Wp = W.copy(); Wp[Wp <= 0] = np.nan\n",
    "im0 = ax[0].imshow(Wp, cmap=\"YlOrRd\", norm=LogNorm(vmin=max(1e-2, np.nanmin(Wp)), vmax=np.nanmax(Wp)), aspect=\"auto\")\n",
    "ax[0].set_title(\"(a) 연계강도 W (생산유발, 로그색)\\n열 j → 행 i 유발\")\n",
    "im1 = ax[1].imshow(omega, cmap=\"RdBu_r\", norm=TwoSlopeNorm(1.0, omega[off].min(), min(4, omega[off].max())), aspect=\"auto\")\n",
    "ax[1].set_title(\"(b) prior 차등화 ω (붉음=느슨/연계강, 청=수축/연계약)\\n미네소타 대비 교차항 배분\")\n",
    "for a_ in ax:\n",
    "    a_.set_xticks(range(n)); a_.set_xticklabels(lab, rotation=90, fontsize=5)\n",
    "    a_.set_yticks(range(n)); a_.set_yticklabels(lab, fontsize=5)\n",
    "fig.colorbar(im0, ax=ax[0], shrink=.8, pad=.02); fig.colorbar(im1, ax=ax[1], shrink=.8, pad=.02)\n",
    "fig.tight_layout(rect=[0, 0, 1, 0.95])\n",
    "fig.savefig(os.path.join(FIG, \"fig1_io_prior_design.png\"), bbox_inches=\"tight\")\n",
    "print(\"\\n저장: ch2/data/(W, ω, mapping, 입력사본), ch2/figures/fig1_io_prior_design.png\")"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "ch2_io_prior.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}