├── Circulant Matrices and FFT.ipynb ├── Dynamic Programming.ipynb ├── Extra-Tree.ipynb ├── Gaussian Elimination.ipynb ├── Harmonic analysis on graphs.ipynb ├── KL Estimation for GMM.ipynb ├── Least-Squares Fitting.ipynb ├── Machine learning in Python.ipynb ├── Phase-Type Distributions.ipynb ├── README.md ├── RLLAB April 23rd 2014.ipynb ├── RM-MLE.ipynb ├── Slow Feature Analysis.ipynb ├── Starcluster and IPython tutorial.ipynb ├── comp598-fall2015.ipynb ├── comp598-semisupervised.ipynb ├── d3jupyterwidget.ipynb └── fvi_replacement.ipynb /Circulant Matrices and FFT.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Circulant Matrices and FFT\n", 15 | "\n" 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "The Hankel matrix is determined by its first column and last row" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "collapsed": false, 28 | "input": [ 29 | "from scipy.linalg import circulant, hankel, toeplitz\n", 30 | "import numpy as np\n", 31 | "from numpy.fft import fft\n", 32 | "from numpy.linalg import qr\n", 33 | "\n", 34 | "H = hankel([1, 2, 3], [3, 4, 5])\n", 35 | "print H" 36 | ], 37 | "language": "python", 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "output_type": "stream", 42 | "stream": "stdout", 43 | "text": [ 44 | "[[1 2 3]\n", 45 | " [2 3 4]\n", 46 | " [3 4 5]]\n" 47 | ] 48 | } 49 | ], 50 | "prompt_number": 7 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "The Toeplitz matrix is determined by its first column and first row" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "collapsed": false, 62 | "input": [ 63 | "T = toeplitz([3, 4, 5], [3, 2, 1])\n", 64 | "print T" 65 | ], 66 | "language": "python", 67 | "metadata": {}, 68 | "outputs": [ 69 | { 70 | "output_type": "stream", 71 | "stream": "stdout", 72 | "text": [ 73 | "[[3 2 1]\n", 74 | " [4 3 2]\n", 75 | " [5 4 3]]\n" 76 | ] 77 | } 78 | ], 79 | "prompt_number": 8 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "By flipping the columns of a Hankel matrix, we can obtain a Toeplitz matrix. This can be achieved by first forming $\\mathbf{S}$:\n", 86 | "\\begin{align}\n", 87 | "\\mathbf{S} = \\begin{bmatrix}\n", 88 | "0 & 0 & 1 \\\\\n", 89 | "0 & 1 & 0 \\\\\n", 90 | "1 & 0 & 0 \\\\\n", 91 | "\\end{bmatrix}\n", 92 | "\\end{align}\n", 93 | "\n", 94 | "and postmultiply it with $\\mathbf{H}$:\n", 95 | "\\begin{equation}\n", 96 | "H(\\mathbf{h})S = T(\\mathbf{h})\n", 97 | "\\end{equation}" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "collapsed": false, 103 | "input": [ 104 | "n = H.shape[0]\n", 105 | "S = np.fliplr(np.eye(3))\n", 106 | "print S\n", 107 | "print H.dot(S)\n", 108 | "\n", 109 | "def hankel_to_toeplitz(H):\n", 110 | " return np.fliplr(H)\n", 111 | "\n", 112 | "print hankel_to_toeplitz(H)" 113 | ], 114 | "language": "python", 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "output_type": "stream", 119 | "stream": "stdout", 120 | "text": [ 121 | "[[ 0. 0. 1.]\n", 122 | " [ 0. 1. 0.]\n", 123 | " [ 1. 0. 0.]]\n", 124 | "[[ 3. 2. 1.]\n", 125 | " [ 4. 3. 2.]\n", 126 | " [ 5. 4. 3.]]\n", 127 | "[[3 2 1]\n", 128 | " [4 3 2]\n", 129 | " [5 4 3]]\n" 130 | ] 131 | } 132 | ], 133 | "prompt_number": 9 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "We can embed a Toeplitz matrix in a circulant matrix, determined by its first column.\n" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "collapsed": false, 145 | "input": [ 146 | "def hankel_embedding(H):\n", 147 | " c_hat = np.concatenate((H[-1,:], H[:-1,0]))\n", 148 | " return (c_hat, circulant(c_hat))\n", 149 | "\n", 150 | "c_hat, C = hankel_embedding(H)\n", 151 | "print C" 152 | ], 153 | "language": "python", 154 | "metadata": {}, 155 | "outputs": [ 156 | { 157 | "output_type": "stream", 158 | "stream": "stdout", 159 | "text": [ 160 | "[[3 2 1 5 4]\n", 161 | " [4 3 2 1 5]\n", 162 | " [5 4 3 2 1]\n", 163 | " [1 5 4 3 2]\n", 164 | " [2 1 5 4 3]]\n" 165 | ] 166 | } 167 | ], 168 | "prompt_number": 10 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "and we can see that the leading principal submatrix is the Toeplitz matrix $T(h)$." 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "collapsed": false, 180 | "input": [ 181 | "np.array_equal(C[:3,:3], T)" 182 | ], 183 | "language": "python", 184 | "metadata": {}, 185 | "outputs": [ 186 | { 187 | "metadata": {}, 188 | "output_type": "pyout", 189 | "prompt_number": 11, 190 | "text": [ 191 | "True" 192 | ] 193 | } 194 | ], 195 | "prompt_number": 11 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "# Matrix-vector multiplication\n", 202 | "\n", 203 | "Let $w$ be a vector, we want to compute\n", 204 | "\\begin{align}\n", 205 | "\\mathbf{p} &= \\mathbf{H}\\mathbf{w} \\\\\n", 206 | "\\mathbf{p} &= \\mathbf{H}(h)\\mathbf{w} = \\mathbf{T}(h) \\mathbf{S} \\mathbf{w}\n", 207 | "\\end{align}\n", 208 | "\n", 209 | "We will form $\\hat{\\mathbf{w}}$ of size $2n - 1$ as follow\n", 210 | "\\begin{align}\n", 211 | "\\hat{\\mathbf{w}} = [w_n, w_{n-1}, ..., w_1, 0, ..., 0]^\\top\n", 212 | "\\end{align}\n", 213 | "\n", 214 | "Then the product of $\\mathbf{H}\\mathbf{w}$ can be recovered from \n", 215 | "\\begin{align}\n", 216 | "\\mathbf{y} = C(\\hat{\\mathbf{c}})\\hat{\\mathbf{w}}\n", 217 | "\\end{align}" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "collapsed": false, 223 | "input": [ 224 | "w = np.random.randint(10, size=3)\n", 225 | "\n", 226 | "w_hat = np.zeros((2*n-1,))\n", 227 | "w_hat[:n] = S.dot(w)\n", 228 | "\n", 229 | "y = C.dot(w_hat)[:n]\n", 230 | "print y\n", 231 | "print np.array_equal(y, H.dot(w))" 232 | ], 233 | "language": "python", 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "output_type": "stream", 238 | "stream": "stdout", 239 | "text": [ 240 | "[ 25. 36. 47.]\n", 241 | "True\n" 242 | ] 243 | } 244 | ], 245 | "prompt_number": 12 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "# Circulant matrix-vector multiplication with the FFT\n", 252 | "\n", 253 | "\\begin{align}\n", 254 | "C(\\hat{\\mathbf{c}})\\hat{\\mathbf{w}} = \\mathcal{F}^{-1}\\left(\\mathcal{F}(\\hat{\\mathbf{c}}) \\odot \\mathcal{F}(\\hat{\\mathbf{w}})\\right)\n", 255 | "\\end{align}\n", 256 | "\n", 257 | "where $\\odot$ denotes component-wise multiplication." 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "collapsed": false, 263 | "input": [ 264 | "from numpy.fft import fft\n", 265 | "\n", 266 | "y = ifft(fft(c_hat)*fft(w_hat))\n", 267 | "print y[:n]" 268 | ], 269 | "language": "python", 270 | "metadata": {}, 271 | "outputs": [ 272 | { 273 | "output_type": "stream", 274 | "stream": "stdout", 275 | "text": [ 276 | "[ 25.+0.j 36.+0.j 47.+0.j]\n" 277 | ] 278 | } 279 | ], 280 | "prompt_number": 13 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "metadata": {}, 285 | "source": [ 286 | "# Eigendecomposition of an Hankel matrix\n", 287 | "\n", 288 | "Circulant matrices are diagonalized by the FFT. \n" 289 | ] 290 | }, 291 | { 292 | "cell_type": "code", 293 | "collapsed": false, 294 | "input": [ 295 | "from numpy.linalg import eig\n", 296 | "\n", 297 | "print fft(c_hat)\n", 298 | "w, v = eig(C)\n", 299 | "print w" 300 | ], 301 | "language": "python", 302 | "metadata": {}, 303 | "outputs": [ 304 | { 305 | "output_type": "stream", 306 | "stream": "stdout", 307 | "text": [ 308 | "[ 15.+0.j 0.-4.25325404j 0.+2.62865556j 0.-2.62865556j\n", 309 | " 0.+4.25325404j]\n", 310 | "[ 1.50000000e+01+0.j 1.11022302e-15+4.25325404j\n", 311 | " 1.11022302e-15-4.25325404j 2.22044605e-16+2.62865556j\n", 312 | " 2.22044605e-16-2.62865556j]\n" 313 | ] 314 | } 315 | ], 316 | "prompt_number": 16 317 | }, 318 | { 319 | "cell_type": "code", 320 | "collapsed": false, 321 | "input": [], 322 | "language": "python", 323 | "metadata": {}, 324 | "outputs": [], 325 | "prompt_number": 14 326 | } 327 | ], 328 | "metadata": {} 329 | } 330 | ] 331 | } -------------------------------------------------------------------------------- /Dynamic Programming.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "", 4 | "signature": "sha256:cc31fac0ca28516f6d4c1f39e55e151bcb9a9c2e419c4568dc84cdd1d7c1e44e" 5 | }, 6 | "nbformat": 3, 7 | "nbformat_minor": 0, 8 | "worksheets": [ 9 | { 10 | "cells": [ 11 | { 12 | "cell_type": "code", 13 | "collapsed": false, 14 | "input": [ 15 | "import numpy as np\n", 16 | "\n", 17 | "def forest_management(n=3, p=0.1, r1=4, r2=2):\n", 18 | " P = np.zeros((n, n, 2))\n", 19 | " P[:,:,0] = (1. - p)*np.diag(np.ones(n-1), 1)\n", 20 | " P[:,0,0] = p\n", 21 | " P[-1,-1,0] = 1. - p\n", 22 | " P[:,0,1] = 1.\n", 23 | " \n", 24 | " r = np.zeros((n, 2))\n", 25 | " r[-1,0] = r1\n", 26 | " r[1:,1] = 1.\n", 27 | " r[-1,1] = r2\n", 28 | "\n", 29 | " return P, r" 30 | ], 31 | "language": "python", 32 | "metadata": {}, 33 | "outputs": [], 34 | "prompt_number": 1 35 | }, 36 | { 37 | "cell_type": "code", 38 | "collapsed": false, 39 | "input": [ 40 | "def value_iteration(P, r, gamma, epsilon, verbose=False):\n", 41 | " n, m = P.shape[0], P.shape[2]\n", 42 | " v = np.zeros(n)\n", 43 | " \n", 44 | " stopping = epsilon*(1. - gamma)/gamma\n", 45 | " span_norm = lambda v: np.max(v) - np.min(v)\n", 46 | " def bellman_update(v):\n", 47 | " Q = np.zeros((n,m))\n", 48 | " for a in range(m):\n", 49 | " Q[:, a] = r[:, a] + gamma*P[:, :, a].dot(v)\n", 50 | " return (Q.max(axis=1), v, Q.argmax(axis=1))\n", 51 | " \n", 52 | " v, vprev, policy = bellman_update(v)\n", 53 | " \n", 54 | " i = 0\n", 55 | " while span_norm(v - vprev) > stopping:\n", 56 | " if verbose: print 'Iteration {0}: {1}'.format(i, span_norm(v - vprev))\n", 57 | " v, vprev, policy = bellman_update(v)\n", 58 | " i += 1\n", 59 | " \n", 60 | " return v, policy" 61 | ], 62 | "language": "python", 63 | "metadata": {}, 64 | "outputs": [], 65 | "prompt_number": 2 66 | }, 67 | { 68 | "cell_type": "code", 69 | "collapsed": false, 70 | "input": [ 71 | "def policy_evaluation_inv(P, r, gamma, policy):\n", 72 | " n = P.shape[0]\n", 73 | " Q = np.zeros((n,n))\n", 74 | " for s in range(n):\n", 75 | " Q[s,:] = P[s,:,policy[s]]\n", 76 | " \n", 77 | " R = np.zeros(n)\n", 78 | " for s in range(n):\n", 79 | " R[s] = r[s,policy[s]]\n", 80 | " \n", 81 | " return np.linalg.solve(np.eye(Q.shape[1]) - gamma*Q, R)" 82 | ], 83 | "language": "python", 84 | "metadata": {}, 85 | "outputs": [], 86 | "prompt_number": 3 87 | }, 88 | { 89 | "cell_type": "code", 90 | "collapsed": false, 91 | "input": [ 92 | "def policy_evaluation_iter(P, r, gamma, policy):\n", 93 | " n = P.shape[0]\n", 94 | " v = np.zeros(n)\n", 95 | "\n", 96 | " Q = np.zeros((n,n))\n", 97 | " for s in range(n):\n", 98 | " Q[s,:] = P[s,:,policy[s]]\n", 99 | " Q = gamma*Q\n", 100 | " \n", 101 | " R = np.zeros(n)\n", 102 | " for s in range(n):\n", 103 | " R[s] = r[s,policy[s]]\n", 104 | " \n", 105 | " stopping = epsilon*(1. - gamma)/gamma\n", 106 | " span_norm = lambda v: np.max(v) - np.min(v)\n", 107 | " bellman_update = lambda v: (R + Q.dot(v), v)\n", 108 | "\n", 109 | " v, vprev = bellman_update(v)\n", 110 | " while span_norm(v - vprev) > stopping:\n", 111 | " v, vprev = bellman_update(v)\n", 112 | " \n", 113 | " return v" 114 | ], 115 | "language": "python", 116 | "metadata": {}, 117 | "outputs": [], 118 | "prompt_number": 4 119 | }, 120 | { 121 | "cell_type": "code", 122 | "collapsed": false, 123 | "input": [ 124 | "def policy_iteration(P, r, gamma, verbose=False):\n", 125 | " n = P.shape[0]\n", 126 | " m = P.shape[2]\n", 127 | " v = np.zeros(n)\n", 128 | " policy = np.zeros(n)\n", 129 | " policy_prev = np.ones(n)\n", 130 | "\n", 131 | " def policy_improvement(v):\n", 132 | " Q = np.zeros((n,m))\n", 133 | " for a in range(m):\n", 134 | " Q[:,a] = r[:,a] + gamma*P[:,:,a].dot(v)\n", 135 | " return (np.argmax(Q, axis=1), policy)\n", 136 | " \n", 137 | " i = 0\n", 138 | " while np.any(policy != policy_prev): \n", 139 | " v = policy_evaluation_inv(P, r, gamma, policy)\n", 140 | " policy, policy_prev = policy_improvement(v)\n", 141 | " if verbose: print 'Iteration {0}'.format(i)\n", 142 | " i += 1\n", 143 | " \n", 144 | " return policy" 145 | ], 146 | "language": "python", 147 | "metadata": {}, 148 | "outputs": [], 149 | "prompt_number": 5 150 | }, 151 | { 152 | "cell_type": "code", 153 | "collapsed": false, 154 | "input": [ 155 | "gamma, epsilon = 0.2, 0.01\n", 156 | "P, r = forest_management()" 157 | ], 158 | "language": "python", 159 | "metadata": {}, 160 | "outputs": [], 161 | "prompt_number": 6 162 | }, 163 | { 164 | "cell_type": "code", 165 | "collapsed": false, 166 | "input": [ 167 | "print 'Policy eval. by inverse', policy_evaluation_inv(P, r, gamma, [0,1,0])" 168 | ], 169 | "language": "python", 170 | "metadata": {}, 171 | "outputs": [ 172 | { 173 | "output_type": "stream", 174 | "stream": "stdout", 175 | "text": [ 176 | "Policy eval. by inverse [ 0.19067797 1.03813559 4.88269946]\n" 177 | ] 178 | } 179 | ], 180 | "prompt_number": 7 181 | }, 182 | { 183 | "cell_type": "code", 184 | "collapsed": false, 185 | "input": [ 186 | "v, policy_vi = value_iteration(P, r, gamma, epsilon)\n", 187 | "policy_pi = policy_iteration(P, r, gamma)\n", 188 | "print 'Optimal policies are equal ? {0}'.format(not np.any(policy_vi != policy_pi))\n", 189 | "print 'Optimal policy:', policy_pi\n", 190 | "print 'Policy eval. by inverse', policy_evaluation_inv(P, r, gamma, [0,1,0])\n", 191 | "print 'Policy eval. by fixed point', policy_evaluation_iter(P, r, gamma, [0,1,0])" 192 | ], 193 | "language": "python", 194 | "metadata": {}, 195 | "outputs": [ 196 | { 197 | "output_type": "stream", 198 | "stream": "stdout", 199 | "text": [ 200 | "Optimal policies are equal ? True\n", 201 | "Optimal policy: [0 1 0]\n", 202 | "Policy eval. by inverse [ 0.19067797 1.03813559 4.88269946]\n", 203 | "Policy eval. by fixed point [ 0.190152 1.03672 4.877248]\n" 204 | ] 205 | } 206 | ], 207 | "prompt_number": 8 208 | } 209 | ], 210 | "metadata": {} 211 | } 212 | ] 213 | } -------------------------------------------------------------------------------- /Extra-Tree.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "", 4 | "signature": "sha256:3b6544516ea6aebec2e1cebdddf2f82a5bc7843eca0e083a5316e91d28ac7ea0" 5 | }, 6 | "nbformat": 3, 7 | "nbformat_minor": 0, 8 | "worksheets": [ 9 | { 10 | "cells": [ 11 | { 12 | "cell_type": "code", 13 | "collapsed": false, 14 | "input": [ 15 | "class Node(object):\n", 16 | " LEFT = 0\n", 17 | " RIGHT = 1\n", 18 | " \n", 19 | " def __init__(self, cutpoint=None, attr=None):\n", 20 | " self.cutpoint = cutpoint\n", 21 | " self.attr = attr\n", 22 | " self.value = None\n", 23 | " self.left = None\n", 24 | " self.right = None\n", 25 | " \n", 26 | " def attach(self, node, leftright):\n", 27 | " if leftright == self.LEFT:\n", 28 | " self.left = node\n", 29 | " else:\n", 30 | " self.right = node\n", 31 | " \n", 32 | " def __repr__(self):\n", 33 | " return 'If {0} < {1}'.format(self.attr, self.cutpoint) if self.cutpoint else str(self.value)" 34 | ], 35 | "language": "python", 36 | "metadata": {}, 37 | "outputs": [], 38 | "prompt_number": 1 39 | }, 40 | { 41 | "cell_type": "code", 42 | "collapsed": false, 43 | "input": [ 44 | "class ExtraTreeEnsemble(object):\n", 45 | " \n", 46 | " def __init__(self, n_estimators=10, max_features=None, max_depth=5, min_samples_split=2):\n", 47 | " self.trees = [ExtraTree(max_features, max_depth, min_samples_split) for i in range(n_estimators)]\n", 48 | " \n", 49 | " def fit(self, X, y):\n", 50 | " for tree in self.trees:\n", 51 | " tree.fit(X, y)\n", 52 | " \n", 53 | " def predict(self, X):\n", 54 | " return np.mean([tree.predict(X) for tree in self.trees], axis=0)" 55 | ], 56 | "language": "python", 57 | "metadata": {}, 58 | "outputs": [], 59 | "prompt_number": 2 60 | }, 61 | { 62 | "cell_type": "code", 63 | "collapsed": false, 64 | "input": [ 65 | "class ExtraTree(object): \n", 66 | " def __init__(self, max_features=None, max_depth=5, min_samples_split=2, random_state=None):\n", 67 | " self.smin = min_samples_split\n", 68 | " self.K = max_features\n", 69 | " self.max_depth = max_depth\n", 70 | " self.root = None\n", 71 | " self.rng = numpy.random.RandomState(random_state)\n", 72 | " \n", 73 | " def fit(self, X, y):\n", 74 | " self.root = self.build(X, y, self.K, self.smin, self.max_depth)\n", 75 | " \n", 76 | " def find_leaf(self, x):\n", 77 | " node = self.root\n", 78 | " while node.cutpoint != None:\n", 79 | " node = node.left if x[node.attr] < node.cutpoint else node.right \n", 80 | " return node.value\n", 81 | " \n", 82 | " def predict(self, X):\n", 83 | " out = np.empty((X.shape[0],))\n", 84 | " for i, sample in enumerate(X):\n", 85 | " out[i] = self.find_leaf(sample)\n", 86 | " return out\n", 87 | " \n", 88 | " def isconstant_attribute(self, subset, attr, threshold=1e-7):\n", 89 | " return np.abs(np.max(subset[:,attr]) - np.min(subset[:,attr])) < threshold\n", 90 | " \n", 91 | " def isconstant_output(self, Y, threshold=1e-7):\n", 92 | " return np.abs(np.max(Y) - np.min(Y)) < threshold\n", 93 | " \n", 94 | " def nonconstant_attributes(self, subset, candidates):\n", 95 | " return [attr for attr in candidates if not self.isconstant_attribute(subset, attr)]\n", 96 | " \n", 97 | " def build(self, X, Y, K, smin, max_depth):\n", 98 | " stack, root = [], None\n", 99 | " stack.append((None, 0, 1, np.array(range(X.shape[0]))))\n", 100 | " allattributes = range(X.shape[1])\n", 101 | " \n", 102 | " while len(stack) > 0:\n", 103 | " parent, leftright, depth, subset_idx = stack.pop()\n", 104 | " subset = X[subset_idx]\n", 105 | " candidates = self.nonconstant_attributes(subset, allattributes)\n", 106 | " \n", 107 | " if depth >= max_depth or subset.shape[0] < smin \\\n", 108 | " or len(candidates) == 0 or self.isconstant_output(Y[subset_idx]):\n", 109 | " node = Node()\n", 110 | " node.value = np.mean(Y[subset_idx])\n", 111 | " parent.attach(node, leftright)\n", 112 | " else: \n", 113 | " # Select randomly K attributes, {a1,...,aK},\n", 114 | " # without replacement, among all (non constant in S)\n", 115 | " # candidate attributes;\n", 116 | " rnd_attributes = candidates #if K == None else self.rng.choice(candidates, K, replace=False)\n", 117 | "\n", 118 | " # Generate K random splits\n", 119 | " rnd_splits = [self.split(subset, attr) for attr in rnd_attributes]\n", 120 | " # Select a split s\u2217 such that score is max among all splits\n", 121 | " scores = [self.score(Y, subset_idx, subset[:,attr] < split, subset[:,attr] > split)\n", 122 | " for attr, split in zip(rnd_attributes, rnd_splits)]\n", 123 | " best_split = np.argmax(scores)\n", 124 | " best_attr = rnd_attributes[best_split]\n", 125 | " best_split_value = rnd_splits[best_split]\n", 126 | "\n", 127 | " # Create a node with the split s\u2217, attach tl and tr as left and right subtrees\n", 128 | " node = Node(best_split_value, best_attr)\n", 129 | " if parent:\n", 130 | " parent.attach(node, leftright)\n", 131 | " else:\n", 132 | " root = node\n", 133 | "\n", 134 | " # Split S into subsets Sl and Sr\n", 135 | " # Build from these subsets\n", 136 | " stack.append((node, node.LEFT, depth+1, subset_idx[subset[:,best_attr] < best_split_value]))\n", 137 | " stack.append((node, node.RIGHT, depth+1, subset_idx[subset[:,best_attr] > best_split_value]))\n", 138 | " return root\n", 139 | " \n", 140 | " def split(self, subset, attr):\n", 141 | " \"\"\" Draw a random split point for the given attribute\n", 142 | " \n", 143 | " Parameters\n", 144 | " ----------\n", 145 | " subset : ndarray\n", 146 | " Training set\n", 147 | " attr : int\n", 148 | " Attribute index\n", 149 | " \n", 150 | " Returns\n", 151 | " -------\n", 152 | " double:\n", 153 | " A random split point uniformly at random within\n", 154 | " the empirical attribute range.\n", 155 | " \"\"\"\n", 156 | " minattr = np.min(subset[:,attr], axis=0)\n", 157 | " maxattr = np.max(subset[:,attr], axis=0)\n", 158 | " return self.rng.uniform(minattr, maxattr)\n", 159 | " \n", 160 | " def score(self, Y, S, Sl, Sr):\n", 161 | " \"\"\" Relative variance reduction \n", 162 | " \n", 163 | " Parameters\n", 164 | " ----------\n", 165 | " Y : ndarray\n", 166 | " Outputs\n", 167 | " S : ndarray\n", 168 | " Training set\n", 169 | " Sl : ndarray\n", 170 | " indices for the left partition\n", 171 | " Sr : ndarray\n", 172 | " indices for the right partition\n", 173 | " \n", 174 | " Returns\n", 175 | " -------\n", 176 | " double: \n", 177 | " The relative variance reduction score as defined in Appendix A\n", 178 | " \n", 179 | " \"\"\"\n", 180 | " varout = np.var(Y[S])\n", 181 | " yleft = Y[Sl]\n", 182 | " yright = Y[Sr]\n", 183 | " Slen = float(len(S))\n", 184 | " Sl_len = float(len(yleft))\n", 185 | " Sr_len = float(len(yright))\n", 186 | "\n", 187 | " return (varout - (Sl_len/Slen)*np.var(yleft) - (Sr_len/Slen)*np.var(yright))#/varout" 188 | ], 189 | "language": "python", 190 | "metadata": {}, 191 | "outputs": [], 192 | "prompt_number": 3 193 | }, 194 | { 195 | "cell_type": "code", 196 | "collapsed": false, 197 | "input": [ 198 | "import asciitree\n", 199 | "from sklearn.datasets import load_boston\n", 200 | "boston = load_boston()\n", 201 | "tree = ExtraTree()#random_state=1234)\n", 202 | "tree.fit(boston.data, boston.target)" 203 | ], 204 | "language": "python", 205 | "metadata": {}, 206 | "outputs": [], 207 | "prompt_number": 4 208 | }, 209 | { 210 | "cell_type": "code", 211 | "collapsed": false, 212 | "input": [ 213 | "print asciitree.draw_tree(tree.root, child_iter=lambda node: [node.right, node.left] if node.cutpoint else [])" 214 | ], 215 | "language": "python", 216 | "metadata": {}, 217 | "outputs": [ 218 | { 219 | "output_type": "stream", 220 | "stream": "stdout", 221 | "text": [ 222 | "If 12 < 16.1963390612\n", 223 | " +--If 8 < 15.2832844055\n", 224 | " | +--If 5 < 5.87523268807\n", 225 | " | | +--If 11 < 119.405458946\n", 226 | " | | | +--14.9121212121\n", 227 | " | | | +--11.9\n", 228 | " | | +--If 11 < 385.807685056\n", 229 | " | | +--10.5133333333\n", 230 | " | | +--11.1866666667\n", 231 | " | +--If 8 < 2.67992808111\n", 232 | " | +--If 7 < 2.74267791276\n", 233 | " | | +--17.7678571429\n", 234 | " | | +--15.18\n", 235 | " | +--If 6 < 96.6432859794\n", 236 | " | +--17.3\n", 237 | " | +--18.3333333333\n", 238 | " +--If 4 < 0.54405933451\n", 239 | " +--If 2 < 14.7660476699\n", 240 | " | +--If 10 < 20.2815295686\n", 241 | " | | +--19.2166666667\n", 242 | " | | +--24.4208955224\n", 243 | " | +--If 4 < 0.554305138672\n", 244 | " | +--29.4434782609\n", 245 | " | +--21.47\n", 246 | " +--If 1 < 16.2681652694\n", 247 | " +--If 8 < 3.84383211697\n", 248 | " | +--27.7734177215\n", 249 | " | +--28.603125\n", 250 | " +--If 9 < 435.84389163\n", 251 | " +--22.62\n", 252 | " +--24.7879432624\n", 253 | "\n" 254 | ] 255 | } 256 | ], 257 | "prompt_number": 5 258 | }, 259 | { 260 | "cell_type": "code", 261 | "collapsed": false, 262 | "input": [ 263 | "print tree.predict(boston.data[:10])\n", 264 | "print boston.target[:10]" 265 | ], 266 | "language": "python", 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "output_type": "stream", 271 | "stream": "stdout", 272 | "text": [ 273 | "[ 28.603125 24.78794326 24.78794326 24.78794326 24.78794326\n", 274 | " 24.78794326 24.78794326 17.76785714 17.76785714 17.76785714]\n", 275 | "[ 24. 21.6 34.7 33.4 36.2 28.7 22.9 27.1 16.5 18.9]\n" 276 | ] 277 | } 278 | ], 279 | "prompt_number": 6 280 | }, 281 | { 282 | "cell_type": "code", 283 | "collapsed": false, 284 | "input": [ 285 | "from sklearn.cross_validation import train_test_split\n", 286 | "from sklearn.metrics import mean_squared_error\n", 287 | "import sklearn.ensemble\n", 288 | "\n", 289 | "X_train, X_test, y_train, y_test = train_test_split(boston.data, boston.target, test_size=0.5, random_state=1234)\n", 290 | "#reg = sklearn.ensemble.ExtraTreesRegressor(max_features=None, max_depth=5, min_samples_split=2, n_estimators=10)\n", 291 | "reg = ExtraTreeEnsemble(max_features=None, max_depth=5, min_samples_split=2, n_estimators=10)\n", 292 | "reg.fit(X_train, y_train)\n", 293 | "y_pred = reg.predict(X_test)\n", 294 | "\n", 295 | "mean_squared_error(y_test, y_pred)" 296 | ], 297 | "language": "python", 298 | "metadata": {}, 299 | "outputs": [ 300 | { 301 | "metadata": {}, 302 | "output_type": "pyout", 303 | "prompt_number": 7, 304 | "text": [ 305 | "30.210714151830381" 306 | ] 307 | } 308 | ], 309 | "prompt_number": 7 310 | }, 311 | { 312 | "cell_type": "code", 313 | "collapsed": false, 314 | "input": [], 315 | "language": "python", 316 | "metadata": {}, 317 | "outputs": [], 318 | "prompt_number": 7 319 | } 320 | ], 321 | "metadata": {} 322 | } 323 | ] 324 | } -------------------------------------------------------------------------------- /Gaussian Elimination.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "", 4 | "signature": "sha256:9a341a604bcaf7350ed2f04bac2391abd0e03fccc3b059dd45c2f1d7e3b64267" 5 | }, 6 | "nbformat": 3, 7 | "nbformat_minor": 0, 8 | "worksheets": [ 9 | { 10 | "cells": [ 11 | { 12 | "cell_type": "code", 13 | "collapsed": false, 14 | "input": [ 15 | "import numpy as np\n", 16 | "\n", 17 | "def lu_factorization(B):\n", 18 | " A = np.copy(B)\n", 19 | " n = A.shape[0]\n", 20 | " P = np.eye(n)\n", 21 | "\n", 22 | " rinterchg = np.zeros(n, dtype=np.int)\n", 23 | " for k in range(n-1):\n", 24 | " pvalue, prow = A[:,k].max(), A[:,k].argmax()\n", 25 | " \n", 26 | " if np.isclose(pvalue, 0.):\n", 27 | " rinterchg[k] = 0\n", 28 | " print 'Singular matrix'\n", 29 | " else:\n", 30 | " rinterchg[k] = prow\n", 31 | " if prow != k:\n", 32 | " A[[prow,k],:] = A[[k,prow],:]\n", 33 | " P[[prow,k],:] = P[[k,prow],:]\n", 34 | " for i in range(k+1,n):\n", 35 | " A[i,k] = A[i,k]/A[k,k]\n", 36 | " for i in range(k+1,n):\n", 37 | " A[i,k+1:] -= A[i,k]*A[k,k+1:]\n", 38 | " \n", 39 | " if np.isclose(A[-1,-1],0.):\n", 40 | " rinterchg[n-1] = 0\n", 41 | " print 'Singular matrix'\n", 42 | " else:\n", 43 | " rinterchg[n-1] = n-1\n", 44 | " \n", 45 | " L = np.eye(n)\n", 46 | " lindices = np.tril_indices(n,k=-1)\n", 47 | " L[lindices] = A[lindices]\n", 48 | " \n", 49 | " return L, np.triu(A), P" 50 | ], 51 | "language": "python", 52 | "metadata": {}, 53 | "outputs": [], 54 | "prompt_number": 1 55 | }, 56 | { 57 | "cell_type": "code", 58 | "collapsed": false, 59 | "input": [ 60 | "A = np.array([[0, 4, 1], [1, 1, 3], [2, -2, 1]], dtype=np.float64)\n", 61 | "L, U, P = lu_factorization(A)\n", 62 | "print P\n", 63 | "print L\n", 64 | "print U\n", 65 | "print P.T.dot(L).dot(U)" 66 | ], 67 | "language": "python", 68 | "metadata": {}, 69 | "outputs": [ 70 | { 71 | "output_type": "stream", 72 | "stream": "stdout", 73 | "text": [ 74 | "[[ 0. 0. 1.]\n", 75 | " [ 1. 0. 0.]\n", 76 | " [ 0. 1. 0.]]\n", 77 | "[[ 1. 0. 0. ]\n", 78 | " [ 0. 1. 0. ]\n", 79 | " [ 0.5 0.5 1. ]]\n", 80 | "[[ 2. -2. 1.]\n", 81 | " [ 0. 4. 1.]\n", 82 | " [ 0. 0. 2.]]\n", 83 | "[[ 0. 4. 1.]\n", 84 | " [ 1. 1. 3.]\n", 85 | " [ 2. -2. 1.]]\n" 86 | ] 87 | } 88 | ], 89 | "prompt_number": 2 90 | }, 91 | { 92 | "cell_type": "code", 93 | "collapsed": false, 94 | "input": [ 95 | "from scipy.linalg import lu\n", 96 | "[P,L,U] = lu(A)\n", 97 | "print P.T\n", 98 | "print L\n", 99 | "print U" 100 | ], 101 | "language": "python", 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "output_type": "stream", 106 | "stream": "stdout", 107 | "text": [ 108 | "[[ 0. 0. 1.]\n", 109 | " [ 1. 0. 0.]\n", 110 | " [ 0. 1. 0.]]\n", 111 | "[[ 1. 0. 0. ]\n", 112 | " [ 0. 1. 0. ]\n", 113 | " [ 0.5 0.5 1. ]]\n", 114 | "[[ 2. -2. 1.]\n", 115 | " [ 0. 4. 1.]\n", 116 | " [ 0. 0. 2.]]\n" 117 | ] 118 | } 119 | ], 120 | "prompt_number": 3 121 | } 122 | ], 123 | "metadata": {} 124 | } 125 | ] 126 | } -------------------------------------------------------------------------------- /Least-Squares Fitting.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "", 4 | "signature": "sha256:7df01695821e952444d75a1f6033770ef2ccfabba84bac36e7ba685ac1b0a039" 5 | }, 6 | "nbformat": 3, 7 | "nbformat_minor": 0, 8 | "worksheets": [ 9 | { 10 | "cells": [ 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "# Least-squares fitting without explicit inverses\n", 16 | "\n", 17 | "I want to show you in this notebook how you can solve a least-squares problem without having recourse to a direct application of the normal equation. If you have to use [np.linalg.inv](http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.inv.html) somewhere in your code, it should ring a bell. Explicit matrix inverses can almost always be avoided. And they should be avoided ! Here's how" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "# Synthetic example" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "collapsed": false, 30 | "input": [ 31 | "from sklearn import linear_model, datasets\n", 32 | "A, b, coef = datasets.make_regression(n_samples=1000, n_features=1,\n", 33 | " n_informative=1, noise=10,\n", 34 | " coef=True, random_state=0)\n", 35 | "plt.plot(A[:,0], b, '.')" 36 | ], 37 | "language": "python", 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "metadata": {}, 42 | "output_type": "pyout", 43 | "prompt_number": 1, 44 | "text": [ 45 | "[]" 46 | ] 47 | }, 48 | { 49 | "metadata": {}, 50 | "output_type": "display_data", 51 | "png": "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\nRdKh1soyLoL5+/Pn/YAPI5ukga3MbfaWAba3w2uv+eWcwRW18+f7TdDU+lgkc0rvyLgI5u9TiURs\nwra21soyH3oovVG7yjNFYim9I3kVzOPPmAELF1qlTbAlMsRuUThpkgV8NzmbSZpG7RVEMqegLykl\nm5SNr4vfuDHxyL6mxpqnPf20tTZ+5hkry3Qbmtx6q71PaRqR8af0jqQUv5PVtm1+cJ8/31og1NXZ\nBiXB7Q2Durrg8cftcX8/LF9u9ffz5ytNI5IrSu9IWkZrigaxE6a1tbHtj0+fjl1lm0zwGj5/vm2A\n4ihNI5I/qt6RUZuiQWxjtP5+fzFVTY3/eMIEv+TSqa+3+7Y2m5wVkcJT0JeUpY/BvWLde2tqrJbe\npXOCbYybmy2d88orVpM/eTJ84xvJUz8ikj/K6UtGOXX33rfe8ituamqsCufUKbjySltUNTho6Z6F\nC2H7dntfd7fSOCLjSW0YJKeCuf+zZ22VbFMTXHqpH9hnzoSPPvIbornyTPXFERl/6QR9pXckRjQK\ns2ZZieXs2VZl4/awDeb+6+tt5P766/5etmAj/I8+8p8PD8OcOQr4IsVC1TsSo7fXL8c8ccLSOGAX\nA5fPr6+HHTtsEvfii+Hqq22EPzhoI/qf/tQ2NrlwARoaYlsji0hhKb0jn4hGraGZ641TWWmB2+0/\nC5bKCZZsOqtWWW7fzQssXx67yla5fJHxpzp9yUhvrx/wKyr8JmktLf5Ivb3d0jsNDX7efsmSkf1y\nGhr892uVrUjxUE5fPhEs3Wxs9I8HF125mv3du21039Xl708bFL/puYgUB6V3ylywIuf++/1e9d3d\nVp3jUjsK3CLFTyWbklKwr86CBbbJePwFINOAn6qtg4iMD+X0JaO+OhMn+heA224b++RrcNcsbVQu\nUlyU0y9x6fbVWbzY2hyDTcxmM/mqHa1EipeCfolLt69Of79fuTNvXnYpGU3iihQvBf0SFo1aWWVz\nM1xyiVXauNW18YIXh2w7YgYbtIlIcdFEbgkLTtJWVcG5c/Y40WIpbWQiEn6q3ikjiSZsOzv9Pjmn\nT9v7mpqsX44Cu0jpUcO1MpJownbtWivDnDDBnkcisHOnH/CjUfs1kCzlIyKlJ5ugfw/wKrAL+Dcg\nsIaTO4ADwH7ghsDxpcAe77UfZfG3JU6iCdtIxCZlT56055/9rG1V6KSq7BGR0pNN0P8NcAXwKaAX\n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\n", 52 | "text": [ 53 | "" 54 | ] 55 | } 56 | ], 57 | "prompt_number": 1 58 | }, 59 | { 60 | "cell_type": "code", 61 | "collapsed": false, 62 | "input": [ 63 | "print coef" 64 | ], 65 | "language": "python", 66 | "metadata": {}, 67 | "outputs": [ 68 | { 69 | "output_type": "stream", 70 | "stream": "stdout", 71 | "text": [ 72 | "82.1903908408\n" 73 | ] 74 | } 75 | ], 76 | "prompt_number": 2 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "# Normal equations\n", 83 | "\n", 84 | "The solution to the least-squares problem can be found through the direct application of the normal equations:\n", 85 | "\\begin{align*}\n", 86 | "\\mathbf{A}^\\top\\mathbf{A}\\mathbf{x} = \\mathbf{A}^\\top\\mathbf{b} \\\\\n", 87 | "\\mathbf{x} = (\\mathbf{A}^\\top\\mathbf{A})^{-1}\\mathbf{A}^\\top\\mathbf{b}\n", 88 | "\\end{align*}\n", 89 | "\n", 90 | "where $\\mathbf{A}^\\top\\mathbf{A}$ is symmetric. Let's try it:" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "collapsed": false, 96 | "input": [ 97 | "coef_inv = np.linalg.inv(A.T.dot(A)).dot(A.T).dot(b)" 98 | ], 99 | "language": "python", 100 | "metadata": {}, 101 | "outputs": [], 102 | "prompt_number": 3 103 | }, 104 | { 105 | "cell_type": "code", 106 | "collapsed": false, 107 | "input": [ 108 | "print coef_inv" 109 | ], 110 | "language": "python", 111 | "metadata": {}, 112 | "outputs": [ 113 | { 114 | "output_type": "stream", 115 | "stream": "stdout", 116 | "text": [ 117 | "[ 82.11934255]\n" 118 | ] 119 | } 120 | ], 121 | "prompt_number": 4 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "But does it mean that you should compute the inverse directly ? No ! Although the inverse appears in the normal equations, we can avoid computing it. This is almost always the case in matrix computations. It is not only computationally costly, it is also numerically unstable !" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "# QR factorization\n", 135 | "\n", 136 | "Given the QR factorization of our design matrix, we can find the least-squares solution as follow:\n", 137 | "\\begin{align*}\n", 138 | "\\mathbf{A}\\mathbf{x} = \\mathbf{b} \\\\\n", 139 | "(\\mathbf{Q}\\mathbf{R})\\mathbf{x} = \\mathbf{b} \\\\\n", 140 | "\\mathbf{Q}^\\top\\mathbf{Q}\\mathbf{R}\\mathbf{x} = \\mathbf{Q}^\\top\\mathbf{b} \\\\\n", 141 | "\\mathbf{R}\\mathbf{x} = \\mathbf{Q}^\\top\\mathbf{b}\n", 142 | "\\end{align*}\n", 143 | "\n", 144 | "where the last line follows from the fact that $\\mathbf{Q}$ is othogonal. Since $\\mathbf{R}$ is triangular, we can efficiently solve the last system of equations through backward substitution:" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "collapsed": false, 150 | "input": [ 151 | "from scipy.linalg import solve_triangular\n", 152 | "Q,R = np.linalg.qr(A)\n", 153 | "solve_triangular(R, Q.T.dot(b))" 154 | ], 155 | "language": "python", 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "metadata": {}, 160 | "output_type": "pyout", 161 | "prompt_number": 5, 162 | "text": [ 163 | "array([ 82.11934255])" 164 | ] 165 | } 166 | ], 167 | "prompt_number": 5 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": {}, 172 | "source": [ 173 | "The complexity of QR is $\\frac{2}{3}n^3+n^2+\\frac{1}{3}n-2=O(n^3)$" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": {}, 179 | "source": [ 180 | "# SVD factorization\n", 181 | "\n", 182 | "What if the inverse of $\\mathbf{A}$ does not exist (not a square matrix for example) ? We can instead take the pseudo-inverse $\\mathbf{A}^+$ through the [SVD decomposition](http://www.cis.upenn.edu/~cis610/cis61009sl10.pdf):\n", 183 | "\n", 184 | "\\begin{equation}\n", 185 | "\\mathbf{A} = \\mathbf{U}\\mathbf{D}\\mathbf{V}^\\top\n", 186 | "\\end{equation}\n", 187 | "\n", 188 | "The pseudo-inverse is then given as:\n", 189 | "\\begin{equation}\n", 190 | "\\mathbf{A}^+ = \\mathbf{U}\\mathbf{D}^+\\mathbf{V}^\\top\n", 191 | "\\end{equation}\n", 192 | "\n", 193 | "The matrix $\\mathbf{D}^+$ is a diagonal matrix of the inverses of the singular values of $\\mathbf{A}$ of rank $r$:\n", 194 | "\\begin{equation}\n", 195 | "\\mathbf{D}^+ = \\mbox{diag}(1/\\lambda_1, ..., 1/\\lambda_r,..., 0, 0)\n", 196 | "\\end{equation}\n", 197 | "\n", 198 | "Note that the singular values of $\\mathbf{A}$ are the eigenvalues of $\\mathbf{A}^\\top\\mathbf{A}$. It can be shown that the least-squares solution can be obtained through:\n", 199 | "\\begin{equation}\n", 200 | "\\mathbf{x}^+ = \\mathbf{A}^+\\mathbf{b}\n", 201 | "\\end{equation}" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "collapsed": false, 207 | "input": [ 208 | "U, s, Vt = np.linalg.svd(A, full_matrices=False)\n", 209 | "Apinv = U.dot(np.diag(1./s)).dot(Vt)\n", 210 | "print Apinv.T.dot(b)" 211 | ], 212 | "language": "python", 213 | "metadata": {}, 214 | "outputs": [ 215 | { 216 | "output_type": "stream", 217 | "stream": "stdout", 218 | "text": [ 219 | "[ 82.11934255]\n" 220 | ] 221 | } 222 | ], 223 | "prompt_number": 6 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "# Standard numpy functions" 230 | ] 231 | }, 232 | { 233 | "cell_type": "markdown", 234 | "metadata": {}, 235 | "source": [ 236 | "If $\\mathbf{A}$ is full-rank, calling [numpy.linalg.solve (http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.solve.html) will invoke the LAPACK routine gesv which according to [cvxopt](http://cvxopt.org/userguide/lapack.html) uses the LU factorization." 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "collapsed": false, 242 | "input": [ 243 | "np.linalg.solve(A.T.dot(A), A.T.dot(b))" 244 | ], 245 | "language": "python", 246 | "metadata": {}, 247 | "outputs": [ 248 | { 249 | "metadata": {}, 250 | "output_type": "pyout", 251 | "prompt_number": 7, 252 | "text": [ 253 | "array([ 82.11934255])" 254 | ] 255 | } 256 | ], 257 | "prompt_number": 7 258 | }, 259 | { 260 | "cell_type": "markdown", 261 | "metadata": {}, 262 | "source": [ 263 | "Looking at the [source code](https://github.com/numpy/numpy/blob/v1.8.1/numpy/linalg/linalg.py#L1733) for [numpy.linalg.lstq](http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.lstsq.html), we see that the LAPACK function dgelsd is being invoked under the hood. The dgelsd function is based on the SVD method that we have seen above." 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "collapsed": false, 269 | "input": [ 270 | "np.linalg.lstsq(A, b)[0]" 271 | ], 272 | "language": "python", 273 | "metadata": {}, 274 | "outputs": [ 275 | { 276 | "metadata": {}, 277 | "output_type": "pyout", 278 | "prompt_number": 8, 279 | "text": [ 280 | "array([ 82.11934255])" 281 | ] 282 | } 283 | ], 284 | "prompt_number": 8 285 | } 286 | ], 287 | "metadata": {} 288 | } 289 | ] 290 | } -------------------------------------------------------------------------------- /Phase-Type Distributions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## Phase-Type distribution\n", 15 | "\n", 16 | "A discrete phase-type distribution is determined by an initial probability vector $\\pi$ and a transition matrix $\\mathbf{T}$ between the transient states. We recover the full transition matrix $\\mathbf{P}$ as follow\n", 17 | "\n", 18 | "\\begin{equation}\n", 19 | "\\mathbf{P} = \\begin{bmatrix} \\mathbf{T} & \\mathbf{t_0} \\\\ \\mathbf{0} & 1 \\end{bmatrix}\n", 20 | "\\end{equation}\n", 21 | "\n", 22 | "The vector $\\mathbf{t_0}$ contains the absorption probabilies and can be obtained from $\\mathbf{T} + \\mathbf{T_0} = \\mathbf{1}$." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "collapsed": false, 28 | "input": [ 29 | "from scipy.linalg import hankel\n", 30 | "\n", 31 | "alphainf = np.array([0, 0, 0, 1])\n", 32 | "alpha0 = np.array([0.5, 0.5, 0, 0])\n", 33 | "A = np.array([[0, 0.5, 0.5, 0], [0, 0.9, 0, 0.1],\n", 34 | " [0.6, 0, 0, 0.4], [0, 0, 0, 0]])\n", 35 | "\n", 36 | "def evaluate(alpha0, A, alphainf, t=1):\n", 37 | " return np.dot(alpha0, np.dot(np.linalg.matrix_power(A, t), alphainf))\n", 38 | "\n", 39 | "T = 100\n", 40 | "h = np.array([evaluate(alpha0, A, alphainf, t) for t in range(T)])\n", 41 | "H = hankel(h)\n", 42 | "H = H[:T/2, :T/2]\n", 43 | "#print H" 44 | ], 45 | "language": "python", 46 | "metadata": {}, 47 | "outputs": [], 48 | "prompt_number": 1 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "## Spectral Learning\n", 55 | "\n", 56 | "A WFA $A = \\langle \\mathbf{\\alpha}_0, \\mathbf{\\alpha}_\\infty, {\\mathbf{A}_\\sigma}\\rangle$ for a function $f$ and $n$ states induces a factorization of $\\mathbf{H}_f = \\mathbf{P} \\mathbf{S}$ and its sub-blocks $\\mathbf{H}_\\mathcal{B}$ for an arbitrary basis $\\mathcal{B}=(\\mathcal{P}, \\mathcal{S})$. If $A$ is minimal for $f$, then the factorization of $\\mathbf{H}_f$ is rank factorization with both $\\mathbf{P}$ and $\\mathbf{S}$ of the same rank. A rank factorization can be obtained through the compact SVD decomposition $\\mathbf{H}_\\lambda = \\mathbf{U}\\mathbf{\\Lambda}\\mathbf{V}^\\top$ with $\\mathbf{U} \\in \\mathbb{R}^{p \\times r}$, $\\mathbf{\\Lambda} \\in \\mathbb{R}^{r \\times r}$ and $\\mathbf{V} \\in \\mathbb{R}^{s \\times r}$. The above factorization can then be expressed as \n", 57 | "\\begin{align}\n", 58 | "\\mathbf{\\alpha}_0^\\top &= \\mathbf{h}_{\\lambda, \\mathcal{S}}^\\top \\mathbf{V}\\\\\n", 59 | "\\mathbf{\\alpha}_\\infty &= \\mathbf{\\Lambda^{-1}}\\mathbf{U}^\\top\\mathbf{h}_{\\mathcal{P},\\lambda} \\\\\n", 60 | "\\mathbf{A}_\\sigma &= \\mathbf{\\Lambda^{-1}}\\mathbf{U}^\\top \\mathbf{H_\\sigma}\\mathbf{V}\n", 61 | "\\end{align}" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "collapsed": false, 67 | "input": [ 68 | "from numpy.linalg import svd, inv\n", 69 | "from scipy.linalg import diagsvd\n", 70 | "\n", 71 | "k = 4\n", 72 | "Hsigma = H[1:,:]\n", 73 | "H = H[:-1,:]\n", 74 | "U, D, V = svd(H, full_matrices=False)\n", 75 | "U, D, V = U[:,:k], diagsvd(D[:k], k, k), V[:k,:]\n", 76 | "Dinv_ut = inv(D).dot(U.T)\n", 77 | "\n", 78 | "beta0 = np.dot(H[0,:], V.T)\n", 79 | "betainf = Dinv_ut.dot(H[:,0])\n", 80 | "betasigma = np.dot(Dinv_ut, np.dot(Hsigma, V.T))" 81 | ], 82 | "language": "python", 83 | "metadata": {}, 84 | "outputs": [], 85 | "prompt_number": 2 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": {}, 90 | "source": [ 91 | "## Evaluation\n", 92 | "\n", 93 | "A weighted automaton $A$ computes a function $f_A: \\sigma^* \\to \\mathbb{R}$ through the application of the initial, transition and termination components\n", 94 | "\n", 95 | "\\begin{align}\n", 96 | "f_A(x_1, ..., x_t) = \\mathbf{\\alpha}_0^\\top \\mathbf{A}_{x_1} ... \\mathbf{A}_{x_t} \\mathbf{\\alpha}_\\infty\n", 97 | "\\end{align}\n", 98 | "\n", 99 | "Our model for the phase-type distribution can now used to infer the probability of a given duration $\\tau$ by computing $\\tau$ matrix-vector multiplications. \n", 100 | "\\begin{align}\n", 101 | "f(\\tau) = f_A(\\sigma_1, ..., \\sigma_\\tau) = \\mathbf{\\alpha}_0^\\top \\mathbf{A}_{\\sigma}^\\tau \\mathbf{\\alpha}_\\infty\n", 102 | "\\end{align}\n", 103 | "\n", 104 | "The time complexity of a time query is therefore a function of $\\tau$. " 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "collapsed": false, 110 | "input": [ 111 | "print 'Factorized: ', np.array([evaluate(beta0, betasigma, betainf, t) \n", 112 | " for t in range(T)])\n", 113 | "print '\\nOriginal: ', h" 114 | ], 115 | "language": "python", 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "output_type": "stream", 120 | "stream": "stdout", 121 | "text": [ 122 | "Factorized: [ -8.36461976e-17 5.00000000e-02 1.70000000e-01 6.30000000e-02\n", 123 | " 9.42000000e-02 5.77800000e-02 6.32520000e-02 4.88268000e-02\n", 124 | " 4.73191200e-02 4.01572080e-02 3.71539872e-02 3.27095885e-02\n", 125 | " 2.97423796e-02 2.65494417e-02 2.39856225e-02 2.15214503e-02\n", 126 | " 1.93966427e-02 1.74372955e-02 1.57017672e-02 1.41256855e-02\n", 127 | " 1.27155774e-02 1.14422482e-02 1.02987615e-02 9.26835387e-03\n", 128 | " 8.34173991e-03 7.50740649e-03 6.75673227e-03 6.08101121e-03\n", 129 | " 5.47293002e-03 4.92562267e-03 4.43306638e-03 3.98975544e-03\n", 130 | " 3.59078169e-03 3.23170223e-03 2.90853254e-03 2.61767890e-03\n", 131 | " 2.35591117e-03 2.12031994e-03 1.90828799e-03 1.71745916e-03\n", 132 | " 1.54571326e-03 1.39114192e-03 1.25202773e-03 1.12682496e-03\n", 133 | " 1.01414246e-03 9.12728216e-04 8.21455395e-04 7.39309855e-04\n", 134 | " 6.65378870e-04 5.98840983e-04 5.38956884e-04 4.85061196e-04\n", 135 | " 4.36555076e-04 3.92899569e-04 3.53609612e-04 3.18248651e-04\n", 136 | " 2.86423786e-04 2.57781407e-04 2.32003266e-04 2.08802940e-04\n", 137 | " 1.87922646e-04 1.69130381e-04 1.52217343e-04 1.36995609e-04\n", 138 | " 1.23296048e-04 1.10966443e-04 9.98697988e-05 8.98828189e-05\n", 139 | " 8.08945370e-05 7.28050833e-05 6.55245750e-05 5.89721175e-05\n", 140 | " 5.30749057e-05 4.77674152e-05 4.29906736e-05 3.86916063e-05\n", 141 | " 3.48224457e-05 3.13402011e-05 2.82061810e-05 2.53855629e-05\n", 142 | " 2.28470066e-05 2.05623059e-05 1.85060753e-05 1.66554678e-05\n", 143 | " 1.49899210e-05 1.34909289e-05 1.21418360e-05 1.09276524e-05\n", 144 | " 9.83488718e-06 8.85139847e-06 7.96625862e-06 7.16963276e-06\n", 145 | " 6.45266948e-06 5.80740253e-06 5.22666228e-06 4.70399605e-06\n", 146 | " 4.23359645e-06 3.81023680e-06 3.42921312e-06 3.08629181e-06]\n", 147 | "\n", 148 | "Original: [ 0.00000000e+00 5.00000000e-02 1.70000000e-01 6.30000000e-02\n", 149 | " 9.42000000e-02 5.77800000e-02 6.32520000e-02 4.88268000e-02\n", 150 | " 4.73191200e-02 4.01572080e-02 3.71539872e-02 3.27095885e-02\n", 151 | " 2.97423796e-02 2.65494417e-02 2.39856225e-02 2.15214503e-02\n", 152 | " 1.93966427e-02 1.74372955e-02 1.57017672e-02 1.41256855e-02\n", 153 | " 1.27155774e-02 1.14422482e-02 1.02987615e-02 9.26835387e-03\n", 154 | " 8.34173991e-03 7.50740649e-03 6.75673227e-03 6.08101121e-03\n", 155 | " 5.47293002e-03 4.92562267e-03 4.43306638e-03 3.98975544e-03\n", 156 | " 3.59078169e-03 3.23170223e-03 2.90853254e-03 2.61767890e-03\n", 157 | " 2.35591117e-03 2.12031994e-03 1.90828799e-03 1.71745916e-03\n", 158 | " 1.54571326e-03 1.39114192e-03 1.25202773e-03 1.12682496e-03\n", 159 | " 1.01414246e-03 9.12728216e-04 8.21455395e-04 7.39309855e-04\n", 160 | " 6.65378870e-04 5.98840983e-04 5.38956884e-04 4.85061196e-04\n", 161 | " 4.36555076e-04 3.92899569e-04 3.53609612e-04 3.18248651e-04\n", 162 | " 2.86423786e-04 2.57781407e-04 2.32003266e-04 2.08802940e-04\n", 163 | " 1.87922646e-04 1.69130381e-04 1.52217343e-04 1.36995609e-04\n", 164 | " 1.23296048e-04 1.10966443e-04 9.98697988e-05 8.98828189e-05\n", 165 | " 8.08945370e-05 7.28050833e-05 6.55245750e-05 5.89721175e-05\n", 166 | " 5.30749057e-05 4.77674152e-05 4.29906736e-05 3.86916063e-05\n", 167 | " 3.48224457e-05 3.13402011e-05 2.82061810e-05 2.53855629e-05\n", 168 | " 2.28470066e-05 2.05623059e-05 1.85060753e-05 1.66554678e-05\n", 169 | " 1.49899210e-05 1.34909289e-05 1.21418360e-05 1.09276524e-05\n", 170 | " 9.83488718e-06 8.85139847e-06 7.96625862e-06 7.16963276e-06\n", 171 | " 6.45266948e-06 5.80740253e-06 5.22666228e-06 4.70399605e-06\n", 172 | " 4.23359645e-06 3.81023680e-06 3.42921312e-06 3.08629181e-06]\n" 173 | ] 174 | } 175 | ], 176 | "prompt_number": 3 177 | }, 178 | { 179 | "cell_type": "markdown", 180 | "metadata": {}, 181 | "source": [ 182 | "# Learning from samples\n", 183 | "\n", 184 | "We will try to characterize the approximation error with respect to the $L_1$ distance as a function of the number of samples. " 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "collapsed": false, 190 | "input": [ 191 | "from scipy import stats\n", 192 | "from itertools import *\n", 193 | "from functools import partial\n", 194 | "import matplotlib.pyplot as plt\n", 195 | "\n", 196 | "def sample_wfa(alpha0, A, alphainf):\n", 197 | " init_dist = stats.rv_discrete(values=(range(len(alpha0)), alpha0))\n", 198 | " P = [stats.rv_discrete(values=(range(len(d)), d)) for d in A]\n", 199 | " last_state = len(alpha0)-1\n", 200 | " \n", 201 | " x = init_dist.rvs()\n", 202 | " while x is not last_state:\n", 203 | " yield x\n", 204 | " x = P[x].rvs()\n", 205 | " \n", 206 | "def empirical_freq(values):\n", 207 | " f = np.zeros(np.max(values)+1)\n", 208 | " for x in values:\n", 209 | " f[x] += 1\n", 210 | " return f/float(len(values))\n", 211 | "\n", 212 | "def empirical_hankel(durations):\n", 213 | " frequencies = empirical_freq(durations)\n", 214 | " s = len(frequencies)\n", 215 | " return hankel(frequencies)[:s/2, :s/2]\n", 216 | "\n", 217 | "def spectral_wfa(H, k=2):\n", 218 | " Hsigma = H[1:,:]\n", 219 | " H = H[:-1,:]\n", 220 | " U, D, V = svd(H, full_matrices=False)\n", 221 | " U, D, V = U[:,:k], diagsvd(D[:k], k, k), V[:k,:]\n", 222 | " Dinv_ut = inv(D).dot(U.T)\n", 223 | "\n", 224 | " beta0 = np.dot(H[0,:], V.T)\n", 225 | " betainf = Dinv_ut.dot(H[:,0])\n", 226 | " betasigma = np.dot(Dinv_ut, np.dot(Hsigma, V.T))\n", 227 | " \n", 228 | " return (beta0, betasigma, betainf)\n", 229 | "\n", 230 | "lb, ub = 10, 5001\n", 231 | "X = range(lb, ub)\n", 232 | "errors = np.zeros(len(X))\n", 233 | "durations = [len(list(sample_wfa(alpha0, A, alphainf))) for i in range(lb)]\n", 234 | "for n in X:\n", 235 | " H = empirical_hankel(durations)\n", 236 | "\n", 237 | " pdist_hat = np.array([partial(evaluate, *spectral_wfa(H, k=4))(i) \n", 238 | " for i in range(100)])\n", 239 | " errors[n-lb] = np.linalg.norm(h - pdist_hat, ord=1)\n", 240 | " if not n%100:\n", 241 | " print len(durations), errors[n-lb] \n", 242 | "\n", 243 | " # Generate one more trajectory from the WFA\n", 244 | " durations.append(len(list(sample_wfa(alpha0, A, alphainf))))\n", 245 | "\n", 246 | "plt.plot(X, errors)\n", 247 | "plt.show()" 248 | ], 249 | "language": "python", 250 | "metadata": {}, 251 | "outputs": [ 252 | { 253 | "output_type": "stream", 254 | "stream": "stdout", 255 | "text": [ 256 | "100 0.148754706752\n", 257 | "200" 258 | ] 259 | }, 260 | { 261 | "output_type": "stream", 262 | "stream": "stdout", 263 | "text": [ 264 | " 0.116786315332\n", 265 | "300" 266 | ] 267 | }, 268 | { 269 | "output_type": "stream", 270 | "stream": "stdout", 271 | "text": [ 272 | " 0.144351144253\n", 273 | "400" 274 | ] 275 | }, 276 | { 277 | "output_type": "stream", 278 | "stream": "stdout", 279 | "text": [ 280 | " 0.0863355699614\n", 281 | "500" 282 | ] 283 | }, 284 | { 285 | "output_type": "stream", 286 | "stream": "stdout", 287 | "text": [ 288 | " 0.11297931197\n", 289 | "600" 290 | ] 291 | }, 292 | { 293 | "output_type": "stream", 294 | "stream": "stdout", 295 | "text": [ 296 | " 0.105627969618\n", 297 | "700" 298 | ] 299 | }, 300 | { 301 | "output_type": "stream", 302 | "stream": "stdout", 303 | "text": [ 304 | " 0.0740549727069\n", 305 | "800" 306 | ] 307 | }, 308 | { 309 | "output_type": "stream", 310 | "stream": "stdout", 311 | "text": [ 312 | " 0.11001365564\n", 313 | "900" 314 | ] 315 | }, 316 | { 317 | "output_type": "stream", 318 | "stream": "stdout", 319 | "text": [ 320 | " 0.0719856914856\n", 321 | "1000" 322 | ] 323 | }, 324 | { 325 | "output_type": "stream", 326 | "stream": "stdout", 327 | "text": [ 328 | " 0.0962170689602\n", 329 | "1100" 330 | ] 331 | }, 332 | { 333 | "output_type": "stream", 334 | "stream": "stdout", 335 | "text": [ 336 | " 0.0537371827217\n", 337 | "1200" 338 | ] 339 | }, 340 | { 341 | "output_type": "stream", 342 | "stream": "stdout", 343 | "text": [ 344 | " 0.090309481595\n", 345 | "1300" 346 | ] 347 | }, 348 | { 349 | "output_type": "stream", 350 | "stream": "stdout", 351 | "text": [ 352 | " 0.0379913860767\n", 353 | "1400" 354 | ] 355 | }, 356 | { 357 | "output_type": "stream", 358 | "stream": "stdout", 359 | "text": [ 360 | " 0.0391767215297\n", 361 | "1500" 362 | ] 363 | }, 364 | { 365 | "output_type": "stream", 366 | "stream": "stdout", 367 | "text": [ 368 | " 0.046880020938\n", 369 | "1600" 370 | ] 371 | }, 372 | { 373 | "output_type": "stream", 374 | "stream": "stdout", 375 | "text": [ 376 | " 0.0560346047961\n", 377 | "1700" 378 | ] 379 | }, 380 | { 381 | "output_type": "stream", 382 | "stream": "stdout", 383 | "text": [ 384 | " 0.051482526335\n", 385 | "1800" 386 | ] 387 | }, 388 | { 389 | "output_type": "stream", 390 | "stream": "stdout", 391 | "text": [ 392 | " 0.0461758296981\n", 393 | "1900" 394 | ] 395 | }, 396 | { 397 | "output_type": "stream", 398 | "stream": "stdout", 399 | "text": [ 400 | " 0.0399404479275\n", 401 | "2000" 402 | ] 403 | }, 404 | { 405 | "output_type": "stream", 406 | "stream": "stdout", 407 | "text": [ 408 | " 0.0262453398718\n", 409 | "2100" 410 | ] 411 | }, 412 | { 413 | "output_type": "stream", 414 | "stream": "stdout", 415 | "text": [ 416 | " 0.0220799252457\n", 417 | "2200" 418 | ] 419 | }, 420 | { 421 | "output_type": "stream", 422 | "stream": "stdout", 423 | "text": [ 424 | " 0.0232579745995\n", 425 | "2300" 426 | ] 427 | }, 428 | { 429 | "output_type": "stream", 430 | "stream": "stdout", 431 | "text": [ 432 | " 0.0229945793294\n", 433 | "2400" 434 | ] 435 | }, 436 | { 437 | "output_type": "stream", 438 | "stream": "stdout", 439 | "text": [ 440 | " 0.0259045000818\n", 441 | "2500" 442 | ] 443 | }, 444 | { 445 | "output_type": "stream", 446 | "stream": "stdout", 447 | "text": [ 448 | " 0.0225475158363\n", 449 | "2600" 450 | ] 451 | }, 452 | { 453 | "output_type": "stream", 454 | "stream": "stdout", 455 | "text": [ 456 | " 0.0151319115696\n", 457 | "2700" 458 | ] 459 | }, 460 | { 461 | "output_type": "stream", 462 | "stream": "stdout", 463 | "text": [ 464 | " 0.0136409057128\n", 465 | "2800" 466 | ] 467 | }, 468 | { 469 | "output_type": "stream", 470 | "stream": "stdout", 471 | "text": [ 472 | " 0.0198478133039\n", 473 | "2900" 474 | ] 475 | }, 476 | { 477 | "output_type": "stream", 478 | "stream": "stdout", 479 | "text": [ 480 | " 0.0279090302488\n", 481 | "3000" 482 | ] 483 | }, 484 | { 485 | "output_type": "stream", 486 | "stream": "stdout", 487 | "text": [ 488 | " 0.0266789764673\n", 489 | "3100" 490 | ] 491 | }, 492 | { 493 | "output_type": "stream", 494 | "stream": "stdout", 495 | "text": [ 496 | " 0.0279553684583\n", 497 | "3200" 498 | ] 499 | }, 500 | { 501 | "output_type": "stream", 502 | "stream": "stdout", 503 | "text": [ 504 | " 0.0297174069744\n", 505 | "3300" 506 | ] 507 | }, 508 | { 509 | "output_type": "stream", 510 | "stream": "stdout", 511 | "text": [ 512 | " 0.0286068162613\n", 513 | "3400" 514 | ] 515 | }, 516 | { 517 | "output_type": "stream", 518 | "stream": "stdout", 519 | "text": [ 520 | " 0.0300464309158\n", 521 | "3500" 522 | ] 523 | }, 524 | { 525 | "output_type": "stream", 526 | "stream": "stdout", 527 | "text": [ 528 | " 0.029916848425\n", 529 | "3600" 530 | ] 531 | }, 532 | { 533 | "output_type": "stream", 534 | "stream": "stdout", 535 | "text": [ 536 | " 0.0271357095749\n", 537 | "3700" 538 | ] 539 | }, 540 | { 541 | "output_type": "stream", 542 | "stream": "stdout", 543 | "text": [ 544 | " 0.0298006178293\n", 545 | "3800" 546 | ] 547 | }, 548 | { 549 | "output_type": "stream", 550 | "stream": "stdout", 551 | "text": [ 552 | " 0.0296620879524\n", 553 | "3900" 554 | ] 555 | }, 556 | { 557 | "output_type": "stream", 558 | "stream": "stdout", 559 | "text": [ 560 | " 0.0298798370816\n", 561 | "4000" 562 | ] 563 | }, 564 | { 565 | "output_type": "stream", 566 | "stream": "stdout", 567 | "text": [ 568 | " 0.0298303753625\n", 569 | "4100" 570 | ] 571 | }, 572 | { 573 | "output_type": "stream", 574 | "stream": "stdout", 575 | "text": [ 576 | " 0.0303644768301\n", 577 | "4200" 578 | ] 579 | }, 580 | { 581 | "output_type": "stream", 582 | "stream": "stdout", 583 | "text": [ 584 | " 0.0282981566471\n", 585 | "4300" 586 | ] 587 | }, 588 | { 589 | "output_type": "stream", 590 | "stream": "stdout", 591 | "text": [ 592 | " 0.0257440859383\n", 593 | "4400" 594 | ] 595 | }, 596 | { 597 | "output_type": "stream", 598 | "stream": "stdout", 599 | "text": [ 600 | " 0.0260895858215\n", 601 | "4500" 602 | ] 603 | }, 604 | { 605 | "output_type": "stream", 606 | "stream": "stdout", 607 | "text": [ 608 | " 0.0260678182607\n", 609 | "4600" 610 | ] 611 | }, 612 | { 613 | "output_type": "stream", 614 | "stream": "stdout", 615 | "text": [ 616 | " 0.0256440233622\n", 617 | "4700" 618 | ] 619 | }, 620 | { 621 | "output_type": "stream", 622 | "stream": "stdout", 623 | "text": [ 624 | " 0.0268507263172\n", 625 | "4800" 626 | ] 627 | }, 628 | { 629 | "output_type": "stream", 630 | "stream": "stdout", 631 | "text": [ 632 | " 0.0252498469298\n", 633 | "4900" 634 | ] 635 | }, 636 | { 637 | "output_type": "stream", 638 | "stream": "stdout", 639 | "text": [ 640 | " 0.0222466207997\n", 641 | "5000" 642 | ] 643 | }, 644 | { 645 | "output_type": "stream", 646 | "stream": "stdout", 647 | "text": [ 648 | " 0.0212167996821\n" 649 | ] 650 | }, 651 | { 652 | "metadata": {}, 653 | "output_type": "display_data", 654 | "png": "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\n", 655 | "text": [ 656 | "" 657 | ] 658 | } 659 | ], 660 | "prompt_number": 13 661 | } 662 | ], 663 | "metadata": {} 664 | } 665 | ] 666 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Science commonplaces 2 | ==================== 3 | 4 | An attempt to formalize my thoughts and learn more efficiently by explaining back. 5 | 6 | Some of the notes are half baked and might be hugely inaccurate. But that's just how learning goes 7 | 8 | On Wikipedia: [Commonplacing](http://en.wikipedia.org/wiki/Commonplace_book) 9 | -------------------------------------------------------------------------------- /RLLAB April 23rd 2014.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "" 4 | }, 5 | "nbformat": 3, 6 | "nbformat_minor": 0, 7 | "worksheets": [ 8 | { 9 | "cells": [ 10 | { 11 | "cell_type": "markdown", 12 | "metadata": { 13 | "slideshow": { 14 | "slide_type": "slide" 15 | } 16 | }, 17 | "source": [ 18 | "

