{
 "nbformat": 4,
 "nbformat_minor": 0,
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Challenge] 데이터 사이언스 2차시 — 까다로운 데이터 요리하기\n",
    "**이름:** 한정연  \n",
    "**학교:** 용인외대부고 국제과정 2학년"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 0. 데이터 준비"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0-1. 한글 폰트 설정\n",
    "히스토그램에 한글 제목/라벨이 들어가니까 폰트를 먼저 잡아 놓겠습니다. 코랩에서는 `koreanize_matplotlib` 한 줄이 제일 간편합니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "!pip install -q koreanize-matplotlib\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import koreanize_matplotlib  # 한글 폰트 자동 설정"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0-2. CSV 파일 업로드\n",
    "`bus.csv`(서울시 자치구별 버스 승객수)와 `master.csv`(자치구·행정동 매핑)를 코랩에 업로드합니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "from google.colab import files\n",
    "\n",
    "# bus.csv, master.csv 두 파일을 같이 업로드\n",
    "uploaded = files.upload()"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0-3. CSV 읽어오기\n",
    "한글 컬럼명이라 인코딩은 `euc-kr`로 해야 안 깨집니다. (안 되면 `cp949`로 바꿔보기)"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "import pandas as pd\n",
    "\n",
    "bus = pd.read_csv('bus.csv', encoding='euc-kr')\n",
    "master = pd.read_csv('master.csv', encoding='euc-kr')\n",
    "\n",
    "print('bus 크기:', bus.shape)\n",
    "print('master 크기:', master.shape)\n",
    "bus.head()"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0-4. merge로 두 데이터를 합치기\n",
    "`bus`에는 `행정동_ID`만 있고 자치구 이름은 없습니다. `master`와 `행정동_ID` 기준으로 `inner` join 해서 자치구 정보까지 들어간 `bus_merged`를 만들겠습니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "bus_merged = bus.merge(master, on='행정동_ID', how='inner')\n",
    "\n",
    "print('bus_merged 크기:', bus_merged.shape)\n",
    "bus_merged[['행정동_명칭', '자치구_명칭', '버스_승객_수']].head()"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 과제 1: 자치구별 평균/최대 버스 승객 수 구하기"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1-1. 강남구의 평균 버스 승객 수\n",
    "`groupby('자치구_명칭')`으로 자치구별로 묶고, `버스_승객_수`의 평균을 구하면 자치구별 평균이 나옵니다. 거기서 `loc['강남구']`로 강남구만 꺼내겠습니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "# 자치구별 평균 버스 승객 수\n",
    "gu_mean = bus_merged.groupby('자치구_명칭')['버스_승객_수'].mean()\n",
    "\n",
    "# 강남구만 뽑기\n",
    "print('강남구 평균:', gu_mean.loc['강남구'])"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "강남구의 평균 버스 승객 수는 약 **9,741명**입니다."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1-2. 최대 승객 수가 가장 많은 자치구\n",
    "이번엔 집계 함수를 `mean()` 대신 `max()`로 바꿔서 자치구별 최댓값을 구하고, `idxmax()`로 가장 큰 값을 가진 자치구 이름을 바로 뽑겠습니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "# 자치구별 최대 버스 승객 수\n",
    "gu_max = bus_merged.groupby('자치구_명칭')['버스_승객_수'].max()\n",
    "\n",
    "# 큰 순으로 5개 확인\n",
    "print(gu_max.sort_values(ascending=False).head())\n",
    "\n",
    "# 1등 자치구 이름만 바로\n",
    "print('최대 승객 자치구:', gu_max.idxmax())"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "최대 버스 승객 수가 가장 많았던 자치구는 **마포구**입니다. (서교동 약 54,011명으로 1위)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 과제 2: 특정 조건을 만족하는 데이터 추출하기"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2-1. loc — 강남구이거나 승객수가 30,000명 이상\n",
    "\"이거나\"는 **OR** 이니까 `|`를 씁니다. (`&`는 AND라서 다른 의미!) 각 조건은 괄호로 감싸야 한다는 점만 조심하면 됩니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "# 두 조건을 | (OR) 로 결합\n",
    "mask = (bus_merged['자치구_명칭'] == '강남구') | (bus_merged['버스_승객_수'] >= 30000)\n",
    "\n",
    "# loc로 행정동·승객수만 뽑기\n",
    "result_21 = bus_merged.loc[mask, ['행정동_명칭', '버스_승객_수']]\n",
    "\n",
    "print('추출된 행 수:', len(result_21))\n",
    "result_21"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "총 **26개 행정동**이 추출됩니다. 강남구 22개 행정동 + 30,000명 이상인 곳 4개(종로1·2·3·4가동, 신촌동, 서교동, 영등포동)이네요."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2-2. sort_values — 자치구·행정동 가나다순으로 정렬\n",
    "`by=['자치구_명칭', '행정동_명칭']`처럼 리스트로 넘기면 1순위·2순위 정렬이 됩니다. 둘 다 가나다순(오름차순)이라 `ascending`은 기본값(True)으로 두면 됩니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "# 자치구 → 행정동 순서로 다중 정렬\n",
    "sorted_df = bus_merged.sort_values(by=['자치구_명칭', '행정동_명칭'])\n",
    "\n",
    "# 가장 첫 번째 행 1개만 보기\n",
    "sorted_df[['자치구_명칭', '행정동_명칭', '버스_승객_수']].head(1)"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "가나다순으로 정렬했을 때 첫 번째 행정동은 **강남구 개포1동**이고, 버스 승객 수는 약 **3,461명**입니다."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 과제 3: 영등포구의 버스 승객 수 히스토그램"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 영등포구만 추출 + 평균·중앙값 계산\n",
    "먼저 `loc`로 영등포구 데이터만 뽑고, 평균과 중앙값을 계산해 두겠습니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "# 영등포구 행정동만 추출\n",
    "ydp = bus_merged.loc[bus_merged['자치구_명칭'] == '영등포구']\n",
    "\n",
    "# 평균 / 중앙값\n",
    "mean_val = ydp['버스_승객_수'].mean()\n",
    "median_val = ydp['버스_승객_수'].median()\n",
    "\n",
    "print('영등포구 행정동 수:', len(ydp))\n",
    "print(f'평균: {mean_val:.2f}')\n",
    "print(f'중앙값: {median_val:.2f}')"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 영등포구 버스 승객수 히스토그램\n",
    "교재 4-5에서 배운 `plt.hist()` + `plt.axvline()` 패턴 그대로 적용합니다."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "plt.figure(figsize=(8, 4))\n",
    "plt.hist(ydp['버스_승객_수'],\n",
    "         bins=12, alpha=0.7, color='skyblue', label='버스 승객수')\n",
    "\n",
    "# 평균 (빨강 점선)\n",
    "plt.axvline(mean_val, color='red', linestyle='--', linewidth=2,\n",
    "            label=f'평균: {mean_val:.0f}')\n",
    "# 중앙값 (주황 실선)\n",
    "plt.axvline(median_val, color='orange', linestyle='-', linewidth=2,\n",
    "            label=f'중앙값: {median_val:.0f}')\n",
    "\n",
    "plt.title('영등포구 행정동별 버스 승객수 분포')\n",
    "plt.xlabel('버스 승객 수 (명)')\n",
    "plt.ylabel('행정동 수')\n",
    "plt.grid(True, alpha=0.3)\n",
    "plt.legend()\n",
    "plt.show()"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3-1. 영등포구 분포의 특징\n",
    "\n",
    "히스토그램을 보면 영등포구는 **오른쪽으로 긴 꼬리**를 가진 **Right skew** 분포입니다. 대부분의 행정동은 약 5,000명 안팎의 작은 구간에 몰려 있는데, 여의동이나 영등포동처럼 승객이 훨씬 많은 행정동 몇 개가 그래프 오른쪽에 멀리 떨어져 있어서 꼬리가 길게 늘어진 모양이 나왔습니다.\n",
    "\n",
    "그래서 **평균이 중앙값보다 큽니다.** (교재에서 배운 Right skew의 전형적 특징인 *Mode < Median < Mean* 관계가 그대로 보입니다.) 영등포동·여의동 같은 큰 값이 평균을 끌어올리는 거죠.\n",
    "\n",
    "이 데이터로 영등포구 \"보통\" 행정동의 승객 규모를 말하려면 **평균보다는 중앙값**을 쓰는 게 더 정확할 것 같습니다. 영등포구가 영등포역·여의도 같은 상업·업무 지구와 도림·양평·대림 같은 주거 지구가 같이 있는 동네라서, 행정동마다 유동인구 차이가 크게 나타난 결과로 보입니다."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 제출 체크리스트\n",
    "\n",
    "- [ ] **과제 1** (1-1, 1-2): 코드 + 결과 캡처\n",
    "- [ ] **과제 2** (2-1, 2-2): 코드 + 결과 캡처\n",
    "- [ ] **과제 3**: 코드 + 히스토그램 이미지 + 3-1 분포 특징 서술\n",
    "- [ ] 모든 결과를 1개의 zip 파일로 압축\n",
    "- [ ] 2026년 5월 3일(일) 23:59 이전 제출"
   ]
  }
 ]
}