{"id":25188,"date":"2016-09-01T19:30:32","date_gmt":"2016-09-02T00:30:32","guid":{"rendered":"http:\/\/www.dannyadam.com\/blog\/?p=25188"},"modified":"2020-02-18T14:01:30","modified_gmt":"2020-02-18T19:01:30","slug":"matrix-factorization-with-theano","status":"publish","type":"post","link":"https:\/\/www.dannyadam.com\/blog\/2016\/09\/matrix-factorization-with-theano\/","title":{"rendered":"Matrix Factorization with Theano"},"content":{"rendered":"<p>Matrix factorization algorithms factorize a matrix <em>D<\/em> into two matrices <em>P<\/em> and <em>Q<\/em>, such that <em>D<\/em>\u00a0\u2248 <em>PQ<\/em>. By limiting the dimensionality of <em>P<\/em> and <em>Q<\/em>, <em>PQ<\/em> provides a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Low-rank_approximation\">low-rank approximation<\/a> of <em>D<\/em>. While <a href=\"https:\/\/en.wikipedia.org\/wiki\/Singular_value_decomposition\">singular value decomposition<\/a> (SVD) can also be used for this same task, the matrix factorization algorithms considered in this post accommodate\u00a0missing data in matrix <em>D<\/em>, unlike SVD.<\/p>\n<p>For an overview of matrix factorization, I recommend\u00a0Albert Au Yeung&#8217;s <a href=\"http:\/\/www.quuxlabs.com\/blog\/2010\/09\/matrix-factorization-a-simple-tutorial-and-implementation-in-python\/\">tutorial<\/a>. That post describes matrix factorization, motivates the problem with\u00a0a ratings prediction task, derives the gradients used by\u00a0stochastic gradient descent, and implements the algorithm in Python.<\/p>\n<p>For exploratory work, it would be great if the algorithm could be implemented\u00a0in such a way that the gradients could be automatically derived. With such an approach, gradients would not have to be\u00a0re-derived\u00a0when e.g., a change is made to the loss function (either the error term\u00a0and\/or the regularization term). In general, automatically derived gradients for machine learning problems facilitate increased exploration of ideas by removing a time-consuming step.<\/p>\n<p><a href=\"http:\/\/deeplearning.net\/software\/theano\/\">Theano<\/a> is a Python library that allows users to specify their problem symbolically using NumPy-based syntax. The expressions are compiled to run efficiently on actual data. Theano&#8217;s webpage provides documentation and a <a href=\"http:\/\/deeplearning.net\/software\/theano\/tutorial\/index.html\">tutorial<\/a>.<\/p>\n<p>The following code includes\u00a0a Theano-based implementation of matrix factorization using batch gradient descent. The parameters are similar to those in the <a href=\"http:\/\/www.quuxlabs.com\/blog\/2010\/09\/matrix-factorization-a-simple-tutorial-and-implementation-in-python\/\">quuxlabs<\/a>\u00a0matrix factorization implementation. <em>D<\/em> is a second-order masked numpy.ndarray (e.g., a ratings matrix, where the mask indicates missing ratings), and <em>P<\/em> and <em>Q<\/em>\u00a0are the\u00a0initial matrix factors. The elements of <em>P<\/em> and <em>Q<\/em> are the parameters of the model, which are\u00a0initialized by the function&#8217;s caller. The rank of the factorization is specified by the dimensions\u00a0of <em>P<\/em> and <em>Q<\/em>. For a rank-<em>k<\/em> factorization,\u00a0<em>P<\/em> must be <img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=m+%5Ctimes+k&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"m &#92;times k\" class=\"latex\" \/> and <em>Q<\/em> must be <img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=k+%5Ctimes+n&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"k &#92;times n\" class=\"latex\" \/> (where\u00a0<em>D<\/em> is an <img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=m+%5Ctimes+n&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"m &#92;times n\" class=\"latex\" \/> matrix). Additional parameters specify the number of iterations, the learning rate, and the regularization importance.<\/p>\n<p>The code\u00a0doesn&#8217;t contain any derived gradients. It specifies the loss function and the parameters that the loss function will be minimized with respect to. Theano figures out the rest!<\/p>\n<style>.gist table { margin-bottom: 0; }<\/style>\n<div style=\"tab-size: 8\" id=\"gist39445874\" class=\"gist\">\n<div class=\"gist-file\" translate=\"no\" data-color-mode=\"light\" data-light-theme=\"light\">\n<div class=\"gist-data\">\n<div class=\"js-gist-file-update-container js-task-list-container\">\n<div id=\"file-matrix_factorization_bgd-py\" class=\"file my-2\">\n<div itemprop=\"text\"\n      class=\"Box-body p-0 blob-wrapper data type-python  \"\n      style=\"overflow: auto\" tabindex=\"0\" role=\"region\"\n      aria-label=\"matrix_factorization_bgd.py content, created by dstein64 on 10:45PM on September 01, 2016.\"\n    ><\/p>\n<div class=\"js-check-hidden-unicode js-blob-code-container blob-code-content\">\n<p>  <template class=\"js-file-alert-template\"><\/p>\n<div data-view-component=\"true\" class=\"flash flash-warn flash-full d-flex flex-items-center\">\n  <svg aria-hidden=\"true\" data-component=\"Octicon\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" data-view-component=\"true\" class=\"octicon octicon-alert\">\n    <path d=\"M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\"><\/path>\n<\/svg><br \/>\n    <span><br \/>\n      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.<br \/>\n      <a class=\"Link--inTextBlock\" href=\"https:\/\/github.co\/hiddenchars\" target=\"_blank\">Learn more about bidirectional Unicode characters<\/a><br \/>\n    <\/span><\/p>\n<div data-view-component=\"true\" class=\"flash-action\">        <a href=\"{{ revealButtonHref }}\" data-view-component=\"true\" class=\"btn-sm btn\">    Show hidden characters<br \/>\n<\/a>\n<\/div>\n<\/div>\n<p><\/template><br \/>\n<template class=\"js-line-alert-template\"><br \/>\n  <span aria-label=\"This line has hidden Unicode characters\" data-view-component=\"true\" class=\"line-alert tooltipped tooltipped-e\"><br \/>\n    <svg aria-hidden=\"true\" data-component=\"Octicon\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" data-view-component=\"true\" class=\"octicon octicon-alert\">\n    <path d=\"M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\"><\/path>\n<\/svg><br \/>\n<\/span><\/template><\/p>\n<table data-hpc class=\"highlight tab-size js-file-line-container\" data-tab-size=\"4\" data-paste-markdown-skip data-tagsearch-path=\"matrix_factorization_bgd.py\">\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L1\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"1\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC1\" class=\"blob-code blob-code-inner js-file-line\">import numpy as np<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L2\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"2\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC2\" class=\"blob-code blob-code-inner js-file-line\">import numpy.ma as ma<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L3\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"3\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC3\" class=\"blob-code blob-code-inner js-file-line\">import theano<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L4\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"4\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC4\" class=\"blob-code blob-code-inner js-file-line\">from theano import tensor as T<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L5\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"5\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC5\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L6\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"6\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC6\" class=\"blob-code blob-code-inner js-file-line\">floatX = theano.config.floatX<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L7\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"7\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC7\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L8\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"8\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC8\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L9\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"9\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC9\" class=\"blob-code blob-code-inner js-file-line\">def getmask(D):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L10\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"10\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC10\" class=\"blob-code blob-code-inner js-file-line\">  return ma.getmaskarray(D) if ma.isMA(D) else np.zeros(D.shape, dtype=bool)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L11\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"11\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC11\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L12\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"12\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC12\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L13\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"13\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC13\" class=\"blob-code blob-code-inner js-file-line\">def matrix_factorization_bgd(<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L14\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"14\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC14\" class=\"blob-code blob-code-inner js-file-line\">    D, P, Q, steps=5000, alpha=0.0002, beta=0.02):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L15\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"15\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC15\" class=\"blob-code blob-code-inner js-file-line\">  P = theano.shared(P.astype(floatX))<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L16\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"16\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC16\" class=\"blob-code blob-code-inner js-file-line\">  Q = theano.shared(Q.astype(floatX))<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L17\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"17\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC17\" class=\"blob-code blob-code-inner js-file-line\">  X = T.matrix()<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L18\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"18\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC18\" class=\"blob-code blob-code-inner js-file-line\">  error = T.sum(T.sqr(~getmask(D) * (P.dot(Q) &#8211; X)))<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L19\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"19\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC19\" class=\"blob-code blob-code-inner js-file-line\">  regularization = (beta\/2.0) * (T.sum(T.sqr(P)) + T.sum(T.sqr(Q)))<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L20\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"20\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC20\" class=\"blob-code blob-code-inner js-file-line\">  cost = error + regularization<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L21\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"21\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC21\" class=\"blob-code blob-code-inner js-file-line\">  gp, gq = T.grad(cost=cost, wrt=[P, Q])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L22\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"22\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC22\" class=\"blob-code blob-code-inner js-file-line\">  train = theano.function(inputs=[X],<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L23\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"23\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC23\" class=\"blob-code blob-code-inner js-file-line\">                          updates=[(P, P &#8211; gp * alpha), (Q, Q &#8211; gq * alpha)])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L24\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"24\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC24\" class=\"blob-code blob-code-inner js-file-line\">  for _ in xrange(steps):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L25\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"25\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC25\" class=\"blob-code blob-code-inner js-file-line\">    train(D)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_bgd-py-L26\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"26\"><\/td>\n<td id=\"file-matrix_factorization_bgd-py-LC26\" class=\"blob-code blob-code-inner js-file-line\">  return P.get_value(), Q.get_value()<\/td>\n<\/tr>\n<\/table>\n<\/div><\/div>\n<\/p><\/div>\n<\/div><\/div>\n<div class=\"gist-meta\">\n        <a href=\"https:\/\/gist.github.com\/dstein64\/69ef1d3f1e65b66e171981c378446220\/raw\/b19baeb68fedc3bfee2c3de4b17ab321db6d512a\/matrix_factorization_bgd.py\" style=\"float:right\" class=\"Link--inTextBlock\">view raw<\/a><br \/>\n        <a href=\"https:\/\/gist.github.com\/dstein64\/69ef1d3f1e65b66e171981c378446220#file-matrix_factorization_bgd-py\" class=\"Link--inTextBlock\"><br \/>\n          matrix_factorization_bgd.py<br \/>\n        <\/a><br \/>\n        hosted with &#10084; by <a class=\"Link--inTextBlock\" href=\"https:\/\/github.com\">GitHub<\/a>\n      <\/div>\n<\/p><\/div>\n<\/div>\n<p><!--more--><\/p>\n<p>The preceding code is not completely analogous to the\u00a0<a href=\"http:\/\/www.quuxlabs.com\/blog\/2010\/09\/matrix-factorization-a-simple-tutorial-and-implementation-in-python\/\">quuxlabs<\/a>\u00a0matrix factorization implementation, since their implementation uses stochastic gradient descent, and the preceding code uses batch\u00a0gradient descent.<\/p>\n<p>The Theano-based implementation below uses stochastic gradient descent. It retains automatically derived gradients, but in my opinion it&#8217;s less\u00a0elegant than the code above.<\/p>\n<style>.gist table { margin-bottom: 0; }<\/style>\n<div style=\"tab-size: 8\" id=\"gist39446250\" class=\"gist\">\n<div class=\"gist-file\" translate=\"no\" data-color-mode=\"light\" data-light-theme=\"light\">\n<div class=\"gist-data\">\n<div class=\"js-gist-file-update-container js-task-list-container\">\n<div id=\"file-matrix_factorization_sgd-py\" class=\"file my-2\">\n<div itemprop=\"text\"\n      class=\"Box-body p-0 blob-wrapper data type-python  \"\n      style=\"overflow: auto\" tabindex=\"0\" role=\"region\"\n      aria-label=\"matrix_factorization_sgd.py content, created by dstein64 on 11:03PM on September 01, 2016.\"\n    ><\/p>\n<div class=\"js-check-hidden-unicode js-blob-code-container blob-code-content\">\n<p>  <template class=\"js-file-alert-template\"><\/p>\n<div data-view-component=\"true\" class=\"flash flash-warn flash-full d-flex flex-items-center\">\n  <svg aria-hidden=\"true\" data-component=\"Octicon\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" data-view-component=\"true\" class=\"octicon octicon-alert\">\n    <path d=\"M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\"><\/path>\n<\/svg><br \/>\n    <span><br \/>\n      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.<br \/>\n      <a class=\"Link--inTextBlock\" href=\"https:\/\/github.co\/hiddenchars\" target=\"_blank\">Learn more about bidirectional Unicode characters<\/a><br \/>\n    <\/span><\/p>\n<div data-view-component=\"true\" class=\"flash-action\">        <a href=\"{{ revealButtonHref }}\" data-view-component=\"true\" class=\"btn-sm btn\">    Show hidden characters<br \/>\n<\/a>\n<\/div>\n<\/div>\n<p><\/template><br \/>\n<template class=\"js-line-alert-template\"><br \/>\n  <span aria-label=\"This line has hidden Unicode characters\" data-view-component=\"true\" class=\"line-alert tooltipped tooltipped-e\"><br \/>\n    <svg aria-hidden=\"true\" data-component=\"Octicon\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" data-view-component=\"true\" class=\"octicon octicon-alert\">\n    <path d=\"M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\"><\/path>\n<\/svg><br \/>\n<\/span><\/template><\/p>\n<table data-hpc class=\"highlight tab-size js-file-line-container\" data-tab-size=\"4\" data-paste-markdown-skip data-tagsearch-path=\"matrix_factorization_sgd.py\">\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L1\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"1\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC1\" class=\"blob-code blob-code-inner js-file-line\">def matrix_factorization_sgd(<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L2\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"2\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC2\" class=\"blob-code blob-code-inner js-file-line\">    D, P, Q, steps=5000, alpha=0.0002, beta=0.02):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L3\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"3\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC3\" class=\"blob-code blob-code-inner js-file-line\">  P = theano.shared(P.astype(floatX))<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L4\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"4\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC4\" class=\"blob-code blob-code-inner js-file-line\">  Q = theano.shared(Q.astype(floatX))<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L5\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"5\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC5\" class=\"blob-code blob-code-inner js-file-line\">  P_i = T.vector()<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L6\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"6\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC6\" class=\"blob-code blob-code-inner js-file-line\">  Q_j = T.vector()<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L7\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"7\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC7\" class=\"blob-code blob-code-inner js-file-line\">  i = T.iscalar()<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L8\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"8\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC8\" class=\"blob-code blob-code-inner js-file-line\">  j = T.iscalar()<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L9\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"9\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC9\" class=\"blob-code blob-code-inner js-file-line\">  x = T.scalar()<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L10\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"10\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC10\" class=\"blob-code blob-code-inner js-file-line\">  error = T.sqr(P_i.dot(Q_j) &#8211; x)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L11\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"11\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC11\" class=\"blob-code blob-code-inner js-file-line\">  regularization = (beta\/2.0) * (P_i.dot(P_i) + Q_j.dot(Q_j))<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L12\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"12\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC12\" class=\"blob-code blob-code-inner js-file-line\">  cost = error + regularization<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L13\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"13\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC13\" class=\"blob-code blob-code-inner js-file-line\">  gp, gq = T.grad(cost=cost, wrt=[P_i, Q_j])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L14\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"14\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC14\" class=\"blob-code blob-code-inner js-file-line\">  train = theano.function(inputs=[i, j, x],<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L15\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"15\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC15\" class=\"blob-code blob-code-inner js-file-line\">                          givens=[(P_i, P[i, :]), (Q_j, Q[:, j])],<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L16\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"16\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC16\" class=\"blob-code blob-code-inner js-file-line\">                          updates=[(P, T.inc_subtensor(P[i, :], -gp * alpha)),<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L17\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"17\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC17\" class=\"blob-code blob-code-inner js-file-line\">                                   (Q, T.inc_subtensor(Q[:, j], -gq * alpha))])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L18\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"18\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC18\" class=\"blob-code blob-code-inner js-file-line\">  for _ in xrange(steps):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L19\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"19\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC19\" class=\"blob-code blob-code-inner js-file-line\">    for (row, col), val in np.ndenumerate(D):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L20\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"20\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC20\" class=\"blob-code blob-code-inner js-file-line\">      if not getmask(D)[row, col]:<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L21\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"21\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC21\" class=\"blob-code blob-code-inner js-file-line\">        train(row, col, val)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L22\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"22\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC22\" class=\"blob-code blob-code-inner js-file-line\">  return P.get_value(), Q.get_value()<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_sgd-py-L23\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"23\"><\/td>\n<td id=\"file-matrix_factorization_sgd-py-LC23\" class=\"blob-code blob-code-inner js-file-line\">  <\/td>\n<\/tr>\n<\/table>\n<\/div><\/div>\n<\/p><\/div>\n<\/div><\/div>\n<div class=\"gist-meta\">\n        <a href=\"https:\/\/gist.github.com\/dstein64\/c541c5c79a4731cb6ee66acbd8423f50\/raw\/db9b6ce730e3800959b95b7942ebf8a1a22a0d2c\/matrix_factorization_sgd.py\" style=\"float:right\" class=\"Link--inTextBlock\">view raw<\/a><br \/>\n        <a href=\"https:\/\/gist.github.com\/dstein64\/c541c5c79a4731cb6ee66acbd8423f50#file-matrix_factorization_sgd-py\" class=\"Link--inTextBlock\"><br \/>\n          matrix_factorization_sgd.py<br \/>\n        <\/a><br \/>\n        hosted with &#10084; by <a class=\"Link--inTextBlock\" href=\"https:\/\/github.com\">GitHub<\/a>\n      <\/div>\n<\/p><\/div>\n<\/div>\n<p>Lastly, the code below runs the two Theano-based matrix factorization implementations and a modified version of the quuxlabs implementation (minor modifications were made for consistency with the code above). The input data is the same ratings matrix used in the quuxlabs post and a rank-2 approximation is used for the factorizations.<\/p>\n<style>.gist table { margin-bottom: 0; }<\/style>\n<div style=\"tab-size: 8\" id=\"gist39447434\" class=\"gist\">\n<div class=\"gist-file\" translate=\"no\" data-color-mode=\"light\" data-light-theme=\"light\">\n<div class=\"gist-data\">\n<div class=\"js-gist-file-update-container js-task-list-container\">\n<div id=\"file-matrix_factorization_compare-py\" class=\"file my-2\">\n<div itemprop=\"text\"\n      class=\"Box-body p-0 blob-wrapper data type-python  \"\n      style=\"overflow: auto\" tabindex=\"0\" role=\"region\"\n      aria-label=\"matrix_factorization_compare.py content, created by dstein64 on 11:55PM on September 01, 2016.\"\n    ><\/p>\n<div class=\"js-check-hidden-unicode js-blob-code-container blob-code-content\">\n<p>  <template class=\"js-file-alert-template\"><\/p>\n<div data-view-component=\"true\" class=\"flash flash-warn flash-full d-flex flex-items-center\">\n  <svg aria-hidden=\"true\" data-component=\"Octicon\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" data-view-component=\"true\" class=\"octicon octicon-alert\">\n    <path d=\"M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\"><\/path>\n<\/svg><br \/>\n    <span><br \/>\n      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.<br \/>\n      <a class=\"Link--inTextBlock\" href=\"https:\/\/github.co\/hiddenchars\" target=\"_blank\">Learn more about bidirectional Unicode characters<\/a><br \/>\n    <\/span><\/p>\n<div data-view-component=\"true\" class=\"flash-action\">        <a href=\"{{ revealButtonHref }}\" data-view-component=\"true\" class=\"btn-sm btn\">    Show hidden characters<br \/>\n<\/a>\n<\/div>\n<\/div>\n<p><\/template><br \/>\n<template class=\"js-line-alert-template\"><br \/>\n  <span aria-label=\"This line has hidden Unicode characters\" data-view-component=\"true\" class=\"line-alert tooltipped tooltipped-e\"><br \/>\n    <svg aria-hidden=\"true\" data-component=\"Octicon\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" data-view-component=\"true\" class=\"octicon octicon-alert\">\n    <path d=\"M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\"><\/path>\n<\/svg><br \/>\n<\/span><\/template><\/p>\n<table data-hpc class=\"highlight tab-size js-file-line-container\" data-tab-size=\"4\" data-paste-markdown-skip data-tagsearch-path=\"matrix_factorization_compare.py\">\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L1\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"1\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC1\" class=\"blob-code blob-code-inner js-file-line\">def matrix_factorization_quux(<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L2\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"2\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC2\" class=\"blob-code blob-code-inner js-file-line\">    D, P, Q, steps=5000, alpha=0.0002, beta=0.02):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L3\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"3\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC3\" class=\"blob-code blob-code-inner js-file-line\">  K = P.shape[1]<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L4\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"4\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC4\" class=\"blob-code blob-code-inner js-file-line\">  P = np.copy(P)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L5\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"5\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC5\" class=\"blob-code blob-code-inner js-file-line\">  Q = np.copy(Q)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L6\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"6\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC6\" class=\"blob-code blob-code-inner js-file-line\">  for step in xrange(steps):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L7\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"7\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC7\" class=\"blob-code blob-code-inner js-file-line\">    for i in xrange(len(D)):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L8\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"8\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC8\" class=\"blob-code blob-code-inner js-file-line\">      for j in xrange(len(D[i])):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L9\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"9\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC9\" class=\"blob-code blob-code-inner js-file-line\">        if not getmask(D)[i, j]:<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L10\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"10\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC10\" class=\"blob-code blob-code-inner js-file-line\">          eij = D[i, j] &#8211; np.dot(P[i, :], Q[:, j])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L11\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"11\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC11\" class=\"blob-code blob-code-inner js-file-line\">          for k in xrange(K):<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L12\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"12\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC12\" class=\"blob-code blob-code-inner js-file-line\">            P[i, k] = P[i, k] + alpha * (2 * eij * Q[k, j] &#8211; beta * P[i, k])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L13\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"13\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC13\" class=\"blob-code blob-code-inner js-file-line\">            Q[k, j] = Q[k, j] + alpha * (2 * eij * P[i, k] &#8211; beta * Q[k, j])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L14\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"14\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC14\" class=\"blob-code blob-code-inner js-file-line\">  return P, Q<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L15\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"15\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC15\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L16\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"16\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC16\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L17\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"17\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC17\" class=\"blob-code blob-code-inner js-file-line\">if __name__ == &#39;__main__&#39;:<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L18\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"18\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC18\" class=\"blob-code blob-code-inner js-file-line\">  D = np.array([[5,  3, -1, 1],<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L19\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"19\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC19\" class=\"blob-code blob-code-inner js-file-line\">                [4, -1, -1, 1],<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L20\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"20\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC20\" class=\"blob-code blob-code-inner js-file-line\">                [1,  1, -1, 5],<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L21\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"21\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC21\" class=\"blob-code blob-code-inner js-file-line\">                [1, -1, -1, 4],<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L22\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"22\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC22\" class=\"blob-code blob-code-inner js-file-line\">                [-1, 1,  5, 5]])<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L23\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"23\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC23\" class=\"blob-code blob-code-inner js-file-line\">  D = ma.masked_array(D, mask=D==-1)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L24\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"24\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC24\" class=\"blob-code blob-code-inner js-file-line\">  m, n = D.shape<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L25\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"25\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC25\" class=\"blob-code blob-code-inner js-file-line\">  K = 2<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L26\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"26\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC26\" class=\"blob-code blob-code-inner js-file-line\">  P = np.random.rand(m, K)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L27\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"27\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC27\" class=\"blob-code blob-code-inner js-file-line\">  Q = np.random.rand(K, n)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L28\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"28\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC28\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L29\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"29\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC29\" class=\"blob-code blob-code-inner js-file-line\">  np.set_printoptions(formatter={&#39;all&#39;: lambda x: str(x).rjust(2)})<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L30\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"30\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC30\" class=\"blob-code blob-code-inner js-file-line\">  print &#39;Ratings Matrix\\n&#39;, D, &#39;\\n&#39;<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L31\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"31\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC31\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L32\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"32\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC32\" class=\"blob-code blob-code-inner js-file-line\">  np.set_printoptions(precision = 2, formatter=None)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L33\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"33\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC33\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L34\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"34\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC34\" class=\"blob-code blob-code-inner js-file-line\">  P_theano_bgd, Q_theano_bgd = matrix_factorization_bgd(D, P, Q)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L35\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"35\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC35\" class=\"blob-code blob-code-inner js-file-line\">  print &#39;Theano Batch Gradient Descent\\n&#39;,\\<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L36\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"36\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC36\" class=\"blob-code blob-code-inner js-file-line\">    np.dot(P_theano_bgd, Q_theano_bgd), &#39;\\n&#39;<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L37\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"37\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC37\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L38\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"38\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC38\" class=\"blob-code blob-code-inner js-file-line\">  P_theano_sgd, Q_theano_sgd = matrix_factorization_sgd(D, P, Q)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L39\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"39\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC39\" class=\"blob-code blob-code-inner js-file-line\">  print &#39;Theano Stochastic Gradient Descent\\n&#39;,\\<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L40\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"40\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC40\" class=\"blob-code blob-code-inner js-file-line\">    np.dot(P_theano_sgd, Q_theano_sgd), &#39;\\n&#39;<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L41\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"41\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC41\" class=\"blob-code blob-code-inner js-file-line\">\n<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L42\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"42\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC42\" class=\"blob-code blob-code-inner js-file-line\">  P_quux, Q_quux = matrix_factorization_quux(D, P, Q)<\/td>\n<\/tr>\n<tr>\n<td id=\"file-matrix_factorization_compare-py-L43\" class=\"blob-num js-line-number js-blob-rnum\" data-line-number=\"43\"><\/td>\n<td id=\"file-matrix_factorization_compare-py-LC43\" class=\"blob-code blob-code-inner js-file-line\">  print &#39;quuxlabs\\n&#39;, np.dot(P_quux, Q_quux), &#39;\\n&#39;<\/td>\n<\/tr>\n<\/table>\n<\/div><\/div>\n<\/p><\/div>\n<\/div><\/div>\n<div class=\"gist-meta\">\n        <a href=\"https:\/\/gist.github.com\/dstein64\/c08c57707962b3033dc56b441bcd28e3\/raw\/92ee45da36887d6c516adbef59acd347152a7f6a\/matrix_factorization_compare.py\" style=\"float:right\" class=\"Link--inTextBlock\">view raw<\/a><br \/>\n        <a href=\"https:\/\/gist.github.com\/dstein64\/c08c57707962b3033dc56b441bcd28e3#file-matrix_factorization_compare-py\" class=\"Link--inTextBlock\"><br \/>\n          matrix_factorization_compare.py<br \/>\n        <\/a><br \/>\n        hosted with &#10084; by <a class=\"Link--inTextBlock\" href=\"https:\/\/github.com\">GitHub<\/a>\n      <\/div>\n<\/p><\/div>\n<\/div>\n<p>Here&#8217;s the output:<\/p>\n<pre>Ratings Matrix\r\n[[ 5  3 --  1]\r\n [ 4 -- --  1]\r\n [ 1  1 --  5]\r\n [ 1 -- --  4]\r\n [--  1  5  5]] \r\n\r\nTheano Batch Gradient Descent\r\n[[ 5.    2.98  2.76  1.  ]\r\n [ 3.98  2.38  2.38  1.  ]\r\n [ 1.07  0.85  4.75  4.99]\r\n [ 0.97  0.74  3.84  3.99]\r\n [ 1.57  1.14  4.96  5.01]] \r\n\r\nTheano Stochastic Gradient Descent\r\n[[ 4.98  2.97  2.74  1.  ]\r\n [ 3.97  2.38  2.36  1.  ]\r\n [ 1.06  0.85  4.77  4.98]\r\n [ 0.97  0.75  3.86  3.98]\r\n [ 1.54  1.13  4.96  4.99]] \r\n\r\nquuxlabs\r\n[[ 4.98  2.97  2.74  1.  ]\r\n [ 3.97  2.38  2.36  1.  ]\r\n [ 1.06  0.85  4.77  4.98]\r\n [ 0.97  0.75  3.86  3.98]\r\n [ 1.54  1.13  4.96  4.99]]\r\n<\/pre>\n<p><em>Theano Stochastic Gradient Descent<\/em> and <em>quuxlabs<\/em>\u00a0factorizations produce the same approximation for the ratings matrix, as they both use\u00a0stochastic gradient descent to learn the model parameters. The approximation from\u00a0<em>Theano Batch Gradient Descent<\/em> is slightly different, given that each iteration of batch gradient descent uses all the ratings, making it inherently different than stochastic gradient descent, which uses a single rating for each iteration.<\/p>\n<p>The full Python source code of this post\u00a0is available at\u00a0<a href=\"https:\/\/gist.github.com\/dstein64\/672132657242d279c1e1cfbbecf7c467\">https:\/\/<wbr \/>gist.github.com\/<wbr \/>dstein64\/<wbr \/>672132657242d279c1e1cfbbecf7c467<\/a>. The code was written and tested using Python 2.7, Theano\u00a00.8.2, and\u00a0NumPy\u00a01.11.1. You are welcome to use the Theano-based matrix factorization implementations\u00a0under the terms of an <a href=\"https:\/\/en.wikipedia.org\/wiki\/MIT_License\">MIT license<\/a>.\u00a0Please let me know if you have any ideas for how\u00a0my\u00a0code can be improved.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Matrix factorization algorithms factorize a matrix D into two matrices P and Q, such that D\u00a0\u2248 PQ. By limiting the dimensionality of P and Q, PQ provides a low-rank approximation of D. While singular value decomposition (SVD) can also be used for this same task, the matrix factorization algorithms considered in this post accommodate\u00a0missing data [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[46,45,36,44],"class_list":["post-25188","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-machine-learning","tag-matrix-factorization","tag-python","tag-theano"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1sCC6-6yg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/posts\/25188","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/comments?post=25188"}],"version-history":[{"count":57,"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/posts\/25188\/revisions"}],"predecessor-version":[{"id":26346,"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/posts\/25188\/revisions\/26346"}],"wp:attachment":[{"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/media?parent=25188"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/categories?post=25188"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dannyadam.com\/blog\/wp-json\/wp\/v2\/tags?post=25188"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}