From 818a46ad069d8376095fd928331cc36f2ffdb2e6 Mon Sep 17 00:00:00 2001
From: shawk masboob <masboob.shawk@gmail.com>
Date: Fri, 28 Feb 2020 23:05:11 -0500
Subject: [PATCH] Major updates to prediction notebook

---
 TDA_Prediction.ipynb | 609 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 541 insertions(+), 68 deletions(-)

diff --git a/TDA_Prediction.ipynb b/TDA_Prediction.ipynb
index 6af9c03..520afe0 100644
--- a/TDA_Prediction.ipynb
+++ b/TDA_Prediction.ipynb
@@ -17,122 +17,595 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 27,
    "metadata": {},
    "outputs": [],
    "source": [
     "from Topological_ML import TDA_Prediction as tdap\n",
     "from sklearn.datasets import fetch_california_housing\n",
+    "from sklearn.model_selection import train_test_split\n",
+    "from sklearn.linear_model import LinearRegression\n",
+    "import kmapper as km\n",
     "import pandas as pd\n",
-    "import numpy as np"
+    "import numpy as np\n",
+    "import matplotlib.pyplot as plt\n",
+    "import sklearn\n",
+    "from sklearn import ensemble"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 45,
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cal_housing = fetch_california_housing()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
    "metadata": {},
    "outputs": [],
    "source": [
-    "cal_housing = fetch_california_housing()\n",
-    "\n",
     "def numpy_to_pandas(sklearn_data):\n",
     "    df = pd.DataFrame(data = sklearn_data.data, columns = sklearn_data.feature_names)\n",
     "    df['response'] = pd.Series(sklearn_data.target)\n",
-    "    return df"
+    "    return df\n",
+    "\n",
+    "df = numpy_to_pandas(cal_housing)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 50,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
-    "df = numpy_to_pandas(cal_housing)"
+    "def descriptive_statistic(df, n):\n",
+    "    \"\"\"\n",
+    "    Provides brief descriptive statistics on dataset. \n",
+    "    Takes dataframe as input.\n",
+    "    \"\"\"\n",
+    "    d = dict()\n",
+    "    d['head'] = df.head(n)\n",
+    "    d['shape'] = df.shape\n",
+    "    d['missing values'] = df.isna().sum()\n",
+    "    d['describe'] = df.describe()\n",
+    "    return d"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'head':    MedInc  HouseAge  AveRooms  AveBedrms  Population  AveOccup  Latitude  \\\n",
+       " 0  8.3252      41.0  6.984127   1.023810       322.0  2.555556     37.88   \n",
+       " 1  8.3014      21.0  6.238137   0.971880      2401.0  2.109842     37.86   \n",
+       " 2  7.2574      52.0  8.288136   1.073446       496.0  2.802260     37.85   \n",
+       " 3  5.6431      52.0  5.817352   1.073059       558.0  2.547945     37.85   \n",
+       " 4  3.8462      52.0  6.281853   1.081081       565.0  2.181467     37.85   \n",
+       " \n",
+       "    Longitude  response  \n",
+       " 0    -122.23     4.526  \n",
+       " 1    -122.22     3.585  \n",
+       " 2    -122.24     3.521  \n",
+       " 3    -122.25     3.413  \n",
+       " 4    -122.25     3.422  ,\n",
+       " 'shape': (20640, 9),\n",
+       " 'missing values': MedInc        0\n",
+       " HouseAge      0\n",
+       " AveRooms      0\n",
+       " AveBedrms     0\n",
+       " Population    0\n",
+       " AveOccup      0\n",
+       " Latitude      0\n",
+       " Longitude     0\n",
+       " response      0\n",
+       " dtype: int64,\n",
+       " 'describe':              MedInc      HouseAge      AveRooms     AveBedrms    Population  \\\n",
+       " count  20640.000000  20640.000000  20640.000000  20640.000000  20640.000000   \n",
+       " mean       3.870671     28.639486      5.429000      1.096675   1425.476744   \n",
+       " std        1.899822     12.585558      2.474173      0.473911   1132.462122   \n",
+       " min        0.499900      1.000000      0.846154      0.333333      3.000000   \n",
+       " 25%        2.563400     18.000000      4.440716      1.006079    787.000000   \n",
+       " 50%        3.534800     29.000000      5.229129      1.048780   1166.000000   \n",
+       " 75%        4.743250     37.000000      6.052381      1.099526   1725.000000   \n",
+       " max       15.000100     52.000000    141.909091     34.066667  35682.000000   \n",
+       " \n",
+       "            AveOccup      Latitude     Longitude      response  \n",
+       " count  20640.000000  20640.000000  20640.000000  20640.000000  \n",
+       " mean       3.070655     35.631861   -119.569704      2.068558  \n",
+       " std       10.386050      2.135952      2.003532      1.153956  \n",
+       " min        0.692308     32.540000   -124.350000      0.149990  \n",
+       " 25%        2.429741     33.930000   -121.800000      1.196000  \n",
+       " 50%        2.818116     34.260000   -118.490000      1.797000  \n",
+       " 75%        3.282261     37.710000   -118.010000      2.647250  \n",
+       " max     1243.333333     41.950000   -114.310000      5.000010  }"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "descriptive_statistic(df, 5)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "((20640,), (20640, 7))"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "lm = LinearRegression()\n",
+    "\n",
+    "ys = df['response']\n",
+    "xs = np.c_[df['MedInc'],df['HouseAge'], df['AveRooms'], df['Population'], df['AveOccup'], df['Latitude'], df['Longitude']]\n",
+    "\n",
+    "lm.fit(xs,ys)\n",
+    "ys.shape, xs.shape"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(20640,)"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pred = lm.predict(xs)\n",
+    "pred.shape"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.5961995839710023"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "r2_sk = lm.score(xs,ys)\n",
+    "r2_sk"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "train, test = train_test_split(df, test_size = .2, random_state = 42)\n",
+    "x_train = train.drop('response', axis = 1)\n",
+    "y_train = train.response\n",
+    "\n",
+    "def linear_regression(x, y):\n",
+    "    model = LinearRegression()\n",
+    "    model.fit(x, y)\n",
+    "    return model.score(x ,y)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 66,
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1.0"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a = pd.DataFrame({\"A\": [1,2,3,4,5,6,7,8,9,10]})\n",
+    "b = pd.DataFrame({\"B\": [2,4,6,8,10,12,14,16,18,20]})\n",
+    "test = linear_regression(a, b)\n",
+    "test"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
    "metadata": {
-    "collapsed": true
+    "scrolled": true
    },
    "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.6125511913966952"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "test = linear_regression(x_train, y_train)\n",
+    "test"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### MAPPER"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "cal_housing = fetch_california_housing()\n",
+    "df = numpy_to_pandas(cal_housing)\n",
+    "\n",
+    "features = [c for c in df.columns if c not in ['response']]\n",
+    "\n",
+    "X = np.array(df[features])\n",
+    "y = np.array(df.response)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# We create a custom 1-D lens with Isolation Forest\n",
+    "def lens_1d(X, rs, v):\n",
+    "    model = ensemble.IsolationForest(random_state = rs)\n",
+    "    model.fit(X)\n",
+    "    lens1 = model.decision_function(X).reshape((X.shape[0], 1))\n",
+    "    mapper = km.KeplerMapper(verbose = v)\n",
+    "    lens2 = mapper.fit_transform(X, projection=\"l2norm\")\n",
+    "    lens = np.c_[lens1, lens2]\n",
+    "    return lens"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/Users/shawkmasboob/anaconda3/lib/python3.7/site-packages/sklearn/ensemble/iforest.py:237: FutureWarning: default contamination parameter 0.1 will change in version 0.22 to \"auto\". This will change the predict method behavior.\n",
+      "  FutureWarning)\n",
+      "/Users/shawkmasboob/anaconda3/lib/python3.7/site-packages/sklearn/ensemble/iforest.py:247: FutureWarning: behaviour=\"old\" is deprecated and will be removed in version 0.22. Please use behaviour=\"new\", which makes the decision_function change to match other anomaly detection algorithm API.\n",
+      "  FutureWarning)\n"
+     ]
+    },
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Shape :  (20640, 9)\n",
-      "Head -- \n",
-      "    MedInc  HouseAge  AveRooms  AveBedrms  Population  AveOccup  Latitude  \\\n",
-      "0  8.3252      41.0  6.984127   1.023810       322.0  2.555556     37.88   \n",
-      "1  8.3014      21.0  6.238137   0.971880      2401.0  2.109842     37.86   \n",
-      "2  7.2574      52.0  8.288136   1.073446       496.0  2.802260     37.85   \n",
-      "3  5.6431      52.0  5.817352   1.073059       558.0  2.547945     37.85   \n",
-      "4  3.8462      52.0  6.281853   1.081081       565.0  2.181467     37.85   \n",
-      "\n",
-      "   Longitude  target  \n",
-      "0    -122.23   4.526  \n",
-      "1    -122.22   3.585  \n",
-      "2    -122.24   3.521  \n",
-      "3    -122.25   3.413  \n",
-      "4    -122.25   3.422  \n",
-      "Describe :               MedInc      HouseAge      AveRooms     AveBedrms    Population  \\\n",
-      "count  20640.000000  20640.000000  20640.000000  20640.000000  20640.000000   \n",
-      "mean       3.870671     28.639486      5.429000      1.096675   1425.476744   \n",
-      "std        1.899822     12.585558      2.474173      0.473911   1132.462122   \n",
-      "min        0.499900      1.000000      0.846154      0.333333      3.000000   \n",
-      "25%        2.563400     18.000000      4.440716      1.006079    787.000000   \n",
-      "50%        3.534800     29.000000      5.229129      1.048780   1166.000000   \n",
-      "75%        4.743250     37.000000      6.052381      1.099526   1725.000000   \n",
-      "max       15.000100     52.000000    141.909091     34.066667  35682.000000   \n",
-      "\n",
-      "           AveOccup      Latitude     Longitude        target  \n",
-      "count  20640.000000  20640.000000  20640.000000  20640.000000  \n",
-      "mean       3.070655     35.631861   -119.569704      2.068558  \n",
-      "std       10.386050      2.135952      2.003532      1.153956  \n",
-      "min        0.692308     32.540000   -124.350000      0.149990  \n",
-      "25%        2.429741     33.930000   -121.800000      1.196000  \n",
-      "50%        2.818116     34.260000   -118.490000      1.797000  \n",
-      "75%        3.282261     37.710000   -118.010000      2.647250  \n",
-      "max     1243.333333     41.950000   -114.310000      5.000010  \n",
-      "None\n"
+      "KeplerMapper()\n",
+      "..Composing projection pipeline of length 1:\n",
+      "\tProjections: l2norm\n",
+      "\tDistance matrices: False\n",
+      "\tScalers: MinMaxScaler(copy=True, feature_range=(0, 1))\n",
+      "..Projecting on data shaped (20640, 8)\n",
+      "\n",
+      "..Projecting data using: l2norm\n",
+      "\n",
+      "..Scaling with: MinMaxScaler(copy=True, feature_range=(0, 1))\n",
+      "\n"
      ]
     }
    ],
    "source": [
-    "def descriptive_statistic(df, n):\n",
-    "    \"\"\"\n",
-    "    Provides brief descriptive statistics on dataset. \n",
-    "    Takes dataframe as input.\n",
-    "    \"\"\"\n",
-    "    print(\"Shape : \", df.shape)\n",
-    "    print(\"Head -- \\n\", df.head(n))\n",
-    "    print(\"Describe : \", df.describe())\n",
-    "    \n",
-    "descriptive_statistic(df, 5)"
+    "lens = lens_1d(X, 1729, 3)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 44,
    "metadata": {},
-   "outputs": [],
-   "source": []
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "KeplerMapper()\n",
+      "..Composing projection pipeline of length 1:\n",
+      "\tProjections: l2norm\n",
+      "\tDistance matrices: False\n",
+      "\tScalers: MinMaxScaler(copy=True, feature_range=(0, 1))\n",
+      "..Projecting on data shaped (2, 1)\n",
+      "\n",
+      "..Projecting data using: l2norm\n",
+      "\n",
+      "..Scaling with: MinMaxScaler(copy=True, feature_range=(0, 1))\n",
+      "\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/Users/shawkmasboob/anaconda3/lib/python3.7/site-packages/sklearn/ensemble/iforest.py:237: FutureWarning: default contamination parameter 0.1 will change in version 0.22 to \"auto\". This will change the predict method behavior.\n",
+      "  FutureWarning)\n",
+      "/Users/shawkmasboob/anaconda3/lib/python3.7/site-packages/sklearn/ensemble/iforest.py:247: FutureWarning: behaviour=\"old\" is deprecated and will be removed in version 0.22. Please use behaviour=\"new\", which makes the decision_function change to match other anomaly detection algorithm API.\n",
+      "  FutureWarning)\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "array([[0., 0.],\n",
+       "       [0., 0.]])"
+      ]
+     },
+     "execution_count": 44,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a = pd.DataFrame({\"A\": [0,0]})\n",
+    "lens_1d(a,123,1)"
+   ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 16,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "KeplerMapper()\n",
+      "Mapping on data shaped (20640, 8) using lens shaped (20640, 2)\n",
+      "\n",
+      "Minimal points in hypercube before clustering: 2\n",
+      "Creating 225 hypercubes.\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "Cube_9 is empty.\n",
+      "\n",
+      "Cube_10 is empty.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "Cube_16 is empty.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "Cube_21 is empty.\n",
+      "\n",
+      "Cube_22 is empty.\n",
+      "\n",
+      "Cube_23 is empty.\n",
+      "\n",
+      "Cube_24 is empty.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "Cube_31 is empty.\n",
+      "\n",
+      "Cube_32 is empty.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "Cube_47 is empty.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "   > Found 2 clusters.\n",
+      "\n",
+      "\n",
+      "Created 288 edges and 128 nodes in 0:00:01.880401.\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Create the simplicial complex\n",
+    "mapper = km.KeplerMapper(verbose=3)\n",
+    "graph = mapper.map(lens, X, cover=km.Cover(n_cubes=15, perc_overlap=0.4), \n",
+    "                   clusterer=sklearn.cluster.KMeans(n_clusters=2, random_state=1618033))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/Users/shawkmasboob/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:579: MatplotlibDeprecationWarning: \n",
+      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
+      "  if not cb.iterable(width):\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<Figure size 1440x1440 with 0 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<Figure size 432x288 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
    "source": [
-    "def test_srt_rt1():\n",
-    "    assert tdap.mysqrt(-4) == 2\n",
-    "    return\n",
-    "\n",
-    "def test_srt_rt2():\n",
-    "    assert tdap.mysqrt(4) == 2\n",
-    "    return\n",
-    "\n"
+    "plt.figure(figsize=(20,20))\n",
+    "km.draw_matplotlib(graph)\n",
+    "plt.show()"
    ]
   }
  ],
-- 
GitLab