{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Feature Scaling\n",
    "\n",
    "With any distance based machine learning model (regularized regression methods, neural networks, and now kmeans), you will want to scale your data.  \n",
    "\n",
    "If you have some features that are on completely different scales, this can greatly impact the clusters you get when using K-Means. \n",
    "\n",
    "In this notebook, you will get to see this first hand.  To begin, let's read in the necessary libraries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.cluster import KMeans\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn import preprocessing as p\n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "plt.rcParams['figure.figsize'] = (16, 9)\n",
    "import helpers2 as h\n",
    "import tests as t\n",
    "\n",
    "\n",
    "# Create the dataset for the notebook\n",
    "data = h.simulate_data(200, 2, 4)\n",
    "df = pd.DataFrame(data)\n",
    "df.columns = ['height', 'weight']\n",
    "df['height'] = np.abs(df['height']*100)\n",
    "df['weight'] = df['weight'] + np.random.normal(50, 10, 200)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`1.` Next, take a look at the data to get familiar with it.  The dataset has two columns, and it is stored in the **df** variable.  It might be useful to get an idea of the spread in the current data, as well as a visual of the points.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>height</th>\n",
       "      <th>weight</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>650.565335</td>\n",
       "      <td>60.096089</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>512.894273</td>\n",
       "      <td>56.516825</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>885.057453</td>\n",
       "      <td>60.310782</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1028.641210</td>\n",
       "      <td>64.484814</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>746.899195</td>\n",
       "      <td>36.936752</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        height     weight\n",
       "0   650.565335  60.096089\n",
       "1   512.894273  56.516825\n",
       "2   885.057453  60.310782\n",
       "3  1028.641210  64.484814\n",
       "4   746.899195  36.936752"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Take a look at the data\n",
    "df.head(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>height</th>\n",
       "      <th>weight</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>200.000000</td>\n",
       "      <td>200.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>569.726207</td>\n",
       "      <td>54.137034</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>246.966215</td>\n",
       "      <td>11.938455</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>92.998481</td>\n",
       "      <td>26.058373</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>357.542793</td>\n",
       "      <td>46.838821</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>545.766752</td>\n",
       "      <td>55.053171</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>773.310607</td>\n",
       "      <td>60.982262</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>1096.222348</td>\n",
       "      <td>84.145520</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            height      weight\n",
       "count   200.000000  200.000000\n",
       "mean    569.726207   54.137034\n",
       "std     246.966215   11.938455\n",
       "min      92.998481   26.058373\n",
       "25%     357.542793   46.838821\n",
       "50%     545.766752   55.053171\n",
       "75%     773.310607   60.982262\n",
       "max    1096.222348   84.145520"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#use this cell if you would like as well\n",
    "df.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we've got a dataset, let's look at some options for scaling the data.  As well as how the data might be scaled.  There are two very common types of feature scaling that we should discuss:\n",
    "\n",
    "\n",
    "**I.  MinMaxScaler**\n",
    "\n",
    "In some cases it is useful to think of your data in terms of the percent they are as compared to the maximum value.  In these cases, you will want to use **MinMaxScaler**.\n",
    "\n",
    "**II. StandardScaler**\n",
    "\n",
    "Another very popular type of scaling is to scale data so that it has mean 0 and variance 1.  In these cases, you will want to use **StandardScaler**.  \n",
    "\n",
    "It is probably more appropriate with this data to use **StandardScaler**.  However, to get practice with feature scaling methods in python, we will perform both.\n",
    "\n",
    "`2.` First let's fit the **StandardScaler** transformation to this dataset.  I will do this one so you can see how to apply preprocessing in sklearn."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "df_ss = p.StandardScaler().fit_transform(df) # Fit and transform the data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 21764 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff0d98c9898>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df_ss = pd.DataFrame(df_ss) #create a dataframe\n",
    "df_ss.columns = ['height', 'weight'] #add column names again\n",
    "\n",
    "plt.figure(figsize = [15,15])\n",
    "plt.scatter(df_ss['height'], df_ss['weight']); # create a plot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`3.` Now it's your turn.  Try fitting the **MinMaxScaler** transformation to this dataset. You should be able to use the previous example to assist."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>height</th>\n",
       "      <th>weight</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.555775</td>\n",
       "      <td>0.585977</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.418546</td>\n",
       "      <td>0.524358</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.789514</td>\n",
       "      <td>0.589673</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.932636</td>\n",
       "      <td>0.661531</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.651799</td>\n",
       "      <td>0.187277</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     height    weight\n",
       "0  0.555775  0.585977\n",
       "1  0.418546  0.524358\n",
       "2  0.789514  0.589673\n",
       "3  0.932636  0.661531\n",
       "4  0.651799  0.187277"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# fit and transform\n",
    "\n",
    "# for a dataframe called df with 2 cols to be scaled\n",
    "df_mm = p.MinMaxScaler().fit_transform(df)\n",
    "df_mm = pd.DataFrame(df_mm)\n",
    "df_mm.columns = ['height', 'weight']\n",
    "df_mm.head(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x7ff0d954a470>"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 22776 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff0d9641a20>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#create a dataframe\n",
    "#change the column names\n",
    "#plot the data\n",
    "plt.figure(figsize = [15,15])\n",
    "plt.scatter(df_mm['height'], df_mm['weight'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`4.`  Now let's take a look at how kmeans divides the dataset into different groups for each of the different scalings of the data.  Did you end up with different clusters when the data was scaled differently?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 59468 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff0d9565fd0>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def fit_kmeans(data, centers):\n",
    "    '''\n",
    "    INPUT:\n",
    "        data = the dataset you would like to fit kmeans to (dataframe)\n",
    "        centers = the number of centroids (int)\n",
    "    OUTPUT:\n",
    "        labels - the labels for each datapoint to which group it belongs (nparray)\n",
    "    \n",
    "    '''\n",
    "    kmeans = KMeans(centers)\n",
    "    labels = kmeans.fit_predict(data)\n",
    "    return labels\n",
    "\n",
    "labels = fit_kmeans(df, 10) #fit kmeans to get the labels\n",
    "    \n",
    "# Plot the original data with clusters\n",
    "plt.figure(figsize = [15,15])\n",
    "\n",
    "plt.scatter(df['height'], df['weight'], c=labels, cmap='Set1');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x7ff0d9484f98>"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 59060 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff0db93b7f0>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#plot each of the scaled datasets\n",
    "plt.figure(figsize = [15,15])\n",
    "\n",
    "labels_ss = fit_kmeans(df_ss, 10)\n",
    "plt.scatter(df_ss['height'], df_ss['weight'], c=labels_ss, cmap='Set1')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x7ff0d942d550>"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 59140 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff0d9363a20>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#another plot of the other scaled dataset\n",
    "plt.figure(figsize = [15,15])\n",
    "\n",
    "labels_mm = fit_kmeans(df_mm, 10)\n",
    "plt.scatter(df_mm['height'], df_mm['weight'], c=labels_mm, cmap='Set1')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Write your response here!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Yes"
   ]
  },
  {
   "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.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
