{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Mission735Solutions.ipynb",
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "# Purpose of Notebook\n",
        "\n",
        "The purpose of this notebook is to offer an example answer to the Guided Project for Logistic Regression in Python course. Since the choice of model predictors is up to the student, results can differ. Use this solution as a guide to how to structure your own answer."
      ],
      "metadata": {
        "id": "bnTWrWK6dzDN"
      }
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "I2w0LCJcIt8m"
      },
      "outputs": [],
      "source": [
        "import pandas as pd\n",
        "import numpy as np\n",
        "from sklearn.linear_model import LogisticRegression\n",
        "from sklearn.metrics import confusion_matrix\n",
        "from sklearn.model_selection import train_test_split"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Load in the heart disease dataset\n",
        "heart = pd.read_csv(\"heart_disease.csv\")"
      ],
      "metadata": {
        "id": "UIdZ-PUeeQqz"
      },
      "execution_count": 2,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Exploring The Dataset"
      ],
      "metadata": {
        "id": "VbQQ1VCHJXwu"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Columns in the dataset\n",
        "heart.columns"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "cR8YEHlTekVj",
        "outputId": "aeeaaa35-f8b1-4c7e-ed92-cf8f38a4c137"
      },
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "Index(['Unnamed: 0', 'age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg',\n",
              "       'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal', 'present'],\n",
              "      dtype='object')"
            ]
          },
          "metadata": {},
          "execution_count": 3
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "The `present` column is our binary outcome of interest. `0` encodes the absence of any heart disease, while `1` encodes the presence. \n",
        "\n",
        "Note: the original dataset actually has a multiclass version of the problem, based on heart disease severity. We've reduced it to a binary case for simplicity. "
      ],
      "metadata": {
        "id": "S9Ebj3L4f7FY"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "heart.head"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "nSR8tsPFh_KE",
        "outputId": "9badfdfc-65a4-498b-9026-4691cb54f005"
      },
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "<bound method NDFrame.head of      Unnamed: 0  age  sex  cp  trestbps  chol  fbs  restecg  thalach  exang  \\\n",
              "0             1   63    1   1       145   233    1        2      150      0   \n",
              "1             2   67    1   4       160   286    0        2      108      1   \n",
              "2             3   67    1   4       120   229    0        2      129      1   \n",
              "3             4   37    1   3       130   250    0        0      187      0   \n",
              "4             5   41    0   2       130   204    0        2      172      0   \n",
              "..          ...  ...  ...  ..       ...   ...  ...      ...      ...    ...   \n",
              "292         293   57    0   4       140   241    0        0      123      1   \n",
              "293         294   45    1   1       110   264    0        0      132      0   \n",
              "294         295   68    1   4       144   193    1        0      141      0   \n",
              "295         296   57    1   4       130   131    0        0      115      1   \n",
              "296         297   57    0   2       130   236    0        2      174      0   \n",
              "\n",
              "     oldpeak  slope  ca  thal  present  \n",
              "0        2.3      3   0     6        0  \n",
              "1        1.5      2   3     3        1  \n",
              "2        2.6      2   2     7        1  \n",
              "3        3.5      3   0     3        0  \n",
              "4        1.4      1   0     3        0  \n",
              "..       ...    ...  ..   ...      ...  \n",
              "292      0.2      2   0     7        1  \n",
              "293      1.2      2   0     7        1  \n",
              "294      3.4      2   2     7        1  \n",
              "295      1.2      2   1     7        1  \n",
              "296      0.0      2   1     3        1  \n",
              "\n",
              "[297 rows x 15 columns]>"
            ]
          },
          "metadata": {},
          "execution_count": 4
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Checking the outcome\n",
        "heart.hist(\"present\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 316
        },
        "id": "QQhwn9Fpeqni",
        "outputId": "4097cc97-ccf6-43e7-91d3-9d17aeeba125"
      },
      "execution_count": 5,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7f2567b9cd10>]],\n",
              "      dtype=object)"
            ]
          },
          "metadata": {},
          "execution_count": 5
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ],
            "image/png": "[encoded data, 7840 characters]\n"
          },
          "metadata": {
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "There's almost an equal number of cases and non-cases in the dataset."
      ],
      "metadata": {
        "id": "KKC_peF4gf_N"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Checking potential predictors\n",
        "heart.groupby(\"present\").agg(\n",
        "    {\n",
        "        \"age\": \"mean\",\n",
        "        \"sex\": \"mean\",\n",
        "        \"cp\": \"mean\",\n",
        "        \"trestbps\": \"mean\",\n",
        "        \"chol\": \"mean\",\n",
        "        \"fbs\": \"mean\",\n",
        "        \"restecg\": \"mean\",\n",
        "        \"thalach\": \"mean\",\n",
        "        \"exang\": \"mean\",\n",
        "        \"oldpeak\": \"mean\",\n",
        "        \"slope\": \"mean\",\n",
        "        \"ca\": \"mean\",\n",
        "        \"thal\": \"mean\"\n",
        "    }\n",
        ")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 143
        },
        "id": "3K8mvrwPge0Q",
        "outputId": "1b975922-47ec-4ebb-e78e-23e6f9f39902"
      },
      "execution_count": 6,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "               age       sex        cp    trestbps        chol       fbs  \\\n",
              "present                                                                    \n",
              "0        52.643750  0.556250  2.793750  129.175000  243.493750  0.143750   \n",
              "1        56.759124  0.817518  3.583942  134.635036  251.854015  0.145985   \n",
              "\n",
              "          restecg     thalach     exang   oldpeak     slope        ca  \\\n",
              "present                                                                 \n",
              "0        0.843750  158.581250  0.143750  0.598750  1.412500  0.275000   \n",
              "1        1.175182  139.109489  0.540146  1.589051  1.824818  1.145985   \n",
              "\n",
              "             thal  \n",
              "present            \n",
              "0        3.787500  \n",
              "1        5.832117  "
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-aca68377-9d5b-447e-bbaa-011ec7d53525\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>age</th>\n",
              "      <th>sex</th>\n",
              "      <th>cp</th>\n",
              "      <th>trestbps</th>\n",
              "      <th>chol</th>\n",
              "      <th>fbs</th>\n",
              "      <th>restecg</th>\n",
              "      <th>thalach</th>\n",
              "      <th>exang</th>\n",
              "      <th>oldpeak</th>\n",
              "      <th>slope</th>\n",
              "      <th>ca</th>\n",
              "      <th>thal</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>present</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>52.643750</td>\n",
              "      <td>0.556250</td>\n",
              "      <td>2.793750</td>\n",
              "      <td>129.175000</td>\n",
              "      <td>243.493750</td>\n",
              "      <td>0.143750</td>\n",
              "      <td>0.843750</td>\n",
              "      <td>158.581250</td>\n",
              "      <td>0.143750</td>\n",
              "      <td>0.598750</td>\n",
              "      <td>1.412500</td>\n",
              "      <td>0.275000</td>\n",
              "      <td>3.787500</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>56.759124</td>\n",
              "      <td>0.817518</td>\n",
              "      <td>3.583942</td>\n",
              "      <td>134.635036</td>\n",
              "      <td>251.854015</td>\n",
              "      <td>0.145985</td>\n",
              "      <td>1.175182</td>\n",
              "      <td>139.109489</td>\n",
              "      <td>0.540146</td>\n",
              "      <td>1.589051</td>\n",
              "      <td>1.824818</td>\n",
              "      <td>1.145985</td>\n",
              "      <td>5.832117</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-aca68377-9d5b-447e-bbaa-011ec7d53525')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-aca68377-9d5b-447e-bbaa-011ec7d53525 button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-aca68377-9d5b-447e-bbaa-011ec7d53525');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 6
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Some columns have a small, but noticeable difference when stratified by predictors. Based on the differences and some knowledge about heart disease, these seem like good candidates for predictors:\n",
        "\n",
        "1. `age`\n",
        "2. `thalach` (maximum heart rate achieved)\n",
        "3. `restecg` (resting ECG)\n",
        "4. `ca` (number of vessels colored by fluoroscopy)"
      ],
      "metadata": {
        "id": "taQvjXPujO2t"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Dividing The Data\n",
        "\n",
        "We'll use a 70-30 split of the dataset for the training and test sets."
      ],
      "metadata": {
        "id": "vI_WqGgIkQyG"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "X = heart[[\"age\", \"thalach\", \"restecg\", \"ca\"]]\n",
        "y = heart[\"present\"]\n",
        "\n",
        "# 70% for training set, 30% for test set\n",
        "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 1)"
      ],
      "metadata": {
        "id": "x5WmmGofh1fT"
      },
      "execution_count": 7,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Checking for separation in the datasets\n",
        "print(\"Y_train: \", sum(y_train == 0))\n",
        "print(\"Y_train: \", sum(y_train == 1))\n",
        "print(\"Y_test: \", sum(y_test == 0))\n",
        "print(\"Y_test: \", sum(y_test == 1))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "p3yyxhn5qNoh",
        "outputId": "67a8a5c2-4483-449c-950d-e0e776736863"
      },
      "execution_count": 8,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Y_train:  109\n",
            "Y_train:  98\n",
            "Y_test:  51\n",
            "Y_test:  39\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "We confirm above that there are both cases and non-cases in both the training and test sets"
      ],
      "metadata": {
        "id": "oKOzD_DvtL90"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Build The Model"
      ],
      "metadata": {
        "id": "0TVJVZrXuM2S"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "model = LogisticRegression()\n",
        "model.fit(X_train, y_train)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "PQUN7oIDtGs9",
        "outputId": "3e07b10b-2917-472c-fcda-d6e04b8d4bdd"
      },
      "execution_count": 9,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "LogisticRegression()"
            ]
          },
          "metadata": {},
          "execution_count": 9
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Checking the various metrics for the model\n",
        "acc = model.score(X_train, y_train)\n",
        "\n",
        "predictions = model.predict(X_train)\n",
        "tp = sum((predictions == 1) & (y_train == 1))\n",
        "fp = sum((predictions == 1) & (y_train == 0))\n",
        "tn = sum((predictions == 0) & (y_train == 0))\n",
        "fn = sum((predictions == 0) & (y_train == 1))\n",
        "sens = tp / (tp + fn)\n",
        "spec = tn / (tn + fp)\n",
        "\n",
        "print(\"Training Accuracy: \", acc)\n",
        "print(\"Training Sensitivity: \", sens)\n",
        "print(\"Training Specificity: \", spec)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "WiLjpMH-uZp5",
        "outputId": "21914b76-1383-4404-cc51-ee4e82e76aa5"
      },
      "execution_count": 10,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Training Accuracy:  0.7681159420289855\n",
            "Training Sensitivity:  0.6632653061224489\n",
            "Training Specificity:  0.8623853211009175\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Overall the training accuracy was about 76%, the sensitivity was 66%, and the specificity was 86%. Based on these metrics, the model seems to perform better for non-cases."
      ],
      "metadata": {
        "id": "bPjstCJlvltd"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Interpreting The Model Coefficients"
      ],
      "metadata": {
        "id": "q8enICp2b3U6"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "coefs = [\"age\", \"thalach\", \"restecg\", \"ca\"]\n",
        "\n",
        "# Checking in terms of log-odds\n",
        "for coef, val  in zip(coefs, model.coef_[0]):\n",
        "    print(coef, \":\", round(val, 2))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "PewJFkb1uiY3",
        "outputId": "26fd702e-8b67-4e95-8a5b-843313272872"
      },
      "execution_count": 11,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "age : -0.02\n",
            "thalach : -0.04\n",
            "restecg : 0.39\n",
            "ca : 1.18\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Checking in terms of odds\n",
        "for coef, val  in zip(coefs, model.coef_[0]):\n",
        "    print(coef, \":\", round(np.exp(val), 2))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "UstP_qZwu2Wu",
        "outputId": "55e8d78c-8b29-4a46-9205-b0c9c385ddc5"
      },
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "age : 0.98\n",
            "thalach : 0.96\n",
            "restecg : 1.47\n",
            "ca : 3.25\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "- Higher age and maximum heart rate (`thalach`) is associated with lower odds of heart disease holding the other predictors constant, but both of these odds ratios are close to 1.\n",
        "- Resting ECG and the number of colored vessels are associated with higher odds of heart disease holding the other predictors constant. These increases seem to be moderate and high, respectively (a 47% increase and 225% (!) increase)."
      ],
      "metadata": {
        "id": "KZrimAItdKho"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Final Model Evaluation"
      ],
      "metadata": {
        "id": "8OmQq3Wzd999"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Checking the various metrics for the model (test set)\n",
        "acc = model.score(X_test, y_test)\n",
        "\n",
        "predictions = model.predict(X_test)\n",
        "tp = sum((predictions == 1) & (y_test == 1))\n",
        "fp = sum((predictions == 1) & (y_test == 0))\n",
        "tn = sum((predictions == 0) & (y_test == 0))\n",
        "fn = sum((predictions == 0) & (y_test == 1))\n",
        "sens = tp / (tp + fn)\n",
        "spec = tn / (tn + fp)\n",
        "\n",
        "print(\"Test Accuracy: \", acc)\n",
        "print(\"Test Sensitivity: \", sens)\n",
        "print(\"Test Specificity: \", spec)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ZXCPWUSgcDT-",
        "outputId": "d7c0dae9-def3-4086-a955-52fe28129abb"
      },
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Test Accuracy:  0.7555555555555555\n",
            "Test Sensitivity:  0.7948717948717948\n",
            "Test Specificity:  0.7254901960784313\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Drawing Conclusions\n",
        "\n",
        "Test accuracy was 75%, sensitivity was 79%, and specificity was 72%. Compared to the training set, the accuracy didn't change much, while the model fared better with cases and worse with non-cases. This is potentially useful since this application is health-based. We might be more interested in being better at identifying cases than non-cases."
      ],
      "metadata": {
        "id": "kZszRo_Afrn8"
      }
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "W6bvaupneNhv"
      },
      "execution_count": 13,
      "outputs": []
    }
  ]
}