{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "b4KaSB7qau0Q"
      },
      "outputs": [],
      "source": [
        "import pandas as pd\n",
        "import numpy as np\n",
        "from sklearn.model_selection import train_test_split, GridSearchCV\n",
        "from sklearn.impute import SimpleImputer\n",
        "from sklearn.preprocessing import StandardScaler\n",
        "from sklearn.ensemble import RandomForestClassifier\n",
        "from sklearn.feature_selection import SelectKBest, f_classif, RFE\n",
        "from sklearn.linear_model import LogisticRegression\n",
        "from sklearn.metrics import classification_report, accuracy_score\n",
        "from sklearn.svm import SVC"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "from google.colab import files\n",
        "uploaded = files.upload()\n",
        "\n",
        "import pandas as pd\n",
        "\n",
        "df = pd.read_csv('heart.csv')\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 74
        },
        "id": "T-qRUE55bg0P",
        "outputId": "5a9bf4df-8fd3-4c9c-da61-0c7d22717a06"
      },
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ],
            "text/html": [
              "\n",
              "     <input type=\"file\" id=\"files-2cd57251-410a-44e3-852e-29fb27d6f818\" name=\"files[]\" multiple disabled\n",
              "        style=\"border:none\" />\n",
              "     <output id=\"result-2cd57251-410a-44e3-852e-29fb27d6f818\">\n",
              "      Upload widget is only available when the cell has been executed in the\n",
              "      current browser session. Please rerun this cell to enable.\n",
              "      </output>\n",
              "      <script>// Copyright 2017 Google LLC\n",
              "//\n",
              "// Licensed under the Apache License, Version 2.0 (the \"License\");\n",
              "// you may not use this file except in compliance with the License.\n",
              "// You may obtain a copy of the License at\n",
              "//\n",
              "//      http://www.apache.org/licenses/LICENSE-2.0\n",
              "//\n",
              "// Unless required by applicable law or agreed to in writing, software\n",
              "// distributed under the License is distributed on an \"AS IS\" BASIS,\n",
              "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
              "// See the License for the specific language governing permissions and\n",
              "// limitations under the License.\n",
              "\n",
              "/**\n",
              " * @fileoverview Helpers for google.colab Python module.\n",
              " */\n",
              "(function(scope) {\n",
              "function span(text, styleAttributes = {}) {\n",
              "  const element = document.createElement('span');\n",
              "  element.textContent = text;\n",
              "  for (const key of Object.keys(styleAttributes)) {\n",
              "    element.style[key] = styleAttributes[key];\n",
              "  }\n",
              "  return element;\n",
              "}\n",
              "\n",
              "// Max number of bytes which will be uploaded at a time.\n",
              "const MAX_PAYLOAD_SIZE = 100 * 1024;\n",
              "\n",
              "function _uploadFiles(inputId, outputId) {\n",
              "  const steps = uploadFilesStep(inputId, outputId);\n",
              "  const outputElement = document.getElementById(outputId);\n",
              "  // Cache steps on the outputElement to make it available for the next call\n",
              "  // to uploadFilesContinue from Python.\n",
              "  outputElement.steps = steps;\n",
              "\n",
              "  return _uploadFilesContinue(outputId);\n",
              "}\n",
              "\n",
              "// This is roughly an async generator (not supported in the browser yet),\n",
              "// where there are multiple asynchronous steps and the Python side is going\n",
              "// to poll for completion of each step.\n",
              "// This uses a Promise to block the python side on completion of each step,\n",
              "// then passes the result of the previous step as the input to the next step.\n",
              "function _uploadFilesContinue(outputId) {\n",
              "  const outputElement = document.getElementById(outputId);\n",
              "  const steps = outputElement.steps;\n",
              "\n",
              "  const next = steps.next(outputElement.lastPromiseValue);\n",
              "  return Promise.resolve(next.value.promise).then((value) => {\n",
              "    // Cache the last promise value to make it available to the next\n",
              "    // step of the generator.\n",
              "    outputElement.lastPromiseValue = value;\n",
              "    return next.value.response;\n",
              "  });\n",
              "}\n",
              "\n",
              "/**\n",
              " * Generator function which is called between each async step of the upload\n",
              " * process.\n",
              " * @param {string} inputId Element ID of the input file picker element.\n",
              " * @param {string} outputId Element ID of the output display.\n",
              " * @return {!Iterable<!Object>} Iterable of next steps.\n",
              " */\n",
              "function* uploadFilesStep(inputId, outputId) {\n",
              "  const inputElement = document.getElementById(inputId);\n",
              "  inputElement.disabled = false;\n",
              "\n",
              "  const outputElement = document.getElementById(outputId);\n",
              "  outputElement.innerHTML = '';\n",
              "\n",
              "  const pickedPromise = new Promise((resolve) => {\n",
              "    inputElement.addEventListener('change', (e) => {\n",
              "      resolve(e.target.files);\n",
              "    });\n",
              "  });\n",
              "\n",
              "  const cancel = document.createElement('button');\n",
              "  inputElement.parentElement.appendChild(cancel);\n",
              "  cancel.textContent = 'Cancel upload';\n",
              "  const cancelPromise = new Promise((resolve) => {\n",
              "    cancel.onclick = () => {\n",
              "      resolve(null);\n",
              "    };\n",
              "  });\n",
              "\n",
              "  // Wait for the user to pick the files.\n",
              "  const files = yield {\n",
              "    promise: Promise.race([pickedPromise, cancelPromise]),\n",
              "    response: {\n",
              "      action: 'starting',\n",
              "    }\n",
              "  };\n",
              "\n",
              "  cancel.remove();\n",
              "\n",
              "  // Disable the input element since further picks are not allowed.\n",
              "  inputElement.disabled = true;\n",
              "\n",
              "  if (!files) {\n",
              "    return {\n",
              "      response: {\n",
              "        action: 'complete',\n",
              "      }\n",
              "    };\n",
              "  }\n",
              "\n",
              "  for (const file of files) {\n",
              "    const li = document.createElement('li');\n",
              "    li.append(span(file.name, {fontWeight: 'bold'}));\n",
              "    li.append(span(\n",
              "        `(${file.type || 'n/a'}) - ${file.size} bytes, ` +\n",
              "        `last modified: ${\n",
              "            file.lastModifiedDate ? file.lastModifiedDate.toLocaleDateString() :\n",
              "                                    'n/a'} - `));\n",
              "    const percent = span('0% done');\n",
              "    li.appendChild(percent);\n",
              "\n",
              "    outputElement.appendChild(li);\n",
              "\n",
              "    const fileDataPromise = new Promise((resolve) => {\n",
              "      const reader = new FileReader();\n",
              "      reader.onload = (e) => {\n",
              "        resolve(e.target.result);\n",
              "      };\n",
              "      reader.readAsArrayBuffer(file);\n",
              "    });\n",
              "    // Wait for the data to be ready.\n",
              "    let fileData = yield {\n",
              "      promise: fileDataPromise,\n",
              "      response: {\n",
              "        action: 'continue',\n",
              "      }\n",
              "    };\n",
              "\n",
              "    // Use a chunked sending to avoid message size limits. See b/62115660.\n",
              "    let position = 0;\n",
              "    do {\n",
              "      const length = Math.min(fileData.byteLength - position, MAX_PAYLOAD_SIZE);\n",
              "      const chunk = new Uint8Array(fileData, position, length);\n",
              "      position += length;\n",
              "\n",
              "      const base64 = btoa(String.fromCharCode.apply(null, chunk));\n",
              "      yield {\n",
              "        response: {\n",
              "          action: 'append',\n",
              "          file: file.name,\n",
              "          data: base64,\n",
              "        },\n",
              "      };\n",
              "\n",
              "      let percentDone = fileData.byteLength === 0 ?\n",
              "          100 :\n",
              "          Math.round((position / fileData.byteLength) * 100);\n",
              "      percent.textContent = `${percentDone}% done`;\n",
              "\n",
              "    } while (position < fileData.byteLength);\n",
              "  }\n",
              "\n",
              "  // All done.\n",
              "  yield {\n",
              "    response: {\n",
              "      action: 'complete',\n",
              "    }\n",
              "  };\n",
              "}\n",
              "\n",
              "scope.google = scope.google || {};\n",
              "scope.google.colab = scope.google.colab || {};\n",
              "scope.google.colab._files = {\n",
              "  _uploadFiles,\n",
              "  _uploadFilesContinue,\n",
              "};\n",
              "})(self);\n",
              "</script> "
            ]
          },
          "metadata": {}
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Saving heart.csv to heart.csv\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "df = pd.read_csv(\"heart.csv\")"
      ],
      "metadata": {
        "id": "vnPxAkc8cEDR"
      },
      "execution_count": 3,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "print(\"Dataset Head:\")\n",
        "print(df.head())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "zFEL6NtScPaX",
        "outputId": "dcc96ac7-5802-48e3-ecc5-625206b8a00b"
      },
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Dataset Head:\n",
            "   age  sex  cp  trestbps  chol  fbs  restecg  thalach  exang  oldpeak  slope  \\\n",
            "0   52    1   0       125   212    0        1      168      0      1.0      2   \n",
            "1   53    1   0       140   203    1        0      155      1      3.1      0   \n",
            "2   70    1   0       145   174    0        1      125      1      2.6      0   \n",
            "3   61    1   0       148   203    0        1      161      0      0.0      2   \n",
            "4   62    0   0       138   294    1        1      106      0      1.9      1   \n",
            "\n",
            "   ca  thal  target  \n",
            "0   2     3       0  \n",
            "1   0     3       0  \n",
            "2   0     3       0  \n",
            "3   1     3       0  \n",
            "4   3     2       0  \n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Check for missing values\n",
        "print(\"\\nMissing Values:\")\n",
        "print(df.isnull().sum())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "cJICXt71cRDL",
        "outputId": "4865f96a-1bc4-4269-8a5e-0a736c0e706c"
      },
      "execution_count": 5,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Missing Values:\n",
            "age         0\n",
            "sex         0\n",
            "cp          0\n",
            "trestbps    0\n",
            "chol        0\n",
            "fbs         0\n",
            "restecg     0\n",
            "thalach     0\n",
            "exang       0\n",
            "oldpeak     0\n",
            "slope       0\n",
            "ca          0\n",
            "thal        0\n",
            "target      0\n",
            "dtype: int64\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# 1. Handle missing values\n",
        "# Replace missing values with the mean for numerical columns\n",
        "imputer = SimpleImputer(strategy=\"mean\")\n",
        "df_imputed = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)"
      ],
      "metadata": {
        "id": "jUZme96_cVlF"
      },
      "execution_count": 6,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Ensure no missing values remain\n",
        "print(\"\\nMissing Values After Imputation:\")\n",
        "print(df_imputed.isnull().sum())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "XWgdeKR7cbRP",
        "outputId": "d1ebe01c-709d-4459-b78f-03f9cd8ccc73"
      },
      "execution_count": 7,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Missing Values After Imputation:\n",
            "age         0\n",
            "sex         0\n",
            "cp          0\n",
            "trestbps    0\n",
            "chol        0\n",
            "fbs         0\n",
            "restecg     0\n",
            "thalach     0\n",
            "exang       0\n",
            "oldpeak     0\n",
            "slope       0\n",
            "ca          0\n",
            "thal        0\n",
            "target      0\n",
            "dtype: int64\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Separate features and target variable\n",
        "X = df_imputed.drop(\"target\", axis=1)\n",
        "y = df_imputed[\"target\"]"
      ],
      "metadata": {
        "id": "8uzaFScBcfgw"
      },
      "execution_count": 8,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Split the dataset into training and testing sets\n",
        "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)"
      ],
      "metadata": {
        "id": "OpN1zoU8cld-"
      },
      "execution_count": 9,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Standardize the features\n",
        "scaler = StandardScaler()\n",
        "X_train_scaled = scaler.fit_transform(X_train)\n",
        "X_test_scaled = scaler.transform(X_test)"
      ],
      "metadata": {
        "id": "bhoAubS4cokI"
      },
      "execution_count": 10,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# 2. Apply machine learning models with grid search optimizer\n",
        "print(\"\\nGrid Search with Random Forest and SVC:\")\n",
        "# Define the models and their hyperparameters for grid search\n",
        "model_params = {\n",
        "    \"RandomForest\": {\n",
        "        \"model\": RandomForestClassifier(random_state=42),\n",
        "        \"params\": {\n",
        "            \"n_estimators\": [50, 100, 200],\n",
        "            \"max_depth\": [None, 10, 20],\n",
        "            \"min_samples_split\": [2, 5, 10],\n",
        "        },\n",
        "    },\n",
        "    \"SVC\": {\n",
        "        \"model\": SVC(random_state=42),\n",
        "        \"params\": {\n",
        "            \"C\": [0.1, 1, 10],\n",
        "            \"kernel\": [\"linear\", \"rbf\"],\n",
        "            \"gamma\": [0.1, 1, 10],\n",
        "        },\n",
        "    },\n",
        "}\n",
        "\n",
        "# Perform grid search for each model\n",
        "best_models = {}\n",
        "for model_name, mp in model_params.items():\n",
        "    clf = GridSearchCV(mp[\"model\"], mp[\"params\"], cv=5, scoring=\"accuracy\")\n",
        "    clf.fit(X_train_scaled, y_train)\n",
        "    best_models[model_name] = clf.best_estimator_\n",
        "    print(f\"\\nBest parameters for {model_name}: {clf.best_params_}\")\n",
        "    print(f\"Training accuracy: {clf.best_score_:.4f}\")\n",
        "\n",
        "# Evaluate the best models on the test set\n",
        "for model_name, model in best_models.items():\n",
        "    y_pred = model.predict(X_test_scaled)\n",
        "    print(f\"\\n{model_name} Test Accuracy: {accuracy_score(y_test, y_pred):.4f}\")\n",
        "    print(f\"Classification Report for {model_name}:\\n{classification_report(y_test, y_pred)}\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5a1bTTT5cpho",
        "outputId": "5a9d048e-509c-41db-ec57-5eaca2ba6a9c"
      },
      "execution_count": 11,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Grid Search with Random Forest and SVC:\n",
            "\n",
            "Best parameters for RandomForest: {'max_depth': None, 'min_samples_split': 2, 'n_estimators': 50}\n",
            "Training accuracy: 0.9817\n",
            "\n",
            "Best parameters for SVC: {'C': 10, 'gamma': 0.1, 'kernel': 'rbf'}\n",
            "Training accuracy: 0.9671\n",
            "\n",
            "RandomForest Test Accuracy: 0.9854\n",
            "Classification Report for RandomForest:\n",
            "              precision    recall  f1-score   support\n",
            "\n",
            "         0.0       0.97      1.00      0.99       102\n",
            "         1.0       1.00      0.97      0.99       103\n",
            "\n",
            "    accuracy                           0.99       205\n",
            "   macro avg       0.99      0.99      0.99       205\n",
            "weighted avg       0.99      0.99      0.99       205\n",
            "\n",
            "\n",
            "SVC Test Accuracy: 0.9854\n",
            "Classification Report for SVC:\n",
            "              precision    recall  f1-score   support\n",
            "\n",
            "         0.0       0.97      1.00      0.99       102\n",
            "         1.0       1.00      0.97      0.99       103\n",
            "\n",
            "    accuracy                           0.99       205\n",
            "   macro avg       0.99      0.99      0.99       205\n",
            "weighted avg       0.99      0.99      0.99       205\n",
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# 3. Use two feature selection methods\n",
        "print(\"\\nFeature Selection Using SelectKBest and RFE:\")\n",
        "\n",
        "# Method 1: SelectKBest\n",
        "selector_kbest = SelectKBest(score_func=f_classif, k=5)  # Select top 5 features\n",
        "X_new_kbest = selector_kbest.fit_transform(X_train_scaled, y_train)\n",
        "selected_features_kbest = X.columns[selector_kbest.get_support()]\n",
        "print(f\"\\nTop features selected by SelectKBest: {list(selected_features_kbest)}\")\n",
        "\n",
        "# Method 2: Recursive Feature Elimination (RFE)\n",
        "model = LogisticRegression(max_iter=1000, random_state=42)  # Logistic Regression as base model\n",
        "selector_rfe = RFE(model, n_features_to_select=5)\n",
        "selector_rfe.fit(X_train_scaled, y_train)\n",
        "selected_features_rfe = X.columns[selector_rfe.support_]\n",
        "print(f\"\\nTop features selected by RFE: {list(selected_features_rfe)}\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5wRGIKQuc7l0",
        "outputId": "428a3a5c-5c60-4416-c2ec-71fd6af26580"
      },
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Feature Selection Using SelectKBest and RFE:\n",
            "\n",
            "Top features selected by SelectKBest: ['cp', 'thalach', 'exang', 'oldpeak', 'ca']\n",
            "\n",
            "Top features selected by RFE: ['cp', 'thalach', 'oldpeak', 'ca', 'thal']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# 4. Apply machine learning models to the selected features and evaluate\n",
        "print(\"\\nEvaluating Models on Selected Features:\")\n",
        "\n",
        "# Subset the dataset to the features selected by SelectKBest\n",
        "X_train_kbest = X_train_scaled[:, selector_kbest.get_support()]\n",
        "X_test_kbest = X_test_scaled[:, selector_kbest.get_support()]\n",
        "\n",
        "# Train and evaluate Random Forest with SelectKBest features\n",
        "rf_kbest = RandomForestClassifier(random_state=42, n_estimators=100)\n",
        "rf_kbest.fit(X_train_kbest, y_train)\n",
        "y_pred_kbest = rf_kbest.predict(X_test_kbest)\n",
        "print(f\"\\nRandom Forest with SelectKBest Features Accuracy: {accuracy_score(y_test, y_pred_kbest):.4f}\")\n",
        "print(f\"Classification Report:\\n{classification_report(y_test, y_pred_kbest)}\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7TTwvwZDdD6h",
        "outputId": "13fb80b6-a5ae-4798-adeb-7e9cd0ecf13f"
      },
      "execution_count": 14,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Evaluating Models on Selected Features:\n",
            "\n",
            "Random Forest with SelectKBest Features Accuracy: 0.9805\n",
            "Classification Report:\n",
            "              precision    recall  f1-score   support\n",
            "\n",
            "         0.0       0.97      0.99      0.98       102\n",
            "         1.0       0.99      0.97      0.98       103\n",
            "\n",
            "    accuracy                           0.98       205\n",
            "   macro avg       0.98      0.98      0.98       205\n",
            "weighted avg       0.98      0.98      0.98       205\n",
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Subset the dataset to the features selected by RFE\n",
        "X_train_rfe = X_train_scaled[:, selector_rfe.support_]\n",
        "X_test_rfe = X_test_scaled[:, selector_rfe.support_]"
      ],
      "metadata": {
        "id": "OkSxmJPCdSVm"
      },
      "execution_count": 15,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Train and evaluate Logistic Regression with RFE features\n",
        "lr_rfe = LogisticRegression(max_iter=1000, random_state=42)\n",
        "lr_rfe.fit(X_train_rfe, y_train)\n",
        "y_pred_rfe = lr_rfe.predict(X_test_rfe)\n",
        "print(f\"\\nLogistic Regression with RFE Features Accuracy: {accuracy_score(y_test, y_pred_rfe):.4f}\")\n",
        "print(f\"Classification Report:\\n{classification_report(y_test, y_pred_rfe)}\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "JCOfccnkdXUA",
        "outputId": "204bd793-9426-4acd-97ca-8d0f83aa7174"
      },
      "execution_count": 16,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Logistic Regression with RFE Features Accuracy: 0.7805\n",
            "Classification Report:\n",
            "              precision    recall  f1-score   support\n",
            "\n",
            "         0.0       0.84      0.70      0.76       102\n",
            "         1.0       0.74      0.86      0.80       103\n",
            "\n",
            "    accuracy                           0.78       205\n",
            "   macro avg       0.79      0.78      0.78       205\n",
            "weighted avg       0.79      0.78      0.78       205\n",
            "\n"
          ]
        }
      ]
    }
  ]
}