diff --git a/ArtificialNeuralNetwork.ipynb b/ArtificialNeuralNetwork.ipynb
index 6fa36fd..e7e0d54 100644
--- a/ArtificialNeuralNetwork.ipynb
+++ b/ArtificialNeuralNetwork.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
@@ -22,28 +22,68 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 3,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Requirement already satisfied: tensorflow==1.13.1 in /home/andrew/anaconda3/lib/python3.7/site-packages (from -r requirements.txt (line 1)) (1.13.1)\n",
+ "Requirement already satisfied: numpy==1.16.2 in /home/andrew/anaconda3/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (1.16.2)\n",
+ "Requirement already satisfied: pandas==0.24.2 in /home/andrew/anaconda3/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (0.24.2)\n",
+ "Requirement already satisfied: matplotlib==3.0.3 in /home/andrew/anaconda3/lib/python3.7/site-packages (from -r requirements.txt (line 4)) (3.0.3)\n",
+ "Requirement already satisfied: Keras==2.2.4 in /home/andrew/anaconda3/lib/python3.7/site-packages (from -r requirements.txt (line 5)) (2.2.4)\n",
+ "Requirement already satisfied: sklearn==0.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from -r requirements.txt (line 6)) (0.0)\n",
+ "Requirement already satisfied: wheel>=0.26 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (0.32.3)\n",
+ "Requirement already satisfied: six>=1.10.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (1.12.0)\n",
+ "Requirement already satisfied: absl-py>=0.1.6 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (0.7.1)\n",
+ "Requirement already satisfied: tensorboard<1.14.0,>=1.13.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (1.13.1)\n",
+ "Requirement already satisfied: tensorflow-estimator<1.14.0rc0,>=1.13.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (1.13.0)\n",
+ "Requirement already satisfied: grpcio>=1.8.6 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (1.19.0)\n",
+ "Requirement already satisfied: astor>=0.6.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (0.7.1)\n",
+ "Requirement already satisfied: termcolor>=1.1.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (1.1.0)\n",
+ "Requirement already satisfied: keras-applications>=1.0.6 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (1.0.7)\n",
+ "Requirement already satisfied: gast>=0.2.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (0.2.2)\n",
+ "Requirement already satisfied: protobuf>=3.6.1 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (3.7.1)\n",
+ "Requirement already satisfied: keras-preprocessing>=1.0.5 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow==1.13.1->-r requirements.txt (line 1)) (1.0.9)\n",
+ "Requirement already satisfied: python-dateutil>=2.5.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from pandas==0.24.2->-r requirements.txt (line 3)) (2.7.5)\n",
+ "Requirement already satisfied: pytz>=2011k in /home/andrew/anaconda3/lib/python3.7/site-packages (from pandas==0.24.2->-r requirements.txt (line 3)) (2018.7)\n",
+ "Requirement already satisfied: cycler>=0.10 in /home/andrew/anaconda3/lib/python3.7/site-packages (from matplotlib==3.0.3->-r requirements.txt (line 4)) (0.10.0)\n",
+ "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /home/andrew/anaconda3/lib/python3.7/site-packages (from matplotlib==3.0.3->-r requirements.txt (line 4)) (2.3.0)\n",
+ "Requirement already satisfied: kiwisolver>=1.0.1 in /home/andrew/anaconda3/lib/python3.7/site-packages (from matplotlib==3.0.3->-r requirements.txt (line 4)) (1.0.1)\n",
+ "Requirement already satisfied: h5py in /home/andrew/anaconda3/lib/python3.7/site-packages (from Keras==2.2.4->-r requirements.txt (line 5)) (2.8.0)\n",
+ "Requirement already satisfied: pyyaml in /home/andrew/anaconda3/lib/python3.7/site-packages (from Keras==2.2.4->-r requirements.txt (line 5)) (3.13)\n",
+ "Requirement already satisfied: scipy>=0.14 in /home/andrew/anaconda3/lib/python3.7/site-packages (from Keras==2.2.4->-r requirements.txt (line 5)) (1.1.0)\n",
+ "Requirement already satisfied: scikit-learn in /home/andrew/anaconda3/lib/python3.7/site-packages (from sklearn==0.0->-r requirements.txt (line 6)) (0.20.1)\n",
+ "Requirement already satisfied: werkzeug>=0.11.15 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorboard<1.14.0,>=1.13.0->tensorflow==1.13.1->-r requirements.txt (line 1)) (0.14.1)\n",
+ "Requirement already satisfied: markdown>=2.6.8 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorboard<1.14.0,>=1.13.0->tensorflow==1.13.1->-r requirements.txt (line 1)) (3.1)\n",
+ "Requirement already satisfied: mock>=2.0.0 in /home/andrew/anaconda3/lib/python3.7/site-packages (from tensorflow-estimator<1.14.0rc0,>=1.13.0->tensorflow==1.13.1->-r requirements.txt (line 1)) (2.0.0)\n",
+ "Requirement already satisfied: setuptools in /home/andrew/anaconda3/lib/python3.7/site-packages (from protobuf>=3.6.1->tensorflow==1.13.1->-r requirements.txt (line 1)) (40.6.3)\n",
+ "Requirement already satisfied: pbr>=0.11 in /home/andrew/anaconda3/lib/python3.7/site-packages (from mock>=2.0.0->tensorflow-estimator<1.14.0rc0,>=1.13.0->tensorflow==1.13.1->-r requirements.txt (line 1)) (5.1.3)\n"
+ ]
+ }
+ ],
"source": [
"!pip install -r requirements.txt"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 256,
"metadata": {},
"outputs": [],
"source": [
"# Importing the libraries\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
- "import pandas as pd"
+ "import pandas as pd\n",
+ "from mlxtend.plotting import plot_confusion_matrix\n"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 257,
"metadata": {},
"outputs": [],
"source": [
@@ -55,9 +95,162 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 258,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " CreditScore | \n",
+ " Geography | \n",
+ " Gender | \n",
+ " Age | \n",
+ " Tenure | \n",
+ " Balance | \n",
+ " NumOfProducts | \n",
+ " HasCrCard | \n",
+ " IsActiveMember | \n",
+ " EstimatedSalary | \n",
+ " Exited | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 619 | \n",
+ " France | \n",
+ " Female | \n",
+ " 42 | \n",
+ " 2 | \n",
+ " 0.00 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 101348.88 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 608 | \n",
+ " Spain | \n",
+ " Female | \n",
+ " 41 | \n",
+ " 1 | \n",
+ " 83807.86 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 1 | \n",
+ " 112542.58 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 502 | \n",
+ " France | \n",
+ " Female | \n",
+ " 42 | \n",
+ " 8 | \n",
+ " 159660.80 | \n",
+ " 3 | \n",
+ " 1 | \n",
+ " 0 | \n",
+ " 113931.57 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 699 | \n",
+ " France | \n",
+ " Female | \n",
+ " 39 | \n",
+ " 1 | \n",
+ " 0.00 | \n",
+ " 2 | \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 93826.63 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 850 | \n",
+ " Spain | \n",
+ " Female | \n",
+ " 43 | \n",
+ " 2 | \n",
+ " 125510.82 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 79084.10 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " CreditScore Geography Gender Age Tenure Balance NumOfProducts \\\n",
+ "0 619 France Female 42 2 0.00 1 \n",
+ "1 608 Spain Female 41 1 83807.86 1 \n",
+ "2 502 France Female 42 8 159660.80 3 \n",
+ "3 699 France Female 39 1 0.00 2 \n",
+ "4 850 Spain Female 43 2 125510.82 1 \n",
+ "\n",
+ " HasCrCard IsActiveMember EstimatedSalary Exited \n",
+ "0 1 1 101348.88 1 \n",
+ "1 0 1 112542.58 0 \n",
+ "2 1 0 113931.57 1 \n",
+ "3 0 0 93826.63 0 \n",
+ "4 1 1 79084.10 0 "
+ ]
+ },
+ "execution_count": 258,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df1 = dataset.iloc[:, 3:14]\n",
+ "df1.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 259,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/andrew/anaconda3/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py:368: FutureWarning: The handling of integer data will change in version 0.22. Currently, the categories are determined based on the range [0, max(values)], while in the future they will be determined based on the unique values.\n",
+ "If you want the future behaviour and silence this warning, you can specify \"categories='auto'\".\n",
+ "In case you used a LabelEncoder before this OneHotEncoder to convert the categories to integers, then you can now use the OneHotEncoder directly.\n",
+ " warnings.warn(msg, FutureWarning)\n",
+ "/home/andrew/anaconda3/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py:390: DeprecationWarning: The 'categorical_features' keyword is deprecated in version 0.20 and will be removed in 0.22. You can use the ColumnTransformer instead.\n",
+ " \"use the ColumnTransformer instead.\", DeprecationWarning)\n"
+ ]
+ }
+ ],
"source": [
"# Encoding categorical data\n",
"from sklearn.preprocessing import LabelEncoder, OneHotEncoder\n",
@@ -72,7 +265,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 261,
"metadata": {},
"outputs": [],
"source": [
@@ -83,7 +276,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 262,
"metadata": {},
"outputs": [],
"source": [
@@ -96,7 +289,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 263,
"metadata": {},
"outputs": [],
"source": [
@@ -110,52 +303,341 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 318,
"metadata": {},
"outputs": [],
"source": [
- "# Initialising the ANN\n",
- "classifier = Sequential()\n",
+ "def plotConfusion(array):\n",
+ "# Method to plot confusion matrix\n",
+ " df_cm = pd.DataFrame(\n",
+ " array\n",
+ " )\n",
+ " fig = plt.figure(figsize=(5, 4))\n",
+ " try:\n",
+ " heatmap = sn.heatmap(df_cm, annot=True, fmt=\"d\")\n",
+ " except ValueError:\n",
+ " raise ValueError(\"Confusion matrix values must be integers.\")\n",
+ " heatmap.yaxis.set_ticklabels(heatmap.yaxis.get_ticklabels(), rotation=0, ha='right')\n",
+ " heatmap.xaxis.set_ticklabels(heatmap.xaxis.get_ticklabels(), rotation=45, ha='right')\n",
+ " plt.ylabel('True label')\n",
+ " plt.xlabel('Predicted label')\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 320,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def learn(layers,epochs=30):\n",
+ " # layers -> array of dictionaries\n",
+ " # epochs -> int \n",
+ " # EX:\n",
+ " # learn([\n",
+ " # {'units': 10, 'activation': 'relu'},\n",
+ " # {'units': 1, 'activation': 'sigmoid'}\n",
+ " # ], 50)\n",
+ " \n",
+ " \n",
+ " # Initialising the ANN\n",
+ " classifier = Sequential()\n",
"\n",
- "# Adding the input layer and the first hidden layer\n",
- "classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))\n",
+ " for layer in layers:\n",
+ " # Adding the input layer and the first hidden layer\n",
+ " classifier.add(Dense(units = layer['units'], activation = layer['activation']))\n",
"\n",
- "# Adding the second hidden layer\n",
- "classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))\n",
+ " # Compiling the ANN\n",
+ " classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])\n",
+ " \n",
+ " # Fitting the ANN to the Training set\n",
+ " classifier.fit(X_train, y_train, batch_size = 10, epochs = epochs)\n",
"\n",
- "# Adding the output layer\n",
- "classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))\n",
+ " # Predicting the Test set results\n",
+ " y_pred = classifier.predict(X_test)\n",
+ " y_pred = (y_pred > 0.5)\n",
"\n",
- "# Compiling the ANN\n",
- "classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])"
+ " # Making the Confusion Matrix\n",
+ " from sklearn.metrics import confusion_matrix\n",
+ " cm = confusion_matrix(y_test, y_pred)\n",
+ " plotConfusion(cm)"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 326,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/30\n",
+ "8000/8000 [==============================] - 4s 537us/step - loss: 0.8432 - acc: 0.5835\n",
+ "Epoch 2/30\n",
+ "8000/8000 [==============================] - 2s 220us/step - loss: 0.5007 - acc: 0.7976\n",
+ "Epoch 3/30\n",
+ "8000/8000 [==============================] - 2s 212us/step - loss: 0.4582 - acc: 0.8065\n",
+ "Epoch 4/30\n",
+ "8000/8000 [==============================] - 2s 210us/step - loss: 0.4489 - acc: 0.8127\n",
+ "Epoch 5/30\n",
+ "8000/8000 [==============================] - 2s 219us/step - loss: 0.4442 - acc: 0.8172\n",
+ "Epoch 6/30\n",
+ "8000/8000 [==============================] - 2s 217us/step - loss: 0.4273 - acc: 0.8154\n",
+ "Epoch 7/30\n",
+ "8000/8000 [==============================] - 2s 210us/step - loss: 0.4181 - acc: 0.8191\n",
+ "Epoch 8/30\n",
+ "8000/8000 [==============================] - 2s 216us/step - loss: 0.4180 - acc: 0.8241\n",
+ "Epoch 9/30\n",
+ "8000/8000 [==============================] - 2s 211us/step - loss: 0.4146 - acc: 0.8317\n",
+ "Epoch 10/30\n",
+ "8000/8000 [==============================] - 2s 214us/step - loss: 0.4202 - acc: 0.8297\n",
+ "Epoch 11/30\n",
+ "8000/8000 [==============================] - 2s 217us/step - loss: 0.4070 - acc: 0.8331\n",
+ "Epoch 12/30\n",
+ "8000/8000 [==============================] - 2s 213us/step - loss: 0.4066 - acc: 0.8366\n",
+ "Epoch 13/30\n",
+ "8000/8000 [==============================] - 2s 217us/step - loss: 0.4211 - acc: 0.8415\n",
+ "Epoch 14/30\n",
+ "8000/8000 [==============================] - 2s 219us/step - loss: 0.4375 - acc: 0.8387\n",
+ "Epoch 15/30\n",
+ "8000/8000 [==============================] - 2s 213us/step - loss: 0.4185 - acc: 0.8436\n",
+ "Epoch 16/30\n",
+ "8000/8000 [==============================] - 2s 242us/step - loss: 0.4182 - acc: 0.8435\n",
+ "Epoch 17/30\n",
+ "8000/8000 [==============================] - 2s 239us/step - loss: 0.4108 - acc: 0.8427\n",
+ "Epoch 18/30\n",
+ "8000/8000 [==============================] - 2s 222us/step - loss: 0.4019 - acc: 0.8444\n",
+ "Epoch 19/30\n",
+ "8000/8000 [==============================] - 2s 219us/step - loss: 0.4065 - acc: 0.8466\n",
+ "Epoch 20/30\n",
+ "8000/8000 [==============================] - 2s 221us/step - loss: 0.4028 - acc: 0.8471\n",
+ "Epoch 21/30\n",
+ "8000/8000 [==============================] - 2s 216us/step - loss: 0.4065 - acc: 0.8482\n",
+ "Epoch 22/30\n",
+ "8000/8000 [==============================] - 2s 222us/step - loss: 0.4162 - acc: 0.8472\n",
+ "Epoch 23/30\n",
+ "8000/8000 [==============================] - 2s 225us/step - loss: 0.4084 - acc: 0.8506\n",
+ "Epoch 24/30\n",
+ "8000/8000 [==============================] - 2s 221us/step - loss: 0.3963 - acc: 0.8504\n",
+ "Epoch 25/30\n",
+ "8000/8000 [==============================] - 2s 230us/step - loss: 0.4130 - acc: 0.8477\n",
+ "Epoch 26/30\n",
+ "8000/8000 [==============================] - 2s 247us/step - loss: 0.4010 - acc: 0.8504\n",
+ "Epoch 27/30\n",
+ "8000/8000 [==============================] - 2s 228us/step - loss: 0.3955 - acc: 0.8477\n",
+ "Epoch 28/30\n",
+ "8000/8000 [==============================] - 2s 233us/step - loss: 0.3928 - acc: 0.8496\n",
+ "Epoch 29/30\n",
+ "8000/8000 [==============================] - 2s 240us/step - loss: 0.3997 - acc: 0.8437\n",
+ "Epoch 30/30\n",
+ "8000/8000 [==============================] - 2s 280us/step - loss: 0.3960 - acc: 0.8486\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ "