{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "provenance": [], "collapsed_sections": [ "lx4RpN47ybt6" ] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "code", "source": [ "import tensorflow as tf\n", "import numpy as np\n", "import pandas as pd\n", "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "from keras import losses\n", "from keras import optimizers\n", "from keras import metrics\n", "import math\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns" ], "metadata": { "id": "sIDDU2PYPdH_" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "CSV_HEADER = [\n", " \"duration\",\n", " \"protocol_type\",\n", " \"service\",\n", " \"flag\",\n", " \"src_bytes\",\n", " \"dst_bytes\",\n", " \"land\",\n", " \"wrong_fragment\",\n", " \"urgent\",\n", " \"hot\",\n", " \"num_failed_logins\",\n", " \"logged_in\",\n", " \"num_compromised\",\n", " \"root_shell\",\n", " \"su_attempted\",\n", " \"num_root\",\n", " \"num_file_creations\",\n", " \"num_shells\",\n", " \"num_access_files\",\n", " \"num_outbound_cmds\",\n", " \"is_host_login\",\n", " \"is_guest_login\",\n", " \"count\",\n", " \"srv_count\",\n", " \"serror_rate\",\n", " \"srv_serror_rate\",\n", " \"rerror_rate\",\n", " \"srv_rerror_rate\",\n", " \"same_srv_rate\",\n", " \"diff_srv_rate\",\n", " \"srv_diff_host_rate\",\n", " \"dst_host_count\",\n", " \"dst_host_srv_count\",\n", " \"dst_host_same_srv_rate\",\n", " \"dst_host_diff_srv_rate\",\n", " \"dst_host_same_src_port_rate\",\n", " \"dst_host_srv_diff_host_rate\",\n", " \"dst_host_serror_rate\",\n", " \"dst_host_srv_serror_rate\",\n", " \"dst_host_rerror_rate\",\n", " \"dst_host_srv_rerror_rate\",\n", " \"class\"\n", "]\n", "\n", "\n", "train_data = pd.read_csv(\"train.csv\", header=None, names=CSV_HEADER)\n", "\n", "test_data = pd.read_csv(\"test.csv\", header=None, names=CSV_HEADER)\n", "\n", "print(f\"Train dataset shape: {train_data.shape}\")\n", "print(f\"Test dataset shape: {test_data.shape}\")\n", "train_data['class'] = train_data['class'].str.replace(r\"^(.(?:53: FutureWarning: The default value of regex will change from True to False in a future version.\n", " train_data['class'] = train_data['class'].str.replace(r\"^(.(?:54: FutureWarning: The default value of regex will change from True to False in a future version.\n", " test_data['class'] = test_data['class'].str.replace(r\"^(.(?" ], "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlkAAAHPCAYAAABgL8+EAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABJdklEQVR4nO3dfVxUZf7/8feADN4xIC6xmZKASVaQWIkEsd5moKmVpbZZrqTWpgbprkreVe56s6aGWglhabaaVluZSJaZpPltt5XWWitvwMLMm0RnUJHb+f3hcn5Ooxs7emKw1/Px8IFzzudc5zqzXrPvrnPNweJ0Op0CAADAReVT3x0AAAC4FBGyAAAATEDIAgAAMAEhCwAAwASELAAAABMQsgAAAExAyAIAADABIQsAAMAEhCwAAAATELIA/CK88cYbioqK0v79++u7KwB+IQhZAPALt3nzZi1cuLC+uwFccghZAPALt3nzZi1atKi+uwFccghZAAAAJiBkAfA6eXl5ioqK0t///ne3fatWrVJUVJR27dolSfrqq680ceJE9ejRQ9HR0UpISNCkSZN07NixnzxPVFTUOW+Tde/eXRMnTnTZ5nA49Kc//Um/+c1vdN1116lXr17KyspSTU1Nna5p8+bNuu+++xQbG6tOnTrprrvu0tq1a11q1q9frzvvvFMxMTGKi4vT+PHjdejQIZeaoUOHaujQoW7tT5w4Ud27dzde79+/X1FRUcrJydGrr76qnj176rrrrtNdd92lHTt2uBz3yiuvGO9H7R8AF65RfXcAAH6sa9euatq0qdavX6/OnTu77MvNzdVVV12l9u3bS5I+/vhjFRcX684771RISIh2796t1atXa8+ePVq9erUsFssF96esrEz33XefDh06pMGDB+vyyy9XQUGB5s2bpyNHjujxxx//r8e/8cYbysjI0FVXXaVRo0YpICBAX375pT766CPdfvvtRs2kSZMUHR2txx57TEePHtXy5cu1fft2vfnmm7LZbB71/Z133tHJkyc1aNAgWSwWvfDCCxozZozef/99+fn5adCgQTp8+LC2bt2qOXPmeHQOAOdGyALgdRo3bqzu3bvr3Xff1eTJk+Xr6ytJOnLkiP7xj39o9OjRRu29996r4cOHuxzfsWNHPfbYY/rnP/+pG2+88YL78+KLL6q4uFh/+9vf1LZtW0nS4MGDddlllyknJ0fDhw/X5Zdffs5jS0tLNWPGDMXExOjll1+Wv7+/sc/pdEqSKisrNXfuXLVv316vvPKKUXPDDTdo1KhReumllzR27FiP+n7gwAFt2LBBgYGBkqTw8HD9/ve/15YtW9StWzfFxsaqbdu22rp1q/r37+/ROQCcG7cLAXil5ORkHT161OWW4bvvvquamhqlpKQY2xo3bmz8vby8XCUlJbr++uslSf/+978vSl/y8vJ0ww03yGazqaSkxPhz8803q7q6Wv/4xz/Oe+zWrVt18uRJjRw50iVgSTJm2b744gsdPXpUQ4YMcanp2rWrIiIi9OGHH3rc95SUFCNgSTJCZ3FxscdtAqgbZrIAeKWkpCQFBAQoNzdX8fHxks7cKuzQoYPCw8ONuuPHj2vRokXKzc3V0aNHXdooLS29KH355ptv9PXXXxv9+LGSkpLzHvvtt99Kkq666qrz1hw4cECSXK6rVkREhP75z3/+L9118eMZttrA5XA4PG4TQN0QsgB4JavVqp49e+q9997TtGnTdPToUW3fvl2PPfaYS11aWpoKCgqUmpqqDh06qGnTpqqpqdGDDz5o3I77X1VXV7u8rqmpUUJCgh588MFz1tfeQqxPP+5zrdpbrT/m6XsDoO4IWQC8VnJysv72t79p27Zt2rt3r5xOp5KTk439drtd27Zt05gxY1zWae3bt69O7QcGBrrN6FRUVOjIkSMu28LCwnTq1CndfPPN//M1hIWFSZJ2796tK6+88pw1rVq1kiQVFRW5zZYVFRUZ+2v7fK5bfbWzYZ64GF8OAOCONVkAvNbNN9+soKAg5ebmav369YqJiVGbNm2M/eebpVm2bFmd2m/Tpo0+/fRTl22rV692mxVKTk5WQUGBPvroI7c2HA6HqqqqznuOxMRENWvWTEuWLFF5ebnLvtrZpOuuu04tW7bUqlWrVFFRYezfvHmz9u7dq65du7r0ubCw0OUW5VdffaXt27f/9AWfR5MmTYxrAXDxMJMFwGv5+fmpV69eWrduncrKyjRhwgSX/c2bN9dNN92kF154QZWVlQoNDdXWrVvr/PsJ7777bk2bNk1jxozRzTffrK+++kpbtmxRixYtXOpSU1P1wQcf6KGHHtIdd9yha6+9VmVlZdq1a5feffddbdy4UcHBwec8R/PmzTVp0iRNnjxZAwcOVN++fWWz2fTVV1/p9OnTmj17tvz8/DR+/HhNmjRJ9913n/r06WM8wuGKK67QsGHDjPYGDhyol156SampqRo4cKCOHj2qVatWqV27djp58uT/9gb/x7XXXitJmjFjhhITE+Xr66s+ffp41BaA/4+QBcCrpaSkaM2aNbJYLC63Cms9/fTTeuqpp/TXv/5VTqdTCQkJys7O1i233PKTbd9zzz3av3+/XnvtNX300Ue64YYb9OKLL7qEGunMTM/LL7+sJUuWKC8vT2+++aaaN2+utm3basyYMQoICPiv57n77rvVsmVLZWVl6dlnn1WjRo0UERHhcp4777xTjRs3VnZ2tubOnaumTZuqZ8+e+sMf/uDyjKzIyEjNnj1bmZmZmjlzptq1a6c5c+bonXfeOefDW+vi1ltv1dChQ7Vu3Tq9/fbbcjqdhCzgIrA4Wf0IAABw0bEmCwAAwASELAAAABMQsgAAAExAyAIAADABIQsAAMAEXhWyhg4dqqioqHP+WbdunVG3Zs0a9e7dW9HR0erXr582bdrk1lZpaakyMjLUuXNnxcbGauzYsTp8+LBb3fbt2zVo0CDFxMSoW7duysrKcvt1E06nU1lZWeratatiYmI0aNAgffbZZxf9+gEAwKXDqx7hsGfPHp04ccJl27Jly7RhwwZ99NFHCg4O1rp16zRu3Dg99NBD6tKli3Jzc/X666/rlVdeUceOHY3jUlNTtWfPHk2YMEH+/v5asGCBfHx89Prrr6tRozOPB/vmm280YMAAJSQk6Le//a2+/vprzZ07V+np6UpNTTXaysrKUmZmpsaPH6+oqCi98sor+vjjj/XWW2+5PH0aAACglleFrHPp0aOHIiMjlZWVJUnq3bu3rrvuOj399NNGzeDBgxUQEKDs7GxJUkFBgQYPHqycnBwlJiZKkgoLC5WSkqJ58+YpJSVFkjR16lRt2bJFeXl5slqtkqR58+Zp5cqV2rp1q6xWq8rLy3XzzTfrt7/9rfGLaSsqKnTbbbcpKSlJ06dP9/janE6namq8+u0HAABn8fGx1Pn3fXr1E9+3b9+u/fv3Ky0tTZJUXFysffv26Q9/+INLXUpKiubMmaOKigpZrVbl5+fLZrMpISHBqImIiFCHDh2Un59vhKz8/Hz16tXLCFi1bS1ZskQFBQWKi4vT9u3bdeLECZcnTVutVvXq1UvvvffeBV1fTY1TJSWe/RoMAADw8wsObiZf30sgZL3zzjtq2rSpevToIenMbJQkhYeHu9RFRkaqsrJSxcXFioyMVGFhocLDw92SZkREhNHGqVOn9P333ysiIsKtxmKxqLCwUHFxcUb9j+siIyO1bNkynT59Wo0bN/b4Ghs18qplcQAA4CLx2pBVVVWl9evXq3v37mratKkkyW63S5LL7/E6+3XtfofDcc7fJRYYGKgvvvhC0pmF8edqy2q1qkmTJi5tWa1W+fv7u53T6XTKbrd7HLJ8fCxq0aKZR8cCAADv5rUha+vWrSopKVHfvn3ruyumqalxyuE4Vd/dAAAAdWSzNZGvb93uQnltyHrnnXcUFBRkLFyXzsxESWdmoUJCQoztDofDZb/NZtPBgwfd2rTb7UZN7UxX7YxWrYqKCpWVlbm0VVFRofLycpfZLIfDIYvFYtR5qqqq5oKOBwAA3skrFwSdPn1a77//vm677Tb5+fkZ22vXRdWuk6pVWFgoPz8/43EKERERKioqcnveVVFRkdFG06ZNdfnll7u1VXtcbV3tz6KiIrdztmrV6oLWYwEAgEuXV4asDz74QKdOndLtt9/usr1NmzZq27at8vLyXLbn5uYqPj7e+JZgUlKS7Ha7tm3bZtQUFRVp586dSkpKMrYlJSVp48aNqqysdGnLZrMpNjZWktSpUyc1b95c69evN2oqKyu1YcMGl7YAAADO5pW3C9euXatWrVrphhtucNs3ZswYjR8/XmFhYYqLi1Nubq527NihFStWGDWxsbFKTExURkaG8TDS+fPnKyoqSrfeeqtRl5qaqrVr12rcuHEaMmSIdu3apZycHKWnpxuBzd/fX6NGjdLChQsVHBys9u3ba+XKlTp+/LjLA0sBAADO5nUPI7Xb7UpISNADDzzg9jysWmvWrFF2drYOHDig8PBwPfbYY+rWrZtLTWlpqWbOnKn33ntPVVVVSkxM1OTJkxUaGupSt337ds2aNUtffvmlgoOD9dvf/lYjRoxwefxD7a/V+etf/6qSkhJ16NBBkyZNMma7PFVdXcNzsgAAaEDOPCerbjcCvS5k/ZIQsgAAaFj+l5DllWuyAAAAGjpCFgAAgAkIWQAAACYgZAEAAJiAkAUAAGACr3xOFi4eHx+LfHwsP10I/ILU1DhVU8MXqwGYi5B1CfPxsSgoqGmdv2oK/FJUV9fo+PFTBC0ApiJkXcJ8fCzy9fXR4pVb9d1he313B/AKV1wWqEeGJMjHx0LIAmAqQtYvwHeH7dr33bH67gYAAL8o3EcCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwASELAAAABMQsgAAAExAyAIAADABIQsAAMAEhCwAAAATELIAAABMQMgCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwASELAAAABMQsgAAAExAyAIAADABIQsAAMAEhCwAAAATELIAAABMQMgCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwAReGbL+9re/acCAAYqOjlZcXJwefPBBnT592tj/wQcfqF+/foqOjlbv3r31+uuvu7VRUVGh2bNnKyEhQR07dtTvfvc7FRYWutXt3btXv/vd79SxY0clJCRozpw5qqiocKtbs2aNevfurejoaPXr10+bNm26uBcNAAAuKV4Xsp577jk99dRTSklJUU5Ojp588km1bt1a1dXVkqRPP/1Uo0ePVseOHZWdna3k5GQ9/vjjysvLc2lnxowZWrNmjdLT07Vw4UJVVFRo2LBhKi0tNWrsdrseeOABVVZWauHChUpPT9fq1as1a9Ysl7bWrVunKVOmKDk5WdnZ2erYsaNGjx6tzz77zPT3AwAANEyN6rsDZyssLNSiRYv07LPP6je/+Y2xvXfv3sbfn3vuOcXExOjJJ5+UJHXp0kXFxcXKzMzUbbfdJkk6ePCgXnvtNU2bNk0DBw6UJEVHR6tbt25atWqVRowYIUlatWqVTp48qUWLFikoKEiSVF1drSeeeEKjRo1SaGioJCkzM1N9+vRRWlqacc5du3Zp8eLFys7ONvU9AQAADZNXzWS98cYbat26tUvAOltFRYU++eQTI0zVSklJ0d69e7V//35J0pYtW1RTU+NSFxQUpISEBOXn5xvb8vPzFR8fbwQsSUpOTlZNTY22bt0qSSouLta+ffuUnJzsds5t27ad89YiAACAV4Wsf/3rX2rfvr2effZZxcfH67rrrtPgwYP1r3/9S5L07bffqrKyUhERES7HRUZGSpKx5qqwsFAtW7ZUYGCgW93Z67IKCwvd2rLZbAoJCXFpS5LCw8Pd2qqsrFRxcfGFXjYAALgEedXtwiNHjuiLL77Qrl27NG3aNDVp0kTPP/+8hg8frg0bNshut0s6E4TOVvu6dr/D4VBAQIBb+zabzaiprftxW5IUGBho1NX1nJ5q1Mi8nOvr61UZGvAqjA8AZvOqkOV0OnXq1Ck988wzuvrqqyVJ119/vbp3764VK1YoMTGxnnt4cfn4WNSiRbP67gbwi2SzNanvLgC4xHlVyLLZbAoKCjIClnRmLdU111yjPXv2qE+fPpLk8g1B6cyMlCTj9qDNZtOJEyfc2nc4HC63EG02m1tb0pnZqdq62p+lpaUKCQk57zk9UVPjlMNxyuPjf4qvrw//RwKch8NRpurqmvruBoAGxmZrUueZcK8KWe3atdO33357zn3l5eUKCwuTn5+fCgsLdcsttxj7atdN1a6vioiI0A8//OASlmrrzl6DFRER4fbsrNLSUh05csSlrXMdW1hYKD8/P7Vp0+ZCLllVVXzIA/WhurqG8QfAVF61KKFbt246fvy4vvzyS2PbsWPH9O9//1vXXnutrFar4uLi9O6777ocl5ubq8jISLVu3VqSlJiYKB8fH23YsMGosdvt2rJli5KSkoxtSUlJ+vjjj41ZKUnKy8uTj4+PEhISJElt2rRR27Zt3Z7DlZubq/j4eFmt1ov3BgAAgEuGV81k9ezZU9HR0Ro7dqzS09Pl7++vrKwsWa1W3XvvvZKkhx9+WPfff7+mT5+u5ORkffLJJ3rnnXc0f/58o51f//rXGjhwoObMmSMfHx+FhoZqyZIlCggI0ODBg426wYMH6+WXX9YjjzyiUaNG6dChQ5ozZ44GDx5sPCNLksaMGaPx48crLCxMcXFxys3N1Y4dO7RixYqf780BAAANisXpdDrruxNnKykp0cyZM7Vp0yZVVlbqxhtv1KRJk9SuXTujZuPGjVqwYIGKiorUqlUrjRw50njoaK2KigrNnz9fb731lk6ePKlOnTpp8uTJxuMeau3du1dPPfWUCgoK1KxZM/Xv31/p6eluM1Rr1qxRdna2Dhw4oPDwcD322GPq1q3bBV1rdXWNSkpOXlAb/02jRj5q0aKZMp7J1b7vjpl2HqAhaXtFC/350RQdO3aS24UA/mfBwc3qvCbL60LWLwkhC/j5XUohy8fHIh8fS313A/AqNTVO1dSYF23+l5DlVbcLAQB1c+YRME3k4+Nb310BvEpNTbWOHSszNWjVFSELABqgM7NYvip6J1tlR7+v7+4AXqFJy8sV3neEfHwshCwAwIUpO/q9yg6d+9E3AOqXVz3CAQAA4FJByAIAADABIQsAAMAEhCwAAAATELIAAABMQMgCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwASELAAAABMQsgAAAExAyAIAADABIQsAAMAEhCwAAAATELIAAABMQMgCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwASELAAAABMQsgAAAExAyAIAADABIQsAAMAEhCwAAAATELIAAABMQMgCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwASELAAAABMQsgAAAEzgVSHrjTfeUFRUlNufuXPnutStWbNGvXv3VnR0tPr166dNmza5tVVaWqqMjAx17txZsbGxGjt2rA4fPuxWt337dg0aNEgxMTHq1q2bsrKy5HQ6XWqcTqeysrLUtWtXxcTEaNCgQfrss88u6rUDAIBLS6P67sC5vPDCCwoICDBeh4aGGn9ft26dpkyZooceekhdunRRbm6uRo8erVdeeUUdO3Y06tLS0rRnzx5Nnz5d/v7+WrBggUaMGKHXX39djRqduexvvvlGqampSkhIUFpamr7++mvNnTtXvr6+Sk1NNdrKzs5WZmamxo8fr6ioKL3yyisaPny43nrrLbVp08b8NwQAADQ4Xhmyrr32WgUHB59zX2Zmpvr06aO0tDRJUpcuXbRr1y4tXrxY2dnZkqSCggJt2bJFOTk5SkxMlCSFh4crJSVFGzZsUEpKiiQpJydHLVq00Lx582S1WhUfH6+SkhI9//zzGjp0qKxWq8rLy7VkyRINHz5cw4YNkyTdcMMNuu2225STk6Pp06eb+l4AAICGyatuF/6U4uJi7du3T8nJyS7bU1JStG3bNlVUVEiS8vPzZbPZlJCQYNRERESoQ4cOys/PN7bl5+erR48eslqtLm05HA4VFBRIOnM78cSJEy7ntFqt6tWrl0tbAAAAZ/PKmay+ffvq2LFjatWqle655x49+OCD8vX1VWFhoaQzs1Jni4yMVGVlpYqLixUZGanCwkKFh4fLYrG41EVERBhtnDp1St9//70iIiLcaiwWiwoLCxUXF2fU/7guMjJSy5Yt0+nTp9W4cWOPr7VRI/Nyrq9vg8rQwM+qoY+Pht5/wEzeMj68KmSFhIRozJgxuv7662Wx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wASELAAAABMQsgAAAExAyAIAADABIQsAAMAEhCwAAAATELIAAABMQMgCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwASELAAAABMQsgAAAExAyAIAADABIQsAAMAEhCwAAAATELIAAABMQMgCAAAwASELAADABIQsAAAAExCyAAAATEDIAgAAMAEhCwAAwASELAAAABN4Vchav369Hn74YSUlJaljx47q37+/XnvtNTmdTpe6NWvWqHfv3oqOjla/fv20adMmt7ZKS0uVkZGhzp07KzY2VmPHjtXhw4fd6rZv365BgwYpJiZG3bp1U1ZWltv5nE6nsrKy1LVrV8XExGjQoEH67LPPLuq1AwCAS4tXhayXXnpJTZo00cSJE/Xcc88pKSlJU6ZM0eLFi42adevWacqUKUpOTlZ2drY6duyo0aNHu4WetLQ0bd26VdOnT9fcuXNVVFSkESNGqKqqyqj55ptvlJqaqpCQEC1ZskQPPPCAMjMztXTpUpe2srOzlZmZqWHDhmnJkiUKCQnR8OHDVVxcbOr7AQAAGq5G9d2Bsz333HMKDg42XsfHx+v48eN68cUX9fvf/14+Pj7KzMxUnz59lJaWJknq0qWLdu3apcWLFys7O1uSVFBQoC1btignJ0eJiYmSpPDwcKWkpGjDhg1KSUmRJOXk5KhFixaaN2+erFar4uPjVVJSoueff15Dhw6V1WpVeXm5lixZouHDh2vYsGGSpBtuuEG33XabcnJyNH369J/t/QEAAA2HV81knR2wanXo0EEnTpzQqVOnVFxcrH379ik5OdmlJiUlRdu2bVNFRYUkKT8/XzabTQkJCUZNRESEOnTooPz8fGNbfn6+evToIavV6tKWw+FQQUGBpDO3E0+cOOFyTqvVql69erm0BQAAcDavClnn8s9//lOhoaFq3ry5CgsLJZ2ZlTpbZGSkKisrjdt3hYWFCg8Pl8VicamLiIgw2jh16pS+//57RUREuNVYLBajrvbnj+siIyN14MABnT59+iJdKQAAuJR41e3CH/v000+Vm5urCRMmSJLsdrskyWazudTVvq7d73A4FBAQ4NZeYGCgvvjiC0lnFsafqy2r1aomTZq4tGW1WuXv7+92TqfTKbvdrsaNG3t8jY0amZdzfX29PkMD9aahj4+G3n/ATN4yPrw2ZB08eFDp6emK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\n" }, "metadata": {} } ] }, { "cell_type": "markdown", "source": [ "## Removing outliers and duplicates" ], "metadata": { "id": "wHhIvDl9V5kl" } }, { "cell_type": "code", "source": [ "def Remove_Outlier_Indices(df):\n", " Q1 = df.quantile(0.02)\n", " Q3 = df.quantile(0.98)\n", " IQR = Q3 - Q1\n", " #trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR)))\n", " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR))).any(axis=1)\n", " return trueList\n", "\n", "nonOutlierList = Remove_Outlier_Indices(train_data)\n", "new_train_data = train_data[nonOutlierList]\n", "\n", "nonOutlierList = Remove_Outlier_Indices(test_data)\n", "new_test_data = test_data[nonOutlierList]" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "8GZwWkuSV5HT", "outputId": "f174d533-118b-4e2a-abe7-9baa85269641" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ ":2: FutureWarning: The default value of numeric_only in DataFrame.quantile is deprecated. In a future version, it will default to False. Select only valid columns or specify the value of numeric_only to silence this warning.\n", " Q1 = df.quantile(0.02)\n", ":3: FutureWarning: The default value of numeric_only in DataFrame.quantile is deprecated. In a future version, it will default to False. Select only valid columns or specify the value of numeric_only to silence this warning.\n", " Q3 = df.quantile(0.98)\n", ":6: FutureWarning: Automatic reindexing on DataFrame vs Series comparisons is deprecated and will raise ValueError in a future version. Do `left, right = left.align(right, axis=1, copy=False)` before e.g. `left == right`\n", " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR))).any(axis=1)\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Merging train and test datasets" ], "metadata": { "id": "uNzhq0uHKkUB" } }, { "cell_type": "code", "source": [ "frames = [new_train_data, new_test_data]\n", "df = pd.concat(frames)\n", "df = df.reset_index(drop=True)\n", "df" ], "metadata": { "id": "3kxP6kBRGX2y", "colab": { "base_uri": "https://localhost:8080/", "height": 444 }, "outputId": "a4b2c9b5-1bcc-4922-eba8-8a2f9c39b881" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " duration protocol_type service flag src_bytes dst_bytes land \\\n", "0 0 1 20 9 491 0 0 \n", "1 0 2 44 9 146 0 0 \n", "2 0 1 49 5 0 0 0 \n", "3 0 1 24 9 232 8153 0 \n", "4 0 1 24 9 199 420 0 \n", "... ... ... ... ... ... ... ... \n", "139899 0 0 14 9 1032 0 0 \n", "139900 0 1 49 9 794 333 0 \n", "139901 0 1 22 9 317 938 0 \n", "139902 0 2 11 9 42 42 0 \n", "139903 0 1 52 1 0 0 0 \n", "\n", " wrong_fragment urgent hot ... dst_host_srv_count \\\n", "0 0 0 0 ... 25 \n", "1 0 0 0 ... 1 \n", "2 0 0 0 ... 26 \n", "3 0 0 0 ... 255 \n", "4 0 0 0 ... 255 \n", "... ... ... ... ... ... \n", "139899 0 0 0 ... 255 \n", "139900 0 0 0 ... 141 \n", "139901 0 0 0 ... 255 \n", "139902 0 0 0 ... 252 \n", "139903 0 0 0 ... 21 \n", "\n", " dst_host_same_srv_rate dst_host_diff_srv_rate \\\n", "0 0.17 0.03 \n", "1 0.00 0.60 \n", "2 0.10 0.05 \n", "3 1.00 0.00 \n", "4 1.00 0.00 \n", "... ... ... \n", "139899 1.00 0.00 \n", "139900 0.72 0.06 \n", "139901 1.00 0.00 \n", "139902 0.99 0.01 \n", "139903 0.08 0.03 \n", "\n", " dst_host_same_src_port_rate dst_host_srv_diff_host_rate \\\n", "0 0.17 0.00 \n", "1 0.88 0.00 \n", "2 0.00 0.00 \n", "3 0.03 0.04 \n", "4 0.00 0.00 \n", "... ... ... \n", "139899 1.00 0.00 \n", "139900 0.01 0.01 \n", "139901 0.01 0.01 \n", "139902 0.00 0.00 \n", "139903 0.00 0.00 \n", "\n", " dst_host_serror_rate dst_host_srv_serror_rate dst_host_rerror_rate \\\n", "0 0.00 0.00 0.05 \n", "1 0.00 0.00 0.00 \n", "2 1.00 1.00 0.00 \n", "3 0.03 0.01 0.00 \n", "4 0.00 0.00 0.00 \n", "... ... ... ... \n", "139899 0.00 0.00 0.00 \n", "139900 0.01 0.00 0.00 \n", "139901 0.01 0.00 0.00 \n", "139902 0.00 0.00 0.00 \n", "139903 0.00 0.00 0.44 \n", "\n", " dst_host_srv_rerror_rate class \n", "0 0.00 normal \n", "1 0.00 normal \n", "2 0.00 anomaly \n", "3 0.01 normal \n", "4 0.00 normal \n", "... ... ... \n", "139899 0.00 anomaly \n", "139900 0.00 normal \n", "139901 0.00 normal \n", "139902 0.00 normal \n", "139903 1.00 anomaly \n", "\n", "[139904 rows x 42 columns]" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
durationprotocol_typeserviceflagsrc_bytesdst_byteslandwrong_fragmenturgenthot...dst_host_srv_countdst_host_same_srv_ratedst_host_diff_srv_ratedst_host_same_src_port_ratedst_host_srv_diff_host_ratedst_host_serror_ratedst_host_srv_serror_ratedst_host_rerror_ratedst_host_srv_rerror_rateclass
00120949100000...250.170.030.170.000.000.000.050.00normal
10244914600000...10.000.600.880.000.000.000.000.00normal
201495000000...260.100.050.000.001.001.000.000.00anomaly
30124923281530000...2551.000.000.030.040.030.010.000.01normal
4012491994200000...2551.000.000.000.000.000.000.000.00normal
..................................................................
13989900149103200000...2551.000.001.000.000.000.000.000.00anomaly
139900014997943330000...1410.720.060.010.010.010.000.000.00normal
139901012293179380000...2551.000.000.010.010.010.000.000.00normal
1399020211942420000...2520.990.010.000.000.000.000.000.00normal
13990301521000000...210.080.030.000.000.000.000.441.00anomaly
\n", "

139904 rows × 42 columns

\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 74 } ] }, { "cell_type": "markdown", "source": [ "# PCA" ], "metadata": { "id": "FiXD9jj7JzAt" } }, { "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.decomposition import PCA\n", "n_components = 10\n", "columns = []\n", "for x in range(n_components):\n", " columns.append(str(x+1))\n", "sns.set()\n", "X = df.drop(['class'], axis=1)\n", "y = df[\"class\"]\n", "x_scaled = StandardScaler().fit_transform(X)\n", "\n", "pca = PCA(n_components)\n", "\n", "# Fit and transform data\n", "principalComponents = pca.fit_transform(x_scaled)\n", "\n", "principalDf = pd.DataFrame(data = principalComponents\n", " , columns = columns)\n", "finalDf = pd.concat([principalDf, df[\"class\"]], axis = 1)\n" ], "metadata": { "id": "7NHskuswvChi" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "\n", "\n", "model = pca\n", "X_pc = principalComponents\n", "\n", "# number of components\n", "n_pcs= model.components_.shape[0]\n", "\n", "# get the index of the most important feature on EACH component\n", "# LIST COMPREHENSION HERE\n", "most_important = [np.abs(model.components_[i]).argmax() for i in range(n_pcs)]\n", "\n", "initial_feature_names = CSV_HEADER\n", "# get the names\n", "most_important_names = [initial_feature_names[most_important[i]] for i in range(n_pcs)]\n", "\n", "# LIST COMPREHENSION HERE AGAIN\n", "dic = {'PC{}'.format(i): most_important_names[i] for i in range(n_pcs)}\n", "\n", "# build the dataframe\n", "dfx = pd.DataFrame(dic.items())\n", "dfx" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 520 }, "id": "atTpAHhnJZXy", "outputId": "e61d84dc-9d87-46c3-a640-d102cfb494dc" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " 0 1\n", "0 PC0 same_srv_rate\n", "1 PC1 srv_rerror_rate\n", "2 PC2 dst_host_srv_diff_host_rate\n", "3 PC3 is_guest_login\n", "4 PC4 is_guest_login\n", "5 PC5 dst_host_diff_srv_rate\n", "6 PC6 src_bytes\n", "7 PC7 num_failed_logins\n", "8 PC8 num_failed_logins\n", "9 PC9 duration\n", "10 PC10 service\n", "11 PC11 srv_diff_host_rate\n", "12 PC12 dst_bytes\n", "13 PC13 dst_host_same_src_port_rate\n", "14 PC14 dst_host_srv_diff_host_rate" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
01
0PC0same_srv_rate
1PC1srv_rerror_rate
2PC2dst_host_srv_diff_host_rate
3PC3is_guest_login
4PC4is_guest_login
5PC5dst_host_diff_srv_rate
6PC6src_bytes
7PC7num_failed_logins
8PC8num_failed_logins
9PC9duration
10PC10service
11PC11srv_diff_host_rate
12PC12dst_bytes
13PC13dst_host_same_src_port_rate
14PC14dst_host_srv_diff_host_rate
\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 69 } ] }, { "cell_type": "code", "source": [ "\n", "# number of components\n", "n_pcs= pca.components_.shape[0]\n", "n_pcs\n", "# get the index of the most important feature on EACH component i.e. largest absolute value\n", "# using LIST COMPREHENSION HERE\n", "most_important = [np.abs(pca.components_[i]).argmax() for i in range(n_pcs)]\n", "\n", "initial_feature_names = CSV_HEADER\n", "\n", "# get the names\n", "most_important_names = [initial_feature_names[most_important[i]] for i in range(n_pcs)]\n", "\n", "# using LIST COMPREHENSION HERE AGAIN\n", "dic = {'PC{}'.format(i+1): most_important_names[i] for i in range(n_pcs)}\n", "\n", "# build the dataframe\n", "df = pd.DataFrame(sorted(dic.items()))" ], "metadata": { "id": "kMi0txUbD0vE" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "df" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 363 }, "id": "LOKV6FgnIMsR", "outputId": "48da67c9-ec3d-40cb-dcd5-783f1e71e0f0" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " 0 1\n", "0 PC1 same_srv_rate\n", "1 PC10 duration\n", "2 PC2 srv_rerror_rate\n", "3 PC3 dst_host_srv_diff_host_rate\n", "4 PC4 is_guest_login\n", "5 PC5 is_guest_login\n", "6 PC6 dst_host_diff_srv_rate\n", "7 PC7 src_bytes\n", "8 PC8 num_failed_logins\n", "9 PC9 num_failed_logins" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
01
0PC1same_srv_rate
1PC10duration
2PC2srv_rerror_rate
3PC3dst_host_srv_diff_host_rate
4PC4is_guest_login
5PC5is_guest_login
6PC6dst_host_diff_srv_rate
7PC7src_bytes
8PC8num_failed_logins
9PC9num_failed_logins
\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 33 } ] }, { "cell_type": "markdown", "source": [ "# Model" ], "metadata": { "id": "B6B5ZuR5J5WQ" } }, { "cell_type": "code", "source": [ "from sklearn.model_selection import train_test_split\n", "train_data, test_data = train_test_split(finalDf, test_size=0.25)\n", "train_data_file = \"train_data.csv\"\n", "test_data_file = \"test_data.csv\"\n", "\n", "train_data.to_csv(train_data_file, index=False, header=False)\n", "test_data.to_csv(test_data_file, index=False, header=False)" ], "metadata": { "id": "_1N70b_DJb2m" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "CSV_HEADER = []\n", "for x in columns:\n", " CSV_HEADER.append(x)\n", "CSV_HEADER.append(\"class\")\n", "\n", "# A list of the numerical feature names.\n", "NUMERIC_FEATURE_NAMES = columns\n", "# A dictionary of the categorical features and their vocabulary.\n", "CATEGORICAL_FEATURES_WITH_VOCABULARY = {\n", "}\n", "# A list of the columns to ignore from the dataset.\n", "IGNORE_COLUMN_NAMES = []\n", "# A list of the categorical feature names.\n", "CATEGORICAL_FEATURE_NAMES = list(CATEGORICAL_FEATURES_WITH_VOCABULARY.keys())\n", "# A list of all the input features.\n", "FEATURE_NAMES = NUMERIC_FEATURE_NAMES + CATEGORICAL_FEATURE_NAMES\n", "# A list of column default values for each feature.\n", "COLUMN_DEFAULTS = [\n", " [0.0] if feature_name in NUMERIC_FEATURE_NAMES + IGNORE_COLUMN_NAMES else [\"NA\"]\n", " for feature_name in CSV_HEADER\n", "]\n", "# The name of the target feature.\n", "TARGET_FEATURE_NAME = \"class\"\n", "# A list of the labels of the target features.\n", "TARGET_LABELS = [\"normal\", \"anomaly\"]\n", "\n", "from tensorflow.keras.layers import StringLookup\n", "\n", "target_label_lookup = StringLookup(\n", " vocabulary=TARGET_LABELS, mask_token=None, num_oov_indices=0\n", ")\n", "\n", "\n", "def get_dataset_from_csv(csv_file_path, shuffle=False, batch_size=128):\n", " dataset = tf.data.experimental.make_csv_dataset(\n", " csv_file_path,\n", " batch_size=batch_size,\n", " column_names=CSV_HEADER,\n", " column_defaults=COLUMN_DEFAULTS,\n", " label_name=TARGET_FEATURE_NAME,\n", " num_epochs=1,\n", " header=False,\n", " na_value=\"?\",\n", " shuffle=shuffle,\n", " ).map(lambda features, target: (features, target_label_lookup(target)))\n", " return dataset.cache()\n", "\n", "def create_model_inputs():\n", " inputs = {}\n", " for feature_name in FEATURE_NAMES:\n", " if feature_name in NUMERIC_FEATURE_NAMES:\n", " inputs[feature_name] = layers.Input(\n", " name=feature_name, shape=(), dtype=tf.float32\n", " )\n", " else:\n", " inputs[feature_name] = layers.Input(\n", " name=feature_name, shape=(), dtype=tf.string\n", " )\n", " return inputs\n", "\n", "def encode_inputs(inputs):\n", " encoded_features = []\n", " for feature_name in inputs:\n", " if feature_name in CATEGORICAL_FEATURE_NAMES:\n", " vocabulary = CATEGORICAL_FEATURES_WITH_VOCABULARY[feature_name]\n", " #print(vocabulary)\n", " # Create a lookup to convert a string values to an integer indices.\n", " # Since we are not using a mask token, nor expecting any out of vocabulary\n", " # (oov) token, we set mask_token to None and num_oov_indices to 0.\n", " lookup = StringLookup(\n", " vocabulary=vocabulary, mask_token=None, num_oov_indices=0\n", " )\n", " # Convert the string input values into integer indices.\n", " value_index = lookup(inputs[feature_name])\n", " embedding_dims = int(math.sqrt(lookup.vocabulary_size()))\n", " # Create an embedding layer with the specified dimensions.\n", " embedding = layers.Embedding(\n", " input_dim=lookup.vocabulary_size(), output_dim=embedding_dims\n", " )\n", " # Convert the index values to embedding representations.\n", " encoded_feature = embedding(value_index)\n", " else:\n", " # Use the numerical features as-is.\n", " encoded_feature = inputs[feature_name]\n", " if inputs[feature_name].shape[-1] is None:\n", " encoded_feature = tf.expand_dims(encoded_feature, -1)\n", "\n", " encoded_features.append(encoded_feature)\n", "\n", " encoded_features = layers.concatenate(encoded_features)\n", " return encoded_features\n", "\n", "class NeuralDecisionTree(keras.Model):\n", " def __init__(self, depth, num_features, used_features_rate, num_classes):\n", " super().__init__()\n", " self.depth = depth\n", " self.num_leaves = 2 ** depth\n", " self.num_classes = num_classes\n", "\n", " # Create a mask for the randomly selected features.\n", " num_used_features = int(num_features * used_features_rate)\n", " one_hot = np.eye(num_features)\n", " sampled_feature_indicies = np.random.choice(\n", " np.arange(num_features), num_used_features, replace=False\n", " )\n", " self.used_features_mask = one_hot[sampled_feature_indicies]\n", "\n", " # Initialize the weights of the classes in leaves.\n", " self.pi = tf.Variable(\n", " initial_value=tf.random_normal_initializer()(\n", " shape=[self.num_leaves, self.num_classes]\n", " ),\n", " dtype=\"float32\",\n", " trainable=True,\n", " )\n", "\n", " # Initialize the stochastic routing layer.\n", " self.decision_fn = layers.Dense(\n", " units=self.num_leaves, activation=\"sigmoid\", name=\"decision\"\n", " )\n", "\n", " def call(self, features):\n", " batch_size = tf.shape(features)[0]\n", "\n", " # Apply the feature mask to the input features.\n", " features = tf.matmul(\n", " features, self.used_features_mask, transpose_b=True\n", " ) # [batch_size, num_used_features]\n", " # Compute the routing probabilities.\n", " decisions = tf.expand_dims(\n", " self.decision_fn(features), axis=2\n", " ) # [batch_size, num_leaves, 1]\n", " # Concatenate the routing probabilities with their complements.\n", " decisions = layers.concatenate(\n", " [decisions, 1 - decisions], axis=2\n", " ) # [batch_size, num_leaves, 2]\n", "\n", " mu = tf.ones([batch_size, 1, 1])\n", "\n", " begin_idx = 1\n", " end_idx = 2\n", " # Traverse the tree in breadth-first order.\n", " for level in range(self.depth):\n", " mu = tf.reshape(mu, [batch_size, -1, 1]) # [batch_size, 2 ** level, 1]\n", " mu = tf.tile(mu, (1, 1, 2)) # [batch_size, 2 ** level, 2]\n", " level_decisions = decisions[\n", " :, begin_idx:end_idx, :\n", " ] # [batch_size, 2 ** level, 2]\n", " mu = mu * level_decisions # [batch_size, 2**level, 2]\n", " begin_idx = end_idx\n", " end_idx = begin_idx + 2 ** (level + 1)\n", "\n", " mu = tf.reshape(mu, [batch_size, self.num_leaves]) # [batch_size, num_leaves]\n", " probabilities = keras.activations.softmax(self.pi) # [num_leaves, num_classes]\n", " outputs = tf.matmul(mu, probabilities) # [batch_size, num_classes]\n", " return outputs\n", "\n", "class NeuralDecisionForest(keras.Model):\n", " def __init__(self, num_trees, depth, num_features, used_features_rate, num_classes):\n", " super().__init__()\n", " self.ensemble = []\n", " # Initialize the ensemble by adding NeuralDecisionTree instances.\n", " # Each tree will have its own randomly selected input features to use.\n", " for _ in range(num_trees):\n", " self.ensemble.append(\n", " NeuralDecisionTree(depth, num_features, used_features_rate, num_classes)\n", " )\n", "\n", " def call(self, inputs):\n", " # Initialize the outputs: a [batch_size, num_classes] matrix of zeros.\n", " batch_size = tf.shape(inputs)[0]\n", " outputs = tf.zeros([batch_size, num_classes])\n", "\n", " # Aggregate the outputs of trees in the ensemble.\n", " for tree in self.ensemble:\n", " outputs += tree(inputs)\n", " # Divide the outputs by the ensemble size to get the average.\n", " outputs /= len(self.ensemble)\n", " return outputs\n", "learning_rate = 0.01\n", "batch_size = 128\n", "num_epochs = 10\n", "\n", "\n", "def run_experiment(model):\n", "\n", " # model.compile(\n", " # optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", " # loss=keras.losses.SparseCategoricalCrossentropy(),\n", " # metrics=[keras.metrics.SparseCategoricalAccuracy()],\n", " # )\n", " model.compile(\n", " optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", " loss=keras.losses.SparseCategoricalCrossentropy(),\n", " metrics=[metrics.SparseCategoricalAccuracy()],\n", " )\n", " print(\"Start training the model...\")\n", " train_dataset = get_dataset_from_csv(\n", " train_data_file, shuffle=True, batch_size=batch_size\n", " )\n", "\n", " model.fit(train_dataset, epochs=num_epochs)\n", " print(\"Model training finished\")\n", "\n", " print(\"Evaluating the model on the test data...\")\n", " test_dataset = get_dataset_from_csv(test_data_file, batch_size=batch_size)\n", "\n", " _, accuracy = model.evaluate(test_dataset)\n", " print(f\"Test accuracy: {round(accuracy * 100, 2)}%\")\n", " return model" ], "metadata": { "id": "PGCEwlOPPpEP", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "d11c2e57-c34a-4dce-d04b-22ee0655f7f9" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.10/dist-packages/numpy/core/numeric.py:2463: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison\n", " return bool(asarray(a1 == a2).all())\n" ] } ] }, { "cell_type": "code", "source": [ "num_trees = 25\n", "depth = 5\n", "used_features_rate = 0.5\n", "num_classes = len(TARGET_LABELS)\n", "\n", "\n", "def create_forest_model():\n", " inputs = create_model_inputs()\n", " features = encode_inputs(inputs)\n", " features = layers.BatchNormalization()(features)\n", " num_features = features.shape[1]\n", "\n", " forest_model = NeuralDecisionForest(\n", " num_trees, depth, num_features, used_features_rate, num_classes\n", " )\n", "\n", " outputs = forest_model(features)\n", " model = keras.Model(inputs=inputs, outputs=outputs)\n", " return model\n", "\n", "\n", "forest_model = create_forest_model()\n", "\n", "finalModel = run_experiment(forest_model)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "vLjxBfBIQUKR", "outputId": "a83b97e9-cbdd-4dd9-d987-d3a018cac0b1" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Start training the model...\n", "Epoch 1/10\n", "820/820 [==============================] - 45s 28ms/step - loss: 0.1757 - sparse_categorical_accuracy: 0.9566\n", "Epoch 2/10\n", "820/820 [==============================] - 20s 24ms/step - loss: 0.0962 - sparse_categorical_accuracy: 0.9687\n", "Epoch 3/10\n", "820/820 [==============================] - 18s 22ms/step - loss: 0.0874 - sparse_categorical_accuracy: 0.9703\n", "Epoch 4/10\n", "820/820 [==============================] - 19s 23ms/step - loss: 0.0833 - sparse_categorical_accuracy: 0.9712\n", "Epoch 5/10\n", "820/820 [==============================] - 18s 22ms/step - loss: 0.0810 - sparse_categorical_accuracy: 0.9717\n", "Epoch 6/10\n", "820/820 [==============================] - 20s 24ms/step - loss: 0.0793 - sparse_categorical_accuracy: 0.9718\n", "Epoch 7/10\n", "820/820 [==============================] - 18s 22ms/step - loss: 0.0779 - sparse_categorical_accuracy: 0.9723\n", "Epoch 8/10\n", "820/820 [==============================] - 19s 24ms/step - loss: 0.0768 - sparse_categorical_accuracy: 0.9726\n", "Epoch 9/10\n", "820/820 [==============================] - 18s 22ms/step - loss: 0.0759 - sparse_categorical_accuracy: 0.9727\n", "Epoch 10/10\n", "820/820 [==============================] - 18s 22ms/step - loss: 0.0751 - sparse_categorical_accuracy: 0.9729\n", "Model training finished\n", "Evaluating the model on the test data...\n", "274/274 [==============================] - 7s 16ms/step - loss: 0.0672 - sparse_categorical_accuracy: 0.9754\n", "Test accuracy: 97.54%\n" ] } ] }, { "cell_type": "code", "source": [ "test_dataset = get_dataset_from_csv(test_data_file, batch_size=batch_size)\n", "colnames=['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'target']\n", "data = pd.read_csv(\"test_data.csv\", names=colnames, header=None)\n", "data['target'].replace('normal', 0,inplace=True)\n", "data['target'].replace('anomaly', 1,inplace=True)\n", "y_test = data['target'].values # as a numpy array\n", "from sklearn.metrics import confusion_matrix\n", "y_prediction = finalModel.predict(test_dataset)\n", "y_prediction = np.argmax (y_prediction, axis = 1)\n", "result = confusion_matrix(y_test, y_prediction , normalize='pred')\n", "print(result)\n", "TP = result[0][0]\n", "FP = result[0][1]\n", "TN = result[1][1]\n", "FN = result[1][0]\n", "ACC = (TP+TN)/(TP+TN+FP+FN)\n", "PR = TP/(TP+FP) #precision\n", "TPR = TP/(TP+FN) #Recall or True positive rate\n", "FPR = FP/(FP+TN)\n", "F1Score = 2*(PR*TPR)/(PR+TPR)\n", "print(\"ACC: \" + str(ACC))\n", "print(\"PR: \" + str(PR))\n", "print(\"TPR: \" + str(TPR))\n", "print(\"FPR: \" + str(FPR))\n", "print(\"F1Score: \" + str(F1Score))\n" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "5pukCWAiuyv5", "outputId": "2cd847d4-3635-4d4d-a542-4576d55f27d5" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "274/274 [==============================] - 5s 11ms/step\n", "[[0.96431656 0.01209579]\n", " [0.03568344 0.98790421]]\n", "ACC: 0.9761103842365505\n", "PR: 0.9876120025022016\n", "TPR: 0.9643165622975599\n", "FPR: 0.012095793824459033\n", "F1Score: 0.9758252717966972\n" ] } ] }, { "cell_type": "code", "source": [ "result = confusion_matrix(y_test, y_prediction , normalize='pred')" ], "metadata": { "id": "9VDBBzEQLOJS" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "import numpy\n", "from sklearn import metrics\n", "\n", "\n", "cm_display = metrics.ConfusionMatrixDisplay(confusion_matrix = result, display_labels = [True, False])\n", "\n", "cm_display.plot()\n", "plt.show()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 449 }, "id": "ruhkENcrJGRh", "outputId": "d7b95a9c-dd92-4247-a436-d0c8dd8f7cbf" }, "execution_count": null, "outputs": [ { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhAAAAGwCAYAAAD49Fz6AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA8EUlEQVR4nO3deXQUZdbH8V8nIfvCnpAQCRBZ8rKHkRcVEScCOqLoODqKsijMCEYRhk0ddiGuiDAICrIpDji4jAIyL6IgEUYlCG4QDIthCzuEBMjSVe8fGZpp6WA6XVma/n7OqXPo6uepuu2Jye17n6qymaZpCgAAwA1+VR0AAADwPiQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbQFVHYA3MAxDBw8eVEREhGw2W1WHAwBwk2maOnPmjGJjY+XnV3Hfnc+fP6/CwkKPjxMYGKjg4GALIqo4JBBlcPDgQcXHx1d1GAAAD+3bt08NGzaskGOfP39ejRuFK+eI3eNjxcTEaM+ePdU6iSCBKIOIiAhJ0neboxURTtcHV6b+La6p6hCAClOsIqVrleP3eUUoLCxUzhG7fs5IUGRE+f9W5J4x1Ch5rwoLC0kgvN2FtkVEuJ9HPxRAdRZgq1HVIQAV5z8PbaiMNnR4hE3hEeU/jyHvaJWTQAAAYCG7acjuwVOm7KZhXTAViAQCAAALGTJlqPwZhCdzKxP1eAAA4DYqEAAAWMiQIU+aEJ7NrjwkEAAAWMhumrKb5W9DeDK3MtHCAAAAbqMCAQCAhXxlESUJBAAAFjJkyu4DCQQtDAAA4DYqEAAAWIgWBgAAcBtXYQAAAJSCCgQAABYy/rN5Mt8bkEAAAGAhu4dXYXgytzKRQAAAYCG7KQ+fxmldLBWJNRAAAMBtVCAAALAQayAAAIDbDNlkl82j+d6AFgYAAHAbFQgAACxkmCWbJ/O9AQkEAAAWsnvYwvBkbmWihQEAANxGBQIAAAv5SgWCBAIAAAsZpk2G6cFVGB7MrUy0MAAAgNuoQAAAYCFaGAAAwG12+cnuQYHfbmEsFYkEAgAAC5keroEwWQMBAACuVFQgAACwEGsgAACA2+ymn+ymB2sgvORW1rQwAACA26hAAABgIUM2GR58PzfkHSUIEggAACzkK2sgaGEAAAC3UYEAAMBCni+ipIUBAIDPKVkD4cHDtGhhAACAKxUVCAAALGR4+CwMrsIAAMAHsQYCAAC4zZCfT9wHgjUQAADAbVQgAACwkN20ye7BI7k9mVuZSCAAALCQ3cNFlHZaGAAA4EpFBQIAAAsZpp8MD67CMLgKAwAA30MLAwAAoBRUIAAAsJAhz66kMKwLpUKRQAAAYCHPbyTlHc0B74gSAABUK1QgAACwkOfPwvCO7/YkEAAAWMiQTYY8WQPBnSgBAPA5vlKB8I4oAQBAtUIFAgAAC3l+Iynv+G5PAgEAgIUM0ybDk/tAeMnTOL0jzQEAANUKFQgAACxkeNjC8JYbSZFAAABgIc+fxukdCYR3RAkAAKoVKhAAAFjILpvsHtwMypO5lYkEAgAAC9HCAAAAKAUVCAAALGSXZ20Iu3WhVCgqEAAAWOhCC8OTrTxmzZqlhIQEBQcHq1OnTvrqq68uO3769Olq3ry5QkJCFB8fr2HDhun8+fNlPh8VCAAALFQVD9NatmyZhg8frjlz5qhTp06aPn26evTooczMTNWvX/+S8W+//bbGjBmj+fPn69prr9XOnTvVv39/2Ww2TZs2rUznpAIBAEA1lJub67QVFBSUOnbatGkaNGiQBgwYoKSkJM2ZM0ehoaGaP3++y/EbN27Uddddp/vvv18JCQnq3r277rvvvl+tWvw3EggAACxkyibDg838z/qJ+Ph4RUVFOba0tDSX5yssLFRGRoZSUlIc+/z8/JSSkqJNmza5nHPttdcqIyPDkTDs3r1bq1at0q233lrmz0kLAwAAC1nVwti3b58iIyMd+4OCglyOP3bsmOx2u6Kjo532R0dHa8eOHS7n3H///Tp27Jiuv/56maap4uJiPfLII3rqqafKHCcVCAAAqqHIyEinrbQEojzWrVunqVOn6tVXX9WWLVv03nvvaeXKlZo8eXKZj0EFAgAAC1X247zr1q0rf39/HT582Gn/4cOHFRMT43LO2LFj9eCDD2rgwIGSpNatWys/P19/+tOf9PTTT8vP79frC1QgAACwkP0/T+P0ZHNHYGCgkpOTtXbtWsc+wzC0du1ade7c2eWcs2fPXpIk+Pv7S5JM0yzTealAAADg5YYPH65+/fqpY8eOuuaaazR9+nTl5+drwIABkqS+ffsqLi7OsRCzV69emjZtmtq3b69OnTopKytLY8eOVa9evRyJxK8hgQAAwEKV3cKQpHvvvVdHjx7VuHHjlJOTo3bt2mn16tWOhZXZ2dlOFYe//vWvstls+utf/6oDBw6oXr166tWrl6ZMmVLmc9rMstYqfFhubq6ioqK0d0cDRUbQ9cGV6Z6GrkudwJWg2CzSOv1Tp0+fdrqywUoX/lakpt+poPAa5T5OQV6R/nb9+xUaqxX4awgAANxGCwMAAAvZTZvsHrQwPJlbmUggAACwUFWsgagKJBAAAFjI9OCJmhfmewPviBIAAFQrVCAAALCQXTbZ5cEaCA/mViYSCAAALGSYnq1jMLzk5gq0MAAAgNuoQKBSrF4YrY/mxOrU0UA1apmvhybvVWL7PJdji4ts+uBvcVq/vJ5O5AQqtsk59XkqW+26nXIad+JQoN6aepW2flZTBef8FZNwXkOmZalp2/xK+ETwZb36H9Pdg4+odr1i7f4xRK/+NU6ZW0NLHd/ltlPqNypH0Q0LdWBPkN6Y0kBff3rxBkHX3XJKv+t7XFe3PqfI2nYNvrmZdv8Q4ng/omaxHhyRow5d81Q/tlCnTwRo4+ooLXo+RmfPlO22w6g8hoeLKD2ZW5m8I0p4tY0f1tHiSQm6e9h+Pffxt2qUdFZTHmip08dc569Ln4/XmreiNWDSHk37dKtufvCwXhjYXHu+v/gLOu+Uv8be+T8KqGHqqTd36OXPtqrvuL0KiyqurI8FH9X19pP60/iDWjItRo/2aKbdPwZrytu7FVWnyOX4pI75evLVn7X677U1pHszbVwdqfHz96pR83OOMcGhhn74KkxvTG3g8hi1o4tUJ7pYcyc10J9vaq4Xn4hXxxtzNfylfRXyGeEZQzaPN29QrRIIm8122W3ChAlVHSLKYcXrDfTb+46o271H1bDZOQ16drcCgw19trS+y/Eb3qunOx/brw6/PaXoRgXq3vew2t90Uh+9FusY889X41QntlBDpu1SYvs81b+qQG27nlZMQkFlfSz4qLv+dEyr366t/1tWW9k/BWvG6IYqOGdTj/tOuBzfe+BRbf4sQstn19e+rGAtfqGBsr4L0R0DjjvGrH23tpa8HKNvPo9weYyfM0M0eVCCvlwTpUM/B2nbFxFa+FwDdbo5V37+XtIwxxWnWrUwDh065Pj3smXLNG7cOGVmZjr2hYeHO/5tmqbsdrsCAqrVR8AvFBfatPu7cPVOPeDY5+cnte5ySju3uP5lWVRgU2CQ8y/FwGBDmV9fHL95TS217XpK0/7cTD/+O1K1YwrVvW+OUvocqZgPAkgKqGHo6jZntfRvF5Nf07Tpmw0RSko+63JOy+Szeu+1ek77MtZH6Noepz2KJSzSrrN5fjLs3vFt1Zf4yp0oq1UFIiYmxrFFRUXJZrM5Xu/YsUMRERH6+OOPlZycrKCgIKWnp6t///7q3bu303GeeOIJ3XjjjY7XhmEoLS1NjRs3VkhIiNq2bavly5dX7ofzUbknAmTYbapZz7m8W7NukU4dcf2wmbZdT2vF3AY6tDtYhiF9+3mUvvq4tk4eCXSMOZIdrDVvxiim8Tk9veRHdX8wRwvGNda6f9RzeUzACpG17fIPkE4ddf7icvJYgGrVc90+q1WvWCd/0a47eTRAteqXv90WWbtY9z9xWB+/Vafcx0DFubAGwpPNG3jd1/cxY8boxRdfVJMmTVSrVq0yzUlLS9Nbb72lOXPm6Oqrr9bnn3+uBx54QPXq1VPXrl0vGV9QUKCCgoul8NzcXMvix68bMGmP5oxqqidubCebTYpudF433nvUqeVhGFLTNvm6f0xJD7hxq7PKzgzVmjejdeMfjlZV6ECFCw23a/LiPcreGaw3X4qp6nDgw7wugZg0aZJuvvnmMo8vKCjQ1KlT9cknn6hz55LHFTdp0kTp6el67bXXXCYQaWlpmjhxomUx+7LI2sXy8zd16qhzteHUsRqqWd/1orPIOsUa9UamCs/blHeyhmrFFGrJ1KsU3ei8Y0yt+kVqeLVzybjh1ef05Sq+kaHi5J7wl71YqvmLakOtusU6edT1r9OTRwNUq+4vxtcr1skj7v/6DQmza8rbu3Uu308TH06Qvdg7St2+xpCHz8JgEWXF6Nixo1vjs7KydPbsWd18880KDw93bIsXL9auXbtcznnyySd1+vRpx7ZvHyudyysg0FST1nn6Pj3Ksc8wpO/To9Ssw5nLzg0MNlW7QaHsxTZ9uaqOOna/uEitecczOrg7xGn8wd3BqteQRZSoOMVFfvrp21C1v/7iz67NZqrd9Xn6McP1ZZzbM0LVrovzJcsdbjij7Rlhbp07NNyuqX/fraJCm8b3b6yiAq/79e0zTA+vwDC9JIHwugpEWJjz/3R+fn4yTecFd0VFF7/Z5uWV/I+7cuVKxcXFOY0LCgpyeY6goKBS34P7bvvTIc0alqgmbfOV2C5Pq+Y1UME5f914b0mr4W9DE1U7plD3P5ktSfppS7hO5AQq4X/ydSInUP+YFi/TlO4YfNBxzN8NOqixvVvpvZlxuva248raGq61S6L1p+d2V8lnhO947/W6GjF9n3ZuC1XmN6G6c9BRBYca+r+ltSVJI1/J1rGcGlqQVnJJ5gfz6umFd7P0+z8f0VdrI9X1jlO6us05TR/Z0HHMiJrFqhdXpDrRJb+74puWVNtOHgnQyaM1HMlDUIih5x9LUGi4XaHhdknS6eMBMgzv+IPjK3gap5eoV6+evv/+e6d9W7duVY0aJSXzpKQkBQUFKTs722W7AhXv2tuPK/d4Db3zYrxOHa2hhKR8PfXmdsfCymMHAmXzu5gEFhX4aekL8TqSHazgULva33RKqa/8pLAou2NMYrt8jZiXqbfTGund6Q1VP/68+k3Yqy53Hav0zwffsv7DWoqqY1ffkTmqVa9Yu38I0dN9GuvUsZLfOfXiCmUYF8f/uDlMzz7aSP1G56j/mBwd3BOkiQ8l6OfMixW0/+2eqxHTL1Y6n5pTkky/+VK03nopRomtz6nlf67yWLhph1M8fa9pqcP7AwVUNq9PIG666Sa98MILWrx4sTp37qy33npL33//vdq3by9JioiI0IgRIzRs2DAZhqHrr79ep0+f1hdffKHIyEj169evij+Bb+g5IEc9B+S4fG/C8h+dXid1ztXLn2371WMmp5xScsopK8ID3PLhgrr6cEFdl++Nujvxkn0bVtTUhhU1Sz3emndqa807tUt9/9tN4eoR29btOFE1fOVOlF6fQPTo0UNjx47VqFGjdP78eT300EPq27evvvvuO8eYyZMnq169ekpLS9Pu3btVs2ZNdejQQU899VQVRg4AuBL5SgvDZv5yAQEukZubq6ioKO3d0UCREd6RGQLuuqdh56oOAagwxWaR1umfOn36tCIjI399Qjlc+Ftxx/89pBph5W8rFeUX6p/d51dorFbw+goEAADViafPs/CWyzhJIAAAsJCvtDCoxwMAALdRgQAAwEK+UoEggQAAwEK+kkDQwgAAAG6jAgEAgIV8pQJBAgEAgIVMeXYpprfcnIkEAgAAC/lKBYI1EAAAwG1UIAAAsJCvVCBIIAAAsJCvJBC0MAAAgNuoQAAAYCFfqUCQQAAAYCHTtMn0IAnwZG5looUBAADcRgUCAAALGbJ5dCMpT+ZWJhIIAAAs5CtrIGhhAAAAt1GBAADAQr6yiJIEAgAAC/lKC4MEAgAAC/lKBYI1EAAAwG1UIAAAsJDpYQvDWyoQJBAAAFjIlGSans33BrQwAACA26hAAABgIUM22bgTJQAAcAdXYQAAAJSCCgQAABYyTJts3EgKAAC4wzQ9vArDSy7DoIUBAADcRgUCAAAL+coiShIIAAAsRAIBAADc5iuLKFkDAQAA3EYFAgAAC/nKVRgkEAAAWKgkgfBkDYSFwVQgWhgAAMBtVCAAALAQV2EAAAC3mf/ZPJnvDWhhAAAAt1GBAADAQr7SwqACAQCAlUwLtnKYNWuWEhISFBwcrE6dOumrr7667PhTp07p0UcfVYMGDRQUFKRmzZpp1apVZT4fFQgAAKzkYQVC5Zi7bNkyDR8+XHPmzFGnTp00ffp09ejRQ5mZmapfv/4l4wsLC3XzzTerfv36Wr58ueLi4vTzzz+rZs2aZT4nCQQAAF5u2rRpGjRokAYMGCBJmjNnjlauXKn58+drzJgxl4yfP3++Tpw4oY0bN6pGjRqSpISEBLfOSQsDAAALXbgTpSebJOXm5jptBQUFLs9XWFiojIwMpaSkOPb5+fkpJSVFmzZtcjnnww8/VOfOnfXoo48qOjparVq10tSpU2W328v8OUkgAACw0IVFlJ5skhQfH6+oqCjHlpaW5vJ8x44dk91uV3R0tNP+6Oho5eTkuJyze/duLV++XHa7XatWrdLYsWP10ksv6Zlnninz56SFAQBANbRv3z5FRkY6XgcFBVl2bMMwVL9+fb3++uvy9/dXcnKyDhw4oBdeeEHjx48v0zFIIAAAsJJpK9dCSKf5kiIjI50SiNLUrVtX/v7+Onz4sNP+w4cPKyYmxuWcBg0aqEaNGvL393fsa9mypXJyclRYWKjAwMBfPS8tDAAALGTVGoiyCgwMVHJystauXevYZxiG1q5dq86dO7ucc9111ykrK0uGYTj27dy5Uw0aNChT8iCRQAAA4PWGDx+uuXPnatGiRdq+fbsGDx6s/Px8x1UZffv21ZNPPukYP3jwYJ04cUJDhw7Vzp07tXLlSk2dOlWPPvpomc9JCwMAACtVwcMw7r33Xh09elTjxo1TTk6O2rVrp9WrVzsWVmZnZ8vP72LNID4+Xv/61780bNgwtWnTRnFxcRo6dKhGjx5d5nOSQAAAYKGqupV1amqqUlNTXb63bt26S/Z17txZ//73v8t1LqmMCcSHH35Y5gPefvvt5Q4GAAB4hzIlEL179y7TwWw2m1s3oQAA4IrkLc/k9kCZEoj/XqUJAABKx9M4y+D8+fNWxQEAwJWhip7GWdncTiDsdrsmT56suLg4hYeHa/fu3ZKksWPH6o033rA8QAAAUP24nUBMmTJFCxcu1PPPP+90s4lWrVpp3rx5lgYHAID3sVmwVX9uJxCLFy/W66+/rj59+jjdArNt27basWOHpcEBAOB1aGG4duDAASUmJl6y3zAMFRUVWRIUAACo3txOIJKSkrRhw4ZL9i9fvlzt27e3JCgAALyWj1Qg3L4T5bhx49SvXz8dOHBAhmHovffeU2ZmphYvXqwVK1ZURIwAAHgPi57GWd25XYG444479NFHH+mTTz5RWFiYxo0bp+3bt+ujjz7SzTffXBExAgCAaqZcz8Lo0qWL1qxZY3UsAAB4vfI8kvuX871BuR+mtXnzZm3fvl1SybqI5ORky4ICAMBrVcHTOKuC2wnE/v37dd999+mLL75QzZo1JUmnTp3Stddeq6VLl6phw4ZWxwgAAKoZt9dADBw4UEVFRdq+fbtOnDihEydOaPv27TIMQwMHDqyIGAEA8B4XFlF6snkBtysQ69ev18aNG9W8eXPHvubNm2vmzJnq0qWLpcEBAOBtbGbJ5sl8b+B2AhEfH+/yhlF2u12xsbGWBAUAgNfykTUQbrcwXnjhBT322GPavHmzY9/mzZs1dOhQvfjii5YGBwAAqqcyVSBq1aolm+1iTyY/P1+dOnVSQEDJ9OLiYgUEBOihhx5S7969KyRQAAC8go/cSKpMCcT06dMrOAwAAK4QPtLCKFMC0a9fv4qOAwAAeJFy30hKks6fP6/CwkKnfZGRkR4FBACAV/ORCoTbiyjz8/OVmpqq+vXrKywsTLVq1XLaAADwaT7yNE63E4hRo0bp008/1ezZsxUUFKR58+Zp4sSJio2N1eLFiysiRgAAUM243cL46KOPtHjxYt14440aMGCAunTposTERDVq1EhLlixRnz59KiJOAAC8g49cheF2BeLEiRNq0qSJpJL1DidOnJAkXX/99fr888+tjQ4AAC9z4U6UnmzewO0EokmTJtqzZ48kqUWLFnrnnXcklVQmLjxcCwAAXNncTiAGDBigbdu2SZLGjBmjWbNmKTg4WMOGDdPIkSMtDxAAAK/iI4so3V4DMWzYMMe/U1JStGPHDmVkZCgxMVFt2rSxNDgAAFA9eXQfCElq1KiRGjVqZEUsAAB4PZs8fBqnZZFUrDIlEDNmzCjzAR9//PFyBwMAALxDmRKIl19+uUwHs9lsV3QC8VC7LgqwBVZ1GECF+NfBf1d1CECFyT1jqFazSjqZj1zGWaYE4sJVFwAA4FdwK2sAAADXPF5ECQAA/ouPVCBIIAAAsJCnd5O8Yu9ECQAAQAUCAAAr+UgLo1wViA0bNuiBBx5Q586ddeDAAUnSm2++qfT0dEuDAwDA6/jIrazdTiDeffdd9ejRQyEhIfrmm29UUFAgSTp9+rSmTp1qeYAAAKD6cTuBeOaZZzRnzhzNnTtXNWrUcOy/7rrrtGXLFkuDAwDA2/jK47zdXgORmZmpG2644ZL9UVFROnXqlBUxAQDgvXzkTpRuVyBiYmKUlZV1yf709HQ1adLEkqAAAPBarIFwbdCgQRo6dKi+/PJL2Ww2HTx4UEuWLNGIESM0ePDgiogRAABUM263MMaMGSPDMPTb3/5WZ8+e1Q033KCgoCCNGDFCjz32WEXECACA1/CVG0m5nUDYbDY9/fTTGjlypLKyspSXl6ekpCSFh4dXRHwAAHgXH7kPRLlvJBUYGKikpCQrYwEAAF7C7QSiW7dustlKXyH66aefehQQAABezdNLMa/UCkS7du2cXhcVFWnr1q36/vvv1a9fP6viAgDAO9HCcO3ll192uX/ChAnKy8vzOCAAAFD9WfY0zgceeEDz58+36nAAAHgnH7kPhGVP49y0aZOCg4OtOhwAAF6JyzhLcddddzm9Nk1Thw4d0ubNmzV27FjLAgMAANWX2wlEVFSU02s/Pz81b95ckyZNUvfu3S0LDAAAVF9uJRB2u10DBgxQ69atVatWrYqKCQAA7+UjV2G4tYjS399f3bt356mbAACUwlce5+32VRitWrXS7t27KyIWAADgJdxOIJ555hmNGDFCK1as0KFDh5Sbm+u0AQDg867wSzglN9ZATJo0SX/5y1906623SpJuv/12p1tam6Ypm80mu91ufZQAAHgLH1kDUeYEYuLEiXrkkUf02WefVWQ8AADAC5Q5gTDNkpSoa9euFRYMAADejhtJuXC5p3ACAADRwnClWbNmv5pEnDhxwqOAAABA9edWAjFx4sRL7kQJAAAuooXhwh//+EfVr1+/omIBAMD7+UgLo8z3gWD9AwAA1desWbOUkJCg4OBgderUSV999VWZ5i1dulQ2m029e/d263xlTiAuXIUBAAAuw5ObSJWzerFs2TINHz5c48eP15YtW9S2bVv16NFDR44cuey8vXv3asSIEerSpYvb5yxzAmEYBu0LAAB+RVU8C2PatGkaNGiQBgwYoKSkJM2ZM0ehoaGaP39+qXPsdrv69OmjiRMnqkmTJm6f0+1bWQMAgMuwqALxy0dFFBQUuDxdYWGhMjIylJKS4tjn5+enlJQUbdq0qdQwJ02apPr16+vhhx8u18ckgQAAoBqKj49XVFSUY0tLS3M57tixY7Lb7YqOjnbaHx0drZycHJdz0tPT9cYbb2ju3Lnljs+tqzAAAMCvsOgqjH379ikyMtKxOygoyKOwLjhz5owefPBBzZ07V3Xr1i33cUggAACwkFX3gYiMjHRKIEpTt25d+fv76/Dhw077Dx8+rJiYmEvG79q1S3v37lWvXr0c+wzDkCQFBAQoMzNTTZs2/dXz0sIAAMCLBQYGKjk5WWvXrnXsMwxDa9euVefOnS8Z36JFC3333XfaunWrY7v99tvVrVs3bd26VfHx8WU6LxUIAACsVAU3kho+fLj69eunjh076pprrtH06dOVn5+vAQMGSJL69u2ruLg4paWlKTg4WK1atXKaX7NmTUm6ZP/lkEAAAGChqriV9b333qujR49q3LhxysnJUbt27bR69WrHwsrs7Gz5+VnbdCCBAADgCpCamqrU1FSX761bt+6ycxcuXOj2+UggAACwko88C4MEAgAAK/lIAsFVGAAAwG1UIAAAsJDtP5sn870BCQQAAFbykRYGCQQAABaqiss4qwJrIAAAgNuoQAAAYCVaGAAAoFy8JAnwBC0MAADgNioQAABYyFcWUZJAAABgJR9ZA0ELAwAAuI0KBAAAFqKFAQAA3EcLAwAAwDUqEAAAWIgWBgAAcJ+PtDBIIAAAsJKPJBCsgQAAAG6jAgEAgIVYAwEAANxHCwMAAMA1KhAAAFjIZpqymeUvI3gytzKRQAAAYCVaGAAAAK5RgQAAwEJchQEAANxHCwMAAMA1KhAAAFiIFgYAAHCfj7QwSCAAALCQr1QgWAMBAADcRgUCAAAr0cIAAADl4S1tCE/QwgAAAG6jAgEAgJVMs2TzZL4XIIEAAMBCXIUBAABQCioQAABYiaswAACAu2xGyebJfG9ACwMAALiNCgQqxG0P5ujuQYdUq16Rdm8P1ewJCdr5bXip46+/5bj6Dt+v6IYFOrA3WAueu0pfr6vpeL/P0P3qettx1WtQqKIim7K+D9OiF+OVuc35mL/pdlL3P3ZAjVucVWGBn777MlKTH2lWUR8TcPhwQV0tn11fJ44GqEnSOQ155oBatD/rcmxxkbR0ZrQ++UdtHcupoYZNC/Tw0wf1m25nHGPO5vlp0fMNtPHjKJ06HqCm/3NOgyfvV/N25yrrI6G8fKSF4ZUViIULF6pmzZpVHQZKccPvjutPT2VryYyGeqxXK+3ZHqpnFu1QVJ0il+NbdjijMa9k6V/v1FPqba216f9qaeycnWrU7OIv3wN7gvXqhAQNvqW1RtyTpMP7gzRl8Q5F1b54zOt6ntDIl3ZpzfJ6evR3rTXiD0la92GdCv+8wLp/1tTrE2PVZ3iOZv0rU02Szunp+5vo1DHX39EWPtdAq96qoyHP7NfcdTv0uwePadLDjZX1XYhjzMt/ideWz8M1aubPmrN2h5K7ntGYexN17FCNyvpYKKcLV2F4snmDKk0g+vfvL5vNdsmWlZVVlWHBQ3c+fEgfL6uvNcvrKTsrVDP/2lgF5/zU/Q9HXY6/o3+ONn9eU+/OjdW+XSF68+V47fohVL36HnaMWfdhXW39Iko5+4KV/VOo5k65SmERdjVuUZJk+PmbemTsXs179iqtejtaB/aEKDsrVBtWkUCg4r33ej31vP+4evzxhBo1K9Djz+1XUIihf/29tsvxa9+trT8+dkTX/PaMGjQqVK9+x/Wbm3L17mv1JEkF52xKX1VTA/96SK3/N19xjQv14IgcxSYUaMVifqarvQv3gfBk8wJVXoHo2bOnDh065LQ1bty4qsNCOQXUMHR1q3xt/SLSsc80bdr6RZRatj/jck7LDnlO4yUpY0NNtWyfV+o5bvnjUeXl+mv39lBJUuL/5KtugyKZhk1/++g7Lfn3Fk2av8OpigFUhKJCm376NlQdulz8efXzk9p3ydOPGWGlzgkMcl4pFxRs6IevSlpydrtNhv3yY4CqVuUJRFBQkGJiYpy2V155Ra1bt1ZYWJji4+M1ZMgQ5eW5/mMiSdu2bVO3bt0UERGhyMhIJScna/PmzY7309PT1aVLF4WEhCg+Pl6PP/648vPzSz1eQUGBcnNznTaUTWStYvkHSCePOZdZTx6roVr1XLcwatUtKmV8odO+a246qfe++1r/3P61ej90SE/3baHckyXzGlxVIKlkrcTfZ8Vp/MDmyssN0HNvb1d4VLFVHw+4RO4Jfxl2m2r+4ue7Vt0inTzquoWR3PWM3n29ng7sDpRhSBnrw/XFqpo6caRkfGi4oZbJ+Xp7eoyO5wTIbpfWvltL2zPCdOIwS9eqO1oYVcjPz08zZszQDz/8oEWLFunTTz/VqFGjSh3fp08fNWzYUF9//bUyMjI0ZswY1ahR8odl165d6tmzp37/+9/r22+/1bJly5Senq7U1NRSj5eWlqaoqCjHFh8fb/lnhPu2bYrUo7e11l/uTlLG5zX15Mwsx7oKm1/J/3HLZsXpi9W1lfV9mF4e1UQypS63Hq/KsIFLDJ68X3GNCzXwhpb6XaO2evXphup+73HZ/us38qiZP8s0pfs7tNJtCW31wRt1dWPvk05jUE2ZFmxeoMpT2RUrVig8/GJJ7pZbbtE//vEPx+uEhAQ988wzeuSRR/Tqq6+6PEZ2drZGjhypFi1aSJKuvvpqx3tpaWnq06ePnnjiCcd7M2bMUNeuXTV79mwFBwdfcrwnn3xSw4cPd7zOzc0liSij3JMBsheXfPv6byXfxlwv/jp5rEYp4wOd9hWc89ehn/116Odg7dgaoXmfblWPe47ondlxOnGk5NjZWRcXoRUV+unQviDVj3WuZABWiqxtl5+/qVNHXVXRXFe/ataxa8KCPSo8b1PuyQDViSnSG1MaKOY/lTRJik0o1IvvZen8WT/ln/FTnehiTflzIzVoVODymEBlq/Jctlu3btq6datjmzFjhj755BP99re/VVxcnCIiIvTggw/q+PHjOnvWdT97+PDhGjhwoFJSUvTss89q165djve2bdumhQsXKjw83LH16NFDhmFoz549Lo8XFBSkyMhIpw1lU1zkp5++D1O7ay+2fWw2U+2uPa3t30S4nLN9S7jTeElqf91pbf/m8r1eP5tUI7AkVc/6PkyFBTbFNbl4iZt/gKHohgU6ciCovB8H+FU1Ak1d3easvkm/+PNqGNLW9HAlJZfeKpWkwGBTdRsUyV4spa+qqc49Lm2XBocaqhNdrDOn/JWxPtLlGFQvtDAqSVhYmBITEx1bQUGBbrvtNrVp00bvvvuuMjIyNGvWLElSYaHrb5ITJkzQDz/8oN/97nf69NNPlZSUpPfff1+SlJeXpz//+c9OScq2bdv0008/qWnTppX2OX3J+280UM8/HlHKXUcV3/ScUifvVVCooTXLS1aY/+XFXeo/Mtsx/p8LY5R8w2nd9fAhNWxyTn2G7tfVrfP10eJoSVJQiF39RuxTi3ZnVD+2QImt8jXsud2qE1OoDatKVrmfzQvQqrej9eDQ/epw/SnFNS45ryTHGKCi3PWno/r47Tpa804tZf8UpJljGur8WT91/+MJSdLzj1+l+VMbOMbv2BKq9FVROvRzoL77MkxP92kq05DuGXLEMWbzugh9/VmEcrIDlbE+XKPuTlR84nl1v5eWXLXnI1dhVHkL45cyMjJkGIZeeukl+fmV5DfvvPPOr85r1qyZmjVrpmHDhum+++7TggULdOedd6pDhw768ccflZiYWNGh4z8+X1lHUbWL9MCw/apdt0i7todqbP8WOvWfhZL1Ywtk/tfi8u1bIvTcE03V7y/71X/EPh3YG6zJjzTTzztLrrAw7DbFNz2nlLuOKqpWsXJPBWjnt2EaeW+Ssn8KdRxnXlq87MXSiGm7FBRkaMe2cI3p01J5udXuxxxXmBvvOKXTxwO0+IUGOnk0QE3+55ymLNntaGEcPRAov//6ulZYYNOi5xroUHagQkIN/ea3uRo142eFR9kdY/Jz/bUgrYGOHaqhiJp2XXfrKQ0Yc0gB3AYC1US1+82amJiooqIizZw5U7169dIXX3yhOXPmlDr+3LlzGjlypO6++241btxY+/fv19dff63f//73kqTRo0frf//3f5WamqqBAwcqLCxMP/74o9asWaO//e1vlfWxfM5Hb8boozdjXL43+v6kS/alf1xH6R+7vr69qNBPzwz+9btJ2ov9NC+tkealNXIvWMACdzx0THc8dMzley+863xvmzad8zV3/Y7LHq/r7afU9fZTVoWHSsTjvKtI27ZtNW3aND333HNq1aqVlixZorS0tFLH+/v76/jx4+rbt6+aNWume+65R7fccosmTpwoSWrTpo3Wr1+vnTt3qkuXLmrfvr3GjRun2NjYyvpIAABf4iNXYdhM00uaLVUoNzdXUVFRuin4HgXYAn99AuCFPt7976oOAagwuWcM1Wq2W6dPn66whfEX/lZ07jlJATUuvcKvrIqLzmvT6nEVGqsVql0LAwAAb+YrLQwSCAAArGSYJZsn870ACQQAAFbydB2Dd+QP1W8RJQAAqP6oQAAAYCGbPFwDYVkkFYsEAgAAK3l6N0kvuTiSFgYAAHAbFQgAACzEZZwAAMB9XIUBAADgGgkEAAAWspmmx1t5zJo1SwkJCQoODlanTp301VdflTp27ty56tKli2rVqqVatWopJSXlsuNdIYEAAMBKhgWbm5YtW6bhw4dr/Pjx2rJli9q2basePXroyJEjLsevW7dO9913nz777DNt2rRJ8fHx6t69uw4cOFDmc5JAAADg5aZNm6ZBgwZpwIABSkpK0pw5cxQaGqr58+e7HL9kyRINGTJE7dq1U4sWLTRv3jwZhqG1a9eW+ZwkEAAAWMiqFkZubq7TVlBQ4PJ8hYWFysjIUEpKimOfn5+fUlJStGnTpjLFfPbsWRUVFal27dpl/pwkEAAAWMm0YJMUHx+vqKgox5aWlubydMeOHZPdbld0dLTT/ujoaOXk5JQp5NGjRys2NtYpCfk1XMYJAICVLLoT5b59+xQZGenYHRQU5GlkLj377LNaunSp1q1bp+Dg4DLPI4EAAKAaioyMdEogSlO3bl35+/vr8OHDTvsPHz6smJiYy8598cUX9eyzz+qTTz5RmzZt3IqPFgYAABa6cCdKTzZ3BAYGKjk52WkB5IUFkZ07dy513vPPP6/Jkydr9erV6tixo9ufkwoEAABWqoKHaQ0fPlz9+vVTx44ddc0112j69OnKz8/XgAEDJEl9+/ZVXFycYx3Fc889p3Hjxuntt99WQkKCY61EeHi4wsPDy3ROEggAALzcvffeq6NHj2rcuHHKyclRu3bttHr1asfCyuzsbPn5XWw6zJ49W4WFhbr77rudjjN+/HhNmDChTOckgQAAwEI2o2TzZH55pKamKjU11eV769atc3q9d+/e8p3kv5BAAABgpSpoYVQFFlECAAC3UYEAAMBKPvI4bxIIAAAs5MkTNS/M9wa0MAAAgNuoQAAAYCUfWURJAgEAgJVMSR5cxskaCAAAfBBrIAAAAEpBBQIAACuZ8nANhGWRVCgSCAAArOQjiyhpYQAAALdRgQAAwEqGJJuH870ACQQAABbiKgwAAIBSUIEAAMBKPrKIkgQCAAAr+UgCQQsDAAC4jQoEAABW8pEKBAkEAABW4jJOAADgLi7jBAAAKAUVCAAArMQaCAAA4DbDlGweJAGGdyQQtDAAAIDbqEAAAGAlWhgAAMB9HiYQ8o4EghYGAABwGxUIAACsRAsDAAC4zTDlURuCqzAAAMCVigoEAABWMo2SzZP5XoAEAgAAK7EGAgAAuI01EAAAAK5RgQAAwEq0MAAAgNtMeZhAWBZJhaKFAQAA3EYFAgAAK9HCAAAAbjMMSR7cy8HwjvtA0MIAAABuowIBAICVaGEAAAC3+UgCQQsDAAC4jQoEAABW8pFbWZNAAABgIdM0ZHrwRE1P5lYmEggAAKxkmp5VEVgDAQAArlRUIAAAsJLp4RoIL6lAkEAAAGAlw5BsHqxj8JI1ELQwAACA26hAAABgJVoYAADAXaZhyPSgheEtl3HSwgAAAG6jAgEAgJVoYQAAALcZpmS78hMIWhgAAMBtVCAAALCSaUry5D4Q3lGBIIEAAMBCpmHK9KCFYZJAAADgg0xDnlUguIwTAABcoahAAABgIVoYAADAfT7SwiCBKIML2WCxWVTFkQAVJ/eMd/zSAsojN6/k57syvt0Xq8ij+0gVyzv+1pBAlMGZM2ckSZ8XvF/FkQAVp1azqo4AqHhnzpxRVFRUhRw7MDBQMTExSs9Z5fGxYmJiFBgYaEFUFcdmekuzpQoZhqGDBw8qIiJCNputqsPxCbm5uYqPj9e+ffsUGRlZ1eEAluLnu/KZpqkzZ84oNjZWfn4Vd/3A+fPnVVhY6PFxAgMDFRwcbEFEFYcKRBn4+fmpYcOGVR2GT4qMjOQXLK5Y/HxXroqqPPy34ODgav+H3ypcxgkAANxGAgEAANxGAoFqKSgoSOPHj1dQUFBVhwJYjp9vXAlYRAkAANxGBQIAALiNBAIAALiNBAIAALiNBAIAKtHChQtVs2bNqg4D8BgJBCqUzWa77DZhwoSqDhEol/79+7v8mc7Kyqrq0IBKwZ0oUaEOHTrk+PeyZcs0btw4ZWZmOvaFh4c7/m2apux2uwIC+LGEd+jZs6cWLFjgtK9evXpVFA1QuahAoELFxMQ4tqioKNlsNsfrHTt2KCIiQh9//LGSk5MVFBSk9PR09e/fX71793Y6zhNPPKEbb7zR8dowDKWlpalx48YKCQlR27ZttXz58sr9cPB5QUFBTj/jMTExeuWVV9S6dWuFhYUpPj5eQ4YMUV5eXqnH2LZtm7p166aIiAhFRkYqOTlZmzdvdryfnp6uLl26KCQkRPHx8Xr88ceVn59fGR8PuCwSCFS5MWPG6Nlnn9X27dvVpk2bMs1JS0vT4sWLNWfOHP3www8aNmyYHnjgAa1fv76CowUuz8/PTzNmzNAPP/ygRYsW6dNPP9WoUaNKHd+nTx81bNhQX3/9tTIyMjRmzBjVqFFDkrRr1y717NlTv//97/Xtt99q2bJlSk9PV2pqamV9HKBU1IpR5SZNmqSbb765zOMLCgo0depUffLJJ+rcubMkqUmTJkpPT9drr72mrl27VlSogJMVK1Y4teFuueUW/eMf/3C8TkhI0DPPPKNHHnlEr776qstjZGdna+TIkWrRooUk6eqrr3a8l5aWpj59+uiJJ55wvDdjxgx17dpVs2fP9pmHNqF6IoFAlevYsaNb47OysnT27NlLko7CwkK1b9/eytCAy+rWrZtmz57teB0WFqZPPvlEaWlp2rFjh3Jzc1VcXKzz58/r7NmzCg0NveQYw4cP18CBA/Xmm28qJSVFf/jDH9S0aVNJJe2Nb7/9VkuWLHGMN01ThmFoz549atmyZcV/SKAUJBCocmFhYU6v/fz89Ms7rBcVFTn+faGfvHLlSsXFxTmN49kCqExhYWFKTEx0vN67d69uu+02DR48WFOmTFHt2rWVnp6uhx9+WIWFhS4TiAkTJuj+++/XypUr9fHHH2v8+PFaunSp7rzzTuXl5enPf/6zHn/88UvmXXXVVRX62YBfQwKBaqdevXr6/vvvnfZt3brV0RdOSkpSUFCQsrOzaVegWsnIyJBhGHrppZfk51eyxOydd9751XnNmjVTs2bNNGzYMN13331asGCB7rzzTnXo0EE//vijU5ICVBcsokS1c9NNN2nz5s1avHixfvrpJ40fP94poYiIiNCIESM0bNgwLVq0SLt27dKWLVs0c+ZMLVq0qAojh69LTExUUVGRZs6cqd27d+vNN9/UnDlzSh1/7tw5paamat26dfr555/1xRdf6Ouvv3a0JkaPHq2NGzcqNTVVW7du1U8//aR//vOfLKJEtUACgWqnR48eGjt2rEaNGqXf/OY3OnPmjPr27es0ZvLkyRo7dqzS0tLUsmVL9ezZUytXrlTjxo2rKGpAatu2raZNm6bnnntOrVq10pIlS5SWllbqeH9/fx0/flx9+/ZVs2bNdM899+iWW27RxIkTJUlt2rTR+vXrtXPnTnXp0kXt27fXuHHjFBsbW1kfCSgVj/MGAABuowIBAADcRgIBAADcRgIBAADcRgIBAADcRgIBAADcRgIBAADcRgIBAADcRgIBAADcRgIBeIn+/furd+/ejtc33nij4zHPlWndunWy2Ww6depUqWNsNps++OCDMh9zwoQJateunUdx7d27VzabTVu3bvXoOADKhgQC8ED//v1ls9lks9kUGBioxMRETZo0ScXFxRV+7vfee0+TJ08u09iy/NEHAHfwNE7AQz179tSCBQtUUFCgVatW6dFHH1WNGjX05JNPXjK2sLBQgYGBlpy3du3alhwHAMqDCgTgoaCgIMXExKhRo0YaPHiwUlJS9OGHH0q62HaYMmWKYmNj1bx5c0nSvn37dM8996hmzZqqXbu27rjjDu3du9dxTLvdruHDh6tmzZqqU6eORo0apV8+tuaXLYyCggKNHj1a8fHxCgoKUmJiot544w3t3btX3bp1kyTVqlVLNptN/fv3lyQZhqG0tDQ1btxYISEhatu2rZYvX+50nlWrVqlZs2YKCQlRt27dnOIsq9GjR6tZs2YKDQ1VkyZNNHbsWBUVFV0y7rXXXlN8fLxCQ0N1zz336PTp007vz5s3Ty1btlRwcLBatGihV1991e1YAFiDBAKwWEhIiAoLCx2v165dq8zMTK1Zs0YrVqxQUVGRevTooYiICG3YsEFffPGFwsPD1bNnT8e8l156SQsXLtT8+fOVnp6uEydO6P3337/sefv27au///3vmjFjhrZv367XXntN4eHhio+P17vvvitJyszM1KFDh/TKK69IktLS0rR48WLNmTNHP/zwg4YNG6YHHnhA69evl1SS6Nx1113q1auXtm7dqoEDB2rMmDFu/zeJiIjQwoUL9eOPP+qVV17R3Llz9fLLLzuNycrK0jvvvKOPPvpIq1ev1jfffKMhQ4Y43l+yZInGjRunKVOmaPv27Zo6darGjh3LI9yBqmICKLd+/fqZd9xxh2mapmkYhrlmzRozKCjIHDFihOP96Ohos6CgwDHnzTffNJs3b24ahuHYV1BQYIaEhJj/+te/TNM0zQYNGpjPP/+84/2ioiKzYcOGjnOZpml27drVHDp0qGmappmZmWlKMtesWeMyzs8++8yUZJ48edKx7/z582ZoaKi5ceNGp7EPP/ywed9995mmaZpPPvmkmZSU5PT+6NGjLznWL0ky33///VLff+GFF8zk5GTH6/Hjx5v+/v7m/v37Hfs+/vhj08/Pzzx06JBpmqbZtGlT8+2333Y6zuTJk83OnTubpmmae/bsMSWZ33zzTannBWAd1kAAHlqxYoXCw8NVVFQkwzB0//33a8KECY73W7du7bTuYdu2bcrKylJERITTcc6fP69du3bp9OnTOnTokDp16uR4LyAgQB07drykjXHB1q1b5e/vr65du5Y57qysLJ09e1Y333yz0/7CwkK1b99ekrR9+3anOCSpc+fOZT7HBcuWLdOMGTO0a9cu5eXlqbi4WJGRkU5jrrrqKsXFxTmdxzAMZWZmKiIiQrt27dLDDz+sQYMGOcYUFxcrKirK7XgAeI4EAvBQt27dNHv2bAUGBio2NlYBAc7/W4WFhTm9zsvLU3JyspYsWXLJserVq1euGEJCQtyek5eXJ0lauXKl0x9uqWRdh1U2bdqkPn36aOLEierRo4eioqK0dOlSvfTSS27HOnfu3EsSGn9/f8tiBVB2JBCAh8LCwpSYmFjm8R06dNCyZctUv379S76FX9CgQQN9+eWXuuGGGySVfNPOyMhQhw4dXI5v3bq1DMPQ+vXrlZKScsn7FyogdrvdsS8pKUlBQUHKzs4utXLRsmVLx4LQC/7973//+of8Lxs3blSjRo309NNPO/b9/PPPl4zLzs7WwYMHFRsb6ziPn5+fmjdvrujoaMXGxmr37t3q06ePW+cHUDFYRAlUsj59+qhu3bq64447tGHDBu3Zs0fr1q3T448/rv3790uShg4dqmeffVYffPCBduzYoSFDhlz2Hg4JCQnq16+fHnroIX3wwQeOY77zzjuSpEaNGslms2nFihU6evSo8vLyFBERoREjRmjYsGFatGiRdu3apS1btmjmzJmOhYmPPPKIfvrpJ40cOVKZmZl6++23tXDhQrc+79VXX63s7GwtXbpUu3bt0owZM1wuCA0ODla/fv20bds2bdiwQY8//rjuuecexcTESJImTpyotLQ0zZgxQzt37tR3332nBQsWaNq0aW7FA8AaJBBAJQsNDdXnn3+uq666SnfddZdatmyphx9+WOfPn3dUJP7yl7/owQcfVL9+/dS5c2dFRETozjvvvOxxZ8+erbvvvltDhgxRixYtNGjQIOXn50uS4uLiNHHiRI0ZM0bR0dFKTU2VJE2ePFljx45VWlqaWrZsqZ49e2rlypVq3LixpJJ1Ce+++64++OADtW3bVnPmzNHUqVPd+ry33367hg0bptTUVLVr104bN27U2LFjLxmXmJiou+66S7feequ6d++uNm3aOF2mOXDgQM2bN08LFixQ69at1bVrVy1cuNARK4DKZTNLW5UFAABQCioQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbSQQAADAbf8P9ex/fOYMdN0AAAAASUVORK5CYII=\n" }, "metadata": {} } ] }, { "cell_type": "code", "source": [ "result" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Qv5tjBAsLcFw", "outputId": "ad68ccf3-1277-46d4-8738-3a6d51bfff86" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "array([[0.96431656, 0.01209579],\n", " [0.03568344, 0.98790421]])" ] }, "metadata": {}, "execution_count": 110 } ] }, { "cell_type": "code", "source": [ "import numpy as np\n", "result = np.array( [[0.96431656, 0.01209579],\n", " [0.03568344, 0.98790421]])\n", "result" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Mg1rGRl2Os5T", "outputId": "16330d04-23d9-4dfc-b76c-3ac55d81369b" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "array([[0.96431656, 0.01209579],\n", " [0.03568344, 0.98790421]])" ] }, "metadata": {}, "execution_count": 3 } ] }, { "cell_type": "markdown", "source": [ "## CISIDS2017" ], "metadata": { "id": "lx4RpN47ybt6" } }, { "cell_type": "code", "source": [ "from google.colab import drive\n", "drive.mount('/content/drive')" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "kHU-PAI6yhyz", "outputId": "a7e81346-a8b3-44c0-841f-4d2217882c02" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Mounted at /content/drive\n" ] } ] }, { "cell_type": "code", "source": [ "import pandas as pd\n", "import glob\n", "import os\n", "\n", "path = r'C:\\DRO\\DCL_rawdata_files' # use your path\n", "all_files = glob.glob(os.path.join(path , \"/content/drive/MyDrive/datasets/CISIDS2017/*.csv\"))\n", "\n", "li = []\n", "\n", "for filename in all_files:\n", " df = pd.read_csv(filename, index_col=None, header=0)\n", " li.append(df)\n", "\n", "frame = pd.concat(li, axis=0, ignore_index=True)" ], "metadata": { "id": "orUywltc2yaK" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "frame" ], "metadata": { "id": "OnM8i81AUmva", "outputId": "f6e5ef49-82cf-4268-a39b-4f5b75f92b01", "colab": { "base_uri": "https://localhost:8080/", "height": 496 } }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " Destination Port Flow Duration Total Fwd Packets \\\n", "0 54865 3 2 \n", "1 55054 109 1 \n", "2 55055 52 1 \n", "3 46236 34 1 \n", "4 54863 3 2 \n", "... ... ... ... \n", "2830738 53 32215 4 \n", "2830739 53 324 2 \n", "2830740 58030 82 2 \n", "2830741 53 1048635 6 \n", "2830742 53 94939 4 \n", "\n", " Total Backward Packets Total Length of Fwd Packets \\\n", "0 0 12 \n", "1 1 6 \n", "2 1 6 \n", "3 1 6 \n", "4 0 12 \n", "... ... ... \n", "2830738 2 112 \n", "2830739 2 84 \n", "2830740 1 31 \n", "2830741 2 192 \n", "2830742 2 188 \n", "\n", " Total Length of Bwd Packets Fwd Packet Length Max \\\n", "0 0 6 \n", "1 6 6 \n", "2 6 6 \n", "3 6 6 \n", "4 0 6 \n", "... ... ... \n", "2830738 152 28 \n", "2830739 362 42 \n", "2830740 6 31 \n", "2830741 256 32 \n", "2830742 226 47 \n", "\n", " Fwd Packet Length Min Fwd Packet Length Mean \\\n", "0 6 6.0 \n", "1 6 6.0 \n", "2 6 6.0 \n", "3 6 6.0 \n", "4 6 6.0 \n", "... ... ... \n", "2830738 28 28.0 \n", "2830739 42 42.0 \n", "2830740 0 15.5 \n", "2830741 32 32.0 \n", "2830742 47 47.0 \n", "\n", " Fwd Packet Length Std ... min_seg_size_forward Active Mean \\\n", "0 0.00000 ... 20 0.0 \n", "1 0.00000 ... 20 0.0 \n", "2 0.00000 ... 20 0.0 \n", "3 0.00000 ... 20 0.0 \n", "4 0.00000 ... 20 0.0 \n", "... ... ... ... ... \n", "2830738 0.00000 ... 20 0.0 \n", "2830739 0.00000 ... 20 0.0 \n", "2830740 21.92031 ... 32 0.0 \n", "2830741 0.00000 ... 20 0.0 \n", "2830742 0.00000 ... 20 0.0 \n", "\n", " Active Std Active Max Active Min Idle Mean Idle Std \\\n", "0 0.0 0 0 0.0 0.0 \n", "1 0.0 0 0 0.0 0.0 \n", "2 0.0 0 0 0.0 0.0 \n", "3 0.0 0 0 0.0 0.0 \n", "4 0.0 0 0 0.0 0.0 \n", "... ... ... ... ... ... \n", "2830738 0.0 0 0 0.0 0.0 \n", "2830739 0.0 0 0 0.0 0.0 \n", "2830740 0.0 0 0 0.0 0.0 \n", "2830741 0.0 0 0 0.0 0.0 \n", "2830742 0.0 0 0 0.0 0.0 \n", "\n", " Idle Max Idle Min Label \n", "0 0 0 BENIGN \n", "1 0 0 BENIGN \n", "2 0 0 BENIGN \n", "3 0 0 BENIGN \n", "4 0 0 BENIGN \n", "... ... ... ... \n", "2830738 0 0 BENIGN \n", "2830739 0 0 BENIGN \n", "2830740 0 0 BENIGN \n", "2830741 0 0 BENIGN \n", "2830742 0 0 BENIGN \n", "\n", "[2830743 rows x 79 columns]" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Destination PortFlow DurationTotal Fwd PacketsTotal Backward PacketsTotal Length of Fwd PacketsTotal Length of Bwd PacketsFwd Packet Length MaxFwd Packet Length MinFwd Packet Length MeanFwd Packet Length Std...min_seg_size_forwardActive MeanActive StdActive MaxActive MinIdle MeanIdle StdIdle MaxIdle MinLabel
054865320120666.00.00000...200.00.0000.00.000BENIGN
1550541091166666.00.00000...200.00.0000.00.000BENIGN
255055521166666.00.00000...200.00.0000.00.000BENIGN
346236341166666.00.00000...200.00.0000.00.000BENIGN
454863320120666.00.00000...200.00.0000.00.000BENIGN
..................................................................
2830738533221542112152282828.00.00000...200.00.0000.00.000BENIGN
2830739533242284362424242.00.00000...200.00.0000.00.000BENIGN
283074058030822131631015.521.92031...320.00.0000.00.000BENIGN
283074153104863562192256323232.00.00000...200.00.0000.00.000BENIGN
2830742539493942188226474747.00.00000...200.00.0000.00.000BENIGN
\n", "

2830743 rows × 79 columns

\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 3 } ] }, { "cell_type": "code", "source": [ "column_headers = list(frame.columns.values)\n", "column_headers" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "eJcGQKBn4Abs", "outputId": "c7e1dd53-ea73-4d25-e6d8-c1d45feb61b9" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "[' Destination Port',\n", " ' Flow Duration',\n", " ' Total Fwd Packets',\n", " ' Total Backward Packets',\n", " 'Total Length of Fwd Packets',\n", " ' Total Length of Bwd Packets',\n", " ' Fwd Packet Length Max',\n", " ' Fwd Packet Length Min',\n", " ' Fwd Packet Length Mean',\n", " ' Fwd Packet Length Std',\n", " 'Bwd Packet Length Max',\n", " ' Bwd Packet Length Min',\n", " ' Bwd Packet Length Mean',\n", " ' Bwd Packet Length Std',\n", " 'Flow Bytes/s',\n", " ' Flow Packets/s',\n", " ' Flow IAT Mean',\n", " ' Flow IAT Std',\n", " ' Flow IAT Max',\n", " ' Flow IAT Min',\n", " 'Fwd IAT Total',\n", " ' Fwd IAT Mean',\n", " ' Fwd IAT Std',\n", " ' Fwd IAT Max',\n", " ' Fwd IAT Min',\n", " 'Bwd IAT Total',\n", " ' Bwd IAT Mean',\n", " ' Bwd IAT Std',\n", " ' Bwd IAT Max',\n", " ' Bwd IAT Min',\n", " 'Fwd PSH Flags',\n", " ' Bwd PSH Flags',\n", " ' Fwd URG Flags',\n", " ' Bwd URG Flags',\n", " ' Fwd Header Length',\n", " ' Bwd Header Length',\n", " 'Fwd Packets/s',\n", " ' Bwd Packets/s',\n", " ' Min Packet Length',\n", " ' Max Packet Length',\n", " ' Packet Length Mean',\n", " ' Packet Length Std',\n", " ' Packet Length Variance',\n", " 'FIN Flag Count',\n", " ' SYN Flag Count',\n", " ' RST Flag Count',\n", " ' PSH Flag Count',\n", " ' ACK Flag Count',\n", " ' URG Flag Count',\n", " ' CWE Flag Count',\n", " ' ECE Flag Count',\n", " ' Down/Up Ratio',\n", " ' Average Packet Size',\n", " ' Avg Fwd Segment Size',\n", " ' Avg Bwd Segment Size',\n", " ' Fwd Header Length.1',\n", " 'Fwd Avg Bytes/Bulk',\n", " ' Fwd Avg Packets/Bulk',\n", " ' Fwd Avg Bulk Rate',\n", " ' Bwd Avg Bytes/Bulk',\n", " ' Bwd Avg Packets/Bulk',\n", " 'Bwd Avg Bulk Rate',\n", " 'Subflow Fwd Packets',\n", " ' Subflow Fwd Bytes',\n", " ' Subflow Bwd Packets',\n", " ' Subflow Bwd Bytes',\n", " 'Init_Win_bytes_forward',\n", " ' Init_Win_bytes_backward',\n", " ' act_data_pkt_fwd',\n", " ' min_seg_size_forward',\n", " 'Active Mean',\n", " ' Active Std',\n", " ' Active Max',\n", " ' Active Min',\n", " 'Idle Mean',\n", " ' Idle Std',\n", " ' Idle Max',\n", " ' Idle Min',\n", " ' Label']" ] }, "metadata": {}, "execution_count": 4 } ] }, { "cell_type": "code", "source": [ "frame[' Label'] = frame[' Label'].str.replace(r\"^(.(?:1: FutureWarning: The default value of regex will change from True to False in a future version.\n", " frame[' Label'] = frame[' Label'].str.replace(r\"^(.(? (Q3 + 1.5 * IQR)))\n", " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR))).any(axis=1)\n", " return trueList\n", "\n", "nonOutlierList = Remove_Outlier_Indices(df)\n", "new_data = df[nonOutlierList]\n", "\n" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "90ea9f7e-42a2-4a2e-8d6c-c6179f7e9d2b", "id": "i_PXbZyt5-fR" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ ":2: FutureWarning: The default value of numeric_only in DataFrame.quantile is deprecated. In a future version, it will default to False. Select only valid columns or specify the value of numeric_only to silence this warning.\n", " Q1 = df.quantile(0.02)\n", ":3: FutureWarning: The default value of numeric_only in DataFrame.quantile is deprecated. In a future version, it will default to False. Select only valid columns or specify the value of numeric_only to silence this warning.\n", " Q3 = df.quantile(0.98)\n", ":6: FutureWarning: Automatic reindexing on DataFrame vs Series comparisons is deprecated and will raise ValueError in a future version. Do `left, right = left.align(right, axis=1, copy=False)` before e.g. `left == right`\n", " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR))).any(axis=1)\n" ] } ] }, { "cell_type": "code", "source": [ "#Deleting local variables to free the memory\n", "df = new_data\n", "df = df.reset_index(drop=True)\n", "del new_data\n", "del nonOutlierList\n", "del li\n", "del frame" ], "metadata": { "id": "FSPL95xg5-fT" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.decomposition import PCA\n", "n_components = 10\n", "columns = []\n", "for x in range(n_components):\n", " columns.append(str(x+1))\n", "\n", "X = df.drop([' Label'], axis=1).values\n", "y = df[\" Label\"].values\n", "x_scaled = StandardScaler().fit_transform(X)\n", "\n", "pca = PCA(n_components)\n", "\n", "# Fit and transform data\n", "principalComponents = pca.fit_transform(x_scaled)\n", "\n", "principalDf = pd.DataFrame(data = principalComponents\n", " , columns = columns)\n", "finalDf = pd.concat([principalDf, df[\" Label\"]], axis = 1)\n" ], "metadata": { "id": "KH6-dLBE5-fU" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "model = pca\n", "X_pc = principalComponents\n", "\n", "# number of components\n", "n_pcs= model.components_.shape[0]\n", "\n", "# get the index of the most important feature on EACH component\n", "# LIST COMPREHENSION HERE\n", "most_important = [np.abs(model.components_[i]).argmax() for i in range(n_pcs)]\n", "\n", "initial_feature_names = CSV_HEADER\n", "# get the names\n", "most_important_names = [initial_feature_names[most_important[i]] for i in range(n_pcs)]\n", "\n", "# LIST COMPREHENSION HERE AGAIN\n", "dic = {'PC{}'.format(i): most_important_names[i] for i in range(n_pcs)}\n", "\n", "# build the dataframe\n", "dfx = pd.DataFrame(dic.items())\n", "dfx" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 363 }, "id": "2cutctpIQIFe", "outputId": "5054c835-302f-45bb-e6a6-f84bcc92e0df" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " 0 1\n", "0 PC0 Flow Duration\n", "1 PC1 Total Length of Fwd Packets\n", "2 PC2 ACK Flag Count\n", "3 PC3 Fwd Packet Length Min\n", "4 PC4 Fwd Packet Length Mean\n", "5 PC5 Flow Bytes/s\n", "6 PC6 Bwd IAT Std\n", "7 PC7 Active Mean\n", "8 PC8 URG Flag Count\n", "9 PC9 Bwd IAT Min" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
01
0PC0Flow Duration
1PC1Total Length of Fwd Packets
2PC2ACK Flag Count
3PC3Fwd Packet Length Min
4PC4Fwd Packet Length Mean
5PC5Flow Bytes/s
6PC6Bwd IAT Std
7PC7Active Mean
8PC8URG Flag Count
9PC9Bwd IAT Min
\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 64 } ] }, { "cell_type": "code", "source": [ "from sklearn.model_selection import train_test_split\n", "train_data, test_data = train_test_split(finalDf, test_size=0.25)\n", "train_data_file = \"train_data.csv\"\n", "test_data_file = \"test_data.csv\"\n", "\n", "train_data.to_csv(train_data_file, index=False, header=False)\n", "test_data.to_csv(test_data_file, index=False, header=False)" ], "metadata": { "id": "c85wOCBv5-fX" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "del finalDf\n", "del principalDf\n", "del train_data\n", "del test_data" ], "metadata": { "id": "szYkC6TjPd0U" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "CSV_HEADER = []\n", "for x in columns:\n", " CSV_HEADER.append(x)\n", "CSV_HEADER.append(\" Label\")\n", "\n", "# A list of the numerical feature names.\n", "NUMERIC_FEATURE_NAMES = columns\n", "# A dictionary of the categorical features and their vocabulary.\n", "CATEGORICAL_FEATURES_WITH_VOCABULARY = {\n", "}\n", "# A list of the columns to ignore from the dataset.\n", "IGNORE_COLUMN_NAMES = []\n", "# A list of the categorical feature names.\n", "CATEGORICAL_FEATURE_NAMES = list(CATEGORICAL_FEATURES_WITH_VOCABULARY.keys())\n", "# A list of all the input features.\n", "FEATURE_NAMES = NUMERIC_FEATURE_NAMES + CATEGORICAL_FEATURE_NAMES\n", "# A list of column default values for each feature.\n", "COLUMN_DEFAULTS = [\n", " [0.0] if feature_name in NUMERIC_FEATURE_NAMES + IGNORE_COLUMN_NAMES else [\"NA\"]\n", " for feature_name in CSV_HEADER\n", "]\n", "# The name of the target feature.\n", "TARGET_FEATURE_NAME = \" Label\"\n", "# A list of the labels of the target features.\n", "TARGET_LABELS = [\"BENIGN\", \"ANOMALY\"]\n", "\n", "from tensorflow.keras.layers import StringLookup\n", "\n", "target_label_lookup = StringLookup(\n", " vocabulary=TARGET_LABELS, mask_token=None, num_oov_indices=0\n", ")\n", "\n", "\n", "def get_dataset_from_csv(csv_file_path, shuffle=False, batch_size=128):\n", " dataset = tf.data.experimental.make_csv_dataset(\n", " csv_file_path,\n", " batch_size=batch_size,\n", " column_names=CSV_HEADER,\n", " column_defaults=COLUMN_DEFAULTS,\n", " label_name=TARGET_FEATURE_NAME,\n", " num_epochs=1,\n", " header=False,\n", " na_value=\"?\",\n", " shuffle=shuffle,\n", " ).map(lambda features, target: (features, target_label_lookup(target)))\n", " return dataset.cache()\n", "\n", "def create_model_inputs():\n", " inputs = {}\n", " for feature_name in FEATURE_NAMES:\n", " if feature_name in NUMERIC_FEATURE_NAMES:\n", " inputs[feature_name] = layers.Input(\n", " name=feature_name, shape=(), dtype=tf.float32\n", " )\n", " else:\n", " inputs[feature_name] = layers.Input(\n", " name=feature_name, shape=(), dtype=tf.string\n", " )\n", " return inputs\n", "\n", "def encode_inputs(inputs):\n", " encoded_features = []\n", " for feature_name in inputs:\n", " if feature_name in CATEGORICAL_FEATURE_NAMES:\n", " vocabulary = CATEGORICAL_FEATURES_WITH_VOCABULARY[feature_name]\n", " #print(vocabulary)\n", " # Create a lookup to convert a string values to an integer indices.\n", " # Since we are not using a mask token, nor expecting any out of vocabulary\n", " # (oov) token, we set mask_token to None and num_oov_indices to 0.\n", " lookup = StringLookup(\n", " vocabulary=vocabulary, mask_token=None, num_oov_indices=0\n", " )\n", " # Convert the string input values into integer indices.\n", " value_index = lookup(inputs[feature_name])\n", " embedding_dims = int(math.sqrt(lookup.vocabulary_size()))\n", " # Create an embedding layer with the specified dimensions.\n", " embedding = layers.Embedding(\n", " input_dim=lookup.vocabulary_size(), output_dim=embedding_dims\n", " )\n", " # Convert the index values to embedding representations.\n", " encoded_feature = embedding(value_index)\n", " else:\n", " # Use the numerical features as-is.\n", " encoded_feature = inputs[feature_name]\n", " if inputs[feature_name].shape[-1] is None:\n", " encoded_feature = tf.expand_dims(encoded_feature, -1)\n", "\n", " encoded_features.append(encoded_feature)\n", "\n", " encoded_features = layers.concatenate(encoded_features)\n", " return encoded_features\n", "\n", "class NeuralDecisionTree(keras.Model):\n", " def __init__(self, depth, num_features, used_features_rate, num_classes):\n", " super().__init__()\n", " self.depth = depth\n", " self.num_leaves = 2 ** depth\n", " self.num_classes = num_classes\n", "\n", " # Create a mask for the randomly selected features.\n", " num_used_features = int(num_features * used_features_rate)\n", " one_hot = np.eye(num_features)\n", " sampled_feature_indicies = np.random.choice(\n", " np.arange(num_features), num_used_features, replace=False\n", " )\n", " self.used_features_mask = one_hot[sampled_feature_indicies]\n", "\n", " # Initialize the weights of the classes in leaves.\n", " self.pi = tf.Variable(\n", " initial_value=tf.random_normal_initializer()(\n", " shape=[self.num_leaves, self.num_classes]\n", " ),\n", " dtype=\"float32\",\n", " trainable=True,\n", " )\n", "\n", " # Initialize the stochastic routing layer.\n", " self.decision_fn = layers.Dense(\n", " units=self.num_leaves, activation=\"sigmoid\", name=\"decision\"\n", " )\n", "\n", " def call(self, features):\n", " batch_size = tf.shape(features)[0]\n", "\n", " # Apply the feature mask to the input features.\n", " features = tf.matmul(\n", " features, self.used_features_mask, transpose_b=True\n", " ) # [batch_size, num_used_features]\n", " # Compute the routing probabilities.\n", " decisions = tf.expand_dims(\n", " self.decision_fn(features), axis=2\n", " ) # [batch_size, num_leaves, 1]\n", " # Concatenate the routing probabilities with their complements.\n", " decisions = layers.concatenate(\n", " [decisions, 1 - decisions], axis=2\n", " ) # [batch_size, num_leaves, 2]\n", "\n", " mu = tf.ones([batch_size, 1, 1])\n", "\n", " begin_idx = 1\n", " end_idx = 2\n", " # Traverse the tree in breadth-first order.\n", " for level in range(self.depth):\n", " mu = tf.reshape(mu, [batch_size, -1, 1]) # [batch_size, 2 ** level, 1]\n", " mu = tf.tile(mu, (1, 1, 2)) # [batch_size, 2 ** level, 2]\n", " level_decisions = decisions[\n", " :, begin_idx:end_idx, :\n", " ] # [batch_size, 2 ** level, 2]\n", " mu = mu * level_decisions # [batch_size, 2**level, 2]\n", " begin_idx = end_idx\n", " end_idx = begin_idx + 2 ** (level + 1)\n", "\n", " mu = tf.reshape(mu, [batch_size, self.num_leaves]) # [batch_size, num_leaves]\n", " probabilities = keras.activations.softmax(self.pi) # [num_leaves, num_classes]\n", " outputs = tf.matmul(mu, probabilities) # [batch_size, num_classes]\n", " return outputs\n", "\n", "class NeuralDecisionForest(keras.Model):\n", " def __init__(self, num_trees, depth, num_features, used_features_rate, num_classes):\n", " super().__init__()\n", " self.ensemble = []\n", " # Initialize the ensemble by adding NeuralDecisionTree instances.\n", " # Each tree will have its own randomly selected input features to use.\n", " for _ in range(num_trees):\n", " self.ensemble.append(\n", " NeuralDecisionTree(depth, num_features, used_features_rate, num_classes)\n", " )\n", "\n", " def call(self, inputs):\n", " # Initialize the outputs: a [batch_size, num_classes] matrix of zeros.\n", " batch_size = tf.shape(inputs)[0]\n", " outputs = tf.zeros([batch_size, num_classes])\n", "\n", " # Aggregate the outputs of trees in the ensemble.\n", " for tree in self.ensemble:\n", " outputs += tree(inputs)\n", " # Divide the outputs by the ensemble size to get the average.\n", " outputs /= len(self.ensemble)\n", " return outputs\n", "learning_rate = 0.01\n", "batch_size = 128\n", "num_epochs = 10\n", "\n", "\n", "def run_experiment(model):\n", "\n", " # model.compile(\n", " # optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", " # loss=keras.losses.SparseCategoricalCrossentropy(),\n", " # metrics=[keras.metrics.SparseCategoricalAccuracy()],\n", " # )\n", " model.compile(\n", " optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", " loss=keras.losses.SparseCategoricalCrossentropy(),\n", " metrics=[metrics.SparseCategoricalAccuracy()],\n", " )\n", " print(\"Start training the model...\")\n", " train_dataset = get_dataset_from_csv(\n", " train_data_file, shuffle=True, batch_size=batch_size\n", " )\n", "\n", " model.fit(train_dataset, epochs=num_epochs)\n", " print(\"Model training finished\")\n", "\n", " print(\"Evaluating the model on the test data...\")\n", " test_dataset = get_dataset_from_csv(test_data_file, batch_size=batch_size)\n", "\n", " _, accuracy = model.evaluate(test_dataset)\n", " print(f\"Test accuracy: {round(accuracy * 100, 2)}%\")\n", " return model" ], "metadata": { "id": "8txIkhqk5-fX", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "9f5593a3-23af-4019-e1a8-8b65018be338" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.10/dist-packages/numpy/core/numeric.py:2463: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison\n", " return bool(asarray(a1 == a2).all())\n" ] } ] }, { "cell_type": "code", "source": [ "num_trees = 25\n", "depth = 5\n", "used_features_rate = 0.5\n", "num_classes = len(TARGET_LABELS)\n", "\n", "\n", "def create_forest_model():\n", " inputs = create_model_inputs()\n", " features = encode_inputs(inputs)\n", " features = layers.BatchNormalization()(features)\n", " num_features = features.shape[1]\n", "\n", " forest_model = NeuralDecisionForest(\n", " num_trees, depth, num_features, used_features_rate, num_classes\n", " )\n", "\n", " outputs = forest_model(features)\n", " model = keras.Model(inputs=inputs, outputs=outputs)\n", " return model\n", "\n", "\n", "forest_model = create_forest_model()\n", "\n", "finalModel = run_experiment(forest_model)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "939b76c5-0742-4f09-e122-8ec4988c107f", "id": "cEIPaJMi5-fa" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Start training the model...\n", "Epoch 1/10\n", "14880/14880 [==============================] - 479s 31ms/step - loss: 0.0907 - sparse_categorical_accuracy: 0.9675\n", "Epoch 2/10\n", "14880/14880 [==============================] - 397s 27ms/step - loss: 0.0763 - sparse_categorical_accuracy: 0.9725\n", "Epoch 3/10\n", "14880/14880 [==============================] - 391s 26ms/step - loss: 0.0741 - sparse_categorical_accuracy: 0.9734\n", "Epoch 4/10\n", "14880/14880 [==============================] - 392s 26ms/step - loss: 0.0729 - sparse_categorical_accuracy: 0.9738\n", "Epoch 5/10\n", "14880/14880 [==============================] - 393s 26ms/step - loss: 0.0721 - sparse_categorical_accuracy: 0.9740\n", "Epoch 6/10\n", "14880/14880 [==============================] - 392s 26ms/step - loss: 0.0715 - sparse_categorical_accuracy: 0.9741\n", "Epoch 7/10\n", "14880/14880 [==============================] - 396s 27ms/step - loss: 0.0711 - sparse_categorical_accuracy: 0.9743\n", "Epoch 8/10\n", "14880/14880 [==============================] - 395s 27ms/step - loss: 0.0705 - sparse_categorical_accuracy: 0.9744\n", "Epoch 9/10\n", "14880/14880 [==============================] - 379s 25ms/step - loss: 0.0702 - sparse_categorical_accuracy: 0.9745\n", "Epoch 10/10\n", "14880/14880 [==============================] - 378s 25ms/step - loss: 0.0700 - sparse_categorical_accuracy: 0.9746\n", "Model training finished\n", "Evaluating the model on the test data...\n", "4960/4960 [==============================] - 62s 12ms/step - loss: 0.0522 - sparse_categorical_accuracy: 0.9818\n", "Test accuracy: 98.18%\n" ] } ] }, { "cell_type": "code", "source": [ "test_dataset = get_dataset_from_csv(test_data_file, batch_size=batch_size)\n", "colnames=['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'target']\n", "data = pd.read_csv(\"test_data.csv\", names=colnames, header=None)\n", "data['target'].replace('BENIGN', 0,inplace=True)\n", "data['target'].replace('ANOMALY', 1,inplace=True)\n", "y_test = data['target'].values # as a numpy array\n", "from sklearn.metrics import confusion_matrix\n", "y_prediction = finalModel.predict(test_dataset)\n", "y_prediction = np.argmax (y_prediction, axis = 1)\n", "result = confusion_matrix(y_test, y_prediction , normalize='pred')\n", "print(result)\n", "TP = result[0][0]\n", "FP = result[0][1]\n", "TN = result[1][1]\n", "FN = result[1][0]\n", "ACC = (TP+TN)/(TP+TN+FP+FN)\n", "PR = TP/(TP+FP) #precision\n", "TPR = TP/(TP+FN) #Recall or True positive rate\n", "FPR = FP/(FP+TN)\n", "F1Score = 2*(PR*TPR)/(PR+TPR)\n", "print(\"ACC: \" + str(ACC))\n", "print(\"PR: \" + str(PR))\n", "print(\"TPR: \" + str(TPR))\n", "print(\"FPR: \" + str(FPR))\n", "print(\"F1Score: \" + str(F1Score))\n", "import matplotlib.pyplot as plt\n", "import numpy\n", "from sklearn import metrics\n", "\n", "\n", "cm_display = metrics.ConfusionMatrixDisplay(confusion_matrix = result, display_labels = [True, False])\n", "\n", "cm_display.plot()\n", "plt.show()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 588 }, "id": "JR5WC1Y0m3hJ", "outputId": "cdc82ece-caf7-4c5b-ea7f-57ac3a84742b" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "4960/4960 [==============================] - 66s 13ms/step\n", "[[0.98051765 0.01229758]\n", " [0.01948235 0.98770242]]\n", "ACC: 0.9841100339902484\n", "PR: 0.987613421019833\n", "TPR: 0.9805176523221462\n", "FPR: 0.012297584341649253\n", "F1Score: 0.9840527453650412\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/png": "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wwaP9gOgbEggAA/07t1bNptNNptNgYGBSkpK0tixY1VcXFzux37vvfc0bty4Mo0ty5c+ALiDp3ECHurSpYtmzZqlgoICLV26VI8++qiqVaump5566qKxhYWFCgwMtOS41atXt2Q/AHA5qEAAHrLb7YqLi1PdunXVv39/paWl6cMPP5R0oe0wfvx4xcfHq3HjxpKkvXv36u6771ZUVJSqV6+ubt26affu3c59OhwODRo0SFFRUapRo4aGDh2qXz625pctjIKCAg0bNkyJiYmy2+1KSkrSm2++qd27d6tDhw6SpOjoaNlsNvXu3VuSZBiGMjIyVL9+fQUHB6tFixZauHBhieMsXbpUjRo1UnBwsDp06FAizrIaNmyYGjVqpJCQEDVo0EAjRoxQUVHRReNee+01JSYmKiQkRHfffbdOnjxZ4v033nhDTZs2VVBQkJo0aaJXX33V7VgAWIMEArBYcHCwCgsLna9XrFihbdu2afny5Vq8eLGKiorUuXNnhYeHa/Xq1fryyy8VFhamLl26OLebOHGiZs+erZkzZyozM1PHjh3T+++/f8nj9uzZU//85z81ZcoUbdmyRa+99prCwsKUmJioRYsWSZK2bdumgwcP6uWXX5YkZWRkaM6cOZo+fbo2bdqkgQMH6v7779eqVasknUt07rjjDnXt2lUbNmxQ3759NXz4cLf/NwkPD9fs2bO1efNmvfzyy5oxY4ZeeumlEmO2b9+uBQsW6KOPPtKyZcv0zTffaMCAAc73586dq5EjR2r8+PHasmWLJkyYoBEjRvAId6CymAAuW69evcxu3bqZpmmahmGYy5cvN+12uzl48GDn+7GxsWZBQYFzm7ffftts3LixaRiGc11BQYEZHBxsfvLJJ6Zpmmbt2rXN559/3vl+UVGRWadOHeexTNM027dvbz7xxBOmaZrmtm3bTEnm8uXLXcb5+eefm5LM48ePO9fl5+ebISEh5po1a0qMfeihh8x7773XNE3TfOqpp8zk5OQS7w8bNuyiff2SJPP9998v9f0XXnjBTElJcb4eNWqU6e/vb+7bt8+57uOPPzb9/PzMgwcPmqZpmldffbX57rvvltjPuHHjzNTUVNM0TXPXrl2mJPObb74p9bgArMMcCMBDixcvVlhYmIqKimQYhu677z6NHj3a+X6zZs1KzHvYuHGjtm/frvDw8BL7yc/P144dO3Ty5EkdPHhQbdu2db4XEBCgNm3aXNTGOG/Dhg3y9/dX+/btyxz39u3bdebMGXXs2LHE+sLCQrVq1UqStGXLlhJxSFJqamqZj3He/PnzNWXKFO3YsUOnT59WcXGxIiIiSoy56qqrlJCQUOI4hmFo27ZtCg8P144dO/TQQw+pX79+zjHFxcWKjIx0Ox4AniOBADzUoUMHTZs2TYGBgYqPj1dAQMl/VqGhoSVenz59WikpKZo7d+5F+4qJibmsGIKDg93e5vTp05KkJUuWlPjils7N67DK2rVr1aNHD40ZM0adO3dWZGSk5s2bp4kTJ7od64wZMy5KaPz9/S2LFUDZkUAAHgoNDVVSUlKZx7du3Vrz589XrVq1LvoVfl7t2rX13//+VzfccIOkc7+0s7Ky1Lp1a5fjmzVrJsMwtGrVKqWlpV30/vkKiMPhcK5LTk6W3W5XdnZ2qZWLpk2bOieEnvef//zn10/yZ9asWaO6devq6aefdq7bs2fPReOys7N14MABxcfHO4/j5+enxo0bKzY2VvHx8dq5c6d69Ojh1vEBlA8mUQIVrEePHqpZs6a6deum1atXa9euXVq5cqUef/xx7du3T5L0xBNP6Nlnn9UHH3ygrVu3asCAAZe8h0O9evXUq1cvPfjgg/rggw+c+1ywYIEkqW7durLZbFq8eLEOHz6s06dPKzw8XIMHD9bAgQP11ltvaceOHVq/fr1eeeUV58TERx55RD/++KOGDBmibdu26d1339Xs2bPdOt+GDRsqOztb8+bN044dOzRlyhSXE0KDgoLUq1cvbdy4UatXr9bjjz+uu+++W3FxcZKkMWPGKCMjQ1OmTNEPP/yg7777TrNmzdKkSZPcigeANUgggAoWEhKiL774QldddZXuuOMONW3aVA899JDy8/OdFYm//vWveuCBB9SrVy+lpqYqPDxct99++yX3O23aNN11110aMGCAmjRpon79+ikvL0+SlJCQoDFjxmj48OGKjY1Venq6JGncuHEaMWKEMjIy1LRpU3Xp0kVLlixR/fr1JZ2bl7Bo0SJ98MEHatGihaZPn64JEya4db633XabBg4cqPT0dLVs2VJr1qzRiBEjLhqXlJSkO+64Q7fccos6deqk5s2bl7hMs2/fvnrjjTc0a9YsNWvWTO3bt9fs2bOdsQKoWDaztFlZAAAApaACAQAA3EYCAQAA3EYCAQAA3EYCAQAA3EYCAQAA3EYCAQAA3EYCAQAA3EYCAQAA3EYCAQAA3EYCAQAA3EYCAQAA3Pb/tdVwvHV1WkUAAAAASUVORK5CYII=\n" }, "metadata": {} } ] }, { "cell_type": "markdown", "source": [ "## UNSW-NB15" ], "metadata": { "id": "qjs4Ip6kFAJZ" } }, { "cell_type": "code", "source": [ "import tensorflow as tf\n", "import numpy as np\n", "import pandas as pd\n", "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "from keras import losses\n", "from keras import optimizers\n", "from keras import metrics\n", "import math\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns" ], "metadata": { "id": "t6hf8w1lMbqG" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "from google.colab import drive\n", "drive.mount('/content/drive')" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "496bd7cd-ee69-436f-9006-8a085e020510", "id": "CDFWCDSjFAJj" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Mounted at /content/drive\n" ] } ] }, { "cell_type": "code", "source": [ "CSV_HEADER = [\n", "\"srcip\",\n", "\"sport\",\n", "\"dstip\",\n", "\"dsport\",\n", "\"proto\",\n", "\"state\",\n", "\"dur\",\n", "\"sbytes\",\n", "\"dbytes\",\n", "\"sttl\",\n", "\"dttl\",\n", "\"sloss\",\n", "\"dloss\",\n", "\"service\",\n", "\"Sload\",\n", "\"Dload\",\n", "\"Spkts\",\n", "\"Dpkts\",\n", "\"swin\",\n", "\"dwin\",\n", "\"stcpb\",\n", "\"dtcpb\",\n", "\"smeansz\",\n", "\"dmeansz\",\n", "\"trans_depth\",\n", "\"res_bdy_len\",\n", "\"Sjit\",\n", "\"Djit\",\n", "\"Stime\",\n", "\"Ltime\",\n", "\"Sintpkt\",\n", "\"Dintpkt\",\n", "\"tcprtt\",\n", "\"synack\",\n", "\"ackdat\",\n", "\"is_sm_ips_ports\",\n", "\"ct_state_ttl\",\n", "\"ct_flw_http_mthd\",\n", "\"is_ftp_login\",\n", "\"ct_ftp_cmd\",\n", "\"ct_srv_src\",\n", "\"ct_srv_dst\",\n", "\"ct_dst_ltm\",\n", "\"ct_src_ ltm\",\n", "\"ct_src_dport_ltm\",\n", "\"ct_dst_sport_ltm\",\n", "\"ct_dst_src_ltm\",\n", "\"attack_cat\",\n", "\"Label\"\n", "]" ], "metadata": { "id": "-nz1C-V-dNpp" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "import pandas as pd\n", "import glob\n", "import os\n", "\n", "path = r'C:\\DRO\\DCL_rawdata_files' # use your path\n", "all_files = glob.glob(os.path.join(path , \"/content/drive/MyDrive/datasets/UNSW-NB15/*.csv\"))\n", "\n", "li = []\n", "\n", "for filename in all_files:\n", " df = pd.read_csv(filename, index_col=None, header=None, names=CSV_HEADER,low_memory=False)\n", " li.append(df)\n", "\n", "frame = pd.concat(li, axis=0, ignore_index=True)" ], "metadata": { "id": "D-JA_26MFAJj" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "pd.set_option('display.max_columns', None)\n", "frame" ], "metadata": { "id": "GUChMqNeFAJk", "colab": { "base_uri": "https://localhost:8080/", "height": 461 }, "outputId": "e0557a78-8300-4d34-a2a8-dac9470b903f" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " srcip sport dstip dsport proto state dur \\\n", "0 59.166.0.9 7045 149.171.126.7 25 tcp FIN 0.201886 \n", "1 59.166.0.9 9685 149.171.126.2 80 tcp FIN 5.864748 \n", "2 59.166.0.2 1421 149.171.126.4 53 udp CON 0.001391 \n", "3 59.166.0.2 21553 149.171.126.2 25 tcp FIN 0.053948 \n", "4 59.166.0.8 45212 149.171.126.4 53 udp CON 0.000953 \n", "... ... ... ... ... ... ... ... \n", "2540042 59.166.0.8 12520 149.171.126.6 31010 tcp FIN 0.020383 \n", "2540043 59.166.0.0 18895 149.171.126.9 80 tcp FIN 1.402957 \n", "2540044 59.166.0.0 30103 149.171.126.5 5190 tcp FIN 0.007108 \n", "2540045 59.166.0.6 30388 149.171.126.5 111 udp CON 0.004435 \n", "2540046 59.166.0.0 6055 149.171.126.5 54145 tcp FIN 0.072974 \n", "\n", " sbytes dbytes sttl dttl sloss dloss service Sload \\\n", "0 37552 3380 31 29 18 8 smtp 1.459438e+06 \n", "1 19410 1087890 31 29 2 370 http 2.640454e+04 \n", "2 146 178 31 29 0 0 dns 4.198418e+05 \n", "3 37812 3380 31 29 19 8 smtp 5.503374e+06 \n", "4 146 178 31 29 0 0 dns 6.128017e+05 \n", "... ... ... ... ... ... ... ... ... \n", "2540042 320 1874 31 29 1 2 - 1.047932e+05 \n", "2540043 19410 1087890 31 29 2 370 http 1.103783e+05 \n", "2540044 2158 2464 31 29 6 6 - 2.328644e+06 \n", "2540045 568 304 31 29 0 0 - 7.684329e+05 \n", "2540046 4238 60788 31 29 7 30 - 4.582454e+05 \n", "\n", " Dload Spkts Dpkts swin dwin stcpb dtcpb \\\n", "0 1.307669e+05 52 42 255 255 1422136554 3572668484 \n", "1 1.481983e+06 364 746 255 255 389619597 394688654 \n", "2 5.118620e+05 2 2 0 0 0 0 \n", "3 4.893601e+05 54 42 255 255 4047523379 1903327524 \n", "4 7.471144e+05 2 2 0 0 0 0 \n", "... ... ... ... ... ... ... ... \n", "2540042 6.436736e+05 6 8 255 255 3208686479 3225486168 \n", "2540043 6.195098e+06 364 746 255 255 283296697 2429736754 \n", "2540044 2.658413e+06 24 24 255 255 703293844 2848960529 \n", "2540045 4.112740e+05 4 4 0 0 0 0 \n", "2540046 6.571546e+06 72 72 255 255 1003293149 1003585034 \n", "\n", " smeansz dmeansz trans_depth res_bdy_len Sjit Djit \\\n", "0 722 80 0 0 456.043567 15.530109 \n", "1 53 1458 1 0 1031.366423 690.219581 \n", "2 73 89 0 0 0.000000 0.000000 \n", "3 700 80 0 0 65.909688 3.155258 \n", "4 73 89 0 0 0.000000 0.000000 \n", "... ... ... ... ... ... ... \n", "2540042 53 234 0 0 212.810729 3.079195 \n", "2540043 53 1458 1 3924 203.808900 114.173588 \n", "2540044 90 103 0 0 17.627831 0.432619 \n", "2540045 142 76 0 0 1.638604 1.390643 \n", "2540046 59 844 0 0 62.045310 61.899776 \n", "\n", " Stime Ltime Sintpkt Dintpkt tcprtt synack \\\n", "0 1424250009 1424250009 3.943843 4.912488 0.000590 0.000473 \n", "1 1424250003 1424250009 16.155447 7.871279 0.000771 0.000638 \n", "2 1424250009 1424250009 0.009000 0.002000 0.000000 0.000000 \n", "3 1424250009 1424250009 1.011547 1.302561 0.000674 0.000540 \n", "4 1424250009 1424250009 0.009000 0.004000 0.000000 0.000000 \n", "... ... ... ... ... ... ... \n", "2540042 1421955842 1421955842 4.007400 2.027429 0.006386 0.006189 \n", "2540043 1421955841 1421955842 3.864028 1.882421 0.000712 0.000550 \n", "2540044 1421955842 1421955842 0.274261 0.285478 0.000657 0.000532 \n", "2540045 1421955842 1421955842 1.165667 0.987333 0.000000 0.000000 \n", "2540046 1421955842 1421955842 1.022690 0.997042 0.002317 0.002173 \n", "\n", " ackdat is_sm_ips_ports ct_state_ttl ct_flw_http_mthd \\\n", "0 0.000117 0 0 NaN \n", "1 0.000133 0 0 1.0 \n", "2 0.000000 0 0 NaN \n", "3 0.000134 0 0 NaN \n", "4 0.000000 0 0 NaN \n", "... ... ... ... ... \n", "2540042 0.000197 0 0 0.0 \n", "2540043 0.000162 0 0 4.0 \n", "2540044 0.000125 0 0 0.0 \n", "2540045 0.000000 0 0 0.0 \n", "2540046 0.000144 0 0 0.0 \n", "\n", " is_ftp_login ct_ftp_cmd ct_srv_src ct_srv_dst ct_dst_ltm \\\n", "0 NaN 2 2 7 \n", "1 NaN 3 1 4 \n", "2 NaN 3 5 2 \n", "3 NaN 1 1 4 \n", "4 NaN 2 5 2 \n", "... ... ... ... ... ... \n", "2540042 0.0 0 8 20 7 \n", "2540043 0.0 0 1 1 2 \n", "2540044 0.0 0 13 13 6 \n", "2540045 0.0 0 10 13 6 \n", "2540046 0.0 0 13 13 6 \n", "\n", " ct_src_ ltm ct_src_dport_ltm ct_dst_sport_ltm ct_dst_src_ltm \\\n", "0 4 1 1 3 \n", "1 4 1 1 1 \n", "2 7 1 1 4 \n", "3 7 1 1 3 \n", "4 1 1 1 2 \n", "... ... ... ... ... \n", "2540042 5 1 1 4 \n", "2540043 7 2 2 2 \n", "2540044 7 2 1 2 \n", "2540045 5 1 1 3 \n", "2540046 7 1 1 2 \n", "\n", " attack_cat Label \n", "0 NaN 0 \n", "1 NaN 0 \n", "2 NaN 0 \n", "3 NaN 0 \n", "4 NaN 0 \n", "... ... ... \n", "2540042 NaN 0 \n", "2540043 NaN 0 \n", "2540044 NaN 0 \n", "2540045 NaN 0 \n", "2540046 NaN 0 \n", "\n", "[2540047 rows x 49 columns]" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
srcipsportdstipdsportprotostatedursbytesdbytessttldttlslossdlossserviceSloadDloadSpktsDpktsswindwinstcpbdtcpbsmeanszdmeansztrans_depthres_bdy_lenSjitDjitStimeLtimeSintpktDintpkttcprttsynackackdatis_sm_ips_portsct_state_ttlct_flw_http_mthdis_ftp_loginct_ftp_cmdct_srv_srcct_srv_dstct_dst_ltmct_src_ ltmct_src_dport_ltmct_dst_sport_ltmct_dst_src_ltmattack_catLabel
059.166.0.97045149.171.126.725tcpFIN0.2018863755233803129188smtp1.459438e+061.307669e+055242255255142213655435726684847228000456.04356715.530109142425000914242500093.9438434.9124880.0005900.0004730.00011700NaNNaN2274113NaN0
159.166.0.99685149.171.126.280tcpFIN5.86474819410108789031292370http2.640454e+041.481983e+06364746255255389619597394688654531458101031.366423690.2195811424250003142425000916.1554477.8712790.0007710.0006380.000133001.0NaN3144111NaN0
259.166.0.21421149.171.126.453udpCON0.001391146178312900dns4.198418e+055.118620e+052200007389000.0000000.000000142425000914242500090.0090000.0020000.0000000.0000000.00000000NaNNaN3527114NaN0
359.166.0.221553149.171.126.225tcpFIN0.0539483781233803129198smtp5.503374e+064.893601e+05544225525540475233791903327524700800065.9096883.155258142425000914242500091.0115471.3025610.0006740.0005400.00013400NaNNaN1147113NaN0
459.166.0.845212149.171.126.453udpCON0.000953146178312900dns6.128017e+057.471144e+052200007389000.0000000.000000142425000914242500090.0090000.0040000.0000000.0000000.00000000NaNNaN2521112NaN0
......................................................................................................................................................
254004259.166.0.812520149.171.126.631010tcpFIN0.0203833201874312912-1.047932e+056.436736e+0568255255320868647932254861685323400212.8107293.079195142195584214219558424.0074002.0274290.0063860.0061890.000197000.00.0082075114NaN0
254004359.166.0.018895149.171.126.980tcpFIN1.40295719410108789031292370http1.103783e+056.195098e+06364746255255283296697242973675453145813924203.808900114.173588142195584114219558423.8640281.8824210.0007120.0005500.000162004.00.001127222NaN0
254004459.166.0.030103149.171.126.55190tcpFIN0.00710821582464312966-2.328644e+062.658413e+0624242552557032938442848960529901030017.6278310.432619142195584214219558420.2742610.2854780.0006570.0005320.000125000.00.00131367212NaN0
254004559.166.0.630388149.171.126.5111udpCON0.004435568304312900-7.684329e+054.112740e+0544000014276001.6386041.390643142195584214219558421.1656670.9873330.0000000.0000000.000000000.00.00101365113NaN0
254004659.166.0.06055149.171.126.554145tcpFIN0.0729744238607883129730-4.582454e+056.571546e+06727225525510032931491003585034598440062.04531061.899776142195584214219558421.0226900.9970420.0023170.0021730.000144000.00.00131367112NaN0
\n", "

2540047 rows × 49 columns

\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 5 } ] }, { "cell_type": "code", "source": [ "frame.srcip = frame.srcip.astype('category').cat.codes\n", "frame.dstip = frame.dstip.astype('category').cat.codes\n", "frame.proto = frame.proto.astype('category').cat.codes\n", "frame.state = frame.state.astype('category').cat.codes\n", "frame.service = frame.service.astype('category').cat.codes\n", "frame.ct_flw_http_mthd = frame.ct_flw_http_mthd.astype('category').cat.codes\n", "frame.is_ftp_login = frame.is_ftp_login.astype('category').cat.codes\n", "frame.ct_ftp_cmd = frame.ct_ftp_cmd.astype('category').cat.codes\n", "frame['Label'] = frame['Label'].astype(str)\n", "frame['Label'] = frame['Label'].str.replace(\"1\", \"anomaly\")\n", "frame['Label'] = frame['Label'].str.replace(\"0\", \"normal\")\n", "frame = frame.drop('attack_cat', axis=1)\n", "frame" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 461 }, "id": "Itl2LFrGfVmY", "outputId": "758bbcde-5712-4734-a070-e7c5d7eefdd5" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " srcip sport dstip dsport proto state dur sbytes dbytes \\\n", "0 42 7045 25 25 114 5 0.201886 37552 3380 \n", "1 42 9685 20 80 114 5 5.864748 19410 1087890 \n", "2 35 1421 22 53 120 2 0.001391 146 178 \n", "3 35 21553 20 25 114 5 0.053948 37812 3380 \n", "4 41 45212 22 53 120 2 0.000953 146 178 \n", "... ... ... ... ... ... ... ... ... ... \n", "2540042 41 12520 24 31010 114 5 0.020383 320 1874 \n", "2540043 33 18895 27 80 114 5 1.402957 19410 1087890 \n", "2540044 33 30103 23 5190 114 5 0.007108 2158 2464 \n", "2540045 39 30388 23 111 120 2 0.004435 568 304 \n", "2540046 33 6055 23 54145 114 5 0.072974 4238 60788 \n", "\n", " sttl dttl sloss dloss service Sload Dload Spkts \\\n", "0 31 29 18 8 9 1.459438e+06 1.307669e+05 52 \n", "1 31 29 2 370 5 2.640454e+04 1.481983e+06 364 \n", "2 31 29 0 0 2 4.198418e+05 5.118620e+05 2 \n", "3 31 29 19 8 9 5.503374e+06 4.893601e+05 54 \n", "4 31 29 0 0 2 6.128017e+05 7.471144e+05 2 \n", "... ... ... ... ... ... ... ... ... \n", "2540042 31 29 1 2 0 1.047932e+05 6.436736e+05 6 \n", "2540043 31 29 2 370 5 1.103783e+05 6.195098e+06 364 \n", "2540044 31 29 6 6 0 2.328644e+06 2.658413e+06 24 \n", "2540045 31 29 0 0 0 7.684329e+05 4.112740e+05 4 \n", "2540046 31 29 7 30 0 4.582454e+05 6.571546e+06 72 \n", "\n", " Dpkts swin dwin stcpb dtcpb smeansz dmeansz \\\n", "0 42 255 255 1422136554 3572668484 722 80 \n", "1 746 255 255 389619597 394688654 53 1458 \n", "2 2 0 0 0 0 73 89 \n", "3 42 255 255 4047523379 1903327524 700 80 \n", "4 2 0 0 0 0 73 89 \n", "... ... ... ... ... ... ... ... \n", "2540042 8 255 255 3208686479 3225486168 53 234 \n", "2540043 746 255 255 283296697 2429736754 53 1458 \n", "2540044 24 255 255 703293844 2848960529 90 103 \n", "2540045 4 0 0 0 0 142 76 \n", "2540046 72 255 255 1003293149 1003585034 59 844 \n", "\n", " trans_depth res_bdy_len Sjit Djit Stime \\\n", "0 0 0 456.043567 15.530109 1424250009 \n", "1 1 0 1031.366423 690.219581 1424250003 \n", "2 0 0 0.000000 0.000000 1424250009 \n", "3 0 0 65.909688 3.155258 1424250009 \n", "4 0 0 0.000000 0.000000 1424250009 \n", "... ... ... ... ... ... \n", "2540042 0 0 212.810729 3.079195 1421955842 \n", "2540043 1 3924 203.808900 114.173588 1421955841 \n", "2540044 0 0 17.627831 0.432619 1421955842 \n", "2540045 0 0 1.638604 1.390643 1421955842 \n", "2540046 0 0 62.045310 61.899776 1421955842 \n", "\n", " Ltime Sintpkt Dintpkt tcprtt synack ackdat \\\n", "0 1424250009 3.943843 4.912488 0.000590 0.000473 0.000117 \n", "1 1424250009 16.155447 7.871279 0.000771 0.000638 0.000133 \n", "2 1424250009 0.009000 0.002000 0.000000 0.000000 0.000000 \n", "3 1424250009 1.011547 1.302561 0.000674 0.000540 0.000134 \n", "4 1424250009 0.009000 0.004000 0.000000 0.000000 0.000000 \n", "... ... ... ... ... ... ... \n", "2540042 1421955842 4.007400 2.027429 0.006386 0.006189 0.000197 \n", "2540043 1421955842 3.864028 1.882421 0.000712 0.000550 0.000162 \n", "2540044 1421955842 0.274261 0.285478 0.000657 0.000532 0.000125 \n", "2540045 1421955842 1.165667 0.987333 0.000000 0.000000 0.000000 \n", "2540046 1421955842 1.022690 0.997042 0.002317 0.002173 0.000144 \n", "\n", " is_sm_ips_ports ct_state_ttl ct_flw_http_mthd is_ftp_login \\\n", "0 0 0 -1 -1 \n", "1 0 0 1 -1 \n", "2 0 0 -1 -1 \n", "3 0 0 -1 -1 \n", "4 0 0 -1 -1 \n", "... ... ... ... ... \n", "2540042 0 0 0 0 \n", "2540043 0 0 4 0 \n", "2540044 0 0 0 0 \n", "2540045 0 0 0 0 \n", "2540046 0 0 0 0 \n", "\n", " ct_ftp_cmd ct_srv_src ct_srv_dst ct_dst_ltm ct_src_ ltm \\\n", "0 8 2 2 7 4 \n", "1 8 3 1 4 4 \n", "2 8 3 5 2 7 \n", "3 8 1 1 4 7 \n", "4 8 2 5 2 1 \n", "... ... ... ... ... ... \n", "2540042 0 8 20 7 5 \n", "2540043 0 1 1 2 7 \n", "2540044 0 13 13 6 7 \n", "2540045 0 10 13 6 5 \n", "2540046 0 13 13 6 7 \n", "\n", " ct_src_dport_ltm ct_dst_sport_ltm ct_dst_src_ltm Label \n", "0 1 1 3 normal \n", "1 1 1 1 normal \n", "2 1 1 4 normal \n", "3 1 1 3 normal \n", "4 1 1 2 normal \n", "... ... ... ... ... \n", "2540042 1 1 4 normal \n", "2540043 2 2 2 normal \n", "2540044 2 1 2 normal \n", "2540045 1 1 3 normal \n", "2540046 1 1 2 normal \n", "\n", "[2540047 rows x 48 columns]" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
srcipsportdstipdsportprotostatedursbytesdbytessttldttlslossdlossserviceSloadDloadSpktsDpktsswindwinstcpbdtcpbsmeanszdmeansztrans_depthres_bdy_lenSjitDjitStimeLtimeSintpktDintpkttcprttsynackackdatis_sm_ips_portsct_state_ttlct_flw_http_mthdis_ftp_loginct_ftp_cmdct_srv_srcct_srv_dstct_dst_ltmct_src_ ltmct_src_dport_ltmct_dst_sport_ltmct_dst_src_ltmLabel
0427045252511450.201886375523380312918891.459438e+061.307669e+055242255255142213655435726684847228000456.04356715.530109142425000914242500093.9438434.9124880.0005900.0004730.00011700-1-182274113normal
1429685208011455.8647481941010878903129237052.640454e+041.481983e+06364746255255389619597394688654531458101031.366423690.2195811424250003142425000916.1554477.8712790.0007710.0006380.000133001-183144111normal
2351421225312020.00139114617831290024.198418e+055.118620e+052200007389000.0000000.000000142425000914242500090.0090000.0020000.0000000.0000000.00000000-1-183527114normal
33521553202511450.053948378123380312919895.503374e+064.893601e+05544225525540475233791903327524700800065.9096883.155258142425000914242500091.0115471.3025610.0006740.0005400.00013400-1-181147113normal
44145212225312020.00095314617831290026.128017e+057.471144e+052200007389000.0000000.000000142425000914242500090.0090000.0040000.0000000.0000000.00000000-1-182521112normal
...................................................................................................................................................
25400424112520243101011450.020383320187431291201.047932e+056.436736e+0568255255320868647932254861685323400212.8107293.079195142195584214219558424.0074002.0274290.0063860.0061890.0001970000082075114normal
25400433318895278011451.4029571941010878903129237051.103783e+056.195098e+06364746255255283296697242973675453145813924203.808900114.173588142195584114219558423.8640281.8824210.0007120.0005500.000162004001127222normal
2540044333010323519011450.0071082158246431296602.328644e+062.658413e+0624242552557032938442848960529901030017.6278310.432619142195584214219558420.2742610.2854780.0006570.0005320.00012500000131367212normal
254004539303882311112020.00443556830431290007.684329e+054.112740e+0544000014276001.6386041.390643142195584214219558421.1656670.9873330.0000000.0000000.00000000000101365113normal
2540046336055235414511450.072974423860788312973004.582454e+056.571546e+06727225525510032931491003585034598440062.04531061.899776142195584214219558421.0226900.9970420.0023170.0021730.00014400000131367112normal
\n", "

2540047 rows × 48 columns

\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 6 } ] }, { "cell_type": "code", "source": [ "column_headers = list(frame.columns.values)\n", "column_headers" ], "metadata": { "id": "HBU4liaUFAJk", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "49430254-abd1-4f33-cec5-14d453fd7e89" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['srcip',\n", " 'sport',\n", " 'dstip',\n", " 'dsport',\n", " 'proto',\n", " 'state',\n", " 'dur',\n", " 'sbytes',\n", " 'dbytes',\n", " 'sttl',\n", " 'dttl',\n", " 'sloss',\n", " 'dloss',\n", " 'service',\n", " 'Sload',\n", " 'Dload',\n", " 'Spkts',\n", " 'Dpkts',\n", " 'swin',\n", " 'dwin',\n", " 'stcpb',\n", " 'dtcpb',\n", " 'smeansz',\n", " 'dmeansz',\n", " 'trans_depth',\n", " 'res_bdy_len',\n", " 'Sjit',\n", " 'Djit',\n", " 'Stime',\n", " 'Ltime',\n", " 'Sintpkt',\n", " 'Dintpkt',\n", " 'tcprtt',\n", " 'synack',\n", " 'ackdat',\n", " 'is_sm_ips_ports',\n", " 'ct_state_ttl',\n", " 'ct_flw_http_mthd',\n", " 'is_ftp_login',\n", " 'ct_ftp_cmd',\n", " 'ct_srv_src',\n", " 'ct_srv_dst',\n", " 'ct_dst_ltm',\n", " 'ct_src_ ltm',\n", " 'ct_src_dport_ltm',\n", " 'ct_dst_sport_ltm',\n", " 'ct_dst_src_ltm',\n", " 'Label']" ] }, "metadata": {}, "execution_count": 7 } ] }, { "cell_type": "code", "source": [ "CSV_HEADER = column_headers" ], "metadata": { "id": "C_Ip5YuJFAJk" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "df = frame" ], "metadata": { "id": "zIimPNGpFAJk" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "def Remove_Outlier_Indices(df):\n", " Q1 = df.quantile(0.02)\n", " Q3 = df.quantile(0.98)\n", " IQR = Q3 - Q1\n", " #trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR)))\n", " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR))).any(axis=1)\n", " return trueList\n", "\n", "nonOutlierList = Remove_Outlier_Indices(df)\n", "new_data = df[nonOutlierList]\n", "\n" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "cf0b98a2-b125-4549-be98-3660c104a082", "id": "CSOxAQvDFAJl" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ ":2: FutureWarning: The default value of numeric_only in DataFrame.quantile is deprecated. In a future version, it will default to False. Select only valid columns or specify the value of numeric_only to silence this warning.\n", " Q1 = df.quantile(0.02)\n", ":3: FutureWarning: The default value of numeric_only in DataFrame.quantile is deprecated. In a future version, it will default to False. Select only valid columns or specify the value of numeric_only to silence this warning.\n", " Q3 = df.quantile(0.98)\n", ":6: FutureWarning: Automatic reindexing on DataFrame vs Series comparisons is deprecated and will raise ValueError in a future version. Do `left, right = left.align(right, axis=1, copy=False)` before e.g. `left == right`\n", " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR))).any(axis=1)\n" ] } ] }, { "cell_type": "code", "source": [ "df = new_data\n", "df = df.reset_index(drop=True)\n", "del new_data\n", "del nonOutlierList\n", "del li\n", "del frame" ], "metadata": { "id": "HDj30IAFFAJl" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "import gc\n", "gc.collect()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "sbG0z0rpkHyA", "outputId": "2a5f4d0b-b992-465b-ab80-9d5e95eeb4ad" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "31" ] }, "metadata": {}, "execution_count": 12 } ] }, { "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.decomposition import PCA\n", "n_components = 10\n", "columns = []\n", "for x in range(n_components):\n", " columns.append(str(x+1))\n", "\n", "X = df.drop(['Label'], axis=1).values\n", "y = df[\"Label\"].values\n", "x_scaled = StandardScaler().fit_transform(X)\n", "\n", "pca = PCA(n_components)\n", "\n", "# Fit and transform data\n", "principalComponents = pca.fit_transform(x_scaled)\n", "\n", "principalDf = pd.DataFrame(data = principalComponents\n", " , columns = columns)\n", "finalDf = pd.concat([principalDf, df[\"Label\"]], axis = 1)\n" ], "metadata": { "id": "f2NXLHjjFAJl" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "model = pca\n", "X_pc = principalComponents\n", "\n", "# number of components\n", "n_pcs= model.components_.shape[0]\n", "\n", "# get the index of the most important feature on EACH component\n", "# LIST COMPREHENSION HERE\n", "most_important = [np.abs(model.components_[i]).argmax() for i in range(n_pcs)]\n", "\n", "initial_feature_names = CSV_HEADER\n", "# get the names\n", "most_important_names = [initial_feature_names[most_important[i]] for i in range(n_pcs)]\n", "\n", "# LIST COMPREHENSION HERE AGAIN\n", "dic = {'PC{}'.format(i): most_important_names[i] for i in range(n_pcs)}\n", "\n", "# build the dataframe\n", "dfx = pd.DataFrame(dic.items())\n", "dfx" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 363 }, "outputId": "3e4cae10-de94-4634-f748-49e8f3613266", "id": "BPBMVK7JFAJl" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " 0 1\n", "0 PC0 ct_dst_src_ltm\n", "1 PC1 Sintpkt\n", "2 PC2 Spkts\n", "3 PC3 tcprtt\n", "4 PC4 dbytes\n", "5 PC5 Ltime\n", "6 PC6 smeansz\n", "7 PC7 dstip\n", "8 PC8 sport\n", "9 PC9 trans_depth" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
01
0PC0ct_dst_src_ltm
1PC1Sintpkt
2PC2Spkts
3PC3tcprtt
4PC4dbytes
5PC5Ltime
6PC6smeansz
7PC7dstip
8PC8sport
9PC9trans_depth
\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "
\n", "
\n" ] }, "metadata": {}, "execution_count": 14 } ] }, { "cell_type": "code", "source": [ "from sklearn.model_selection import train_test_split\n", "train_data, test_data = train_test_split(finalDf, test_size=0.25)\n", "train_data_file = \"train_data.csv\"\n", "test_data_file = \"test_data.csv\"\n", "\n", "train_data.to_csv(train_data_file, index=False, header=False)\n", "test_data.to_csv(test_data_file, index=False, header=False)" ], "metadata": { "id": "AKxpbbLDFAJm" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "del finalDf\n", "del principalDf\n", "del train_data\n", "del test_data" ], "metadata": { "id": "L9qPLpF6FAJm" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "gc.collect()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "3IslsX9SkfSu", "outputId": "c2868f98-fbe4-4949-960e-00bc74e8efeb" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "0" ] }, "metadata": {}, "execution_count": 17 } ] }, { "cell_type": "code", "source": [ "CSV_HEADER = []\n", "for x in columns:\n", " CSV_HEADER.append(x)\n", "CSV_HEADER.append(\"Label\")\n", "\n", "# A list of the numerical feature names.\n", "NUMERIC_FEATURE_NAMES = columns\n", "# A dictionary of the categorical features and their vocabulary.\n", "CATEGORICAL_FEATURES_WITH_VOCABULARY = {\n", "}\n", "# A list of the columns to ignore from the dataset.\n", "IGNORE_COLUMN_NAMES = []\n", "# A list of the categorical feature names.\n", "CATEGORICAL_FEATURE_NAMES = list(CATEGORICAL_FEATURES_WITH_VOCABULARY.keys())\n", "# A list of all the input features.\n", "FEATURE_NAMES = NUMERIC_FEATURE_NAMES + CATEGORICAL_FEATURE_NAMES\n", "# A list of column default values for each feature.\n", "COLUMN_DEFAULTS = [\n", " [0.0] if feature_name in NUMERIC_FEATURE_NAMES + IGNORE_COLUMN_NAMES else [\"NA\"]\n", " for feature_name in CSV_HEADER\n", "]\n", "# The name of the target feature.\n", "TARGET_FEATURE_NAME = \"Label\"\n", "# A list of the labels of the target features.\n", "TARGET_LABELS = [\"normal\", \"anomaly\"]\n", "\n", "from tensorflow.keras.layers import StringLookup\n", "\n", "target_label_lookup = StringLookup(\n", " vocabulary=TARGET_LABELS, mask_token=None, num_oov_indices=0\n", ")\n", "\n", "\n", "def get_dataset_from_csv(csv_file_path, shuffle=False, batch_size=128):\n", " dataset = tf.data.experimental.make_csv_dataset(\n", " csv_file_path,\n", " batch_size=batch_size,\n", " column_names=CSV_HEADER,\n", " column_defaults=COLUMN_DEFAULTS,\n", " label_name=TARGET_FEATURE_NAME,\n", " num_epochs=1,\n", " header=False,\n", " na_value=\"?\",\n", " shuffle=shuffle,\n", " ).map(lambda features, target: (features, target_label_lookup(target)))\n", " return dataset.cache()\n", "\n", "def create_model_inputs():\n", " inputs = {}\n", " for feature_name in FEATURE_NAMES:\n", " if feature_name in NUMERIC_FEATURE_NAMES:\n", " inputs[feature_name] = layers.Input(\n", " name=feature_name, shape=(), dtype=tf.float32\n", " )\n", " else:\n", " inputs[feature_name] = layers.Input(\n", " name=feature_name, shape=(), dtype=tf.string\n", " )\n", " return inputs\n", "\n", "def encode_inputs(inputs):\n", " encoded_features = []\n", " for feature_name in inputs:\n", " if feature_name in CATEGORICAL_FEATURE_NAMES:\n", " vocabulary = CATEGORICAL_FEATURES_WITH_VOCABULARY[feature_name]\n", " #print(vocabulary)\n", " # Create a lookup to convert a string values to an integer indices.\n", " # Since we are not using a mask token, nor expecting any out of vocabulary\n", " # (oov) token, we set mask_token to None and num_oov_indices to 0.\n", " lookup = StringLookup(\n", " vocabulary=vocabulary, mask_token=None, num_oov_indices=0\n", " )\n", " # Convert the string input values into integer indices.\n", " value_index = lookup(inputs[feature_name])\n", " embedding_dims = int(math.sqrt(lookup.vocabulary_size()))\n", " # Create an embedding layer with the specified dimensions.\n", " embedding = layers.Embedding(\n", " input_dim=lookup.vocabulary_size(), output_dim=embedding_dims\n", " )\n", " # Convert the index values to embedding representations.\n", " encoded_feature = embedding(value_index)\n", " else:\n", " # Use the numerical features as-is.\n", " encoded_feature = inputs[feature_name]\n", " if inputs[feature_name].shape[-1] is None:\n", " encoded_feature = tf.expand_dims(encoded_feature, -1)\n", "\n", " encoded_features.append(encoded_feature)\n", "\n", " encoded_features = layers.concatenate(encoded_features)\n", " return encoded_features\n", "\n", "class NeuralDecisionTree(keras.Model):\n", " def __init__(self, depth, num_features, used_features_rate, num_classes):\n", " super().__init__()\n", " self.depth = depth\n", " self.num_leaves = 2 ** depth\n", " self.num_classes = num_classes\n", "\n", " # Create a mask for the randomly selected features.\n", " num_used_features = int(num_features * used_features_rate)\n", " one_hot = np.eye(num_features)\n", " sampled_feature_indicies = np.random.choice(\n", " np.arange(num_features), num_used_features, replace=False\n", " )\n", " self.used_features_mask = one_hot[sampled_feature_indicies]\n", "\n", " # Initialize the weights of the classes in leaves.\n", " self.pi = tf.Variable(\n", " initial_value=tf.random_normal_initializer()(\n", " shape=[self.num_leaves, self.num_classes]\n", " ),\n", " dtype=\"float32\",\n", " trainable=True,\n", " )\n", "\n", " # Initialize the stochastic routing layer.\n", " self.decision_fn = layers.Dense(\n", " units=self.num_leaves, activation=\"sigmoid\", name=\"decision\"\n", " )\n", "\n", " def call(self, features):\n", " batch_size = tf.shape(features)[0]\n", "\n", " # Apply the feature mask to the input features.\n", " features = tf.matmul(\n", " features, self.used_features_mask, transpose_b=True\n", " ) # [batch_size, num_used_features]\n", " # Compute the routing probabilities.\n", " decisions = tf.expand_dims(\n", " self.decision_fn(features), axis=2\n", " ) # [batch_size, num_leaves, 1]\n", " # Concatenate the routing probabilities with their complements.\n", " decisions = layers.concatenate(\n", " [decisions, 1 - decisions], axis=2\n", " ) # [batch_size, num_leaves, 2]\n", "\n", " mu = tf.ones([batch_size, 1, 1])\n", "\n", " begin_idx = 1\n", " end_idx = 2\n", " # Traverse the tree in breadth-first order.\n", " for level in range(self.depth):\n", " mu = tf.reshape(mu, [batch_size, -1, 1]) # [batch_size, 2 ** level, 1]\n", " mu = tf.tile(mu, (1, 1, 2)) # [batch_size, 2 ** level, 2]\n", " level_decisions = decisions[\n", " :, begin_idx:end_idx, :\n", " ] # [batch_size, 2 ** level, 2]\n", " mu = mu * level_decisions # [batch_size, 2**level, 2]\n", " begin_idx = end_idx\n", " end_idx = begin_idx + 2 ** (level + 1)\n", "\n", " mu = tf.reshape(mu, [batch_size, self.num_leaves]) # [batch_size, num_leaves]\n", " probabilities = keras.activations.softmax(self.pi) # [num_leaves, num_classes]\n", " outputs = tf.matmul(mu, probabilities) # [batch_size, num_classes]\n", " return outputs\n", "\n", "class NeuralDecisionForest(keras.Model):\n", " def __init__(self, num_trees, depth, num_features, used_features_rate, num_classes):\n", " super().__init__()\n", " self.ensemble = []\n", " # Initialize the ensemble by adding NeuralDecisionTree instances.\n", " # Each tree will have its own randomly selected input features to use.\n", " for _ in range(num_trees):\n", " self.ensemble.append(\n", " NeuralDecisionTree(depth, num_features, used_features_rate, num_classes)\n", " )\n", "\n", " def call(self, inputs):\n", " # Initialize the outputs: a [batch_size, num_classes] matrix of zeros.\n", " batch_size = tf.shape(inputs)[0]\n", " outputs = tf.zeros([batch_size, num_classes])\n", "\n", " # Aggregate the outputs of trees in the ensemble.\n", " for tree in self.ensemble:\n", " outputs += tree(inputs)\n", " # Divide the outputs by the ensemble size to get the average.\n", " outputs /= len(self.ensemble)\n", " return outputs\n", "learning_rate = 0.01\n", "batch_size = 128\n", "num_epochs = 10\n", "\n", "\n", "def run_experiment(model):\n", "\n", " # model.compile(\n", " # optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", " # loss=keras.losses.SparseCategoricalCrossentropy(),\n", " # metrics=[keras.metrics.SparseCategoricalAccuracy()],\n", " # )\n", " model.compile(\n", " optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", " loss=keras.losses.SparseCategoricalCrossentropy(),\n", " metrics=[metrics.SparseCategoricalAccuracy()],\n", " )\n", " print(\"Start training the model...\")\n", " train_dataset = get_dataset_from_csv(\n", " train_data_file, shuffle=True, batch_size=batch_size\n", " )\n", "\n", " model.fit(train_dataset, epochs=num_epochs)\n", " print(\"Model training finished\")\n", "\n", " print(\"Evaluating the model on the test data...\")\n", " test_dataset = get_dataset_from_csv(test_data_file, batch_size=batch_size)\n", "\n", " _, accuracy = model.evaluate(test_dataset)\n", " print(f\"Test accuracy: {round(accuracy * 100, 2)}%\")\n", " return model" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "08677cf6-ca87-4167-e052-7ff369682416", "id": "1_26_8h7FAJm" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.10/dist-packages/numpy/core/numeric.py:2463: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison\n", " return bool(asarray(a1 == a2).all())\n" ] } ] }, { "cell_type": "code", "source": [ "num_trees = 25\n", "depth = 5\n", "used_features_rate = 0.5\n", "num_classes = len(TARGET_LABELS)\n", "\n", "\n", "def create_forest_model():\n", " inputs = create_model_inputs()\n", " features = encode_inputs(inputs)\n", " features = layers.BatchNormalization()(features)\n", " num_features = features.shape[1]\n", "\n", " forest_model = NeuralDecisionForest(\n", " num_trees, depth, num_features, used_features_rate, num_classes\n", " )\n", "\n", " outputs = forest_model(features)\n", " model = keras.Model(inputs=inputs, outputs=outputs)\n", " return model\n", "\n", "\n", "forest_model = create_forest_model()\n", "\n", "finalModel = run_experiment(forest_model)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "9c964e00-9015-4791-e8d0-916e62c7afe6", "id": "IybH5is1FAJn" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Start training the model...\n", "Epoch 1/10\n", "14290/14290 [==============================] - 435s 29ms/step - loss: 0.0348 - sparse_categorical_accuracy: 0.9868\n", "Epoch 2/10\n", "14290/14290 [==============================] - 350s 24ms/step - loss: 0.0289 - sparse_categorical_accuracy: 0.9887\n", "Epoch 3/10\n", "14290/14290 [==============================] - 351s 25ms/step - loss: 0.0273 - sparse_categorical_accuracy: 0.9890\n", "Epoch 4/10\n", "14290/14290 [==============================] - 353s 25ms/step - loss: 0.0251 - sparse_categorical_accuracy: 0.9890\n", "Epoch 5/10\n", "14290/14290 [==============================] - 352s 25ms/step - loss: 0.0248 - sparse_categorical_accuracy: 0.9890\n", "Epoch 6/10\n", "14290/14290 [==============================] - 360s 25ms/step - loss: 0.0246 - sparse_categorical_accuracy: 0.9891\n", "Epoch 7/10\n", "14290/14290 [==============================] - 354s 25ms/step - loss: 0.0244 - sparse_categorical_accuracy: 0.9890\n", "Epoch 8/10\n", "14290/14290 [==============================] - 370s 26ms/step - loss: 0.0243 - sparse_categorical_accuracy: 0.9891\n", "Epoch 9/10\n", "14290/14290 [==============================] - 360s 25ms/step - loss: 0.0242 - sparse_categorical_accuracy: 0.9892\n", "Epoch 10/10\n", "14290/14290 [==============================] - 356s 25ms/step - loss: 0.0241 - sparse_categorical_accuracy: 0.9892\n", "Model training finished\n", "Evaluating the model on the test data...\n", "4764/4764 [==============================] - 59s 12ms/step - loss: 0.0223 - sparse_categorical_accuracy: 0.9893\n", "Test accuracy: 98.93%\n" ] } ] }, { "cell_type": "code", "source": [ "test_dataset = get_dataset_from_csv(test_data_file, batch_size=batch_size)\n", "colnames=['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'target']\n", "data = pd.read_csv(\"test_data.csv\", names=colnames, header=None)\n", "data['target'].replace('normal', 0,inplace=True)\n", "data['target'].replace('anomaly', 1,inplace=True)\n", "y_test = data['target'].values # as a numpy array\n", "from sklearn.metrics import confusion_matrix\n", "y_prediction = finalModel.predict(test_dataset)\n", "y_prediction = np.argmax (y_prediction, axis = 1)\n", "result = confusion_matrix(y_test, y_prediction , normalize='pred')\n", "print(result)\n", "TP = result[0][0]\n", "FP = result[0][1]\n", "TN = result[1][1]\n", "FN = result[1][0]\n", "ACC = (TP+TN)/(TP+TN+FP+FN)\n", "PR = TP/(TP+FP) #precision\n", "TPR = TP/(TP+FN) #Recall or True positive rate\n", "FPR = FP/(FP+TN)\n", "F1Score = 2*(PR*TPR)/(PR+TPR)\n", "print(\"ACC: \" + str(ACC))\n", "print(\"PR: \" + str(PR))\n", "print(\"TPR: \" + str(TPR))\n", "print(\"FPR: \" + str(FPR))\n", "print(\"F1Score: \" + str(F1Score))\n", "import matplotlib.pyplot as plt\n", "import numpy\n", "from sklearn import metrics\n", "\n", "\n", "cm_display = metrics.ConfusionMatrixDisplay(confusion_matrix = result, display_labels = [True, False])\n", "\n", "cm_display.plot()\n", "plt.show()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 588 }, "outputId": "f6abffa5-93ff-464b-ce93-18dde70585fd", "id": "pPffXGpiFAJo" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "4764/4764 [==============================] - 56s 11ms/step\n", "[[0.9963139 0.05992979]\n", " [0.0036861 0.94007021]]\n", "ACC: 0.9681920531916617\n", "PR: 0.9432613986597967\n", "TPR: 0.9963138957514277\n", "FPR: 0.059929789368104315\n", "F1Score: 0.9690620843837493\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/png": "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lMPhuOw2duzYsg4RuCK9e/f2+jO9a9eusg4NKBXciRIl6vDhw+4/z58/X6NHj9b27dvd+yIjI91/Nk1TLpdLFSrwYwn/0LlzZ82cOdNjX2xsbBlFA5QuKhAoUfHx8e4tJiZGDofD/Xrbtm2KiorSp59+quTkZDmdTqWnp6t3797q2rWrx3GeeOIJ3XLLLe7XhmEoLS1NderUUVhYmJo1a6aFCxeW7odDwHM6nR4/4/Hx8XrttdfUpEkTRUREKDExUQMGDFBOTk6Rx9i0aZPat2+vqKgoRUdHKzk5WevXr3e/n56errZt2yosLEyJiYkaOHCgzp49WxofD7gsEgiUuZEjR+q5557T1q1b1bRp02LNSUtL05w5czR16lRt3rxZgwcP1oMPPqhVq1aVcLTA5QUFBWny5MnavHmzZs+erRUrVmj48OFFju/Ro4dq1qypr776ShkZGRo5cqQqVqwoSdq9e7c6d+6se+65R998843mz5+v9PR0paamltbHAYpErRhl7plnnlGHDh2KPT4vL08TJ07UsmXL1KZNG0lS3bp1lZ6errfeekvt2rUrqVABD4sWLfJow912223617/+5X5du3ZtPfvss3rkkUf05ptvej1GZmamhg0bpgYNGkiSrr/+evd7aWlp6tGjh5544gn3e5MnT1a7du00ZcqUgHloE8onEgiUuVatWlkav2vXLp07d+6SpCM/P18tWrSwMzTgstq3b68pU6a4X0dERGjZsmVKS0vTtm3blJ2drcLCQuXm5urcuXMKDw+/5BhDhgxRv3799M477yglJUX33XefrrvuOknn2xvffPON5s6d6x5vmqYMw9DevXvVsGHDkv+QQBFIIFDmIiIiPF4HBQXpl3dYLygocP/5Qj958eLFqlGjhsc4ni2A0hQREaGkpCT363379ukPf/iDHn30UU2YMEFVqlRRenq6+vbtq/z8fK8JxNixY/XAAw9o8eLF+vTTTzVmzBjNmzdPd911l3JycvTnP/9ZAwcOvGTetddeW6KfDfg1JBAod2JjY/Xdd9957Nu4caO7L9yoUSM5nU5lZmbSrkC5kpGRIcMw9PLLLyso6PwSswULFvzqvHr16qlevXoaPHiwunfvrpkzZ+quu+5Sy5YttWXLFo8kBSgvWESJcufWW2/V+vXrNWfOHO3cuVNjxozxSCiioqI0dOhQDR48WLNnz9bu3bu1YcMGvf7665o9e3YZRo5Al5SUpIKCAr3++uvas2eP3nnnHU2dOrXI8T/++KNSU1O1cuVKff/991qzZo2++uord2tixIgRWrt2rVJTU7Vx40bt3LlT//73v1lEiXKBBALlTqdOnTRq1CgNHz5cv/nNb3TmzBn17NnTY8z48eM1atQopaWlqWHDhurcubMWL16sOnXqlFHUgNSsWTNNmjRJzz//vBo3bqy5c+cqLS2tyPHBwcH64Ycf1LNnT9WrV0/dunXTbbfdpnHjxkmSmjZtqlWrVmnHjh1q27atWrRoodGjRyshIaG0PhJQJB7nDQAALKMCAQAALCOBAAAAlpFAAAAAy0ggAACAZSQQAADAMhIIAABgGQkEAACwjAQCAABYRgIB+InevXura9eu7te33HKL+zHPpWnlypVyOBw6depUkWMcDoc+/PDDYh9z7Nixat68uU9x7du3Tw6HQxs3bvTpOACKhwQC8EHv3r3lcDjkcDgUEhKipKQkPfPMMyosLCzxc7///vsaP358scYW50sfAKzgaZyAjzp37qyZM2cqLy9Pn3zyiR577DFVrFhRTz311CVj8/PzFRISYst5q1SpYstxAOBKUIEAfOR0OhUfH69atWrp0UcfVUpKij766CNJF9sOEyZMUEJCgurXry9J2r9/v7p166ZKlSqpSpUquvPOO7Vv3z73MV0ul4YMGaJKlSrpmmuu0fDhw/XLx9b8soWRl5enESNGKDExUU6nU0lJSXr77be1b98+tW/fXpJUuXJlORwO9e7dW5JkGIbS0tJUp04dhYWFqVmzZlq4cKHHeT755BPVq1dPYWFhat++vUecxTVixAjVq1dP4eHhqlu3rkaNGqWCgoJLxr311ltKTExUeHi4unXrptOnT3u8P336dDVs2FChoaFq0KCB3nzzTcuxALAHCQRgs7CwMOXn57tfL1++XNu3b9fSpUu1aNEiFRQUqFOnToqKitLq1au1Zs0aRUZGqnPnzu55L7/8smbNmqUZM2YoPT1dWVlZ+uCDDy573p49e+qf//ynJk+erK1bt+qtt95SZGSkEhMT9d5770mStm/frsOHD+u1116TJKWlpWnOnDmaOnWqNm/erMGDB+vBBx/UqlWrJJ1PdO6++2516dJFGzduVL9+/TRy5EjLfydRUVGaNWuWtmzZotdee03Tpk3TK6+84jFm165dWrBggT7++GMtWbJEX3/9tQYMGOB+f+7cuRo9erQmTJigrVu3auLEiRo1ahSPcAfKigngivXq1cu88847TdM0TcMwzKVLl5pOp9McOnSo+/24uDgzLy/PPeedd94x69evbxqG4d6Xl5dnhoWFmZ999plpmqZZvXp184UXXnC/X1BQYNasWdN9LtM0zXbt2pmDBg0yTdM0t2/fbkoyly5d6jXOzz//3JRknjx50r0vNzfXDA8PN9euXesxtm/fvmb37t1N0zTNp556ymzUqJHH+yNGjLjkWL8kyfzggw+KfP/FF180k5OT3a/HjBljBgcHmwcOHHDv+/TTT82goCDz8OHDpmma5nXXXWe+++67HscZP3682aZNG9M0TXPv3r2mJPPrr78u8rwA7MMaCMBHixYtUmRkpAoKCmQYhh544AGNHTvW/X6TJk081j1s2rRJu3btUlRUlMdxcnNztXv3bp0+fVqHDx9W69at3e9VqFBBrVq1uqSNccHGjRsVHBysdu3aFTvuXbt26dy5c+rQoYPH/vz8fLVo0UKStHXrVo84JKlNmzbFPscF8+fP1+TJk7V7927l5OSosLBQ0dHRHmOuvfZa1ahRw+M8hmFo+/btioqK0u7du9W3b1/179/fPaawsFAxMTGW4wHgOxIIwEft27fXlClTFBISooSEBFWo4Pm/VUREhMfrnJwcJScna+7cuZccKzY29opiCAsLszwnJydHkrR48WKPL27p/LoOu6xbt049evTQuHHj1KlTJ8XExGjevHl6+eWXLcc6bdq0SxKa4OBg22IFUHwkEICPIiIilJSUVOzxLVu21Pz581WtWrVLfgu/oHr16vrvf/+rm2++WdL537QzMjLUsmVLr+ObNGkiwzC0atUqpaSkXPL+hQqIy+Vy72vUqJGcTqcyMzOLrFw0bNjQvSD0gv/85z+//iF/Zu3atapVq5aefvpp977vv//+knGZmZk6dOiQEhIS3OcJCgpS/fr1FRcXp4SEBO3Zs0c9evSwdH4AJYNFlEAp69Gjh6pWrao777xTq1ev1t69e7Vy5UoNHDhQBw4ckCQNGjRIzz33nD788ENt27ZNAwYMuOw9HGrXrq1evXrp4Ycf1ocffug+5oIFCyRJtWrVksPh0KJFi3T8+HHl5OQoKipKQ4cO1eDBgzV79mzt3r1bGzZs0Ouvv+5emPjII49o586dGjZsmLZv3653331Xs2bNsvR5r7/+emVmZmrevHnavXu3Jk+e7HVBaGhoqHr16qVNmzZp9erVGjhwoLp166b4+HhJ0rhx45SWlqbJkydrx44d+vbbbzVz5kxNmjTJUjwA7EECAZSy8PBwffHFF7r22mt19913q2HDhurbt69yc3PdFYknn3xSDz30kHr16qU2bdooKipKd91112WPO2XKFN17770aMGCAGjRooP79++vs2bOSpBo1amjcuHEaOXKk4uLilJqaKkkaP368Ro0apbS0NDVs2FCdO3fW4sWLVadOHUnn1yW89957+vDDD9WsWTNNnTpVEydOtPR577jjDg0ePFipqalq3ry51q5dq1GjRl0yLikpSXfffbduv/12dezYUU2bNvW4TLNfv36aPn26Zs6cqSZNmqhdu3aaNWuWO1YApcthFrUqCwAAoAhUIAAAgGUkEAAAwDISCAAAYBkJBAAAsIwEAgAAWEYCAQAALCOBAAAAlpFAAAAAy0ggAACAZSQQAADAMhIIAABg2f8DfP9mj/75/VEAAAAASUVORK5CYII=\n" }, "metadata": {} } ] } ] }