{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Chapter 11: Neural nets (code to produce additional figures)\n",
    "\n",
    "> (c) 2019 Galit Shmueli, Peter C. Bruce, Peter Gedeck \n",
    ">\n",
    "> Code included in\n",
    ">\n",
    "> _Data Mining for Business Analytics: Concepts, Techniques, and Applications in Python_ (First Edition) \n",
    "> Galit Shmueli, Peter C. Bruce, Peter Gedeck, and Nitin R. Patel. 2019.\n",
    "\n",
    "## Import required packages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:10.026357Z",
     "iopub.status.busy": "2021-05-27T20:03:10.025886Z",
     "iopub.status.idle": "2021-05-27T20:03:10.818302Z",
     "shell.execute_reply": "2021-05-27T20:03:10.817688Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "no display found. Using non-interactive Agg backend\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "import pydotplus\n",
    "from IPython.display import Image\n",
    "import numbers\n",
    "\n",
    "import dmba\n",
    "\n",
    "%matplotlib inline\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:10.821801Z",
     "iopub.status.busy": "2021-05-27T20:03:10.821374Z",
     "iopub.status.idle": "2021-05-27T20:03:10.823833Z",
     "shell.execute_reply": "2021-05-27T20:03:10.823404Z"
    }
   },
   "outputs": [],
   "source": [
    "def layoutGraph(dot_data, pdfFile=None):\n",
    "    graph = pydotplus.graph_from_dot_data(dot_data)\n",
    "    return Image(graph.create_png())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:10.827450Z",
     "iopub.status.busy": "2021-05-27T20:03:10.826860Z",
     "iopub.status.idle": "2021-05-27T20:03:10.829495Z",
     "shell.execute_reply": "2021-05-27T20:03:10.829084Z"
    }
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:10.843079Z",
     "iopub.status.busy": "2021-05-27T20:03:10.837628Z",
     "iopub.status.idle": "2021-05-27T20:03:10.996767Z",
     "shell.execute_reply": "2021-05-27T20:03:10.996304Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 49956 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def unbiasedNode(id, label=None, output=None, style=None):\n",
    "    label = label or f'N{id}'\n",
    "    common = style or 'shape=record, style=rounded, color=gray26'\n",
    "    if output is None:\n",
    "        return f'{id} [ label=\"{label}\", fontsize=11, {common} ];'\n",
    "    return f'{id} [ label=\"{{ {label} | {output:.2f} }}\", fontsize=11, {common} ];'\n",
    "\n",
    "def biasedNode(id, bias, label=None, output=None):\n",
    "    label = label or f'N{id}'\n",
    "    if isinstance(bias, numbers.Number):\n",
    "        bias = f'{bias:.3f}'\n",
    "    if isinstance(output, numbers.Number):\n",
    "        output = f'{output:.3f}'\n",
    "    common = 'shape=record, style=rounded, fontsize=11, color=gray26'\n",
    "    if output is None:\n",
    "        return f'{id} [ label=\"{label}&#92;n{bias}\", {common} ];'\n",
    "    return f'{id} [ label=\"{{ {label}&#92;n{bias} | {output} }}\", {common} ];'\n",
    "\n",
    "def edge(n1, n2, weight=None):\n",
    "    if weight is None:\n",
    "        return f'{n1} -> {n2} [ label=\"w{n1}{n2}\" ];'\n",
    "    return f'{n1} -> {n2} [ label=\"{weight:.3f}\" ];'\n",
    "\n",
    "commonSettings = \"\"\"\n",
    "edge [ fontsize=11, color=gray55 ];\n",
    "rankdir=LR;\n",
    "# size=\"10,10\"\n",
    "graph [ranksep=\"0.8\"];\n",
    "\"\"\"\n",
    "# node [shape=record, style=rounded, fontsize=11, color=gray26]; \n",
    "\n",
    "s = f\"\"\"\n",
    "digraph ethane {{\n",
    "{ commonSettings }\n",
    "{ unbiasedNode('Salt', label='Salt', style='color=white') }\n",
    "{ unbiasedNode('Fat', label='Fat', style='color=white') }\n",
    "subgraph cluster_input {{ label=\"Input layer\"; color=\"grey75\"; \n",
    "    { unbiasedNode(2) }\n",
    "    { unbiasedNode(1) }\n",
    "}}\n",
    "subgraph cluster_hidden {{ label=\"Hidden layer\"; color=\"grey75\"; \n",
    "    { biasedNode(4, '&theta;4')}\n",
    "    { biasedNode(3, '&theta;3')}\n",
    "    { biasedNode(5, '&theta;5')}\n",
    "}}\n",
    "subgraph cluster_output {{ label=\"Output layer\"; color=\"grey75\"; \n",
    "    { biasedNode(6, '&theta;6')}\n",
    "}}\n",
    "{ unbiasedNode('like', label='like', style='color=white') }\n",
    "Salt -> 2;\n",
    "Fat -> 1;\n",
    "{ edge(1, 3) }\n",
    "{ edge(2, 3) }\n",
    "{ edge(1, 4) }\n",
    "{ edge(2, 4) }\n",
    "{ edge(1, 5) }\n",
    "{ edge(2, 5) }\n",
    "{ edge(3, 6) }\n",
    "{ edge(4, 6) }\n",
    "{ edge(5, 6) }\n",
    "6 -> like\n",
    " }}\n",
    " \"\"\"\n",
    "layoutGraph(s, pdfFile='network-layout.pdf')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:11.009873Z",
     "iopub.status.busy": "2021-05-27T20:03:11.004522Z",
     "iopub.status.idle": "2021-05-27T20:03:11.188655Z",
     "shell.execute_reply": "2021-05-27T20:03:11.188994Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 39796 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Random network\n",
    "s = f\"\"\"\n",
    "digraph ethane {{\n",
    "{ commonSettings }\n",
    "{ unbiasedNode('Salt', label='Salt', style='color=white') }\n",
    "{ unbiasedNode('Fat', label='Fat', style='color=white') }\n",
    "{ unbiasedNode(2, output=0.9) }\n",
    "{ unbiasedNode(1, output=0.2) }\n",
    "{ biasedNode(4, 0.02, output=0.51224755)}\n",
    "{ biasedNode(3, -0.3, output=0.42580196)}\n",
    "{ biasedNode(5, 0.05, output=0.520238936)}\n",
    "{ biasedNode(6, -0.015, output=0.505668252)}\n",
    "{ unbiasedNode('like', label='like', style='color=white') }\n",
    "Salt -> 2;\n",
    "Fat -> 1;\n",
    "{ edge(1, 3, 0.05) }\n",
    "{ edge(2, 3, 0.01) }\n",
    "{ edge(1, 4, -0.01) }\n",
    "{ edge(2, 4, 0.03) }\n",
    "{ edge(1, 5, 0.2) }\n",
    "{ edge(2, 5, -0.01) }\n",
    "{ edge(3, 6, 0.01) }\n",
    "{ edge(4, 6, 0.05) }\n",
    "{ edge(5, 6, 0.015) }\n",
    "6 -> like\n",
    " }}\n",
    " \"\"\"\n",
    "layoutGraph(s, pdfFile='network-random.pdf')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:11.197306Z",
     "iopub.status.busy": "2021-05-27T20:03:11.196835Z",
     "iopub.status.idle": "2021-05-27T20:03:11.304208Z",
     "shell.execute_reply": "2021-05-27T20:03:11.304541Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 51816 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Optimized network\n",
    "s = f\"\"\"\n",
    "digraph ethane {{\n",
    "{ commonSettings }\n",
    "{ unbiasedNode('Salt', label='Salt', style='color=white') }\n",
    "{ unbiasedNode('Fat', label='Fat', style='color=white') }\n",
    "{ unbiasedNode(2, output=0.9) }\n",
    "{ unbiasedNode(1, output=0.2) }\n",
    "{ biasedNode(4, 4.07247552, output=0.232750971)}\n",
    "{ biasedNode(3, 0.13368045, output=0.458287289)}\n",
    "{ biasedNode(5, 7.00768104, output=0.253183219)}\n",
    "{ biasedNode(6, 14.30748676, output=0.99950954)}\n",
    "{ unbiasedNode('like', label='like', style='color=white') }\n",
    "Salt -> 2;\n",
    "Fat -> 1;\n",
    "{ edge(1, 3, -1.30656481) }\n",
    "{ edge(2, 3, -0.04399727) }\n",
    "{ edge(1, 4, -4.20427792) }\n",
    "{ edge(2, 4, -4.91606924) }\n",
    "{ edge(1, 5, -13.29587332) }\n",
    "{ edge(2, 5, -6.03356987) }\n",
    "{ edge(3, 6, -0.27348313) }\n",
    "{ edge(4, 6, -9.01211573) }\n",
    "{ edge(5, 6, -17.63504694) }\n",
    "6 -> like\n",
    "}}\n",
    " \"\"\"\n",
    "layoutGraph(s) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:11.322959Z",
     "iopub.status.busy": "2021-05-27T20:03:11.317566Z",
     "iopub.status.idle": "2021-05-27T20:03:11.451462Z",
     "shell.execute_reply": "2021-05-27T20:03:11.451787Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 48372 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Optimized network\n",
    "s = f\"\"\"\n",
    "digraph ethane {{\n",
    "{ commonSettings }\n",
    "{ unbiasedNode('Salt', label='Salt', style='color=white') }\n",
    "{ unbiasedNode('Fat', label='Fat', style='color=white') }\n",
    "{ unbiasedNode(2) }\n",
    "{ unbiasedNode(1) }\n",
    "{ biasedNode(4, 4.07247552)}\n",
    "{ biasedNode(3, 0.13368045)}\n",
    "{ biasedNode(5, 7.00768104)}\n",
    "{ biasedNode(6, 14.30748676)}\n",
    "{ unbiasedNode('like', label='like', style='color=white') }\n",
    "Salt -> 2;\n",
    "Fat -> 1;\n",
    "{ edge(1, 3, -1.30656481) }\n",
    "{ edge(2, 3, -0.04399727) }\n",
    "{ edge(1, 4, -4.20427792) }\n",
    "{ edge(2, 4, -4.91606924) }\n",
    "{ edge(1, 5, -13.29587332) }\n",
    "{ edge(2, 5, -6.03356987) }\n",
    "{ edge(3, 6, -0.27348313) }\n",
    "{ edge(4, 6, -9.01211573) }\n",
    "{ edge(5, 6, -17.63504694) }\n",
    "6 -> like\n",
    "}}\n",
    " \"\"\"\n",
    "layoutGraph(s, pdfFile='network-optimized.pdf') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-05-27T20:03:11.459944Z",
     "iopub.status.busy": "2021-05-27T20:03:11.459435Z",
     "iopub.status.idle": "2021-05-27T20:03:11.705296Z",
     "shell.execute_reply": "2021-05-27T20:03:11.704854Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 60352 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def node(color):\n",
    "    return f'[label=\"\", shape=\"circle\", color=\"{color}\", fillcolor=\"{color}\", style=\"filled\"]'\n",
    "\n",
    "input = '\\n'.join(f'i{i} {node(\"#A55B60\")}; ' for i in range(4))\n",
    "hidden1 = '\\n'.join(f'h1{i} {node(\"#74BEEB\")}; ' for i in range(3))\n",
    "hidden2 = '\\n'.join(f'h2{i} {node(\"#74BEEB\")}; ' for i in range(3))\n",
    "output = '\\n'.join(f'o{i} {node(\"#3D92A2\")}; ' for i in range(1))\n",
    "\n",
    "def connections(layer1, count1, layer2, count2):\n",
    "    s = []\n",
    "    for i in range(count1):\n",
    "        for j in range(count2):\n",
    "            s.append(f'{layer1}{i} -- {layer2}{j} [color=\"gray55\"];')\n",
    "    return '\\n'.join(s)\n",
    "\n",
    "s = f\"\"\"\n",
    "graph {{\n",
    "    size=\"10,10\"\n",
    "    graph [ranksep=\"1\"];\n",
    "    rankdir=LR;\n",
    "    splines=line;\n",
    "    subgraph cluster_input {{ label=\"Input layer\"; color=\"grey75\"; { input } }}\n",
    "    subgraph cluster_hidden1 {{ label=\"Hidden layer 1\"; color=\"grey75\"; { hidden1 } }}\n",
    "    subgraph cluster_hidden2 {{ label=\"Hidden layer 2\"; color=\"grey75\"; { hidden2 } }}\n",
    "    subgraph cluster_output {{ label=\"Output layer\"; color=\"grey75\"; { output } }}\n",
    "    { connections('i', 4, 'h1', 3)}\n",
    "    { connections('h1', 3, 'h2', 3)}\n",
    "    { connections('h2', 3, 'o', 1)}\n",
    "}}\n",
    "\"\"\"\n",
    "layoutGraph(s, pdfFile='network-4331.pdf') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
