{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 대성고 2차시 — AI 두뇌 실험실\n",
        "## 70% 학생 탐구형 Lab: 결정 트리 + 신경망\n",
        "\n",
        "오늘 수업은 강사가 오래 설명하는 방식이 아닙니다.\n",
        "\n",
        "> **짧게 듣고 → 직접 바꾸고 → 결과를 비교하고 → 한 줄로 설명하는 수업**입니다.\n",
        "\n",
        "오늘의 한 문장:\n",
        "\n",
        "> **AI는 데이터를 보고 경계를 배운다.**\n",
        "\n",
        "마지막 결론:\n",
        "\n",
        "> **좋은 AI는 무조건 큰 모델이 아니라, 문제에 맞는 모델이다.**"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 오늘의 실험 규칙\n",
        "\n",
        "1. 코드를 전부 외우려고 하지 않습니다.\n",
        "2. 바꿔보라고 표시된 값만 먼저 바꿉니다.\n",
        "3. `train_accuracy`보다 `test_accuracy`를 더 중요하게 봅니다.\n",
        "4. 숫자만 보지 말고, **경계 그림이 자연스러운지** 봅니다.\n",
        "5. 결과는 팀별로 한 줄 결론으로 남깁니다.\n",
        "\n",
        "Colab에서 막히면 먼저 확인하세요.\n",
        "\n",
        "- 위쪽 셀을 먼저 실행했는가?\n",
        "- 셀을 `Shift + Enter`로 실행했는가?\n",
        "- 그래프가 늦게 뜨는 중은 아닌가?\n",
        "\n",
        "그래프 제목은 Colab 폰트 경고를 피하려고 영어로 표시합니다. 한글 설명은 `print()`로 나옵니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 0. 준비물 불러오기\n",
        "\n",
        "아래 셀은 오늘 쓸 도구를 불러옵니다. 일단 실행하세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import warnings\n",
        "warnings.filterwarnings('ignore')\n",
        "\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "from sklearn.model_selection import train_test_split\n",
        "from sklearn.tree import DecisionTreeClassifier, plot_tree\n",
        "from sklearn.neural_network import MLPClassifier\n",
        "from sklearn.datasets import make_moons, make_circles\n",
        "from sklearn.pipeline import make_pipeline\n",
        "from sklearn.preprocessing import StandardScaler\n",
        "from sklearn.metrics import accuracy_score\n",
        "\n",
        "np.random.seed(42)\n",
        "print('준비 완료')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# PART A — 결정 트리: AI가 만든 규칙 보기\n",
        "\n",
        "지난 시간 방식은 사람이 규칙을 직접 쓰는 것이었습니다.\n",
        "\n",
        "```python\n",
        "if blue > 120:\n",
        "    return \"ocean\"\n",
        "```\n",
        "\n",
        "오늘 방식은 다릅니다.\n",
        "\n",
        "```text\n",
        "데이터 + 정답 → 모델 학습 → AI가 규칙을 스스로 찾음\n",
        "```\n",
        "\n",
        "먼저 연습용 RGB 픽셀 데이터를 만들겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class_names = ['ocean', 'forest', 'desert', 'city']\n",
        "centers = {\n",
        "    'ocean':  [35, 95, 175],\n",
        "    'forest': [45, 135, 65],\n",
        "    'desert': [205, 170, 95],\n",
        "    'city':   [135, 135, 135],\n",
        "}\n",
        "\n",
        "rows = []\n",
        "for label, center in centers.items():\n",
        "    pixels = np.random.normal(loc=center, scale=32, size=(350, 3))\n",
        "    pixels = np.clip(pixels, 0, 255).astype(int)\n",
        "    for r, g, b in pixels:\n",
        "        rows.append({'R': r, 'G': g, 'B': b, 'label': label})\n",
        "\n",
        "df = pd.DataFrame(rows)\n",
        "display(df.head())\n",
        "print('데이터 개수:', len(df))\n",
        "print('라벨 종류:', sorted(df['label'].unique()))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n",
        "\n",
        "color_map = {\n",
        "    'ocean': '#2b6cb0',\n",
        "    'forest': '#2f855a',\n",
        "    'desert': '#d69e2e',\n",
        "    'city': '#718096',\n",
        "}\n",
        "for label in class_names:\n",
        "    part = df[df['label'] == label]\n",
        "    axes[0].scatter(part['R'], part['B'], s=10, alpha=0.55, label=label, c=color_map[label])\n",
        "axes[0].set_xlabel('R value')\n",
        "axes[0].set_ylabel('B value')\n",
        "axes[0].set_title('Pixel features: R vs B')\n",
        "axes[0].legend()\n",
        "\n",
        "sample = df.sample(120, random_state=1)\n",
        "strip = sample[['R', 'G', 'B']].to_numpy().reshape(10, 12, 3) / 255\n",
        "axes[1].imshow(strip)\n",
        "axes[1].set_title('Random pixel samples')\n",
        "axes[1].axis('off')\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 학습용 / 시험용 나누기\n",
        "\n",
        "AI에게 이미 본 문제로 시험을 보면 안 됩니다.\n",
        "\n",
        "- `train`: 공부용 데이터\n",
        "- `test`: 처음 보는 시험용 데이터\n",
        "\n",
        "오늘은 계속 `test_accuracy`를 기준으로 판단합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "X = df[['R', 'G', 'B']]\n",
        "y = df['label']\n",
        "\n",
        "X_train, X_test, y_train, y_test = train_test_split(\n",
        "    X, y,\n",
        "    test_size=0.30,\n",
        "    random_state=42,\n",
        "    stratify=y,\n",
        ")\n",
        "\n",
        "print('공부용:', len(X_train))\n",
        "print('시험용:', len(X_test))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 함께 실행: 결정 트리 기본 모델\n",
        "\n",
        "먼저 기본 모델을 한 번 학습시킵니다.\n",
        "\n",
        "핵심 단어:\n",
        "\n",
        "- `fit`: 학습한다\n",
        "- `predict`: 처음 보는 것을 판단한다\n",
        "- `score` / `accuracy`: 얼마나 맞혔는지 본다"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "tree = DecisionTreeClassifier(max_depth=4, random_state=42)\n",
        "tree.fit(X_train, y_train)\n",
        "\n",
        "train_acc = accuracy_score(y_train, tree.predict(X_train))\n",
        "test_acc = accuracy_score(y_test, tree.predict(X_test))\n",
        "print(f'결정 트리 train 정확도: {train_acc:.3f}')\n",
        "print(f'결정 트리 test  정확도: {test_acc:.3f}')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "plt.figure(figsize=(18, 8))\n",
        "plot_tree(\n",
        "    tree,\n",
        "    feature_names=['R', 'G', 'B'],\n",
        "    class_names=tree.classes_,\n",
        "    filled=True,\n",
        "    rounded=True,\n",
        "    fontsize=9,\n",
        ")\n",
        "plt.title('Decision tree rules')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 탐구 1 — 결정 트리는 얼마나 깊어야 좋을까?\n",
        "\n",
        "아래 셀에서 바꿔볼 값은 이것뿐입니다.\n",
        "\n",
        "```python\n",
        "depths_to_try = [1, 2, 3, 5, 10, None]\n",
        "```\n",
        "\n",
        "팀 미션:\n",
        "\n",
        "1. `test_accuracy`가 가장 높은 깊이를 찾으세요.\n",
        "2. `train_accuracy`와 `test_accuracy`가 많이 벌어지는 깊이를 찾으세요.\n",
        "3. 그 모델은 “이해한 모델”인지 “외운 모델”인지 한 줄로 쓰세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# TODO: 여기 숫자를 바꿔보세요.\n",
        "depths_to_try = [1, 2, 3, 5, 10, None]\n",
        "\n",
        "rows = []\n",
        "for depth in depths_to_try:\n",
        "    model = DecisionTreeClassifier(max_depth=depth, random_state=42)\n",
        "    model.fit(X_train, y_train)\n",
        "    train_acc = accuracy_score(y_train, model.predict(X_train))\n",
        "    test_acc = accuracy_score(y_test, model.predict(X_test))\n",
        "    rows.append({\n",
        "        'max_depth': 'None' if depth is None else depth,\n",
        "        'train_accuracy': round(train_acc, 3),\n",
        "        'test_accuracy': round(test_acc, 3),\n",
        "        'gap_train_minus_test': round(train_acc - test_acc, 3),\n",
        "    })\n",
        "\n",
        "depth_df = pd.DataFrame(rows)\n",
        "display(depth_df)\n",
        "\n",
        "best = depth_df.iloc[depth_df['test_accuracy'].idxmax()]\n",
        "print('test 기준 가장 좋은 깊이:', best['max_depth'])\n",
        "\n",
        "plt.figure(figsize=(8, 4))\n",
        "plt.plot(depth_df['max_depth'].astype(str), depth_df['train_accuracy'], marker='o', label='train')\n",
        "plt.plot(depth_df['max_depth'].astype(str), depth_df['test_accuracy'], marker='o', label='test')\n",
        "plt.ylim(0.7, 1.02)\n",
        "plt.xlabel('max_depth')\n",
        "plt.ylabel('accuracy')\n",
        "plt.title('Tree depth vs accuracy')\n",
        "plt.legend()\n",
        "plt.grid(alpha=0.25)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 탐구 1 기록표\n",
        "\n",
        "아래 표를 팀 노트에 채우세요. 종이에 써도 됩니다.\n",
        "\n",
        "| max_depth | train accuracy | test accuracy | 한 줄 평가 |\n",
        "|---:|---:|---:|---|\n",
        "| 1 | | | 너무 단순한가? |\n",
        "| 2 | | | |\n",
        "| 3 | | | |\n",
        "| 5 | | | |\n",
        "| 10 | | | 외운 것 같은가? |\n",
        "| None | | | |\n",
        "\n",
        "발표용 한 문장:\n",
        "\n",
        "> 우리 팀은 `max_depth=__`가 가장 적절하다고 봤습니다. 이유는 `__`입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 처음 보는 픽셀 예측하기\n",
        "\n",
        "`fit`은 배울 때, `predict`는 판단할 때 씁니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "new_pixels = pd.DataFrame([\n",
        "    {'R': 30, 'G': 90, 'B': 180},\n",
        "    {'R': 50, 'G': 150, 'B': 70},\n",
        "    {'R': 210, 'G': 175, 'B': 95},\n",
        "    {'R': 140, 'G': 140, 'B': 145},\n",
        "])\n",
        "\n",
        "predicted = tree.predict(new_pixels)\n",
        "result = new_pixels.copy()\n",
        "result['prediction'] = predicted\n",
        "display(result)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 탐구 2 — 일부러 과적합 모델 찾아보기\n",
        "\n",
        "이번 목표는 “좋은 모델”이 아니라 **수상한 모델**을 찾는 것입니다.\n",
        "\n",
        "수상한 모델의 특징:\n",
        "\n",
        "- `train_accuracy`는 매우 높다.\n",
        "- 그런데 `test_accuracy`는 생각보다 낮다.\n",
        "- 즉, 공부용 문제를 외웠을 가능성이 있다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "overfit_candidates = {\n",
        "    'too_simple_depth_1': 1,\n",
        "    'middle_depth_4': 4,\n",
        "    'very_deep_no_limit': None,\n",
        "}\n",
        "\n",
        "rows = []\n",
        "for name, depth in overfit_candidates.items():\n",
        "    model = DecisionTreeClassifier(max_depth=depth, random_state=42)\n",
        "    model.fit(X_train, y_train)\n",
        "    rows.append({\n",
        "        'setting': name,\n",
        "        'max_depth': 'None' if depth is None else depth,\n",
        "        'train_accuracy': round(accuracy_score(y_train, model.predict(X_train)), 3),\n",
        "        'test_accuracy': round(accuracy_score(y_test, model.predict(X_test)), 3),\n",
        "    })\n",
        "\n",
        "overfit_df = pd.DataFrame(rows)\n",
        "overfit_df['gap'] = (overfit_df['train_accuracy'] - overfit_df['test_accuracy']).round(3)\n",
        "display(overfit_df)\n",
        "print('gap이 클수록 외웠을 가능성을 의심해볼 수 있습니다.')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# PART B — 신경망: 휘어진 경계 보기\n",
        "\n",
        "결정 트리는 질문을 이어가며 데이터를 나눕니다. 그래서 경계가 계단처럼 보일 수 있습니다.\n",
        "\n",
        "신경망은 작은 계산 단위인 **뉴런**을 여러 층으로 연결해서 더 휘어진 경계를 만들 수 있습니다.\n",
        "\n",
        "이제 초승달 모양 데이터를 놓고 트리와 신경망을 비교합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "X_moon, y_moon = make_moons(n_samples=700, noise=0.25, random_state=42)\n",
        "X_m_train, X_m_test, y_m_train, y_m_test = train_test_split(\n",
        "    X_moon, y_moon,\n",
        "    test_size=0.30,\n",
        "    random_state=42,\n",
        "    stratify=y_moon,\n",
        ")\n",
        "\n",
        "plt.figure(figsize=(6, 5))\n",
        "plt.scatter(X_moon[:, 0], X_moon[:, 1], c=y_moon, cmap='coolwarm', s=18, edgecolor='k', linewidth=0.2)\n",
        "plt.title('Moon-shaped data')\n",
        "plt.xlabel('x1')\n",
        "plt.ylabel('x2')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def plot_boundary(model, X, y, title):\n",
        "    x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5\n",
        "    y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5\n",
        "    xx, yy = np.meshgrid(\n",
        "        np.linspace(x_min, x_max, 220),\n",
        "        np.linspace(y_min, y_max, 220),\n",
        "    )\n",
        "    grid = np.c_[xx.ravel(), yy.ravel()]\n",
        "    zz = model.predict(grid).reshape(xx.shape)\n",
        "\n",
        "    plt.contourf(xx, yy, zz, alpha=0.25, cmap='coolwarm')\n",
        "    plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', s=18, edgecolor='k', linewidth=0.2)\n",
        "    plt.title(title)\n",
        "    plt.xlabel('x1')\n",
        "    plt.ylabel('x2')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 탐구 3 — 트리 vs 신경망 경계 비교\n",
        "\n",
        "팀 미션:\n",
        "\n",
        "1. 결정 트리 경계가 어떤 모양인지 봅니다.\n",
        "2. 신경망 경계가 어떤 모양인지 봅니다.\n",
        "3. 정확도와 경계 모양을 함께 비교합니다.\n",
        "\n",
        "질문:\n",
        "\n",
        "> 정확도만 보면 누가 좋나요? 그림까지 보면 누가 더 자연스럽나요?"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "moon_tree = DecisionTreeClassifier(max_depth=5, random_state=42)\n",
        "moon_tree.fit(X_m_train, y_m_train)\n",
        "\n",
        "moon_nn = make_pipeline(\n",
        "    StandardScaler(),\n",
        "    MLPClassifier(\n",
        "        hidden_layer_sizes=(16, 16),\n",
        "        activation='tanh',\n",
        "        solver='lbfgs',\n",
        "        alpha=0.01,\n",
        "        max_iter=1000,\n",
        "        random_state=42,\n",
        "    )\n",
        ")\n",
        "moon_nn.fit(X_m_train, y_m_train)\n",
        "\n",
        "tree_acc = accuracy_score(y_m_test, moon_tree.predict(X_m_test))\n",
        "nn_acc = accuracy_score(y_m_test, moon_nn.predict(X_m_test))\n",
        "\n",
        "plt.figure(figsize=(13, 5))\n",
        "plt.subplot(1, 2, 1)\n",
        "plot_boundary(moon_tree, X_moon, y_moon, f'Decision Tree / test acc={tree_acc:.3f}')\n",
        "plt.subplot(1, 2, 2)\n",
        "plot_boundary(moon_nn, X_moon, y_moon, f'Neural Network / test acc={nn_acc:.3f}')\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "print('트리는 계단처럼 나누는 경향이 있습니다.')\n",
        "print('신경망은 휘어진 경계를 더 자연스럽게 만들 수 있습니다.')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 탐구 3 기록표\n",
        "\n",
        "| 모델 | test accuracy | 경계 모양 | 한 줄 평가 |\n",
        "|---|---:|---|---|\n",
        "| 결정 트리 | | 계단형 / 복잡함 / 자연스러움 | |\n",
        "| 신경망 | | 계단형 / 곡선형 / 자연스러움 | |\n",
        "\n",
        "발표용 한 문장:\n",
        "\n",
        "> 이 초승달 문제에서는 `__`이 더 적절해 보입니다. 이유는 `__`입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 탐구 4 — 신경망 크기 바꿔보기\n",
        "\n",
        "`hidden_layer_sizes`는 신경망 안쪽 크기입니다.\n",
        "\n",
        "바꿔볼 값:\n",
        "\n",
        "- `(2,)`\n",
        "- `(4,)`\n",
        "- `(8, 8)`\n",
        "- `(16, 16)`\n",
        "- `(64, 64)`\n",
        "\n",
        "너무 작으면 못 배우고, 너무 크면 필요 이상으로 복잡해질 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# TODO: 후보를 바꿔보세요.\n",
        "sizes_to_try = [(2,), (4,), (8, 8), (16, 16), (32, 32), (64, 64)]\n",
        "\n",
        "rows = []\n",
        "for size in sizes_to_try:\n",
        "    model = make_pipeline(\n",
        "        StandardScaler(),\n",
        "        MLPClassifier(\n",
        "            hidden_layer_sizes=size,\n",
        "            activation='tanh',\n",
        "            solver='lbfgs',\n",
        "            alpha=0.01,\n",
        "            max_iter=1000,\n",
        "            random_state=42,\n",
        "        )\n",
        "    )\n",
        "    model.fit(X_m_train, y_m_train)\n",
        "    rows.append({\n",
        "        'hidden_layer_sizes': str(size),\n",
        "        'train_accuracy': round(accuracy_score(y_m_train, model.predict(X_m_train)), 3),\n",
        "        'test_accuracy': round(accuracy_score(y_m_test, model.predict(X_m_test)), 3),\n",
        "    })\n",
        "\n",
        "tune_df = pd.DataFrame(rows)\n",
        "tune_df['gap_train_minus_test'] = (tune_df['train_accuracy'] - tune_df['test_accuracy']).round(3)\n",
        "display(tune_df)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 반전 — 신경망이 항상 이길까?\n",
        "\n",
        "아닙니다.\n",
        "\n",
        "단순한 색 분류 문제에서는 결정 트리도 충분히 잘할 수 있습니다.\n",
        "중요한 건 **제일 멋진 모델**이 아니라 **문제에 맞는 모델**입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "color_tree = DecisionTreeClassifier(max_depth=4, random_state=42)\n",
        "color_tree.fit(X_train, y_train)\n",
        "\n",
        "color_nn = make_pipeline(\n",
        "    StandardScaler(),\n",
        "    MLPClassifier(\n",
        "        hidden_layer_sizes=(16, 16),\n",
        "        activation='relu',\n",
        "        solver='lbfgs',\n",
        "        alpha=0.01,\n",
        "        max_iter=1000,\n",
        "        random_state=42,\n",
        "    )\n",
        ")\n",
        "color_nn.fit(X_train, y_train)\n",
        "\n",
        "compare = pd.DataFrame([\n",
        "    {'problem': 'RGB land pixels', 'model': 'Decision Tree', 'test_accuracy': accuracy_score(y_test, color_tree.predict(X_test))},\n",
        "    {'problem': 'RGB land pixels', 'model': 'Neural Network', 'test_accuracy': accuracy_score(y_test, color_nn.predict(X_test))},\n",
        "    {'problem': 'Moon-shaped data', 'model': 'Decision Tree', 'test_accuracy': tree_acc},\n",
        "    {'problem': 'Moon-shaped data', 'model': 'Neural Network', 'test_accuracy': nn_acc},\n",
        "])\n",
        "compare['test_accuracy'] = compare['test_accuracy'].round(3)\n",
        "display(compare)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 최종 챌린지 — 우리 팀의 결론 만들기\n",
        "\n",
        "아래 중 하나를 고르세요.\n",
        "\n",
        "## LEVEL 1 — 안정형\n",
        "결정 트리 `max_depth`를 조정해서 `test_accuracy`가 가장 좋은 값을 찾기.\n",
        "\n",
        "## LEVEL 2 — 비교형\n",
        "초승달 데이터에서 트리와 신경망의 경계 차이를 설명하기.\n",
        "\n",
        "## LEVEL 3 — 도전형\n",
        "동심원 데이터 `make_circles`에서 트리와 신경망을 비교하기.\n",
        "\n",
        "발표에는 5개만 들어가면 됩니다.\n",
        "\n",
        "1. 우리가 고른 문제\n",
        "2. 바꾼 값\n",
        "3. 가장 좋았던 결과\n",
        "4. 경계 그림에서 보인 차이\n",
        "5. 결론 한 문장"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# LEVEL 3 힌트 코드: 동심원 데이터\n",
        "X_circle, y_circle = make_circles(n_samples=700, noise=0.12, factor=0.45, random_state=7)\n",
        "\n",
        "circle_tree = DecisionTreeClassifier(max_depth=6, random_state=42)\n",
        "circle_nn = make_pipeline(\n",
        "    StandardScaler(),\n",
        "    MLPClassifier(hidden_layer_sizes=(16, 16), activation='tanh', solver='lbfgs', alpha=0.01, max_iter=1000, random_state=42)\n",
        ")\n",
        "\n",
        "circle_tree.fit(X_circle, y_circle)\n",
        "circle_nn.fit(X_circle, y_circle)\n",
        "\n",
        "plt.figure(figsize=(13, 5))\n",
        "plt.subplot(1, 2, 1)\n",
        "plot_boundary(circle_tree, X_circle, y_circle, 'Tree on circle data')\n",
        "plt.subplot(1, 2, 2)\n",
        "plot_boundary(circle_nn, X_circle, y_circle, 'Neural net on circle data')\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 발표 템플릿\n",
        "\n",
        "아래 문장을 채워서 발표하면 됩니다.\n",
        "\n",
        "> 저희 팀은 `__` 문제를 골랐습니다.  \n",
        "> 바꾼 값은 `__`입니다.  \n",
        "> 가장 좋았던 test accuracy는 `__`입니다.  \n",
        "> 경계 그림은 `__`처럼 보였습니다.  \n",
        "> 그래서 저희 결론은 `__`입니다.\n",
        "\n",
        "마지막 한 문장:\n",
        "\n",
        "> **좋은 AI는 무조건 큰 모델이 아니라, 문제에 맞는 모델이다.**"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "pygments_lexer": "ipython3"
    },
    "colab": {
      "provenance": []
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}