Subjective localization with options maps

\n", 19 | "

Pierre-Luc Bacon

\n", 20 | "

in collaboration with Borja Balle and Doina Precup

\n", 21 | "

April 23, 2014

\n", 22 | "

McGill University

" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": { 28 | "slideshow": { 29 | "slide_type": "slide" 30 | } 31 | }, 32 | "source": [ 33 | "# Control under imperfect state information\n", 34 | "\n", 35 | "A Partially Observable Markov Decision Process is a tuple $\\langle \\mathcal{X}, \\mathcal{Y}, \\mathcal{A}, T, Z, R \\rangle$, where \n", 36 | "\n" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": { 42 | "slideshow": { 43 | "slide_type": "fragment" 44 | } 45 | }, 46 | "source": [ 47 | " $\\mathcal{X}$ is a set of states" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": { 53 | "slideshow": { 54 | "slide_type": "fragment" 55 | } 56 | }, 57 | "source": [ 58 | "$\\mathcal{Y}$ is a set of observations" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": { 64 | "slideshow": { 65 | "slide_type": "fragment" 66 | } 67 | }, 68 | "source": [ 69 | " $\\mathcal{A}$ is a set of actions\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "slideshow": { 76 | "slide_type": "fragment" 77 | } 78 | }, 79 | "source": [ 80 | " $T: \\mathcal{X} \\times \\mathcal{A} \\to \\Delta(\\mathcal{X})$ is a transition kernel \n" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "metadata": { 86 | "slideshow": { 87 | "slide_type": "fragment" 88 | } 89 | }, 90 | "source": [ 91 | "$Z$ is an observation function $Z: \\mathcal{X} \\times \\mathcal{A} \\to \\Delta(\\mathcal{Y})$" 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "metadata": { 97 | "slideshow": { 98 | "slide_type": "fragment" 99 | } 100 | }, 101 | "source": [ 102 | " $R$ is a reward function $R: \\mathcal{X} \\times \\mathcal{A} \\to \\Delta([0, R_\\text{max}])$" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": { 108 | "slideshow": { 109 | "slide_type": "fragment" 110 | } 111 | }, 112 | "source": [ 113 | "The history of a POMDP is form $x_0, y_0, a_0, x_1, y_1, a_1, ..., x_t, y_t, a_t$, but the controller only sees an __information vector__\n", 114 | "$I_t = (y_0, y_1, ..., y_t, ..., a_0,a_1, ..., a_t)$\n" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": { 120 | "slideshow": { 121 | "slide_type": "slide" 122 | } 123 | }, 124 | "source": [ 125 | "In a finite discounted POMDP, we have a discount factor $\\gamma \\in [0, 1)$ and the objective is to maximize\n", 126 | "$$\\begin{equation}\n", 127 | "V_\\pi = \\mathbb{E}\\left\\{ \\sum_{t=0}^\\infty \\gamma^t R(X_t, A_t)\\right\\}\n", 128 | "\\end{equation}$$\n", 129 | "\n", 130 | "The objective remains the same as in the perfectly observable setting but our policy is now a function an information vector." 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": { 136 | "slideshow": { 137 | "slide_type": "-" 138 | } 139 | }, 140 | "source": [ 141 | "$\\pi: \\mathcal{I} \\to \\Delta(\\mathcal{A})$" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": { 147 | "slideshow": { 148 | "slide_type": "slide" 149 | } 150 | }, 151 | "source": [ 152 | "The information vector increases with time. What we would truly want is some compact state representation to be used as a substitute: a __sufficient statistics__. " 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": { 158 | "slideshow": { 159 | "slide_type": "fragment" 160 | } 161 | }, 162 | "source": [ 163 | "A trivial example of a sufficient statistics would be the identity function." 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": { 169 | "slideshow": { 170 | "slide_type": "fragment" 171 | } 172 | }, 173 | "source": [ 174 | "The conditional probability distribution $\\mathbb{P}\\left\\{ X_{t+1} \\,\\middle|\\, I_t \\right\\}$ is the *de facto* sufficient statistics. It can be generated recursively through a Bayesian update \n", 175 | "\n", 176 | "$$\\begin{equation}\n", 177 | "\\mathbf{p}_{x_{t+1} |\\, I_{t+1}} = \\Phi_t \\left(\\mathbf{p}_{x_t |\\, I_t}, a_t, y_{t+1}\\right)\n", 178 | "\\end{equation}$$" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": { 184 | "slideshow": { 185 | "slide_type": "slide" 186 | } 187 | }, 188 | "source": [ 189 | "# Predictive state representations\n", 190 | "\n", 191 | "PSR uses conditional probability distributions over future __tests__ given some __history__ as a sufficient statistics." 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "$$\\begin{equation}\n", 199 | "P: \\left\\{\\mathcal{Y} \\times \\mathcal{A}\\right\\}^* \\to \\Delta( \\left\\{\\mathcal{Y} \\times \\mathcal{A}\\right\\}^* )\n", 200 | "\\end{equation}$$" 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": {}, 206 | "source": [ 207 | "The same kind of recursive update also exists in this case." 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": { 213 | "slideshow": { 214 | "slide_type": "slide" 215 | } 216 | }, 217 | "source": [ 218 | "# Options\n", 219 | "\n", 220 | "An __option__ is a tuple $\\langle \\mathcal{I}, \\pi, \\mathcal{B} \\rangle$" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": { 226 | "slideshow": { 227 | "slide_type": "fragment" 228 | } 229 | }, 230 | "source": [ 231 | "$\\mathcal{I} \\subseteq \\mathcal{X}$ is the __initiation set__ " 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": { 237 | "slideshow": { 238 | "slide_type": "fragment" 239 | } 240 | }, 241 | "source": [ 242 | "$\\pi: \\mathcal{X} \\to \\Delta(\\mathcal{A})$ is a policy (stochastic in this case)" 243 | ] 244 | }, 245 | { 246 | "cell_type": "markdown", 247 | "metadata": { 248 | "slideshow": { 249 | "slide_type": "fragment" 250 | } 251 | }, 252 | "source": [ 253 | "$\\beta$ is a __termination function__ (a probability distribution over $\\mathcal{X}$)" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": { 259 | "slideshow": { 260 | "slide_type": "fragment" 261 | } 262 | }, 263 | "source": [ 264 | "We usually have a set of options $\\mathcal{O}$ and we might want to learn a __behavior policy__ $\\pi: \\mathcal{X} \\to \\Delta(\\mathcal{O})$" 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": { 270 | "slideshow": { 271 | "slide_type": "slide" 272 | } 273 | }, 274 | "source": [ 275 | "# Duration models\n", 276 | "\n", 277 | "While potentially more compact than *standard* POMDP, PSRs might still be challenging to learn. Our bet is that a simpler PSR-like sufficient statistics might be " 278 | ] 279 | }, 280 | { 281 | "cell_type": "markdown", 282 | "metadata": {}, 283 | "source": [ 284 | "$$\\begin{equation}\n", 285 | "P: \\mathcal{O} \\to \\Delta(\\mathbb{D})\n", 286 | "\\end{equation}$$\n", 287 | "\n", 288 | "where $\\mathcal{O}$ is a set of __options__ and $\\mathbb{D}$ is a set of __durations__ (say $\\mathbb{Z}$)." 289 | ] 290 | }, 291 | { 292 | "cell_type": "markdown", 293 | "metadata": {}, 294 | "source": [ 295 | "" 453 | ] 454 | }, 455 | { 456 | "cell_type": "markdown", 457 | "metadata": { 458 | "slideshow": { 459 | "slide_type": "slide" 460 | } 461 | }, 462 | "source": [ 463 | "

Proofs and experiments are yet to come...

\n", 464 | "\n", 465 | "

But we known how to learn these distributions !

" 466 | ] 467 | }, 468 | { 469 | "cell_type": "markdown", 470 | "metadata": { 471 | "slideshow": { 472 | "slide_type": "slide" 473 | } 474 | }, 475 | "source": [ 476 | "## Phase-Type distribution\n", 477 | "\n", 478 | "\"Red\n" 480 | ] 481 | }, 482 | { 483 | "cell_type": "markdown", 484 | "metadata": { 485 | "slideshow": { 486 | "slide_type": "slide" 487 | } 488 | }, 489 | "source": [ 490 | "A discrete phase-type distribution is determined by an initial probability vector $\\mathbf{\\mu}$ and a transition matrix $\\mathbf{T}$ between the transient states. We recover the full transition matrix $\\mathbf{Q}$ as follow\n", 491 | "\n", 492 | "$$\\begin{equation}\n", 493 | "\\mathbf{Q} = \\begin{bmatrix} \\mathbf{T} & \\mathbf{t_0} \\\\ \\mathbf{0} & 1 \\end{bmatrix}\n", 494 | "\\end{equation}$$\n", 495 | "\n", 496 | "The vector $\\mathbf{t_0}$ contains the absorption probabilies and can be obtained from $\\mathbf{T} + \\mathbf{T_0} = \\mathbf{1}$." 497 | ] 498 | }, 499 | { 500 | "cell_type": "markdown", 501 | "metadata": {}, 502 | "source": [ 503 | "## Evaluation\n", 504 | "\n", 505 | "A weighted automaton $A$ computes a function $f_A: \\sigma^* \\to \\mathbb{R}$ through the application of the initial, transition and termination components\n", 506 | "\n", 507 | "$$\\begin{align}\n", 508 | "f_A(x_1, ..., x_t) = \\mathbf{\\alpha}_0^\\top \\mathbf{A}_{x_1} ... \\mathbf{A}_{x_t} \\mathbf{\\alpha}_\\infty\n", 509 | "\\end{align}$$\n", 510 | "\n", 511 | "Our model for the phase-type distribution can now used to infer the probability of a given duration $\\tau$ by computing $\\tau$ matrix-vector multiplications. \n", 512 | "$$\\begin{align}\n", 513 | "f(\\tau) = \\mathbf{\\alpha}_0^\\top \\mathbf{A}_{\\sigma}^\\tau \\mathbf{\\alpha}_\\infty\n", 514 | "\\end{align}$$\n", 515 | "\n", 516 | "The time complexity of a time query is therefore a function of $\\tau$. " 517 | ] 518 | }, 519 | { 520 | "cell_type": "markdown", 521 | "metadata": { 522 | "slideshow": { 523 | "slide_type": "slide" 524 | } 525 | }, 526 | "source": [ 527 | "## Spectral Learning\n", 528 | "\n", 529 | "A WFA $A = \\langle \\mathbf{\\alpha}_0, \\mathbf{\\alpha}_\\infty, {\\mathbf{A}_\\sigma}\\rangle$ for a function $f$ and $n$ states induces a factorization of $\\mathbf{H}_f = \\mathbf{P} \\mathbf{S}$ and its sub-blocks $\\mathbf{H}_\\mathcal{B}$ for an arbitrary basis $\\mathcal{B}=(\\mathcal{P}, \\mathcal{S})$. \n", 530 | "\n", 531 | "A rank factorization can be obtained through the compact SVD decomposition $\\mathbf{H}_\\lambda = \\mathbf{U}\\mathbf{\\Lambda}\\mathbf{V}^\\top$ with $\\mathbf{U} \\in \\mathbb{R}^{p \\times r}$, $\\mathbf{\\Lambda} \\in \\mathbb{R}^{r \\times r}$ and $\\mathbf{V} \\in \\mathbb{R}^{s \\times r}$. \n", 532 | "\n", 533 | "$$\\begin{align}\n", 534 | "\\mathbf{\\alpha}_0^\\top &= \\mathbf{h}_{\\lambda, \\mathcal{S}}^\\top \\mathbf{V}\\\\\n", 535 | "\\mathbf{\\alpha}_\\infty &= \\mathbf{\\Lambda^{-1}}\\mathbf{U}^\\top\\mathbf{h}_{\\mathcal{P},\\lambda} \\\\\n", 536 | "\\mathbf{A}_\\sigma &= \\mathbf{\\Lambda^{-1}}\\mathbf{U}^\\top \\mathbf{H_\\sigma}\\mathbf{V}\n", 537 | "\\end{align}$$" 538 | ] 539 | }, 540 | { 541 | "cell_type": "heading", 542 | "level": 2, 543 | "metadata": { 544 | "slideshow": { 545 | "slide_type": "slide" 546 | } 547 | }, 548 | "source": [ 549 | "Hankel matrix of a known system" 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "collapsed": false, 555 | "input": [ 556 | "from scipy.linalg import hankel\n", 557 | "\n", 558 | "alphainf = np.array([0, 0, 0, 1])\n", 559 | "alpha0 = np.array([0.5, 0.5, 0, 0])\n", 560 | "A = np.array([[0, 0.5, 0.5, 0], [0, 0.9, 0, 0.1],\n", 561 | " [0.6, 0, 0, 0.4], [0, 0, 0, 0]])\n", 562 | "\n", 563 | "def evaluate(alpha0, A, alphainf, t=1):\n", 564 | " return np.dot(alpha0, np.dot(np.linalg.matrix_power(A, t), alphainf))\n", 565 | "\n", 566 | "T = 100\n", 567 | "h = np.array([evaluate(alpha0, A, alphainf, t) for t in range(T)])\n", 568 | "H = hankel(h)\n", 569 | "H = H[:T/2, :T/2]\n", 570 | "print H[:5, :5]" 571 | ], 572 | "language": "python", 573 | "metadata": { 574 | "slideshow": { 575 | "slide_type": "-" 576 | } 577 | }, 578 | "outputs": [ 579 | { 580 | "output_type": "stream", 581 | "stream": "stdout", 582 | "text": [ 583 | "[[ 0. 0.05 0.17 0.063 0.0942 ]\n", 584 | " [ 0.05 0.17 0.063 0.0942 0.05778 ]\n", 585 | " [ 0.17 0.063 0.0942 0.05778 0.063252 ]\n", 586 | " [ 0.063 0.0942 0.05778 0.063252 0.0488268 ]\n", 587 | " [ 0.0942 0.05778 0.063252 0.0488268 0.04731912]]\n" 588 | ] 589 | } 590 | ], 591 | "prompt_number": 1 592 | }, 593 | { 594 | "cell_type": "heading", 595 | "level": 2, 596 | "metadata": { 597 | "slideshow": { 598 | "slide_type": "slide" 599 | } 600 | }, 601 | "source": [ 602 | "Recovering the automaton" 603 | ] 604 | }, 605 | { 606 | "cell_type": "code", 607 | "collapsed": false, 608 | "input": [ 609 | "from numpy.linalg import svd, inv\n", 610 | "from scipy.linalg import diagsvd\n", 611 | "\n", 612 | "def spectral_wfa(H, k=2):\n", 613 | " Hsigma = H[1:,:]\n", 614 | " H = H[:-1,:]\n", 615 | " U, D, V = svd(H, full_matrices=False)\n", 616 | " U, D, V = U[:,:k], diagsvd(D[:k], k, k), V[:k,:]\n", 617 | " Dinv_ut = inv(D).dot(U.T)\n", 618 | "\n", 619 | " beta0 = np.dot(H[0,:], V.T)\n", 620 | " betainf = Dinv_ut.dot(H[:,0])\n", 621 | " betasigma = np.dot(Dinv_ut, np.dot(Hsigma, V.T))\n", 622 | " \n", 623 | " return (beta0, betasigma, betainf)\n", 624 | "\n", 625 | "beta0, betasigma, betainf = spectral_wfa(H, k=4)\n", 626 | "pdist_hat = np.array([evaluate(beta0, betasigma, betainf, t) \n", 627 | " for t in range(T)])\n", 628 | "print 'Recovered: ', pdist_hat[:10]\n", 629 | "print 'Original: ', h[:10]\n", 630 | "print 'L1 error: ', np.linalg.norm(h - pdist_hat, ord=1)" 631 | ], 632 | "language": "python", 633 | "metadata": { 634 | "slideshow": { 635 | "slide_type": "-" 636 | } 637 | }, 638 | "outputs": [ 639 | { 640 | "output_type": "stream", 641 | "stream": "stdout", 642 | "text": [ 643 | "Recovered: [ -8.36461976e-17 5.00000000e-02 1.70000000e-01 6.30000000e-02\n", 644 | " 9.42000000e-02 5.77800000e-02 6.32520000e-02 4.88268000e-02\n", 645 | " 4.73191200e-02 4.01572080e-02]\n", 646 | "Original: [ 0. 0.05 0.17 0.063 0.0942 0.05778\n", 647 | " 0.063252 0.0488268 0.04731912 0.04015721]\n", 648 | "L1 error: 5.30906232944e-15\n" 649 | ] 650 | } 651 | ], 652 | "prompt_number": 2 653 | }, 654 | { 655 | "cell_type": "markdown", 656 | "metadata": { 657 | "slideshow": { 658 | "slide_type": "slide" 659 | } 660 | }, 661 | "source": [ 662 | "# Learning from samples\n", 663 | "\n", 664 | "We will try to characterize the approximation error with respect to the $L_1$ distance as a function of the number of samples. " 665 | ] 666 | }, 667 | { 668 | "cell_type": "code", 669 | "collapsed": false, 670 | "input": [ 671 | "from scipy import stats\n", 672 | "from itertools import *\n", 673 | "from functools import partial\n", 674 | "import matplotlib.pyplot as plt\n", 675 | "\n", 676 | "def sample_wfa(alpha0, A, alphainf):\n", 677 | " init_dist = stats.rv_discrete(values=(range(len(alpha0)), alpha0))\n", 678 | " P = [stats.rv_discrete(values=(range(len(d)), d)) for d in A]\n", 679 | " last_state = len(alpha0)-1\n", 680 | " \n", 681 | " x = init_dist.rvs()\n", 682 | " while x is not last_state:\n", 683 | " yield x\n", 684 | " x = P[x].rvs()\n", 685 | " \n", 686 | "def empirical_freq(values):\n", 687 | " f = np.zeros(np.max(values)+1)\n", 688 | " for x in values:\n", 689 | " f[x] += 1\n", 690 | " return f/float(len(values))\n", 691 | "\n", 692 | "def empirical_hankel(durations):\n", 693 | " frequencies = empirical_freq(durations)\n", 694 | " s = len(frequencies)\n", 695 | " return hankel(frequencies)[:s/2, :s/2]" 696 | ], 697 | "language": "python", 698 | "metadata": {}, 699 | "outputs": [], 700 | "prompt_number": 3 701 | }, 702 | { 703 | "cell_type": "markdown", 704 | "metadata": { 705 | "slideshow": { 706 | "slide_type": "slide" 707 | } 708 | }, 709 | "source": [ 710 | "# Recovering the automaton from samples" 711 | ] 712 | }, 713 | { 714 | "cell_type": "code", 715 | "collapsed": false, 716 | "input": [ 717 | "lb, ub, inc = 10, 4001, 10\n", 718 | "X = range(lb, ub, inc)\n", 719 | "errors, durations = [], []\n", 720 | "for n in X:\n", 721 | " durations.extend([len(list(sample_wfa(alpha0, A, alphainf))) for i in range(inc)])\n", 722 | " \n", 723 | " H = empirical_hankel(durations)\n", 724 | " automaton = spectral_wfa(H, k=4)\n", 725 | " \n", 726 | " pdist_hat = np.array([partial(evaluate, *automaton)(i) for i in range(100)])\n", 727 | " errors.append(np.linalg.norm(h - pdist_hat, ord=1))\n", 728 | " \n", 729 | " if not n%1000:\n", 730 | " print len(durations), errors[-1]" 731 | ], 732 | "language": "python", 733 | "metadata": {}, 734 | "outputs": [ 735 | { 736 | "output_type": "stream", 737 | "stream": "stdout", 738 | "text": [ 739 | "1000 0.06079182736\n", 740 | "2000" 741 | ] 742 | }, 743 | { 744 | "output_type": "stream", 745 | "stream": "stdout", 746 | "text": [ 747 | " 0.05529009822\n", 748 | "3000" 749 | ] 750 | }, 751 | { 752 | "output_type": "stream", 753 | "stream": "stdout", 754 | "text": [ 755 | " 0.0592218955868\n", 756 | "4000" 757 | ] 758 | }, 759 | { 760 | "output_type": "stream", 761 | "stream": "stdout", 762 | "text": [ 763 | " 0.0328719987897\n" 764 | ] 765 | } 766 | ], 767 | "prompt_number": 4 768 | }, 769 | { 770 | "cell_type": "code", 771 | "collapsed": false, 772 | "input": [ 773 | "plt.plot(X, errors)\n", 774 | "plt.show()" 775 | ], 776 | "language": "python", 777 | "metadata": { 778 | "slideshow": { 779 | "slide_type": "slide" 780 | } 781 | }, 782 | "outputs": [ 783 | { 784 | "metadata": {}, 785 | "output_type": "display_data", 786 | "png": "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\n0sD/A0ZCwcFxvyzEAAAAAElFTkSuQmCC\n", 787 | "text": [ 788 | "" 789 | ] 790 | } 791 | ], 792 | "prompt_number": 5 793 | }, 794 | { 795 | "cell_type": "markdown", 796 | "metadata": { 797 | "slideshow": { 798 | "slide_type": "slide" 799 | } 800 | }, 801 | "source": [ 802 | "# Fast Hankel matrix-vector multiplications\n", 803 | "## An excursion in frequency space\n", 804 | "\n", 805 | "Let $\\mathbf{H}$ be a Hankel matrix" 806 | ] 807 | }, 808 | { 809 | "cell_type": "code", 810 | "collapsed": false, 811 | "input": [ 812 | "from scipy.linalg import hankel, circulant\n", 813 | "H = hankel([1, 2, 3], [3, 4, 5])\n", 814 | "print H" 815 | ], 816 | "language": "python", 817 | "metadata": {}, 818 | "outputs": [ 819 | { 820 | "output_type": "stream", 821 | "stream": "stdout", 822 | "text": [ 823 | "[[1 2 3]\n", 824 | " [2 3 4]\n", 825 | " [3 4 5]]\n" 826 | ] 827 | } 828 | ], 829 | "prompt_number": 6 830 | }, 831 | { 832 | "cell_type": "markdown", 833 | "metadata": {}, 834 | "source": [ 835 | "and $\\mathbf{w}$ some arbitrary vector" 836 | ] 837 | }, 838 | { 839 | "cell_type": "code", 840 | "collapsed": false, 841 | "input": [ 842 | "w = np.random.randint(10, size=3)\n", 843 | "print w" 844 | ], 845 | "language": "python", 846 | "metadata": {}, 847 | "outputs": [ 848 | { 849 | "output_type": "stream", 850 | "stream": "stdout", 851 | "text": [ 852 | "[2 0 8]\n" 853 | ] 854 | } 855 | ], 856 | "prompt_number": 7 857 | }, 858 | { 859 | "cell_type": "markdown", 860 | "metadata": { 861 | "slideshow": { 862 | "slide_type": "slide" 863 | } 864 | }, 865 | "source": [ 866 | "If we want to compute\n", 867 | "$$\\begin{align}\n", 868 | "\\mathbf{p} &= \\mathbf{H}\\mathbf{w} \\\\\n", 869 | "\\end{align}$$\n", 870 | "\n", 871 | "we can form $\\widehat{\\mathbf{w}}$ of size $2n - 1$ as follow\n", 872 | "$$\\begin{align}\n", 873 | "\\widehat{\\mathbf{w}} = [w_n, w_{n-1}, ..., w_1, 0, ..., 0]^\\top\n", 874 | "\\end{align}$$" 875 | ] 876 | }, 877 | { 878 | "cell_type": "code", 879 | "collapsed": false, 880 | "input": [ 881 | "n = H.shape[0]\n", 882 | "w_hat = np.zeros((2*n-1,))\n", 883 | "w_hat[:n] = w[::-1]\n", 884 | "print w_hat" 885 | ], 886 | "language": "python", 887 | "metadata": {}, 888 | "outputs": [ 889 | { 890 | "output_type": "stream", 891 | "stream": "stdout", 892 | "text": [ 893 | "[ 8. 0. 2. 0. 0.]\n" 894 | ] 895 | } 896 | ], 897 | "prompt_number": 8 898 | }, 899 | { 900 | "cell_type": "markdown", 901 | "metadata": { 902 | "slideshow": { 903 | "slide_type": "-" 904 | } 905 | }, 906 | "source": [ 907 | "We can then recover the product by embeddding the Hankel matrix into a __circulant__ matrix $\\mathbf{C}$ and computing\n", 908 | "$$\\begin{align}\n", 909 | "\\mathbf{y} = C(\\widehat{\\mathbf{c}})\\widehat{\\mathbf{w}}\n", 910 | "\\end{align}$$" 911 | ] 912 | }, 913 | { 914 | "cell_type": "code", 915 | "collapsed": false, 916 | "input": [ 917 | "def hankel_embedding(H):\n", 918 | " c_hat = np.concatenate((H[-1,:], H[:-1,0]))\n", 919 | " return (c_hat, circulant(c_hat))\n", 920 | "\n", 921 | "c_hat, C = hankel_embedding(H)\n", 922 | "y = C.dot(w_hat)[:n]\n", 923 | "print y\n", 924 | "print np.allclose(y, H.dot(w))" 925 | ], 926 | "language": "python", 927 | "metadata": {}, 928 | "outputs": [ 929 | { 930 | "output_type": "stream", 931 | "stream": "stdout", 932 | "text": [ 933 | "[ 26. 36. 46.]\n", 934 | "True\n" 935 | ] 936 | } 937 | ], 938 | "prompt_number": 9 939 | }, 940 | { 941 | "cell_type": "markdown", 942 | "metadata": { 943 | "slideshow": { 944 | "slide_type": "slide" 945 | } 946 | }, 947 | "source": [ 948 | "# Now hang on to your hat...\n", 949 | "\n", 950 | "It turns out that we can perform the same matrix-vector multiplication as follow\n", 951 | "\n", 952 | "$$\\begin{align}\n", 953 | "C(\\widehat{\\mathbf{c}})\\widehat{\\mathbf{w}} = \\mathcal{F}^{-1}\\left(\\mathcal{F}(\\widehat{\\mathbf{c}}) \\odot \\mathcal{F}(\\widehat{\\mathbf{w}})\\right)\n", 954 | "\\end{align}$$\n", 955 | "\n", 956 | "where $\\odot$ denotes component-wise multiplication." 957 | ] 958 | }, 959 | { 960 | "cell_type": "code", 961 | "collapsed": false, 962 | "input": [ 963 | "from numpy.fft import fft\n", 964 | "\n", 965 | "y = ifft(fft(c_hat)*fft(w_hat))\n", 966 | "\n", 967 | "print y[:n].real\n", 968 | "print np.allclose(y[:n].real, H.dot(w))" 969 | ], 970 | "language": "python", 971 | "metadata": {}, 972 | "outputs": [ 973 | { 974 | "output_type": "stream", 975 | "stream": "stdout", 976 | "text": [ 977 | "[ 26. 36. 46.]\n", 978 | "True\n" 979 | ] 980 | } 981 | ], 982 | "prompt_number": 10 983 | }, 984 | { 985 | "cell_type": "markdown", 986 | "metadata": {}, 987 | "source": [ 988 | "And this is very exciting because the FFT is $O(n \\log n)$ while the vanilla matrix-vector multiplication is $O(n^2)$" 989 | ] 990 | } 991 | ], 992 | "metadata": {} 993 | } 994 | ] 995 | } -------------------------------------------------------------------------------- /RM-MLE.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "", 4 | "signature": "sha256:5c14354a1186fdd57ad235e474294905fd12af669f171697ed013574bb36dc7d" 5 | }, 6 | "nbformat": 3, 7 | "nbformat_minor": 0, 8 | "worksheets": [ 9 | { 10 | "cells": [ 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "# The origins of SGD in Robbins-Monro \n", 16 | "\n", 17 | "In the following, we cast our classification problem under the empirical risk minimization framework. More precisely, we will consider the case where the error function is a decomposable as a sum of individual error contributions from each training pattern:\n", 18 | "\\begin{equation}\n", 19 | "\\sum_{i} E(\\mathbf{e}_i^\\top \\mathbf{X}, t_i)\n", 20 | "\\end{equation}\n", 21 | "\n", 22 | "where $E$ is a per-instance error function and where the matrix $\\mathbf{X}$ consists of the training instances as rows and has as many columns as the dimensionality of the input vectors. While the sum-of-squares error function is commonplace in the regression setting, we will rather consider the negative log-likelihood criterion for our classification task:\n", 23 | "\\begin{equation}\n", 24 | "E(\\mathbf{x}, t) = -\\log(y_t)\n", 25 | "\\end{equation}\n", 26 | "\n", 27 | "In this expression, we used $y_t$ to denote activation of the output neuron of the true class $t$.Under the probabilistic interpretation obtained through the softmax transformation, we can think of the above cost function as being equivalent to the cross-entropy measure. From a coding perspective, the cross-entropy measures the number of bits necessary when some other distribution is used instead of the true one. \n", 28 | "\n", 29 | "Because of the non-linearities introduced in our model, we can no longer solve the empirical risk minimization problem either in closed-form or through standard convex optimization methods. We will then have recourse to the stochastic approximation framework to update the parameters (the weights and biases) of our model in an incremental fashion. The Robbins-Monro (RM) algorithm (see \\cite{Bishop1995} section 2.4.1) was initially introduced for the problem of root-finding for stochastic functions. That is, we assume that samples of pairs (in the unidimensional setting) of correlated variables are available from which one can compute their empirical averages as a proxy to their expectation. A stochastic function $f$ is defined in terms of the conditional expectation of $X$ given $Y$:\n", 30 | "\\begin{equation*}\n", 31 | "f(Y) = \\mathbb{E}\\left\\{ X | Y\\right\\}\n", 32 | "\\end{equation*}\n", 33 | "\n", 34 | "The RM algorithms then solves for the values $X^*$ such that \n", 35 | "\\begin{equation*}\n", 36 | "f(X^*) = 0\n", 37 | "\\end{equation*}\n", 38 | "\n", 39 | "A sequence of updates of the following form can be shown to converge to $X^*$:\n", 40 | "\\begin{equation*}\n", 41 | "X_{t+1} = X_t + \\alpha_t X(Y)\n", 42 | "\\end{equation*}\n", 43 | "\n", 44 | "where $X(Y)$ stands for the observed value of $X$ when $Y$ occurs. The $\\alpha$ coefficients, which we sometimes refer to as the *learning rate*, must obey the following conditions in order for the RM algorithm to converge:\n", 45 | "\\begin{align}\n", 46 | "\\lim_{t \\to \\infty} \\alpha_t = 0 \\hspace{5mm} \\sum_{t=1}^\\infty a_t = \\infty \\hspace{5mm} \\sum_{t=1}^\\infty a^2_t < \\infty\n", 47 | "\\end{align}\n", 48 | "\n", 49 | "A remarkable consequence of the existence of the RM algorithm is that we can now use it to solve maximum likelihood parameter estimates (MLE). That is, the MLE $\\hat{\\theta}$ of the parameters of some probabilistic model is found by solving for \n", 50 | "\\begin{equation}\n", 51 | "\\frac{\\partial}{\\partial\\theta}\\left( \\prod_{n=1}^N \\mathbb{P}\\left\\{x_n | \\theta \\right\\} \\right) = 0\n", 52 | "\\end{equation}\n", 53 | "\n", 54 | "We apply the usual trick of transforming the above product into a sum by taking the log. Taking the limit of the log-transformed derive, we would find that:\n", 55 | "\\begin{equation}\n", 56 | "\\mathbb{E}\\left\\{ \\frac{\\partial}{\\partial \\theta} \\ln \\mathbb{P} \\left\\{ x | \\theta \\right\\} \\right\\} = 0\n", 57 | "\\end{equation}\n", 58 | "\n", 59 | "The above is the asymptotical equivalent of the maximum likelihood estimate. The RM algorithm would then apply readily and compute the following updates:\n", 60 | "\\begin{equation}\n", 61 | "\\theta_{t+1} = \\theta_t + \\alpha_t \\frac{\\partial}{\\partial \\theta} \\ln \\mathbb{P}\\left\\{ x_{t+1} | \\theta \\right\\} \n", 62 | "\\end{equation}\n", 63 | "\n", 64 | "Under the negative log-likehood criterion, we can therefore see how the RM algorithm can be used to find parameters for an artificial neural network. In order to do so, we will however have to find the derivative of the loss function with respect to the parameters. This will be achieved through the backpropagation algorithm. \n", 65 | "\n", 66 | "## Reference\n", 67 | "\n", 68 | "For a better explanation, take a look at Bishop 1995 section 2.4.1" 69 | ] 70 | } 71 | ], 72 | "metadata": {} 73 | } 74 | ] 75 | } -------------------------------------------------------------------------------- /d3jupyterwidget.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import ipywidgets as widgets\n", 12 | "from traitlets import Unicode, CInt\n", 13 | "\n", 14 | "class HelloWidget(widgets.DOMWidget):\n", 15 | " _view_name = Unicode('HelloView').tag(sync=True)\n", 16 | " _view_module = Unicode('hello').tag(sync=True)\n", 17 | " radius = CInt(20).tag(sync=True)" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 2, 23 | "metadata": { 24 | "collapsed": false 25 | }, 26 | "outputs": [ 27 | { 28 | "data": { 29 | "application/javascript": [ 30 | "require.config({\n", 31 | " paths: {\n", 32 | " d3: \"https://d3js.org/d3.v3.min\"\n", 33 | " }\n", 34 | "});\n", 35 | "\n", 36 | "require.undef('hello');\n", 37 | "define('hello', [\"jupyter-js-widgets\", \"d3\"], function(widgets, d3) {\n", 38 | "\n", 39 | " var HelloView = widgets.DOMWidgetView.extend({\n", 40 | "\n", 41 | " render: function() {\n", 42 | " this.svg = d3.select(this.el).append('svg')\n", 43 | " .attr('width', 250)\n", 44 | " .attr('height', 250)\n", 45 | " .append('g')\n", 46 | " .attr('transform', 'scale(1)');\n", 47 | " \n", 48 | "\n", 49 | " this.robot = this.svg.append('circle')\n", 50 | " .attr('cx', 100)\n", 51 | " .attr('cy', 100)\n", 52 | " .attr('r', this.model.get('radius'))\n", 53 | " .attr('fill', '#FF0')\n", 54 | " .attr('stroke', '#000');\n", 55 | "\n", 56 | " this.model.on('change:radius', this.value_changed, this);\n", 57 | " },\n", 58 | "\n", 59 | " value_changed: function() {\n", 60 | " this.robot.attr('r', this.model.get('radius'));\n", 61 | " },\n", 62 | " });\n", 63 | "\n", 64 | " return {\n", 65 | " HelloView : HelloView\n", 66 | " };\n", 67 | "});" 68 | ], 69 | "text/plain": [ 70 | "" 71 | ] 72 | }, 73 | "metadata": {}, 74 | "output_type": "display_data" 75 | } 76 | ], 77 | "source": [ 78 | "%%javascript\n", 79 | "require.config({\n", 80 | " paths: {\n", 81 | " d3: \"https://d3js.org/d3.v3.min\"\n", 82 | " }\n", 83 | "});\n", 84 | "\n", 85 | "require.undef('hello');\n", 86 | "define('hello', [\"jupyter-js-widgets\", \"d3\"], function(widgets, d3) {\n", 87 | "\n", 88 | " var HelloView = widgets.DOMWidgetView.extend({\n", 89 | "\n", 90 | " render: function() {\n", 91 | " this.svg = d3.select(this.el).append('svg')\n", 92 | " .attr('width', 250)\n", 93 | " .attr('height', 250)\n", 94 | " .append('g')\n", 95 | " .attr('transform', 'scale(1)');\n", 96 | " \n", 97 | "\n", 98 | " this.robot = this.svg.append('circle')\n", 99 | " .attr('cx', 100)\n", 100 | " .attr('cy', 100)\n", 101 | " .attr('r', this.model.get('radius'))\n", 102 | " .attr('fill', '#FF0')\n", 103 | " .attr('stroke', '#000');\n", 104 | "\n", 105 | " this.model.on('change:radius', this.value_changed, this);\n", 106 | " },\n", 107 | "\n", 108 | " value_changed: function() {\n", 109 | " this.robot.attr('r', this.model.get('radius'));\n", 110 | " },\n", 111 | " });\n", 112 | "\n", 113 | " return {\n", 114 | " HelloView : HelloView\n", 115 | " };\n", 116 | "});" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 3, 122 | "metadata": { 123 | "collapsed": false 124 | }, 125 | "outputs": [], 126 | "source": [ 127 | "w = HelloWidget()" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 4, 133 | "metadata": { 134 | "collapsed": true 135 | }, 136 | "outputs": [], 137 | "source": [ 138 | "w" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 5, 144 | "metadata": { 145 | "collapsed": false 146 | }, 147 | "outputs": [], 148 | "source": [ 149 | "w.radius = 45" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": null, 155 | "metadata": { 156 | "collapsed": true 157 | }, 158 | "outputs": [], 159 | "source": [] 160 | } 161 | ], 162 | "metadata": { 163 | "kernelspec": { 164 | "display_name": "Python 3", 165 | "language": "python", 166 | "name": "python3" 167 | }, 168 | "language_info": { 169 | "codemirror_mode": { 170 | "name": "ipython", 171 | "version": 3 172 | }, 173 | "file_extension": ".py", 174 | "mimetype": "text/x-python", 175 | "name": "python", 176 | "nbconvert_exporter": "python", 177 | "pygments_lexer": "ipython3", 178 | "version": "3.5.1" 179 | }, 180 | "widgets": { 181 | "state": { 182 | "026c20491c3f43bb8d7fff7634aa102f": { 183 | "views": [] 184 | }, 185 | "15e91fa2a904482d883c467ec0908797": { 186 | "views": [] 187 | }, 188 | "1c7a5665a34a4a418f1bbe39b11edd7e": { 189 | "views": [] 190 | }, 191 | "37f8885f5d3a418e9202f5e509dfdfda": { 192 | "views": [] 193 | }, 194 | "3b8180827cae4385904d3f17870f9651": { 195 | "views": [] 196 | }, 197 | "44263f82728f4173b94b593f3a4f991f": { 198 | "views": [] 199 | }, 200 | "45ce6e50583a4981b63c1ddb578c0437": { 201 | "views": [] 202 | }, 203 | "45d9590ddebd482c8d719205615d3eb5": { 204 | "views": [] 205 | }, 206 | "71b6bbfa79fc4ee3ab8f51d14386adea": { 207 | "views": [] 208 | }, 209 | "761905984e434770858e50c42753485a": { 210 | "views": [] 211 | }, 212 | "80e3276410d749cda462f14b414bd951": { 213 | "views": [ 214 | { 215 | "cell": { 216 | "cell_type": "code", 217 | "execution_count": 4, 218 | "metadata": { 219 | "collapsed": true, 220 | "trusted": true 221 | }, 222 | "outputs": [], 223 | "source": "w" 224 | }, 225 | "cell_index": 3, 226 | "root": true 227 | } 228 | ] 229 | }, 230 | "8e3ef2f09170472c942cb0571e76ea23": { 231 | "views": [] 232 | }, 233 | "a3857cdd997d4123b9e5ccd78d7f5a1a": { 234 | "views": [] 235 | }, 236 | "a83e2210dd4146169569c111fe76e6bb": { 237 | "views": [] 238 | }, 239 | "b91fd99de9a94f84b8fa351dfc11f59e": { 240 | "views": [] 241 | }, 242 | "bc4228542f054c18b63d675c7a0f62d2": { 243 | "views": [] 244 | }, 245 | "c96dd445d670496e9f537b65d10d0513": { 246 | "views": [] 247 | }, 248 | "d65b04799b4140649374814f5d9d5c7d": { 249 | "views": [] 250 | }, 251 | "dca1a763a9db46988dbf1f8bc06c03ed": { 252 | "views": [] 253 | }, 254 | "edf935dd617745a5896bfc5139366a7f": { 255 | "views": [] 256 | } 257 | }, 258 | "version": "1.0.0" 259 | } 260 | }, 261 | "nbformat": 4, 262 | "nbformat_minor": 0 263 | } 264 | -------------------------------------------------------------------------------- /fvi_replacement.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 7, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "%matplotlib inline\n", 12 | "import matplotlib.pyplot as plt\n", 13 | "import numpy as np\n", 14 | "from numpy.polynomial.polynomial import polyvander as poly" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 60, 20 | "metadata": { 21 | "collapsed": false 22 | }, 23 | "outputs": [ 24 | { 25 | "data": { 26 | "text/plain": [ 27 | "(0, 10)" 28 | ] 29 | }, 30 | "execution_count": 60, 31 | "metadata": {}, 32 | "output_type": "execute_result" 33 | }, 34 | { 35 | "data": { 36 | "image/png": "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\nFY0AAAAASUVORK5CYII=\n", 37 | "text/plain": [ 38 | "" 39 | ] 40 | }, 41 | "metadata": {}, 42 | "output_type": "display_data" 43 | } 44 | ], 45 | "source": [ 46 | "norder = 4\n", 47 | "nsim = 10\n", 48 | "nbasepoints = 100\n", 49 | "\n", 50 | "discount = 0.6\n", 51 | "C, beta, xmax = -30, 2, 10\n", 52 | "keep_action, replace_action = 0, 1\n", 53 | "\n", 54 | "weights = np.zeros((norder+1,))\n", 55 | "\n", 56 | "rng = np.random.RandomState(1234)\n", 57 | "basepoints = rng.uniform(0, 10, nbasepoints)\n", 58 | "rewards_keep = -4.*basepoints\n", 59 | "reward_replace = C\n", 60 | "\n", 61 | "for i in range(40):\n", 62 | " next_states_keep = rng.exponential(beta, (nbasepoints, nsim)) + basepoints[:,np.newaxis]\n", 63 | " overbound_states = (next_states_keep > xmax)\n", 64 | " next_states_keep[overbound_states] = rng.exponential(beta, np.sum(overbound_states))\n", 65 | " v_keep = np.mean(rewards_keep[:, np.newaxis] + discount*np.dot(poly(next_states_keep, deg=norder), weights), axis=1)\n", 66 | "\n", 67 | " next_state_replace = rng.exponential(beta, (nbasepoints, nsim))\n", 68 | " v_replace = np.mean(reward_replace + discount*np.dot(poly(next_state_replace, deg=norder), weights), axis=1)\n", 69 | " vhat = np.max(np.column_stack((v_keep, v_replace)), axis=1)\n", 70 | " qhat = np.argmax(np.column_stack((v_keep, v_replace)), axis=1)\n", 71 | "\n", 72 | " weights = np.linalg.lstsq(poly(basepoints, deg=norder), vhat)[0]\n", 73 | " indices = np.argsort(basepoints)\n", 74 | " if i == 1 or i == 19:\n", 75 | " plt.plot(basepoints[indices], np.dot(poly(basepoints, deg=norder), weights)[indices])\n", 76 | " plt.scatter(basepoints, vhat, marker='.')\n", 77 | " \n", 78 | "plt.axvline(4.867, linestyle='dotted', c='k') \n", 79 | "plt.axhline(-48.67, linestyle='dotted', c='k') \n", 80 | "plt.xlim(0, 10)\n", 81 | "#plt.ylim(0, 10)\n", 82 | "#plt.savefig('inventory.pdf')" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 61, 88 | "metadata": { 89 | "collapsed": false 90 | }, 91 | "outputs": [ 92 | { 93 | "data": { 94 | "text/plain": [ 95 | "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", 96 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,\n", 97 | " 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n", 98 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n", 99 | " 1, 1, 1, 1, 1, 1, 1, 1])" 100 | ] 101 | }, 102 | "execution_count": 61, 103 | "metadata": {}, 104 | "output_type": "execute_result" 105 | } 106 | ], 107 | "source": [ 108 | "qhat[indices]" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": { 115 | "collapsed": true 116 | }, 117 | "outputs": [], 118 | "source": [] 119 | } 120 | ], 121 | "metadata": { 122 | "kernelspec": { 123 | "display_name": "Python 3", 124 | "language": "python", 125 | "name": "python3" 126 | }, 127 | "language_info": { 128 | "codemirror_mode": { 129 | "name": "ipython", 130 | "version": 3 131 | }, 132 | "file_extension": ".py", 133 | "mimetype": "text/x-python", 134 | "name": "python", 135 | "nbconvert_exporter": "python", 136 | "pygments_lexer": "ipython3", 137 | "version": "3.5.1" 138 | } 139 | }, 140 | "nbformat": 4, 141 | "nbformat_minor": 0 142 | } 143 | --------------------------------------------------------------------------------