{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Basic Bayesian Linear Regression Implementation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "hideCode": false,
    "hidePrompt": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING (theano.tensor.blas): Using NumPy C-API based implementation for BLAS functions.\n"
     ]
    }
   ],
   "source": [
    "# Pandas and numpy for data manipulation\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# Matplotlib and seaborn for visualization\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline \n",
    "\n",
    "import seaborn as sns\n",
    "\n",
    "# Linear Regression to verify implementation\n",
    "from sklearn.linear_model import LinearRegression\n",
    "\n",
    "# Scipy for statistics\n",
    "import scipy\n",
    "\n",
    "# PyMC3 for Bayesian Inference\n",
    "import pymc3 as pm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hideCode": false,
    "hidePrompt": false
   },
   "source": [
    "# Load in Exercise Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "hideCode": false,
    "hidePrompt": false
   },
   "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>User_ID</th>\n",
       "      <th>Gender</th>\n",
       "      <th>Age</th>\n",
       "      <th>Height</th>\n",
       "      <th>Weight</th>\n",
       "      <th>Duration</th>\n",
       "      <th>Heart_Rate</th>\n",
       "      <th>Body_Temp</th>\n",
       "      <th>Calories</th>\n",
       "      <th>Intercept</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>14733363</td>\n",
       "      <td>male</td>\n",
       "      <td>68</td>\n",
       "      <td>190.0</td>\n",
       "      <td>94.0</td>\n",
       "      <td>29.0</td>\n",
       "      <td>105.0</td>\n",
       "      <td>40.8</td>\n",
       "      <td>231.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>14861698</td>\n",
       "      <td>female</td>\n",
       "      <td>20</td>\n",
       "      <td>166.0</td>\n",
       "      <td>60.0</td>\n",
       "      <td>14.0</td>\n",
       "      <td>94.0</td>\n",
       "      <td>40.3</td>\n",
       "      <td>66.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2</td>\n",
       "      <td>11179863</td>\n",
       "      <td>male</td>\n",
       "      <td>69</td>\n",
       "      <td>179.0</td>\n",
       "      <td>79.0</td>\n",
       "      <td>5.0</td>\n",
       "      <td>88.0</td>\n",
       "      <td>38.7</td>\n",
       "      <td>26.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>3</td>\n",
       "      <td>16180408</td>\n",
       "      <td>female</td>\n",
       "      <td>34</td>\n",
       "      <td>179.0</td>\n",
       "      <td>71.0</td>\n",
       "      <td>13.0</td>\n",
       "      <td>100.0</td>\n",
       "      <td>40.5</td>\n",
       "      <td>71.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4</td>\n",
       "      <td>17771927</td>\n",
       "      <td>female</td>\n",
       "      <td>27</td>\n",
       "      <td>154.0</td>\n",
       "      <td>58.0</td>\n",
       "      <td>10.0</td>\n",
       "      <td>81.0</td>\n",
       "      <td>39.8</td>\n",
       "      <td>35.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   index   User_ID  Gender  Age  Height  Weight  Duration  Heart_Rate  \\\n",
       "0      0  14733363    male   68   190.0    94.0      29.0       105.0   \n",
       "1      1  14861698  female   20   166.0    60.0      14.0        94.0   \n",
       "2      2  11179863    male   69   179.0    79.0       5.0        88.0   \n",
       "3      3  16180408  female   34   179.0    71.0      13.0       100.0   \n",
       "4      4  17771927  female   27   154.0    58.0      10.0        81.0   \n",
       "\n",
       "   Body_Temp  Calories  Intercept  \n",
       "0       40.8     231.0          1  \n",
       "1       40.3      66.0          1  \n",
       "2       38.7      26.0          1  \n",
       "3       40.5      71.0          1  \n",
       "4       39.8      35.0          1  "
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "exercise = pd.read_csv('data/exercise.csv')\n",
    "calories = pd.read_csv('data/calories.csv')\n",
    "df = pd.merge(exercise, calories, on = 'User_ID')\n",
    "df = df[df['Calories'] < 300]\n",
    "df = df.reset_index()\n",
    "df['Intercept'] = 1\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Plot Relationship"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 27080 characters]\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(8, 8))\n",
    "\n",
    "plt.plot(df['Duration'], df['Calories'], 'bo');\n",
    "plt.xlabel('Duration (min)', size = 18); plt.ylabel('Calories', size = 18); \n",
    "plt.title('Calories burned vs Duration of Exercise', size = 20);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create the features and response\n",
    "X = df.loc[:, ['Intercept', 'Duration']]\n",
    "y = df.ix[:, 'Calories']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Implement Ordinary Least Squares Linear Regression by Hand"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "hideCode": false,
    "hidePrompt": false
   },
   "outputs": [],
   "source": [
    "# Takes a matrix of features (with intercept as first column) \n",
    "# and response vector and calculates linear regression coefficients\n",
    "def linear_regression(X, y):\n",
    "    # Equation for linear regression coefficients\n",
    "    beta = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), y)\n",
    "    return beta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Intercept calculated by hand: -21.82810252605084\n",
      "Slope calculated by hand:  7.169783349587853\n"
     ]
    }
   ],
   "source": [
    "# Run the by hand implementation\n",
    "by_hand_coefs = linear_regression(X, y)\n",
    "print('Intercept calculated by hand:', by_hand_coefs[0])\n",
    "print('Slope calculated by hand: ', by_hand_coefs[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 47280 characters]\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "xs = np.linspace(4, 31, 1000)\n",
    "ys = by_hand_coefs[0] + by_hand_coefs[1] * xs\n",
    "\n",
    "plt.figure(figsize=(8, 8))\n",
    "plt.plot(df['Duration'], df['Calories'], 'bo', label = 'observations', alpha = 0.8);\n",
    "plt.xlabel('Duration (min)', size = 18); plt.ylabel('Calories', size = 18); \n",
    "plt.plot(xs, ys, 'r--', label = 'OLS Fit', linewidth = 3)\n",
    "plt.legend(prop={'size': 16})\n",
    "plt.title('Calories burned vs Duration of Exercise', size = 20);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prediction for Datapoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exercising for 15.5 minutes will burn an estimated 89.30 calories.\n"
     ]
    }
   ],
   "source": [
    "print('Exercising for 15.5 minutes will burn an estimated {:.2f} calories.'.format(\n",
    "    by_hand_coefs[0] + by_hand_coefs[1] * 15.5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Verify with Scikit-learn Implementation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "hideCode": false,
    "hidePrompt": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Intercept from library: -21.828102526050813\n",
      "Slope from library: 7.169783349587853\n"
     ]
    }
   ],
   "source": [
    "# Create the model and fit on the data\n",
    "lr = LinearRegression()\n",
    "lr.fit(X.Duration.reshape(-1, 1), y)\n",
    "print('Intercept from library:', lr.intercept_)\n",
    "print('Slope from library:', lr.coef_[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Bayesian Linear Regression\n",
    "\n",
    "### PyMC3 for Bayesian Inference\n",
    "\n",
    "Implement MCMC to find the posterior distribution of the model parameters. Rather than a single point estimate of the model weights, Bayesian linear regression will give us a posterior distribution for the model weights."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model with 500 Observations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with pm.Model() as linear_model_500:\n",
    "    # Intercept\n",
    "    intercept = pm.Normal('Intercept', mu = 0, sd = 10)\n",
    "    \n",
    "    # Slope \n",
    "    slope = pm.Normal('slope', mu = 0, sd = 10)\n",
    "    \n",
    "    # Standard deviation\n",
    "    sigma = pm.HalfNormal('sigma', sd = 10)\n",
    "    \n",
    "    # Estimate of mean\n",
    "    mean = intercept + slope * X.loc[0:499, 'Duration']\n",
    "    \n",
    "    # Observed values\n",
    "    Y_obs = pm.Normal('Y_obs', mu = mean, sd = sigma, observed = y.values[0:500])\n",
    "    \n",
    "    # Sampler\n",
    "    step = pm.NUTS()\n",
    "\n",
    "    # Posterior distribution\n",
    "    linear_trace_500 = pm.sample(1000, step)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model with all Observations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Multiprocess sampling (2 chains in 2 jobs)\n",
      "NUTS: [sigma_log__, slope, Intercept]\n",
      "The acceptance probability does not match the target. It is 0.9876388940291865, but should be close to 0.8. Try to increase the number of tuning steps.\n",
      "The acceptance probability does not match the target. It is 0.9933390669386344, but should be close to 0.8. Try to increase the number of tuning steps.\n",
      "The number of effective samples is smaller than 25% for some parameters.\n"
     ]
    }
   ],
   "source": [
    "with pm.Model() as linear_model:\n",
    "    # Intercept\n",
    "    intercept = pm.Normal('Intercept', mu = 0, sd = 10)\n",
    "    \n",
    "    # Slope \n",
    "    slope = pm.Normal('slope', mu = 0, sd = 10)\n",
    "    \n",
    "    # Standard deviation\n",
    "    sigma = pm.HalfNormal('sigma', sd = 10)\n",
    "    \n",
    "    # Estimate of mean\n",
    "    mean = intercept + slope * X.loc[:, 'Duration']\n",
    "    \n",
    "    # Observed values\n",
    "    Y_obs = pm.Normal('Y_obs', mu = mean, sd = sigma, observed = y.values)\n",
    "    \n",
    "    # Sampler\n",
    "    step = pm.NUTS()\n",
    "\n",
    "    # Posterior distribution\n",
    "    linear_trace = pm.sample(1000, step)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Bayesian Model Results\n",
    "\n",
    "The Bayesian Model provides more opportunities for interpretation than the ordinary least squares regression because it provides a posterior distribution. We can use this distribution to find the most likely single value as well as the entire range of likely values for our model parameters.\n",
    "\n",
    "PyMC3 has many built in tools for visualizing and inspecting model runs. These let us see the distributions and provide estimates with a level of uncertainty, which should be a necessary part of any model."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Trace of All Model Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 218968 characters]\n",
      "text/plain": [
       "<Figure size 864x864 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pm.traceplot(linear_trace, figsize = (12, 12));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Posterior Distribution of Model Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 44104 characters]\n",
      "text/plain": [
       "<Figure size 864x720 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pm.plot_posterior(linear_trace, figsize = (12, 10), text_size = 20);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Confidence Intervals for Model Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 10372 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pm.forestplot(linear_trace);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Predictions of Response Sampled from the Posterior\n",
    "\n",
    "We can now generate predictions of the linear regression line using the model results. The following plot shows 1000 different estimates of the regression line drawn from the posterior. The distribution of the lines gives an estimate of the uncertainty in the estimate. Bayesian Linear Regression has the benefit that it gives us a posterior __distribution__ rather than a __single point estimate__ in the frequentist ordinary least squares regression."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## All Observations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 53748 characters]\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize = (8, 8))\n",
    "pm.plot_posterior_predictive_glm(linear_trace, samples = 100, eval=np.linspace(2, 30, 100), linewidth = 1, \n",
    "                                 color = 'red', alpha = 0.8, label = 'Bayesian Posterior Fits',\n",
    "                                lm = lambda x, sample: sample['Intercept'] + sample['slope'] * x);\n",
    "plt.scatter(X['Duration'], y.values, s = 12, alpha = 0.8, c = 'blue', label = 'Observations')\n",
    "plt.plot(X['Duration'], by_hand_coefs[0] + X['Duration'] * by_hand_coefs[1], 'k--', label = 'OLS Fit', linewidth = 1.4)\n",
    "plt.title('Posterior Predictions with all Observations', size = 20); plt.xlabel('Duration (min)', size = 18);\n",
    "plt.ylabel('Calories', size = 18);\n",
    "plt.legend(prop={'size': 16});"
   ]
  },
  {
   "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>mean</th>\n",
       "      <th>sd</th>\n",
       "      <th>mc_error</th>\n",
       "      <th>hpd_2.5</th>\n",
       "      <th>hpd_97.5</th>\n",
       "      <th>n_eff</th>\n",
       "      <th>Rhat</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Intercept</th>\n",
       "      <td>-21.805933</td>\n",
       "      <td>0.322550</td>\n",
       "      <td>0.011807</td>\n",
       "      <td>-22.465744</td>\n",
       "      <td>-21.209683</td>\n",
       "      <td>736.0</td>\n",
       "      <td>0.999821</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>slope</th>\n",
       "      <td>7.168752</td>\n",
       "      <td>0.018153</td>\n",
       "      <td>0.000681</td>\n",
       "      <td>7.131481</td>\n",
       "      <td>7.202292</td>\n",
       "      <td>707.0</td>\n",
       "      <td>0.999527</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>sigma</th>\n",
       "      <td>18.387170</td>\n",
       "      <td>0.106938</td>\n",
       "      <td>0.004344</td>\n",
       "      <td>18.169925</td>\n",
       "      <td>18.588937</td>\n",
       "      <td>426.0</td>\n",
       "      <td>1.012243</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                mean        sd  mc_error    hpd_2.5   hpd_97.5  n_eff  \\\n",
       "Intercept -21.805933  0.322550  0.011807 -22.465744 -21.209683  736.0   \n",
       "slope       7.168752  0.018153  0.000681   7.131481   7.202292  707.0   \n",
       "sigma      18.387170  0.106938  0.004344  18.169925  18.588937  426.0   \n",
       "\n",
       "               Rhat  \n",
       "Intercept  0.999821  \n",
       "slope      0.999527  \n",
       "sigma      1.012243  "
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pm.df_summary(linear_trace)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Limited Observations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 51408 characters]\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize = (8, 8))\n",
    "pm.plot_posterior_predictive_glm(linear_trace_500, samples = 100, eval=np.linspace(2, 30, 100), linewidth = 1, \n",
    "                                 color = 'red', alpha = 0.8, label = 'Bayesian Posterior Fits',\n",
    "                                lm = lambda x, sample: sample['Intercept'] + sample['slope'] * x);\n",
    "plt.scatter(X['Duration'][:500], y.values[:500], s = 12, alpha = 0.8, c = 'blue', label = 'Observations')\n",
    "plt.plot(X['Duration'], by_hand_coefs[0] + X['Duration'] * by_hand_coefs[1], 'k--', label = 'OLS Fit', linewidth = 1.4)\n",
    "plt.title('Posterior Predictions with Limited Observations', size = 20); plt.xlabel('Duration (min)', size = 18);\n",
    "plt.ylabel('Calories', size = 18);\n",
    "plt.legend(prop={'size': 16});"
   ]
  },
  {
   "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>mean</th>\n",
       "      <th>sd</th>\n",
       "      <th>mc_error</th>\n",
       "      <th>hpd_2.5</th>\n",
       "      <th>hpd_97.5</th>\n",
       "      <th>n_eff</th>\n",
       "      <th>Rhat</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Intercept</th>\n",
       "      <td>-22.854865</td>\n",
       "      <td>1.776303</td>\n",
       "      <td>0.047775</td>\n",
       "      <td>-26.307522</td>\n",
       "      <td>-19.569343</td>\n",
       "      <td>1076.0</td>\n",
       "      <td>0.999589</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>slope</th>\n",
       "      <td>7.355138</td>\n",
       "      <td>0.097234</td>\n",
       "      <td>0.002733</td>\n",
       "      <td>7.171244</td>\n",
       "      <td>7.543756</td>\n",
       "      <td>1063.0</td>\n",
       "      <td>0.999530</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>sigma</th>\n",
       "      <td>18.206843</td>\n",
       "      <td>0.552285</td>\n",
       "      <td>0.016451</td>\n",
       "      <td>17.129418</td>\n",
       "      <td>19.296164</td>\n",
       "      <td>1083.0</td>\n",
       "      <td>1.002193</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                mean        sd  mc_error    hpd_2.5   hpd_97.5   n_eff  \\\n",
       "Intercept -22.854865  1.776303  0.047775 -26.307522 -19.569343  1076.0   \n",
       "slope       7.355138  0.097234  0.002733   7.171244   7.543756  1063.0   \n",
       "sigma      18.206843  0.552285  0.016451  17.129418  19.296164  1083.0   \n",
       "\n",
       "               Rhat  \n",
       "Intercept  0.999589  \n",
       "slope      0.999530  \n",
       "sigma      1.002193  "
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pm.df_summary(linear_trace_500)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Specific Prediction for One Datapoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "bayes_prediction = linear_trace['Intercept'] + linear_trace['slope'] * 15.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 43900 characters]\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize = (8, 8))\n",
    "plt.style.use('fivethirtyeight')\n",
    "sns.kdeplot(bayes_prediction, label = 'Bayes Posterior Prediction')\n",
    "plt.vlines(x = by_hand_coefs[0] + by_hand_coefs[1] * 15.5, \n",
    "           ymin = 0, ymax = 2.5, \n",
    "           label = 'OLS Prediction',\n",
    "          colors = 'red', linestyles='--')\n",
    "plt.legend();\n",
    "plt.xlabel('Calories Burned', size = 18), plt.ylabel('Probability Density', size = 18);\n",
    "plt.title('Posterior Prediction for 15.5 Minutes', size = 20);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "hide_code_all_hidden": false,
  "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.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
