{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook is part of my [Python data science curriculum](http://www.terran.us/articles/python_curriculum.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "RendererRegistry.enable('notebook')"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import altair as alt\n",
    "alt.renderers.enable('notebook')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.datasets import load_boston\n",
    "skBoston = load_boston()"
   ]
  },
  {
   "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>CRIM</th>\n",
       "      <th>ZN</th>\n",
       "      <th>INDUS</th>\n",
       "      <th>CHAS</th>\n",
       "      <th>NOX</th>\n",
       "      <th>RM</th>\n",
       "      <th>AGE</th>\n",
       "      <th>DIS</th>\n",
       "      <th>RAD</th>\n",
       "      <th>TAX</th>\n",
       "      <th>PTRATIO</th>\n",
       "      <th>B</th>\n",
       "      <th>LSTAT</th>\n",
       "      <th>MEDV</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.00632</td>\n",
       "      <td>18.0</td>\n",
       "      <td>2.31</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.538</td>\n",
       "      <td>6.575</td>\n",
       "      <td>65.2</td>\n",
       "      <td>4.0900</td>\n",
       "      <td>1.0</td>\n",
       "      <td>296.0</td>\n",
       "      <td>15.3</td>\n",
       "      <td>396.90</td>\n",
       "      <td>4.98</td>\n",
       "      <td>24.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.02731</td>\n",
       "      <td>0.0</td>\n",
       "      <td>7.07</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.469</td>\n",
       "      <td>6.421</td>\n",
       "      <td>78.9</td>\n",
       "      <td>4.9671</td>\n",
       "      <td>2.0</td>\n",
       "      <td>242.0</td>\n",
       "      <td>17.8</td>\n",
       "      <td>396.90</td>\n",
       "      <td>9.14</td>\n",
       "      <td>21.6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.02729</td>\n",
       "      <td>0.0</td>\n",
       "      <td>7.07</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.469</td>\n",
       "      <td>7.185</td>\n",
       "      <td>61.1</td>\n",
       "      <td>4.9671</td>\n",
       "      <td>2.0</td>\n",
       "      <td>242.0</td>\n",
       "      <td>17.8</td>\n",
       "      <td>392.83</td>\n",
       "      <td>4.03</td>\n",
       "      <td>34.7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.03237</td>\n",
       "      <td>0.0</td>\n",
       "      <td>2.18</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.458</td>\n",
       "      <td>6.998</td>\n",
       "      <td>45.8</td>\n",
       "      <td>6.0622</td>\n",
       "      <td>3.0</td>\n",
       "      <td>222.0</td>\n",
       "      <td>18.7</td>\n",
       "      <td>394.63</td>\n",
       "      <td>2.94</td>\n",
       "      <td>33.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.06905</td>\n",
       "      <td>0.0</td>\n",
       "      <td>2.18</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.458</td>\n",
       "      <td>7.147</td>\n",
       "      <td>54.2</td>\n",
       "      <td>6.0622</td>\n",
       "      <td>3.0</td>\n",
       "      <td>222.0</td>\n",
       "      <td>18.7</td>\n",
       "      <td>396.90</td>\n",
       "      <td>5.33</td>\n",
       "      <td>36.2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      CRIM    ZN  INDUS  CHAS    NOX     RM   AGE     DIS  RAD    TAX  \\\n",
       "0  0.00632  18.0   2.31   0.0  0.538  6.575  65.2  4.0900  1.0  296.0   \n",
       "1  0.02731   0.0   7.07   0.0  0.469  6.421  78.9  4.9671  2.0  242.0   \n",
       "2  0.02729   0.0   7.07   0.0  0.469  7.185  61.1  4.9671  2.0  242.0   \n",
       "3  0.03237   0.0   2.18   0.0  0.458  6.998  45.8  6.0622  3.0  222.0   \n",
       "4  0.06905   0.0   2.18   0.0  0.458  7.147  54.2  6.0622  3.0  222.0   \n",
       "\n",
       "   PTRATIO       B  LSTAT  MEDV  \n",
       "0     15.3  396.90   4.98  24.0  \n",
       "1     17.8  396.90   9.14  21.6  \n",
       "2     17.8  392.83   4.03  34.7  \n",
       "3     18.7  394.63   2.94  33.4  \n",
       "4     18.7  396.90   5.33  36.2  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# sklearn data is in a format with precomputed X and y, which is not what we want.\n",
    "Boston = pd.DataFrame(data= skBoston['data'],\n",
    "                      columns= skBoston['feature_names'])\n",
    "Boston['MEDV']=skBoston.target\n",
    "Boston.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Statsmodels"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Fitting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from statsmodels.multivariate.pca import PCA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "smpca = PCA(Boston,standardize=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Scree Plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "/* Put everything inside the global mpl namespace */\n",
       "window.mpl = {};\n",
       "\n",
       "\n",
       "mpl.get_websocket_type = function() {\n",
       "    if (typeof(WebSocket) !== 'undefined') {\n",
       "        return WebSocket;\n",
       "    } else if (typeof(MozWebSocket) !== 'undefined') {\n",
       "        return MozWebSocket;\n",
       "    } else {\n",
       "        alert('Your browser does not have WebSocket support.' +\n",
       "              'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
       "              'Firefox 4 and 5 are also supported but you ' +\n",
       "              'have to enable WebSockets in about:config.');\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
       "    this.id = figure_id;\n",
       "\n",
       "    this.ws = websocket;\n",
       "\n",
       "    this.supports_binary = (this.ws.binaryType != undefined);\n",
       "\n",
       "    if (!this.supports_binary) {\n",
       "        var warnings = document.getElementById(\"mpl-warnings\");\n",
       "        if (warnings) {\n",
       "            warnings.style.display = 'block';\n",
       "            warnings.textContent = (\n",
       "                \"This browser does not support binary websocket messages. \" +\n",
       "                    \"Performance may be slow.\");\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.imageObj = new Image();\n",
       "\n",
       "    this.context = undefined;\n",
       "    this.message = undefined;\n",
       "    this.canvas = undefined;\n",
       "    this.rubberband_canvas = undefined;\n",
       "    this.rubberband_context = undefined;\n",
       "    this.format_dropdown = undefined;\n",
       "\n",
       "    this.image_mode = 'full';\n",
       "\n",
       "    this.root = $('<div/>');\n",
       "    this._root_extra_style(this.root)\n",
       "    this.root.attr('style', 'display: inline-block');\n",
       "\n",
       "    $(parent_element).append(this.root);\n",
       "\n",
       "    this._init_header(this);\n",
       "    this._init_canvas(this);\n",
       "    this._init_toolbar(this);\n",
       "\n",
       "    var fig = this;\n",
       "\n",
       "    this.waiting = false;\n",
       "\n",
       "    this.ws.onopen =  function () {\n",
       "            fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
       "            fig.send_message(\"send_image_mode\", {});\n",
       "            if (mpl.ratio != 1) {\n",
       "                fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
       "            }\n",
       "            fig.send_message(\"refresh\", {});\n",
       "        }\n",
       "\n",
       "    this.imageObj.onload = function() {\n",
       "            if (fig.image_mode == 'full') {\n",
       "                // Full images could contain transparency (where diff images\n",
       "                // almost always do), so we need to clear the canvas so that\n",
       "                // there is no ghosting.\n",
       "                fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
       "            }\n",
       "            fig.context.drawImage(fig.imageObj, 0, 0);\n",
       "        };\n",
       "\n",
       "    this.imageObj.onunload = function() {\n",
       "        fig.ws.close();\n",
       "    }\n",
       "\n",
       "    this.ws.onmessage = this._make_on_message_function(this);\n",
       "\n",
       "    this.ondownload = ondownload;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_header = function() {\n",
       "    var titlebar = $(\n",
       "        '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
       "        'ui-helper-clearfix\"/>');\n",
       "    var titletext = $(\n",
       "        '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
       "        'text-align: center; padding: 3px;\"/>');\n",
       "    titlebar.append(titletext)\n",
       "    this.root.append(titlebar);\n",
       "    this.header = titletext[0];\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_canvas = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var canvas_div = $('<div/>');\n",
       "\n",
       "    canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
       "\n",
       "    function canvas_keyboard_event(event) {\n",
       "        return fig.key_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    canvas_div.keydown('key_press', canvas_keyboard_event);\n",
       "    canvas_div.keyup('key_release', canvas_keyboard_event);\n",
       "    this.canvas_div = canvas_div\n",
       "    this._canvas_extra_style(canvas_div)\n",
       "    this.root.append(canvas_div);\n",
       "\n",
       "    var canvas = $('<canvas/>');\n",
       "    canvas.addClass('mpl-canvas');\n",
       "    canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
       "\n",
       "    this.canvas = canvas[0];\n",
       "    this.context = canvas[0].getContext(\"2d\");\n",
       "\n",
       "    var backingStore = this.context.backingStorePixelRatio ||\n",
       "\tthis.context.webkitBackingStorePixelRatio ||\n",
       "\tthis.context.mozBackingStorePixelRatio ||\n",
       "\tthis.context.msBackingStorePixelRatio ||\n",
       "\tthis.context.oBackingStorePixelRatio ||\n",
       "\tthis.context.backingStorePixelRatio || 1;\n",
       "\n",
       "    mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
       "\n",
       "    var rubberband = $('<canvas/>');\n",
       "    rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
       "\n",
       "    var pass_mouse_events = true;\n",
       "\n",
       "    canvas_div.resizable({\n",
       "        start: function(event, ui) {\n",
       "            pass_mouse_events = false;\n",
       "        },\n",
       "        resize: function(event, ui) {\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "        stop: function(event, ui) {\n",
       "            pass_mouse_events = true;\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "    });\n",
       "\n",
       "    function mouse_event_fn(event) {\n",
       "        if (pass_mouse_events)\n",
       "            return fig.mouse_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    rubberband.mousedown('button_press', mouse_event_fn);\n",
       "    rubberband.mouseup('button_release', mouse_event_fn);\n",
       "    // Throttle sequential mouse events to 1 every 20ms.\n",
       "    rubberband.mousemove('motion_notify', mouse_event_fn);\n",
       "\n",
       "    rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
       "    rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
       "\n",
       "    canvas_div.on(\"wheel\", function (event) {\n",
       "        event = event.originalEvent;\n",
       "        event['data'] = 'scroll'\n",
       "        if (event.deltaY < 0) {\n",
       "            event.step = 1;\n",
       "        } else {\n",
       "            event.step = -1;\n",
       "        }\n",
       "        mouse_event_fn(event);\n",
       "    });\n",
       "\n",
       "    canvas_div.append(canvas);\n",
       "    canvas_div.append(rubberband);\n",
       "\n",
       "    this.rubberband = rubberband;\n",
       "    this.rubberband_canvas = rubberband[0];\n",
       "    this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
       "    this.rubberband_context.strokeStyle = \"#000000\";\n",
       "\n",
       "    this._resize_canvas = function(width, height) {\n",
       "        // Keep the size of the canvas, canvas container, and rubber band\n",
       "        // canvas in synch.\n",
       "        canvas_div.css('width', width)\n",
       "        canvas_div.css('height', height)\n",
       "\n",
       "        canvas.attr('width', width * mpl.ratio);\n",
       "        canvas.attr('height', height * mpl.ratio);\n",
       "        canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
       "\n",
       "        rubberband.attr('width', width);\n",
       "        rubberband.attr('height', height);\n",
       "    }\n",
       "\n",
       "    // Set the figure to an initial 600x600px, this will subsequently be updated\n",
       "    // upon first draw.\n",
       "    this._resize_canvas(600, 600);\n",
       "\n",
       "    // Disable right mouse context menu.\n",
       "    $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
       "        return false;\n",
       "    });\n",
       "\n",
       "    function set_focus () {\n",
       "        canvas.focus();\n",
       "        canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    window.setTimeout(set_focus, 100);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>')\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            // put a spacer in here.\n",
       "            continue;\n",
       "        }\n",
       "        var button = $('<button/>');\n",
       "        button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
       "                        'ui-button-icon-only');\n",
       "        button.attr('role', 'button');\n",
       "        button.attr('aria-disabled', 'false');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "\n",
       "        var icon_img = $('<span/>');\n",
       "        icon_img.addClass('ui-button-icon-primary ui-icon');\n",
       "        icon_img.addClass(image);\n",
       "        icon_img.addClass('ui-corner-all');\n",
       "\n",
       "        var tooltip_span = $('<span/>');\n",
       "        tooltip_span.addClass('ui-button-text');\n",
       "        tooltip_span.html(tooltip);\n",
       "\n",
       "        button.append(icon_img);\n",
       "        button.append(tooltip_span);\n",
       "\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    var fmt_picker_span = $('<span/>');\n",
       "\n",
       "    var fmt_picker = $('<select/>');\n",
       "    fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
       "    fmt_picker_span.append(fmt_picker);\n",
       "    nav_element.append(fmt_picker_span);\n",
       "    this.format_dropdown = fmt_picker[0];\n",
       "\n",
       "    for (var ind in mpl.extensions) {\n",
       "        var fmt = mpl.extensions[ind];\n",
       "        var option = $(\n",
       "            '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
       "        fmt_picker.append(option)\n",
       "    }\n",
       "\n",
       "    // Add hover states to the ui-buttons\n",
       "    $( \".ui-button\" ).hover(\n",
       "        function() { $(this).addClass(\"ui-state-hover\");},\n",
       "        function() { $(this).removeClass(\"ui-state-hover\");}\n",
       "    );\n",
       "\n",
       "    var status_bar = $('<span class=\"mpl-message\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
       "    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
       "    // which will in turn request a refresh of the image.\n",
       "    this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_message = function(type, properties) {\n",
       "    properties['type'] = type;\n",
       "    properties['figure_id'] = this.id;\n",
       "    this.ws.send(JSON.stringify(properties));\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_draw_message = function() {\n",
       "    if (!this.waiting) {\n",
       "        this.waiting = true;\n",
       "        this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    var format_dropdown = fig.format_dropdown;\n",
       "    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
       "    fig.ondownload(fig, format);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
       "    var size = msg['size'];\n",
       "    if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
       "        fig._resize_canvas(size[0], size[1]);\n",
       "        fig.send_message(\"refresh\", {});\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
       "    var x0 = msg['x0'] / mpl.ratio;\n",
       "    var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
       "    var x1 = msg['x1'] / mpl.ratio;\n",
       "    var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
       "    x0 = Math.floor(x0) + 0.5;\n",
       "    y0 = Math.floor(y0) + 0.5;\n",
       "    x1 = Math.floor(x1) + 0.5;\n",
       "    y1 = Math.floor(y1) + 0.5;\n",
       "    var min_x = Math.min(x0, x1);\n",
       "    var min_y = Math.min(y0, y1);\n",
       "    var width = Math.abs(x1 - x0);\n",
       "    var height = Math.abs(y1 - y0);\n",
       "\n",
       "    fig.rubberband_context.clearRect(\n",
       "        0, 0, fig.canvas.width, fig.canvas.height);\n",
       "\n",
       "    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
       "    // Updates the figure title.\n",
       "    fig.header.textContent = msg['label'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
       "    var cursor = msg['cursor'];\n",
       "    switch(cursor)\n",
       "    {\n",
       "    case 0:\n",
       "        cursor = 'pointer';\n",
       "        break;\n",
       "    case 1:\n",
       "        cursor = 'default';\n",
       "        break;\n",
       "    case 2:\n",
       "        cursor = 'crosshair';\n",
       "        break;\n",
       "    case 3:\n",
       "        cursor = 'move';\n",
       "        break;\n",
       "    }\n",
       "    fig.rubberband_canvas.style.cursor = cursor;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
       "    fig.message.textContent = msg['message'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
       "    // Request the server to send over a new figure.\n",
       "    fig.send_draw_message();\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
       "    fig.image_mode = msg['mode'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Called whenever the canvas gets updated.\n",
       "    this.send_message(\"ack\", {});\n",
       "}\n",
       "\n",
       "// A function to construct a web socket function for onmessage handling.\n",
       "// Called in the figure constructor.\n",
       "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
       "    return function socket_on_message(evt) {\n",
       "        if (evt.data instanceof Blob) {\n",
       "            /* FIXME: We get \"Resource interpreted as Image but\n",
       "             * transferred with MIME type text/plain:\" errors on\n",
       "             * Chrome.  But how to set the MIME type?  It doesn't seem\n",
       "             * to be part of the websocket stream */\n",
       "            evt.data.type = \"image/png\";\n",
       "\n",
       "            /* Free the memory for the previous frames */\n",
       "            if (fig.imageObj.src) {\n",
       "                (window.URL || window.webkitURL).revokeObjectURL(\n",
       "                    fig.imageObj.src);\n",
       "            }\n",
       "\n",
       "            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
       "                evt.data);\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "        else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
       "            fig.imageObj.src = evt.data;\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        var msg = JSON.parse(evt.data);\n",
       "        var msg_type = msg['type'];\n",
       "\n",
       "        // Call the  \"handle_{type}\" callback, which takes\n",
       "        // the figure and JSON message as its only arguments.\n",
       "        try {\n",
       "            var callback = fig[\"handle_\" + msg_type];\n",
       "        } catch (e) {\n",
       "            console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        if (callback) {\n",
       "            try {\n",
       "                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
       "                callback(fig, msg);\n",
       "            } catch (e) {\n",
       "                console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
       "            }\n",
       "        }\n",
       "    };\n",
       "}\n",
       "\n",
       "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
       "mpl.findpos = function(e) {\n",
       "    //this section is from http://www.quirksmode.org/js/events_properties.html\n",
       "    var targ;\n",
       "    if (!e)\n",
       "        e = window.event;\n",
       "    if (e.target)\n",
       "        targ = e.target;\n",
       "    else if (e.srcElement)\n",
       "        targ = e.srcElement;\n",
       "    if (targ.nodeType == 3) // defeat Safari bug\n",
       "        targ = targ.parentNode;\n",
       "\n",
       "    // jQuery normalizes the pageX and pageY\n",
       "    // pageX,Y are the mouse positions relative to the document\n",
       "    // offset() returns the position of the element relative to the document\n",
       "    var x = e.pageX - $(targ).offset().left;\n",
       "    var y = e.pageY - $(targ).offset().top;\n",
       "\n",
       "    return {\"x\": x, \"y\": y};\n",
       "};\n",
       "\n",
       "/*\n",
       " * return a copy of an object with only non-object keys\n",
       " * we need this to avoid circular references\n",
       " * http://stackoverflow.com/a/24161582/3208463\n",
       " */\n",
       "function simpleKeys (original) {\n",
       "  return Object.keys(original).reduce(function (obj, key) {\n",
       "    if (typeof original[key] !== 'object')\n",
       "        obj[key] = original[key]\n",
       "    return obj;\n",
       "  }, {});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.mouse_event = function(event, name) {\n",
       "    var canvas_pos = mpl.findpos(event)\n",
       "\n",
       "    if (name === 'button_press')\n",
       "    {\n",
       "        this.canvas.focus();\n",
       "        this.canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    var x = canvas_pos.x * mpl.ratio;\n",
       "    var y = canvas_pos.y * mpl.ratio;\n",
       "\n",
       "    this.send_message(name, {x: x, y: y, button: event.button,\n",
       "                             step: event.step,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "\n",
       "    /* This prevents the web browser from automatically changing to\n",
       "     * the text insertion cursor when the button is pressed.  We want\n",
       "     * to control all of the cursor setting manually through the\n",
       "     * 'cursor' event from matplotlib */\n",
       "    event.preventDefault();\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    // Handle any extra behaviour associated with a key event\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.key_event = function(event, name) {\n",
       "\n",
       "    // Prevent repeat events\n",
       "    if (name == 'key_press')\n",
       "    {\n",
       "        if (event.which === this._key)\n",
       "            return;\n",
       "        else\n",
       "            this._key = event.which;\n",
       "    }\n",
       "    if (name == 'key_release')\n",
       "        this._key = null;\n",
       "\n",
       "    var value = '';\n",
       "    if (event.ctrlKey && event.which != 17)\n",
       "        value += \"ctrl+\";\n",
       "    if (event.altKey && event.which != 18)\n",
       "        value += \"alt+\";\n",
       "    if (event.shiftKey && event.which != 16)\n",
       "        value += \"shift+\";\n",
       "\n",
       "    value += 'k';\n",
       "    value += event.which.toString();\n",
       "\n",
       "    this._key_event_extra(event, name);\n",
       "\n",
       "    this.send_message(name, {key: value,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
       "    if (name == 'download') {\n",
       "        this.handle_save(this, null);\n",
       "    } else {\n",
       "        this.send_message(\"toolbar_button\", {name: name});\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
       "    this.message.textContent = tooltip;\n",
       "};\n",
       "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to  previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
       "\n",
       "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
       "\n",
       "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
       "    // Create a \"websocket\"-like object which calls the given IPython comm\n",
       "    // object with the appropriate methods. Currently this is a non binary\n",
       "    // socket, so there is still some room for performance tuning.\n",
       "    var ws = {};\n",
       "\n",
       "    ws.close = function() {\n",
       "        comm.close()\n",
       "    };\n",
       "    ws.send = function(m) {\n",
       "        //console.log('sending', m);\n",
       "        comm.send(m);\n",
       "    };\n",
       "    // Register the callback with on_msg.\n",
       "    comm.on_msg(function(msg) {\n",
       "        //console.log('receiving', msg['content']['data'], msg);\n",
       "        // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
       "        ws.onmessage(msg['content']['data'])\n",
       "    });\n",
       "    return ws;\n",
       "}\n",
       "\n",
       "mpl.mpl_figure_comm = function(comm, msg) {\n",
       "    // This is the function which gets called when the mpl process\n",
       "    // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
       "\n",
       "    var id = msg.content.data.id;\n",
       "    // Get hold of the div created by the display call when the Comm\n",
       "    // socket was opened in Python.\n",
       "    var element = $(\"#\" + id);\n",
       "    var ws_proxy = comm_websocket_adapter(comm)\n",
       "\n",
       "    function ondownload(figure, format) {\n",
       "        window.open(figure.imageObj.src);\n",
       "    }\n",
       "\n",
       "    var fig = new mpl.figure(id, ws_proxy,\n",
       "                           ondownload,\n",
       "                           element.get(0));\n",
       "\n",
       "    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
       "    // web socket which is closed, not our websocket->open comm proxy.\n",
       "    ws_proxy.onopen();\n",
       "\n",
       "    fig.parent_element = element.get(0);\n",
       "    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
       "    if (!fig.cell_info) {\n",
       "        console.error(\"Failed to find cell for figure\", id, fig);\n",
       "        return;\n",
       "    }\n",
       "\n",
       "    var output_index = fig.cell_info[2]\n",
       "    var cell = fig.cell_info[0];\n",
       "\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
       "    var width = fig.canvas.width/mpl.ratio\n",
       "    fig.root.unbind('remove')\n",
       "\n",
       "    // Update the output cell to use the data from the current canvas.\n",
       "    fig.push_to_output();\n",
       "    var dataURL = fig.canvas.toDataURL();\n",
       "    // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
       "    // the notebook keyboard shortcuts fail.\n",
       "    IPython.keyboard_manager.enable()\n",
       "    $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
       "    fig.close_ws(fig, msg);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.close_ws = function(fig, msg){\n",
       "    fig.send_message('closing', msg);\n",
       "    // fig.ws.close()\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
       "    // Turn the data on the canvas into data in the output cell.\n",
       "    var width = this.canvas.width/mpl.ratio\n",
       "    var dataURL = this.canvas.toDataURL();\n",
       "    this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Tell IPython that the notebook contents must change.\n",
       "    IPython.notebook.set_dirty(true);\n",
       "    this.send_message(\"ack\", {});\n",
       "    var fig = this;\n",
       "    // Wait a second, then push the new image to the DOM so\n",
       "    // that it is saved nicely (might be nice to debounce this).\n",
       "    setTimeout(function () { fig.push_to_output() }, 1000);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>')\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items){\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) { continue; };\n",
       "\n",
       "        var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    // Add the status bar.\n",
       "    var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "\n",
       "    // Add the close button to the window.\n",
       "    var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
       "    var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
       "    button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
       "    button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
       "    buttongrp.append(button);\n",
       "    var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
       "    titlebar.prepend(buttongrp);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(el){\n",
       "    var fig = this\n",
       "    el.on(\"remove\", function(){\n",
       "\tfig.close_ws(fig, {});\n",
       "    });\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(el){\n",
       "    // this is important to make the div 'focusable\n",
       "    el.attr('tabindex', 0)\n",
       "    // reach out to IPython and tell the keyboard manager to turn it's self\n",
       "    // off when our div gets focus\n",
       "\n",
       "    // location in version 3\n",
       "    if (IPython.notebook.keyboard_manager) {\n",
       "        IPython.notebook.keyboard_manager.register_events(el);\n",
       "    }\n",
       "    else {\n",
       "        // location in version 2\n",
       "        IPython.keyboard_manager.register_events(el);\n",
       "    }\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    var manager = IPython.notebook.keyboard_manager;\n",
       "    if (!manager)\n",
       "        manager = IPython.keyboard_manager;\n",
       "\n",
       "    // Check for shift+enter\n",
       "    if (event.shiftKey && event.which == 13) {\n",
       "        this.canvas_div.blur();\n",
       "        event.shiftKey = false;\n",
       "        // Send a \"J\" for go to next cell\n",
       "        event.which = 74;\n",
       "        event.keyCode = 74;\n",
       "        manager.command_mode();\n",
       "        manager.handle_keydown(event);\n",
       "    }\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    fig.ondownload(fig, null);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.find_output_cell = function(html_output) {\n",
       "    // Return the cell and output element which can be found *uniquely* in the notebook.\n",
       "    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
       "    // IPython event is triggered only after the cells have been serialised, which for\n",
       "    // our purposes (turning an active figure into a static one), is too late.\n",
       "    var cells = IPython.notebook.get_cells();\n",
       "    var ncells = cells.length;\n",
       "    for (var i=0; i<ncells; i++) {\n",
       "        var cell = cells[i];\n",
       "        if (cell.cell_type === 'code'){\n",
       "            for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
       "                var data = cell.output_area.outputs[j];\n",
       "                if (data.data) {\n",
       "                    // IPython >= 3 moved mimebundle to data attribute of output\n",
       "                    data = data.data;\n",
       "                }\n",
       "                if (data['text/html'] == html_output) {\n",
       "                    return [cell, data, j];\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "// Register the function which deals with the matplotlib target/channel.\n",
       "// The kernel may be null if the page has been refreshed.\n",
       "if (IPython.notebook.kernel != null) {\n",
       "    IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
       "}\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nO3deXhU5aHH8TMJWWCC7MiSkIgPgQEFREX0KqkrixTUolYU4trLoiz16pWiohYQq9fW24BckGqpDqAGtFqLFhxDRQTUKEjYF8kFLKAGEGUZ+N0/cmdkkklIwryZdzLfz/O8D+TkZM6b8/jo17M6AgAAQFxxoj0BAAAA1C4CEAAAIM4QgAAAAHGGAAQAAIgzBCAAAECcIQABAADiDAEIAAAQZwhAAACAOEMAAgAAxBkCEAAAIM4QgAAAAHGGAAQAAIgzBCAAAECcIQABAADiDAEIIKZ9/PHHuu6665SRkaHk5GS1bNlSvXr10q9//etoT61GHMcJGWeccYZycnL09ttvh6yXmZmp3Nzcan/+oUOHNHHiRPl8vshMGEBMIgABxKy3335bCQkJuuKKKzR37lx98MEHmjt3ru6//361bds22tOrEcdxNHjwYC1fvlzLli3TX/7yF3Xs2FEulyskAmsagHv37pXjOJo4cWLkJg0g5hCAAGJW7969dfbZZ+vYsWPlvnf8+PGIbOPQoUMR+ZyqchxHo0aNClm2efNmOY6jq666KriMAARwOghAADGrS5cuuuiii6q8/iuvvKJevXrJ7XbL7XarW7dueuGFF4Lfz8nJUZcuXVRQUKCLL75Y9evX18033xz8/rx589SrVy81aNBAbrdb11xzjT777LNy21m1apV+/vOfq0mTJkpJSVH37t01f/78Ks0xXABKUosWLdShQ4fg1+EC8KuvvtKtt96qFi1aKDk5WZ06ddIzzzwTjOFt27aVO8XsOE6NQhJAbCMAAcSsu+++W47j6L777tPHH3+so0ePVrjuI488IsdxdMMNN+i1117Te++9p2effVaPPPJIcJ2cnBw1bdpUGRkZ+uMf/yifz6eCggJJ0uTJk+VyuXTnnXfq7bff1oIFC3TxxRfL7XZr7dq1wc94//33lZycrMsuu0zz58/XokWLdPvtt8txHL344oun/J3CBeC3336rhIQEXXLJJcFlZQNwz549atu2rVq0aKEZM2Zo0aJFuvfee+U4jkaMGCFJOnz4sBYtWiTHcXTXXXdp+fLlWr58uTZv3nzKeQGoWwhAADFr3759uvTSS4NHspKSknTJJZfoySef1MGDB4Prbd26VYmJibr1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\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib notebook\n",
    "smpca.plot_scree();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This suggets that 1 component would be the right number.  Note that the vertical axis is the eigenvalue on a log scale, _not_ the more common proportion of variance explained."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Biplot\n",
    "\n",
    "No biplot for you!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loadings/Rotations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "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>comp_00</th>\n",
       "      <th>comp_01</th>\n",
       "      <th>comp_02</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>CRIM</th>\n",
       "      <td>0.240962</td>\n",
       "      <td>-0.065950</td>\n",
       "      <td>0.393820</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ZN</th>\n",
       "      <td>-0.245618</td>\n",
       "      <td>-0.147745</td>\n",
       "      <td>0.394760</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>INDUS</th>\n",
       "      <td>0.332027</td>\n",
       "      <td>0.126979</td>\n",
       "      <td>-0.065289</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CHAS</th>\n",
       "      <td>-0.004989</td>\n",
       "      <td>0.410562</td>\n",
       "      <td>-0.125809</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>NOX</th>\n",
       "      <td>0.325298</td>\n",
       "      <td>0.254262</td>\n",
       "      <td>-0.046524</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>RM</th>\n",
       "      <td>-0.203014</td>\n",
       "      <td>0.434305</td>\n",
       "      <td>0.352838</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>AGE</th>\n",
       "      <td>0.297132</td>\n",
       "      <td>0.260158</td>\n",
       "      <td>-0.200950</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>DIS</th>\n",
       "      <td>-0.298328</td>\n",
       "      <td>-0.359005</td>\n",
       "      <td>0.156994</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>RAD</th>\n",
       "      <td>0.303431</td>\n",
       "      <td>0.031323</td>\n",
       "      <td>0.420101</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TAX</th>\n",
       "      <td>0.324095</td>\n",
       "      <td>0.008978</td>\n",
       "      <td>0.344904</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PTRATIO</th>\n",
       "      <td>0.207762</td>\n",
       "      <td>-0.314675</td>\n",
       "      <td>0.001774</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>B</th>\n",
       "      <td>-0.196425</td>\n",
       "      <td>0.025932</td>\n",
       "      <td>-0.359408</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>LSTAT</th>\n",
       "      <td>0.311485</td>\n",
       "      <td>-0.201303</td>\n",
       "      <td>-0.161419</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MEDV</th>\n",
       "      <td>-0.266727</td>\n",
       "      <td>0.444997</td>\n",
       "      <td>0.163144</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          comp_00   comp_01   comp_02\n",
       "CRIM     0.240962 -0.065950  0.393820\n",
       "ZN      -0.245618 -0.147745  0.394760\n",
       "INDUS    0.332027  0.126979 -0.065289\n",
       "CHAS    -0.004989  0.410562 -0.125809\n",
       "NOX      0.325298  0.254262 -0.046524\n",
       "RM      -0.203014  0.434305  0.352838\n",
       "AGE      0.297132  0.260158 -0.200950\n",
       "DIS     -0.298328 -0.359005  0.156994\n",
       "RAD      0.303431  0.031323  0.420101\n",
       "TAX      0.324095  0.008978  0.344904\n",
       "PTRATIO  0.207762 -0.314675  0.001774\n",
       "B       -0.196425  0.025932 -0.359408\n",
       "LSTAT    0.311485 -0.201303 -0.161419\n",
       "MEDV    -0.266727  0.444997  0.163144"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "smpca.loadings.iloc[:,0:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# H2O\n",
    "\n",
    "Overall I'm not very pleased with the PCA implementation in H2O; it doesn't offer much functionality and the UI is awkward."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Init"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Checking whether there is an H2O instance running at http://localhost:54321..... not found.\n",
      "Attempting to start a local H2O server...\n",
      "  Java Version: java version \"1.7.0_71\"; Java(TM) SE Runtime Environment (build 1.7.0_71-b14); Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)\n",
      "  Starting server from /Users/terran/.pyenv/versions/anaconda3-5.2.0/lib/python3.6/site-packages/h2o/backend/bin/h2o.jar\n",
      "  Ice root: /var/folders/55/2417s3bs6s977dvsrs15x3n00000gp/T/tmpunlw44_o\n",
      "  JVM stdout: /var/folders/55/2417s3bs6s977dvsrs15x3n00000gp/T/tmpunlw44_o/h2o_terran_started_from_python.out\n",
      "  JVM stderr: /var/folders/55/2417s3bs6s977dvsrs15x3n00000gp/T/tmpunlw44_o/h2o_terran_started_from_python.err\n",
      "  Server is running at http://127.0.0.1:54321\n",
      "Connecting to H2O server at http://127.0.0.1:54321... successful.\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div style=\"overflow:auto\"><table style=\"width:50%\"><tr><td>H2O cluster uptime:</td>\n",
       "<td>03 secs</td></tr>\n",
       "<tr><td>H2O cluster timezone:</td>\n",
       "<td>America/New_York</td></tr>\n",
       "<tr><td>H2O data parsing timezone:</td>\n",
       "<td>UTC</td></tr>\n",
       "<tr><td>H2O cluster version:</td>\n",
       "<td>3.22.0.2</td></tr>\n",
       "<tr><td>H2O cluster version age:</td>\n",
       "<td>1 month and 23 days </td></tr>\n",
       "<tr><td>H2O cluster name:</td>\n",
       "<td>H2O_from_python_terran_96nm83</td></tr>\n",
       "<tr><td>H2O cluster total nodes:</td>\n",
       "<td>1</td></tr>\n",
       "<tr><td>H2O cluster free memory:</td>\n",
       "<td>1.778 Gb</td></tr>\n",
       "<tr><td>H2O cluster total cores:</td>\n",
       "<td>4</td></tr>\n",
       "<tr><td>H2O cluster allowed cores:</td>\n",
       "<td>4</td></tr>\n",
       "<tr><td>H2O cluster status:</td>\n",
       "<td>accepting new members, healthy</td></tr>\n",
       "<tr><td>H2O connection url:</td>\n",
       "<td>http://127.0.0.1:54321</td></tr>\n",
       "<tr><td>H2O connection proxy:</td>\n",
       "<td>None</td></tr>\n",
       "<tr><td>H2O internal security:</td>\n",
       "<td>False</td></tr>\n",
       "<tr><td>H2O API Extensions:</td>\n",
       "<td>AutoML, XGBoost, Algos, Core V3, Core V4</td></tr>\n",
       "<tr><td>Python version:</td>\n",
       "<td>3.6.5 final</td></tr></table></div>"
      ],
      "text/plain": [
       "--------------------------  ----------------------------------------\n",
       "H2O cluster uptime:         03 secs\n",
       "H2O cluster timezone:       America/New_York\n",
       "H2O data parsing timezone:  UTC\n",
       "H2O cluster version:        3.22.0.2\n",
       "H2O cluster version age:    1 month and 23 days\n",
       "H2O cluster name:           H2O_from_python_terran_96nm83\n",
       "H2O cluster total nodes:    1\n",
       "H2O cluster free memory:    1.778 Gb\n",
       "H2O cluster total cores:    4\n",
       "H2O cluster allowed cores:  4\n",
       "H2O cluster status:         accepting new members, healthy\n",
       "H2O connection url:         http://127.0.0.1:54321\n",
       "H2O connection proxy:\n",
       "H2O internal security:      False\n",
       "H2O API Extensions:         AutoML, XGBoost, Algos, Core V3, Core V4\n",
       "Python version:             3.6.5 final\n",
       "--------------------------  ----------------------------------------"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import h2o\n",
    "h2o.init()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Loading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Parse progress: |█████████████████████████████████████████████████████████| 100%\n"
     ]
    }
   ],
   "source": [
    "hbos = h2o.H2OFrame(Boston, destination_frame=\"Boston\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "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>key</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Boston</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      key\n",
       "0  Boston"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "h2o.ls()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<thead>\n",
       "<tr><th style=\"text-align: right;\">   CRIM</th><th style=\"text-align: right;\">  ZN</th><th style=\"text-align: right;\">  INDUS</th><th style=\"text-align: right;\">  CHAS</th><th style=\"text-align: right;\">  NOX</th><th style=\"text-align: right;\">   RM</th><th style=\"text-align: right;\">  AGE</th><th style=\"text-align: right;\">   DIS</th><th style=\"text-align: right;\">  RAD</th><th style=\"text-align: right;\">  TAX</th><th style=\"text-align: right;\">  PTRATIO</th><th style=\"text-align: right;\">     B</th><th style=\"text-align: right;\">  LSTAT</th><th style=\"text-align: right;\">  MEDV</th></tr>\n",
       "</thead>\n",
       "<tbody>\n",
       "<tr><td style=\"text-align: right;\">0.00632</td><td style=\"text-align: right;\">18  </td><td style=\"text-align: right;\">   2.31</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.538</td><td style=\"text-align: right;\">6.575</td><td style=\"text-align: right;\"> 65.2</td><td style=\"text-align: right;\">4.09  </td><td style=\"text-align: right;\">    1</td><td style=\"text-align: right;\">  296</td><td style=\"text-align: right;\">     15.3</td><td style=\"text-align: right;\">396.9 </td><td style=\"text-align: right;\">   4.98</td><td style=\"text-align: right;\">  24  </td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.02731</td><td style=\"text-align: right;\"> 0  </td><td style=\"text-align: right;\">   7.07</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.469</td><td style=\"text-align: right;\">6.421</td><td style=\"text-align: right;\"> 78.9</td><td style=\"text-align: right;\">4.9671</td><td style=\"text-align: right;\">    2</td><td style=\"text-align: right;\">  242</td><td style=\"text-align: right;\">     17.8</td><td style=\"text-align: right;\">396.9 </td><td style=\"text-align: right;\">   9.14</td><td style=\"text-align: right;\">  21.6</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.02729</td><td style=\"text-align: right;\"> 0  </td><td style=\"text-align: right;\">   7.07</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.469</td><td style=\"text-align: right;\">7.185</td><td style=\"text-align: right;\"> 61.1</td><td style=\"text-align: right;\">4.9671</td><td style=\"text-align: right;\">    2</td><td style=\"text-align: right;\">  242</td><td style=\"text-align: right;\">     17.8</td><td style=\"text-align: right;\">392.83</td><td style=\"text-align: right;\">   4.03</td><td style=\"text-align: right;\">  34.7</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.03237</td><td style=\"text-align: right;\"> 0  </td><td style=\"text-align: right;\">   2.18</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.458</td><td style=\"text-align: right;\">6.998</td><td style=\"text-align: right;\"> 45.8</td><td style=\"text-align: right;\">6.0622</td><td style=\"text-align: right;\">    3</td><td style=\"text-align: right;\">  222</td><td style=\"text-align: right;\">     18.7</td><td style=\"text-align: right;\">394.63</td><td style=\"text-align: right;\">   2.94</td><td style=\"text-align: right;\">  33.4</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.06905</td><td style=\"text-align: right;\"> 0  </td><td style=\"text-align: right;\">   2.18</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.458</td><td style=\"text-align: right;\">7.147</td><td style=\"text-align: right;\"> 54.2</td><td style=\"text-align: right;\">6.0622</td><td style=\"text-align: right;\">    3</td><td style=\"text-align: right;\">  222</td><td style=\"text-align: right;\">     18.7</td><td style=\"text-align: right;\">396.9 </td><td style=\"text-align: right;\">   5.33</td><td style=\"text-align: right;\">  36.2</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.02985</td><td style=\"text-align: right;\"> 0  </td><td style=\"text-align: right;\">   2.18</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.458</td><td style=\"text-align: right;\">6.43 </td><td style=\"text-align: right;\"> 58.7</td><td style=\"text-align: right;\">6.0622</td><td style=\"text-align: right;\">    3</td><td style=\"text-align: right;\">  222</td><td style=\"text-align: right;\">     18.7</td><td style=\"text-align: right;\">394.12</td><td style=\"text-align: right;\">   5.21</td><td style=\"text-align: right;\">  28.7</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.08829</td><td style=\"text-align: right;\">12.5</td><td style=\"text-align: right;\">   7.87</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.524</td><td style=\"text-align: right;\">6.012</td><td style=\"text-align: right;\"> 66.6</td><td style=\"text-align: right;\">5.5605</td><td style=\"text-align: right;\">    5</td><td style=\"text-align: right;\">  311</td><td style=\"text-align: right;\">     15.2</td><td style=\"text-align: right;\">395.6 </td><td style=\"text-align: right;\">  12.43</td><td style=\"text-align: right;\">  22.9</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.14455</td><td style=\"text-align: right;\">12.5</td><td style=\"text-align: right;\">   7.87</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.524</td><td style=\"text-align: right;\">6.172</td><td style=\"text-align: right;\"> 96.1</td><td style=\"text-align: right;\">5.9505</td><td style=\"text-align: right;\">    5</td><td style=\"text-align: right;\">  311</td><td style=\"text-align: right;\">     15.2</td><td style=\"text-align: right;\">396.9 </td><td style=\"text-align: right;\">  19.15</td><td style=\"text-align: right;\">  27.1</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.21124</td><td style=\"text-align: right;\">12.5</td><td style=\"text-align: right;\">   7.87</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.524</td><td style=\"text-align: right;\">5.631</td><td style=\"text-align: right;\">100  </td><td style=\"text-align: right;\">6.0821</td><td style=\"text-align: right;\">    5</td><td style=\"text-align: right;\">  311</td><td style=\"text-align: right;\">     15.2</td><td style=\"text-align: right;\">386.63</td><td style=\"text-align: right;\">  29.93</td><td style=\"text-align: right;\">  16.5</td></tr>\n",
       "<tr><td style=\"text-align: right;\">0.17004</td><td style=\"text-align: right;\">12.5</td><td style=\"text-align: right;\">   7.87</td><td style=\"text-align: right;\">     0</td><td style=\"text-align: right;\">0.524</td><td style=\"text-align: right;\">6.004</td><td style=\"text-align: right;\"> 85.9</td><td style=\"text-align: right;\">6.5921</td><td style=\"text-align: right;\">    5</td><td style=\"text-align: right;\">  311</td><td style=\"text-align: right;\">     15.2</td><td style=\"text-align: right;\">386.71</td><td style=\"text-align: right;\">  17.1 </td><td style=\"text-align: right;\">  18.9</td></tr>\n",
       "</tbody>\n",
       "</table>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": []
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hbos"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Fitting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# In h2o, it is mandatory to state the number of components to keep - it does not just assume\n",
    "# full rank if unspecified.\n",
    "modpca = h2o.estimators.pca.H2OPrincipalComponentAnalysisEstimator(\n",
    "    transform='standardize',k=9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pca Model Build progress: |███████████████████████████████████████████████| 100%\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/terran/.pyenv/versions/anaconda3-5.2.0/lib/python3.6/site-packages/h2o/job.py:69: UserWarning: _train: Dataset used may contain fewer number of rows due to removal of rows with NA/missing values.  If this is not desirable, set impute_missing argument in pca call to TRUE/True/true/... depending on the client language.\n",
      "  warnings.warn(w)\n"
     ]
    }
   ],
   "source": [
    "# It is mandatory to state which columns are to be used for x\n",
    "modpca.train(x=list(range(hbos.ncol)),training_frame=hbos)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "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></th>\n",
       "      <th>pc1</th>\n",
       "      <th>pc2</th>\n",
       "      <th>pc3</th>\n",
       "      <th>pc4</th>\n",
       "      <th>pc5</th>\n",
       "      <th>pc6</th>\n",
       "      <th>pc7</th>\n",
       "      <th>pc8</th>\n",
       "      <th>pc9</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Standard deviation</td>\n",
       "      <td>2.55769</td>\n",
       "      <td>1.284347</td>\n",
       "      <td>1.160291</td>\n",
       "      <td>0.941489</td>\n",
       "      <td>0.922435</td>\n",
       "      <td>0.813827</td>\n",
       "      <td>0.734218</td>\n",
       "      <td>0.635248</td>\n",
       "      <td>0.527020</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Proportion of Variance</td>\n",
       "      <td>0.46727</td>\n",
       "      <td>0.117825</td>\n",
       "      <td>0.096162</td>\n",
       "      <td>0.063314</td>\n",
       "      <td>0.060778</td>\n",
       "      <td>0.047308</td>\n",
       "      <td>0.038505</td>\n",
       "      <td>0.028824</td>\n",
       "      <td>0.019839</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Cumulative Proportion</td>\n",
       "      <td>0.46727</td>\n",
       "      <td>0.585095</td>\n",
       "      <td>0.681257</td>\n",
       "      <td>0.744571</td>\n",
       "      <td>0.805349</td>\n",
       "      <td>0.852657</td>\n",
       "      <td>0.891163</td>\n",
       "      <td>0.919987</td>\n",
       "      <td>0.939826</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                               pc1       pc2       pc3       pc4       pc5  \\\n",
       "0      Standard deviation  2.55769  1.284347  1.160291  0.941489  0.922435   \n",
       "1  Proportion of Variance  0.46727  0.117825  0.096162  0.063314  0.060778   \n",
       "2   Cumulative Proportion  0.46727  0.585095  0.681257  0.744571  0.805349   \n",
       "\n",
       "        pc6       pc7       pc8       pc9  \n",
       "0  0.813827  0.734218  0.635248  0.527020  \n",
       "1  0.047308  0.038505  0.028824  0.019839  \n",
       "2  0.852657  0.891163  0.919987  0.939826  "
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "modpca.varimp(use_pandas=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Scree Plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "KeyError('server',)\n"
     ]
    }
   ],
   "source": [
    "# Haha, no\n",
    "try:\n",
    "    modpca.screeplot()\n",
    "except Exception as e:\n",
    "    print(repr(e))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So I guess we're going to do it the manual way."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "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>index</th>\n",
       "      <th>Standard deviation</th>\n",
       "      <th>Proportion of Variance</th>\n",
       "      <th>Cumulative Proportion</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>pc1</td>\n",
       "      <td>2.55769</td>\n",
       "      <td>0.46727</td>\n",
       "      <td>0.46727</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>pc2</td>\n",
       "      <td>1.28435</td>\n",
       "      <td>0.117825</td>\n",
       "      <td>0.585095</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>pc3</td>\n",
       "      <td>1.16029</td>\n",
       "      <td>0.0961625</td>\n",
       "      <td>0.681257</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>pc4</td>\n",
       "      <td>0.941489</td>\n",
       "      <td>0.0633144</td>\n",
       "      <td>0.744571</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>pc5</td>\n",
       "      <td>0.922435</td>\n",
       "      <td>0.0607776</td>\n",
       "      <td>0.805349</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  index Standard deviation Proportion of Variance Cumulative Proportion\n",
       "0   pc1            2.55769                0.46727               0.46727\n",
       "1   pc2            1.28435               0.117825              0.585095\n",
       "2   pc3            1.16029              0.0961625              0.681257\n",
       "3   pc4           0.941489              0.0633144              0.744571\n",
       "4   pc5           0.922435              0.0607776              0.805349"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vi = modpca.varimp(use_pandas=True).transpose()\n",
    "# The column headers are now in the first row, so put that row back on the columns.\n",
    "vi.columns=vi.iloc[0,:]\n",
    "vi.drop('',inplace=True)\n",
    "# and, as always, remove the index before using with Altair\n",
    "vi.reset_index(inplace=True)\n",
    "vi.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "var spec = {\"config\": {\"view\": {\"width\": 400, \"height\": 300}}, \"data\": {\"name\": \"data-17b9964c12d26ddafb9df5f84b3340ac\"}, \"mark\": \"bar\", \"encoding\": {\"x\": {\"type\": \"nominal\", \"field\": \"index\"}, \"y\": {\"type\": \"quantitative\", \"field\": \"Proportion of Variance\"}}, \"selection\": {\"selector001\": {\"type\": \"interval\", \"bind\": \"scales\", \"encodings\": [\"x\", \"y\"]}}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v2.6.0.json\", \"datasets\": {\"data-17b9964c12d26ddafb9df5f84b3340ac\": [{\"index\": \"pc1\", \"Standard deviation\": 2.557689867282875, \"Proportion of Variance\": 0.467269818371535, \"Cumulative Proportion\": 0.467269818371535}, {\"index\": \"pc2\", \"Standard deviation\": 1.2843466906579748, \"Proportion of Variance\": 0.11782474441457794, \"Cumulative Proportion\": 0.5850945627861129}, {\"index\": \"pc3\", \"Standard deviation\": 1.1602907422135043, \"Proportion of Variance\": 0.0961624718904546, \"Cumulative Proportion\": 0.6812570346765675}, {\"index\": \"pc4\", \"Standard deviation\": 0.9414889049631343, \"Proportion of Variance\": 0.0633143827263344, \"Cumulative Proportion\": 0.7445714174029019}, {\"index\": \"pc5\", \"Standard deviation\": 0.9224346616795772, \"Proportion of Variance\": 0.06077755036199399, \"Cumulative Proportion\": 0.8053489677648958}, {\"index\": \"pc6\", \"Standard deviation\": 0.8138274372072686, \"Proportion of Variance\": 0.04730822125366789, \"Cumulative Proportion\": 0.8526571890185637}, {\"index\": \"pc7\", \"Standard deviation\": 0.7342175678652845, \"Proportion of Variance\": 0.038505388354429536, \"Cumulative Proportion\": 0.8911625773729932}, {\"index\": \"pc8\", \"Standard deviation\": 0.6352480646181379, \"Proportion of Variance\": 0.028824293114363554, \"Cumulative Proportion\": 0.9199868704873567}, {\"index\": \"pc9\", \"Standard deviation\": 0.5270198125919952, \"Proportion of Variance\": 0.019839277347464403, \"Cumulative Proportion\": 0.9398261478348211}]}};\n",
       "var opt = {};\n",
       "var type = \"vega-lite\";\n",
       "var id = \"b964e0ad-c3a2-42b9-940f-461ed43b940a\";\n",
       "\n",
       "var output_area = this;\n",
       "\n",
       "require([\"nbextensions/jupyter-vega/index\"], function(vega) {\n",
       "  var target = document.createElement(\"div\");\n",
       "  target.id = id;\n",
       "  target.className = \"vega-embed\";\n",
       "\n",
       "  var style = document.createElement(\"style\");\n",
       "  style.textContent = [\n",
       "    \".vega-embed .error p {\",\n",
       "    \"  color: firebrick;\",\n",
       "    \"  font-size: 14px;\",\n",
       "    \"}\",\n",
       "  ].join(\"\\\\n\");\n",
       "\n",
       "  // element is a jQuery wrapped DOM element inside the output area\n",
       "  // see http://ipython.readthedocs.io/en/stable/api/generated/\\\n",
       "  // IPython.display.html#IPython.display.Javascript.__init__\n",
       "  element[0].appendChild(target);\n",
       "  element[0].appendChild(style);\n",
       "\n",
       "  vega.render(\"#\" + id, spec, type, opt, output_area);\n",
       "}, function (err) {\n",
       "  if (err.requireType !== \"scripterror\") {\n",
       "    throw(err);\n",
       "  }\n",
       "});\n"
      ],
      "text/plain": [
       "<vega.vegalite.VegaLite at 0x11672d978>"
      ]
     },
     "metadata": {
      "jupyter-vega": "#b964e0ad-c3a2-42b9-940f-461ed43b940a"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": []
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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"
     },
     "metadata": {
      "jupyter-vega": "#b964e0ad-c3a2-42b9-940f-461ed43b940a"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "alt.Chart(vi).mark_bar().encode(\n",
    "   x='index',y='Proportion of Variance').interactive()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This suggests that reasonable choices would be 1 or 3 components to retain."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loadings/Rotations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "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></th>\n",
       "      <th>pc1</th>\n",
       "      <th>pc2</th>\n",
       "      <th>pc3</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>CRIM</td>\n",
       "      <td>-0.240962</td>\n",
       "      <td>-0.065950</td>\n",
       "      <td>-0.393820</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>ZN</td>\n",
       "      <td>0.245618</td>\n",
       "      <td>-0.147745</td>\n",
       "      <td>-0.394760</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>INDUS</td>\n",
       "      <td>-0.332027</td>\n",
       "      <td>0.126979</td>\n",
       "      <td>0.065289</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>CHAS</td>\n",
       "      <td>0.004989</td>\n",
       "      <td>0.410562</td>\n",
       "      <td>0.125809</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>NOX</td>\n",
       "      <td>-0.325298</td>\n",
       "      <td>0.254262</td>\n",
       "      <td>0.046524</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>RM</td>\n",
       "      <td>0.203014</td>\n",
       "      <td>0.434305</td>\n",
       "      <td>-0.352838</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>AGE</td>\n",
       "      <td>-0.297132</td>\n",
       "      <td>0.260158</td>\n",
       "      <td>0.200950</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>DIS</td>\n",
       "      <td>0.298328</td>\n",
       "      <td>-0.359005</td>\n",
       "      <td>-0.156994</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>RAD</td>\n",
       "      <td>-0.303431</td>\n",
       "      <td>0.031323</td>\n",
       "      <td>-0.420101</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>TAX</td>\n",
       "      <td>-0.324095</td>\n",
       "      <td>0.008978</td>\n",
       "      <td>-0.344904</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>PTRATIO</td>\n",
       "      <td>-0.207762</td>\n",
       "      <td>-0.314675</td>\n",
       "      <td>-0.001774</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>B</td>\n",
       "      <td>0.196425</td>\n",
       "      <td>0.025932</td>\n",
       "      <td>0.359408</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>LSTAT</td>\n",
       "      <td>-0.311485</td>\n",
       "      <td>-0.201303</td>\n",
       "      <td>0.161419</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>MEDV</td>\n",
       "      <td>0.266727</td>\n",
       "      <td>0.444997</td>\n",
       "      <td>-0.163144</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  pc1       pc2       pc3\n",
       "0      CRIM -0.240962 -0.065950 -0.393820\n",
       "1        ZN  0.245618 -0.147745 -0.394760\n",
       "2     INDUS -0.332027  0.126979  0.065289\n",
       "3      CHAS  0.004989  0.410562  0.125809\n",
       "4       NOX -0.325298  0.254262  0.046524\n",
       "5        RM  0.203014  0.434305 -0.352838\n",
       "6       AGE -0.297132  0.260158  0.200950\n",
       "7       DIS  0.298328 -0.359005 -0.156994\n",
       "8       RAD -0.303431  0.031323 -0.420101\n",
       "9       TAX -0.324095  0.008978 -0.344904\n",
       "10  PTRATIO -0.207762 -0.314675 -0.001774\n",
       "11        B  0.196425  0.025932  0.359408\n",
       "12    LSTAT -0.311485 -0.201303  0.161419\n",
       "13     MEDV  0.266727  0.444997 -0.163144"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "modpca.rotation().as_data_frame().iloc[:,0:4]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Comparison to R results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(ignore sign changes; those are arbitrary)\n",
    "```\n",
    "> prcomp(MASS::Boston,scale=T)$rotation[,1:3]\n",
    "                 PC1          PC2          PC3\n",
    "crim     0.242284451 -0.065873108  0.395077419\n",
    "zn      -0.245435005 -0.148002653  0.394545713\n",
    "indus    0.331859746  0.127075668 -0.066081913\n",
    "chas    -0.005027133  0.410668763 -0.125305293\n",
    "nox      0.325193880  0.254276363 -0.046475549\n",
    "rm      -0.202816554  0.434005810  0.353406095\n",
    "age      0.296976574  0.260303205 -0.200823078\n",
    "dis     -0.298169809 -0.359149977  0.157068710\n",
    "rad      0.303412754  0.031149596  0.418510334\n",
    "tax      0.324033052  0.008851406  0.343232194\n",
    "ptratio  0.207679535 -0.314623061  0.000399092\n",
    "black   -0.196638358  0.026481032 -0.361375914\n",
    "lstat    0.311397955 -0.201245177 -0.161060336\n",
    "medv    -0.266636396  0.444924411  0.163188735\n",
    "```"
   ]
  },
  {
   "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.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}