{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "4e6f6cb1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.model_selection import cross_val_score\n",
    "from sklearn.metrics import accuracy_score, f1_score, classification_report, confusion_matrix, roc_curve\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4dd5223b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c1ab7ec9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset shape: (116, 10)\n",
      "   Age        BMI  Glucose  Insulin      HOMA   Leptin  Adiponectin  Resistin  \\\n",
      "0   48  23.500000       70    2.707  0.467409   8.8071     9.702400   7.99585   \n",
      "1   83  20.690495       92    3.115  0.706897   8.8438     5.429285   4.06405   \n",
      "2   82  23.124670       91    4.498  1.009651  17.9393    22.432040   9.27715   \n",
      "3   68  21.367521       77    3.226  0.612725   9.8827     7.169560  12.76600   \n",
      "4   86  21.111111       92    3.549  0.805386   6.6994     4.819240  10.57635   \n",
      "\n",
      "     MCP.1  Classification  \n",
      "0  417.114               1  \n",
      "1  468.786               1  \n",
      "2  554.697               1  \n",
      "3  928.220               1  \n",
      "4  773.920               1  \n"
     ]
    }
   ],
   "source": [
    "# fetch dataset \n",
    "data = pd.read_csv(\"dataR2.csv\")\n",
    "  \n",
    "# data (as pandas dataframes) \n",
    "X = data.drop(columns='Classification')\n",
    "y = data['Classification']\n",
    "  \n",
    "print(\"Dataset shape:\", data.shape)\n",
    "print(data.head())\n",
    "\n",
    "# transform {1,2} to {0,1}\n",
    "y = y.map({1: 0, 2: 1})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a1004c28",
   "metadata": {},
   "source": [
    "# K-NN classifier "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "082c143b",
   "metadata": {},
   "source": [
    "### Cross-validation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "754dce9b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of samples: 116\n",
      "Number of features: 9\n"
     ]
    }
   ],
   "source": [
    "print(\"Number of samples:\", X.shape[0])\n",
    "print(\"Number of features:\", X.shape[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01bb817a",
   "metadata": {},
   "source": [
    "Then d is small enough to insure that we are not in the curse of dimention"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "feb42adf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The best k for k-NN is k = 22\n"
     ]
    }
   ],
   "source": [
    "k_scores = []\n",
    "K_list = np.arange(1, X.shape[0] // 4 )  # concidering 1/4 of the samples as neaighbors is large enough for k-NN to don't overfit\n",
    "\n",
    "# Cross-validation to find the best k\n",
    "\n",
    "for k in K_list:\n",
    "    knn = KNeighborsClassifier(n_neighbors=k)\n",
    "    score = cross_val_score(knn, X, y, cv=5, scoring='accuracy')\n",
    "    k_scores.append(score.mean())\n",
    "\n",
    "k_scores = np.array(k_scores)\n",
    "\n",
    "print(\"The best k for k-NN is k =\", np.argmax(k_scores))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "064a5aa7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 0.8\n",
      "F1 Score: 0.798014888337469\n",
      "Classification Report:\n",
      "               precision    recall  f1-score   support\n",
      "\n",
      "           0       0.86      0.71      0.77        17\n",
      "           1       0.76      0.89      0.82        18\n",
      "\n",
      "    accuracy                           0.80        35\n",
      "   macro avg       0.81      0.80      0.80        35\n",
      "weighted avg       0.81      0.80      0.80        35\n",
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 21292 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 50832 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)\n",
    "\n",
    "scaler = StandardScaler()\n",
    "X_train = scaler.fit_transform(X_train)\n",
    "X_test = scaler.transform(X_test)\n",
    "\n",
    "knn = KNeighborsClassifier(n_neighbors=22) # using the best k found\n",
    "knn.fit(X_train, y_train)\n",
    "\n",
    "y_pred = knn.predict(X_test)\n",
    "\n",
    "acc = accuracy_score(y_test, y_pred)\n",
    "f1 = f1_score(y_test, y_pred, average='weighted')\n",
    "class_report = classification_report(y_test, y_pred)\n",
    "\n",
    "# Display differents performance of the model\n",
    "print(\"Accuracy:\", acc)\n",
    "print(\"F1 Score:\", f1)\n",
    "print(\"Classification Report:\\n\", class_report)\n",
    "\n",
    "# Plottinf the confusion matrix\n",
    "cm = confusion_matrix(y_test, y_pred)\n",
    "plt.figure(figsize=(8, 6))\n",
    "plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)\n",
    "plt.title('Confusion Matrix')\n",
    "for i in range(cm.shape[0]):\n",
    "    for j in range(cm.shape[1]):\n",
    "        plt.text(j, i, cm[i, j], horizontalalignment='center', color='white' if cm[i, j] > cm.max() / 2 else 'black')\n",
    "plt.xticks(np.arange(len(np.unique(y))),labels = [\"negative\", \"positive\"])\n",
    "plt.yticks(np.arange(len(np.unique(y))),labels = [\"negative\", \"positive\"])\n",
    "plt.xlabel('Predicted label')\n",
    "plt.ylabel('True label')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# Plotting ROC curve\n",
    "fpr, tpr, thresholds = roc_curve(y_test, knn.predict_proba(X_test)[:, 1])\n",
    "plt.figure(figsize=(8, 6))\n",
    "plt.plot(fpr, tpr, color='blue', label='ROC curve (area = {:.2f})'.format(f1))\n",
    "plt.plot([0, 1], [0, 1], color='red', linestyle='--')\n",
    "plt.xlim([-0.05, 1.05])\n",
    "plt.ylim([-0.05, 1.05])\n",
    "plt.xlabel('False Positive Rate')\n",
    "plt.ylabel('True Positive Rate')\n",
    "plt.title('Receiver Operating Characteristic (ROC) Curve')\n",
    "plt.legend(loc='lower right')\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "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.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
