{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from statsmodels.tsa.stattools import adfuller\n",
    "from statsmodels.graphics.tsaplots import plot_acf, plot_pacf\n",
    "from statsmodels.tsa.arima_model import ARMA\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def perform_adf_test(series):\n",
    "    result = adfuller(series)\n",
    "    print('ADF Statistic: %f' % result[0])\n",
    "    print('p-value: %f' % result[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Original Series"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts = pd.read_csv('original_series.csv')\n",
    "ts.index = np.arange(1,len(ts)+1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0, 0.5, 'Views')"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 22760 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(ts)\n",
    "\n",
    "plt.xticks(np.arange(0,78,6), fontsize=14)\n",
    "plt.xlabel('Hours Since Published', fontsize=16)\n",
    "\n",
    "plt.yticks(np.arange(0,50000,10000), fontsize=14)\n",
    "plt.ylabel('Views', fontsize=16)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Original Series: $v_t$\n",
    "\n",
    "# (1) Normalize ($v_t \\rightarrow n_t$): $n_t = \\frac{v_t - \\mu}{\\sigma}$\n",
    "\n",
    "# (2) Exponentiate ($n_t \\rightarrow e_t$): $e_t = e^{n_t}$\n",
    "\n",
    "# (3) First Difference ($e_t \\rightarrow d_t$): $d_t = e_t - e_{t-1}$\n",
    "\n",
    "# $d_t = e^{\\frac{v_t - \\mu}{\\sigma}} - e^{\\frac{v_{t-1} - \\mu}{\\sigma}}$\n",
    "\n",
    "# ------------------------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# (1) Normalize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "mu = np.mean(ts).iloc[0]\n",
    "sigma = np.std(ts).iloc[0]\n",
    "\n",
    "norm_ts = (ts - mu) / sigma"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.lines.Line2D at 0x243588e5a08>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 21292 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(norm_ts)\n",
    "\n",
    "plt.xticks(np.arange(0,78,6), fontsize=14)\n",
    "plt.xlabel('Hours Since Published', fontsize=16)\n",
    "\n",
    "plt.yticks(np.arange(-3,2), fontsize=14)\n",
    "plt.ylabel('Norm. Views', fontsize=16)\n",
    "\n",
    "plt.axhline(0, color='k', linestyle='--')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# (2) Exponentiate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "exp_ts = np.exp(norm_ts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0, 0.5, 'Exp. Norm. Views')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 24808 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(exp_ts)\n",
    "\n",
    "plt.xticks(np.arange(0,78,6), fontsize=14)\n",
    "plt.xlabel('Hours Since Published', fontsize=16)\n",
    "\n",
    "plt.yticks(np.arange(0,3.5,.5), fontsize=14)\n",
    "plt.ylabel('Exp. Norm. Views', fontsize=16)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ADF Statistic: 1.648979\n",
      "p-value: 0.997997\n"
     ]
    }
   ],
   "source": [
    "perform_adf_test(exp_ts)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# (3) First Difference"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "diff_ts = exp_ts.diff().dropna()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0, 0.5, 'First Diff. \\nExp. Norm. Views')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 45812 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(diff_ts)\n",
    "\n",
    "plt.xticks(np.arange(0,78,6), fontsize=14)\n",
    "plt.xlabel('Hours Since Published', fontsize=16)\n",
    "\n",
    "plt.yticks(np.arange(-0.2,0.3,.1), fontsize=14)\n",
    "plt.ylabel('First Diff. \\nExp. Norm. Views', fontsize=16)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ADF Statistic: -4.881064\n",
      "p-value: 0.000038\n"
     ]
    }
   ],
   "source": [
    "perform_adf_test(diff_ts)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Fit AR Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 10400 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_pacf(diff_ts)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 11292 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_acf(diff_ts)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\ritvik\\Anaconda3\\lib\\site-packages\\statsmodels\\tsa\\base\\tsa_model.py:214: ValueWarning: An unsupported index was provided and will be ignored when e.g. forecasting.\n",
      "  ' ignored when e.g. forecasting.', ValueWarning)\n"
     ]
    }
   ],
   "source": [
    "#create the model\n",
    "model = ARMA(diff_ts, order=(4,1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_fit = model.fit()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Predict Out 3 Hours"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "prediction_info = model_fit.forecast(3)\n",
    "\n",
    "predictions = prediction_info[0]\n",
    "lower_bound = prediction_info[2][:,0]\n",
    "upper_bound = prediction_info[2][:,1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PolyCollection at 0x24358a97488>"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 46484 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(diff_ts)\n",
    "\n",
    "plt.xticks(np.arange(0,78,6), fontsize=14)\n",
    "plt.xlabel('Hours Since Published', fontsize=16)\n",
    "\n",
    "plt.yticks(np.arange(-0.2,0.3,.1), fontsize=14)\n",
    "plt.ylabel('First Diff. \\nExp. Norm. Views', fontsize=16)\n",
    "\n",
    "plt.plot(np.arange(len(ts)+1, len(ts)+4), predictions, color='g')\n",
    "plt.fill_between(np.arange(len(ts)+1, len(ts)+4), lower_bound, upper_bound, color='g', alpha=0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Undo Transformations: ($\\hat{d}_{t+1} \\rightarrow \\hat{v}_{t+1}$)\n",
    "\n",
    "# $\\hat{v}_{t+1} = \\sigma \\ln(\\hat{d}_{t+1} + e^{\\frac{v_t - \\mu}{\\sigma}}) + \\mu$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "def undo_transformations(predictions, series, mu, sigma):\n",
    "    first_pred = sigma*np.log(predictions[0] + np.exp((series.iloc[-1]-mu)/sigma)) + mu\n",
    "    orig_predictions = [first_pred]\n",
    "    \n",
    "    for i in range(len(predictions[1:])):\n",
    "        next_pred = sigma*np.log(predictions[i+1] + np.exp((orig_predictions[-1]-mu)/sigma)) + mu\n",
    "        orig_predictions.append(next_pred)\n",
    "    \n",
    "    return np.array(orig_predictions).flatten()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "orig_preds = undo_transformations(predictions, ts, mu, sigma)\n",
    "orig_lower_bound = undo_transformations(lower_bound, ts, mu, sigma)\n",
    "orig_upper_bound = undo_transformations(upper_bound, ts, mu, sigma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PolyCollection at 0x24358cd7c08>"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 23108 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(ts)\n",
    "\n",
    "plt.xticks(np.arange(0,78,6), fontsize=14)\n",
    "plt.xlabel('Hours Since Published', fontsize=16)\n",
    "\n",
    "plt.yticks(np.arange(0,50000,10000), fontsize=14)\n",
    "plt.ylabel('Views', fontsize=16)\n",
    "\n",
    "plt.plot(np.arange(len(ts)+1, len(ts)+4), orig_preds, color='g')\n",
    "plt.fill_between(np.arange(len(ts)+1, len(ts)+4), orig_lower_bound, orig_upper_bound, color='g', alpha=0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(40000.0, 45000.0)"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 20804 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(ts)\n",
    "\n",
    "plt.xticks(np.arange(0,78), fontsize=14)\n",
    "plt.xlabel('Hours Since Published', fontsize=16)\n",
    "\n",
    "plt.yticks(np.arange(40000,46000,1000), fontsize=14)\n",
    "plt.ylabel('Views', fontsize=16)\n",
    "\n",
    "plt.plot(np.arange(len(ts)+1, len(ts)+4), orig_preds, color='g')\n",
    "plt.fill_between(np.arange(len(ts)+1, len(ts)+4), orig_lower_bound, orig_upper_bound, color='g', alpha=0.1)\n",
    "plt.xlim(64,76)\n",
    "plt.ylim(40000, 45000)"
   ]
  },
  {
   "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.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
