diff --git a/blog/2016-03-05-predicting-santander-customer-happiness/_article.md b/blog/2016-03-05-predicting-santander-customer-happiness/_article.md new file mode 100644 index 0000000..af9c95f --- /dev/null +++ b/blog/2016-03-05-predicting-santander-customer-happiness/_article.md @@ -0,0 +1,16 @@ +Title: Predicting Santander Customer Happiness +Date: 2016-03-05 +Category: Blog +Tags: machine learning, data science, kaggle +Authors: Bradlee Speice +Summary: My first real-world data challenge: predicting whether a bank's customers will be happy. +[//]: <> "Modified: " + +{% notebook 2016-3-5-predicting-santander-customer-happiness.ipynb %} + + + + diff --git a/blog/2016-03-05-predicting-santander-customer-happiness/_notebook.ipynb b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook.ipynb new file mode 100644 index 0000000..8ba9f81 --- /dev/null +++ b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook.ipynb @@ -0,0 +1,436 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### My first Kaggle competition\n", + "\n", + "It's time! After embarking on a Machine Learning class this semester, and with a Saturday in which I don't have much planned, I wanted to put this class and training to work. It's my first competition submission. I want to walk you guys through how I'm approaching this problem, because I thought it would be really neat. The competition is Banco Santander's [Santander Customer Satisfaction][1] competition. It seemed like an easy enough problem I could actually make decent progress on it.\n", + "\n", + "# Data Exploration\n", + "\n", + "First up: we need to load our data and do some exploratory work. Because we're going to be using this data for model selection prior to testing, we need to make a further split. I've already gone ahead and done this work, please see the code in the [appendix below](#Appendix).\n", + "\n", + "[1]: https://www.kaggle.com/c/santander-customer-satisfaction" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "# Record how long it takes to run the notebook - I'm curious.\n", + "from datetime import datetime\n", + "start = datetime.now()\n", + "\n", + "dataset = pd.read_csv('split_train.csv')\n", + "dataset.index = dataset.ID\n", + "X = dataset.drop(['TARGET', 'ID', 'ID.1'], 1)\n", + "y = dataset.TARGET" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0, 1], dtype=int64)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y.unique()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "369" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(X.columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Okay, so there are only [two classes we're predicting][2]: 1 for unsatisfied customers, 0 for satisfied customers. I would have preferred this to be something more like a regression, or predicting multiple classes: maybe the customer isn't the most happy, but is nowhere near closing their accounts. For now though, that's just the data we're working with.\n", + "\n", + "Now, I'd like to make a scatter matrix of everything going on. Unfortunately as noted above, we have 369 different features. There's no way I can graphically make sense of that much data to start with.\n", + "\n", + "We're also not told what the data actually represents: Are these survey results? Average time between contact with a customer care person? Frequency of contacting a customer care person? The idea is that I need to reduce the number of dimensions we're predicting across.\n", + "\n", + "## Dimensionality Reduction pt. 1 - Binary Classifiers\n", + "\n", + "My first attempt to reduce the data dimensionality is to find all the binary classifiers in the dataset \\(i.e. 0 or 1 values\\) and see if any of those are good \\(or anti-good\\) predictors of the final data.\n", + "\n", + "[2]: https://www.kaggle.com/c/santander-customer-satisfaction/data" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "111" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cols = X.columns\n", + "b_class = []\n", + "for c in cols:\n", + " if len(X[c].unique()) == 2:\n", + " b_class.append(c)\n", + " \n", + "len(b_class)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So there are 111 features in the dataset that are a binary label. Let's see if any of them are good at predicting the users satisfaction!" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Accuracy
count111.000000
mean0.905159
std0.180602
min0.043598
25%0.937329
50%0.959372
75%0.960837
max0.960837
\n", + "
" + ], + "text/plain": [ + " Accuracy\n", + "count 111.000000\n", + "mean 0.905159\n", + "std 0.180602\n", + "min 0.043598\n", + "25% 0.937329\n", + "50% 0.959372\n", + "75% 0.960837\n", + "max 0.960837" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# First we need to `binarize` the data to 0-1; some of the labels are {0, 1},\n", + "# some are {0, 3}, etc.\n", + "from sklearn.preprocessing import binarize\n", + "X_bin = binarize(X[b_class])\n", + "\n", + "accuracy = [np.mean(X_bin[:,i] == y) for i in range(0, len(b_class))]\n", + "acc_df = pd.DataFrame({\"Accuracy\": accuracy}, index=b_class)\n", + "acc_df.describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wow! Looks like we've got some incredibly predictive features! So much so that we should be a bit concerned. My initial guess for what's happening is that we have a sparsity issue: so many of the values are 0, and these likely happen to line up with satisfied customers.\n", + "\n", + "So the question we must now answer, which I likely should have asked long before now: What exactly is the distribution of un/satisfied customers?" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Satisfied customers: 51131; Unsatisfied customers: 2083\n", + "Naive guess accuracy: 0.9608561656706882\n" + ] + } + ], + "source": [ + "unsat = y[y == 1].count()\n", + "print(\"Satisfied customers: {}; Unsatisfied customers: {}\".format(len(y) - unsat, unsat))\n", + "naive_guess = np.mean(y == np.zeros(len(y)))\n", + "print(\"Naive guess accuracy: {}\".format(naive_guess))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a bit discouraging. A naive guess of \"always satisfied\" performs as well as our best individual binary classifier. What this tells me then, is that these data columns aren't incredibly helpful in prediction. I'd be interested in a polynomial expansion of this data-set, but for now, that's more computation than I want to take on.\n", + "\n", + "# Dimensionality Reduction pt. 2 - LDA\n", + "\n", + "Knowing that our naive guess performs so well is a blessing and a curse:\n", + "\n", + "- Curse: The threshold for performance is incredibly high: We can only \"improve\" over the naive guess by 4%\n", + "- Blessing: All the binary classification features we just discovered are worthless on their own. We can throw them out and reduce the data dimensionality from 369 to 111.\n", + "\n", + "Now, in removing these features from the dataset, I'm not saying that there is no \"information\" contained within them. There might be. But the only way we'd know is through a polynomial expansion, and I'm not going to take that on within this post.\n", + "\n", + "My initial thought for a \"next guess\" is to use the [LDA][3] model for dimensionality reduction. However, it can only reduce dimensions to $1 - p$, with $p$ being the number of classes. Since this is a binary classification, every LDA model that I try will have dimensionality one; when I actually try this, the predictor ends up being slightly less accurate than the naive guess.\n", + "\n", + "Instead, let's take a different approach to dimensionality reduction: [principle components analysis][4]. This allows us to perform the dimensionality reduction without worrying about the number of classes. Then, we'll use a [Gaussian Naive Bayes][5] model to actually do the prediction. This model is chosen simply because it doesn't take a long time to fit and compute; because PCA will take so long, I just want a prediction at the end of this. We can worry about using a more sophisticated LDA/QDA/SVM model later.\n", + "\n", + "Now into the actual process: We're going to test out PCA dimensionality reduction from 1 - 20 dimensions, and then predict using a Gaussian Naive Bayes model. The 20 dimensions upper limit was selected because the accuracy never improves after you get beyond that \\(I found out by running it myself\\). Hopefully, we'll find that we can create a model better than the naive guess.\n", + "\n", + "[3]:http://scikit-learn.org/stable/modules/lda_qda.html\n", + "[4]:http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html\n", + "[5]:http://scikit-learn.org/stable/modules/naive_bayes.html#gaussian-naive-bayes" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsYAAAFwCAYAAAC7E71AAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl8VfWd//HXNxDWQAiJbElYpK503KZgrdpiGUH9iVor\nCCi2OFXb2hmxdWHsaEOXcURt1dZldKw74tJ26r4UjdW2bq3ISJXNDkgKsgUjsoTl+/vjhmsIWclN\n7k3yej4e55F7zvnecz73cI1vvnzP+YYYI5IkSVJHl5XuAiRJkqRMYDCWJEmSMBhLkiRJgMFYkiRJ\nAgzGkiRJEmAwliRJkoBGBOMQwp0hhA9DCPPraXNTCGFxCGFeCOGw1JYoSZIktbzG9BjfBYyra2cI\n4URgeIxxP+AC4LYU1SZJkiS1mgaDcYzxFaC8nianAvdWtX0NyA0h9E9NeZIkSVLrSMUY40Lgg2rr\nZVXbJEmSpDbDm+8kSZIkoHMKjlEGFFdbL6ratocQQkzB+SRJkqQGxRhDU9o3NhiHqqU2jwEXAg+F\nED4PbIgxflhPgU2pT2o1JSUllJSUpLsMaQ9+N5Wp/G4qk4XQpEwMNCIYhxBmA6OB/BDCcuAHQBcg\nxhhvjzE+FUI4KYSwBPgEmNbkKiRJkqQ0azAYxxinNKLNd1JTjiRJkpQe3nwnVRk9enS6S5Bq5XdT\nmcrvptqb0JpjfkMI0THGkiRJamkhhBa7+U6SJLUjQ4cOZdmyZekuQ2q2IUOG8H//938pOZY9xpIk\ndUBVvWnpLkNqtrq+y3vTY+wYY0mSJAmDsSRJkgQYjCVJkiTAYCxJktSgk046ifvuuy/dZaiFdbib\n7371K1i/Pq0l7CaE+pesrIbbNHcRdOsGRx+d7iokqfVk+s13c+bM4YYbbuCdd94hJyeHYcOGcc45\n5/Ctb30r3aWl1D333MO0adOYNWsWl1xySXJ7cXExDzzwAF/84heZOXMmP/nJT+jWrVty349+9CNO\nP/30eo9dWlrKl7/8Za655houvfTSFv0c6ZTKm++IMbbaAkQXFxcXFxeXzFgy1XXXXRcHDBgQf/3r\nX8eNGzfGGGOcN29ePPvss2NlZWWaq0utu+++O+bn58d99tkn+VljjLGoqCi+9NJLMcYYS0pK4tSp\nU5P7nn322di9e/e4evXqeo89bdq0WFBQED/72c+2TPH12L59e6udq4HveJOyaqsPpWhqgS4urbEc\nfXTk979Pfx0uLi4urbVkqoqKCn7wgx9w66238pWvfIWePXsCcOihh3LfffeRnZ0NwFNPPcURRxxB\nbm4uQ4YMYebMmcljvPTSSxQXF+923GHDhvHCCy8A8MYbbzBy5Ehyc3MZOHBgsqd269atTJ06lYKC\nAvLy8jjyyCNZs2YNAMcddxy//OUvAXj//fcZM2YMBQUF9OvXj7PPPpuKiordznX99ddz6KGHkpeX\nx+TJk6msrKzzMx900EEcddRRXH/99Y26RmPHjqVXr14sXbq0zjabNm3i0Ucf5eabb2bx4sX85S9/\n2W3/K6+8wtFHH01eXh5Dhgzh3nvvBWDLli1873vfY+jQoeTl5fHFL36RrVu3NnhNZ86cyYQJE5g6\ndSp9+vThnnvu4Y033uALX/gCeXl5FBYW8i//8i9s3749+f4FCxYwduxY8vPzGThwIP/5n//Jhx9+\nSM+ePSkvL0+2+8tf/kK/fv3YsWNHnZ83Vd9xxxhLQFERrFiR7iokSX/605+orKzklFNOqbddTk4O\n9913Hx999BFPPvkkt912G4899lhyf6hnrOBFF13E9OnT+eijj1i6dCkTJ04EEsMaKioqKCsrY/36\n9dx222107959j/fHGLniiitYtWoV7777LitWrKCkpGS3No888gjPPfccf/vb33j77be5++6766wn\nhMCPfvQjbrjhBjZs2FDv5wZ48skn2bZtGwcffHCdbX71q1/Rq1cvJkyYwNixY7nnnnuS+5YvX85J\nJ53ERRddxNq1a5k3bx6HHXYYAN/73vd46623ePXVV1m/fj2zZs0iKysrWWd9HnvsMSZOnMiGDRs4\n66yz6Ny5MzfccAPr16/nT3/6Ey+88AK33HILABs3buT444/npJNOYuXKlSxZsoQxY8bQv39/jjvu\nOB5++OHkce+//34mT55Mp06dGrw2zWUwljAYS1KmWLt2LQUFBckwBiR7Nnv06MErr7wCwBe/+EVG\njBgBwGc/+1kmTZrESy+91KhzdOnShSVLlrBu3Tp69OjBqFGjAMjOzmbdunUsWrSIEAKHH344OTk5\ne7x/+PDhjBkzhs6dO5Ofn8/FF1+8x7kvuugi+vfvT58+fRg/fjzz5s2rt6ZDDjmE448/nmuuuabW\n/Q899BB9+/YlJyeH0047jSuuuILevXvXebx7772XSZMmEUJgypQpzJkzJ9njOnv2bI4//ngmTpxI\np06dyMvL45BDDiHGyF133cVNN93EgAEDCCHw+c9/PtlL35CjjjqK8ePHA9C1a1cOP/xwRo0aRQiB\nwYMHc/755yev0xNPPMHAgQOZPn06Xbp0oWfPnowcORKAc845J3mj486dO3nwwQeZOnVqo2poLoOx\nhMFYkmqTjhu88/PzWbt2LTt37kxu+8Mf/kB5eTkFBQXJ7a+99hpf/vKX6devH3369OG//uu/WLt2\nbaPOceedd7Jw4UIOPPBAjjzySJ588kkApk6dyrhx45g0aRJFRUVcfvnltf7z/erVq5k8eTJFRUX0\n6dOHs88+e49z9+/fP/m6R48ebNy4scG6fvjDH3LrrbeyevXqPfadeeaZrF+/no0bN7J06VLuuece\n7rjjjlqPs2LFCl588UWmTJkCwCmnnMLmzZuTn/ODDz5g+PDhe7xv7dq1bN26lX333bfBWmtTc6jF\n4sWLGT9+PAMHDqRPnz58//vfT16numoAOPXUU3n33XdZtmwZzz33HH369OFzn/vcXtXUVAZjCYOx\nJNUmxuYvTXXUUUfRtWtXfvvb39ZSz6cHPOusszjttNMoKytjw4YNXHDBBcn9PXv2ZNOmTcm2O3bs\nSI4VhkSP7+zZs1mzZg2XXXYZZ5xxBps3b6Zz585ceeWVLFiwgD/+8Y888cQTybG31V1xxRVkZWWx\nYMECNmzYwP3335+ScdsHHHAAp59+Oj/5yU/qHbYwePBgTjzxRB5//PFa9997773EGJOhdPjw4Wzd\nujU5nKK4uJglS5bs8b6CggK6detW69jlhq4p7DnU4lvf+hYHHXQQS5cuZcOGDfzkJz9JXqfi4uI6\nx0h37dqViRMnct9993H//fe3Wm8xGIwlwGAsSZkiNzeXq666im9/+9v86le/YuPGjcQYmTdv3m7B\nbOPGjeTl5ZGdnc3rr7/O7Nmzk/v2339/tmzZwtNPP8327dv58Y9/vNvNbw888ECy5zI3N5cQAllZ\nWZSWlvLOO++wc+dOcnJyyM7OrnVc68cff0xOTg69evWirKyMa6+9NmWf/6qrruKuu+7aY6xx9eC9\nYsUKnnnmGT772c/Weox7772XkpIS5s2bx9tvv83bb7/No48+ypNPPkl5eTlnnXUWc+fO5dFHH2XH\njh2sX7+et99+mxAC06ZN47vf/S4rV65k586dvPrqq2zbtq3Ba1qbjz/+mN69e9OjRw/ee+89br31\n1uS+k08+mVWrVnHTTTdRWVnJxo0bef3115P7p06dyt13383jjz9uMJZam8FYkjLHpZdeyk9/+lNm\nzZrFgAEDGDBgAN/61reYNWsWX/jCFwC45ZZbuPLKK8nNzeXHP/4xZ555ZvL9vXv35pZbbuGf//mf\nKSoqolevXhQVFSX3P/PMM4wYMYLevXtz8cUX89BDD9G1a1dWrVrFGWecQW5uLiNGjOC4447j7LPP\nBnbvDf3BD37An//85+T44a9+9au71d/QTWr1GTp0KFOnTuWTTz7ZbfvDDz9M79696d27N0ceeSTH\nHnssV1111R7vf+2111i+fDnf/va36devX3IZP348++23Hw8++CDFxcU89dRTXHfddfTt25fDDz+c\n+fPnA3DdddfxD//wD4wcOZL8/HxmzJjBzp07G7ymtbnuuut44IEH6N27NxdccAGTJk1K7svJyeH5\n55/nscceY8CAAey///6UlpYm93/hC18gKyuLI444Yo8hGi2pw03wIdVm+3bo0QM++QQaeY+BJLVp\nmT7BhzRmzBjOOusszj333HrbpXKCD3uMJaBzZ9hnH1i1Kt2VSJKkN954g7feemu3fwloDQZjqYrD\nKSRJSr+vf/3rjB07lhtvvDE5wUtr6dyqZ5MymMFYkqT0q28ylJZmj7FUxWAsSVLHZjCWqhiMJUnq\n2AzGUhWDsSRJHZvBWKpiMJYkqWMzGEtVDMaSJHVsBmOpyqBBsHIl7NiR7kokSc1x9dVXc/7556e7\nDLVBBmOpSteukJcHq1enuxJJ6tiGDh1K//792bx5c3LbnXfeyXHHHdeo9//bv/0bt99+e4vU9vzz\nz/PlL3+Z3r17s88++3DEEUdw7bXXUllZ2SLnU+syGEvVOJxCktIvhMDOnTu54YYb9tieTo888ggT\nJkzg7LPPZvny5axZs4aHHnqIFStW8MEHH6S1NqWGwViqpqgIysrSXYUk6dJLL+X666+noqKi1v3T\np09n8ODB5ObmMnLkSF555ZXkvpkzZ3LOOecAcNJJJ3HLLbfs9t7DDjuM//mf/wHgvffeY+zYseTn\n53PQQQfxyCOP1FnT9773PUpKSjj33HPp06cPAPvttx833ngjw4cPB2DatGlcddVVyfe89NJLFBcX\nJ9dXrlzJGWecQb9+/Rg+fDg///nPk/veeOMNRo4cSW5uLgMHDuSSSy4BYOvWrUydOpWCggLy8vI4\n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\nP38+S5YsoaysjB/+8IfJtqtWrWLDhg0sX76c22+/neuvv57i4mLWrVvH6tWr+Y//+A8AYoyMHz+e\nww8/nJUrVzJ37lxuvPFGnn/++Tpr7tGjB1dccQVXXHFFrfv79+/PU089RUVFBXfddRcXX3wx8+bN\nS+7f1bs8adIknn76aT755BMAdu7cySOPPJL8jF/72tfo0qUL77//Pm+99RbPP/88//3f/13rOX/3\nu9/x1a9+tf6LzZ4929XX67umdV2/RYsWcfPNN/PnP/+ZiooKnn32WYYOHdpgHelgMJZqYTCWpMwx\nZMgQzj33XEIIfO1rX2PlypWsXr2a7t27c8opp/Dggw8CsHjxYhYuXMgpp5wCwB133MHPfvYzcnNz\n6dmzJzNmzEi2BejUqRMzZ84kOzubrl27kp2dzcqVK/nb3/5Gp06dOProowF44403WLt2Ld///vfp\n1KkTQ4cO5Rvf+AZz5sypt+7zzz+f5cuXJ3u4qzvxxBOT4fDYY49l7NixtfYuDx48mCOOOILf/OY3\nAMydO5eePXsycuRIPvzwQ55++ml+9rOf0a1bNwoKCpg+ffpun7G6tWvXMmDAgOT6zTffTF5eHr16\n9eKCCy6o83NU74Gu75rWdf06depEZWUl77zzDtu3b2fw4MEMGzas3muXLgZjqRZFRVBWlu4qJCm9\nQgjNXlKhepjr3r07ABs3bgRgypQpyWA2e/ZsTjvtNLp27cqaNWvYtGkT//iP/0jfvn3p27cvJ554\nIuvWrUsea5999iE7Ozu5ftlllzF8+HDGjh3LZz7zGa655hoAli1bRllZWfI4eXl5XH311axevbre\nurt06cKVV17JlVdeuce+p59+mqOOOor8/Hzy8vJ4+umnWbt2ba3HmTx5cvIzPvjgg0yZMgWA5cuX\ns23bNgYOHJis65vf/Gadx8nPz2flypXJ9QsvvJDy8nKmT5/Otm3b6v0sQIPX9NJLL631+g0fPpwb\nbriBkpIS+vfvz5QpU3arI5MYjKVa2GMsSYmewuYuLe34449nzZo1vP3228yZMycZGgsKCujRowcL\nFixg/fr1rF+/ng0bNvBRtWdx1gzuPXv25LrrrmPp0qU89thj/PSnP+XFF1+kuLiYfffdN3mc8vJy\nPvroIx5//PEG65s2bRobNmzg17/+dXJbZWUlZ5xxBpdddhlr1qyhvLycE088sc7rNWHCBEpLSykr\n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\nrkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from sklearn.naive_bayes import GaussianNB\n", + "from sklearn.decomposition import PCA\n", + "\n", + "X_no_bin = X.drop(b_class, 1)\n", + "\n", + "def evaluate_gnb(dims):\n", + " pca = PCA(n_components=dims)\n", + " X_xform = pca.fit_transform(X_no_bin)\n", + " \n", + " gnb = GaussianNB()\n", + " gnb.fit(X_xform, y)\n", + " return gnb.score(X_xform, y)\n", + "\n", + "dim_range = np.arange(1, 21)\n", + "plt.plot(dim_range, [evaluate_gnb(dim) for dim in dim_range], label=\"Gaussian NB Accuracy\")\n", + "plt.axhline(naive_guess, label=\"Naive Guess\", c='k')\n", + "plt.axhline(1 - naive_guess, label=\"Inverse Naive Guess\", c='k')\n", + "plt.gcf().set_size_inches(12, 6)\n", + "plt.legend();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\\*\\*sigh...\\*\\* After all the effort and computational power, we're still at square one: we have yet to beat out the naive guess threshold. With PCA in play we end up performing terribly, but not terribly enough that we can guess against ourselves.\n", + "\n", + "Let's try one last-ditch attempt using the entire data set:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsYAAAFwCAYAAAC7E71AAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl8VfWd//HXNxDWQAiJbElYpK503KZgrdpiGUH9iVor\nCCi2OFXb2hmxdWHsaEOXcURt1dZldKw74tJ26r4UjdW2bq3ISJXNDkgKsgUjsoTl+/vjhmsIWclN\n7k3yej4e55F7zvnecz73cI1vvnzP+YYYI5IkSVJHl5XuAiRJkqRMYDCWJEmSMBhLkiRJgMFYkiRJ\nAgzGkiRJEmAwliRJkoBGBOMQwp0hhA9DCPPraXNTCGFxCGFeCOGw1JYoSZIktbzG9BjfBYyra2cI\n4URgeIxxP+AC4LYU1SZJkiS1mgaDcYzxFaC8nianAvdWtX0NyA0h9E9NeZIkSVLrSMUY40Lgg2rr\nZVXbJEmSpDbDm+8kSZIkoHMKjlEGFFdbL6ratocQQkzB+SRJkqQGxRhDU9o3NhiHqqU2jwEXAg+F\nED4PbIgxflhPgU2pT2o1JSUllJSUpLsMaQ9+N5Wp/G4qk4XQpEwMNCIYhxBmA6OB/BDCcuAHQBcg\nxhhvjzE+FUI4KYSwBPgEmNbkKiRJkqQ0azAYxxinNKLNd1JTjiRJkpQe3nwnVRk9enS6S5Bq5XdT\nmcrvptqb0JpjfkMI0THGkiRJamkhhBa7+U6SJLUjQ4cOZdmyZekuQ2q2IUOG8H//938pOZY9xpIk\ndUBVvWnpLkNqtrq+y3vTY+wYY0mSJAmDsSRJkgQYjCVJkiTAYCxJktSgk046ifvuuy/dZaiFdbib\n7371K1i/Pq0l7CaE+pesrIbbNHcRdOsGRx+d7iokqfVk+s13c+bM4YYbbuCdd94hJyeHYcOGcc45\n5/Ctb30r3aWl1D333MO0adOYNWsWl1xySXJ7cXExDzzwAF/84heZOXMmP/nJT+jWrVty349+9CNO\nP/30eo9dWlrKl7/8Za655houvfTSFv0c6ZTKm++IMbbaAkQXFxcXFxeXzFgy1XXXXRcHDBgQf/3r\nX8eNGzfGGGOcN29ePPvss2NlZWWaq0utu+++O+bn58d99tkn+VljjLGoqCi+9NJLMcYYS0pK4tSp\nU5P7nn322di9e/e4evXqeo89bdq0WFBQED/72c+2TPH12L59e6udq4HveJOyaqsPpWhqgS4urbEc\nfXTk979Pfx0uLi4urbVkqoqKCn7wgx9w66238pWvfIWePXsCcOihh3LfffeRnZ0NwFNPPcURRxxB\nbm4uQ4YMYebMmcljvPTSSxQXF+923GHDhvHCCy8A8MYbbzBy5Ehyc3MZOHBgsqd269atTJ06lYKC\nAvLy8jjyyCNZs2YNAMcddxy//OUvAXj//fcZM2YMBQUF9OvXj7PPPpuKiordznX99ddz6KGHkpeX\nx+TJk6msrKzzMx900EEcddRRXH/99Y26RmPHjqVXr14sXbq0zjabNm3i0Ucf5eabb2bx4sX85S9/\n2W3/K6+8wtFHH01eXh5Dhgzh3nvvBWDLli1873vfY+jQoeTl5fHFL36RrVu3NnhNZ86cyYQJE5g6\ndSp9+vThnnvu4Y033uALX/gCeXl5FBYW8i//8i9s3749+f4FCxYwduxY8vPzGThwIP/5n//Jhx9+\nSM+ePSkvL0+2+8tf/kK/fv3YsWNHnZ83Vd9xxxhLQFERrFiR7iokSX/605+orKzklFNOqbddTk4O\n9913Hx999BFPPvkkt912G4899lhyf6hnrOBFF13E9OnT+eijj1i6dCkTJ04EEsMaKioqKCsrY/36\n9dx222107959j/fHGLniiitYtWoV7777LitWrKCkpGS3No888gjPPfccf/vb33j77be5++6766wn\nhMCPfvQjbrjhBjZs2FDv5wZ48skn2bZtGwcffHCdbX71q1/Rq1cvJkyYwNixY7nnnnuS+5YvX85J\nJ53ERRddxNq1a5k3bx6HHXYYAN/73vd46623ePXVV1m/fj2zZs0iKysrWWd9HnvsMSZOnMiGDRs4\n66yz6Ny5MzfccAPr16/nT3/6Ey+88AK33HILABs3buT444/npJNOYuXKlSxZsoQxY8bQv39/jjvu\nOB5++OHkce+//34mT55Mp06dGrw2zWUwljAYS1KmWLt2LQUFBckwBiR7Nnv06MErr7wCwBe/+EVG\njBgBwGc/+1kmTZrESy+91KhzdOnShSVLlrBu3Tp69OjBqFGjAMjOzmbdunUsWrSIEAKHH344OTk5\ne7x/+PDhjBkzhs6dO5Ofn8/FF1+8x7kvuugi+vfvT58+fRg/fjzz5s2rt6ZDDjmE448/nmuuuabW\n/Q899BB9+/YlJyeH0047jSuuuILevXvXebx7772XSZMmEUJgypQpzJkzJ9njOnv2bI4//ngmTpxI\np06dyMvL45BDDiHGyF133cVNN93EgAEDCCHw+c9/PtlL35CjjjqK8ePHA9C1a1cOP/xwRo0aRQiB\nwYMHc/755yev0xNPPMHAgQOZPn06Xbp0oWfPnowcORKAc845J3mj486dO3nwwQeZOnVqo2poLoOx\nhMFYkmqTjhu88/PzWbt2LTt37kxu+8Mf/kB5eTkFBQXJ7a+99hpf/vKX6devH3369OG//uu/WLt2\nbaPOceedd7Jw4UIOPPBAjjzySJ588kkApk6dyrhx45g0aRJFRUVcfvnltf7z/erVq5k8eTJFRUX0\n6dOHs88+e49z9+/fP/m6R48ebNy4scG6fvjDH3LrrbeyevXqPfadeeaZrF+/no0bN7J06VLuuece\n7rjjjlqPs2LFCl588UWmTJkCwCmnnMLmzZuTn/ODDz5g+PDhe7xv7dq1bN26lX333bfBWmtTc6jF\n4sWLGT9+PAMHDqRPnz58//vfT16numoAOPXUU3n33XdZtmwZzz33HH369OFzn/vcXtXUVAZjCYOx\nJNUmxuYvTXXUUUfRtWtXfvvb39ZSz6cHPOusszjttNMoKytjw4YNXHDBBcn9PXv2ZNOmTcm2O3bs\nSI4VhkSP7+zZs1mzZg2XXXYZZ5xxBps3b6Zz585ceeWVLFiwgD/+8Y888cQTybG31V1xxRVkZWWx\nYMECNmzYwP3335+ScdsHHHAAp59+Oj/5yU/qHbYwePBgTjzxRB5//PFa9997773EGJOhdPjw4Wzd\nujU5nKK4uJglS5bs8b6CggK6detW69jlhq4p7DnU4lvf+hYHHXQQS5cuZcOGDfzkJz9JXqfi4uI6\nx0h37dqViRMnct9993H//fe3Wm8xGIwlwGAsSZkiNzeXq666im9/+9v86le/YuPGjcQYmTdv3m7B\nbOPGjeTl5ZGdnc3rr7/O7Nmzk/v2339/tmzZwtNPP8327dv58Y9/vNvNbw888ECy5zI3N5cQAllZ\nWZSWlvLOO++wc+dOcnJyyM7OrnVc68cff0xOTg69evWirKyMa6+9NmWf/6qrruKuu+7aY6xx9eC9\nYsUKnnnmGT772c/Weox7772XkpIS5s2bx9tvv83bb7/No48+ypNPPkl5eTlnnXUWc+fO5dFHH2XH\njh2sX7+et99+mxAC06ZN47vf/S4rV65k586dvPrqq2zbtq3Ba1qbjz/+mN69e9OjRw/ee+89br31\n1uS+k08+mVWrVnHTTTdRWVnJxo0bef3115P7p06dyt13383jjz9uMJZam8FYkjLHpZdeyk9/+lNm\nzZrFgAEDGDBgAN/61reYNWsWX/jCFwC45ZZbuPLKK8nNzeXHP/4xZ555ZvL9vXv35pZbbuGf//mf\nKSoqolevXhQVFSX3P/PMM4wYMYLevXtz8cUX89BDD9G1a1dWrVrFGWecQW5uLiNGjOC4447j7LPP\nBnbvDf3BD37An//85+T44a9+9au71d/QTWr1GTp0KFOnTuWTTz7ZbfvDDz9M79696d27N0ceeSTH\nHnssV1111R7vf+2111i+fDnf/va36devX3IZP348++23Hw8++CDFxcU89dRTXHfddfTt25fDDz+c\n+fPnA3DdddfxD//wD4wcOZL8/HxmzJjBzp07G7ymtbnuuut44IEH6N27NxdccAGTJk1K7svJyeH5\n55/nscceY8CAAey///6UlpYm93/hC18gKyuLI444Yo8hGi2pw03wIdVm+3bo0QM++QQaeY+BJLVp\nmT7BhzRmzBjOOusszj333HrbpXKCD3uMJaBzZ9hnH1i1Kt2VSJKkN954g7feemu3fwloDQZjqYrD\nKSRJSr+vf/3rjB07lhtvvDE5wUtr6dyqZ5MymMFYkqT0q28ylJZmj7FUxWAsSVLHZjCWqhiMJUnq\n2AzGUhWDsSRJHZvBWKpiMJYkqWMzGEtVDMaSJHVsBmOpyqBBsHIl7NiR7kokSc1x9dVXc/7556e7\nDLVBBmOpSteukJcHq1enuxJJ6tiGDh1K//792bx5c3LbnXfeyXHHHdeo9//bv/0bt99+e4vU9vzz\nz/PlL3+Z3r17s88++3DEEUdw7bXXUllZ2SLnU+syGEvVOJxCktIvhMDOnTu54YYb9tieTo888ggT\nJkzg7LPPZvny5axZs4aHHnqIFStW8MEHH6S1NqWGwViqpqgIysrSXYUk6dJLL+X666+noqKi1v3T\np09n8ODB5ObmMnLkSF555ZXkvpkzZ3LOOecAcNJJJ3HLLbfs9t7DDjuM//mf/wHgvffeY+zYseTn\n53PQQQfxyCOP1FnT9773PUpKSjj33HPp06cPAPvttx833ngjw4cPB2DatGlcddVVyfe89NJLFBcX\nJ9dXrlzJGWecQb9+/Rg+fDg///nPk/veeOMNRo4cSW5uLgMHDuSSSy4BYOvWrUydOpWCggLy8vI4\n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\nP38+S5YsoaysjB/+8IfJtqtWrWLDhg0sX76c22+/neuvv57i4mLWrVvH6tWr+Y//+A8AYoyMHz+e\nww8/nJUrVzJ37lxuvPFGnn/++Tpr7tGjB1dccQVXXHFFrfv79+/PU089RUVFBXfddRcXX3wx8+bN\nS+7f1bs8adIknn76aT755BMAdu7cySOPPJL8jF/72tfo0qUL77//Pm+99RbPP/88//3f/13rOX/3\nu9/x1a9+tf6LzZ4929XX67umdV2/RYsWcfPNN/PnP/+ZiooKnn32WYYOHdpgHelgMJZqYTCWpMwx\nZMgQzj33XEIIfO1rX2PlypWsXr2a7t27c8opp/Dggw8CsHjxYhYuXMgpp5wCwB133MHPfvYzcnNz\n6dmzJzNmzEi2BejUqRMzZ84kOzubrl27kp2dzcqVK/nb3/5Gp06dOProowF44403WLt2Ld///vfp\n1KkTQ4cO5Rvf+AZz5sypt+7zzz+f5cuXJ3u4qzvxxBOT4fDYY49l7NixtfYuDx48mCOOOILf/OY3\nAMydO5eePXsycuRIPvzwQ55++ml+9rOf0a1bNwoKCpg+ffpun7G6tWvXMmDAgOT6zTffTF5eHr16\n9eKCCy6o83NU74Gu75rWdf06depEZWUl77zzDtu3b2fw4MEMGzas3muXLgZjqRZFRVBWlu4qJCm9\nQgjNXlKhepjr3r07ABs3bgRgypQpyWA2e/ZsTjvtNLp27cqaNWvYtGkT//iP/0jfvn3p27cvJ554\nIuvWrUsea5999iE7Ozu5ftlllzF8+HDGjh3LZz7zGa655hoAli1bRllZWfI4eXl5XH311axevbre\nurt06cKVV17JlVdeuce+p59+mqOOOor8/Hzy8vJ4+umnWbt2ba3HmTx5cvIzPvjgg0yZMgWA5cuX\ns23bNgYOHJis65vf/Gadx8nPz2flypXJ9QsvvJDy8nKmT5/Otm3b6v0sQIPX9NJLL631+g0fPpwb\nbriBkpIS+vfvz5QpU3arI5MYjKVa2GMsSYmewuYuLe34449nzZo1vP3228yZMycZGgsKCujRowcL\nFixg/fr1rF+/ng0bNvBRtWdx1gzuPXv25LrrrmPp0qU89thj/PSnP+XFF1+kuLiYfffdN3mc8vJy\nPvroIx5//PEG65s2bRobNmzg17/+dXJbZWUlZ5xxBpdddhlr1qyhvLycE088sc7rNWHCBEpLSykr\n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\nrkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def evaluate_gnb_full(dims):\n", + " pca = PCA(n_components=dims)\n", + " X_xform = pca.fit_transform(X)\n", + " \n", + " gnb = GaussianNB()\n", + " gnb.fit(X_xform, y)\n", + " return gnb.score(X_xform, y)\n", + "\n", + "dim_range = np.arange(1, 21)\n", + "plt.plot(dim_range, [evaluate_gnb(dim) for dim in dim_range], label=\"Gaussian NB Accuracy\")\n", + "plt.axhline(naive_guess, label=\"Naive Guess\", c='k')\n", + "plt.axhline(1 - naive_guess, label=\"Inverse Naive Guess\", c='k')\n", + "plt.gcf().set_size_inches(12, 6)\n", + "plt.legend();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nothing. It is interesting to note that the graphs are almost exactly the same: This would imply again that the variables we removed earlier (all the binary classifiers) indeed have almost no predictive power. It seems this problem is high-dimensional, but with almost no data that can actually inform our decisions.\n", + "\n", + "# Summary for Day 1\n", + "\n", + "After spending a couple hours with this dataset, there seems to be a fundamental issue in play: We have very high-dimensional data, and it has no bearing on our ability to actually predict customer satisfaction. This can be a huge issue: it implies that **no matter what model we use, we fundamentally can't perform well.** I'm sure most of this is because I'm not an experienced data scientist. Even so, we have yet to develop a strategy that can actually beat out the village idiot; **so far, the bank is best off just assuming all its customers are satisfied.** Hopefully more to come soon." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running time: 0:00:58.715714\n" + ] + } + ], + "source": [ + "end = datetime.now()\n", + "print(\"Running time: {}\".format(end - start))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Appendix\n", + "\n", + "Code used to split the initial training data:\n", + "\n", + "```python\n", + "from sklearn.cross_validation import train_test_split\n", + "data = pd.read_csv('train.csv')\n", + "data.index = data.ID\n", + "\n", + "data_train, data_validate = train_test_split(\n", + " data, train_size=.7)\n", + "\n", + "data_train.to_csv('split_train.csv')\n", + "data_validate.to_csv('split_validate.csv')\n", + "```" + ] + } + ], + "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.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/blog/2016-03-05-predicting-santander-customer-happiness/_notebook.md b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook.md new file mode 100644 index 0000000..2afcdd9 --- /dev/null +++ b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook.md @@ -0,0 +1,269 @@ +### My first Kaggle competition + +It's time! After embarking on a Machine Learning class this semester, and with a Saturday in which I don't have much planned, I wanted to put this class and training to work. It's my first competition submission. I want to walk you guys through how I'm approaching this problem, because I thought it would be really neat. The competition is Banco Santander's [Santander Customer Satisfaction][1] competition. It seemed like an easy enough problem I could actually make decent progress on it. + +# Data Exploration + +First up: we need to load our data and do some exploratory work. Because we're going to be using this data for model selection prior to testing, we need to make a further split. I've already gone ahead and done this work, please see the code in the [appendix below](#Appendix). + +[1]: https://www.kaggle.com/c/santander-customer-satisfaction + + +```python +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +%matplotlib inline + +# Record how long it takes to run the notebook - I'm curious. +from datetime import datetime +start = datetime.now() + +dataset = pd.read_csv('split_train.csv') +dataset.index = dataset.ID +X = dataset.drop(['TARGET', 'ID', 'ID.1'], 1) +y = dataset.TARGET +``` + + +```python +y.unique() +``` + + + + + array([0, 1], dtype=int64) + + + + +```python +len(X.columns) +``` + + + + + 369 + + + +Okay, so there are only [two classes we're predicting][2]: 1 for unsatisfied customers, 0 for satisfied customers. I would have preferred this to be something more like a regression, or predicting multiple classes: maybe the customer isn't the most happy, but is nowhere near closing their accounts. For now though, that's just the data we're working with. + +Now, I'd like to make a scatter matrix of everything going on. Unfortunately as noted above, we have 369 different features. There's no way I can graphically make sense of that much data to start with. + +We're also not told what the data actually represents: Are these survey results? Average time between contact with a customer care person? Frequency of contacting a customer care person? The idea is that I need to reduce the number of dimensions we're predicting across. + +## Dimensionality Reduction pt. 1 - Binary Classifiers + +My first attempt to reduce the data dimensionality is to find all the binary classifiers in the dataset \(i.e. 0 or 1 values\) and see if any of those are good \(or anti-good\) predictors of the final data. + +[2]: https://www.kaggle.com/c/santander-customer-satisfaction/data + + +```python +cols = X.columns +b_class = [] +for c in cols: + if len(X[c].unique()) == 2: + b_class.append(c) + +len(b_class) +``` + + + + + 111 + + + +So there are 111 features in the dataset that are a binary label. Let's see if any of them are good at predicting the users satisfaction! + + +```python +# First we need to `binarize` the data to 0-1; some of the labels are {0, 1}, +# some are {0, 3}, etc. +from sklearn.preprocessing import binarize +X_bin = binarize(X[b_class]) + +accuracy = [np.mean(X_bin[:,i] == y) for i in range(0, len(b_class))] +acc_df = pd.DataFrame({"Accuracy": accuracy}, index=b_class) +acc_df.describe() +``` + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accuracy
count111.000000
mean0.905159
std0.180602
min0.043598
25%0.937329
50%0.959372
75%0.960837
max0.960837
+
+ + + +Wow! Looks like we've got some incredibly predictive features! So much so that we should be a bit concerned. My initial guess for what's happening is that we have a sparsity issue: so many of the values are 0, and these likely happen to line up with satisfied customers. + +So the question we must now answer, which I likely should have asked long before now: What exactly is the distribution of un/satisfied customers? + + +```python +unsat = y[y == 1].count() +print("Satisfied customers: {}; Unsatisfied customers: {}".format(len(y) - unsat, unsat)) +naive_guess = np.mean(y == np.zeros(len(y))) +print("Naive guess accuracy: {}".format(naive_guess)) +``` + + Satisfied customers: 51131; Unsatisfied customers: 2083 + Naive guess accuracy: 0.9608561656706882 + + +This is a bit discouraging. A naive guess of "always satisfied" performs as well as our best individual binary classifier. What this tells me then, is that these data columns aren't incredibly helpful in prediction. I'd be interested in a polynomial expansion of this data-set, but for now, that's more computation than I want to take on. + +# Dimensionality Reduction pt. 2 - LDA + +Knowing that our naive guess performs so well is a blessing and a curse: + +- Curse: The threshold for performance is incredibly high: We can only "improve" over the naive guess by 4% +- Blessing: All the binary classification features we just discovered are worthless on their own. We can throw them out and reduce the data dimensionality from 369 to 111. + +Now, in removing these features from the dataset, I'm not saying that there is no "information" contained within them. There might be. But the only way we'd know is through a polynomial expansion, and I'm not going to take that on within this post. + +My initial thought for a "next guess" is to use the [LDA][3] model for dimensionality reduction. However, it can only reduce dimensions to $1 - p$, with $p$ being the number of classes. Since this is a binary classification, every LDA model that I try will have dimensionality one; when I actually try this, the predictor ends up being slightly less accurate than the naive guess. + +Instead, let's take a different approach to dimensionality reduction: [principle components analysis][4]. This allows us to perform the dimensionality reduction without worrying about the number of classes. Then, we'll use a [Gaussian Naive Bayes][5] model to actually do the prediction. This model is chosen simply because it doesn't take a long time to fit and compute; because PCA will take so long, I just want a prediction at the end of this. We can worry about using a more sophisticated LDA/QDA/SVM model later. + +Now into the actual process: We're going to test out PCA dimensionality reduction from 1 - 20 dimensions, and then predict using a Gaussian Naive Bayes model. The 20 dimensions upper limit was selected because the accuracy never improves after you get beyond that \(I found out by running it myself\). Hopefully, we'll find that we can create a model better than the naive guess. + +[3]:http://scikit-learn.org/stable/modules/lda_qda.html +[4]:http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html +[5]:http://scikit-learn.org/stable/modules/naive_bayes.html#gaussian-naive-bayes + + +```python +from sklearn.naive_bayes import GaussianNB +from sklearn.decomposition import PCA + +X_no_bin = X.drop(b_class, 1) + +def evaluate_gnb(dims): + pca = PCA(n_components=dims) + X_xform = pca.fit_transform(X_no_bin) + + gnb = GaussianNB() + gnb.fit(X_xform, y) + return gnb.score(X_xform, y) + +dim_range = np.arange(1, 21) +plt.plot(dim_range, [evaluate_gnb(dim) for dim in dim_range], label="Gaussian NB Accuracy") +plt.axhline(naive_guess, label="Naive Guess", c='k') +plt.axhline(1 - naive_guess, label="Inverse Naive Guess", c='k') +plt.gcf().set_size_inches(12, 6) +plt.legend(); +``` + + + +![png](_notebook_files/_notebook_11_0.png) + + + +\*\*sigh...\*\* After all the effort and computational power, we're still at square one: we have yet to beat out the naive guess threshold. With PCA in play we end up performing terribly, but not terribly enough that we can guess against ourselves. + +Let's try one last-ditch attempt using the entire data set: + + +```python +def evaluate_gnb_full(dims): + pca = PCA(n_components=dims) + X_xform = pca.fit_transform(X) + + gnb = GaussianNB() + gnb.fit(X_xform, y) + return gnb.score(X_xform, y) + +dim_range = np.arange(1, 21) +plt.plot(dim_range, [evaluate_gnb(dim) for dim in dim_range], label="Gaussian NB Accuracy") +plt.axhline(naive_guess, label="Naive Guess", c='k') +plt.axhline(1 - naive_guess, label="Inverse Naive Guess", c='k') +plt.gcf().set_size_inches(12, 6) +plt.legend(); +``` + + + +![png](_notebook_files/_notebook_13_0.png) + + + +Nothing. It is interesting to note that the graphs are almost exactly the same: This would imply again that the variables we removed earlier (all the binary classifiers) indeed have almost no predictive power. It seems this problem is high-dimensional, but with almost no data that can actually inform our decisions. + +# Summary for Day 1 + +After spending a couple hours with this dataset, there seems to be a fundamental issue in play: We have very high-dimensional data, and it has no bearing on our ability to actually predict customer satisfaction. This can be a huge issue: it implies that **no matter what model we use, we fundamentally can't perform well.** I'm sure most of this is because I'm not an experienced data scientist. Even so, we have yet to develop a strategy that can actually beat out the village idiot; **so far, the bank is best off just assuming all its customers are satisfied.** Hopefully more to come soon. + + +```python +end = datetime.now() +print("Running time: {}".format(end - start)) +``` + + Running time: 0:00:58.715714 + + +# Appendix + +Code used to split the initial training data: + +```python +from sklearn.cross_validation import train_test_split +data = pd.read_csv('train.csv') +data.index = data.ID + +data_train, data_validate = train_test_split( + data, train_size=.7) + +data_train.to_csv('split_train.csv') +data_validate.to_csv('split_validate.csv') +``` diff --git a/blog/2016-03-05-predicting-santander-customer-happiness/_notebook_files/_notebook_11_0.png b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook_files/_notebook_11_0.png new file mode 100644 index 0000000..6843a02 Binary files /dev/null and b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook_files/_notebook_11_0.png differ diff --git a/blog/2016-03-05-predicting-santander-customer-happiness/_notebook_files/_notebook_13_0.png b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook_files/_notebook_13_0.png new file mode 100644 index 0000000..6843a02 Binary files /dev/null and b/blog/2016-03-05-predicting-santander-customer-happiness/_notebook_files/_notebook_13_0.png differ diff --git a/blog/2016-03-05-predicting-santander-customer-happiness/index.mdx b/blog/2016-03-05-predicting-santander-customer-happiness/index.mdx new file mode 100644 index 0000000..10db523 --- /dev/null +++ b/blog/2016-03-05-predicting-santander-customer-happiness/index.mdx @@ -0,0 +1,256 @@ +--- +slug: 2016/03/predicting-santander-customer-happiness +title: Predicting Santander customer happiness +date: 2016-03-05 12:00:00 +authors: [bspeice] +tags: [] +--- + +My first Kaggle competition. + + + +It's time! After embarking on a Machine Learning class this semester, and with a Saturday in which I don't have much planned, I wanted to put this class and training to work. It's my first competition submission. I want to walk you guys through how I'm approaching this problem, because I thought it would be really neat. The competition is Banco Santander's [Santander Customer Satisfaction][1] competition. It seemed like an easy enough problem I could actually make decent progress on it. + +## Data Exploration + +First up: we need to load our data and do some exploratory work. Because we're going to be using this data for model selection prior to testing, we need to make a further split. I've already gone ahead and done this work, please see the code in the [appendix below](#appendix). + +[1]: https://www.kaggle.com/c/santander-customer-satisfaction + + +```python +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +%matplotlib inline + +# Record how long it takes to run the notebook - I'm curious. +from datetime import datetime +start = datetime.now() + +dataset = pd.read_csv('split_train.csv') +dataset.index = dataset.ID +X = dataset.drop(['TARGET', 'ID', 'ID.1'], 1) +y = dataset.TARGET +``` + + +```python +y.unique() +``` + +``` + array([0, 1], dtype=int64) +``` + +```python +len(X.columns) +``` + +``` + 369 +``` + +Okay, so there are only [two classes we're predicting][2]: 1 for unsatisfied customers, 0 for satisfied customers. I would have preferred this to be something more like a regression, or predicting multiple classes: maybe the customer isn't the most happy, but is nowhere near closing their accounts. For now though, that's just the data we're working with. + +Now, I'd like to make a scatter matrix of everything going on. Unfortunately as noted above, we have 369 different features. There's no way I can graphically make sense of that much data to start with. + +We're also not told what the data actually represents: Are these survey results? Average time between contact with a customer care person? Frequency of contacting a customer care person? The idea is that I need to reduce the number of dimensions we're predicting across. + +### Dimensionality Reduction pt. 1 - Binary Classifiers + +My first attempt to reduce the data dimensionality is to find all the binary classifiers in the dataset \(i.e. 0 or 1 values\) and see if any of those are good \(or anti-good\) predictors of the final data. + +[2]: https://www.kaggle.com/c/santander-customer-satisfaction/data + + +```python +cols = X.columns +b_class = [] +for c in cols: + if len(X[c].unique()) == 2: + b_class.append(c) + +len(b_class) +``` + +``` + 111 +``` + +So there are 111 features in the dataset that are a binary label. Let's see if any of them are good at predicting the users satisfaction! + +```python +# First we need to `binarize` the data to 0-1; some of the labels are {0, 1}, +# some are {0, 3}, etc. +from sklearn.preprocessing import binarize +X_bin = binarize(X[b_class]) + +accuracy = [np.mean(X_bin[:,i] == y) for i in range(0, len(b_class))] +acc_df = pd.DataFrame({"Accuracy": accuracy}, index=b_class) +acc_df.describe() +``` + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accuracy
count111.000000
mean0.905159
std0.180602
min0.043598
25%0.937329
50%0.959372
75%0.960837
max0.960837
+
+ +Wow! Looks like we've got some incredibly predictive features! So much so that we should be a bit concerned. My initial guess for what's happening is that we have a sparsity issue: so many of the values are 0, and these likely happen to line up with satisfied customers. + +So the question we must now answer, which I likely should have asked long before now: What exactly is the distribution of un/satisfied customers? + +```python +unsat = y[y == 1].count() +print("Satisfied customers: {}; Unsatisfied customers: {}".format(len(y) - unsat, unsat)) +naive_guess = np.mean(y == np.zeros(len(y))) +print("Naive guess accuracy: {}".format(naive_guess)) +``` + +``` + Satisfied customers: 51131; Unsatisfied customers: 2083 + Naive guess accuracy: 0.9608561656706882 +``` + +This is a bit discouraging. A naive guess of "always satisfied" performs as well as our best individual binary classifier. What this tells me then, is that these data columns aren't incredibly helpful in prediction. I'd be interested in a polynomial expansion of this data-set, but for now, that's more computation than I want to take on. + +### Dimensionality Reduction pt. 2 - LDA + +Knowing that our naive guess performs so well is a blessing and a curse: + +- Curse: The threshold for performance is incredibly high: We can only "improve" over the naive guess by 4% +- Blessing: All the binary classification features we just discovered are worthless on their own. We can throw them out and reduce the data dimensionality from 369 to 111. + +Now, in removing these features from the dataset, I'm not saying that there is no "information" contained within them. There might be. But the only way we'd know is through a polynomial expansion, and I'm not going to take that on within this post. + +My initial thought for a "next guess" is to use the [LDA][3] model for dimensionality reduction. However, it can only reduce dimensions to $1 - p$, with $p$ being the number of classes. Since this is a binary classification, every LDA model that I try will have dimensionality one; when I actually try this, the predictor ends up being slightly less accurate than the naive guess. + +Instead, let's take a different approach to dimensionality reduction: [principle components analysis][4]. This allows us to perform the dimensionality reduction without worrying about the number of classes. Then, we'll use a [Gaussian Naive Bayes][5] model to actually do the prediction. This model is chosen simply because it doesn't take a long time to fit and compute; because PCA will take so long, I just want a prediction at the end of this. We can worry about using a more sophisticated LDA/QDA/SVM model later. + +Now into the actual process: We're going to test out PCA dimensionality reduction from 1 - 20 dimensions, and then predict using a Gaussian Naive Bayes model. The 20 dimensions upper limit was selected because the accuracy never improves after you get beyond that \(I found out by running it myself\). Hopefully, we'll find that we can create a model better than the naive guess. + +[3]:http://scikit-learn.org/stable/modules/lda_qda.html +[4]:http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html +[5]:http://scikit-learn.org/stable/modules/naive_bayes.html#gaussian-naive-bayes + + +```python +from sklearn.naive_bayes import GaussianNB +from sklearn.decomposition import PCA + +X_no_bin = X.drop(b_class, 1) + +def evaluate_gnb(dims): + pca = PCA(n_components=dims) + X_xform = pca.fit_transform(X_no_bin) + + gnb = GaussianNB() + gnb.fit(X_xform, y) + return gnb.score(X_xform, y) + +dim_range = np.arange(1, 21) +plt.plot(dim_range, [evaluate_gnb(dim) for dim in dim_range], label="Gaussian NB Accuracy") +plt.axhline(naive_guess, label="Naive Guess", c='k') +plt.axhline(1 - naive_guess, label="Inverse Naive Guess", c='k') +plt.gcf().set_size_inches(12, 6) +plt.legend(); +``` + +![png](_notebook_files/_notebook_11_0.png) + +**sigh...** After all the effort and computational power, we're still at square one: we have yet to beat out the naive guess threshold. With PCA in play we end up performing terribly, but not terribly enough that we can guess against ourselves. + +Let's try one last-ditch attempt using the entire data set: + + +```python +def evaluate_gnb_full(dims): + pca = PCA(n_components=dims) + X_xform = pca.fit_transform(X) + + gnb = GaussianNB() + gnb.fit(X_xform, y) + return gnb.score(X_xform, y) + +dim_range = np.arange(1, 21) +plt.plot(dim_range, [evaluate_gnb(dim) for dim in dim_range], label="Gaussian NB Accuracy") +plt.axhline(naive_guess, label="Naive Guess", c='k') +plt.axhline(1 - naive_guess, label="Inverse Naive Guess", c='k') +plt.gcf().set_size_inches(12, 6) +plt.legend(); +``` + +![png](_notebook_files/_notebook_13_0.png) + +Nothing. It is interesting to note that the graphs are almost exactly the same: This would imply again that the variables we removed earlier (all the binary classifiers) indeed have almost no predictive power. It seems this problem is high-dimensional, but with almost no data that can actually inform our decisions. + +## Summary for Day 1 + +After spending a couple hours with this dataset, there seems to be a fundamental issue in play: We have very high-dimensional data, and it has no bearing on our ability to actually predict customer satisfaction. This can be a huge issue: it implies that **no matter what model we use, we fundamentally can't perform well.** I'm sure most of this is because I'm not an experienced data scientist. Even so, we have yet to develop a strategy that can actually beat out the village idiot; **so far, the bank is best off just assuming all its customers are satisfied.** Hopefully more to come soon. + + +```python +end = datetime.now() +print("Running time: {}".format(end - start)) +``` + +``` + Running time: 0:00:58.715714 +``` + +## Appendix + +Code used to split the initial training data: + +```python +from sklearn.cross_validation import train_test_split +data = pd.read_csv('train.csv') +data.index = data.ID + +data_train, data_validate = train_test_split( + data, train_size=.7) + +data_train.to_csv('split_train.csv') +data_validate.to_csv('split_validate.csv') +``` \ No newline at end of file diff --git a/blog/2016-04-06-tick-tock/index.mdx b/blog/2016-04-06-tick-tock/index.mdx index 9d2f79f..4311879 100644 --- a/blog/2016-04-06-tick-tock/index.mdx +++ b/blog/2016-04-06-tick-tock/index.mdx @@ -8,7 +8,7 @@ tags: [] If all we have is a finite number of heartbeats left, what about me? ---- + Warning: this one is a bit creepier. But that's what you get when you come up with data science ideas as you're drifting off to sleep. diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_article.md b/blog/2016-06-08-event-studies-and-earnings-releases/_article.md new file mode 100644 index 0000000..e5ad4bf --- /dev/null +++ b/blog/2016-06-08-event-studies-and-earnings-releases/_article.md @@ -0,0 +1,17 @@ +Title: Event Studies and Earnings Releases +Date: 2016-06-08 +Category: Blog +Tags: event study, earnings +Authors: Bradlee Speice +Summary: Looking at earnings releases to see how good people are at actually predicting earnings. +[//]: <> "Modified: " + + + +{% notebook 2016-6-8-event-studies-and-earnings-releases.ipynb %} + + + diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook.ipynb b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook.ipynb new file mode 100644 index 0000000..87f3b58 --- /dev/null +++ b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook.ipynb @@ -0,0 +1,994 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or, being suspicious of market insiders.\n", + "\n", + "---\n", + "\n", + "Use the button below to show the code I've used to generate this article. Because there is a significant amount more code involved than most other posts I've written, it's hidden by default to allow people to concentrate on the important bits." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import HTML\n", + "\n", + "HTML('''\n", + "
''')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The Market Just Knew\n", + "\n", + "I recently saw two examples of stock charts that have kept me thinking for a while. And now that the semester is complete, I finally have enough time to really look at them and give them the treatment they deserve. The first is good old Apple:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEKCAYAAAACS67iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xt8XHWd//HXu1D40bRJ0yJJtaUtClJQEFbkKgRdtsIu\nFwUR+CEg6HpDWDSr6PrbpojKJeKusAishYJSFcUtKIKAENyiqCsod+RiWygkwLaQNlwK6ef3xzmJ\n0+lMMrnMzMnk/Xw85pGZc75zvp85mfnMd77n+z1HEYGZmY19E6odgJmZjQ4ndDOzGuGEbmZWI5zQ\nzcxqhBO6mVmNcEI3M6sRTujjlKQTJf13her6tqR/qURdZuOZE/oYIKlD0mpJE0d508OahJDG87Kk\nbknPSrpWUlPRSiI+GRFfHX6YBWP4kKSHJb0oqVPSFZIm55WZIenJ9P6nJf1e0iuSLi+yzTMlnS1p\nT0k3S/pfSV2SfiipOa/suZKel/ScpHPy1p0l6V5Jr0n61wL1bC3pakkvpHV8dwT7YYGk9en/Ym36\nd05emb0k3VlKbGmZSyR9VNIhkv5b0hpJT0u6TFJdTrktJF2e/g+elnRG3nYuTf9HvZJOKFDPXEk/\nzXkfnZNfxobGCT3jJM0G9gM2AIdVOZw+AXwqIuqBHYCpwDcLFZRUrvfYncD+EdEAbAdMBM7OK3MI\ncGN6fxXwFWDRANv8e+DnQCNwKTA7va0DrugrJOnjJP+LtwO7AIdK+sec7TwK/DPwsyL1/AR4GpgJ\nbAO0DxBTKX4QEfURMSX9u7zA67qhxNgADibZDw0k+2wGMC+N9/yccguBNwOzgPcAn5f0dznr/wh8\nEvhDfgVp4+QW4FaSfTAT+N6gr9QG5ISefScAvwEWAyflrkhbpd9OW5Pdkm6XtG3O+g2SPiPp8bQF\ndF6xSiTtmNMqfUjSBweJSwAR8QJwLfC2nJgulnSDpLVAS7rsrJy6Dpd0T9qye7QvCUiql/SdtLX3\npKSvSFKhyiPiqYh4Nn04AegF3pJX7BCSxERELI2I64HVRV7/VGB74DcRcVNEXBsR6yLiFeAiYJ+c\n4icA34iIZyLiGZKEfFJObN+NiF+QfBHk13MQSfL6fLr93oj4U6GYRlHufigaWxrf24E1EfF0RHw/\nIm6OiFci4kXgP4F9c4qfAJwVEd0R8TBwGRvvh29HxO3AqwWqOglYFRH/nm5/fUTcP/KXOr45oWff\nCSQtlyXAfElvyFt/HElLaTrwJ+DqvPVHALunt8MlnZxfgaRJwM1pPVsDxwD/IWnHwYKTtDVwJHB3\nzuJjga9ExBSSlnRu+XcBVwKfS1vX+wPL09VXAutJWty7AQcBHx2g7n0lvQB0Ax8g51eCpM3Tbd8y\n2GtIzQd+GYXPhXEA8EDO451J9nWfP6XLSrEX8GfgqrTL5reS9i/xucUcmm7rPkmfyF2RdhVtExF/\nLHFbh/DX1ny+/v2QfgHOAO7NWT/U/bBC0s/TbqvbJL2txOdaEU7oGSZpP2Bb4JqIuBt4jCSB57oh\nIu6MiNeAfwH2lvSmnPXnRMSLEfEU8G8kyTbfPwB/iYirIvEnkm6BgVrpF0paDdxD0n3wuZx110XE\nXQARkd86OxlYFBG3peufiYg/S9qG5Kf+GWmL7fkB4iV97p0RMRV4E0lXwMqc1fsDf4yIngFeQ66+\n7paNSNoF+H9Aa87iycCLOY+702WlmEnyRfVLoAm4ALhO0rQSn5/vhyTdIW8A/hH4V0kfyll/CHDT\nELZXbD8cBHyYZF9A8nqDTffDlBLrmQl8iOR/PCOt87r0i9iGyQk9204Abo6INenj7wMn5pV5su9O\nmrxWA2/MWf9Uzv0Veev6zAb2UnLgdbWkNSRfHM0Fyvb5TERMi4hZEfHhiPjfQjEVMAt4vEgME4Fn\ncmK4hOQXw4DSbo9fAD/IWdzfzTCYtFvnIPISn6S3pNv4TET8OmfVOqA+53EDRbowCngZWB4Ri9Pu\nlh+S7K998wtKOi7nQGfBVnNEPBwRnekX8W+AfweOyikylP3QALwV+HXe8r1IfvkdGRF9/7u+15u/\nH9aWUhfJfliWdum8HhHtJL8y55X4fCvA34YZJen/AEcDEyQ9ky7eApgq6e0RcV+6bFbOcyYD00gO\nAJKz/qH0/rYkrel8TwIdETF/lMIfaPTMkyQH0gotfwWYXqTbYzATSbpq+hwCvL/E5+5BkmT7v5TS\ng9G3AAsjYkle+QeAXYH/SR+/g427ZAZyL8kvolwFX29ab37dgwnS4xtpa/cA8o69DGA+cFvu/pe0\nG7AUOCkiOnJieyF9X+5K8muD9P5Q9sM+g5ayIXELPbveD7xO0mLZNb3NA5aRtNz7HCJpH0lbkIxI\n+E1E5Cbtf5Y0VdIs4HQ2bsX2+Rmwg6TjJW0uaaKkd5bShz4Mi4CPSDpQiTdKemtEdJL0439T0pR0\n3XbF+pfT1uus9P5skhEut6aP5wBbRMQjOeU3S78kNwM2l7SlpM3S1Rv1G6ddVr8ELoyI/yxQ/VXA\nZ9PY3wR8lo1HwWye1jUBmJjW1fdZ+y+gUdKHJU2QdBRJl9GdDIOkw9L+7L7jE6eTJGBIRkf9KSLW\n5ZQfKLb8/fA2klFCn4mIQq387wJfTt9f84CP5e2HiWldArZI6+o7yP09kl+F70n3wxnAc/y18WHD\nERG+ZfBG8kE6r8DyD5K0sieQfHguJkmEa4EOYHZO2Q3AqSRdHM8B5wFK150I/Cqn7PYkif3ZtOyt\nwC5FYrsNOLnIustJRj4UXQYcTnIArZvkAOFB6fIp6et5ElhDMtzt6CL1nJ2WW0vSd/5toDFd92ng\nW3nlF6T7ozfn9q/put8Du+eU/dd0fXd6Wwt0523vHOB/geeBr+etu6JAXSfkrN+XpIXaDfwO2GcE\n75MlaQzdwIPAp3PWnQ98ttTYgGeArfP+b6/n7IO1wH0567cg+YJ+MX3u6Xl13V6grv1z1h9BMozy\nhfQ9Na/an7uxfuv7cBclaRHJT8SuiNglXXYU0EbSYtwjkgN2fS2lh4CH06ffFRGfGrACGzZJVwBP\nRkSxCSIbgLdExBOVjay60v7mCyNi0IOB6cHYuyNiZvkjqyxJD5D0ez9cQtk9SPbZXuWPzMqllC6X\nK0j61nLdR9IlcEeB8o9FxO7pzcncquH29FaKBjYeoVMTlEzcubKUZJ5jQbniscoY9KBoRCxLW965\nyx6B/tEB+QpOBLGyGOzg4bi8vmAkIyZKLfsoyc/+mhLJMNaiE8kKlP99GcOxCinHKJc5ku4m6Vf7\nfxGxrAx1GBARm0wSylu/2UDrzay2jHZCfxrYNiLWSNodWCppp8g5ym5mZuUxqgk9/Zm3Jr1/t6TH\nSU7edHd+WUnjsjvAzGykIqJg13ap49BF8b7x/uVKTgs6Ib2/HcnJkoqOsFiwYEHBoTeFlg+l7FC3\nccABB1S0vqEsLxRbNeIYyr6rRhy1/r/1vhv+vqvGPh0sPhh+HAMZtIUuaQnQAkyXtJLkSPga4EKS\nadk/k/THiDiY5PwZZ0laTzL+9OORnI2voJaWlpKXD6XsULcxZ86citY3lOWFYqtGHEPZd9WIo9b/\nt953g8dWjTiq8bkYUKFvgErckqqzYcGCBdUOoagsxxbh+EYiy7FFZDu+LMcWMXh8I0l/ae4smFc9\n9Z9hfhNWSJZjA8c3ElmODbIdX5Zjg+rFN+hM0bJVLEW16jYzqyYJhpv+JBEjPChqZmYZ54RuZlYj\nnNDNzGqEE7qZWY1wQjczqxFO6GZmNcIJ3cysRjihm5nVCCd0M7Ma4YRuZlYjnNDNzGqEE7qZWY1w\nQjczqxFO6GZmNcIJ3cysRjihm5nVCCd0M7Ma4YRuZiO2ePHiIS238nBCN7MRW758eenLneTLxgnd\nrEpqvfXa3NxMe3v7pitOPRWamysf0DjghG5WJcVatWNRe3s7zXlJuquri56enk0L9/RAV1eFIhtf\nNq92AGY29vX09BRO3lZRbqGbmdUIJ3QzsxrhhG5mZdHU1ERdXV21wxhXnNDNrCw6OztpbW2tdhjj\nihO6mZXNnDlzqh3CuOKEbmZlc9JJJ1U7hHFFEVGdiqWoVt1mWTB58mQmT55MZ2dntUMZMUkAlPSZ\nTssyjj//0vBfviQiQoXWuYVuViU9PT10lTjBptZnldrocAvdrEqG0qrNemveLfShKVcL3TNFzcaA\nrM/ErK+vZ6uttqp2GOOeu1zMMmYsdq+8+OKLmf31MJ44oZtlTFZO2jUWv1jGu0ETuqRFkrok3Zuz\n7ChJ90vqlbR7XvkvSnpU0kOS/q4cQZuVQ6UTWF1dHU1NTSPbSBljLvTF0tDQsMlZFS07SmmhXwHM\nz1t2H/B+4I7chZLmAUcD84CDgYvVd7TELOMq3TJubW0deTdFhWPu7u4ueWSOVd6gCT0ilgFr8pY9\nEhGPAvnJ+nDgBxHxekQsBx4F3jVKsZrVlKHMohyV1rzVvNHuQ38T8GTO41XpMjPLM5RZlKPSmrea\nV9Vhi21tbf33W1paaGlpqVosZkPR0NDAVltt5SRrZdfR0UFHR0dJZUc7oa8CZuU8npkuKyg3oZtl\n1uLFkNea7u7upru7uyrhbKS9HS65BPzFUrPyG7sLFy4sWrbULhexaX957ro+1wPHSNpC0lzgLcDv\nSqzDLJsqeOCx6IWViyl2fc4sDzmsqwMfDyiLUoYtLgF+DewgaaWkj0g6QtKTwF7AzyTdCBARDwLX\nAA8CPwc+5fn9NqY1Nyet4AopemHlocrIWPaCLrrIvyjKZNAul4g4rsiqpUXKfx34+kiCMqu05uZm\n1q1bt2k3oIfojT6fUrdsfC4XM8jM2OqmpiZefvnlaodhY5QTulmGZH3UTF1dHZMnT652GFaEz+Vi\nNgZk5VJuHg+fbU7oZmOAL+VmpXBCNxtIU1MyzG6caWtrK3kyi2WHE7rZQDo7k2F2Y8koDLVsa2vL\n9szthobkddpGfFDUbDAFujsyfXBwlEbsZKXfvqDu7uRmG3EL3YxkuGDdELpWMn1wcJS6iQr122c6\nyZtb6GaQDBcck1foqauD/F8KnZ1QpvMk+eBstrmFbpYak8mqtdXT6K2fE7qZWY1wQjcbBvclWxY5\noZsNQ2a6Z4p9sfgLZyNj8vjIMDihm41lxb5YsvKFU2lFEnelLwBeLU7oZlYbmpvhIx8Z1xOOnNBt\n3BkvP7/Hnb4JVRk5FXI1OKHbyIzB5HjqqafSPI5bcVa7PLHIRmYM9k329PSMzmXezDLGCd3Mxp5C\nM2TNXS5WHu6ntrLyDNmCnNCtLMbLMDGzLHFCt8pxq92qoLm5mfYRnh9+rHAfulWOW+1WBV3jaBij\nW+hmNvYUOrVBU9PGfwdTg1c9ckI3s7Gn0KkNOjthwYLSD5Z2d9fcJCQndBt146nP0rJvqFejGsuc\n0MezMh2k7Orq8sQdy4zOzk5aW1urHUZFOKGPA0XHhFf6IGV7e831WVrtGctzKJzQa0yhN2PBMeHN\nzbBwYWUTbE9PzfVZWu0Zy3MonNBrTMlvxgydma6sLaIx3NqyYRjnF/bwOHSrnCLn3yhri2gMt7Zs\nGIpc2GO8XDLQLfQakvnRJZU+/0Zzc9Jvb+NewUsG1tWVPmZ9jHBCryFDGl0y1EkYhbS1Jf3wbW2l\nla90K6mrK+m3NyukBk/w5YQ+DrS3t296QYehTsIopK0t2UapCX28XufSrEKc0MeBnp6ezJ7Porm5\nmYULF/oKQpYJo/V+rNbQx0ETuqRFkrok3ZuzrFHSzZIekfQLSQ3p8tmSXpJ0d3q7uJzBW2nq6upo\nymhfYd8XTVa/cKyGFegCHK33Y7WGPpbSQr8CmJ+37Ezg1oh4K3Ab8MWcdY9FxO7p7VOjFKeNQGtr\nK50Z7Svs+6LJ6heO1bAa7AIcNKFHxDJgTd7iw4Er0/tXAkfkrNPohGbjQWdnJwsWLMjsF47ZaCp3\nV8xw+9C3iYgugIjoBLbJWTcn7W65XdJ+I47QChqVN0aZRp00NTVRX19flm0PMZBkaJpZRpS7K2a0\nJhZF+vcZYNuIWCNpd2CppJ0iYt0o1WOpUXljjMZPzgJfCplpbXd2eqaoVVxzczNdXV1ccsklFf8s\nDDehd0lqioguSc3AswARsR5Yn96/W9LjwA7A3YU20pYz3K2lpYWWlpZhhmMDKessuaz3Q2Y9PsuU\npqYmurq6MnVMp6Ojg46OjpLKlprQxcZ949cDJwHnAicC1wFI2hpYHREbJG0HvAV4othG20odv2wj\nUnCWXIZUelp2fX09W221VUXrtLGhs7OTtra2EeWm0dhGrvzG7sKFC4uWHTShS1oCtADTJa0EFgDn\nAD+SdDKwAjg6Lb4/cJak9cAG4OMR8cKwXoWNG5X+wnnxxRcrWp9ZpQya0CPiuCKr/rZA2Z8APxlp\nUDY8TU1NrFvnwxVmIzGWT+TlmaJjVKHp/J2dnVx00UVVisisNozGL8ZqfSn49LljVE9PT8ETcWW9\nv9xsPKjW51ARMXipclQsRbXqrgVScoza+9BsbGhubmbdunWsW7cOCYb70ZVERBScwOmEPkY5oZuN\nLbmf2XIldPehm5nVCPehj1F1dXVMLnA5NzMbv9xCH6Muuuii7EyxN7NBVeIcR2O+D33x4sUe2WFm\nY4r70Iuo1onkzcyyZswndDMzSzihm5nVCCd0M7Ma4YRuZlYjnNDNzGrEmB62mHtuBDOzscLDFgvo\n6uoqeMbBIcvwdSfLfZVwM6sdYzqhj5oMj2X3OHszK5UTuplZjXBCz7hCVyYyMyvEB0Wbm2HduuSW\nQT7vuVnt8UHRAjo7O2ltbR3ZRrq6YDQOrBbQ0NDg1rWZVcyYTuiZUmA0Sm9vb+XjMLNxywl9tBQY\njdLa2upzlptZxfiKRRnnKxOZWancQm9qgrq6akdRlFv5ZlaqMZPQyzZjsrMTChxYzcoMzTlz5lQ7\nBDMbI8ZMQq/0jMmi9VU40fvyemZWqjGT0DMzwWYIXyxuXZtZJY2ZhN7T00NXV9cmyzORNJubob19\nk8VuXZtZJY2ZhF5MxZNme3uSwHOVcXKSmVmpPGxxqHp6Nk3eTU2ZPXWAmY0fY76FXi5F++zr6pIE\nnqvISBkzs0pyQgco0A9frM+e1tYkgZuZZUwmE3rFx4D74KWZ1YCqJvRCibu5uZlTTz218sHkqaur\noym/a8XMLMOqmtALTd4pdp3QSidYT7k3s7Fm0IQuaZGkLkn35ixrlHSzpEck/UJSQ866L0p6VNJD\nkv5uoG23Fxi73dTURF2Bc6s4wZqZDayUFvoVwPy8ZWcCt0bEW4HbgC8CSNoJOBqYBxwMXKy+S+4U\nUKglXuyiFZWeQJSJCUtmZkMwaEKPiGXAmrzFhwNXpvevBI5I7x8G/CAiXo+I5cCjwLtGI9BKTyAq\nWp8TvZll1HD70LeJiC6AiOgEtkmXvwl4MqfcqnRZ7XCiN7OMGq2Dor6CsYc+mlmVDXfqf5ekpojo\nktQMPJsuXwXMyik3M11WVFtbGwAtLS20tLQMMxwzs9rU0dFBR0dHSWUVMXjjWtIc4KcR8fb08bnA\n6og4V9IXgMaIODM9KHo1sCdJV8stwPZRoBJJAVCo/ra2tv5Eb2ZWayQoIfUWea6IiIKDTQZtoUta\nArQA0yWtBBYA5wA/knQysIJkZAsR8aCka4AHgdeATxVK5mZmNvoGTegRcVyRVX9bpPzXga+PJCgP\nGTQzG7qSulzKUvEAXS5mZrWsXF0umTw5l5mZDZ0TuplZjXBCNzOrEU7oZmY1wgndzKxGOKGbmdUI\nJ3QzsyoazUtuOqGbmVVRoSu3DZcTuplZjXBCNzOrEU7oZmY1wgndzKxGOKGbmdUIJ3QzsywaxnBG\nJ3Qzsypqb2+nubl50xXDGM443GuKmpnZKOjp6aGnp2dUtlXVC1zU1dWxbt26qtRvZlYtuRe4kJJr\nVWyUi5ubYd265LbJc0dwTdFyam1trWb1ZmbZ1NU1rKdVtQ/d1w41Mxs9Ve1y8fVEzWw8GrTLJV1W\n6MKjvqaomdk44IRuZlYjnNDNzGqEE7qZWY1wQjczqxFO6GZmNcIJ3cysRjihm5nVCCd0M7Ma4YRu\nZlYjfPpcM7MqqqurY/LkyaOyLbfQzcyqqLW1lc7OzlHZlhO6mVmNcEI3M6ui0TyNuE+fa2ZWYbmn\nzy1aACp7+lxJp0u6L72dli5bIOkpSXent/eNpA4zMyvNsEe5SNoZOAV4J/A6cKOkG9LVF0TEBaMQ\nn5mZlWgkwxbnAb+NiFcBJP0K+EC6ruDPATMzK5+RdLncD7xbUqOkScAhwEwggFMl/VHSdyQ1jEag\nZmY2sGG30CPiYUnnArcA64B7gF7g28BXIiIknQ1cQNI1s4m2trb++y0tLbS0tAw3HDOzmtTR0UFH\nR0dJZUdtlIukrwJPRsQlOctmAz+NiF0KlPcoFzMbl7I6yuUN6d9tgfcDSyQ15xT5AEnXjJmZlaqp\nCerqhvy0kZ7L5VpJ04DXgE9FRLekiyS9A9gALAc+PsI6zMzGl85OyOmSLtWIEnpE7F9g2Qkj2aaZ\nmQ2Pp/6bmdUIJ3QzsxrhhG5mlkXDOGmXT85lZlZhgw5bHPC5ZRq2aGZmFdTcPOBqt9DNzCps2C10\nCYFb6GZmY15T04Cr3UI3M6sw96GbmdmAnNDNzGqEE7qZWY0Y6cm5Rt2cOXNYsWJFtcOwGjF79myW\nL19e7TDMKiJzB0XTDv8qRGS1yO8nyyIfFDUzswE5oZuZ1QgndDOzGuGEbmZWI5zQM2zZsmXMmzev\n2mEMyYEHHsjll19e7TDMxiUn9CGaM2cOkyZNor6+nilTplBfX89pp51Wlrr2228/HnroobJsu5gr\nr7ySzTffnPr6eqZOncpuu+3GDTfcUNEYzGx4MjcOPeskccMNN3DggQeOaDu9vb1sttlmoxTV6Npn\nn3341a9+BcBll13GMcccw6pVq6ivr69yZGY2ELfQh6HYuOYnnniC9773vWy99dZss802HH/88XR3\nd/evnzt3Lueddx677rorkydPpre3l7lz5/KNb3yDXXfdlcbGRo499ljWr18PwB133MGsWbM2en6x\nsgDnnXceb3zjG5k5cyaLFi1iwoQJPPHEEwD8/Oc/Z+edd6a+vp5Zs2ZxwQUXlPRaP/zhD9PT08Oj\njz7av+yuu+5i3333pbGxkd1224077rij6PMvv/xydtppJ6ZPn87BBx/MypUr+9f90z/9E9tuuy0N\nDQ3sscceLFu2rH/d73//e/bYYw8aGhqYMWMGra2tw6rfbFyJiKrckqo3VWx5VsyZMyd++ctfFlz3\n2GOPxa233hqvvfZaPP/883HAAQfEGWecsdFzd9ttt1i1alW88sor/cv23HPP6OzsjDVr1sS8efPi\n0ksvjYiIjo6OmDVr1kbPL1b2xhtvjBkzZsRDDz0UL7/8chx//PExYcKEePzxxyMiYsaMGXHnnXdG\nRMQLL7wQ99xzT8HXsHjx4nj3u98dERGvv/56XHTRRbHlllvGc889FxERq1atiunTp8dNN90UERG3\n3nprTJ8+PZ5//vmIiGhpaYlFixZFRMTSpUtj++23j0ceeSR6e3vjq1/9auyzzz79dV199dWxZs2a\n6O3tjQsuuCCam5vj1VdfjYiIvffeO773ve9FRERPT0/89re/Lan+fFl/P9n4NJK3ZfqeLpxXi60o\n920kCT2ZYzXy23DMmTMnpkyZEo2NjTF16tRobGyM73znOwXLLl26NHbfffeNnrt48eJNtrdkyZL+\nx5///Ofjk5/8ZEQUTujFyp588snxpS99qX/dY489FpL6E/rs2bPjsssui+7u7gFf3+LFi2PzzTeP\nxsbGmDhxYkyaNCl+9KMf9a8/99xz44QTTtjoOfPnz4+rrroqIjZO6AcffHBcfvnl/eV6e3tj0qRJ\nsXLlyoJ1NzY2xr333hsREQcccEC0tbVtkqgHqz+fE7plUbkS+pjschmtlD5c1113HatXr2bNmjWs\nXr2aU045BYBnn32WY489lpkzZzJ16lSOP/54nn/++Y2eO3PmzE2215Rz0vpJkyaxbt26onUXK/v0\n009v1D2Tex/g2muv5YYbbmD27NkceOCB3HXXXUXr2HvvvVm9ejUvvPAChx12WH9/OsCKFSu45ppr\nmDZtGtOmTaOxsZE777yTzs7OTbazYsUKTj/99P6y06dPRxKrVq0CoL29nZ122onGxkYaGxvp7u7u\n31+LFi3ikUceYccdd2TPPffsPzBbrP5nnnmm6OsxGy98UHQYosi3wZe+9CUmTJjAAw88QENDA9dd\ndx2f+cxnNiojFTwFw4jNmDGDp556qv/xypUrN6rrb/7mb1i6dCm9vb1ceOGFHH300Rv1ZxcyadIk\nLr74YrbbbjtOOeUUdt11V2bNmsUJJ5zApZdeOmhMs2bN4stf/jLHHnvsJuuWLVvG+eefz+23385O\nO+0EwLRp0/r37Zvf/GaWLFkCJF9GRx11FKtXrx5S/WbjzZhsoWfV2rVrmTx5MlOmTGHVqlWcf/75\nFav76KOP5oorruDhhx/mpZde4uyzz+5f99prr7FkyRK6u7vZbLPNmDJlSskjbBobG/nYxz7GwoUL\nATj++OP56U9/ys0338yGDRt45ZVXuOOOO3j66ac3ee4nPvEJvva1r/Hggw8C8OKLL/LjH/8YSPbV\nxIkTmT59OuvXr+ess85i7dq1/c+9+uqr+1vrDQ0NSGLChAlDqt9svHFCH4ZDDz2U+vr6/tuRRx4J\nwIIFC/jDH/7A1KlTOfTQQ/uX9ynUOh9Ki32gsu973/s47bTTOPDAA9lhhx3Ye++9Adhyyy0B+O53\nv8vcuXOZOnUql112WX/rtxSnn346N954I/fffz8zZ87kuuuu42tf+xpveMMbmD17Nu3t7WzYsGGT\nGI844gjOPPNMjjnmGKZOncouu+zCTTfdBMD8+fOZP38+O+ywA3PnzmXSpEkbdRPddNNN/aNyzjjj\nDH74wx+y5ZZbDlq/2Xjm0+fWqIcffpi3v/3tvPrqq0yYMH6/t/1+sizy6XNtUEuXLmX9+vWsWbOG\nL3zhCxx4t7f9AAAH8ElEQVR22GHjOpmbjTf+tNeQSy+9lG222Ybtt9+eiRMncvHFF1c7JDOrIHe5\nWE3z+8myyF0uZmY2ICd0M7Ma4YRuZlYjMjdTdPbs2WWbTWnjz+zZs6sdglnFjOigqKTTgY+mD/8z\nIr4lqRH4ITAbWA4cHREvFnhuwYOiZma1LnMHRSXtDJwCvBN4B/APkt4MnAncGhFvBW4DvjjcOiql\no6Oj2iEUleXYwPGNRJZjg2zHl+XYoHrxjaQPfR7w24h4NSJ6gV8BHwAOA65My1wJHDGyEMsvy2+O\nLMcGjm8kshwbZDu+LMcGYzOh3w+8W1KjpEnAIcAsoCkiugAiohPYptgGir3oQsuHUnao21i+fHlF\n6xvK8kKxVSOOoey7asRR6/9b77vBY6tGHNX4XAxk2Ak9Ih4GzgVuAX4O3AP0FipabBtZ3vl+45ZW\n1klp+Mu974a/fDx/LgYyajNFJX0VeBI4HWiJiC5JzcDtETGvQHkfETUzG4ZiB0VHNGxR0hsi4jlJ\n2wLvB/YC5gInkbTeTwSuG0pAZmY2PCMdtvgrYBrwGnBGRHRImgZcQ9KfvoJk2OILoxGsmZkVV7WT\nc5mZ2ega81P/JW2QdFXO480kPSfp+hFu932SHpb0Z0lfyFn+A0l3p7e/SLq7SvEtktQl6d4i6z+X\n1j2t0vFJminpNkkPSLpP0mk5646SdL+kXkm7Zyy2XSX9RtI9kn4n6Z0lbvOINNYdhhtXzrYaJd0s\n6RFJv5DUkLd+W0lrJX22CrEV/N9Jmpbu07WSvjXEbVYivs0lLZZ0b/p/P7MKsZ0n6SFJf5R0raT6\ndPlsSS/l5JQRnfN6zCd0oAd4m6Qt08cHkRycLZmkzfIeTwAuAuYDOwPHStoRICKOiYjdI2J34Frg\nJ5WOL3VFGl+h8jPTelaUsPlyxPc68NmI2BnYG/h03/4D7iM53nJHBmM7D1gQEbsBC4BSLwp7DPDf\nwKZXwx48vvzP4GAT875BMqqsVKMZW7H/3SvAl4HPDbWOCsX3QWCLiNiFZCLkx9PjfpWM7WZg54h4\nB/AoG/9fH+vLKRHxqaHWlasWEjokb/C/T+8fC3y/b4WkPST9WtIfJC2TtH26/ERJ10n6JXBr3vbe\nBTwaESsi4jXgB8DhBeo9OreuCsZHRCwD1hSp75vAP5cQV1nii4jOiPhjen8d8BDwpvTxIxHxKFDq\nQfGKxQZsAPpaxFOBVYMFJ6kO2Jdk1vSxOcsPkHSHpJ8p+aV3cc66tZLaJd1DMpAg1+EUmZgn6XDg\nCeCBweIqR2zF/ncR8VJE/Bp4tZS4Kh0fydDpuvTLfVIaZ3eFY7s1IvoufHsXMDO3uoFiGZKIGNM3\nkn/M24AfAVuSjIffH7g+XT8ZmJDefy/w4/T+icBKoKHANo8ELst5fDzwrbwy7wZ+V434crY9G7g3\nb9lhwAXp/b8A06oVX1puDsk5fSbnLb8d2D1LsQE7kvyqWUnyS2BWCf/f40jOYwSwDNgtvX8A8FL6\nPxJJC+0D6boNwJFFtrc67/GanNd6J0lCWkDyK6OisQ32v0v3+7cGi6vS8ZGM5vs+8CywFvhotWJL\ny10PHJfzGV4L3J3GvV+p+6/QrSZa6BFxP8mH81jgBjb+xpsK/FjSfSQt151y1t0SBU4cVqKNWotZ\niE/SVsCXSD7w/YurFZ+kycCPgdMjaQ0PWYVj+2T6eFvgDODyEkI8luQXHCQnpTsuZ93vIvmVFyTv\nlf3S5b0M3lXXp69VtwD4ZkS81PcSMhDbSFUqvneRdLU1A9sBrZLmVCM2Sf8CvBYRS9JFTwPbRtKF\n+zlgSfreHJbMnT53BK4n6fNsAbbOWf4V4LaI+ICk2STfgn16imxrFZDbxzaTnJ/f6U+3DwADHtQr\nY3zFvJkk+f1JktK4/yDpXRHxbCXjk7Q5ScL8bkQUnIswBJWK7cSIOB0gIn4sadFAQSk5s+h7SPr5\nA9iM5Od9X3dX/hCyvscvp8mgkC5JTfHXiXl9/7c9gSMlnQc0Ar2SXo6IggfRyhTbqKlwfMcBN0XS\n5fGcpDtJ+tKXVzI2SSeRnCLlPf1PTLp016T375b0OLADSYt9yGqhhd7XUrkcWBgR+f2LDfw1GX+k\nxG3+HniLkiPQW5AcHMkdWXEQ8FBEPF2l+HK33d9Si4j7I6I5IraLiLnAUyQ/FQdK5uWK73LgwYj4\n9xLqzkpsqyQdACDpvcCfB9nOB4GrImJuus9nA3+R1Ndie1f6HpoAfIjkAFvu6yrkepKJeZAzMS8i\n9k/r2A74N+BrxZJ5GWPLVaxcqc+vZHwrSZNo2je+F/BwJWOT9D6SL4TDIuLVnOVbp9tB0nbAW0iO\nkwxLLST0AIiIVRFxUYH15wHnSPoDJb7eSM4eeSpJ/9gDwA8i4qGcIh+ixO6WcsQHIGkJ8GtgB0kr\nJRVKaMHgH4BRj0/SvsD/Bd6jZAjg3ekbum8o2JMkH6qfSboxK7EB/wh8Iz2odXb6eCAfAv4rb9m1\n/PUg2v+QjJZ6AHg8Ipbmvq4izgUOkvQIyXGBc0p4WRWJbaD/naS/kIzAOTF9P+5YbDtViO8/gCmS\n7gd+CyxKu/IqFhtwIclxkFu08fDE/YF7lQx/vgb4eIxgIqYnFpmVQdrS/1xEHFbtWPJlOTbIdnxZ\njg1qo4VuZma4hW5mVjPcQjczqxFO6GZmNcIJ3cysRjihm5nVCCd0M7Ma4YRuZlYj/j87ypbKS6Xw\nrgAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from secrets import QUANDL_KEY\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib.dates import date2num\n", + "from matplotlib.finance import candlestick_ohlc\n", + "from matplotlib.dates import DateFormatter, WeekdayLocator,\\\n", + " DayLocator, MONDAY\n", + "import quandl\n", + "from datetime import datetime\n", + "import pandas as pd\n", + "%matplotlib inline\n", + "\n", + "def fetch_ticker(ticker, start, end):\n", + " # Quandl is currently giving me issues with returning\n", + " # the entire dataset and not slicing server-side.\n", + " # So instead, we'll do it client-side!\n", + " q_format = '%Y-%m-%d'\n", + " ticker_data = quandl.get('YAHOO/' + ticker,\n", + " start_date=start.strftime(q_format),\n", + " end_date=end.strftime(q_format),\n", + " authtoken=QUANDL_KEY)\n", + " return ticker_data\n", + "\n", + "def ohlc_dataframe(data, ax=None):\n", + " # Much of this code re-used from:\n", + " # http://matplotlib.org/examples/pylab_examples/finance_demo.html\n", + " if ax is None:\n", + " f, ax = plt.subplots()\n", + " \n", + " vals = [(date2num(date), *(data.loc[date]))\n", + " for date in data.index]\n", + " candlestick_ohlc(ax, vals)\n", + " \n", + " mondays = WeekdayLocator(MONDAY)\n", + " alldays = DayLocator()\n", + " weekFormatter = DateFormatter('%b %d')\n", + " ax.xaxis.set_major_locator(mondays)\n", + " ax.xaxis.set_minor_locator(alldays)\n", + " ax.xaxis.set_major_formatter(weekFormatter)\n", + " return ax\n", + "\n", + "AAPL = fetch_ticker('AAPL', datetime(2016, 3, 1), datetime(2016, 5, 1))\n", + "ax = ohlc_dataframe(AAPL)\n", + "plt.vlines(date2num(datetime(2016, 4, 26, 12)),\n", + " ax.get_ylim()[0], ax.get_ylim()[1],\n", + " color='b',\n", + " label='Earnings Release')\n", + "plt.legend(loc=3)\n", + "plt.title(\"Apple Price 3/1/2016 - 5/1/2016\");" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The second chart is from Facebook:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXYAAAEKCAYAAAAGvn7fAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XmcFPWd//HXGxCVAYZDndGAgEbiETUab00cj4jGn1c0\nRlgPjJtj/bm6xEmibjYM2WiMjia/jXGjmxG8iDGaFS88UAfFKzEeiAdBDYKYGTUMwoyKOHx+f1T1\nWNPTPd0z3T3dXf15Ph79mO5vXZ+qqf70t771rSqZGc455+JjULEDcM45l1+e2J1zLmY8sTvnXMx4\nYnfOuZjxxO6cczHjid0552LGE7tzzsWMJ/aYk/SYpNMLMN8bJf043/MN5/0/ki4oxLydqwSe2AeY\npOWSPpC0VtK68G9tseMqJEmLJH0YrmurpD9I2ird+Gb2LTO7NM8xTJP0qqT3Jf1dUpOkYUnjjJO0\nPEXM6yS9mGKeP5LUIGl/SQ9K+ke4fr+Lrp8CjeHwdyVdkjSfiyW9KGmDpItSLGdLSXMlrQnnMSeH\n7fCfkj5O2v/GJY1zkKTm8P1b4f6aGPeeFPP8raTpko6R9LikNkmrJP13dBtL2lTSnPB/sErSuSnm\ns1RSp6RpKZazvaR7wjjekXRxf7dD3HliH3gGHG1mI81sRPi3pdhBFZgB3zazkcCOwJZAY6oRJRVq\nn3wU+JKZVQOfBYYBP0ka52jg3vB9V8zh/2nXFPNMjD8auBrYFpgIrAeaIuOdDRwJ7AzsDnxN0jcj\nw5cC5wPz08Q+D3gT+AywFfCLTCubwU1J+99bScOPBhIJ3IApkXGPTjG/I8PYRwANQC2wC7AdEP2B\n/inBNhoHHAFcJOnQyPBnge8AzycvQNJQ4MFwOVsC44G52a9yZfHEXhzqURD4Q1ibXC3pYUk7RoZv\nLukXkt4Ma0TNkjYJhx0o6cmw/FlJX0qa/WRJfw6H3y6pOjLfEyQtCZe5QNLkyLCdw+W0SXpB0ldT\nrow0UtJCSVdkWmczawP+CHw+nPZGSVdJmi9pHXCQkpp5JH1N0nNhTe+vkg4Py6slXSfpbUkrJM1K\nt3Aze8vM3g0/DgI2EiT4qK/yaWLvijnNOo8FJprZn8zsXjP7XzPrMLMPgV8DB0RGPx1oNLNWM3sb\nuAKYHontBjN7AOhIsZyjgC3N7MJw/p1m9kK6uPKkL9thD6AlXLe5Zvagma03szXAb4EDI6OfBswy\ns3Vm9hLBj9/0xEAzu9rMmoGPUyzqLOBvZnZVOP/14TxcCp7YS8tdwPYENZ4lwI2RYb8kSIZ7A2OA\ni4CN4WH0POA/zGw0cAHwR0mjI9OeBpwKbEPwP/8lgKSdgBuA/0tQC3oIuFPS4PBH4+4wpi2A7wG/\nl7RdNOAwwT0MLDCz8zOtoKQtga8R1M4SpgIzzWwE8FTS+AcQJIAZYW37EILaK8BNBMlwEvBF4KuS\nzuxl2V+WtAZ4HziGSM03rBEeGG6DhMvDQ/5HU/xYHgk8kGZRBwPRpLMLEE3GL4Rl2dgP+KukmyW9\nJ+kpSQdmnKp3J4TzWizp29EB4f5UnZQ0b5HUEv74fj5pXl/l09p9sq7tIGkLgn1scWR4X7fDSkn3\nKWjOWiBp5yynrTxm5q8BfAF/A9YCq8PXH9OMtwVBrXJzgmT8EbBjivEuApqSyhYAU8P3jwE/iQzb\nFfggfN9AcFieGCbgbYLaZh2wMmm+twIXhe9vBP6H4It7boZ1fgxoD9d3JXA9MDoyn98mjX8j8OPw\n/W+Bn6eY5zbAB8AmkbJTgQey+B9sA/wY2D5SdgQwP/J5H4Lmmk2AM8P/2baR4XOBb6SY9x7AP4B9\nI2Ubge0in3cEPk4x7e8S2zdS1gR0hus2GJgWzn9UP/e/nYCa8H99INACnBgZ/m3gvyOfDwCGhvvh\nj4BVwIjI8Cei6xopPwp4j+CoBoImqk5gUGScI4G/ppj2SWBaUtlDBN+Bw4AhBBWYZcDggfrultPL\na+zFcZyZjQlfX4OgbVnSZZJeD2uVywjaN7cg+CJuAryRYl4TgGlhU8pqSW3AvsDWkXFWRt6/CWwa\n1ui34dPaLxZ8g1YRtOVuA6xIWlainTfhGIJk89ss1vlfwvUdb2ZnWNAkkyq+ZOOB11OUTwA2BVoj\n630VQa2wVxY0hzxE9zbabs0PFjSxfGBmG8xsNvA0QbJKnAc4DLg/Ot+wGetu4Gwzezoy6ANgZORz\nNbAuU5yhD4HXzOwmC5ph5gKtwP7JI0o6XZ+e5JyXZt1fsaDZxMzsceBXwEm9bIcnzOxjM/vQzH4a\nrssB4fLGAJOS1jVxlHU9cIKZLQ+L28O/uWyHhWb2kJl9AvycYB+f3PtklckTe3GkarM8naAGU2dm\nowjafxW+WgnaHbdPMd1K4LrID8VoC050XRkZZ3zk/QRgfZhY3w4/B0FJIjixtSoctm3SsrYNhyX8\nN/AIcK+kzfqxzgm93Tt6JenXuyNpvUeZ2R4Z4kjYhODkXkJyu3KqGBPrsB9BTXNNYqCkSQQn9/7D\nzH6fNO1LBCdNE75A96aa3iym5/ZJub0saKtPnOQ8Lsv5d61X2Px2EMERX8bxCfbXbuNK2ovgHMpp\nZvZYJLb3gHfpvh12pwDbwXliLyUjCHpTtEmqAi4h3HHNbCMwB/ilpJqwdn+ApMEEzRYnSDo8LN9M\nUp26d6E8XdLnwvk2AInEcytwbNj2PAT4AUGTw9MEh9gbJH1P0hAFvReOAm6JzNfM7F8IjiTukrRp\nAbZLE/DPkg5W4DOSJlvQk2OhpCskjQiHbZ+iLRwASf8Uth8jaSJBj5gF4efPAhvN7PXw82hJX1HQ\nPW+IgusA9uPTGnq3dmVJ4wmOAK4ws+tSLP4G4HxJW4cxzABmR6YfEv4wDgI2CZebSJ63AzWSpob/\n328QHJU82cftmFjWcQpPnkvaF/hX4I5w8MHAMxacAEbSBAVdOYeEMV1IsJ8mlp28HXYPP59tZt2O\nZkI3Av8RnvTeBfhm0nbYJNwOAoYm7U83EpxYrwuPmOoJKhlL+7MdYi9TWw3BF6sVWBwpuwx4haBb\n0u3AyLD8cOAZgpMifwYOKXZbU6m9CJLgoSnKhwN3EiTWNwhOeHYStusStHH+EngLaCOoKQ8Jh+0L\nLCRoe20J57NNOOxR4D/D/8cagtrUqMhyTwBeJmj/fgj4XGTYLuH0awhqTEdHht3Ap+3gIjiReQ+R\nNu/IuI8Cp6fZHl3zSVdGcLJ1cbhtlia2H8Gh/G8Iau9twF+Ak9Is59Jw260jaGL6NcFJQoDzgCsj\n424Vbq/3w+2yiOBIKjH8OWC3yOefhP+rteFrHbA6MlzA5eG83gMuTortRoJ2+M7Ia1pk+JeBF/n0\nR7dHm3Yf9r/fh/vJ2vD//t3IsF8QOV9CcLI+sd3fJfhh+0JknVoJz5VE/m8bIttgHfBcZPhmBBWU\ntQRHhOckxfZY0jboBA6IDD+RoFluDcG+2uOck7+Cl8INlpakgwjax24ws93CssOBh81so6RLCWpu\nF4a/2K1m1hL+It9vZuPSz9254pN0P3C5mfXWBJEYd2vgaTNLbqYqe5KWEvx4v5bFuPsTbLODCh+Z\n66uMTTFmtoigNhQtW2BB8wAE3dPGheUvWHixjQXdpTYL2+2cK2UPERzxZGMkwcVEsRI2e/w2m6Qe\n2gikvW7AFVfGGjsEbW3AXYkae9KwO4FbLDhbHy0/ieDKvSPyFaxzzrnMhuQysaR/BzakSOq7AD8D\nvpLL/J1zzvVdvxO7pOkEZ8UPTSofx6fdnZb3Mr13VXLOuX4ws966D2fd3THRnzr4IB0JfB841szW\nR8qrCS7Q+KGZPdVjLklmzpzZ42xuvsvSlR988MEFX3ZfYvR4+va/8njKK56+fDdLIR4ofjzpYsxG\nxsQuaS5Bn+bJCm60dCbB1WrDgQcV3HTq6nD0cwguJvmxgps2PRveIyKlurq6gpelK584cWJR4kkX\no8eTvixVLB5PecXTl++mx5O+LGupfhEG4hUsunhmzpxZ1OUn83jSK6VYzDyeTOIQTyHTU67bJ8yd\nvebXir3yNKdfwwLweNIrpVjA48nE4+ndQMSTVXfHgixYsmIt2znneiNBqaYnSViGk6c5dXcshIkT\nJ/Lmm29mHtG5LEyYMIHly5cXOwznBlTJ1djDX6MiROTiyPcn1x/lXmOv2DZ255yLK0/szjkXM57Y\nnXMuZjyxl7BFixax0047FTuMPjnkkEO47rpUz5pwzg0UT+x9NHHiRIYNG8bIkSMZMWIEI0eO5Nxz\nzy3Isg466CBeeeWVgsw7neuvv54hQ4YwcuRIRo0axR577ME996R7CL1zrhSVXHfHUieJe+65h0MO\nOSSn+XR2djJ48OA8RZVfBxxwAI8++igA1157LaeccgqrVq1i5MiRGaZ0zpUCr7H3Q7ruc2+88QaH\nHXYYW2yxBVtttRWnnnoqa9eu7Ro+adIkLrvsMnbffXeGDx9OZ2cnkyZN4oorrmD33Xdn9OjRTJ06\nlY8//hiAhQsXMn78+G7TpxsX4LLLLmObbbZh3LhxNDU1MWjQIN544w0A7r33XnbZZRdGjhzJ+PHj\nufLK6LOu0zvttNPo6Ohg2bJlXWVPPfUUBx54IKNHj2aPPfZg4cL0z6i47rrr2HnnnRk7dixHHXUU\nK1as6Br2b//2b2y77bZUV1ez9957s2jRoq5hf/7zn9l7772prq5m6623pr6+vl/Ld64iZbrnQKFe\npLkZQ7ryUjFx4kR76KGHUg577bXXbMGCBbZhwwZ777337OCDD7YZM2Z0m3aPPfawVatW2UcffdRV\ntu+++1pLS4u1tbXZTjvtZNdcc42ZmTU3N9v48eO7TZ9u3Pnz59vWW29tr7zyin344Yd26qmn2qBB\ng+z11183M7Ott97aHn/8cTMzW7NmjT333HMp12HOnDn2pS99yczMPvnkE7vqqqts0003tXfffdfM\nzFatWmVjx461++67z8zMFixYYGPHjrX33nvPzMzq6uqsqanJzMzuuOMO22GHHWzp0qXW2dlpF198\nsR1wwAFdy7r55putra3NOjs77corr7Ta2lpbv369mZntv//+dtNNN5mZWUdHhz399NNZLT9Zqe9P\nrjR1221mzy5WGCkR13vFSPl59dfxxx/PmDFjGD16NGPGjKGpqQmA7bffnsMOO4whQ4YwduxYZsyY\n0aM2ed5557HNNtuw6aabdiurqalh1KhRHHPMMTz//PNpl51u3D/84Q+ceeaZ7Ljjjmy22WY0NDR0\nO7IYOnQoL730EuvWraO6upovfOELaZfx5JNPMmbMGDbffHN+8IMfcNNNN7HFFsFNOm+66SaOPvpo\npkyZAsBhhx3GXnvtxb333ttjPtdccw0XXnghkydPZtCgQVxwwQU8//zzrFy5EoBp06YxatQoBg0a\nxIwZM1i/fj1Lly7tive1117jH//4B8OGDWOfffbp8/Kdy4syvHK5LBN78Hua+6u/5s2bx+rVq2lr\na2P16tWcddZZALzzzjtMnTqVcePGMWrUKE499VTee++9btOOG9fz2d41NTVd74cNG0Z7e3vaZacb\n9+233+7WbBN9D3D77bdzzz33MGHCBA455BCeeir97fL3339/Vq9ezZo1azj22GO72tsB3nzzTW69\n9VbGjBnT9eP2+OOP09LS0mM+b775Juedd17XuGPHjkUSq1atAqCxsZGdd96Z0aNHM3r0aNauXdu1\nvZqamli6dCk77rgj++67b9cJ3HTL//vf/552fZyrNH7ytB8sza/CRRddxKBBg3jppZeorq5m3rx5\n/Ou//mu3cZTLoUIvtt56a956662uzytWrOi2rC9+8YvccccddHZ28qtf/YqTTz65W3t3KsOGDePq\nq69mu+2246yzzmL33Xdn/PjxnH766VxzzTUZYxo/fjw/+tGPmDp1ao9hixYt4vLLL+eRRx5h5513\nBmDMmDFd23b77bdn7tzgiYu33347J510EqtXr+7T8p2rVGVZYy9V69atY/jw4YwYMYJVq1Zx+eWX\nD9iyTz75ZGbPns2rr77KBx98wE9/+tOuYRs2bGDu3LmsXbuWwYMHM2LEiKx75IwePZpvfetbzJoV\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "FB = fetch_ticker('FB', datetime(2016, 3, 1), datetime(2016, 5, 5))\n", + "ax = ohlc_dataframe(FB)\n", + "plt.vlines(date2num(datetime(2016, 4, 27, 12)),\n", + " ax.get_ylim()[0], ax.get_ylim()[1],\n", + " color='b', label='Earnings Release')\n", + "plt.title('Facebook Price 3/5/2016 - 5/5/2016')\n", + "plt.legend(loc=2);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These two charts demonstrate two very specific phonomena: how the market prepares for earnings releases. Let's look at those charts again, but with some extra information. As we're about the see, the market \"knew\" in advance that Apple was going to perform poorly. The market expected that Facebook was going to perform poorly, and instead shot the lights out. Let's see that trend in action:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nqlShcePGzJkzJ8vXjxs3juOOO45q1apx5plnsnbt2n37brrpJo444ggqVapE8+bNmTt37r598+fP\np3nz5lSqVImaNWsyaNCgfF1fRESksNJ4ROMREZFAOOcC+fKXPlBW26NFQkKC++ijjzLdt3LlSvfh\nhx+63bt3uz/++MO1a9fODRgwYL/XNm7c2K1fv97t2LFj37YWLVq45ORkt3HjRnfssce60aNHO+ec\nmz17tqtdu/Z+r8/q2FmzZrmaNWu6ZcuWuX/++cddcsklrlixYm7VqlXOOedq1qzpPv/8c+ecc5s2\nbXLffPNNpvcwYcIEd+qppzrnnNuzZ4978sknXenSpd3vv//unHNu/fr1rlq1au7dd991zjn34Ycf\numrVqrk//vjDOedcYmKiGzt2rHPOuRkzZrh69eq55cuXu9TUVHffffe5U045Zd+1XnjhBbdx40aX\nmprqRo0a5eLj493OnTudc861atXKTZkyxTnn3LZt29xXX32Vq+tnFO3/nkSkcGBYeH/WhH52BfYe\nXZS+NB7ReETjEREJh3CPBaJBVuMRzUTIh27dulG1alWqVKlC1apVGTt2LABHHXUUHTt2pESJElSr\nVo0BAwYckJXu378/hx12GKVLl95vW1xcHJUrV6Zr1658++23WV47q2NfffVV+vbtS4MGDShTpgzD\nhg1LGxwBUKpUKb7//nu2bt1KpUqVOOmkk7K8xhdffEHVqlU55JBDuPXWW5kyZQrVq1cHYMqUKXTp\n0oVOnToB0LFjR5o1a8Y777xzwHlGjx7N4MGDqV+/PsWKFeP222/n22+/Zd26dQD07t2bypUrU6xY\nMQYMGMDOnTtZvnz5vnhXrlzJn3/+SdmyZTn55JPzfH0REZHCTOMRjUdERIIQkzURbLiF5TxuaObT\nAHMyc+bMTNcg/vbbb/Tv35/PPvuMv//+m9TUVKpWrbrfMbVq1TrgdXFxcft+XbZsWX799dcsr53V\nsRs2bKB58+b79qWfdggwffp07rnnHm677TYaNWrEiBEjaNmyZabXaNWqFZ9++inbt2/nyiuv5NNP\nP6Vnz54ArFmzhldeeYU333wT8DNZ9uzZQ8eOHQ84z5o1a+jfvz8DBw7cd6yZsX79emrXrs3IkSMZ\nN27cvnvYunUrf/zxBwBjx47lzjvvpEGDBhx55JHcdddddOnSJcvrd+jQIcs/MxERkUgIx3gkv2MR\n0HhE4xERkWDEZBLhYN5ww3J9l/n177jjDooVK8b3339PpUqVmDlzJjfeeON+x5iFJwGSUc2aNfnl\nl1/2/X7t2rX7Xatp06bMmDGD1NRUnnjiCXr16rXfesDMlC1blqeffpojjzySK6+8kkaNGlG7dm0u\nu+wyRo8enWNMtWvX5r///S8XXXTRAfvmzp3LQw89xCeffMJxxx0HQNWqVff92R511FFMnToV8AOO\nnj178tdff+Xp+iIiIpGk8ciBNB4RESn8tJwhjLZu3Ur58uWpUKEC69ev56GHHiqwa/fq1Yvx48fz\n448/sn37du699959+3bv3s3UqVPZsmULxYsXp0KFCrmuxFylShWuvvpqhg8fDsAll1zCm2++yfvv\nv8/evXvZsWMHc+bMYcOGDQe89rrrruP+++/nhx9+AGDz5s1MmzYN8H9WJUuWpFq1auzatYu7776b\nrVu37nvtCy+8sO8pQKVKlTAzihUrlqfri4iIFEUaj+xP4xERkfBSEiEfunbtSsWKFfd99ejRA4Ch\nQ4eycOHCfesD07anySzrn5cnAdkd27lzZ/r160f79u2pX78+rVq1Ati31nHy5MnUrVuXypUr89xz\nz+3LqudG//79mTVrFkuXLqVWrVrMnDmT+++/n0MPPZQ6deowcuRI9u7de0CM3bp14/bbb+fCCy+k\ncuXKNGzYkHfffReATp060alTJ+rXr0/dunUpW7bsflMe33333X3VmwcMGMDLL79M6dKlc7y+iIhI\nUaHxiMYjIiJBsKymwkX8wmYus2ubWZbT8yT3fvzxR0488UR27txJsWJFN1ekf08iUhBsuIV1anvo\nZ1dk5pvLfjQeiSyNRzz9exIp/NLGAjt2QMmSkMuJVlEtq/FI0f1pXgjNmDGDXbt2sXHjRm677TbO\nOeecIv2GLSIiIgVP4xERKcqefBI6dICffw46ksjRT/RCZPTo0dSoUYN69epRsmRJnn766aBDEhER\nkSJG4xERKcoGDICu8fM5+WQYOxYK4ySkmOzOIJmbNWtW0CGIiIhIEafxiIgUZcWLw6Bj36bznc25\n9FJ4/XUYMwbi44OOLHw0E0FEREREREQkjE44Ab76Cho3hpNOglBTmEJBSQQRERERERGRMCtVCu65\nB2bMgDvugEsugY0bg47q4CmJICIiIiIiIhIhLVvCt99ClSrQsCG8/37QER0cJRFEREREREREIqhs\n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\nwqAjyClHHQUzZ8Jrr8Hxx8N//hN0RMFTEkFERERERESkErvsAsXF0KqV394wY0bQEQWrTtABiIiI\niIiIiGSyunVh2DBfePG446BTp32DDikwWokgIiIiIiIiEodevWDqVGjbNnc/SufuyEVERCRrmNkI\nMysxs7lljjUyswlmtsjM3jSzhmUu28/MpprZfDP7t5nVCyZyEREJm913h2uvPTHoMAKjJIKIiIhk\ng5HA0eWOXQ1Mcs61BN4GrgEws9rAE8C5zrl9gAJgffpCFRERCS8lEURERCTjOeemAKvKHT4BGB37\nfjTQM/Z9V+Dfzrn5sd9d5ZxzaQlUREQk5JREEBERkWy1g3OuBMA5FwV2iB3fA8DM3jCzWWZ2RVAB\nioiIhI26M4iIiEhYlK42qAMcArQDfgXeMrNZzrl3AotMREQkJJREEBERkWxVYmZ5zrkSM4sAK2PH\nvwLec86tAjCz8UAboMIkwqBBg377vqCggIKCglTGLCIikpGKi4spLi6u8npKIoiIiEi2sNi/UuOA\nQuA24ExgbOz4m8AVZrYVsAE4HLizshstm0TIRpFIhJKSEoYPH040Gg06HBERyVLlE+mDBw+u8HpK\nIoiIiEjGM7Mx+C4L25vZcqAIGAo8Z2ZnAV8AJwM4534wszuBWcAm4DXn3OuBBJ4GJSUlm30VERFJ\nJSURREREMkl+ftARZCTnXP9KLjqykuuPAcakLiIREZHcpO4MIiIimaSwMOgIJJcoaSUiItWkJIKI\niIhIpsvL2/xrsihpJSIi1aQkgoiIiEimi0ahqMh/FRERCZCSCCIiIiIiIiISFyURRERERERERCQu\nSiKIiIiIhFi+iieKiEgSKYkgIiIiEmKFKp4oIiJJpCSCiIiIiIiIiMRFSQQRERERERERiYuSCCIi\nIiIiIiISFyURRERERERERCQuSiKIiIiIiIiISFyURBARERERERGRuCiJICIiIiIiIiJxURJBRERE\nREREROKiJIKIiIiIiIiIxEVJBBERERERERGJi5IIIiIiIiIiIhIXJRFEREREslheXt5mX0VERFJJ\nSQQRERGRbJCfX+HhaDRKUVER0Wg0vfGIiEhOUhJBREREJBsUFgYdgYiIiJIIIiIiIiIiIhIfJRFE\nREREREREJC5KIoiIiIiIiIhIXJREEBEREREREZG4KIkgIiIikuXyK+ncICIikmxKIoiIiIhkuUJ1\n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\ncAw4PwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def plot_hilo(ax, start, end, data):\n", + " ax.plot([date2num(start), date2num(end)],\n", + " [data.loc[start]['High'], data.loc[end]['High']],\n", + " color='b')\n", + " ax.plot([date2num(start), date2num(end)],\n", + " [data.loc[start]['Low'], data.loc[end]['Low']],\n", + " color='b')\n", + "\n", + "f, axarr = plt.subplots(1, 2)\n", + "\n", + "ax_aapl = axarr[0]\n", + "ax_fb = axarr[1]\n", + "\n", + "# Plot the AAPL trend up and down\n", + "ohlc_dataframe(AAPL, ax=ax_aapl)\n", + "plot_hilo(ax_aapl, datetime(2016, 3, 1), datetime(2016, 4, 15), AAPL)\n", + "plot_hilo(ax_aapl, datetime(2016, 4, 18), datetime(2016, 4, 26), AAPL)\n", + "ax_aapl.vlines(date2num(datetime(2016, 4, 26, 12)),\n", + " ax_aapl.get_ylim()[0], ax_aapl.get_ylim()[1],\n", + " color='g', label='Earnings Release')\n", + "ax_aapl.legend(loc=2)\n", + "ax_aapl.set_title('AAPL Price History')\n", + "\n", + "# Plot the FB trend down and up\n", + "ohlc_dataframe(FB, ax=ax_fb)\n", + "plot_hilo(ax_fb, datetime(2016, 3, 30), datetime(2016, 4, 27), FB)\n", + "plot_hilo(ax_fb, datetime(2016, 4, 28), datetime(2016, 5, 5), FB)\n", + "ax_fb.vlines(date2num(datetime(2016, 4, 27, 12)),\n", + " ax_fb.get_ylim()[0], ax_fb.get_ylim()[1],\n", + " color='g', label='Earnings Release')\n", + "ax_fb.legend(loc=2)\n", + "ax_fb.set_title('FB Price History')\n", + "\n", + "f.set_size_inches(18, 6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see above, the market broke a prevailing trend on Apple in order to go down, and ultimately predict the earnings release. For Facebook, the opposite happened. While the trend was down, the earnings were fantastic and the market corrected itself much higher." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Formulating the Question\n", + "\n", + "While these are two specific examples, there are plenty of other examples you could cite one way or another. Even if the preponderance of evidence shows that the market correctly predicts earnings releases, we need not accuse people of collusion; for a company like Apple with many suppliers we can generally forecast how Apple has done based on those same suppliers.\n", + "\n", + "The question then, is this: **how well does the market predict the earnings releases?** It's an incredibly broad question that I want to disect in a couple of different ways:\n", + "\n", + "1. Given a stock that has been trending down over the past N days before an earnings release, how likely does it continue downward after the release?\n", + "2. Given a stock trending up, how likely does it continue up?\n", + "3. Is there a difference in accuracy between large- and small-cap stocks?\n", + "4. How often, and for how long, do markets trend before an earnings release?\n", + "\n", + "**I want to especially thank Alejandro Saltiel for helping me retrieve the data.** He's great. And now for all of the interesting bits." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Event Studies\n", + "\n", + "Before we go too much further, I want to introduce the actual event study. Each chart intends to capture a lot of information and present an easy-to-understand pattern:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtEAAAFwCAYAAAB+YSfRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xl8VPW9//HXdyaTSTLZSICwb+pFRAIJsi8GUNyxqIj7\nUlu1anvb/qoUr1VwudfeVlzaWltrrVqvooiIRSkoxn1BURaFgGjCGkhCyL7MZL6/PyYZs5OYwGR5\nPx+P85g53/mecz4zo+Gdb77nHGOtRUREREREWs4R6gJERERERDobhWgRERERkVZSiBYRERERaSWF\naBERERGRVlKIFhERERFpJYVoEREREZFWapcQbYw50xizzRiz3RizoJHXhxtjPjDGlBtjflnvtUxj\nzEZjzOfGmE/aox4RERERkaMprK07MMY4gD8Cs4B9wHpjzCvW2m21uuUBPwV+0Mgu/ECatTa/rbWI\niIiIiBwL7TESPR7YYa3NstZ6geeB82t3sNbmWms/A3yNbG/aqQ4RERERkWOiPcJrf2B3rfU91W0t\nZYG1xpj1xpgft0M9IiIiIiJHVZunc7SDKdba/caYXgTC9FZr7XuhLkpEREREpCntEaL3AoNqrQ+o\nbmsRa+3+6sccY8zLBKaHNAjRxhjbxjpFRERERFrEWmuae709pnOsB443xgw2xoQDlwArm+kfLMgY\nE2WMia5+7gFmA1ua2tBaq6WTLnfddVfIa9Ci7647Lvr+Ou+i765zL/r+OvfSEm0eibbWVhljbgHW\nEAjlT1hrtxpjbgi8bP9qjEkCPgViAL8x5j+Bk4BewMvVo8xhwLPW2jVtrUlERERE5GhqlznR1trV\nwPB6bX+p9fwAMLCRTYuBMe1Rg4iIiIjIsaJLy8kxkZaWFuoS5HvSd9e56fvrvPTddW76/ro+09J5\nH6FmjLGdpVYRERER6byMMdhjcGKhiIiIiEi3ohAtIiIiItJKCtEiIiIiIq2kEC0iIiIi0koK0SIi\nIiIiraQQLSIiIiLSSgrRIiIiIiKtpBAtIiIiItJKCtEiIiIiIq2kEC0iIiIi0koK0SIiIiIiraQQ\nLSIiIiLSSgrRIiIiIiKtpBAtIiIiItJKCtEiIiIiIq2kEC0iIiIi0koK0SIiIiIiraQQLSIiIiLS\nSgrRIiIiIiKtpBAtIiIiItJKCtEiIiIiIq2kEC0iIiIi0koK0SIiIiIiraQQLSIiIiLSSgrRIiIi\n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\nOTn4GdTv39Tn7PV6ufPOO3nhhRdITU3lxRdfbLQG6Th8Ph+FhYVkZ2fzzTffsGXLFj755BPeeiud\n5ctf4+9/X8aDDz7NokWP8YtfPMCPf3wvN974AP/v/z3FnXeu4v77P+bhh3fy178W8NxzLt54oy+b\nNiWzf/8sKivnExNzMwMH3sHgwQsYOPCnDBx4HQMHXsqgQecDMGDARHr1GkFMTD/Cw3U3PpGORCPR\n3ZgxhksuuYTFixdzzjnnsGnTJq677jreffddAO677z5mzZrFE088QUFBAePHj+e0004jKSmJN954\ng/DwcL7++msuvfRS1q9fDwRG2b766iv69OnDlClT+OCDD5g8eXKDY5eVlfH555/z7rvvcu2117J5\n82YAtm7dyvvvv094eDhvv/128B+Me+65h/j4+GAwrbkd7L333subb75JZGQk//u//8sDDzzAb37z\nm+BxzjrrLG688UZiYmL45S9/yYYNG3jqqadYv349VVVVTJgwgbS0NOLj4/n666955plnGDduXJ1a\nKyoquP7660lPT2fYsGHMnz8/+NqIESN47733cDgcvPnmmyxcuJBly5bxox/9iCeffJIHH3yQ7du3\nU1FRwahRo5gzZw6PPvookyZNorS0lIiIiCa/n7Vr17Jjxw4++eQTrLXMmTOH9957j6lTp/Lkk08S\nHx9PeXk548aN48ILL6SiooJFixbx+eefExsbS1paGqmpqY3uu6qqio8//pjXX3+dRYsWsXbtWh59\n9FESEhLYsmULX375JSkpKU3+d9PU+ubNm/n4448pKioiJSWFc889lz59+gRfv//++/nyyy+D4Xz5\n8uVs2rSJzZs3c/DgQcaNG8epp55KUlJScJtt27axdOlSPvjgA5xOJzfffDPPPvssV1xxBf/93/9N\nfHw8fr+fWbNmceGFFzJ8+HAuueQSXnzxRVJTUykuLg5+zhs3buSLL77A5XIxfPhwfvazn9G/f//g\nsXw+Hz/96U9ZuXIliYmJvPDCC9x+++088cQTeL1esrKyGDx4MEuXLuWSSy7B5/Pxs5/9rNH+TX3O\nd999d3CajRxbfr+f8vLy4MhwSUlJ9WNgRDg/PzBSXFAQWC8qKqWszIvDEYUxHmpGif3+wEhxWFgi\nLtdAXK4oXK4o3O4ooqOjcDpdoX6rInIMKER3cyeffDKZmZk899xznHPOOcERPoA1a9bw6quv8rvf\n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\nFJdEUlxSwOISqY6aTnEnIiIiUiVKlqU+0bLfIiIiIiI+0ki0iIiIyHWgcpUbS41m5/CnymbniIuL\nK7dMrdQ9sbGxZGVlBToMERERuQ40O0c9GInOzs6udElaqTsqWsRBREREJFipJlpERERExEdKokVE\nREREfKQkWkRERETER0qiRURERER8pCT6BpWSksLMmTMDHYaIiIhIUFISXQctWrSIbt260ahRI8aN\nGxfocERERETkCkE/xV1FZs58lWPHvqu188fEfI8XXvgvn4+bN28ekydPvma/6OhoZsyYwbp167hw\n4UJ1QhQRERGRWlQvk+hjx74jLm52rZ0/K6t6587Pz69Sv6FDhwKwfft2jh8/ftW+8+bNY8GCBZw5\nc4bo6Ghee+017r777nL9du3axfjx4/nb3/7GwIEDNW+ziIiISA2onMOPrveiMF999RWLFi1i586d\nnDlzhnXr1hEXF1eu38WLFxk2bBhjx47l1KlTDB8+nD/96U/XNRYRERGRG0m9HImuKw4fPsy77757\naelItmzZwksvvYRzDjOjR48eJCYmVvv8oaGhFBQUsG/fPqKiooiJiamw39atWyksLGTChAkAPPLI\nI3Tr1q3a1xURERG50SmJrkU/+MEPytRA5+fnM2nSpOt6/ldffZXZs2ezf/9+7r//fl5++WVatWpV\npl9OTg7R0dFl9sXGxl63OERERERuNCrnCHLJycl88sknZGdnAzBlypRyfVq1alWutvrYsWN+iU9E\nRESkPlIS7UdVrYkuKioiLy+PoqIiCgsLyc/Pp6ioqFy/r776ik2bNlFQUEB4eDgRERGEhJS/pT17\n9qRBgwYsWLCAwsJCMjIy2LZtW43fj4iIiMiNSuUctejgwYOsWLHCWxO9efNmXnjhBW9NdM+ePRkw\nYEC54+bMmUNqaqp3Bo2lS5cya9ascouj5OfnM2XKFA4cOEBYWBi9evXijTfeAGDQoEH069ePKVOm\nEBYWRkZGBuPHj+f5559n0KBBPPLII2XOdXl/EREREbk6u94zRtQWM3MVxXopQb1cXZ0n+kZW0X0S\nERGR4GSphptVfz/XS/OWq84HXC+TaKl7dJ9ERETqDyXRqokWEREREfGZkmgRERERER+pnEP8QvdJ\nREQkuHmyPHiyPN7XSXFJACTFJXlf1xeqiZY6Q/dJREREgoVqokVEREREaoGSaBERERERHymJFhER\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "from pandas.tseries.holiday import USFederalHolidayCalendar\n", + "from pandas.tseries.offsets import CustomBusinessDay\n", + "from datetime import datetime, timedelta\n", + "\n", + "# If you remove rules, it removes them from *all* calendars\n", + "# To ensure we don't pop rules we don't want to, first make\n", + "# sure to fully copy the object\n", + "trade_calendar = USFederalHolidayCalendar()\n", + "trade_calendar.rules.pop(6) # Remove Columbus day\n", + "trade_calendar.rules.pop(7) # Remove Veteran's day\n", + "TradeDay = lambda days: CustomBusinessDay(days, calendar=trade_calendar)\n", + "\n", + "def plot_study(array):\n", + " # Given a 2-d array, we assume the event happens at index `lookback`,\n", + " # and create all of our summary statistics from there.\n", + " lookback = int((array.shape[1] - 1) / 2)\n", + " norm_factor = np.repeat(array[:,lookback].reshape(-1, 1), array.shape[1], axis=1)\n", + " centered_data = array / norm_factor - 1\n", + " lookforward = centered_data.shape[1] - lookback\n", + " means = centered_data.mean(axis=0)\n", + " lookforward_data = centered_data[:,lookforward:]\n", + " std_dev = np.hstack([0, lookforward_data.std(axis=0)])\n", + " maxes = lookforward_data.max(axis=0)\n", + " mins = lookforward_data.min(axis=0)\n", + " \n", + " f, axarr = plt.subplots(1, 2)\n", + " range_begin = -lookback\n", + " range_end = lookforward\n", + " axarr[0].plot(range(range_begin, range_end), means)\n", + " axarr[1].plot(range(range_begin, range_end), means)\n", + " axarr[0].fill_between(range(0, range_end),\n", + " means[-lookforward:] + std_dev,\n", + " means[-lookforward:] - std_dev,\n", + " alpha=.5, label=\"$\\pm$ 1 s.d.\")\n", + " axarr[1].fill_between(range(0, range_end),\n", + " means[-lookforward:] + std_dev,\n", + " means[-lookforward:] - std_dev,\n", + " alpha=.5, label=\"$\\pm$ 1 s.d.\")\n", + " \n", + " max_err = maxes - means[-lookforward+1:]\n", + " min_err = means[-lookforward+1:] - mins\n", + " axarr[0].errorbar(range(1, range_end),\n", + " means[-lookforward+1:],\n", + " yerr=[min_err, max_err], label='Max & Min')\n", + " axarr[0].legend(loc=2)\n", + " axarr[1].legend(loc=2)\n", + " \n", + " axarr[0].set_xlim((-lookback-1, lookback+1))\n", + " axarr[1].set_xlim((-lookback-1, lookback+1))\n", + " \n", + "def plot_study_small(array):\n", + " # Given a 2-d array, we assume the event happens at index `lookback`,\n", + " # and create all of our summary statistics from there.\n", + " lookback = int((array.shape[1] - 1) / 2)\n", + " norm_factor = np.repeat(array[:,lookback].reshape(-1, 1), array.shape[1], axis=1)\n", + " centered_data = array / norm_factor - 1\n", + " lookforward = centered_data.shape[1] - lookback\n", + " means = centered_data.mean(axis=0)\n", + " lookforward_data = centered_data[:,lookforward:]\n", + " std_dev = np.hstack([0, lookforward_data.std(axis=0)])\n", + " maxes = lookforward_data.max(axis=0)\n", + " mins = lookforward_data.min(axis=0)\n", + " \n", + " range_begin = -lookback\n", + " range_end = lookforward\n", + " plt.plot(range(range_begin, range_end), means)\n", + " plt.fill_between(range(0, range_end),\n", + " means[-lookforward:] + std_dev,\n", + " means[-lookforward:] - std_dev,\n", + " alpha=.5, label=\"$\\pm$ 1 s.d.\")\n", + " \n", + " max_err = maxes - means[-lookforward+1:]\n", + " min_err = means[-lookforward+1:] - mins\n", + " plt.errorbar(range(1, range_end),\n", + " means[-lookforward+1:],\n", + " yerr=[min_err, max_err], label='Max & Min')\n", + " plt.legend(loc=2)\n", + " plt.xlim((-lookback-1, lookback+1))\n", + " \n", + "def fetch_event_data(ticker, events, horizon=5):\n", + " # Use horizon+1 to account for including the day of the event,\n", + " # and half-open interval - that is, for a horizon of 5,\n", + " # we should be including 11 events. Additionally, using the\n", + " # CustomBusinessDay means we automatically handle issues if\n", + " # for example a company reports Friday afternoon - the date\n", + " # calculator will turn this into a \"Saturday\" release, but\n", + " # we effectively shift that to Monday with the logic below.\n", + " td_back = TradeDay(horizon+1)\n", + " td_forward = TradeDay(horizon+1)\n", + " \n", + " start_date = min(events) - td_back\n", + " end_date = max(events) + td_forward\n", + " total_data = fetch_ticker(ticker, start_date, end_date)\n", + " event_data = [total_data.ix[event-td_back:event+td_forward]\\\n", + " [0:horizon*2+1]\\\n", + " ['Adjusted Close']\n", + " for event in events]\n", + " return np.array(event_data)\n", + "\n", + "# Generate a couple of random events\n", + "\n", + "event_dates = [datetime(2016, 5, 27) - timedelta(days=1) - TradeDay(x*20) for x in range(1, 40)]\n", + "data = fetch_event_data('CELG', event_dates)\n", + "plot_study_small(data)\n", + "plt.legend(loc=3)\n", + "plt.gcf().set_size_inches(12, 6);\n", + "\n", + "\n", + "plt.annotate('Mean price for days leading up to each event',\n", + " (-5, -.01), (-4.5, .025),\n", + " arrowprops=dict(facecolor='black', shrink=0.05))\n", + "plt.annotate('', (-.1, .005), (-.5, .02),\n", + " arrowprops={'facecolor': 'black', 'shrink': .05})\n", + "plt.annotate('$\\pm$ 1 std. dev. each day', (5, .055), (2.5, .085),\n", + " arrowprops={'facecolor': 'black', 'shrink': .05})\n", + "plt.annotate('Min/Max each day', (.9, -.07), (-1, -.1),\n", + " arrowprops={'facecolor': 'black', 'shrink': .05});" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And as a quick textual explanation as well:\n", + "\n", + "- The blue line represents the mean price for each day, represented as a percentage of the price on the '0-day'. For example, if we defined an 'event' as whenever the stock price dropped for three days, we would see a decreasing blue line to the left of the 0-day.\n", + "\n", + "- The blue shaded area represents one standard deviation above and below the mean price for each day following an event. This is intended to give us an idea of what the stock price does in general following an event.\n", + "\n", + "- The green bars are the minimum and maximum price for each day following an event. This instructs us as to how much it's possible for the stock to move." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Event Type 1: Trending down over the past N days\n", + "\n", + "The first type of event I want to study is how stocks perform when they've been trending down over the past couple of days prior to a release. However, we need to clarify what exactly is meant by \"trending down.\" To do so, we'll use the following metric: **the midpoint between each day's opening and closing price goes down over a period of N days**.\n", + "\n", + "It's probably helpful to have an example:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\neeSRR5g2bRp///vfl+lz0003MXr0aGbPns2gQYP4wQ9+AMDcuXPZe++9OfHEE5k9ezYnnXQSe+21\nF3Pnzq1xrKeffpqBAwcye/ZsTj311MpLF8477zx23nlnrrzySubPn8/ll1+ep3dCkiRJktSamERY\nSUtmIzz88MMMHDiQXr161XiZwu23386oUaMYOHAga665JiUlJcv02Wuvvdhxxx1p164d559/Pk89\n9RQzZ87kvvvuY8CAAYwYMYI2bdpwyCGHsMkmm3DPPffUGFPfvn056qijiAiOPPJIPvjgAz788MN8\nv3RJkiRJUivVLAsr5qkuIatSmuCwww5jl1124Z133uGII47IxbVsYLNmzWLrrbeufNy3b99lkg19\n+vSpvL/WWmvRpUsXZs2axaxZs+jbt+9Sffv27cvMmTNrjKmoqKjy/pprrgnAJ598Qvfu3Vfw1UmS\nJEmStKxmORMhpfzcVsV6661H//79eeCBB/je975Xa7+ePXvy3nvvVT5+9913l0k2VN3+ySefMHfu\nXHr16kWvXr0oKytbqu+MGTNYd911VzjefK0IIUmSJElqvZplEqGpGD9+PP/4xz8qz/rXdDnD8OHD\nmTBhAlOnTmXhwoX86le/WqbP/fffz5QpU/j8888555xzGDJkCOuuuy577rkn06ZN45ZbbmHRokXc\neuutTJ06lX322WeFY+3Rowdvv/32ir9ISZIkSZJyTCKsoKpn9Pv3789WW21V47Yl9thjD0488UR2\n3XVXBgwYwLBhw5bpM2LECEpKSujWrRv//ve/ueGGGwDo2rUr9957L2PGjGGdddZhzJgx3HfffXTp\n0qXW8WqL9YQTTuD222+nW7dunHjiiSv2oiVJkiRJAqKms+eNMnBEqmnsiKjxjH5LNWrUKPr06VPj\nDAWtutb2eWoOojRIo/03kZYn9/8ur0NrBLUdj0iSWjePWWs/HnEmgiRJkiRJqheTCAVmwUOpHiZM\nKHQEkiRJkmimSzy2JOPHjy90CFLTV22VEkmSJEmF4UwESZIkSZJULyYRJEmSJElSvZhEkCRJkiRJ\n9WISQZIkSZIk1YtJBEmSJEmSVC8mEZqwyZMnM3DgwEKHsUKGDh3qihOSJEmS1EKZRFhB/fr1o337\n9nTs2JEOHTrQsWNHjj/++AYZa6eddmLq1KkNsu/aXHfddbRt25aOHTvSuXNnBg8ezH333deoMUiS\nJEmSmqY6kwgRMS4iKiLipSptF0fE1Ih4ISL+EhEdq2w7MyKm5bbv1lCBF0pEcN999zF//nwWLFjA\n/Pnzufzyy1d4P4sWLWqA6PJjhx12YP78+cybN4/jjjuOQw45hPnz5xc6LEmSJElSgdVnJsK1wO7V\n2h4CNkspbQlMA84EiIhNgeHAQOC7wNiIiPyF2zSklGpsf/vttxk2bBjrrLMO3bt357DDDlvqx3f/\n/v25+OKLGTRoEGuvvTaLFi2if//+/Pa3v2XQoEF06dKFQw89lM8//xyAxx57jD59+iz1/Nr6Alx8\n8cX06tWL3r17M27cONq0acPbb78NwP33389mm21Gx44d6dOnD5deemm9Xuvhhx/Op59+yrRp0yrb\nnnrqKXbccUe6dOnC4MGDeeyxx2p9/vjx49l0003p1q0b3/3ud5kxY0blthNPPJH11luPTp06sc02\n2zB58uTKbc888wzbbLMNnTp1omfPnpxyyikrNb4kSZIkKX/qTCKklCYDc6u1/T2ltDj38Cmgd+7+\nvsAtKaUvU0plZAmGbfMXbtOWUuKss86ivLycqVOn8v7771NSUrJUn1tuuYUHHniAefPmsdpqqwFw\n++2389BDD/HOO+/w4osvMmHChMr+1XMwtfWdOHEil112Gf/4xz+YPn06kyZNWuq5Rx99NNdccw3z\n58/nlVdeYdddd63z9SxatIjx48ez+uqr07dvXwBmzZrF3nvvzbnnnsvcuXMZM2YMBx54ILNnz17m\n+XfffTcXXnghd911Fx999BE777wzhx56aOX2bbfdlpdeeom5c+cyYsQIDj744MqkyAknnMCJJ57I\nxx9/zFtvvcXw4cNXeHxJkiRJUn7loybCUcD9ufvrAu9V2TYz19ai7L///nTt2pUuXbrQtWtXxo0b\nB8AGG2zAsGHDaNu2Ld26deOkk05a5iz5CSecQK9evVhjjTWWauvRowedO3dmn3324YUXXqh17Nr6\n3n777YwaNYpNNtmEr33ta5SUlCw1Y2L11Vfn1VdfZcGCBXTq1Iktt9yy1jGefPJJunbtypprrslp\np53GDTfcwDrrrAPADTfcwF577cXuu2eTU4YNG8bWW2/N/fffv8x+rrrqKs4880wGDBhAmzZtOOOM\nM3jhhRd4773sIzJixAg6d+5MmzZtOOmkk/jss8944403KuOdPn06s2fPpn379my77bYrPL4kSWoY\nVU94SJJal1VKIkTEL4EvUko35yme+o1bGnm5ray7776bOXPmMHfuXObMmcMPf/hDAD788EMOPfRQ\nevfuTefOnTnssMP4z3/+s9Rze/fuvcz+evToUXm/ffv2fPLJJ7WOXVvfWbNmLXXpQ9X7AH/5y1+4\n77776Nu3L0OHDuWpp56qdYztt9+eOXPmMG/ePPbdd1/++c9/Vm579913ue222+jatWtlIuWJJ56g\nvLx8mf28++67nHDCCZV9u3XrRkQwc+ZMAMaMGcOmm25Kly5d6NKlC/Pnz698v8aNG8cbb7zBJpts\nwnbbbVdZ3LG28T/44INaX48kSa1JY/zALysra/AxMFEhSU1S25V9YkSMBPYEqs6LnwlU/fXaO9dW\no6pT/YuLiykuLq7X2Gl0zTUJGkttNRHOOuss2rRpw6uvvkqnTp24++67+fnPf75Un4YqEdGzZ0/e\nf//9ysczZsxYaqxvfvOb3HXXXSxatIgrrriC4cOHL1WfoCbt27dn7NixrL/++vzwhz9k0KBB9OnT\nhyOOOIKrrrqqzpj69OnD2WefvdQlDEtMnjyZSy65hEcffZRNN90UgK5du1a+txtssAE33XQTkCVA\nDjroIObMmbNC40tSczFp0iQmTZpU6DDUQjTKD/zG0FJehyS1MPWdiRC5W/YgYg/gVGDflNJnVfr9\nDTgkIlaPiP7AhsDTte20pKSk8lbfBEJTtmDBAtZee206dOjAzJkzueSSSxpt7OHDh3Pttdfy+uuv\ns3DhQs4777zKbV988QU33XQT8+fPZ7XVVqNDhw6V9Rjq0qVLF4455hhKS0sBOOyww7jnnnt46KGH\nWLx4Mf/73/947LHHmDVr1jLPPfbYY7ngggt47bXXAPj444+54447gOy9ateuHd26dePzzz/nV7/6\nFQsWLKh87o033lg5K6FTp05EBG3atFmh8SWpuSguLl7qO1GSJKmpqs8SjzcBU4ABETEjIkYBVwBr\nAw9HxPMRMRYgpfQacBvwGlmdhJ+k2k7bN2P77LMPHTt2rLwdeOCBAIwePZrnnnuusl7BkvYlapqF\nsCIzE5bXd4899uD4449n6NChDBgwgO233x6gsvbC9ddfT//+/encuTNXX3115Vn++jjhhBN44IEH\neOWVV+jduzd33303F1xwAV//+tfp27cvY8aMYfHixcvEuP/++3PGGWdwyCGH0LlzZ7bYYgsmTpwI\n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\nkCSpOkciSJIkSZKknJhEkCRJkiRJOTGJIEmSJEmScmISQZIkSZIk5cQkgiRJkiRJyolJBEmSJNXp\n0UcfpX///oUOo0GGDBnijhOS1EhMIkiSJLUwffr0oWPHjnTq1Ikdd9yRTp06cf755zdKW1/4whdY\nsGBBo7x2XaZOnUr79u3p1KkTXbp0Yb/99mPmzJlNGoMkqXbtCx2AJEmSGiYimDlzJkOGDNmq11m/\nfj3t2rXLU1T59a//+q/8+c9/BuCXv/wlp556KkuXLqVTp04FjkyS2jZHIkiSJLVAKaVay998802G\nDh1K9+7d6dGjByNGjGDNmjVV5/v27cu1117LgAED2GGHHVi/fj19+/bl+uuvZ8CAARQXF3Paaafx\n0UcfATB37lx69+5d4/q66gJce+219OzZk169ejFx4kSKiop48803AZg1axZ77703nTp1onfv3txw\nww05vdczzjiDf/7zn7z++utVZU8++SSHHHIIxcXF7LfffsydO7fO6ydNmsRee+1Ft27dOProo1my\nZEnVuTFjxrDrrrvSuXNnBg0axKOPPlp17umnn2bQoEF07tyZnXfemQsvvHCL2pek1sQkgiRJUiuS\nUuLSSy9l+fLlLFiwgL/+9a+MGzeuRp3bb7+d2bNn8+6771aNRJg+fTr3338/b731Fi+++CJTpkyp\nqh8RNa6vq+6cOXP4yU9+wkMPPcQbb7xBRUVFjWu//vWv86tf/Yo1a9Ywf/58jjjiiHrfz/r165k0\naRIdOnSgrKwMgGXLlnHcccdx+eWXs3r1aiZMmMBXv/pVVq5cucn1M2bM4JprruHuu+/mnXfe4dBD\nD+W0006rOj948GBeeuklVq9ezfDhwznllFOqkiKjR49mzJgxvPfee/zlL39h2LBhDW5fklobkwiS\nJEkt0EknnUTXrl0pLi6ma9euTJw4EYDdd9+doUOH0r59e7p168YFF1ywyafko0ePpmfPnmy77bY1\nykpKSujSpQvHH388L7zwQp1t11V3+vTpjBo1ij333JPPfOYzjBs3rsaIiQ4dOvDKK6+wdu1aOnfu\nzOc///k623jiiSfo2rUr2223Hd/73ve49dZb6d69OwC33norxx57LEceeSQAQ4cO5YADDmDWrFmb\nvM7NN9/MJZdcQr9+/SgqKuLiiy/mhRde4O233wZg+PDhdOnShaKiIi644ALWrVvHwoULq+J94403\n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\nTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "f, axarr = plt.subplots(1, 2)\n", + "f.set_size_inches(18, 6)\n", + "\n", + "FB_plot = axarr[0]\n", + "ohlc_dataframe(FB[datetime(2016, 4, 18):], FB_plot)\n", + "\n", + "FB_truncated = FB[datetime(2016, 4, 18):datetime(2016, 4, 27)]\n", + "midpoint = FB_truncated['Open']/2 + FB_truncated['Close']/2\n", + "FB_plot.plot(FB_truncated.index, midpoint, label='Midpoint')\n", + "FB_plot.vlines(date2num(datetime(2016, 4, 27, 12)),\n", + " ax_fb.get_ylim()[0], ax_fb.get_ylim()[1],\n", + " color='g', label='Earnings Release')\n", + "FB_plot.legend(loc=2)\n", + "FB_plot.set_title('FB Midpoint Plot')\n", + "\n", + "AAPL_plot = axarr[1]\n", + "ohlc_dataframe(AAPL[datetime(2016, 4, 10):], AAPL_plot)\n", + "AAPL_truncated = AAPL[datetime(2016, 4, 10):datetime(2016, 4, 26)]\n", + "midpoint = AAPL_truncated['Open']/2 + AAPL_truncated['Close']/2\n", + "AAPL_plot.plot(AAPL_truncated.index, midpoint, label='Midpoint')\n", + "AAPL_plot.vlines(date2num(datetime(2016, 4, 26, 12)),\n", + " ax_aapl.get_ylim()[0], ax_aapl.get_ylim()[1],\n", + " color='g', label='Earnings Release')\n", + "AAPL_plot.legend(loc=3)\n", + "AAPL_plot.set_title('AAPL Midpoint Plot');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Given these charts, we can see that FB was trending down for the four days preceding the earnings release, and AAPL was trending down for a whopping 8 days (we don't count the peak day). This will define the methodology that we will use for the study.\n", + "\n", + "So what are the results? For a given horizon, how well does the market actually perform?" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100% (47578 of 47578) |###########################################################| Elapsed Time: 0:21:38 Time: 0:21:38\n" + ] + }, + { + "data": { + "image/png": "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\nNXU1G9arJ1QDUD2hesN63or/vkbedfQGXovky/dZkrqujl6PGDSopPw9SeruYnKQLu56/44ZNHQe\nr0Xy5fssSV1XR69HnKNBkiRJkiSVjEGDJEmSJEkqGYMGSZIkSZJUMgYNkiRJkiSpZAwaJEmSJElS\nyZTnXYAkSVJ3MH78eCK88cf2Nn78+LxLkCRto24dNJTivufd4d7pkiQpf3V1dXmXIElStxBd7T7F\nb/be1aW473lXvXd6Z/vsZz/L2LFj+frXv77Vr/Xe15K6u676f0FH71utbbe5axFJknq7jl6POEdD\nCUyYMIF+/fqxatWqTfZPnDiRQqHAggULSn7O+vp6zjzzTIYNG8aoUaP44he/WLI6r7rqqjcVMkiS\nJEmSZNBQAhHBLrvswm9/+9sN+2bNmsVrr7223cZyXn/99cyYMYO6ujqee+45TjnllC5ZpyRJkiSp\ndzFoKJGPf/zj3HDDDRu2b7jhBj7xiU9s0uaOO+7goIMOorKykvHjxzN58uQNz918883suuuurF27\nFoA777yT0aNHs3LlynbPV1FRQWVlJUOGDKF///684x3vKFmdZ599Nt/85jcBuPfeexk3bhw/+tGP\n2GmnnRgzZgzXX399h84lSZIkSep9DBpK5IgjjuDll1/mqaeeorm5md/97nd87GMf22S+gkGDBvHr\nX/+al156idtvv52f/exn/PnPfwbgwx/+MEcddRSf//znWbVqFZ/61Ke47rrrGD58eLvnO+igg3jw\nwQeZNGlSyetsa9myZbz88sssWbKEX/ziF5x77rm89NJLW3VeSZIkSVLv0K3vOtFWTM63+39Lb4F3\nvOMd7L333uy8886bPH/00UdvWN9vv/047bTTuPfeeznppJMAuPzyy9l///2prq7m5JNP5oQTTmj3\nPKtXr+akk07i9ttv5+KLLyYiuPjiiwEYN24cd911F/vuu++brrOtPn36cNFFF1EoFDjhhBMYNGgQ\nTz31FIcddliH3hdJkiRJUu9RkqAhIo4HLiXrIXFtSumSNs8PAf4bqALKgB+mlK4vxblbK8VdJ7bF\nxz72MY4++miee+45zjzzzNc9/9BDD/HVr36VWbNmUV9fT319PR/60Ic2PF9ZWcmHPvQhfvzjH3PL\nLbds9jz/8z//wz777MN73vMeDjnkEI4++mgigk984hM0NTVtMWToSJ1tDR8+nEJhY+eXAQMGbBji\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Read in the events for each stock;\n", + "# The file was created using the first code block in the Appendix\n", + "import yaml\n", + "from dateutil.parser import parse\n", + "from progressbar import ProgressBar\n", + "\n", + "data_str = open('earnings_dates.yaml', 'r').read()\n", + "# Need to remove invalid lines\n", + "filtered = filter(lambda x: '{' not in x, data_str.split('\\n'))\n", + "earnings_data = yaml.load('\\n'.join(filtered))\n", + "\n", + "# Convert our earnings data into a list of (ticker, date) pairs\n", + "# to make it easy to work with.\n", + "# This is horribly inefficient, but should get us what we need\n", + "ticker_dates = []\n", + "for ticker, date_list in earnings_data.items():\n", + " for iso_str in date_list:\n", + " ticker_dates.append((ticker, parse(iso_str)))\n", + "\n", + "def does_trend_down(ticker, event, horizon):\n", + " # Figure out if the `event` has a downtrend for\n", + " # the `horizon` days preceding it\n", + " # As an interpretation note: it is assumed that\n", + " # the closing price of day `event` is the reference\n", + " # point, and we want `horizon` days before that.\n", + " # The price_data.hdf was created in the second appendix code block\n", + " try:\n", + " ticker_data = pd.read_hdf('price_data.hdf', ticker)\n", + " data = ticker_data[event-TradeDay(horizon):event]\n", + " midpoints = data['Open']/2 + data['Close']/2\n", + "\n", + " # Shift dates one forward into the future and subtract\n", + " # Effectively: do we trend down over all days?\n", + " elems = midpoints - midpoints.shift(1)\n", + " return len(elems)-1 == len(elems.dropna()[elems <= 0])\n", + " except KeyError:\n", + " # If the stock doesn't exist, it doesn't qualify as trending down\n", + " # Mostly this is here to make sure the entire analysis doesn't \n", + " # blow up if there were issues in data retrieval\n", + " return False\n", + "\n", + "def study_trend(horizon, trend_function):\n", + " five_day_events = np.zeros((1, horizon*2 + 1))\n", + " invalid_events = []\n", + " for ticker, event in ProgressBar()(ticker_dates):\n", + " if trend_function(ticker, event, horizon):\n", + " ticker_data = pd.read_hdf('price_data.hdf', ticker)\n", + " event_data = ticker_data[event-TradeDay(horizon):event+TradeDay(horizon)]['Close']\n", + "\n", + " try:\n", + " five_day_events = np.vstack([five_day_events, event_data])\n", + " except ValueError:\n", + " # Sometimes we don't get exactly the right number of values due to calendar\n", + " # issues. I've fixed most everything I can, and the few issues that are left\n", + " # I assume don't systemically bias the results (i.e. data could be missing\n", + " # because it doesn't exist, etc.). After running through, ~1% of events get\n", + " # discarded this way\n", + " invalid_events.append((ticker, event))\n", + " \n", + "\n", + " # Remove our initial zero row\n", + " five_day_events = five_day_events[1:,:]\n", + " plot_study(five_day_events)\n", + " plt.gcf().suptitle('Action over {} days: {} events'\n", + " .format(horizon,five_day_events.shape[0]))\n", + " plt.gcf().set_size_inches(18, 6)\n", + " \n", + "# Start with a 5 day study\n", + "study_trend(5, does_trend_down)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When a stock has been trending down for 5 days, once the earnings are announced it really doesn't move on average. However, the variability is *incredible*. This implies two important things:\n", + "\n", + "1. The market is just as often wrong about an earnings announcement before it happens as it is correct\n", + "2. The incredible width of the min/max bars and standard deviation area tell us that the market reacts *violently* after the earnings are released.\n", + "\n", + "Let's repeat the same study, but over a time horizon of 8 days and 3 days. Presumably if a stock has been going down for 8 days at a time before the earnings, the market should be more accurate." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100% (47578 of 47578) |###########################################################| Elapsed Time: 0:20:29 Time: 0:20:29\n" + ] + }, + { + "data": { + "image/png": "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\nXlrzW/yEisVmdls9x70TSIocey7ben8ATMT/O3h5J/sXbLd/tOifzePAXDN7HjgImBp53bdFjici\nIhJ3LPL3WkRERKRBIvM9fAUM1RwDIiIiAuq5ICIiIo1gZifgexU8oGBBREREaqnngoiIiIiIiIg0\niXouiIiIiIiIiEiTKFwQERERERERkSZRuCAiIiIiIiIiTaJwQURERERERESaROGCiIiIiIiIiDSJ\nwgURERERERERaRKFCyIiIiIiIiLSJAoXRERERERERKRJFC6IiIiIiIiISJMoXBARERERERGRJlG4\nICIiIiIiIiJNonBBRERERERERJpE4YKIiIiIiIiINInCBRERERERERFpEoULIiIiIiIiItIkChdE\nREREREREpEkULoiIiIiIiIhIkyhcEBEREREREZEmUbggIiIiIiIiIk0Sk3DBzE41swVmtsjMbqjn\n8Uwze8vMZpvZXDO7LBbnFRERkfjTgHbHxWb2VWT5zMwGN/S5IiIismfMOde0A5iFgEXACUApMA0Y\n6ZxbELXPH4BM59wfzKwrsBDo7pyrbtLJRUREJK40sN1xFDDfOVdmZqcCY51zRzXkuSIiIrJnYtFz\n4QhgsXNumXOuCngJOGu7fRzQMbLeEVitYEFERET2wG7bHc65Kc65ssjdKUDvhj5XRERE9kwswoXe\nwLdR979j2x/xWg8BA82sFPgKuC4G5xUREZH405B2R7QrgHf38LkiIiLSQIktdJ5TgFnOuZ+a2T7A\nv8xssHNu4/Y7mlnTxmmIiIi0U845C7qGtsTMfgKMAY5r5PPUFhEREdmJnbVHYhEulAD9ou73iWyL\nNga4K1LIEjMrBA4Aptd3wKbOAyGxNXbsWMaOHRt0GRIA/e7jl373rY+ZcoWIhrQ7iEzi+DhwqnNu\nbWOeC2qLtEZ6X4pf+t3HL/3uW59dtUdiMSxiGrCvmeWYWTIwEnhru32WASdGiukO7AcsjcG5RURE\nJL7stt1hZv2AicAo59ySxjxXRERE9kyTey4452rM7DfA+/iw4inn3Hwzu8o/7B4H7gSeMbM5kadd\n75xb09Rzi4iISHxpYLvjVqAz8Ij5r1iqnHNH7Oy5Ab0UERGRdiUmcy445yYB+2+37bGo9eX4eRek\nDcrLywu6BAmIfvfxS797ac0a0O64Eriyoc+VtkHvS/FLv/v4pd9922KtbUyhmbnWVpOIiEjQzEwT\nOrYQtUVERETqt6v2SEtdLaLJcnNzWbZsWdBlyG7k5ORQVFQUdBkiIiIxp7ZIy1BbQkSkbWozPRci\nCUkAFUlj6PckItI81HOh5agtEiz9nEVEWq9dtUdicbUIEREREREREYljChdEREREREREpEkULoiI\niIiIiIhIkyhcEBEREREREZEmUbggIiIiIiIiIk3SZi5Fub3bbruf4uJ1zXb8fv2yueOO3zbb8VvK\nmDFj6Nu3L3fccUfQpYiIiLQ7ao80jNojIiLtX5sNF4qL15GbO7bZjl9U1HzHrvXwww/zzDPPMHfu\nXC6++GImTJjQ7OcUERGR2FF7RERExNOwiGYwfvz4Bu3Xu3dvbr31Vi6//PJmrkhERETijdojIiLS\nkhQuNIMtW7Y0aL8RI0YwfPhwOnfuvNt9x48fT58+fcjMzGTAgAF89NFH9e43a9YsDj30ULKyshg5\nciSbN29uVO0iIiLSPqg9IiIiLUnhQjNwzsX0eIsWLeLhhx9mxowZrF+/nvfee4/c3Nwd9quqquLs\ns89m9OjRrFmzhvPPP5+JEyfGtBYRERFpG9QeERGRltRm51xoTZYsWcJrr72GmeGcY/Lkydxzzz04\n5zAzjjzySI4//vg9Pn5CQgKVlZUUFBTQpUsX+vXrV+9+U6ZMobq6mmuvvRaAc889l8MPP3yPzysi\nIiJth9ojIiISJIULMbDPPvtwww03bL2/ZcsWrr/++pge//7772fs2LHMmzePU045hb/85S/07Nmz\nzn6lpaX07t27zracnJyY1SEiIiKtl9ojIiISJA2LaCNGjhzJp59+yrJlywC48cYbd9inZ8+elJSU\n1NlWXFzcIvWJiIhI+6f2iIiI7IzChWbQ0DGONTU1bN68mZqaGqqrq9myZQs1NTU77Ldo0SI++ugj\nKisrSU5OpkOHDoRCO/7qjj76aBITE3nwwQeprq7m9ddfZ+rUqU1+PSIiItL2qD0iIiItqc0Oi+jX\nL7tZr/3cr192g/dduHAhL7300tYxjh9//DF33HHH1jGORx99NCeddNIOz7vzzjsZN24cZgbA3//+\nd26//XZuu+22Ovtt2bKFG2+8kQULFpCUlMQxxxzD448/DsDpp5/OsGHDuPHGG0lKSuL111/niiuu\n4JZbbuH000/n3HPPrXOs6P1FRESkadQeUXtEREQ8i/VMwk1lZq6+mmr/UErrpt+TiEjziLy/WtB1\nxAO1RYKln7OISOu1q/aIhkWIiIiIiIiISJMoXBARERERERGRJlG4ICIiIiIiIiJNonBBRERERERE\nRJpE4YKIiIiIiIiINInCBRERERERERFpksSgCxARERFpC3JycjDT1UCbW05OTtAliIjIHrDWdh3h\nxlxbOr8on/yi/K3rebl5AOTl5m1d351YHEO20bWpRUSax66uKy2xtbO2iIiISLzbVXukTYcLdR4f\nZ7jbm/ZaYnGM9uBXv/oVffr04eabb270cxUuiIg0D4ULLUfhgoiISP121R7RnAsxkJubS2pqKmvW\nrKmzfciQIYRCIYqLi2N+zsrKSi699FI6d+5Mjx49+N3vfhezOh999NE9ChZEREREREQkPilciAEz\no3///rz44otbtxUUFFBRUdFsYzOfeeYZZs+eTVFREYWFhYwYMaJV1ikiIiIiIiLtn8KFGBk1ahTP\nPvvs1vvPPvsso0ePrrPPO++8w9ChQ8nKyiInJ4dx48ZtfeyVV15h7733ZuPGjQC8++679OzZk9Wr\nV9d7vqSkJLKyssjMzKRDhw4cf/zxMatzzJgx3HbbbQB8/PHH9O3bl3vvvZfu3bvTu3dvnnnmmQad\nS0REREREROKDwoUYOeqoo9iwYQMLFy4kHA7z8ssv8/Of/7zO/AMZGRk8//zzlJWV8fbbb/PXv/6V\nt956C4ALLriAY489lmuvvZY1a9ZwxRVXMGHCBLp06VLv+YYOHcqUKVMYO3ZszOvc3ooVK9iwYQOl\npaU8+eSTXH311ZSVlTXqvCIiIiIiItJ+tatLUdq4YLv21/YKOP744xkwYAC9evWq8/iwYcO2rg8a\nNIiRI0fy8ccfM3z4cAAeeughBg8eTF5eHmeddRannXZavedZu3Ytw4cP5+233+b222/HzLj99tsB\n6Nu3L5MmTeLAAw/c4zq3l5yczK233kooFOK0004jIyODhQsXcsQRRzTo5yIiIiIiIiLtW7sKF2Jx\ntYim+PnPf86wYcMoLCzk0ksv3eHxL7/8kj/84Q8UFBRQWVlJZWUl559//tbHs7KyOP/887nvvvt4\n/fXXd3qeV199lYEDB3LyySdz2GGHMWzYMMyM0aNHU1NTs8tgoSF1bq9Lly6EQts6uaSlpW0dviEi\nIiIiIiKiYREx1K9fP/r378+7777LOeecs8Pjl1xyCSNGjKCkpIR169Zx1VVX1RmOMHv2bCZMmMBF\n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\nAAAAKMr/B9pAH9lY/+K6AAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# 8 day study next\n", + "study_trend(8, does_trend_down)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, looking only at stocks that trended down for 8 days prior to a release, the same pattern emerges: on average, the stock doesn't move, but the market reaction is often incredibly violent." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100% (47578 of 47578) |###########################################################| Elapsed Time: 0:26:26 Time: 0:26:26\n" + ] + }, + { + "data": { + "image/png": "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\nSTfmKmb+uQ4AAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# 3 day study after that\n", + "study_trend(3, does_trend_down)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, when we look at a 3-day horizon, we start getting some incredible outliers. Stocks have a potential to move over ~300% up, and the standard deviation width is again, incredible. The results for a 3-day horizon follow the same pattern we've seen in the 5- and 8-day horizons." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Event Type 2: Trending up for N days\n", + "\n", + "We're now going to repeat the analysis, but do it for uptrends instead. That is, instead of looking at stocks that have been trending down over the past number of days, we focus only on stocks that have been trending up." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100% (47578 of 47578) |###########################################################| Elapsed Time: 0:22:51 Time: 0:22:51\n" + ] + }, + { + "data": { + "image/png": "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\nzsvTaq7XU3dyckYTExO6cmVSzz03qfHxSV29OiP3nKS83H9J6XSb0uk2pVIZuVvl54qaL7fO9LYn\npNfcqI/bXqmqc+jmc9ZVY93Ng6Lydqvu8M5bt7mdzEX3sapzaKP6talquzT3/HWUzSlfQdmcY0v9\nZnMHQPBw3cuF89cXK1vGenk2v0647TN+U7Ds1eVVIy6U9ysvl0eWmHMOk8lm65TrV+pZ5by24Biz\n9SvbiiS9AACLu+ee2/Xgg4dJIAARmvoSxYMHD1aW+/r61NfX18zTY40pd8Cnp6WpqdnlpaZyver6\n88uaVSeVkrLZYMpkgqnWciPXOzqi6z/55FM6fPioisWiUilp69bt2rBhpzo6NqmtbaPS6eCjwar6\nbNXLteYrqTOT2qOHXPod/0rQbax0BqVUeai/cL28vbIedjDDkqCuV62FncjKexjcKsdU+chedczy\nPmEH9W/tev2JTs6eq6K6fRFl0rzyZZb5bNmfW0oHNDehMP+UNddXUb+ZDniNdiWov0XewzEwMKCB\ngYGkmwEAqHL77bfJbEDF4rTS6WzSzQFaViMSCGckPb9qfVdYtkB1AgGN5T7biS1/y7xay/V24lc6\nSbMd8GxWyuXmrs+fqreXl2vNy8vt7dF16jnOYvNUCz9C99a33qFS6XZduHBBIyMjGhoq6PjxQxoc\nLOjMmVGVStdJyqtUyqujo0ddXXl1dm5TKrWaOccuyY7ohX7bKp5jmeySNvmmpFuxkEm18gdoXfMT\n6P39/ck1BgAgSdqwYYNe/OKdevrpZ5TPt2AsArSIRvQGfiTpRjO7XtJZSW+RdF8DjpuI8q3nU1PN\nm8qd7sXK6+3Ql0pzv2Wu/ua7upNda1vc5Y4OaePG+jrzy53SvItvVaVSKW3dulVbt27VLbfcUikv\nlUo6f/68CoWChodHdOzYMzpx4gc6c+a83DdJ6glfnFhOLGxd5cQCAADA6nvVq/bpJz85LIkEAlDL\niqN+dy+a2XskfUezwzg+veKWNcFf/qX0qU8t7MinUkEHuNFTZ+ds5zpqitvpT6dnbwUHViKVSmnb\ntm3atm2bbr1VuueeoLxYLFYSC0NDIxocfFqDg4/pzJmLct+scmKhoyOvrq4edXQwIgMAAFg7br31\nhcrlvqXp6Qlls51JNwdoSQ352tDdvy1pTyOO1Uzvepd0330LO+588w0slE6n1dPTo56eHu3dO1s+\nMzOj0dFRjYyM6OzZggYHn9LgYEGnT49J6lbwKET5boUedXRsIbEAAABaTltbm17xipv0+OM/186d\nLxm2AvAAAA6USURBVEm6OUBLWtf3HW/eHEwAli+Tyai3t1e9vb26reqOv5mZGZ07d66SWDh27Ekd\nP17QqVOXZLZFwWgPPerszKurK6+Oju6mvugPAABgvrvu2qfHHntcEgkEYDHrOoEAYPVkMhlt375d\n27dv1759s+XT09M6d+6cCoWCzp4d0dGjP9XJkyM6efKydIN06tTDMkuFQ0eagiejFi6711defZzy\nslmqMspDedkspfIQgwuWd0jDw0+GP0HVaA5VIzbMXW5OPW2ULl8emnPdfcHoB77C7fGPoW7p4sXj\nVQXzf5aEyrgbFQAQ4cYbb1Q+/02dPPmQSqW8stledXUFX3bwWANAAgFAk2WzWe3YsUM7duzQi140\nWz41NaXP/8X9+tjH7lGpVJK7y90bvlwquYrFokqloHxmZra8erlYLFXq/P0R6WUve1aSVCoFneVy\nvVpl5U52+RhL1VvOPmVdXf8uaX7HWYuWpVIWa/uyjzEu7do1sGh7V1JWXg7+TVXXPvPLuru7F/yM\nSJ6ZdUv6iqTrJR2X9GZ3H1uk3kOS3iBp2N1vj7s/AERJp9Pq73+3hoaGNDQ0rJMnh3Xs2GGdOFHQ\n1as5mQWjVLW391Yez2TYR6wntvi3TatwIjNv1rkArE3Wb/IDrfc5QbvioV3xmJk8uD1m3TKzBySN\nuvsnzeyDkrrd/UOL1HuVpMuSvjgvgVDX/mFd4hEAsbm7xsbGwlGqCjp6dLhq+OtNCh7NzKuzszd8\nNHNLeEcjMNfp0/+sD3zgTu3Z01qvEKw3HuEOBAAAkLR7Jd0dLn9B0oCkBQkAd/9BOGz0svYHgOUy\nM23evFmbN2/WzTffrFe/OigvFosaHR0NH80s6MiRn+n48YJOnrwss21yz8ssrw0bgsRCLnfdoncN\nAmsFCQQAAJC0vLsPS5K7D5lZvsn7A8CypNNp5fN55fN53XabtH9/UD41NaVCoaBCoaDTpws6cuSI\nTpwoaGioJLPgboVMZjaxkMm0J/uDAHUigQAAAFadmT0qqbe6SMEbOO9fpPpKnzFYcv+DBw9Wlvv6\n+tTX17fC0wHAXLlcTrt27dKuXbt0552z5ePj4yoUCuH7Fc7q6NGf6cSJgqam2pVK9apYzKu9PUgs\ndHZuUypFdw2rY2BgQAMDA7H34zcSAACsOnffX2ubmQ2bWa+7D5vZdkmFmIePtX91AgEAmqmrq0u7\nd+/W7t27ddddQZm76+LFi+FjEMMaHHxWg4OP68yZ83LfLLNelUp5dXbm1dZ2nbLZTmWzXUqnczwO\ngWWbn0Dv7++vaz8SCAAAIGnfkPR2SQ9Iepukry9Rd3ac0+XtDwAtxczU3d2t7u5u7dmzR+U+XbFY\nrAx9febMsAYHD2l09LLGxsZ17tyEJieLMuuUWaeCsYo7VSp1yr0rTDIsnLijASvFbxAAAEjaA5K+\nambvlHRC0pslycx2SHrQ3d8Qrn9JUp+krWZ2UtIBd3+41v4AsJal02n19vaqt7dX+/btW7B9ZmZG\nExMTC6bnnhvX2NiILlyY0MWLE7p0KZhGRiZULGbmJB3cg0nqVC63MPGQyXS0xF0O7iWVSkWVSjML\nJvfFy0ulolKptNLpNqXTOWUywbx6nZEy4iOBAAAAEuXu5yX9+iLlZyW9oWr9rXH2B4BrWSaT0caN\nG7Vx48a66ru7JicnF006XLo0oYsXL+j8+XGNjZXXJzQxMSmpXalUl8p3ObgHdzqk07OJBklLduql\nGZkF81SqKGmmxhRscw+m8rKZK5vNKJvNKJNJK5cLlnO5uVMmk1ZbWybcntb0dFHj45O6cmVK4+OT\nunp1ShMTwfzKlUlJGZnlJLVV5lJO7rNz94WJh8XWU6lsSyRbVhsJBAAAAAC4xpmZ2tvb1d7eri1b\nttS1T6lU0pUrVyqJhvHx8XA+obGxMV24cFZjYxOSVOnElzvwbW3BlM2mlc22KZPpUiaTqUzpdHrO\n+lLbUqlUwzvn7q7p6WlNTU1pcnKy5nxyckrj489pfPycxsenKgmJiYlgfvlykJCYmioqlcpJysks\nSEBUJyTcg/nVq+ca+nM0GwkEAAAAAMACqVRKXV1d6urqSropDWdmyuVyyuVy2rBhw4qPVyqVqpIO\nSyUk9up5z3teA36CZJBAAAAAAABgBVKpVOUOj2sZb40AAAAAAACRSCAAAAAAAIBIJBAAAAAAAEAk\nEggAAAAAACASCQQAAAAAABCJBAIAAAAAAIhEAgEAAAAAAEQigQAAAAAAACKRQAAAAAAAAJFIIAAA\nAAAAgEgkEAAAAAAAQCQSCAAAAAAAIBIJBAAAAAAAEIkEAgAAAAAAiEQCAQAAAAAARCKBAAAAAAAA\nIpFAAAAAAAAAkUggAAAAAACASCQQAAAAAABApEzSDQAArH0Dxwc0cHxAknT39Xfr4MBBSVLfDX3q\nu6GPdgEAAFwDzN2bcyIzb9a5AKxN1m/yA633OdFK7aruEA8cH6h0gukQr11mJne3pNuxXhCPAACw\nUL3xCHcgAMAaQqIAAAAASeEdCAAAAAAAIBIJBAAAAAAAEIlHGAAkipfcAQAAAGsDL1EEgEXwskI0\nCy9RbC7iEQAAFqo3HiGBAABAgkggNBfxCAAAC9Ubj/AOBAAAAAAAEIkEAgAAAAAAiEQCAQAAAAAA\nRCKBAAAAAAAAIpFAAAAAAAAAkUggAAAAAACASCQQAAAAAABAJBIIAAAAAAAgEgkEAAAAAAAQiQQC\nAAAAAACIRAIBAAAAAABEIoEAAAAAAAAikUAAAAAAAACRSCAAAAAAAIBIJBAAAAAAAEAkEggAAAAA\nACASCQQAAAAAABBpRQkEM/tdM3vKzIpmdmejGgVpYGAg6SasKVyveLhe8XC94uF6IS4z6zaz75jZ\nM2b2X2a2qUa9h8xs2MyenFd+wMxOm9kT4fS65rT82sf/53i4XvFwveLhesXD9VodK70D4bCk35L0\nWAPagir8wsfD9YqH6xUP1yserheW4UOSvuvueyR9T9KHa9R7WNJra2z7K3e/M5y+vRqNXI/4/xwP\n1yserlc8XK94uF6rY0UJBHd/xt2flWQNag8AAFh/7pX0hXD5C5LetFgld/+BpAs1jkEsAgDAKuMd\nCAAAIGl5dx+WJHcfkpRfxjHeY2aHzOyztR6BAAAAK2PuvnQFs0cl9VYXSXJJH3X3R8I635f0fnd/\nYonjLH0iAADWKXe/5r89XyKeuF/S5919S1XdUXffWuM410t6xN1vryrrkXTO3d3MPi5ph7u/q8b+\nxCMAACyinngkU8dB9jerMQAA4Nq0VDwRvhix192HzWy7pELMY49UrT4o6ZEl6hKPAACwTI18hIE/\nyAAAYDm+Ient4fLbJH19ibqmeTFHmHQo+21JTzWycQAAILDSYRzfZGanJL1c0jfN7FuNaRYAAFhH\nHpC038yekfQaSZ+QJDPbYWbfLFcysy9J+m9JN5vZSTN7R7jpk2b2pJkdknS3pD9tbvMBAFgfIt+B\nAAAAAAAA0PRRGMzsj83saTM7bGafaPb51yIze7+ZlcxsS3Tt9cvMPhn+bh0ys381s41Jt6kVmdnr\nzOx/zez/zOyDSbenlZnZLjP7npn9PPzMem/SbVoLzCxlZk+Y2TeSbkurM7NNZvYv4WfXz83sZUm3\nab0gHomPeKQ+xCP1IR6pH/HI8hCP1C9OPNLUBIKZ9Un6TUn73H2fpE818/xrkZntkrRf0omk27IG\nfEfSXne/Q9Kzkj6ccHtajpmlJH1G0msl7ZV0n5ndkmyrWtqMpD9z972S7pL0bq5XXd4n6RdJN2KN\n+LSk/3T3F0p6kaSnE27PukA8Eh/xSCzEIxGIR2IjHlke4pH61R2PNPsOhD+U9Al3n5Ekdz/X5POv\nRX8t6QNJN2ItcPfvunspXP2hpF1JtqdFvVTSs+5+wt2nJX1Z0r0Jt6llufuQux8Kly8r+DDdmWyr\nWlvYyXi9pM8m3ZZWF34r+Wp3f1iS3H3G3S8l3Kz1gngkPuKROhGP1IV4JAbikfiIR+oXNx5pdgLh\nZkm/amY/NLPvm9mvNPn8a4qZvVHSKXc/nHRb1qB3SuKlngvtlHSqav20+ANUFzO7QdIdkv4n2Za0\nvHIngxfsRNst6ZyZPRzeYvkPZtaRdKPWCeKRGIhHVoR4ZHHEI8tEPFI34pH6xYpHMo0+u5k9Kqm3\nukjBP9z94fm63f3lZvYSSV+V9IJGt2EtibheH1Fwu2D1tnVtiev1UXd/JKzzUUnT7v6lBJqIa5CZ\nbZD0NUnvCzP/WISZ/YakYXc/FN4ivu4/syJkJN0p6d3u/mMz+xtJH5J0INlmXRuIR+IhHomHeARJ\nIB6pD/FIbLHikYYnENx9f61tZvYHkv4trPej8EU8W919tNHtWCtqXS8zu03SDZJ+Zmam4Pa3n5jZ\nS9290MQmtpSlfr8kyczeruB2pV9rSoPWnjOSnl+1vissQw1mllHwx/of3X2psekhvVLSG83s9ZI6\nJF1nZl90999PuF2t6rSCb3V/HK5/TRIvEmsQ4pF4iEfiIR5ZMeKRmIhHYiEeiSdWPNLsRxj+Q+EH\nqZndLCm7nv9YL8Xdn3L37e7+AnffreAf9sXr+Y91FDN7nYJbld7o7pNJt6dF/UjSjWZ2vZnlJL1F\nEm+mXdrnJP3C3T+ddENanbt/xN2f7+4vUPC79T3+WNfm7sOSToV/DyXpNeJlT81CPFIn4pH4iEfq\nQjwSH/FInYhH4okbjzT8DoQID0v6nJkdljQpiX/I+rm4/SbK30nKSXo0+JJEP3T3P0q2Sa3F3Ytm\n9h4Fb4hOSXrI3Xnrew1m9kpJvyfpsJn9VMH/w4+4+7eTbRmuIe+V9E9mlpV0TNI7Em7PekE8snzE\nI9GIRyIQj8RDPIImqDseMXfeKwEAAAAAAJbW7EcYAAAAAADAGkQCAQAAAAAARCKBAAAAAAAAIpFA\nAAAAAAAAkUggAAAAAACASCQQAAAAAABAJBIIAAAAAAAg0v8DKqxIkSzxlWUAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def does_trend_up(ticker, event, horizon):\n", + " # Figure out if the `event` has an uptrend for\n", + " # the `horizon` days preceding it\n", + " # As an interpretation note: it is assumed that\n", + " # the closing price of day `event` is the reference\n", + " # point, and we want `horizon` days before that.\n", + " # The price_data.hdf was created in the second appendix code block\n", + " try:\n", + " ticker_data = pd.read_hdf('price_data.hdf', ticker)\n", + " data = ticker_data[event-TradeDay(horizon):event]\n", + " midpoints = data['Open']/2 + data['Close']/2\n", + "\n", + " # Shift dates one forward into the future and subtract\n", + " # Effectively: do we trend down over all days?\n", + " elems = midpoints - midpoints.shift(1)\n", + " return len(elems)-1 == len(elems.dropna()[elems >= 0])\n", + " except KeyError:\n", + " # If the stock doesn't exist, it doesn't qualify as trending down\n", + " # Mostly this is here to make sure the entire analysis doesn't \n", + " # blow up if there were issues in data retrieval\n", + " return False\n", + "\n", + "study_trend(5, does_trend_up)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The patterns here are very similar. With the exception of noting that stocks can go to nearly 400% after an earnings announcement (most likely this included a takeover announcement, etc.), we still see large min/max bars and wide standard deviation of returns.\n", + "\n", + "We'll repeat the pattern for stocks going up for both 8 and 3 days straight, but at this point, the results should be very predictable:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100% (47578 of 47578) |###########################################################| Elapsed Time: 0:20:51 Time: 0:20:51\n" + ] + }, + { + "data": { + "image/png": "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\nhBL7fpfO3h/g3V2i+3gNye1Xd2ufLPm9uRt418weBE4A3ki87h8m9iciIpJ2zBs/SkRERKRvEuM9\nvAPM1BgDIiIiAuq5ICIiIofBzM7BG9zwZwoWREREpJ16LoiIiIiIiIhIv6jngoiIiIiIiIj0i8IF\nEREREREREekXhQsiIiIiIiIi0i8KF0RERERERESkXxQuiIiIiIiIiEi/KFwQERERERERkX5RuCAi\nIiIiIiIi/aJwQURERERERET6ReGCiIiIiIiIiPSLwgURERERERER6ReFCyIiIiIiIiLSLwoXRERE\nRERERKRfFC6IiIiIiIiISL8oXBARERERERGRflG4ICIiIiIiIiL9onBBRERERERERPpF4YKIiIiI\niIiI9IvCBRERERERERHpF4ULIiIiIiIiItIvKQkXzOwCM1trZuvN7NaDtJtlZhEz+2wqjisiIiLp\n51DnHWZ2jJm9amatZvbtw3muiIiIHBlzzvVvB2YBYD1wDrAdWA7Mdc6t7aHd80ALsMg592S/Diwi\nIiJppy/nHWY2ASgFLgP2Oud+2tfnioiIyJFJRc+Fk4ENzrktzrkI8AhwaQ/tvgE8DuxMwTFFREQk\nPR3yvMM5t8s5twKIHu5zRURE5MikIlwoBrYmLdck1nUws8nAZc65XwGWgmOKiIhIejrkeccAPVdE\nREQOImOQjnMnkHxdY68Bg5n17zoNERGREco5p4B+EOhcREREpHe9nY+kIlzYBpQkLU9JrEt2EvCI\nmRkwAbjQzCLOuad6KTYFZUmqLFiwgAULFvhdhvhAn3360mc/9Hj/hAp9O+/o93N1LjL06O+l9KXP\nPn3psx96DnY+kopwYTlwtJmVAjuAucDVyQ2cc9OSirkX+EtvwYKIiIjIQRzyvKOb5LOgw32uiIiI\n9FG/wwXnXMzMbgKewxvD4R7n3Boz+7q32d3d/Sn9PaaIiIikp76cd5hZIfAmMAqIm9k/Acc55xp7\neq5PL0VERGREScmYC865JcAx3db9ppe2/5CKY8rgmTNnjt8liE/02acvffYylB3qvMM5VwdM7etz\nZXjQ30vpS599+tJnP7zYULum0MzcUKtJRETEb2amAR0Hic5FREREenaw85HBultEv5WVlbFlyxa/\ny5BDKC0tpaqqyu8yREREUk7nIoND5xIiIsPTsOm5kEhIfKhIDoc+JxGRgaGeC4NH5yL+0vssIjJ0\n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\nejFy5EhGjhzJ5MnZfTFGNm7cuKN0WLJkKW++OZvly99i27ZeQCUxVhBCJT16VFBeXkGPHhWUlpYn\n+r0cSJYLkiRJXVgmA9dcAzffDPfeCx/+cNKJJEk7CyHQt29f+vbty6GHHsqxx2b3ZzIZ1q9fz7p1\n62hoaKC+voEVK1awenUDa9c20NiYIpWqACrIZCro1q1iR/nQvftBpFIliX5f+8JyQZIkqYvauBHO\nOgveeSe7vsKgQUknkiTti1QqRWVlJZWVlX/xWoyRLVu20NDQQENDA+vWNbBq1UpWrpzPmjUNrFjx\nLnAQIVQQY7aA2D7jobw8O+uhKy0sabkgSZLUBS1YkF1f4bjj4PbbXV9BkgpNCIGePXvSs2dPDjnk\nkL94vaWlhQ0bNuwoH+rrG1i5chWrVjWwZs06GhvDjlkP69c3An07/Xtoy3JBkiSpi7n3Xjj/fPju\nd+GLX0w6jSQpCSUlJbud9dDY2Pi+WQ/tFRSdyXJBkiSpi8hk4F/+BX72s2zBsH2hMEmS2goh0KNH\nD3r06MGQIUOSjgNYLkiSJHUJGzfCOedAfX12fYXBg5NOJEnS3kslHUCSJKnYvf569i4QAwfCzJkW\nC5Kk/GO5IEmSlKD774djj4VLL4Wf/tSFGyVJ+cnLIiRJkhKQycC118KNN8Ldd8MxxySdSJKk/We5\nIEnSfqhbUkfdkjoApgyfwrS6aQDUjqildkRtYrmUH959F849F1atyq6v0EXW4pIkab+FGGPSGd4n\nhBC7WiZJ0oHR9hfyuiV1O34J76hfyMPVgXhVYfybEkIgxhiSzlEMOmMscvrp0Lcv/OQn0L17h55K\nkqQDZnfjEcsFSVLBslzQ/uiMsciGDdlyQZKkfLK78YgLOkqSJHUyiwVJUqGxXJAkSZIkSTmxXJAk\nSZIkSTlxzQVJUkHp7EUjO4trLnQexyKSJLXPBR0lScpzlgudx7GIJEntc0FHSZIkSZLUYSwXJEmS\nJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElS\nTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwX\nJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmSJElSTiwXJEmS\nJElSTiwXJEmSJElSTnIqF0IIFSGEh0MIC0MID4UQ+u7iuEtDCPNDCHNDCL8KIZTlcl51rrq6uqQj\nKCF+9sXLz15d0T6MO24OIawNIczdn/era/LnUvHysy9efvb5JdeZC1cAj8YYDwceA67c+YAQwhDg\nEmBijPEooBQ4I8fzqhP5l7p4+dkXLz97dVF7HHe0+gXw1zm8X12QP5eKl5998fKzzy+5lgunAbe2\nbt8KfGoXx5UAvUIIpUBPYFWO55UkScVnr8YdMcangIb9fb8kSdp3uZYLVTHGtQAxxjVA1c4HxBhX\nAf8GLANWAutjjI/meF5JklR89jju6OD3S5KkXQgxxt0fEMIjwMC2u4AIfAe4JcZY2ebYd2KM/Xd6\nfz/gTuDvgA3AHcDtMcZf7+J8uw8kSVKRijGGpDN0tFzHHW1eGw7c23pJ5vZ96/bm/Y5FJEnatV2N\nR0r34o3H7+q11sWSBsYY14YQBgH17Rw2FVgcY1zX+p7fAccA7ZYLxTBwkiRJ7TsA447d2av3OxaR\nJGnf5XpZxAzg3Nbtc4B72jlmGTA5hFAeQgjAJ4DXcjyvJEkqPnsz7tgutH7t7/slSdI+2ONlEbt9\ncwiVwG+BDwBLgdNjjOtDCIOBn8cYT2k97iqyd4jYCrwEfDHGuDXX8JIkqXjsw7jj10At0B9YC1wV\nY/zFrt7f+d+JJEmFJ6dyQZIkSZIkKdfLIlQkQghXhRBWhBBebP06MelM6jghhBNDCAtCCK+HEP4h\n6TzqPCGEJSGEl0MIL4UQnk86jyS15XikuDgeKV6OR/KTMxe0V1ovbXk3xnhd0lnUsUIIKeB1suuj\nrAJmAWfEGBckGkydIoSwGKiJMTYknUWSduZ4pHg4HilujkfykzMXtC9cPbs4fAh4I8a4tHVtlNuA\n0xLOpM4T8N8GSV2b45Hi4HikuDkeyUN+YNoXXw0hzAkh3BRC6Jt0GHWYQ4DlbZ6vaN2n4hCBR0II\ns0IIFyQdRpLa4XikODgeKW6OR/KQ5YJ2CCE8EkKY2+ZrXuvjqcANQDrGOB5YAzgdUSpMH40xTgRO\nAi4OIRybdCBJxcXxiCQcj+Sl0qQDqOuIMR6/l4f+HLi3I7MoUSuBYW2eD23dpyIQY1zd+vhWCOEu\nstNSn0o2laRi4nhErRyPFDHHI/nJmQvaKyGEQW2efgaYn1QWdbhZwOgQwvAQQhlwBjAj4UzqBCGE\nniGE3q3bvYAT8O+6pC7E8UhRcTxSpByP5C9nLmhv/SCEMB7IAEuALycbRx0lxtgSQvgq8DDZAvLm\nGONrCcdS5xgI3BVCiGT/ffhVjPHhhDNJUluOR4qE45Gi5ngkT3krSkmSJEmSlBMvi5AkSZIkSTmx\nXJAkSZIkSTmxXJAkSZIkSTmxXJAkSZIkSTmxXJAkSZIkSTmxXJAkSZIkSTmxXJAkSZIkSTn5XwGz\nSIQHpzdOAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "study_trend(8, does_trend_up)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100% (47578 of 47578) |###########################################################| Elapsed Time: 0:26:56 Time: 0:26:56\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "study_trend(3, does_trend_up)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion and Summary\n", + "\n", + "I guess the most important thing to summarize with is this: **looking at the entire market, stock performance prior to an earnings release has no bearing on the stock's performance.** Honestly: given the huge variability of returns after an earnings release, even when the stock has been trending for a long time, you're best off divesting before an earnings release and letting the market sort itself out.\n", + "\n", + "*However*, there is a big caveat. These results are taken when we look at the entire market. So while we can say that the market as a whole knows nothing and just reacts violently, I want to take a closer look into this data. Does the market typically perform poorly on large-cap/high liquidity stocks? Do smaller companies have investors that know them better and can thus predict performance better? Are specific market sectors better at prediction? Presumably technology stocks are more volatile than the industrials.\n", + "\n", + "So there are some more interesting questions I still want to ask with this data. Knowing that the hard work of data processing is largely already done, it should be fairly simple to continue this analysis and get much more refined with it. Until next time." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Appendix\n", + "\n", + "Export event data for Russell 3000 companies:\n", + "\n", + "```python\n", + "import pandas as pd\n", + "from html.parser import HTMLParser\n", + "from datetime import datetime, timedelta\n", + "import requests\n", + "import re\n", + "from dateutil import parser\n", + "import progressbar\n", + "from concurrent import futures\n", + "import yaml\n", + "\n", + "class EarningsParser(HTMLParser):\n", + " store_dates = False\n", + " earnings_offset = None\n", + " dates = []\n", + " \n", + " def __init__(self, *args, **kwargs):\n", + " super().__init__(*args, **kwargs)\n", + " self.dates = []\n", + " \n", + " def handle_starttag(self, tag, attrs):\n", + " if tag == 'table':\n", + " self.store_dates = True\n", + " \n", + " def handle_data(self, data):\n", + " if self.store_dates:\n", + " match = re.match(r'\\d+/\\d+/\\d+', data)\n", + " if match:\n", + " self.dates.append(match.group(0))\n", + " \n", + " # If a company reports before the bell, record the earnings date\n", + " # being at midnight the day before. Ex: WMT reports 5/19/2016,\n", + " # but we want the reference point to be the closing price on 5/18/2016\n", + " if 'After Close' in data:\n", + " self.earnings_offset = timedelta(days=0)\n", + " elif 'Before Open' in data:\n", + " self.earnings_offset = timedelta(days=-1)\n", + " \n", + " def handle_endtag(self, tag):\n", + " if tag == 'table':\n", + " self.store_dates = False\n", + " \n", + "def earnings_releases(ticker):\n", + " #print(\"Looking up ticker {}\".format(ticker))\n", + " user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) '\\\n", + " 'Gecko/20100101 Firefox/46.0'\n", + " headers = {'user-agent': user_agent}\n", + " base_url = 'http://www.streetinsider.com/ec_earnings.php?q={}'\\\n", + " .format(ticker)\n", + " e = EarningsParser()\n", + " s = requests.Session()\n", + " a = requests.adapters.HTTPAdapter(max_retries=0)\n", + " s.mount('http://', a)\n", + " e.feed(str(s.get(base_url, headers=headers).content))\n", + " \n", + " if e.earnings_offset is not None:\n", + " dates = map(lambda x: parser.parse(x) + e.earnings_offset, e.dates)\n", + " past = filter(lambda x: x < datetime.now(), dates)\n", + " return list(map(lambda d: d.isoformat(), past))\n", + "\n", + "# Use a Russell-3000 ETF tracker (ticker IWV) to get a list of holdings\n", + "r3000 = pd.read_csv('https://www.ishares.com/us/products/239714/'\n", + " 'ishares-russell-3000-etf/1449138789749.ajax?'\n", + " 'fileType=csv&fileName=IWV_holdings&dataType=fund',\n", + " header=10)\n", + "r3000_equities = r3000[(r3000['Exchange'] == 'NASDAQ') |\n", + " (r3000['Exchange'] == 'New York Stock Exchange Inc.')]\n", + "\n", + "dates_file = open('earnings_dates.yaml', 'w')\n", + "\n", + "with futures.ThreadPoolExecutor(max_workers=8) as pool:\n", + " fs = {pool.submit(earnings_releases, r3000_equities.ix[t]['Ticker']): t\n", + " for t in r3000_equities.index}\n", + " pbar = progressbar.ProgressBar(term_width=80,\n", + " max_value=r3000_equities.index.max())\n", + " \n", + " for future in futures.as_completed(fs):\n", + " i = fs[future]\n", + " pbar.update(i)\n", + " dates_file.write(yaml.dump({r3000_equities.ix[i]['Ticker']:\n", + " future.result()}))\n", + "```\n", + "\n", + "Downloading stock price data needed for the event studies:\n", + "\n", + "```python\n", + "from secrets import QUANDL_KEY\n", + "import pandas as pd\n", + "import yaml\n", + "from dateutil.parser import parse\n", + "from datetime import timedelta\n", + "import quandl\n", + "from progressbar import ProgressBar\n", + "\n", + "def fetch_ticker(ticker, start, end):\n", + " # Quandl is currently giving me issues with returning\n", + " # the entire dataset and not slicing server-side.\n", + " # So instead, we'll do it client-side!\n", + " q_format = '%Y-%m-%d'\n", + " ticker_data = quandl.get('YAHOO/' + ticker,\n", + " start_date=start.strftime(q_format),\n", + " end_date=end.strftime(q_format),\n", + " authtoken=QUANDL_KEY)\n", + " return ticker_data\n", + " \n", + "data_str = open('earnings_dates.yaml', 'r').read()\n", + "# Need to remove invalid lines\n", + "filtered = filter(lambda x: '{' not in x, data_str.split('\\n'))\n", + "earnings_data = yaml.load('\\n'.join(filtered))\n", + "\n", + "# Get the first 1500 keys - split up into two statements\n", + "# because of Quandl rate limits\n", + "tickers = list(earnings_data.keys())\n", + "\n", + "price_dict = {}\n", + "invalid_tickers = []\n", + "for ticker in ProgressBar()(tickers[0:1500]):\n", + " try:\n", + " # Replace '.' with '-' in name for some tickers\n", + " fixed = ticker.replace('.', '-')\n", + " event_strs = earnings_data[ticker]\n", + " events = [parse(event) for event in event_strs]\n", + " td = timedelta(days=20)\n", + " price_dict[ticker] = fetch_ticker(fixed,\n", + " min(events)-td, max(events)+td)\n", + " except quandl.NotFoundError:\n", + " invalid_tickers.append(ticker)\n", + " \n", + "# Execute this after 10 minutes have passed\n", + "for ticker in ProgressBar()(tickers[1500:]):\n", + " try:\n", + " # Replace '.' with '-' in name for some tickers\n", + " fixed = ticker.replace('.', '-')\n", + " event_strs = earnings_data[ticker]\n", + " events = [parse(event) for event in event_strs]\n", + " td = timedelta(days=20)\n", + " price_dict[ticker] = fetch_ticker(fixed,\n", + " min(events)-td, max(events)+td)\n", + " except quandl.NotFoundError:\n", + " invalid_tickers.append(ticker)\n", + " \n", + "prices_store = pd.HDFStore('price_data.hdf')\n", + "for ticker, prices in price_dict.items():\n", + " prices_store[ticker] = prices\n", + "```" + ] + } + ], + "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.4.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook.md b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook.md new file mode 100644 index 0000000..74ae63a --- /dev/null +++ b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook.md @@ -0,0 +1,724 @@ +Or, being suspicious of market insiders. + +--- + +Use the button below to show the code I've used to generate this article. Because there is a significant amount more code involved than most other posts I've written, it's hidden by default to allow people to concentrate on the important bits. + + +```python +from IPython.display import HTML + +HTML(''' +
''') +``` + + + + + +
+ + + +# The Market Just Knew + +I recently saw two examples of stock charts that have kept me thinking for a while. And now that the semester is complete, I finally have enough time to really look at them and give them the treatment they deserve. The first is good old Apple: + + +```python +from secrets import QUANDL_KEY +import matplotlib.pyplot as plt +from matplotlib.dates import date2num +from matplotlib.finance import candlestick_ohlc +from matplotlib.dates import DateFormatter, WeekdayLocator,\ + DayLocator, MONDAY +import quandl +from datetime import datetime +import pandas as pd +%matplotlib inline + +def fetch_ticker(ticker, start, end): + # Quandl is currently giving me issues with returning + # the entire dataset and not slicing server-side. + # So instead, we'll do it client-side! + q_format = '%Y-%m-%d' + ticker_data = quandl.get('YAHOO/' + ticker, + start_date=start.strftime(q_format), + end_date=end.strftime(q_format), + authtoken=QUANDL_KEY) + return ticker_data + +def ohlc_dataframe(data, ax=None): + # Much of this code re-used from: + # http://matplotlib.org/examples/pylab_examples/finance_demo.html + if ax is None: + f, ax = plt.subplots() + + vals = [(date2num(date), *(data.loc[date])) + for date in data.index] + candlestick_ohlc(ax, vals) + + mondays = WeekdayLocator(MONDAY) + alldays = DayLocator() + weekFormatter = DateFormatter('%b %d') + ax.xaxis.set_major_locator(mondays) + ax.xaxis.set_minor_locator(alldays) + ax.xaxis.set_major_formatter(weekFormatter) + return ax + +AAPL = fetch_ticker('AAPL', datetime(2016, 3, 1), datetime(2016, 5, 1)) +ax = ohlc_dataframe(AAPL) +plt.vlines(date2num(datetime(2016, 4, 26, 12)), + ax.get_ylim()[0], ax.get_ylim()[1], + color='b', + label='Earnings Release') +plt.legend(loc=3) +plt.title("Apple Price 3/1/2016 - 5/1/2016"); +``` + + + +![png](_notebook_files/_notebook_3_0.png) + + + +The second chart is from Facebook: + + +```python +FB = fetch_ticker('FB', datetime(2016, 3, 1), datetime(2016, 5, 5)) +ax = ohlc_dataframe(FB) +plt.vlines(date2num(datetime(2016, 4, 27, 12)), + ax.get_ylim()[0], ax.get_ylim()[1], + color='b', label='Earnings Release') +plt.title('Facebook Price 3/5/2016 - 5/5/2016') +plt.legend(loc=2); +``` + + + +![png](_notebook_files/_notebook_5_0.png) + + + +These two charts demonstrate two very specific phonomena: how the market prepares for earnings releases. Let's look at those charts again, but with some extra information. As we're about the see, the market "knew" in advance that Apple was going to perform poorly. The market expected that Facebook was going to perform poorly, and instead shot the lights out. Let's see that trend in action: + + +```python +def plot_hilo(ax, start, end, data): + ax.plot([date2num(start), date2num(end)], + [data.loc[start]['High'], data.loc[end]['High']], + color='b') + ax.plot([date2num(start), date2num(end)], + [data.loc[start]['Low'], data.loc[end]['Low']], + color='b') + +f, axarr = plt.subplots(1, 2) + +ax_aapl = axarr[0] +ax_fb = axarr[1] + +# Plot the AAPL trend up and down +ohlc_dataframe(AAPL, ax=ax_aapl) +plot_hilo(ax_aapl, datetime(2016, 3, 1), datetime(2016, 4, 15), AAPL) +plot_hilo(ax_aapl, datetime(2016, 4, 18), datetime(2016, 4, 26), AAPL) +ax_aapl.vlines(date2num(datetime(2016, 4, 26, 12)), + ax_aapl.get_ylim()[0], ax_aapl.get_ylim()[1], + color='g', label='Earnings Release') +ax_aapl.legend(loc=2) +ax_aapl.set_title('AAPL Price History') + +# Plot the FB trend down and up +ohlc_dataframe(FB, ax=ax_fb) +plot_hilo(ax_fb, datetime(2016, 3, 30), datetime(2016, 4, 27), FB) +plot_hilo(ax_fb, datetime(2016, 4, 28), datetime(2016, 5, 5), FB) +ax_fb.vlines(date2num(datetime(2016, 4, 27, 12)), + ax_fb.get_ylim()[0], ax_fb.get_ylim()[1], + color='g', label='Earnings Release') +ax_fb.legend(loc=2) +ax_fb.set_title('FB Price History') + +f.set_size_inches(18, 6) +``` + + + +![png](_notebook_files/_notebook_7_0.png) + + + +As we can see above, the market broke a prevailing trend on Apple in order to go down, and ultimately predict the earnings release. For Facebook, the opposite happened. While the trend was down, the earnings were fantastic and the market corrected itself much higher. + +# Formulating the Question + +While these are two specific examples, there are plenty of other examples you could cite one way or another. Even if the preponderance of evidence shows that the market correctly predicts earnings releases, we need not accuse people of collusion; for a company like Apple with many suppliers we can generally forecast how Apple has done based on those same suppliers. + +The question then, is this: **how well does the market predict the earnings releases?** It's an incredibly broad question that I want to disect in a couple of different ways: + +1. Given a stock that has been trending down over the past N days before an earnings release, how likely does it continue downward after the release? +2. Given a stock trending up, how likely does it continue up? +3. Is there a difference in accuracy between large- and small-cap stocks? +4. How often, and for how long, do markets trend before an earnings release? + +**I want to especially thank Alejandro Saltiel for helping me retrieve the data.** He's great. And now for all of the interesting bits. + +# Event Studies + +Before we go too much further, I want to introduce the actual event study. Each chart intends to capture a lot of information and present an easy-to-understand pattern: + + +```python +import numpy as np +import pandas as pd +from pandas.tseries.holiday import USFederalHolidayCalendar +from pandas.tseries.offsets import CustomBusinessDay +from datetime import datetime, timedelta + +# If you remove rules, it removes them from *all* calendars +# To ensure we don't pop rules we don't want to, first make +# sure to fully copy the object +trade_calendar = USFederalHolidayCalendar() +trade_calendar.rules.pop(6) # Remove Columbus day +trade_calendar.rules.pop(7) # Remove Veteran's day +TradeDay = lambda days: CustomBusinessDay(days, calendar=trade_calendar) + +def plot_study(array): + # Given a 2-d array, we assume the event happens at index `lookback`, + # and create all of our summary statistics from there. + lookback = int((array.shape[1] - 1) / 2) + norm_factor = np.repeat(array[:,lookback].reshape(-1, 1), array.shape[1], axis=1) + centered_data = array / norm_factor - 1 + lookforward = centered_data.shape[1] - lookback + means = centered_data.mean(axis=0) + lookforward_data = centered_data[:,lookforward:] + std_dev = np.hstack([0, lookforward_data.std(axis=0)]) + maxes = lookforward_data.max(axis=0) + mins = lookforward_data.min(axis=0) + + f, axarr = plt.subplots(1, 2) + range_begin = -lookback + range_end = lookforward + axarr[0].plot(range(range_begin, range_end), means) + axarr[1].plot(range(range_begin, range_end), means) + axarr[0].fill_between(range(0, range_end), + means[-lookforward:] + std_dev, + means[-lookforward:] - std_dev, + alpha=.5, label="$\pm$ 1 s.d.") + axarr[1].fill_between(range(0, range_end), + means[-lookforward:] + std_dev, + means[-lookforward:] - std_dev, + alpha=.5, label="$\pm$ 1 s.d.") + + max_err = maxes - means[-lookforward+1:] + min_err = means[-lookforward+1:] - mins + axarr[0].errorbar(range(1, range_end), + means[-lookforward+1:], + yerr=[min_err, max_err], label='Max & Min') + axarr[0].legend(loc=2) + axarr[1].legend(loc=2) + + axarr[0].set_xlim((-lookback-1, lookback+1)) + axarr[1].set_xlim((-lookback-1, lookback+1)) + +def plot_study_small(array): + # Given a 2-d array, we assume the event happens at index `lookback`, + # and create all of our summary statistics from there. + lookback = int((array.shape[1] - 1) / 2) + norm_factor = np.repeat(array[:,lookback].reshape(-1, 1), array.shape[1], axis=1) + centered_data = array / norm_factor - 1 + lookforward = centered_data.shape[1] - lookback + means = centered_data.mean(axis=0) + lookforward_data = centered_data[:,lookforward:] + std_dev = np.hstack([0, lookforward_data.std(axis=0)]) + maxes = lookforward_data.max(axis=0) + mins = lookforward_data.min(axis=0) + + range_begin = -lookback + range_end = lookforward + plt.plot(range(range_begin, range_end), means) + plt.fill_between(range(0, range_end), + means[-lookforward:] + std_dev, + means[-lookforward:] - std_dev, + alpha=.5, label="$\pm$ 1 s.d.") + + max_err = maxes - means[-lookforward+1:] + min_err = means[-lookforward+1:] - mins + plt.errorbar(range(1, range_end), + means[-lookforward+1:], + yerr=[min_err, max_err], label='Max & Min') + plt.legend(loc=2) + plt.xlim((-lookback-1, lookback+1)) + +def fetch_event_data(ticker, events, horizon=5): + # Use horizon+1 to account for including the day of the event, + # and half-open interval - that is, for a horizon of 5, + # we should be including 11 events. Additionally, using the + # CustomBusinessDay means we automatically handle issues if + # for example a company reports Friday afternoon - the date + # calculator will turn this into a "Saturday" release, but + # we effectively shift that to Monday with the logic below. + td_back = TradeDay(horizon+1) + td_forward = TradeDay(horizon+1) + + start_date = min(events) - td_back + end_date = max(events) + td_forward + total_data = fetch_ticker(ticker, start_date, end_date) + event_data = [total_data.ix[event-td_back:event+td_forward]\ + [0:horizon*2+1]\ + ['Adjusted Close'] + for event in events] + return np.array(event_data) + +# Generate a couple of random events + +event_dates = [datetime(2016, 5, 27) - timedelta(days=1) - TradeDay(x*20) for x in range(1, 40)] +data = fetch_event_data('CELG', event_dates) +plot_study_small(data) +plt.legend(loc=3) +plt.gcf().set_size_inches(12, 6); + + +plt.annotate('Mean price for days leading up to each event', + (-5, -.01), (-4.5, .025), + arrowprops=dict(facecolor='black', shrink=0.05)) +plt.annotate('', (-.1, .005), (-.5, .02), + arrowprops={'facecolor': 'black', 'shrink': .05}) +plt.annotate('$\pm$ 1 std. dev. each day', (5, .055), (2.5, .085), + arrowprops={'facecolor': 'black', 'shrink': .05}) +plt.annotate('Min/Max each day', (.9, -.07), (-1, -.1), + arrowprops={'facecolor': 'black', 'shrink': .05}); +``` + + + +![png](_notebook_files/_notebook_11_0.png) + + + +And as a quick textual explanation as well: + +- The blue line represents the mean price for each day, represented as a percentage of the price on the '0-day'. For example, if we defined an 'event' as whenever the stock price dropped for three days, we would see a decreasing blue line to the left of the 0-day. + +- The blue shaded area represents one standard deviation above and below the mean price for each day following an event. This is intended to give us an idea of what the stock price does in general following an event. + +- The green bars are the minimum and maximum price for each day following an event. This instructs us as to how much it's possible for the stock to move. + +# Event Type 1: Trending down over the past N days + +The first type of event I want to study is how stocks perform when they've been trending down over the past couple of days prior to a release. However, we need to clarify what exactly is meant by "trending down." To do so, we'll use the following metric: **the midpoint between each day's opening and closing price goes down over a period of N days**. + +It's probably helpful to have an example: + + +```python +f, axarr = plt.subplots(1, 2) +f.set_size_inches(18, 6) + +FB_plot = axarr[0] +ohlc_dataframe(FB[datetime(2016, 4, 18):], FB_plot) + +FB_truncated = FB[datetime(2016, 4, 18):datetime(2016, 4, 27)] +midpoint = FB_truncated['Open']/2 + FB_truncated['Close']/2 +FB_plot.plot(FB_truncated.index, midpoint, label='Midpoint') +FB_plot.vlines(date2num(datetime(2016, 4, 27, 12)), + ax_fb.get_ylim()[0], ax_fb.get_ylim()[1], + color='g', label='Earnings Release') +FB_plot.legend(loc=2) +FB_plot.set_title('FB Midpoint Plot') + +AAPL_plot = axarr[1] +ohlc_dataframe(AAPL[datetime(2016, 4, 10):], AAPL_plot) +AAPL_truncated = AAPL[datetime(2016, 4, 10):datetime(2016, 4, 26)] +midpoint = AAPL_truncated['Open']/2 + AAPL_truncated['Close']/2 +AAPL_plot.plot(AAPL_truncated.index, midpoint, label='Midpoint') +AAPL_plot.vlines(date2num(datetime(2016, 4, 26, 12)), + ax_aapl.get_ylim()[0], ax_aapl.get_ylim()[1], + color='g', label='Earnings Release') +AAPL_plot.legend(loc=3) +AAPL_plot.set_title('AAPL Midpoint Plot'); +``` + + + +![png](_notebook_files/_notebook_14_0.png) + + + +Given these charts, we can see that FB was trending down for the four days preceding the earnings release, and AAPL was trending down for a whopping 8 days (we don't count the peak day). This will define the methodology that we will use for the study. + +So what are the results? For a given horizon, how well does the market actually perform? + + +```python +# Read in the events for each stock; +# The file was created using the first code block in the Appendix +import yaml +from dateutil.parser import parse +from progressbar import ProgressBar + +data_str = open('earnings_dates.yaml', 'r').read() +# Need to remove invalid lines +filtered = filter(lambda x: '{' not in x, data_str.split('\n')) +earnings_data = yaml.load('\n'.join(filtered)) + +# Convert our earnings data into a list of (ticker, date) pairs +# to make it easy to work with. +# This is horribly inefficient, but should get us what we need +ticker_dates = [] +for ticker, date_list in earnings_data.items(): + for iso_str in date_list: + ticker_dates.append((ticker, parse(iso_str))) + +def does_trend_down(ticker, event, horizon): + # Figure out if the `event` has a downtrend for + # the `horizon` days preceding it + # As an interpretation note: it is assumed that + # the closing price of day `event` is the reference + # point, and we want `horizon` days before that. + # The price_data.hdf was created in the second appendix code block + try: + ticker_data = pd.read_hdf('price_data.hdf', ticker) + data = ticker_data[event-TradeDay(horizon):event] + midpoints = data['Open']/2 + data['Close']/2 + + # Shift dates one forward into the future and subtract + # Effectively: do we trend down over all days? + elems = midpoints - midpoints.shift(1) + return len(elems)-1 == len(elems.dropna()[elems <= 0]) + except KeyError: + # If the stock doesn't exist, it doesn't qualify as trending down + # Mostly this is here to make sure the entire analysis doesn't + # blow up if there were issues in data retrieval + return False + +def study_trend(horizon, trend_function): + five_day_events = np.zeros((1, horizon*2 + 1)) + invalid_events = [] + for ticker, event in ProgressBar()(ticker_dates): + if trend_function(ticker, event, horizon): + ticker_data = pd.read_hdf('price_data.hdf', ticker) + event_data = ticker_data[event-TradeDay(horizon):event+TradeDay(horizon)]['Close'] + + try: + five_day_events = np.vstack([five_day_events, event_data]) + except ValueError: + # Sometimes we don't get exactly the right number of values due to calendar + # issues. I've fixed most everything I can, and the few issues that are left + # I assume don't systemically bias the results (i.e. data could be missing + # because it doesn't exist, etc.). After running through, ~1% of events get + # discarded this way + invalid_events.append((ticker, event)) + + + # Remove our initial zero row + five_day_events = five_day_events[1:,:] + plot_study(five_day_events) + plt.gcf().suptitle('Action over {} days: {} events' + .format(horizon,five_day_events.shape[0])) + plt.gcf().set_size_inches(18, 6) + +# Start with a 5 day study +study_trend(5, does_trend_down) +``` + + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:21:38 Time: 0:21:38 + + + + +![png](_notebook_files/_notebook_16_1.png) + + + +When a stock has been trending down for 5 days, once the earnings are announced it really doesn't move on average. However, the variability is *incredible*. This implies two important things: + +1. The market is just as often wrong about an earnings announcement before it happens as it is correct +2. The incredible width of the min/max bars and standard deviation area tell us that the market reacts *violently* after the earnings are released. + +Let's repeat the same study, but over a time horizon of 8 days and 3 days. Presumably if a stock has been going down for 8 days at a time before the earnings, the market should be more accurate. + + +```python +# 8 day study next +study_trend(8, does_trend_down) +``` + + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:20:29 Time: 0:20:29 + + + + +![png](_notebook_files/_notebook_18_1.png) + + + +However, looking only at stocks that trended down for 8 days prior to a release, the same pattern emerges: on average, the stock doesn't move, but the market reaction is often incredibly violent. + + +```python +# 3 day study after that +study_trend(3, does_trend_down) +``` + + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:26:26 Time: 0:26:26 + + + + +![png](_notebook_files/_notebook_20_1.png) + + + +Finally, when we look at a 3-day horizon, we start getting some incredible outliers. Stocks have a potential to move over ~300% up, and the standard deviation width is again, incredible. The results for a 3-day horizon follow the same pattern we've seen in the 5- and 8-day horizons. + +# Event Type 2: Trending up for N days + +We're now going to repeat the analysis, but do it for uptrends instead. That is, instead of looking at stocks that have been trending down over the past number of days, we focus only on stocks that have been trending up. + + +```python +def does_trend_up(ticker, event, horizon): + # Figure out if the `event` has an uptrend for + # the `horizon` days preceding it + # As an interpretation note: it is assumed that + # the closing price of day `event` is the reference + # point, and we want `horizon` days before that. + # The price_data.hdf was created in the second appendix code block + try: + ticker_data = pd.read_hdf('price_data.hdf', ticker) + data = ticker_data[event-TradeDay(horizon):event] + midpoints = data['Open']/2 + data['Close']/2 + + # Shift dates one forward into the future and subtract + # Effectively: do we trend down over all days? + elems = midpoints - midpoints.shift(1) + return len(elems)-1 == len(elems.dropna()[elems >= 0]) + except KeyError: + # If the stock doesn't exist, it doesn't qualify as trending down + # Mostly this is here to make sure the entire analysis doesn't + # blow up if there were issues in data retrieval + return False + +study_trend(5, does_trend_up) +``` + + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:22:51 Time: 0:22:51 + + + + +![png](_notebook_files/_notebook_23_1.png) + + + +The patterns here are very similar. With the exception of noting that stocks can go to nearly 400% after an earnings announcement (most likely this included a takeover announcement, etc.), we still see large min/max bars and wide standard deviation of returns. + +We'll repeat the pattern for stocks going up for both 8 and 3 days straight, but at this point, the results should be very predictable: + + +```python +study_trend(8, does_trend_up) +``` + + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:20:51 Time: 0:20:51 + + + + +![png](_notebook_files/_notebook_25_1.png) + + + + +```python +study_trend(3, does_trend_up) +``` + + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:26:56 Time: 0:26:56 + + + + +![png](_notebook_files/_notebook_26_1.png) + + + +# Conclusion and Summary + +I guess the most important thing to summarize with is this: **looking at the entire market, stock performance prior to an earnings release has no bearing on the stock's performance.** Honestly: given the huge variability of returns after an earnings release, even when the stock has been trending for a long time, you're best off divesting before an earnings release and letting the market sort itself out. + +*However*, there is a big caveat. These results are taken when we look at the entire market. So while we can say that the market as a whole knows nothing and just reacts violently, I want to take a closer look into this data. Does the market typically perform poorly on large-cap/high liquidity stocks? Do smaller companies have investors that know them better and can thus predict performance better? Are specific market sectors better at prediction? Presumably technology stocks are more volatile than the industrials. + +So there are some more interesting questions I still want to ask with this data. Knowing that the hard work of data processing is largely already done, it should be fairly simple to continue this analysis and get much more refined with it. Until next time. + +# Appendix + +Export event data for Russell 3000 companies: + +```python +import pandas as pd +from html.parser import HTMLParser +from datetime import datetime, timedelta +import requests +import re +from dateutil import parser +import progressbar +from concurrent import futures +import yaml + +class EarningsParser(HTMLParser): + store_dates = False + earnings_offset = None + dates = [] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.dates = [] + + def handle_starttag(self, tag, attrs): + if tag == 'table': + self.store_dates = True + + def handle_data(self, data): + if self.store_dates: + match = re.match(r'\d+/\d+/\d+', data) + if match: + self.dates.append(match.group(0)) + + # If a company reports before the bell, record the earnings date + # being at midnight the day before. Ex: WMT reports 5/19/2016, + # but we want the reference point to be the closing price on 5/18/2016 + if 'After Close' in data: + self.earnings_offset = timedelta(days=0) + elif 'Before Open' in data: + self.earnings_offset = timedelta(days=-1) + + def handle_endtag(self, tag): + if tag == 'table': + self.store_dates = False + +def earnings_releases(ticker): + #print("Looking up ticker {}".format(ticker)) + user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) '\ + 'Gecko/20100101 Firefox/46.0' + headers = {'user-agent': user_agent} + base_url = 'http://www.streetinsider.com/ec_earnings.php?q={}'\ + .format(ticker) + e = EarningsParser() + s = requests.Session() + a = requests.adapters.HTTPAdapter(max_retries=0) + s.mount('http://', a) + e.feed(str(s.get(base_url, headers=headers).content)) + + if e.earnings_offset is not None: + dates = map(lambda x: parser.parse(x) + e.earnings_offset, e.dates) + past = filter(lambda x: x < datetime.now(), dates) + return list(map(lambda d: d.isoformat(), past)) + +# Use a Russell-3000 ETF tracker (ticker IWV) to get a list of holdings +r3000 = pd.read_csv('https://www.ishares.com/us/products/239714/' + 'ishares-russell-3000-etf/1449138789749.ajax?' + 'fileType=csv&fileName=IWV_holdings&dataType=fund', + header=10) +r3000_equities = r3000[(r3000['Exchange'] == 'NASDAQ') | + (r3000['Exchange'] == 'New York Stock Exchange Inc.')] + +dates_file = open('earnings_dates.yaml', 'w') + +with futures.ThreadPoolExecutor(max_workers=8) as pool: + fs = {pool.submit(earnings_releases, r3000_equities.ix[t]['Ticker']): t + for t in r3000_equities.index} + pbar = progressbar.ProgressBar(term_width=80, + max_value=r3000_equities.index.max()) + + for future in futures.as_completed(fs): + i = fs[future] + pbar.update(i) + dates_file.write(yaml.dump({r3000_equities.ix[i]['Ticker']: + future.result()})) +``` + +Downloading stock price data needed for the event studies: + +```python +from secrets import QUANDL_KEY +import pandas as pd +import yaml +from dateutil.parser import parse +from datetime import timedelta +import quandl +from progressbar import ProgressBar + +def fetch_ticker(ticker, start, end): + # Quandl is currently giving me issues with returning + # the entire dataset and not slicing server-side. + # So instead, we'll do it client-side! + q_format = '%Y-%m-%d' + ticker_data = quandl.get('YAHOO/' + ticker, + start_date=start.strftime(q_format), + end_date=end.strftime(q_format), + authtoken=QUANDL_KEY) + return ticker_data + +data_str = open('earnings_dates.yaml', 'r').read() +# Need to remove invalid lines +filtered = filter(lambda x: '{' not in x, data_str.split('\n')) +earnings_data = yaml.load('\n'.join(filtered)) + +# Get the first 1500 keys - split up into two statements +# because of Quandl rate limits +tickers = list(earnings_data.keys()) + +price_dict = {} +invalid_tickers = [] +for ticker in ProgressBar()(tickers[0:1500]): + try: + # Replace '.' with '-' in name for some tickers + fixed = ticker.replace('.', '-') + event_strs = earnings_data[ticker] + events = [parse(event) for event in event_strs] + td = timedelta(days=20) + price_dict[ticker] = fetch_ticker(fixed, + min(events)-td, max(events)+td) + except quandl.NotFoundError: + invalid_tickers.append(ticker) + +# Execute this after 10 minutes have passed +for ticker in ProgressBar()(tickers[1500:]): + try: + # Replace '.' with '-' in name for some tickers + fixed = ticker.replace('.', '-') + event_strs = earnings_data[ticker] + events = [parse(event) for event in event_strs] + td = timedelta(days=20) + price_dict[ticker] = fetch_ticker(fixed, + min(events)-td, max(events)+td) + except quandl.NotFoundError: + invalid_tickers.append(ticker) + +prices_store = pd.HDFStore('price_data.hdf') +for ticker, prices in price_dict.items(): + prices_store[ticker] = prices +``` diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_11_0.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_11_0.png new file mode 100644 index 0000000..a57bfcc Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_11_0.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_14_0.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_14_0.png new file mode 100644 index 0000000..9cb3892 Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_14_0.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_16_1.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_16_1.png new file mode 100644 index 0000000..2a5f796 Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_16_1.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_18_1.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_18_1.png new file mode 100644 index 0000000..7ab528a Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_18_1.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_20_1.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_20_1.png new file mode 100644 index 0000000..10ba689 Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_20_1.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_23_1.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_23_1.png new file mode 100644 index 0000000..4432ff1 Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_23_1.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_25_1.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_25_1.png new file mode 100644 index 0000000..943f619 Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_25_1.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_26_1.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_26_1.png new file mode 100644 index 0000000..5ec4434 Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_26_1.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_3_0.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_3_0.png new file mode 100644 index 0000000..d860f2f Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_3_0.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_5_0.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_5_0.png new file mode 100644 index 0000000..eef8ebc Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_5_0.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_7_0.png b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_7_0.png new file mode 100644 index 0000000..1d00856 Binary files /dev/null and b/blog/2016-06-08-event-studies-and-earnings-releases/_notebook_files/_notebook_7_0.png differ diff --git a/blog/2016-06-08-event-studies-and-earnings-releases/index.mdx b/blog/2016-06-08-event-studies-and-earnings-releases/index.mdx new file mode 100644 index 0000000..42417ee --- /dev/null +++ b/blog/2016-06-08-event-studies-and-earnings-releases/index.mdx @@ -0,0 +1,692 @@ +--- +slug: 2016/06/event-studies-and-earnings-releases +title: Event studies and earnings releases +date: 2016-06-08 12:00:00 +authors: [bspeice] +tags: [] +--- + +Or, being suspicious of market insiders. + + + +## The Market Just Knew + +I recently saw two examples of stock charts that have kept me thinking for a while. And now that the semester is complete, I finally have enough time to really look at them and give them the treatment they deserve. The first is good old Apple: + + +
+Code + +```python +from secrets import QUANDL_KEY +import matplotlib.pyplot as plt +from matplotlib.dates import date2num +from matplotlib.finance import candlestick_ohlc +from matplotlib.dates import DateFormatter, WeekdayLocator,\ + DayLocator, MONDAY +import quandl +from datetime import datetime +import pandas as pd +%matplotlib inline + +def fetch_ticker(ticker, start, end): + # Quandl is currently giving me issues with returning + # the entire dataset and not slicing server-side. + # So instead, we'll do it client-side! + q_format = '%Y-%m-%d' + ticker_data = quandl.get('YAHOO/' + ticker, + start_date=start.strftime(q_format), + end_date=end.strftime(q_format), + authtoken=QUANDL_KEY) + return ticker_data + +def ohlc_dataframe(data, ax=None): + # Much of this code re-used from: + # http://matplotlib.org/examples/pylab_examples/finance_demo.html + if ax is None: + f, ax = plt.subplots() + + vals = [(date2num(date), *(data.loc[date])) + for date in data.index] + candlestick_ohlc(ax, vals) + + mondays = WeekdayLocator(MONDAY) + alldays = DayLocator() + weekFormatter = DateFormatter('%b %d') + ax.xaxis.set_major_locator(mondays) + ax.xaxis.set_minor_locator(alldays) + ax.xaxis.set_major_formatter(weekFormatter) + return ax +``` +
+ +```python +AAPL = fetch_ticker('AAPL', datetime(2016, 3, 1), datetime(2016, 5, 1)) +ax = ohlc_dataframe(AAPL) +plt.vlines(date2num(datetime(2016, 4, 26, 12)), + ax.get_ylim()[0], ax.get_ylim()[1], + color='b', + label='Earnings Release') +plt.legend(loc=3) +plt.title("Apple Price 3/1/2016 - 5/1/2016"); +``` + +![png](_notebook_files/_notebook_3_0.png) + +The second chart is from Facebook: + +```python +FB = fetch_ticker('FB', datetime(2016, 3, 1), datetime(2016, 5, 5)) +ax = ohlc_dataframe(FB) +plt.vlines(date2num(datetime(2016, 4, 27, 12)), + ax.get_ylim()[0], ax.get_ylim()[1], + color='b', label='Earnings Release') +plt.title('Facebook Price 3/5/2016 - 5/5/2016') +plt.legend(loc=2); +``` + +![png](_notebook_files/_notebook_5_0.png) + +These two charts demonstrate two very specific phonomena: how the market prepares for earnings releases. Let's look at those charts again, but with some extra information. As we're about the see, the market "knew" in advance that Apple was going to perform poorly. The market expected that Facebook was going to perform poorly, and instead shot the lights out. Let's see that trend in action: + +
+Code + +```python +def plot_hilo(ax, start, end, data): + ax.plot([date2num(start), date2num(end)], + [data.loc[start]['High'], data.loc[end]['High']], + color='b') + ax.plot([date2num(start), date2num(end)], + [data.loc[start]['Low'], data.loc[end]['Low']], + color='b') + +f, axarr = plt.subplots(1, 2) + +ax_aapl = axarr[0] +ax_fb = axarr[1] + +# Plot the AAPL trend up and down +ohlc_dataframe(AAPL, ax=ax_aapl) +plot_hilo(ax_aapl, datetime(2016, 3, 1), datetime(2016, 4, 15), AAPL) +plot_hilo(ax_aapl, datetime(2016, 4, 18), datetime(2016, 4, 26), AAPL) +ax_aapl.vlines(date2num(datetime(2016, 4, 26, 12)), + ax_aapl.get_ylim()[0], ax_aapl.get_ylim()[1], + color='g', label='Earnings Release') +ax_aapl.legend(loc=2) +ax_aapl.set_title('AAPL Price History') + +# Plot the FB trend down and up +ohlc_dataframe(FB, ax=ax_fb) +plot_hilo(ax_fb, datetime(2016, 3, 30), datetime(2016, 4, 27), FB) +plot_hilo(ax_fb, datetime(2016, 4, 28), datetime(2016, 5, 5), FB) +ax_fb.vlines(date2num(datetime(2016, 4, 27, 12)), + ax_fb.get_ylim()[0], ax_fb.get_ylim()[1], + color='g', label='Earnings Release') +ax_fb.legend(loc=2) +ax_fb.set_title('FB Price History') + +f.set_size_inches(18, 6) +``` +
+ +![png](_notebook_files/_notebook_7_0.png) + +As we can see above, the market broke a prevailing trend on Apple in order to go down, and ultimately predict the earnings release. For Facebook, the opposite happened. While the trend was down, the earnings were fantastic and the market corrected itself much higher. + +## Formulating the Question + +While these are two specific examples, there are plenty of other examples you could cite one way or another. Even if the preponderance of evidence shows that the market correctly predicts earnings releases, we need not accuse people of collusion; for a company like Apple with many suppliers we can generally forecast how Apple has done based on those same suppliers. + +The question then, is this: **how well does the market predict the earnings releases?** It's an incredibly broad question that I want to disect in a couple of different ways: + +1. Given a stock that has been trending down over the past N days before an earnings release, how likely does it continue downward after the release? +2. Given a stock trending up, how likely does it continue up? +3. Is there a difference in accuracy between large- and small-cap stocks? +4. How often, and for how long, do markets trend before an earnings release? + +**I want to especially thank Alejandro Saltiel for helping me retrieve the data.** He's great. And now for all of the interesting bits. + +## Event Studies + +Before we go too much further, I want to introduce the actual event study. Each chart intends to capture a lot of information and present an easy-to-understand pattern: + +
+Code + +```python +import numpy as np +import pandas as pd +from pandas.tseries.holiday import USFederalHolidayCalendar +from pandas.tseries.offsets import CustomBusinessDay +from datetime import datetime, timedelta + +# If you remove rules, it removes them from *all* calendars +# To ensure we don't pop rules we don't want to, first make +# sure to fully copy the object +trade_calendar = USFederalHolidayCalendar() +trade_calendar.rules.pop(6) # Remove Columbus day +trade_calendar.rules.pop(7) # Remove Veteran's day +TradeDay = lambda days: CustomBusinessDay(days, calendar=trade_calendar) + +def plot_study(array): + # Given a 2-d array, we assume the event happens at index `lookback`, + # and create all of our summary statistics from there. + lookback = int((array.shape[1] - 1) / 2) + norm_factor = np.repeat(array[:,lookback].reshape(-1, 1), array.shape[1], axis=1) + centered_data = array / norm_factor - 1 + lookforward = centered_data.shape[1] - lookback + means = centered_data.mean(axis=0) + lookforward_data = centered_data[:,lookforward:] + std_dev = np.hstack([0, lookforward_data.std(axis=0)]) + maxes = lookforward_data.max(axis=0) + mins = lookforward_data.min(axis=0) + + f, axarr = plt.subplots(1, 2) + range_begin = -lookback + range_end = lookforward + axarr[0].plot(range(range_begin, range_end), means) + axarr[1].plot(range(range_begin, range_end), means) + axarr[0].fill_between(range(0, range_end), + means[-lookforward:] + std_dev, + means[-lookforward:] - std_dev, + alpha=.5, label="$\pm$ 1 s.d.") + axarr[1].fill_between(range(0, range_end), + means[-lookforward:] + std_dev, + means[-lookforward:] - std_dev, + alpha=.5, label="$\pm$ 1 s.d.") + + max_err = maxes - means[-lookforward+1:] + min_err = means[-lookforward+1:] - mins + axarr[0].errorbar(range(1, range_end), + means[-lookforward+1:], + yerr=[min_err, max_err], label='Max & Min') + axarr[0].legend(loc=2) + axarr[1].legend(loc=2) + + axarr[0].set_xlim((-lookback-1, lookback+1)) + axarr[1].set_xlim((-lookback-1, lookback+1)) + +def plot_study_small(array): + # Given a 2-d array, we assume the event happens at index `lookback`, + # and create all of our summary statistics from there. + lookback = int((array.shape[1] - 1) / 2) + norm_factor = np.repeat(array[:,lookback].reshape(-1, 1), array.shape[1], axis=1) + centered_data = array / norm_factor - 1 + lookforward = centered_data.shape[1] - lookback + means = centered_data.mean(axis=0) + lookforward_data = centered_data[:,lookforward:] + std_dev = np.hstack([0, lookforward_data.std(axis=0)]) + maxes = lookforward_data.max(axis=0) + mins = lookforward_data.min(axis=0) + + range_begin = -lookback + range_end = lookforward + plt.plot(range(range_begin, range_end), means) + plt.fill_between(range(0, range_end), + means[-lookforward:] + std_dev, + means[-lookforward:] - std_dev, + alpha=.5, label="$\pm$ 1 s.d.") + + max_err = maxes - means[-lookforward+1:] + min_err = means[-lookforward+1:] - mins + plt.errorbar(range(1, range_end), + means[-lookforward+1:], + yerr=[min_err, max_err], label='Max & Min') + plt.legend(loc=2) + plt.xlim((-lookback-1, lookback+1)) + +def fetch_event_data(ticker, events, horizon=5): + # Use horizon+1 to account for including the day of the event, + # and half-open interval - that is, for a horizon of 5, + # we should be including 11 events. Additionally, using the + # CustomBusinessDay means we automatically handle issues if + # for example a company reports Friday afternoon - the date + # calculator will turn this into a "Saturday" release, but + # we effectively shift that to Monday with the logic below. + td_back = TradeDay(horizon+1) + td_forward = TradeDay(horizon+1) + + start_date = min(events) - td_back + end_date = max(events) + td_forward + total_data = fetch_ticker(ticker, start_date, end_date) + event_data = [total_data.ix[event-td_back:event+td_forward]\ + [0:horizon*2+1]\ + ['Adjusted Close'] + for event in events] + return np.array(event_data) +``` +
+ +```python +# Generate a couple of random events + +event_dates = [datetime(2016, 5, 27) - timedelta(days=1) - TradeDay(x*20) for x in range(1, 40)] +data = fetch_event_data('CELG', event_dates) +plot_study_small(data) +plt.legend(loc=3) +plt.gcf().set_size_inches(12, 6); + + +plt.annotate('Mean price for days leading up to each event', + (-5, -.01), (-4.5, .025), + arrowprops=dict(facecolor='black', shrink=0.05)) +plt.annotate('', (-.1, .005), (-.5, .02), + arrowprops={'facecolor': 'black', 'shrink': .05}) +plt.annotate('$\pm$ 1 std. dev. each day', (5, .055), (2.5, .085), + arrowprops={'facecolor': 'black', 'shrink': .05}) +plt.annotate('Min/Max each day', (.9, -.07), (-1, -.1), + arrowprops={'facecolor': 'black', 'shrink': .05}); +``` + + + +![png](_notebook_files/_notebook_11_0.png) + + + +And as a quick textual explanation as well: + +- The blue line represents the mean price for each day, represented as a percentage of the price on the '0-day'. For example, if we defined an 'event' as whenever the stock price dropped for three days, we would see a decreasing blue line to the left of the 0-day. +- The blue shaded area represents one standard deviation above and below the mean price for each day following an event. This is intended to give us an idea of what the stock price does in general following an event. +- The green bars are the minimum and maximum price for each day following an event. This instructs us as to how much it's possible for the stock to move. + +## Event Type 1: Trending down over the past N days + +The first type of event I want to study is how stocks perform when they've been trending down over the past couple of days prior to a release. However, we need to clarify what exactly is meant by "trending down." To do so, we'll use the following metric: **the midpoint between each day's opening and closing price goes down over a period of N days**. + +It's probably helpful to have an example: + +
+Code +```python +f, axarr = plt.subplots(1, 2) +f.set_size_inches(18, 6) + +FB_plot = axarr[0] +ohlc_dataframe(FB[datetime(2016, 4, 18):], FB_plot) + +FB_truncated = FB[datetime(2016, 4, 18):datetime(2016, 4, 27)] +midpoint = FB_truncated['Open']/2 + FB_truncated['Close']/2 +FB_plot.plot(FB_truncated.index, midpoint, label='Midpoint') +FB_plot.vlines(date2num(datetime(2016, 4, 27, 12)), + ax_fb.get_ylim()[0], ax_fb.get_ylim()[1], + color='g', label='Earnings Release') +FB_plot.legend(loc=2) +FB_plot.set_title('FB Midpoint Plot') + +AAPL_plot = axarr[1] +ohlc_dataframe(AAPL[datetime(2016, 4, 10):], AAPL_plot) +AAPL_truncated = AAPL[datetime(2016, 4, 10):datetime(2016, 4, 26)] +midpoint = AAPL_truncated['Open']/2 + AAPL_truncated['Close']/2 +AAPL_plot.plot(AAPL_truncated.index, midpoint, label='Midpoint') +AAPL_plot.vlines(date2num(datetime(2016, 4, 26, 12)), + ax_aapl.get_ylim()[0], ax_aapl.get_ylim()[1], + color='g', label='Earnings Release') +AAPL_plot.legend(loc=3) +AAPL_plot.set_title('AAPL Midpoint Plot'); +``` +
+ +![png](_notebook_files/_notebook_14_0.png) + +Given these charts, we can see that FB was trending down for the four days preceding the earnings release, and AAPL was trending down for a whopping 8 days (we don't count the peak day). This will define the methodology that we will use for the study. + +So what are the results? For a given horizon, how well does the market actually perform? + +
+Code + +```python +# Read in the events for each stock; +# The file was created using the first code block in the Appendix +import yaml +from dateutil.parser import parse +from progressbar import ProgressBar + +data_str = open('earnings_dates.yaml', 'r').read() +# Need to remove invalid lines +filtered = filter(lambda x: '{' not in x, data_str.split('\n')) +earnings_data = yaml.load('\n'.join(filtered)) + +# Convert our earnings data into a list of (ticker, date) pairs +# to make it easy to work with. +# This is horribly inefficient, but should get us what we need +ticker_dates = [] +for ticker, date_list in earnings_data.items(): + for iso_str in date_list: + ticker_dates.append((ticker, parse(iso_str))) + +def does_trend_down(ticker, event, horizon): + # Figure out if the `event` has a downtrend for + # the `horizon` days preceding it + # As an interpretation note: it is assumed that + # the closing price of day `event` is the reference + # point, and we want `horizon` days before that. + # The price_data.hdf was created in the second appendix code block + try: + ticker_data = pd.read_hdf('price_data.hdf', ticker) + data = ticker_data[event-TradeDay(horizon):event] + midpoints = data['Open']/2 + data['Close']/2 + + # Shift dates one forward into the future and subtract + # Effectively: do we trend down over all days? + elems = midpoints - midpoints.shift(1) + return len(elems)-1 == len(elems.dropna()[elems <= 0]) + except KeyError: + # If the stock doesn't exist, it doesn't qualify as trending down + # Mostly this is here to make sure the entire analysis doesn't + # blow up if there were issues in data retrieval + return False + +def study_trend(horizon, trend_function): + five_day_events = np.zeros((1, horizon*2 + 1)) + invalid_events = [] + for ticker, event in ProgressBar()(ticker_dates): + if trend_function(ticker, event, horizon): + ticker_data = pd.read_hdf('price_data.hdf', ticker) + event_data = ticker_data[event-TradeDay(horizon):event+TradeDay(horizon)]['Close'] + + try: + five_day_events = np.vstack([five_day_events, event_data]) + except ValueError: + # Sometimes we don't get exactly the right number of values due to calendar + # issues. I've fixed most everything I can, and the few issues that are left + # I assume don't systemically bias the results (i.e. data could be missing + # because it doesn't exist, etc.). After running through, ~1% of events get + # discarded this way + invalid_events.append((ticker, event)) + + + # Remove our initial zero row + five_day_events = five_day_events[1:,:] + plot_study(five_day_events) + plt.gcf().suptitle('Action over {} days: {} events' + .format(horizon,five_day_events.shape[0])) + plt.gcf().set_size_inches(18, 6) + +# Start with a 5 day study +study_trend(5, does_trend_down) +``` + +``` + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:21:38 Time: 0:21:38 +``` +
+ +![png](_notebook_files/_notebook_16_1.png) + +When a stock has been trending down for 5 days, once the earnings are announced it really doesn't move on average. However, the variability is *incredible*. This implies two important things: + +1. The market is just as often wrong about an earnings announcement before it happens as it is correct +2. The incredible width of the min/max bars and standard deviation area tell us that the market reacts *violently* after the earnings are released. + +Let's repeat the same study, but over a time horizon of 8 days and 3 days. Presumably if a stock has been going down for 8 days at a time before the earnings, the market should be more accurate. + +
+Code + +```python +# 8 day study next +study_trend(8, does_trend_down) +``` + +``` + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:20:29 Time: 0:20:29 +``` +
+ +![png](_notebook_files/_notebook_18_1.png) + +However, looking only at stocks that trended down for 8 days prior to a release, the same pattern emerges: on average, the stock doesn't move, but the market reaction is often incredibly violent. + + +
+Code +```python +# 3 day study after that +study_trend(3, does_trend_down) +``` + +``` + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:26:26 Time: 0:26:26 +``` +
+ +![png](_notebook_files/_notebook_20_1.png) + +Finally, when we look at a 3-day horizon, we start getting some incredible outliers. Stocks have a potential to move over ~300% up, and the standard deviation width is again, incredible. The results for a 3-day horizon follow the same pattern we've seen in the 5- and 8-day horizons. + +## Event Type 2: Trending up for N days + +We're now going to repeat the analysis, but do it for uptrends instead. That is, instead of looking at stocks that have been trending down over the past number of days, we focus only on stocks that have been trending up. + +
+Code +```python +def does_trend_up(ticker, event, horizon): + # Figure out if the `event` has an uptrend for + # the `horizon` days preceding it + # As an interpretation note: it is assumed that + # the closing price of day `event` is the reference + # point, and we want `horizon` days before that. + # The price_data.hdf was created in the second appendix code block + try: + ticker_data = pd.read_hdf('price_data.hdf', ticker) + data = ticker_data[event-TradeDay(horizon):event] + midpoints = data['Open']/2 + data['Close']/2 + + # Shift dates one forward into the future and subtract + # Effectively: do we trend down over all days? + elems = midpoints - midpoints.shift(1) + return len(elems)-1 == len(elems.dropna()[elems >= 0]) + except KeyError: + # If the stock doesn't exist, it doesn't qualify as trending down + # Mostly this is here to make sure the entire analysis doesn't + # blow up if there were issues in data retrieval + return False + +study_trend(5, does_trend_up) +``` + +``` + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:22:51 Time: 0:22:51 +``` +
+ +![png](_notebook_files/_notebook_23_1.png) + +The patterns here are very similar. With the exception of noting that stocks can go to nearly 400% after an earnings announcement (most likely this included a takeover announcement, etc.), we still see large min/max bars and wide standard deviation of returns. + +We'll repeat the pattern for stocks going up for both 8 and 3 days straight, but at this point, the results should be very predictable: + +
+Code +```python +study_trend(8, does_trend_up) +``` + +``` + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:20:51 Time: 0:20:51 +``` +
+ +![png](_notebook_files/_notebook_25_1.png) + +
+Code +```python +study_trend(3, does_trend_up) +``` + +``` + 100% (47578 of 47578) |###########################################################| Elapsed Time: 0:26:56 Time: 0:26:56 +``` +
+ +![png](_notebook_files/_notebook_26_1.png) + +## Conclusion and Summary + +I guess the most important thing to summarize with is this: **looking at the entire market, stock performance prior to an earnings release has no bearing on the stock's performance.** Honestly: given the huge variability of returns after an earnings release, even when the stock has been trending for a long time, you're best off divesting before an earnings release and letting the market sort itself out. + +*However*, there is a big caveat. These results are taken when we look at the entire market. So while we can say that the market as a whole knows nothing and just reacts violently, I want to take a closer look into this data. Does the market typically perform poorly on large-cap/high liquidity stocks? Do smaller companies have investors that know them better and can thus predict performance better? Are specific market sectors better at prediction? Presumably technology stocks are more volatile than the industrials. + +So there are some more interesting questions I still want to ask with this data. Knowing that the hard work of data processing is largely already done, it should be fairly simple to continue this analysis and get much more refined with it. Until next time. + +# Appendix + +Export event data for Russell 3000 companies: + +
+Code +```python +import pandas as pd +from html.parser import HTMLParser +from datetime import datetime, timedelta +import requests +import re +from dateutil import parser +import progressbar +from concurrent import futures +import yaml + +class EarningsParser(HTMLParser): + store_dates = False + earnings_offset = None + dates = [] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.dates = [] + + def handle_starttag(self, tag, attrs): + if tag == 'table': + self.store_dates = True + + def handle_data(self, data): + if self.store_dates: + match = re.match(r'\d+/\d+/\d+', data) + if match: + self.dates.append(match.group(0)) + + # If a company reports before the bell, record the earnings date + # being at midnight the day before. Ex: WMT reports 5/19/2016, + # but we want the reference point to be the closing price on 5/18/2016 + if 'After Close' in data: + self.earnings_offset = timedelta(days=0) + elif 'Before Open' in data: + self.earnings_offset = timedelta(days=-1) + + def handle_endtag(self, tag): + if tag == 'table': + self.store_dates = False + +def earnings_releases(ticker): + #print("Looking up ticker {}".format(ticker)) + user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) '\ + 'Gecko/20100101 Firefox/46.0' + headers = {'user-agent': user_agent} + base_url = 'http://www.streetinsider.com/ec_earnings.php?q={}'\ + .format(ticker) + e = EarningsParser() + s = requests.Session() + a = requests.adapters.HTTPAdapter(max_retries=0) + s.mount('http://', a) + e.feed(str(s.get(base_url, headers=headers).content)) + + if e.earnings_offset is not None: + dates = map(lambda x: parser.parse(x) + e.earnings_offset, e.dates) + past = filter(lambda x: x < datetime.now(), dates) + return list(map(lambda d: d.isoformat(), past)) + +# Use a Russell-3000 ETF tracker (ticker IWV) to get a list of holdings +r3000 = pd.read_csv('https://www.ishares.com/us/products/239714/' + 'ishares-russell-3000-etf/1449138789749.ajax?' + 'fileType=csv&fileName=IWV_holdings&dataType=fund', + header=10) +r3000_equities = r3000[(r3000['Exchange'] == 'NASDAQ') | + (r3000['Exchange'] == 'New York Stock Exchange Inc.')] + +dates_file = open('earnings_dates.yaml', 'w') + +with futures.ThreadPoolExecutor(max_workers=8) as pool: + fs = {pool.submit(earnings_releases, r3000_equities.ix[t]['Ticker']): t + for t in r3000_equities.index} + pbar = progressbar.ProgressBar(term_width=80, + max_value=r3000_equities.index.max()) + + for future in futures.as_completed(fs): + i = fs[future] + pbar.update(i) + dates_file.write(yaml.dump({r3000_equities.ix[i]['Ticker']: + future.result()})) +``` +
+ +Downloading stock price data needed for the event studies: + +
+Code +```python +from secrets import QUANDL_KEY +import pandas as pd +import yaml +from dateutil.parser import parse +from datetime import timedelta +import quandl +from progressbar import ProgressBar + +def fetch_ticker(ticker, start, end): + # Quandl is currently giving me issues with returning + # the entire dataset and not slicing server-side. + # So instead, we'll do it client-side! + q_format = '%Y-%m-%d' + ticker_data = quandl.get('YAHOO/' + ticker, + start_date=start.strftime(q_format), + end_date=end.strftime(q_format), + authtoken=QUANDL_KEY) + return ticker_data + +data_str = open('earnings_dates.yaml', 'r').read() +# Need to remove invalid lines +filtered = filter(lambda x: '{' not in x, data_str.split('\n')) +earnings_data = yaml.load('\n'.join(filtered)) + +# Get the first 1500 keys - split up into two statements +# because of Quandl rate limits +tickers = list(earnings_data.keys()) + +price_dict = {} +invalid_tickers = [] +for ticker in ProgressBar()(tickers[0:1500]): + try: + # Replace '.' with '-' in name for some tickers + fixed = ticker.replace('.', '-') + event_strs = earnings_data[ticker] + events = [parse(event) for event in event_strs] + td = timedelta(days=20) + price_dict[ticker] = fetch_ticker(fixed, + min(events)-td, max(events)+td) + except quandl.NotFoundError: + invalid_tickers.append(ticker) + +# Execute this after 10 minutes have passed +for ticker in ProgressBar()(tickers[1500:]): + try: + # Replace '.' with '-' in name for some tickers + fixed = ticker.replace('.', '-') + event_strs = earnings_data[ticker] + events = [parse(event) for event in event_strs] + td = timedelta(days=20) + price_dict[ticker] = fetch_ticker(fixed, + min(events)-td, max(events)+td) + except quandl.NotFoundError: + invalid_tickers.append(ticker) + +prices_store = pd.HDFStore('price_data.hdf') +for ticker, prices in price_dict.items(): + prices_store[ticker] = prices +``` +
\ No newline at end of file diff --git a/blog/2016-10-22-rustic-repodcasting/_article.md b/blog/2016-10-22-rustic-repodcasting/_article.md new file mode 100644 index 0000000..4f7b467 --- /dev/null +++ b/blog/2016-10-22-rustic-repodcasting/_article.md @@ -0,0 +1,309 @@ +Title: A Rustic Re-Podcasting Server (Part 1) +Date: 2016-10-22 +Category: Blog +Tags: Rust, nutone +Authors: Bradlee Speice +Summary: Learning Rust by fire (it sounds better than learning by corrosion) +[//]: <> "Modified: " + +I listen to a lot of Drum and Bass music, because it's beautiful music. And +there's a particular site, [Bassdrive.com](http://bassdrive.com/) that hosts +a lot of great content. Specifically, the +[archives](http://archives.bassdrivearchive.com/) section of the site has a +list of the past shows that you can download and listen to. The issue is, it's +just a [giant list of links to download](http://archives.bassdrivearchive.com/6%20-%20Saturday/Electronic%20Warfare%20-%20The%20Overfiend/). I'd really like +this in a podcast format to take with me on the road, etc. + +So I wrote the [elektricity](https://github.com/bspeice/elektricity) web +application to actually accomplish all that. Whenever you request a feed, it +goes out to Bassdrive, processes all the links on a page, and serves up some +fresh, tasty RSS to satisfy your ears. I hosted it on Heroku using the free +tier because it's really not resource-intensive at all. + +**The issue so far** is that I keep running out of free tier hours during a +month because my podcasting application likes to have a server scan for new +episodes constantly. Not sure why it's doing that, but I don't have a whole +lot of control over it. It's a phenomenal application otherwise. + +**My (over-engineered) solution**: Re-write the application using the +[Rust](https://www.rust-lang.org/en-US/) programming language. I'd like to run +this on a small hacker board I own, and doing this in Rust would allow me to +easily cross-compile it. Plus, I've been very interested in the Rust language +for a while and this would be a great opportunity to really learn it well. +The code is available [here](https://github.com/bspeice/nutone) as development +progresses. + +# The Setup + +We'll be using the [iron](http://ironframework.io/) library to handle the +server, and [hyper](http://hyper.rs/) to fetch the data we need from elsewhere +on the interwebs. [HTML5Ever](http://doc.servo.org/html5ever/index.html) allows +us to ingest the content that will be coming from Bassdrive, and finally, +output is done with [handlebars-rust](http://sunng87.github.io/handlebars-rust/handlebars/index.html). + +It will ultimately be interesting to see how much more work must be done to +actually get this working over another language like Python. Coming from a +dynamic state of mind it's super easy to just chain stuff together, ship it out, +and call it a day. I think I'm going to end up getting much dirtier trying to +write all of this out. + +# Issue 1: Strings + +Strings in Rust are hard. I acknowledge Python can get away with some things +that make strings super easy (and Python 3 has gotten better at cracking down +on some bad cases, `str <-> bytes` specifically), but Rust is hard. + +Let's take for example the `404` error handler I'm trying to write. The result +should be incredibly simple: All I want is to echo back +`Didn't find URL: `. Shouldn't be that hard right? In Python I'd just do +something like: + +```python +def echo_handler(request): + return "You're visiting: {}".format(request.uri) +``` + +And we'd call it a day. Rust isn't so simple. Let's start with the trivial +examples people post online: + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, "You found the server!"))) +} +``` + +Doesn't look too bad right? In fact, it's essentially the same as the Python +version! All we need to do is just send back a string of some form. So, we +look up the documentation for [`Request`](http://ironframework.io/doc/iron/request/struct.Request.html) and see a `url` field that will contain +what we want. Let's try the first iteration: + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, "You found the URL: " + req.url))) +} +``` + +Which yields the error: + + error[E0369]: binary operation `+` cannot be applied to type `&'static str` + +OK, what's going on here? Time to start Googling for ["concatenate strings in Rust"](https://www.google.com/#q=concatenate+strings+in+rust). That's what we +want to do right? Concatenate a static string and the URL. + +After Googling, we come across a helpful [`concat!`](https://doc.rust-lang.org/std/macro.concat!.html) macro that looks really nice! Let's try that one: + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, concat!("You found the URL: ", req.url)))) +} +``` + +And the error: + +`error: expected a literal` + +Turns out Rust actually blows up because the `concat!` macro expects us to know +at compile time what `req.url` is. Which, in my outsider opinion, is a bit +strange. `println!` and `format!`, etc., all handle values they don't know at +compile time. Why can't `concat!`? By any means, we need a new plan of attack. +How about we try formatting strings? + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, format!("You found the URL: {}", req.url)))) +} +``` + +And at long last, it works. Onwards! + +# Issue 2: Fighting with the borrow checker + +Rust's single coolest feature is how the compiler can guarantee safety in your +program. As long as you don't use `unsafe` pointers in Rust, you're guaranteed +safety. And not having truly manual memory management is really cool; I'm +totally OK with never having to write `malloc()` again. + +That said, even [the Rust documentation](https://doc.rust-lang.org/book/ownership.html) makes a specific note: + +> Many new users to Rust experience something we like to call +> ‘fighting with the borrow checker’, where the Rust compiler refuses to +> compile a program that the author thinks is valid. + +If you have to put it in the documentation, it's not a helpful note: +it's hazing. + +So now that we have a handler which works with information from the request, we +want to start making something that looks like an actual web application. +The router provided by `iron` isn't terribly difficult so I won't cover it. +Instead, the thing that had me stumped for a couple hours was trying to +dynamically create routes. + +The unfortunate thing with Rust (in my limited experience at the moment) is that +there is a severe lack of non-trivial examples. Using the router is easy when +you want to give an example of a static function. But how do you you start +working on things that are a bit more complex? + +We're going to cover that here. Our first try: creating a function which returns +other functions. This is a principle called [currying](http://stackoverflow.com/a/36321/1454178). We set up a function that allows us to keep some data in scope +for another function to come later. + +```rust +fn build_handler(message: String) -> Fn(&mut Request) -> IronResult { + move |_: &mut Request| { + Ok(Response::with((status::Ok, message))) + } +} +``` + +We've simply set up a function that returns another anonymous function with the +`message` parameter scoped in. If you compile this, you get not 1, not 2, but 5 +new errors. 4 of them are the same though: + + error[E0277]: the trait bound `for<'r, 'r, 'r> std::ops::Fn(&'r mut iron::Request<'r, 'r>) -> std::result::Result + 'static: std::marker::Sized` is not satisfied + +...oookay. I for one, am not going to spend time trying to figure out what's +going on there. + +And it is here that I will save the audience many hours of frustrated effort. +At this point, I decided to switch from `iron` to pure `hyper` since using +`hyper` would give me a much simpler API. All I would have to do is build a +function that took two parameters as input, and we're done. That said, it +ultimately posed many more issues because I started getting into a weird fight +with the `'static` [lifetime](https://doc.rust-lang.org/book/lifetimes.html) +and being a Rust newbie I just gave up on trying to understand it. + +Instead, we will abandon (mostly) the curried function attempt, and instead +take advantage of something Rust actually intends us to use: `struct` and +`trait`. + +Remember when I talked about a lack of non-trivial examples on the Internet? +This is what I was talking about. I could only find *one* example of this +available online, and it was incredibly complex and contained code we honestly +don't need or care about. There was no documentation of how to build routes that +didn't use static functions, etc. But, I'm assuming you don't really care about +my whining, so let's get to it. + +The `iron` documentation mentions the [`Handler`](http://ironframework.io/doc/iron/middleware/trait.Handler.html) trait as being something we can implement. +Does the function signature for that `handle()` method look familiar? It's what +we've been working with so far. + +The principle is that we need to define a new `struct` to hold our data, then +implement that `handle()` method to return the result. Something that looks +like this might do: + +```rust +struct EchoHandler { + message: String +} + +impl Handler for EchoHandler { + fn handle(&self, _: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, self.message))) + } +} + +// Later in the code when we set up the router... +let echo = EchoHandler { + message: "Is it working yet?" +} +router.get("/", echo.handle, "index"); +``` + +We attempt to build a struct, and give its `handle` method off to the router +so the router knows what to do. + +You guessed it, more errors: + + error: attempted to take value of method `handle` on type `EchoHandler` + +Now, the Rust compiler is actually a really nice fellow, and offers us help: + + help: maybe a `()` to call it is missing? If not, try an anonymous function + +We definitely don't want to call that function, so maybe try an anonymous +function as it recommends? + +```rust +router.get("/", |req: &mut Request| echo.handle(req), "index"); +``` + +Another error: + + error[E0373]: closure may outlive the current function, but it borrows `echo`, which is owned by the current function + +Another helpful message: + + help: to force the closure to take ownership of `echo` (and any other referenced variables), use the `move` keyword + +We're getting closer though! Let's implement this change: + +```rust +router.get("/", move |req: &mut Request| echo.handle(req), "index"); +``` + +And here's where things get strange: + + error[E0507]: cannot move out of borrowed content + --> src/main.rs:18:40 + | + 18 | Ok(Response::with((status::Ok, self.message))) + | ^^^^ cannot move out of borrowed content + +Now, this took me another couple hours to figure out. I'm going to explain it, +but **keep this in mind: Rust only allows one reference at a time** (exceptions +apply of course). + +When we attempt to use `self.message` as it has been created in the earlier +`struct`, we essentially are trying to give it away to another piece of code. +Rust's semantics then state that *we may no longer access it* unless it is +returned to us (which `iron`'s code does not do). There are two ways to fix +this: + +1. Only give away references (i.e. `&self.message` instead of `self.message`) +instead of transferring ownership +2. Make a copy of the underlying value which will be safe to give away + +I didn't know these were the two options originally, so I hope this helps the +audience out. Because `iron` won't accept a reference, we are forced into the +second option: making a copy. To do so, we just need to change the function +to look like this: + +```rust +Ok(Response::with((status::Ok, self.message.clone()))) +``` + +Not so bad, huh? My only complaint is that it took so long to figure out exactly +what was going on. + +And now we have a small server that we can configure dynamically. At long last. + +> Final sidenote: You can actually do this without anonymous functions. Just +> change the router line to: +> `router.get("/", echo, "index");` +> +> Rust's type system seems to figure out that we want to use the `handle()` method. + +# Conclusion + +After a good long days' work, we now have the routing functionality set up on +our application. We should be able to scale this pretty well in the future: +the RSS content we need to deliver in the future can be treated as a string, so +the building blocks are in place. + +There are two important things I learned starting with Rust today: + +1. Rust is a new language, and while the code is high-quality, the mindshare is coming. +2. I'm a terrible programmer. + +Number 1 is pretty obvious and not surprising to anyone. Number two caught me +off guard. I've gotten used to having either a garbage collector (Java, Python, +etc.) or playing a little fast and loose with scoping rules (C, C++). You don't +have to worry about object lifetime there. With Rust, it's forcing me to fully +understand and use well the memory in my applications. In the final mistake I +fixed (using `.clone()`) I would have been fine in C++ to just give away that +reference and never use it again. I wouldn't have run into a "use-after-free" +error, but I would have potentially been leaking memory. Rust forced me to be +incredibly precise about how I use it. + +All said I'm excited for using Rust more. I think it's super cool, it's just +going to take me a lot longer to do this than I originally thought. diff --git a/blog/2016-10-22-rustic-repodcasting/index.mdx b/blog/2016-10-22-rustic-repodcasting/index.mdx new file mode 100644 index 0000000..71ebdf0 --- /dev/null +++ b/blog/2016-10-22-rustic-repodcasting/index.mdx @@ -0,0 +1,329 @@ +--- +slug: 2016/10/rustic-repodcasting +title: A Rustic re-podcasting server +date: 2016-10-22 12:00:00 +authors: [bspeice] +tags: [] +--- + +Learning Rust by fire (it sounds better than learning by corrosion) + + + +I listen to a lot of Drum and Bass music, because it's beautiful music. And +there's a particular site, [Bassdrive.com](http://bassdrive.com/) that hosts +a lot of great content. Specifically, the +[archives](http://archives.bassdrivearchive.com/) section of the site has a +list of the past shows that you can download and listen to. The issue is, it's +just a [giant list of links to download](http://archives.bassdrivearchive.com/6%20-%20Saturday/Electronic%20Warfare%20-%20The%20Overfiend/). I'd really like +this in a podcast format to take with me on the road, etc. + +So I wrote the [elektricity](https://github.com/bspeice/elektricity) web +application to actually accomplish all that. Whenever you request a feed, it +goes out to Bassdrive, processes all the links on a page, and serves up some +fresh, tasty RSS to satisfy your ears. I hosted it on Heroku using the free +tier because it's really not resource-intensive at all. + +**The issue so far** is that I keep running out of free tier hours during a +month because my podcasting application likes to have a server scan for new +episodes constantly. Not sure why it's doing that, but I don't have a whole +lot of control over it. It's a phenomenal application otherwise. + +**My (over-engineered) solution**: Re-write the application using the +[Rust](https://www.rust-lang.org/en-US/) programming language. I'd like to run +this on a small hacker board I own, and doing this in Rust would allow me to +easily cross-compile it. Plus, I've been very interested in the Rust language +for a while and this would be a great opportunity to really learn it well. +The code is available [here](https://github.com/bspeice/nutone) as development +progresses. + +## The Setup + +We'll be using the [iron](http://ironframework.io/) library to handle the +server, and [hyper](http://hyper.rs/) to fetch the data we need from elsewhere +on the interwebs. [HTML5Ever](http://doc.servo.org/html5ever/index.html) allows +us to ingest the content that will be coming from Bassdrive, and finally, +output is done with [handlebars-rust](http://sunng87.github.io/handlebars-rust/handlebars/index.html). + +It will ultimately be interesting to see how much more work must be done to +actually get this working over another language like Python. Coming from a +dynamic state of mind it's super easy to just chain stuff together, ship it out, +and call it a day. I think I'm going to end up getting much dirtier trying to +write all of this out. + +## Issue 1: Strings + +Strings in Rust are hard. I acknowledge Python can get away with some things +that make strings super easy (and Python 3 has gotten better at cracking down +on some bad cases, `str <-> bytes` specifically), but Rust is hard. + +Let's take for example the `404` error handler I'm trying to write. The result +should be incredibly simple: All I want is to echo back +`Didn't find URL: `. Shouldn't be that hard right? In Python I'd just do +something like: + +```python +def echo_handler(request): + return "You're visiting: {}".format(request.uri) +``` + +And we'd call it a day. Rust isn't so simple. Let's start with the trivial +examples people post online: + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, "You found the server!"))) +} +``` + +Doesn't look too bad right? In fact, it's essentially the same as the Python +version! All we need to do is just send back a string of some form. So, we +look up the documentation for [`Request`](http://ironframework.io/doc/iron/request/struct.Request.html) and see a `url` field that will contain +what we want. Let's try the first iteration: + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, "You found the URL: " + req.url))) +} +``` + +Which yields the error: + +``` + error[E0369]: binary operation `+` cannot be applied to type `&'static str` +``` + +OK, what's going on here? Time to start Googling for ["concatenate strings in Rust"](https://www.google.com/#q=concatenate+strings+in+rust). That's what we +want to do right? Concatenate a static string and the URL. + +After Googling, we come across a helpful [`concat!`](https://doc.rust-lang.org/std/macro.concat!.html) macro that looks really nice! Let's try that one: + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, concat!("You found the URL: ", req.url)))) +} +``` + +And the error: + +``` + error: expected a literal +``` + +Turns out Rust actually blows up because the `concat!` macro expects us to know +at compile time what `req.url` is. Which, in my outsider opinion, is a bit +strange. `println!` and `format!`, etc., all handle values they don't know at +compile time. Why can't `concat!`? By any means, we need a new plan of attack. +How about we try formatting strings? + +```rust +fn hello_world(req: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, format!("You found the URL: {}", req.url)))) +} +``` + +And at long last, it works. Onwards! + +## Issue 2: Fighting with the borrow checker + +Rust's single coolest feature is how the compiler can guarantee safety in your +program. As long as you don't use `unsafe` pointers in Rust, you're guaranteed +safety. And not having truly manual memory management is really cool; I'm +totally OK with never having to write `malloc()` again. + +That said, even [the Rust documentation](https://doc.rust-lang.org/book/ownership.html) makes a specific note: + +> Many new users to Rust experience something we like to call +> ‘fighting with the borrow checker’, where the Rust compiler refuses to +> compile a program that the author thinks is valid. + +If you have to put it in the documentation, it's not a helpful note: +it's hazing. + +So now that we have a handler which works with information from the request, we +want to start making something that looks like an actual web application. +The router provided by `iron` isn't terribly difficult so I won't cover it. +Instead, the thing that had me stumped for a couple hours was trying to +dynamically create routes. + +The unfortunate thing with Rust (in my limited experience at the moment) is that +there is a severe lack of non-trivial examples. Using the router is easy when +you want to give an example of a static function. But how do you you start +working on things that are a bit more complex? + +We're going to cover that here. Our first try: creating a function which returns +other functions. This is a principle called [currying](http://stackoverflow.com/a/36321/1454178). We set up a function that allows us to keep some data in scope +for another function to come later. + +```rust +fn build_handler(message: String) -> Fn(&mut Request) -> IronResult { + move |_: &mut Request| { + Ok(Response::with((status::Ok, message))) + } +} +``` + +We've simply set up a function that returns another anonymous function with the +`message` parameter scoped in. If you compile this, you get not 1, not 2, but 5 +new errors. 4 of them are the same though: + +``` + error[E0277]: the trait bound `for<'r, 'r, 'r> std::ops::Fn(&'r mut iron::Request<'r, 'r>) -> std::result::Result + 'static: std::marker::Sized` is not satisfied +``` + +...oookay. I for one, am not going to spend time trying to figure out what's +going on there. + +And it is here that I will save the audience many hours of frustrated effort. +At this point, I decided to switch from `iron` to pure `hyper` since using +`hyper` would give me a much simpler API. All I would have to do is build a +function that took two parameters as input, and we're done. That said, it +ultimately posed many more issues because I started getting into a weird fight +with the `'static` [lifetime](https://doc.rust-lang.org/book/lifetimes.html) +and being a Rust newbie I just gave up on trying to understand it. + +Instead, we will abandon (mostly) the curried function attempt, and instead +take advantage of something Rust actually intends us to use: `struct` and +`trait`. + +Remember when I talked about a lack of non-trivial examples on the Internet? +This is what I was talking about. I could only find *one* example of this +available online, and it was incredibly complex and contained code we honestly +don't need or care about. There was no documentation of how to build routes that +didn't use static functions, etc. But, I'm assuming you don't really care about +my whining, so let's get to it. + +The `iron` documentation mentions the [`Handler`](http://ironframework.io/doc/iron/middleware/trait.Handler.html) trait as being something we can implement. +Does the function signature for that `handle()` method look familiar? It's what +we've been working with so far. + +The principle is that we need to define a new `struct` to hold our data, then +implement that `handle()` method to return the result. Something that looks +like this might do: + +```rust +struct EchoHandler { + message: String +} + +impl Handler for EchoHandler { + fn handle(&self, _: &mut Request) -> IronResult { + Ok(Response::with((status::Ok, self.message))) + } +} + +// Later in the code when we set up the router... +let echo = EchoHandler { + message: "Is it working yet?" +} +router.get("/", echo.handle, "index"); +``` + +We attempt to build a struct, and give its `handle` method off to the router +so the router knows what to do. + +You guessed it, more errors: + +``` + error: attempted to take value of method `handle` on type `EchoHandler` +``` + +Now, the Rust compiler is actually a really nice fellow, and offers us help: + +``` + help: maybe a `()` to call it is missing? If not, try an anonymous function +``` + +We definitely don't want to call that function, so maybe try an anonymous +function as it recommends? + +```rust +router.get("/", |req: &mut Request| echo.handle(req), "index"); +``` + +Another error: + +``` + error[E0373]: closure may outlive the current function, but it borrows `echo`, which is owned by the current function +``` + +Another helpful message: + +``` + help: to force the closure to take ownership of `echo` (and any other referenced variables), use the `move` keyword +``` + +We're getting closer though! Let's implement this change: + +```rust +router.get("/", move |req: &mut Request| echo.handle(req), "index"); +``` + +And here's where things get strange: + +``` + error[E0507]: cannot move out of borrowed content + --> src/main.rs:18:40 + | + 18 | Ok(Response::with((status::Ok, self.message))) + | ^^^^ cannot move out of borrowed content +``` + +Now, this took me another couple hours to figure out. I'm going to explain it, +but **keep this in mind: Rust only allows one reference at a time** (exceptions +apply of course). + +When we attempt to use `self.message` as it has been created in the earlier +`struct`, we essentially are trying to give it away to another piece of code. +Rust's semantics then state that *we may no longer access it* unless it is +returned to us (which `iron`'s code does not do). There are two ways to fix +this: + +1. Only give away references (i.e. `&self.message` instead of `self.message`) +instead of transferring ownership +2. Make a copy of the underlying value which will be safe to give away + +I didn't know these were the two options originally, so I hope this helps the +audience out. Because `iron` won't accept a reference, we are forced into the +second option: making a copy. To do so, we just need to change the function +to look like this: + +```rust +Ok(Response::with((status::Ok, self.message.clone()))) +``` + +Not so bad, huh? My only complaint is that it took so long to figure out exactly +what was going on. + +And now we have a small server that we can configure dynamically. At long last. + +> Final sidenote: You can actually do this without anonymous functions. Just +> change the router line to: +> `router.get("/", echo, "index");` +> +> Rust's type system seems to figure out that we want to use the `handle()` method. + +## Conclusion + +After a good long days' work, we now have the routing functionality set up on +our application. We should be able to scale this pretty well in the future: +the RSS content we need to deliver in the future can be treated as a string, so +the building blocks are in place. + +There are two important things I learned starting with Rust today: + +1. Rust is a new language, and while the code is high-quality, the mindshare is coming. +2. I'm a terrible programmer. + +Number 1 is pretty obvious and not surprising to anyone. Number two caught me +off guard. I've gotten used to having either a garbage collector (Java, Python, +etc.) or playing a little fast and loose with scoping rules (C, C++). You don't +have to worry about object lifetime there. With Rust, it's forcing me to fully +understand and use well the memory in my applications. In the final mistake I +fixed (using `.clone()`) I would have been fine in C++ to just give away that +reference and never use it again. I wouldn't have run into a "use-after-free" +error, but I would have potentially been leaking memory. Rust forced me to be +incredibly precise about how I use it. + +All said I'm excited for using Rust more. I think it's super cool, it's just +going to take me a lot longer to do this than I originally thought. \ No newline at end of file diff --git a/blog/2016-11-01-PCA-audio-compression/1.wav b/blog/2016-11-01-PCA-audio-compression/1.wav new file mode 100644 index 0000000..e85ba39 Binary files /dev/null and b/blog/2016-11-01-PCA-audio-compression/1.wav differ diff --git a/blog/2016-11-01-PCA-audio-compression/2.wav b/blog/2016-11-01-PCA-audio-compression/2.wav new file mode 100644 index 0000000..e85ba39 Binary files /dev/null and b/blog/2016-11-01-PCA-audio-compression/2.wav differ diff --git a/blog/2016-11-01-PCA-audio-compression/3.wav b/blog/2016-11-01-PCA-audio-compression/3.wav new file mode 100644 index 0000000..52ac8c8 Binary files /dev/null and b/blog/2016-11-01-PCA-audio-compression/3.wav differ diff --git a/blog/2016-11-01-PCA-audio-compression/4.wav b/blog/2016-11-01-PCA-audio-compression/4.wav new file mode 100644 index 0000000..0aa398c Binary files /dev/null and b/blog/2016-11-01-PCA-audio-compression/4.wav differ diff --git a/blog/2016-11-01-PCA-audio-compression/5.wav b/blog/2016-11-01-PCA-audio-compression/5.wav new file mode 100644 index 0000000..d708c5d Binary files /dev/null and b/blog/2016-11-01-PCA-audio-compression/5.wav differ diff --git a/blog/2016-11-01-PCA-audio-compression/6.wav b/blog/2016-11-01-PCA-audio-compression/6.wav new file mode 100644 index 0000000..28967e4 Binary files /dev/null and b/blog/2016-11-01-PCA-audio-compression/6.wav differ diff --git a/blog/2016-11-01-PCA-audio-compression/_article.md b/blog/2016-11-01-PCA-audio-compression/_article.md new file mode 100644 index 0000000..df95b1c --- /dev/null +++ b/blog/2016-11-01-PCA-audio-compression/_article.md @@ -0,0 +1,9 @@ +Title: Audio Compression using PCA +Date: 2016-11-01 +Category: Blog +Tags: PCA, Machine Learning, Digital Signal Processing +Authors: Bradlee Speice +Summary: In which I apply Machine Learning techniques to Digital Signal Processing to astounding failure. +[//]: <> "Modified: " + +{% notebook 2016-11-01-PCA-audio-compression.ipynb %} diff --git a/blog/2016-11-01-PCA-audio-compression/_notebook.ipynb b/blog/2016-11-01-PCA-audio-compression/_notebook.ipynb new file mode 100644 index 0000000..3d8e6a1 --- /dev/null +++ b/blog/2016-11-01-PCA-audio-compression/_notebook.ipynb @@ -0,0 +1,599 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Towards a new (and pretty poor) compression scheme\n", + "--------------------------------------------------\n", + "\n", + "I'm going to be working with some audio data for a while as I get prepared for a term project this semester. I'll be working (with a partner) to design a system for separating voices from music. Given my total lack of experience with [Digital Signal Processing][1] I figured that now was as good a time as ever to work on a couple of fun projects that would get me back up to speed.\n", + "\n", + "The first project I want to work on: Designing a new compression scheme for audio data.\n", + "\n", + "A Brief Introduction to Audio Compression\n", + "-----------------------------------------\n", + "\n", + "Audio files when uncompressed (files ending with `.wav`) are huge. Like, 10.5 Megabytes per minute huge. Storage is cheap these days, but that's still an incredible amount of data that we don't really need. Instead, we'd like to compress that data so that it's not taking up so much space. There are broadly two ways to accomplish this:\n", + "\n", + "1. Lossless compression - Formats like [FLAC][2], [ALAC][3], and [Monkey's Audio (.ape)][4] all go down this route. The idea is that when you compress and uncompress a file, you get exactly the same as what you started with.\n", + "\n", + "2. Lossy compression - Formats like [MP3][5], [Ogg][6], and [AAC (`.m4a`)][7] are far more popular, but make a crucial tradeoff: We can reduce the file size even more during compression, but the decompressed file won't be the same.\n", + "\n", + "There is a fundamental tradeoff at stake: Using lossy compression sacrifices some of the integrity of the resulting file to save on storage space. Most people (I personally believe it's everybody) can't hear the difference, so this is an acceptable tradeoff. You have files that take up a 10th of the space, and nobody can tell there's a difference in audio quality.\n", + "\n", + "A PCA-based Compression Scheme\n", + "------------------------------\n", + "\n", + "What I want to try out is a [PCA][8] approach to encoding audio. The PCA technique comes from Machine Learning, where it is used for a process called [Dimensionality Reduction][9]. Put simply, the idea is the same as lossy compression: if we can find a way that represents the data well enough, we can save on space. There are a lot of theoretical concerns that lead me to believe this compression style will not end well, but I'm interested to try it nonetheless.\n", + "\n", + "PCA works as follows: Given a dataset with a number of features, I find a way to approximate those original features using some \"new features\" that are statistically as close as possible to the original ones. This is comparable to a scheme like MP3: Given an original signal, I want to find a way of representing it that gets approximately close to what the original was. The difference is that PCA is designed for statistical data, and not signal data. But we won't let that stop us.\n", + "\n", + "The idea is as follows: Given a signal, reshape it into 1024 columns by however many rows are needed (zero-padded if necessary). Run the PCA algorithm, and do dimensionality reduction with a couple different settings. The number of components I choose determines the quality: If I use 1024 components, I will essentially be using the original signal. If I use a smaller number of components, I start losing some of the data that was in the original file. This will give me an idea of whether it's possible to actually build an encoding scheme off of this, or whether I'm wasting my time.\n", + "\n", + "Running the Algorithm\n", + "---------------------\n", + "\n", + "The audio I will be using comes from the song [Tabulasa][10], by [Broke for Free][11]. I'll be loading in the audio signal to Python and using [Scikit-Learn][12] to actually run the PCA algorithm.\n", + "\n", + "We first need to convert the FLAC file I have to a WAV:\n", + "\n", + "[1]: https://en.wikipedia.org/wiki/Digital_signal_processing\n", + "[2]: https://en.wikipedia.org/wiki/FLAC\n", + "[3]: https://en.wikipedia.org/wiki/Apple_Lossless\n", + "[4]: https://en.wikipedia.org/wiki/Monkey%27s_Audio\n", + "[5]: https://en.wikipedia.org/wiki/MP3\n", + "[6]: https://en.wikipedia.org/wiki/Vorbis\n", + "[7]: https://en.wikipedia.org/wiki/Advanced_Audio_Coding\n", + "[8]: https://en.wikipedia.org/wiki/Principal_component_analysis\n", + "[9]: https://en.wikipedia.org/wiki/Dimensionality_reduction\n", + "[10]: https://brokeforfree.bandcamp.com/track/tabulasa\n", + "[11]: https://brokeforfree.bandcamp.com/album/xxvii\n", + "[12]: http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html#sklearn.decomposition.PCA" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "!ffmpeg -hide_banner -loglevel panic -i \"Broke For Free/XXVII/01 Tabulasa.flac\" \"Tabulasa.wav\" -c wav" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, let's go ahead and load a small sample so you can hear what is going on." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Audio\n", + "from scipy.io import wavfile\n", + "\n", + "samplerate, tabulasa = wavfile.read('Tabulasa.wav')\n", + "\n", + "start = samplerate * 14 # 10 seconds in\n", + "end = start + samplerate * 10 # 5 second duration\n", + "Audio(data=tabulasa[start:end, 0], rate=samplerate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we'll define the code we will be using to do PCA. It's very short, as the PCA algorithm is very simple." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from sklearn.decomposition import PCA\n", + "import numpy as np\n", + "\n", + "def pca_reduce(signal, n_components, block_size=1024):\n", + " \n", + " # First, zero-pad the signal so that it is divisible by the block_size\n", + " samples = len(signal)\n", + " hanging = block_size - np.mod(samples, block_size)\n", + " padded = np.lib.pad(signal, (0, hanging), 'constant', constant_values=0)\n", + " \n", + " # Reshape the signal to have 1024 dimensions\n", + " reshaped = padded.reshape((len(padded) // block_size, block_size))\n", + " \n", + " # Second, do the actual PCA process\n", + " pca = PCA(n_components=n_components)\n", + " pca.fit(reshaped)\n", + " \n", + " transformed = pca.transform(reshaped)\n", + " reconstructed = pca.inverse_transform(transformed).reshape((len(padded)))\n", + " return pca, transformed, reconstructed" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've got our functions set up, let's try actually running something. First, we'll use `n_components == block_size`, which implies that we should end up with the same signal we started with." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tabulasa_left = tabulasa[:,0]\n", + "\n", + "_, _, reconstructed = pca_reduce(tabulasa_left, 1024, 1024)\n", + "\n", + "Audio(data=reconstructed[start:end], rate=samplerate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "OK, that does indeed sound like what we originally had. Let's drastically cut down the number of components we're doing this with as a sanity check: the audio quality should become incredibly poor." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "_, _, reconstructed = pca_reduce(tabulasa_left, 32, 1024)\n", + "\n", + "Audio(data=reconstructed[start:end], rate=samplerate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, our reconstructed audio does sound incredibly poor! But there's something else very interesting going on here under the hood. Did you notice that the bassline comes across very well, but that there's no midrange or treble? The drums are almost entirely gone.\n", + "\n", + "[Drop the (Treble)][13]\n", + "-----------------------\n", + "\n", + "It will help to understand PCA more fully when trying to read this part, but I'll do my best to break it down. PCA tries to find a way to best represent the dataset using \"components.\" Think of each \"component\" as containing some of the information you need in order to reconstruct the full audio. For example, you might have a \"low frequency\" component that contains all the information you need in order to hear the bassline. There might be other components that explain the high frequency things like singers, or melodies, that you also need.\n", + "\n", + "What makes PCA interesting is that it attempts to find the \"most important\" components in explaining the signal. In a signal processing world, this means that PCA is trying to find the signal amongst the noise in your data. In our case, this means that PCA, when forced to work with small numbers of components, will chuck out the noisy components first. It's doing it's best job to reconstruct the signal, but it has to make sacrifices somewhere.\n", + "\n", + "So I've mentioned that PCA identifies the \"noisy\" components in our dataset. This is equivalent to saying that PCA removes the \"high frequency\" components in this case: it's very easy to represent a low-frequency signal like a bassline. It's far more difficult to represent a high-frequency signal because it's changing all the time. When you force PCA to make a tradeoff by using a small number of components, the best it can hope to do is replicate the low-frequency sections and skip the high-frequency things.\n", + "\n", + "This is a very interesting insight, and it also has echos (pardon the pun) of how humans understand music in general. Other encoding schemes (like MP3, etc.) typically chop off a lot of the high-frequency range as well. There is typically a lot of high-frequency noise in audio that is nearly impossible to hear, so it's easy to remove it without anyone noticing. PCA ends up doing something similar, and while that certainly wasn't the intention, it is an interesting effect.\n", + "\n", + "## A More Realistic Example\n", + "\n", + "So we've seen the edge cases so far: Using a large number of components results in audio very close to the original, and using a small number of components acts as a low-pass filter. How about we develop something that sounds \"good enough\" in practice, that we can use as a benchmark for size? We'll use ourselves as judges of audio quality, and build another function to help us estimate how much space we need to store everything in.\n", + "\n", + "[13]: https://youtu.be/Ua0KpfJsxKo?t=1m17s" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
RawPCAPCA w/ BZ2
(1, 1)69.054298138.10859716.431797
(1, 2)69.05430669.05430632.981380
(1, 4)69.05432134.52716116.715032
(4, 32)69.05444317.2636118.481735
(16, 256)69.0546888.6318364.274846
(32, 256)69.05468817.2636728.542909
(64, 256)69.05468834.52734417.097543
(128, 1024)69.05468817.2636729.430644
(256, 1024)69.05468834.52734418.870387
(512, 1024)69.05468869.05468837.800940
(128, 2048)69.0625008.6328126.185015
(256, 2048)69.06250017.26562512.366942
(512, 2048)69.06250034.53125024.736506
(1024, 2048)69.06250069.06250049.517493
\n", + "
" + ], + "text/plain": [ + " Raw PCA PCA w/ BZ2\n", + "(1, 1) 69.054298 138.108597 16.431797\n", + "(1, 2) 69.054306 69.054306 32.981380\n", + "(1, 4) 69.054321 34.527161 16.715032\n", + "(4, 32) 69.054443 17.263611 8.481735\n", + "(16, 256) 69.054688 8.631836 4.274846\n", + "(32, 256) 69.054688 17.263672 8.542909\n", + "(64, 256) 69.054688 34.527344 17.097543\n", + "(128, 1024) 69.054688 17.263672 9.430644\n", + "(256, 1024) 69.054688 34.527344 18.870387\n", + "(512, 1024) 69.054688 69.054688 37.800940\n", + "(128, 2048) 69.062500 8.632812 6.185015\n", + "(256, 2048) 69.062500 17.265625 12.366942\n", + "(512, 2048) 69.062500 34.531250 24.736506\n", + "(1024, 2048) 69.062500 69.062500 49.517493" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from bz2 import compress\n", + "import pandas as pd\n", + "\n", + "def raw_estimate(transformed, pca):\n", + " # We assume that we'll be storing things as 16-bit WAV,\n", + " # meaning two bytes per sample\n", + " signal_bytes = transformed.tobytes()\n", + " # PCA stores the components as floating point, we'll assume\n", + " # that means 32-bit floats, so 4 bytes per element\n", + " component_bytes = transformed.tobytes()\n", + " \n", + " # Return a result in megabytes\n", + " return (len(signal_bytes) + len(component_bytes)) / (2**20)\n", + "\n", + "# Do an estimate for lossless compression applied on top of our\n", + "# PCA reduction\n", + "def bz2_estimate(transformed, pca):\n", + " bytestring = transformed.tobytes() + b';' + pca.components_.tobytes()\n", + " compressed = compress(bytestring)\n", + " return len(compressed) / (2**20)\n", + "\n", + "compression_attempts = [\n", + " (1, 1),\n", + " (1, 2),\n", + " (1, 4),\n", + " (4, 32),\n", + " (16, 256),\n", + " (32, 256),\n", + " (64, 256),\n", + " (128, 1024),\n", + " (256, 1024),\n", + " (512, 1024),\n", + " (128, 2048),\n", + " (256, 2048),\n", + " (512, 2048),\n", + " (1024, 2048)\n", + "]\n", + "\n", + "def build_estimates(signal, n_components, block_size):\n", + " pca, transformed, recon = pca_reduce(tabulasa_left, n_components, block_size)\n", + " raw_pca_estimate = raw_estimate(transformed, pca)\n", + " bz2_pca_estimate = bz2_estimate(transformed, pca)\n", + " raw_size = len(recon.tobytes()) / (2**20)\n", + " return raw_size, raw_pca_estimate, bz2_pca_estimate\n", + "\n", + "pca_compression_results = pd.DataFrame([\n", + " build_estimates(tabulasa_left, n, bs)\n", + " for n, bs in compression_attempts\n", + " ])\n", + "\n", + "pca_compression_results.columns = [\"Raw\", \"PCA\", \"PCA w/ BZ2\"]\n", + "pca_compression_results.index = compression_attempts\n", + "pca_compression_results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see, there are a couple of instances where we do nearly 20 times better on storage space than the uncompressed file. Let's here what that sounds like:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "_, _, reconstructed = pca_reduce(tabulasa_left, 16, 256)\n", + "Audio(data=reconstructed[start:end], rate=samplerate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It sounds incredibly poor though. Let's try something that's a bit more realistic:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "_, _, reconstructed = pca_reduce(tabulasa_left, 1, 4)\n", + "Audio(data=reconstructed[start:end], rate=samplerate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And just out of curiosity, we can try something that has the same ratio of components to block size. This should be close to an apples-to-apples comparison." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "_, _, reconstructed = pca_reduce(tabulasa_left, 64, 256)\n", + "Audio(data=reconstructed[start:end], rate=samplerate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The smaller block size definitely has better high-end response, but I personally think the larger block size sounds better overall." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusions\n", + "\n", + "So, what do I think about audio compression using PCA?\n", + "\n", + "Strangely enough, it actually works pretty well relative to what I expected. That said, it's a terrible idea in general.\n", + "\n", + "First off, you don't really save any space. The component matrix needed to actually run the PCA algorithm takes up a lot of space on its own, so it's very difficult to save space without sacrificing a huge amount of audio quality. And even then, codecs like AAC sound very nice even at bitrates that this PCA method could only dream of.\n", + "\n", + "Second, there's the issue of audio streaming. PCA relies on two components: the datastream, and a matrix used to reconstruct the original signal. While it is easy to stream the data, you can't stream that matrix. And even if you divided the stream up into small blocks to give you a small matrix, you must guarantee that the matrix arrives; if you don't have that matrix, the data stream will make no sense whatsoever.\n", + "\n", + "All said, this was an interesting experiment. It's really cool seeing PCA used for signal analysis where I haven't seen it applied before, but I don't think it will lead to any practical results. Look forward to more signal processing stuff in the future!" + ] + } + ], + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/blog/2016-11-01-PCA-audio-compression/_notebook.md b/blog/2016-11-01-PCA-audio-compression/_notebook.md new file mode 100644 index 0000000..4e1ec14 --- /dev/null +++ b/blog/2016-11-01-PCA-audio-compression/_notebook.md @@ -0,0 +1,401 @@ +Towards a new (and pretty poor) compression scheme +-------------------------------------------------- + +I'm going to be working with some audio data for a while as I get prepared for a term project this semester. I'll be working (with a partner) to design a system for separating voices from music. Given my total lack of experience with [Digital Signal Processing][1] I figured that now was as good a time as ever to work on a couple of fun projects that would get me back up to speed. + +The first project I want to work on: Designing a new compression scheme for audio data. + +A Brief Introduction to Audio Compression +----------------------------------------- + +Audio files when uncompressed (files ending with `.wav`) are huge. Like, 10.5 Megabytes per minute huge. Storage is cheap these days, but that's still an incredible amount of data that we don't really need. Instead, we'd like to compress that data so that it's not taking up so much space. There are broadly two ways to accomplish this: + +1. Lossless compression - Formats like [FLAC][2], [ALAC][3], and [Monkey's Audio (.ape)][4] all go down this route. The idea is that when you compress and uncompress a file, you get exactly the same as what you started with. + +2. Lossy compression - Formats like [MP3][5], [Ogg][6], and [AAC (`.m4a`)][7] are far more popular, but make a crucial tradeoff: We can reduce the file size even more during compression, but the decompressed file won't be the same. + +There is a fundamental tradeoff at stake: Using lossy compression sacrifices some of the integrity of the resulting file to save on storage space. Most people (I personally believe it's everybody) can't hear the difference, so this is an acceptable tradeoff. You have files that take up a 10th of the space, and nobody can tell there's a difference in audio quality. + +A PCA-based Compression Scheme +------------------------------ + +What I want to try out is a [PCA][8] approach to encoding audio. The PCA technique comes from Machine Learning, where it is used for a process called [Dimensionality Reduction][9]. Put simply, the idea is the same as lossy compression: if we can find a way that represents the data well enough, we can save on space. There are a lot of theoretical concerns that lead me to believe this compression style will not end well, but I'm interested to try it nonetheless. + +PCA works as follows: Given a dataset with a number of features, I find a way to approximate those original features using some "new features" that are statistically as close as possible to the original ones. This is comparable to a scheme like MP3: Given an original signal, I want to find a way of representing it that gets approximately close to what the original was. The difference is that PCA is designed for statistical data, and not signal data. But we won't let that stop us. + +The idea is as follows: Given a signal, reshape it into 1024 columns by however many rows are needed (zero-padded if necessary). Run the PCA algorithm, and do dimensionality reduction with a couple different settings. The number of components I choose determines the quality: If I use 1024 components, I will essentially be using the original signal. If I use a smaller number of components, I start losing some of the data that was in the original file. This will give me an idea of whether it's possible to actually build an encoding scheme off of this, or whether I'm wasting my time. + +Running the Algorithm +--------------------- + +The audio I will be using comes from the song [Tabulasa][10], by [Broke for Free][11]. I'll be loading in the audio signal to Python and using [Scikit-Learn][12] to actually run the PCA algorithm. + +We first need to convert the FLAC file I have to a WAV: + +[1]: https://en.wikipedia.org/wiki/Digital_signal_processing +[2]: https://en.wikipedia.org/wiki/FLAC +[3]: https://en.wikipedia.org/wiki/Apple_Lossless +[4]: https://en.wikipedia.org/wiki/Monkey%27s_Audio +[5]: https://en.wikipedia.org/wiki/MP3 +[6]: https://en.wikipedia.org/wiki/Vorbis +[7]: https://en.wikipedia.org/wiki/Advanced_Audio_Coding +[8]: https://en.wikipedia.org/wiki/Principal_component_analysis +[9]: https://en.wikipedia.org/wiki/Dimensionality_reduction +[10]: https://brokeforfree.bandcamp.com/track/tabulasa +[11]: https://brokeforfree.bandcamp.com/album/xxvii +[12]: http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html#sklearn.decomposition.PCA + + +```python +!ffmpeg -hide_banner -loglevel panic -i "Broke For Free/XXVII/01 Tabulasa.flac" "Tabulasa.wav" -c wav +``` + +Then, let's go ahead and load a small sample so you can hear what is going on. + + +```python +from IPython.display import Audio +from scipy.io import wavfile + +samplerate, tabulasa = wavfile.read('Tabulasa.wav') + +start = samplerate * 14 # 10 seconds in +end = start + samplerate * 10 # 5 second duration +Audio(data=tabulasa[start:end, 0], rate=samplerate) +``` + + + + + + + + + + +Next, we'll define the code we will be using to do PCA. It's very short, as the PCA algorithm is very simple. + + +```python +from sklearn.decomposition import PCA +import numpy as np + +def pca_reduce(signal, n_components, block_size=1024): + + # First, zero-pad the signal so that it is divisible by the block_size + samples = len(signal) + hanging = block_size - np.mod(samples, block_size) + padded = np.lib.pad(signal, (0, hanging), 'constant', constant_values=0) + + # Reshape the signal to have 1024 dimensions + reshaped = padded.reshape((len(padded) // block_size, block_size)) + + # Second, do the actual PCA process + pca = PCA(n_components=n_components) + pca.fit(reshaped) + + transformed = pca.transform(reshaped) + reconstructed = pca.inverse_transform(transformed).reshape((len(padded))) + return pca, transformed, reconstructed +``` + +Now that we've got our functions set up, let's try actually running something. First, we'll use `n_components == block_size`, which implies that we should end up with the same signal we started with. + + +```python +tabulasa_left = tabulasa[:,0] + +_, _, reconstructed = pca_reduce(tabulasa_left, 1024, 1024) + +Audio(data=reconstructed[start:end], rate=samplerate) +``` + + + + + + + + + + +OK, that does indeed sound like what we originally had. Let's drastically cut down the number of components we're doing this with as a sanity check: the audio quality should become incredibly poor. + + +```python +_, _, reconstructed = pca_reduce(tabulasa_left, 32, 1024) + +Audio(data=reconstructed[start:end], rate=samplerate) +``` + + + + + + + + + + +As expected, our reconstructed audio does sound incredibly poor! But there's something else very interesting going on here under the hood. Did you notice that the bassline comes across very well, but that there's no midrange or treble? The drums are almost entirely gone. + +[Drop the (Treble)][13] +----------------------- + +It will help to understand PCA more fully when trying to read this part, but I'll do my best to break it down. PCA tries to find a way to best represent the dataset using "components." Think of each "component" as containing some of the information you need in order to reconstruct the full audio. For example, you might have a "low frequency" component that contains all the information you need in order to hear the bassline. There might be other components that explain the high frequency things like singers, or melodies, that you also need. + +What makes PCA interesting is that it attempts to find the "most important" components in explaining the signal. In a signal processing world, this means that PCA is trying to find the signal amongst the noise in your data. In our case, this means that PCA, when forced to work with small numbers of components, will chuck out the noisy components first. It's doing it's best job to reconstruct the signal, but it has to make sacrifices somewhere. + +So I've mentioned that PCA identifies the "noisy" components in our dataset. This is equivalent to saying that PCA removes the "high frequency" components in this case: it's very easy to represent a low-frequency signal like a bassline. It's far more difficult to represent a high-frequency signal because it's changing all the time. When you force PCA to make a tradeoff by using a small number of components, the best it can hope to do is replicate the low-frequency sections and skip the high-frequency things. + +This is a very interesting insight, and it also has echos (pardon the pun) of how humans understand music in general. Other encoding schemes (like MP3, etc.) typically chop off a lot of the high-frequency range as well. There is typically a lot of high-frequency noise in audio that is nearly impossible to hear, so it's easy to remove it without anyone noticing. PCA ends up doing something similar, and while that certainly wasn't the intention, it is an interesting effect. + +## A More Realistic Example + +So we've seen the edge cases so far: Using a large number of components results in audio very close to the original, and using a small number of components acts as a low-pass filter. How about we develop something that sounds "good enough" in practice, that we can use as a benchmark for size? We'll use ourselves as judges of audio quality, and build another function to help us estimate how much space we need to store everything in. + +[13]: https://youtu.be/Ua0KpfJsxKo?t=1m17s + + +```python +from bz2 import compress +import pandas as pd + +def raw_estimate(transformed, pca): + # We assume that we'll be storing things as 16-bit WAV, + # meaning two bytes per sample + signal_bytes = transformed.tobytes() + # PCA stores the components as floating point, we'll assume + # that means 32-bit floats, so 4 bytes per element + component_bytes = transformed.tobytes() + + # Return a result in megabytes + return (len(signal_bytes) + len(component_bytes)) / (2**20) + +# Do an estimate for lossless compression applied on top of our +# PCA reduction +def bz2_estimate(transformed, pca): + bytestring = transformed.tobytes() + b';' + pca.components_.tobytes() + compressed = compress(bytestring) + return len(compressed) / (2**20) + +compression_attempts = [ + (1, 1), + (1, 2), + (1, 4), + (4, 32), + (16, 256), + (32, 256), + (64, 256), + (128, 1024), + (256, 1024), + (512, 1024), + (128, 2048), + (256, 2048), + (512, 2048), + (1024, 2048) +] + +def build_estimates(signal, n_components, block_size): + pca, transformed, recon = pca_reduce(tabulasa_left, n_components, block_size) + raw_pca_estimate = raw_estimate(transformed, pca) + bz2_pca_estimate = bz2_estimate(transformed, pca) + raw_size = len(recon.tobytes()) / (2**20) + return raw_size, raw_pca_estimate, bz2_pca_estimate + +pca_compression_results = pd.DataFrame([ + build_estimates(tabulasa_left, n, bs) + for n, bs in compression_attempts + ]) + +pca_compression_results.columns = ["Raw", "PCA", "PCA w/ BZ2"] +pca_compression_results.index = compression_attempts +pca_compression_results +``` + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RawPCAPCA w/ BZ2
(1, 1)69.054298138.10859716.431797
(1, 2)69.05430669.05430632.981380
(1, 4)69.05432134.52716116.715032
(4, 32)69.05444317.2636118.481735
(16, 256)69.0546888.6318364.274846
(32, 256)69.05468817.2636728.542909
(64, 256)69.05468834.52734417.097543
(128, 1024)69.05468817.2636729.430644
(256, 1024)69.05468834.52734418.870387
(512, 1024)69.05468869.05468837.800940
(128, 2048)69.0625008.6328126.185015
(256, 2048)69.06250017.26562512.366942
(512, 2048)69.06250034.53125024.736506
(1024, 2048)69.06250069.06250049.517493
+
+ + + +As we can see, there are a couple of instances where we do nearly 20 times better on storage space than the uncompressed file. Let's here what that sounds like: + + +```python +_, _, reconstructed = pca_reduce(tabulasa_left, 16, 256) +Audio(data=reconstructed[start:end], rate=samplerate) +``` + + + + + + + + + + +It sounds incredibly poor though. Let's try something that's a bit more realistic: + + +```python +_, _, reconstructed = pca_reduce(tabulasa_left, 1, 4) +Audio(data=reconstructed[start:end], rate=samplerate) +``` + + + + + + + + + + +And just out of curiosity, we can try something that has the same ratio of components to block size. This should be close to an apples-to-apples comparison. + + +```python +_, _, reconstructed = pca_reduce(tabulasa_left, 64, 256) +Audio(data=reconstructed[start:end], rate=samplerate) +``` + + + + + + + + + + +The smaller block size definitely has better high-end response, but I personally think the larger block size sounds better overall. + +## Conclusions + +So, what do I think about audio compression using PCA? + +Strangely enough, it actually works pretty well relative to what I expected. That said, it's a terrible idea in general. + +First off, you don't really save any space. The component matrix needed to actually run the PCA algorithm takes up a lot of space on its own, so it's very difficult to save space without sacrificing a huge amount of audio quality. And even then, codecs like AAC sound very nice even at bitrates that this PCA method could only dream of. + +Second, there's the issue of audio streaming. PCA relies on two components: the datastream, and a matrix used to reconstruct the original signal. While it is easy to stream the data, you can't stream that matrix. And even if you divided the stream up into small blocks to give you a small matrix, you must guarantee that the matrix arrives; if you don't have that matrix, the data stream will make no sense whatsoever. + +All said, this was an interesting experiment. It's really cool seeing PCA used for signal analysis where I haven't seen it applied before, but I don't think it will lead to any practical results. Look forward to more signal processing stuff in the future! diff --git a/blog/2016-11-01-PCA-audio-compression/index.mdx b/blog/2016-11-01-PCA-audio-compression/index.mdx new file mode 100644 index 0000000..3c3cdc8 --- /dev/null +++ b/blog/2016-11-01-PCA-audio-compression/index.mdx @@ -0,0 +1,362 @@ +--- +slug: 2016/11/pca-audio-compression +title: PCA audio compression +date: 2016-11-01 12:00:00 +authors: [bspeice] +tags: [] +--- + +In which I apply Machine Learning techniques to Digital Signal Processing to astounding failure. + + + +Towards a new (and pretty poor) compression scheme +-------------------------------------------------- + +I'm going to be working with some audio data for a while as I get prepared for a term project this semester. I'll be working (with a partner) to design a system for separating voices from music. Given my total lack of experience with [Digital Signal Processing][1] I figured that now was as good a time as ever to work on a couple of fun projects that would get me back up to speed. + +The first project I want to work on: Designing a new compression scheme for audio data. + +A Brief Introduction to Audio Compression +----------------------------------------- + +Audio files when uncompressed (files ending with `.wav`) are huge. Like, 10.5 Megabytes per minute huge. Storage is cheap these days, but that's still an incredible amount of data that we don't really need. Instead, we'd like to compress that data so that it's not taking up so much space. There are broadly two ways to accomplish this: + +1. Lossless compression - Formats like [FLAC][2], [ALAC][3], and [Monkey's Audio (.ape)][4] all go down this route. The idea is that when you compress and uncompress a file, you get exactly the same as what you started with. + +2. Lossy compression - Formats like [MP3][5], [Ogg][6], and [AAC (`.m4a`)][7] are far more popular, but make a crucial tradeoff: We can reduce the file size even more during compression, but the decompressed file won't be the same. + +There is a fundamental tradeoff at stake: Using lossy compression sacrifices some of the integrity of the resulting file to save on storage space. Most people (I personally believe it's everybody) can't hear the difference, so this is an acceptable tradeoff. You have files that take up a 10th of the space, and nobody can tell there's a difference in audio quality. + +A PCA-based Compression Scheme +------------------------------ + +What I want to try out is a [PCA][8] approach to encoding audio. The PCA technique comes from Machine Learning, where it is used for a process called [Dimensionality Reduction][9]. Put simply, the idea is the same as lossy compression: if we can find a way that represents the data well enough, we can save on space. There are a lot of theoretical concerns that lead me to believe this compression style will not end well, but I'm interested to try it nonetheless. + +PCA works as follows: Given a dataset with a number of features, I find a way to approximate those original features using some "new features" that are statistically as close as possible to the original ones. This is comparable to a scheme like MP3: Given an original signal, I want to find a way of representing it that gets approximately close to what the original was. The difference is that PCA is designed for statistical data, and not signal data. But we won't let that stop us. + +The idea is as follows: Given a signal, reshape it into 1024 columns by however many rows are needed (zero-padded if necessary). Run the PCA algorithm, and do dimensionality reduction with a couple different settings. The number of components I choose determines the quality: If I use 1024 components, I will essentially be using the original signal. If I use a smaller number of components, I start losing some of the data that was in the original file. This will give me an idea of whether it's possible to actually build an encoding scheme off of this, or whether I'm wasting my time. + +Running the Algorithm +--------------------- + +The audio I will be using comes from the song [Tabulasa][10], by [Broke for Free][11]. I'll be loading in the audio signal to Python and using [Scikit-Learn][12] to actually run the PCA algorithm. + +We first need to convert the FLAC file I have to a WAV: + +[1]: https://en.wikipedia.org/wiki/Digital_signal_processing +[2]: https://en.wikipedia.org/wiki/FLAC +[3]: https://en.wikipedia.org/wiki/Apple_Lossless +[4]: https://en.wikipedia.org/wiki/Monkey%27s_Audio +[5]: https://en.wikipedia.org/wiki/MP3 +[6]: https://en.wikipedia.org/wiki/Vorbis +[7]: https://en.wikipedia.org/wiki/Advanced_Audio_Coding +[8]: https://en.wikipedia.org/wiki/Principal_component_analysis +[9]: https://en.wikipedia.org/wiki/Dimensionality_reduction +[10]: https://brokeforfree.bandcamp.com/track/tabulasa +[11]: https://brokeforfree.bandcamp.com/album/xxvii +[12]: http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html#sklearn.decomposition.PCA + + +```python +!ffmpeg -hide_banner -loglevel panic -i "Broke For Free/XXVII/01 Tabulasa.flac" "Tabulasa.wav" -c wav +``` + +Then, let's go ahead and load a small sample so you can hear what is going on. + + +```python +from IPython.display import Audio +from scipy.io import wavfile + +samplerate, tabulasa = wavfile.read('Tabulasa.wav') + +start = samplerate * 14 # 10 seconds in +end = start + samplerate * 10 # 5 second duration +Audio(data=tabulasa[start:end, 0], rate=samplerate) +``` + +import wav1 from "./1.wav"; + +