{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "883faef4-2410-40e3-aeb3-1eb0cc7b516d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "464c9db6-b83d-4d59-82c8-b3ddd2da1e21",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Colab 마운트도 동시에 수행하자! (이전 강의자료 참고)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ac41a95-4297-4542-a2ce-cbcd11818694",
   "metadata": {},
   "source": [
    "# Load Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a7291ebf-70d1-4d51-97b8-f39b614bf4cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_train = pd.read_csv(\"train.csv\")\n",
    "df_train.head(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c5ba4a2-8b96-4dd9-aacc-f739763738e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Input Feature 8개 활용\n",
    "num_features = 8\n",
    "x_train = np.zeros([len(df_train), num_features])\n",
    "y_train = df_train[\"Survived\"]\n",
    "\n",
    "print(x_train.shape, y_train.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a420b3e-f754-4eea-ab1e-f5af1e11ebb8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Sex\n",
    "x_train[:, 0] = df_train[\"Sex\"].map({\"male\": 0, \"female\": 1}).astype(float)\n",
    "# Pclass\n",
    "x_train[:, 1] = df_train[\"Pclass\"].map({3: 0, 2: 1, 1: 2}).astype(float)\n",
    "# Fare\n",
    "x_train[:, 2] = (df_train[\"Fare\"] - df_train[\"Fare\"].mean()) / df_train[\"Fare\"].std()\n",
    "# Embarked\n",
    "x_train[:, 3] = df_train[\"Embarked\"].fillna(\"S\").map({\"S\": 0, \"Q\": 1, \"C\": 2}).astype(float)\n",
    "\n",
    "# Age\n",
    "# 결측치 처리: 훈련 데이터의 평균 나이로 대체\n",
    "x_train[:, 4] = df_train[\"Age\"].fillna(df_train[\"Age\"].mean())\n",
    "\n",
    "# 나이를 연령대별로 그룹화\n",
    "bins = [0, 18, 25, 35, 60, 100]\n",
    "x_train[:, 4] = pd.cut(df_train['Age'].fillna(df_train[\"Age\"].mean()), bins=bins, labels=False)\n",
    "\n",
    "# SibSp (동반한 형제자매 또는 배우자의 수)\n",
    "x_train[:, 5] = df_train[\"SibSp\"]\n",
    "\n",
    "# Parch (동반한 부모 또는 자녀의 수)\n",
    "x_train[:, 6] = df_train[\"Parch\"]\n",
    "\n",
    "# Ticket의 첫 글자를 ASCII 값으로 변환\n",
    "x_train[:, 7] = df_train[\"Ticket\"].apply(lambda x: ord(x[0])).astype(float)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4719a97-315d-4cb3-8923-ad94226220d0",
   "metadata": {},
   "source": [
    "# Logistic Regression Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67341e0e-44f1-4f47-b199-825b651da01d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 초기 가중치 값으로 램던 변수 정의\n",
    "w = np.zeros([x_train.shape[1], 1])\n",
    "b = np.random.rand()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72fc506e-53ea-40c6-8e65-82491c723b0e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def sigmoid(x):\n",
    "    return 1.0 / (1.0 + np.exp(-x))\n",
    "def hypothesis(w, x, b):\n",
    "    return sigmoid(x.dot(w) + b)\n",
    "def cost_function(h, y):\n",
    "    return -np.mean(y * np.log(h + 1e-8) + (1.0 - y) * np.log(1.0 - h + 1e-8))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ff587fc-3e81-4e46-b343-9de9e909a636",
   "metadata": {},
   "source": [
    "# Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f943e80b-f03c-4ec3-940b-41c8209a7440",
   "metadata": {},
   "outputs": [],
   "source": [
    "epoch = 20000  # 하이퍼파라메타를 설정하자!\n",
    "alpha = 0.002   # 하이퍼파라메타를 설정하자!\n",
    "\n",
    "w = np.zeros([x_train.shape[1], 1])\n",
    "y_train_np = np.array(y_train).reshape(-1, 1)\n",
    "\n",
    "total_loss = []\n",
    "for i in range(epoch):\n",
    "    h = hypothesis(w, x_train, b).reshape(-1, 1)\n",
    "\n",
    "    # 경사 하강법 구현\n",
    "    # 예측한 h에 대하여 실제값 y_train_np와의 오차를 기반으로\n",
    "    # gradient_w 및 gradient_b 값 업데이트함 => 경사 하강법\n",
    "    gradient_w = np.dot(x_train.T, (h - y_train_np)) / y_train_np.size\n",
    "    gradient_b = np.sum(h - y_train_np) / y_train_np.size\n",
    "    \n",
    "    w -= alpha * gradient_w\n",
    "    b -= alpha * gradient_b\n",
    "\n",
    "    # 매 epoch 마다 오차(loss)를 계산하고 이 값은 학습을 통해 점차 줄어들음\n",
    "    loss = cost_function(h, y_train_np)\n",
    "    total_loss.append(loss)\n",
    "\n",
    "total_loss = np.array(total_loss)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48471614-c1ef-4596-a43a-1ec1b9c34378",
   "metadata": {},
   "source": [
    "# Result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb7dea50-b694-4fc2-be35-61fee0a7302c",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(10.0 * np.log(total_loss / (np.max(total_loss + 1e-5))))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b95e6c40-ca0a-49c5-8add-a023dfc144ce",
   "metadata": {},
   "source": [
    "# Test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "632f4556-aa9f-41de-a88a-9199b07e7c52",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 자신의 경로에 맞게 설정하자!\n",
    "# Test 데이터셋에 대한 File Open\n",
    "df_test = pd.read_csv(\"test.csv\")\n",
    "df_test.head(5)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6180153e-2855-4745-b195-9ebf9991e2f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_test.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a80ccce2-1007-400c-9621-d911b503ccef",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 새롭게 선택된 8개의 피쳐를 활용한 x_test 설정\n",
    "x_test = np.zeros([len(df_test), 8])\n",
    "print(x_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11efd403-cfa4-4e1f-b84b-d2d412ec655b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 앞선 train부분에서 해줬던 방식과 동일한 전처리를 test에대 해줌.\n",
    "\n",
    "# Sex\n",
    "x_test[:, 0] = df_test[\"Sex\"].map({\"male\": 0, \"female\": 1}).astype(float)\n",
    "# Pclass\n",
    "x_test[:, 1] = df_test[\"Pclass\"].map({3: 0, 2: 1, 1: 2}).astype(float)\n",
    "# Fare - use mean and std from training data to standardize test data\n",
    "x_test[:, 2] = (df_test[\"Fare\"].fillna(df_test[\"Fare\"].mean()) - df_train[\"Fare\"].mean()) / df_train[\"Fare\"].std()\n",
    "# Embarked\n",
    "x_test[:, 3] = df_test[\"Embarked\"].fillna(\"S\").map({\"S\": 0, \"Q\": 1, \"C\": 2}).astype(float)\n",
    "# Age \n",
    "x_test[:, 4] = df_test[\"Age\"].fillna(df_train[\"Age\"].mean())\n",
    "bins = [0, 18, 25, 35, 60, 100]\n",
    "x_test[:, 4] = pd.cut(df_test['Age'].fillna(df_train[\"Age\"].mean()), bins=bins, labels=False)\n",
    "# SibSp\n",
    "x_test[:, 5] = df_test[\"SibSp\"]\n",
    "# Parch\n",
    "x_test[:, 6] = df_test[\"Parch\"]\n",
    "# Ticket's first letter as ASCII value\n",
    "x_test[:, 7] = df_test[\"Ticket\"].apply(lambda x: ord(x[0])).astype(float)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7dc8f5c8-3b8b-4c79-95a1-a0c1b8f080ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred = hypothesis(w, x_test, b)\n",
    "y_pred = np.round(y_pred)\n",
    "print(y_pred.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b21ada7e-78da-4caa-bff4-c9748c8a365d",
   "metadata": {},
   "source": [
    "# Submission"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "74767333-29d7-42dc-b8d1-288295d76aa8",
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred = y_pred.reshape(-1)\n",
    "\n",
    "submission = pd.DataFrame({\n",
    " \"PassengerId\" : df_test[\"PassengerId\"].astype(int),\n",
    " \"Survived\" : y_pred.astype(int)\n",
    "})\n",
    "# 구글 코랩에 대한 파일 경로를 추가하자!\n",
    "submission.to_csv(\"result.csv\", index=False)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "prac",
   "language": "python",
   "name": "prac"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
