You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@madlib.apache.org by ri...@apache.org on 2016/10/25 22:45:26 UTC

incubator-madlib git commit: PCA: Update train and project docs

Repository: incubator-madlib
Updated Branches:
  refs/heads/master d62bfbe52 -> e4e93e090


PCA: Update train and project docs

Closes #72


Project: http://git-wip-us.apache.org/repos/asf/incubator-madlib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-madlib/commit/e4e93e09
Tree: http://git-wip-us.apache.org/repos/asf/incubator-madlib/tree/e4e93e09
Diff: http://git-wip-us.apache.org/repos/asf/incubator-madlib/diff/e4e93e09

Branch: refs/heads/master
Commit: e4e93e0904f17b612799be226952d0c3bda0200d
Parents: d62bfbe
Author: Frank McQuillan <fm...@pivotal.io>
Authored: Tue Oct 25 15:43:57 2016 -0700
Committer: Rahul Iyer <ri...@apache.org>
Committed: Tue Oct 25 15:43:57 2016 -0700

----------------------------------------------------------------------
 src/ports/postgres/modules/pca/pca.sql_in       | 200 +++++++++++++------
 .../postgres/modules/pca/pca_project.sql_in     | 143 ++++++++-----
 2 files changed, 234 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/e4e93e09/src/ports/postgres/modules/pca/pca.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/pca/pca.sql_in b/src/ports/postgres/modules/pca/pca.sql_in
index 7873bdf..9f573f3 100644
--- a/src/ports/postgres/modules/pca/pca.sql_in
+++ b/src/ports/postgres/modules/pca/pca.sql_in
@@ -41,11 +41,11 @@ constraint that it be orthogonal to (i.e., uncorrelated with) the preceding
 components.
 
 See the \ref background_pca "Technical Background" for an introduction to
- principal component analysis and the implementation notes.
+ principal component analysis.
 
 @anchor train
 @par Training Function
-The training functions have the following formats:
+The training functions are slightly different for dense and sparse matrices.  For dense matrices:
 <pre class="syntax">
 pca_train( source_table,
            out_table,
@@ -57,15 +57,15 @@ pca_train( source_table,
            result_summary_table
          )
 </pre>
-and
+For sparse matrices:
 <pre class="syntax">
 pca_sparse_train( source_table,
                   out_table,
                   row_id,
-                  col_id,
-                  val_id,
-                  row_dim,
-                  col_dim,
+                  col_id,			-- Sparse matrices only
+                  val_id,			-- Sparse matrices only
+                  row_dim,			-- Sparse matrices only
+                  col_dim,			-- Sparse matrices only
                   components_param,
                   grouping_cols,
                   lanczos_iter,
@@ -86,7 +86,7 @@ A dense input table is expected to be in the one of the
 two standard  MADlib dense matrix formats, and  a sparse input table
  should be in the standard MADlib sparse matrix format.
 
-The two standard MADlib dense matrix formats are
+The two standard MADlib dense matrix formats are:
 <pre>{TABLE|VIEW} <em>source_table</em> (
     <em>row_id</em> INTEGER,
     <em>row_vec</em> FLOAT8[],
@@ -115,11 +115,13 @@ The input table for sparse PCA is expected to be in the form:
 The <em>row_id</em> and <em>col_id</em> columns specify which entries
 in the matrix are nonzero, and the <em>val_id</em> column defines the values
 of the nonzero entries.
+
+Please refer to the \ref grp_matrix documentation for more details on defining matrices.
 </DD>
 
 <DT>out_table</DT>
 <DD>TEXT. The name of the table that will contain the output. 
-The output is divided into three tables.
+There are three possible output tables as described below.
 
 The primary output table (<em>out_table</em>) encodes the principal components 
 with the <em>k</em> highest eigenvalues where <em>k</em> is either directly 
@@ -136,7 +138,7 @@ The table has the following columns:
 </tr>
 <tr>
 <th>std_dev</th>
-<td>The standart deviation of each principal component.</td>
+<td>The standard deviation of each principal component.</td>
 </tr>
 <tr>
 <th>proportion</th>
@@ -144,7 +146,7 @@ The table has the following columns:
 </tr>
 </table>
 
-The table <em>out_table</em>_mean contains the column means.
+The table <em>out_table_mean</em> contains the column means.
 This table has just one column:
 <table class="output">
 <tr>
@@ -158,22 +160,37 @@ The optional table <em>result_summary_table</em> contains information about the
 
 <DT>row_id</DT>
 <DD>TEXT. Column name containing the row IDs in the input source table. The column
-needs to be of type that can be cast to INT and should only contain values between 1 and
-<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>.</DD>
+should be of type INT (or a type that can be cast to INT) and should only contain values between 1 and
+<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>
+describing the full matrix.</DD>
 
 <DT>col_id</DT>
-<DD>TEXT.  Column name of containing the col IDS in sparse matrix representation
-(sparse matrices only). The column should be of type that can be cast to INT and
-contain values between 1 and <em>M</em>.</DD>
+<DD>TEXT.  Column name containing the column IDs in sparse matrix representation. 
+The column should be of type INT (or a type that can be cast to INT) 
+and should only contain values between 1 and <em>M</em>.  <em>This parameter applies to 
+sparse matrices only.</em></DD>
 
 <DT>val_id</DT>
-<DD>TEXT.  Name of 'val_id' column in sparse matrix representation (sparse matrices only). </DD>
+<DD>TEXT.  Name of 'val_id' column in sparse matrix representation defining the values of the nonzero entries. 
+<em>This parameter applies to sparse matrices only.</em></DD>
 
 <DT>row_dim</DT>
-<DD>INTEGER.  The number of rows in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER.  The actual number of rows in the matrix.  That is,
+if the matrix was transformed into dense format, this is the number of rows
+it would have.
+<em>This parameter applies to sparse matrices only.</em></DD>
 
 <DT>col_dim</DT>
-<DD>INTEGER.  The number of columns in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER.  The actual number of columns in the matrix.  That is,
+if the matrix was transformed into dense format, this is the number of columns
+it would have. 
+<em>This parameter applies to sparse matrices only.</em></DD>
+
+@note The parameters 'row_dim' and 'col_dim' could actually be inferred from the 
+sparse matrix representation, so they will be removed in the future.
+For now they are maintained for backward compatability so you must enter them.
+Making 'row_dim' or 'col_dim' larger than the actual matrix has the effect of padding it with 
+zeros, which is probably not useful.
 
 <DT>components_param</DT>
 <DD>INTEGER or FLOAT.  The parameter to control the number of principal 
@@ -203,14 +220,16 @@ principal components, i.e., proportion of variance of 100%.
    computed for each combination of the grouping columns.</DD>
 
 <DT>lanczos_iter (optional)</DT>
-<DD>INTEGER, default: minimum of {k+40, smallest matrix dimension}.  
-The number of Lanczos iterations for the SVD calculation.
+<DD>INTEGER, default: minimum of {<em>k+40</em>, smallest matrix dimension}
+where <em>k</em> is the number of principle components specified in the 
+parameter 'components_param'.  This parameter defines the 
+number of Lanczos iterations for the SVD calculation.
 The Lanczos iteration number roughly corresponds to the accuracy of the SVD
-calculation, and a higher iteration number corresponds to greater accuracy
+calculation, and a higher number of iterations corresponds to greater accuracy
 but longer computation time. The number of iterations must be at least as
 large as the value of <em>k</em>, but no larger than the smallest dimension 
-of the matrix.  If the iteration number is given as zero, then the default 
-number of iterations is used.</DD>
+of the matrix.  If the number of iterations is set to zero, then the default 
+number of iterations will be used.</DD>
 
 @note If both 'lanczos_iter' and proportion of variance (via 
 the 'components_param' parameter) are defined, 'lanczos_iter' 
@@ -221,7 +240,7 @@ proportion had not been reached).
 
 <DT>use_correlation (optional)</DT>
 <DD>BOOLEAN, default FALSE.  Whether to use the correlation matrix for calculating the principal components instead of the covariance matrix. Currently
-<em>use_correlation</em> is a placeholder for forward compatibility, and
+<em>use_correlation</em> is a placeholder for forward compatibility, so
 this value must be set to false.</DD>
 
 <DT>result_summary_table (optional)</DT>
@@ -261,41 +280,35 @@ This sumary table has the following columns:
 @anchor examples
 @examp
 
--# View online help for the PCA training function.
+-# View online help for the PCA training function:
 <pre class="example">
 SELECT madlib.pca_train();
+or
+SELECT madlib.pca_sparse_train();
 </pre>
 
--# Create the sample data.
+-# Create sample data in dense matrix form:
 <pre class="example">
 DROP TABLE IF EXISTS mat;
 CREATE TABLE mat (
-    row_id integer,
-    row_vec double precision[]
+    			row_id integer,
+    			row_vec double precision[]
 );
-COPY mat (row_id, row_vec) FROM stdin DELIMITER '|';
-1|{1,2,3}
-2|{2,1,2}
-3|{3,2,1}
-\\.
-</pre>
-
--# Run the PCA function for a fixed number of components:
-<pre class="example">
-DROP TABLE IF EXISTS result_table;
-DROP TABLE IF EXISTS result_table_mean;
-SELECT pca_train( 'mat',
-                  'result_table',
-                  'row_id',
-                  3
-                );
+INSERT INTO mat VALUES
+(1, '{1,2,3}'),
+(2, '{2,1,2}'),
+(3, '{3,2,1}');
 </pre>
 
--# View the PCA results:
+-# Run the PCA function for a specified number of principle components and view the results:
 <pre class="example">
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_train( 'mat',
+                        'result_table',
+                        'row_id',
+                         3);
 SELECT * FROM result_table;
 </pre>
-Result
 <pre class="result">
  row_id |                     principal_components                     |       std_dev        |      proportion      
 --------+--------------------------------------------------------------+----------------------+----------------------
@@ -304,22 +317,15 @@ Result
       3 | {-0.707106781186548,1.11022302462516e-16,-0.707106781186547} | 1.59506745224211e-16 | 1.09038864737157e-32
 </pre>
 
--# Run the PCA function for a proportion of variance:
-<pre class="example">
-DROP TABLE IF EXISTS result_table;
-DROP TABLE IF EXISTS result_table_mean;
-SELECT pca_train( 'mat',
-                  'result_table',
-                  'row_id',
-                  0.9
-                );
-</pre>
-
--# View the PCA results:
+-# Run the PCA function for a specified proportion of variance and view the results:
 <pre class="example">
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_train( 'mat',
+                         'result_table',
+                         'row_id',
+                          0.9);
 SELECT * FROM result_table;
 </pre>
-Result
 <pre class="result">
  row_id |                     principal_components                     |      std_dev      |    proportion     
 --------+--------------------------------------------------------------+-------------------+-------------------
@@ -327,6 +333,74 @@ Result
       2 | {2.22044604925031e-16,-1,1.11022302462516e-16}               | 0.577350269189626 | 0.142857142857041
 </pre>
 
+-# Create sample data in sparse matrix form:
+<pre class="example">
+DROP TABLE IF EXISTS sparse_mat;
+CREATE TABLE sparse_mat (
+                        row_id integer,
+                        col_id integer,
+                        val_id integer
+                        );
+INSERT INTO sparse_mat VALUES
+(1, 2, 4.0),
+(1, 5, 6.0),
+(3, 8, 4.0),
+(5, 4, 2.0),
+(6, 6, 12.0),
+(8, 1, 2.0),
+(8, 7, 2.0),
+(9, 3, 4.0),
+(9, 8, 2.0);
+</pre>
+
+-# This matrix is what this matrix looks like in dense form:
+<pre class="example">
+DROP TABLE IF EXISTS dense_mat;
+SELECT madlib.matrix_densify(
+							'sparse_mat', 
+							'row=row_id, col=col_id, val=val_id', 
+							'dense_mat');
+SELECT * FROM dense_mat order by row_id;
+</pre>
+<pre class="result">
+ row_id |       val_id       
+--------+--------------------
+      1 | {0,4,0,0,6,0,0,0}
+      2 | {0,0,0,0,0,0,0,0}
+      3 | {0,0,0,0,0,0,0,4}
+      4 | {0,0,0,0,0,0,0,0}
+      5 | {0,0,0,2,0,0,0,0}
+      6 | {0,0,0,0,0,12,0,0}
+      7 | {0,0,0,0,0,0,0,0}
+      8 | {2,0,0,0,0,0,2,0}
+      9 | {0,0,4,0,0,0,0,2}
+</pre>
+
+-# Run the PCA sparse function for a specified number of principle components and view the results:
+<pre class="example">
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_sparse_train(
+                                'sparse_mat', 
+                                'result_table',
+                                'row_id', 
+                                'col_id', 
+                                'val_id', 
+                                9, 
+                                8, 
+                                5);
+SELECT * FROM result_table;
+</pre>
+Result (with principle components truncated for readability):
+<pre class="result">
+  row_id |      principal_components                   |      std_dev      |     proportion     
+--------+----------------------------------------------------------------------------------------
+      1 | {0.0189854059340971,0.0593979357345431,\u2026    |  4.03069474374092 |  0.604208682045711
+      2 | {0.0346801706473592,-0.536234300404824,\u2026    |  2.42282285507368 |  0.218308410262949
+      3 | {0.166190350977087,-0.112693750915351,\u2026     |  1.54680674776235 | 0.0889814051004931
+      4 | {-0.0699448377725649,0.00569475043252321,\u2026  |  1.10233418049845 | 0.0451911810308358
+      5 | {0.645363366217337,0.0403370697192613,\u2026     | 0.906957663197704 | 0.0305915282045503
+</pre>
+
 @anchor notes
 @par Notes
 
@@ -340,8 +414,8 @@ string should be double-quoted; in this case the input would be '"MyTable"').
 
 - Because of the centering step in PCA (see
 \ref background_pca "Technical Background"), sparse matrices almost always
-become dense during the training process. Thus, this implementation
-automatically densifies sparse matrix input, and there should be no expected
+become dense during the training process. Since this implementation
+automatically densifies sparse matrix input, there should be no expected
 performance improvement in using sparse matrix input over dense matrix input.
 
 - For the parameter 'components_param', INTEGER and FLOAT are
@@ -360,7 +434,7 @@ proportion had not been reached).
 @anchor background_pca
 @par Technical Background
 
-The PCA implemented here uses an SVD decomposition implementation to recover
+The PCA implemented here uses a distributed SVD decomposition implementation to recover
 the principal components (as opposed to the directly computing the eigenvectors
  of the covariance matrix).  Let \f$ \boldsymbol X \f$ be the data matrix, and
   let \f$ \hat{x} \f$ be a vector of the column averages of \f$ \boldsymbol{X}\f$.

http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/e4e93e09/src/ports/postgres/modules/pca/pca_project.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/pca/pca_project.sql_in b/src/ports/postgres/modules/pca/pca_project.sql_in
index 0a1bfdc..fde15d0 100644
--- a/src/ports/postgres/modules/pca/pca_project.sql_in
+++ b/src/ports/postgres/modules/pca/pca_project.sql_in
@@ -20,7 +20,7 @@ m4_include(`SQLCommon.m4')
 <li class="level1"><a href="#project">Projection Function</a></li>
 <li class="level1"><a href="#examples">Examples</a></li>
 <li class="level1"><a href="#notes">Notes</a></li>
-<li class="level1"><a href="#background">Technical Background</a></li>
+<li class="level1"><a href="#background_project">Technical Background</a></li>
 <li class="level1"><a href="#related">Related Topics</a></li>
 </ul>
 </div>
@@ -33,14 +33,16 @@ procedure.
 Principal component projection is a mathematical procedure that projects high
 dimensional data onto a lower dimensional space.  This lower dimensional space
 is defined by the \f$ k  \f$  principal components with the highest variance in
-the training data.  More details on the mathematics of PCA can be found in  \ref
-pca_train and some details about the principal component projection calculations
-can be found in the \ref background "Technical Background".
+the training data.  
+
+More details on the mathematics of PCA can be found in \ref
+grp_pca_train and some details about principal component projection calculations
+can be found in the \ref background_project "Technical Background".
 
 
 @anchor project
 @par Projection Function
-The projection functions have the following formats:
+The projection functions are slightly different for dense and sparse matrices. For dense matrices:
 <pre class="syntax">
 madlib.pca_project( source_table,
                     pc_table,
@@ -50,23 +52,23 @@ madlib.pca_project( source_table,
                     result_summary_table
                   )
 </pre>
-and
+For sparse matrices:
 <pre class="syntax">
 madlib.pca_sparse_project( source_table,
                            pc_table,
                            out_table,
                            row_id,
-                           col_id,
-                           val_id,
-                           row_dim,
-                           col_dim,
+                           col_id,              -- Sparse matrices only
+                           val_id,              -- Sparse matrices only
+                           row_dim,             -- Sparse matrices only
+                           col_dim,             -- Sparse matrices only
                            residual_table,
                            result_summary_table
                          )
 </pre>
 
 
-@par Arguments
+\b Arguments
 <DL class="arglist">
 <DT>source_table</DT>
 <DD>TEXT.  Source table name.
@@ -75,9 +77,9 @@ and \f$ M \f$ columns, where \f$ N \f$ is the number of data points, and \f$ M
 \f$ is the number of features for each data point.
 
 The input table for <em> pca_project </em> is expected to be in the one of the
-two standard  MADlib dense matrix formats, and the sparse input table for  <em>
-pca_sparse_project </em>  should be in the standard MADlib sparse matrix format.
-These formats are described in the documentation for \ref pca_train.</DD>
+two standard MADlib dense matrix formats, and the sparse input table for  <em>
+pca_sparse_project </em> should be in the standard MADlib sparse matrix format.
+These formats are described in the documentation for \ref grp_pca_train.</DD>
 
 <DT>pc_table</DT>
 <DD>TEXT.  Table name for the table containing principal components. </DD>
@@ -98,26 +100,41 @@ principal components. The table has the following columns:
         <td>A vector containing elements in the row of the matrix.</td>
     </tr>
 </table>
-
 </DD>
+
 <DT>row_id</DT>
 <DD>TEXT. Column name containing the row IDs in the input source table. The column
-needs to be of type that can be cast to INT and should only contain values between 1 and
-<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>.</DD>
+should be of type INT (or a type that can be cast to INT) and should only contain values between 1 and
+<em>N</em>. For dense matrix format, it should contain all continguous integers from 1 to <em>N</em>
+describing the full matrix.</DD>
 
 <DT>col_id</DT>
-<DD>TEXT.  Column name of containing the col IDS in sparse matrix representation
-(sparse matrices only). The column should be of type that can be cast to INT and
-contain values between 1 and <em>M</em>.</DD>
+<DD>TEXT.  Column name containing the column IDs in sparse matrix representation. 
+The column should be of type INT (or a type that can be cast to INT) 
+and should only contain values between 1 and <em>M</em>.  <em>This parameter applies to 
+sparse matrices only.</em></DD>
 
 <DT>val_id</DT>
-<DD>TEXT.  Name of 'val_id' column in sparse matrix representation (sparse matrices only). </DD>
+<DD>TEXT.  Name of 'val_id' column in sparse matrix representation defining the values of the nonzero entries. 
+<em>This parameter applies to sparse matrices only.</em></DD>
 
 <DT>row_dim</DT>
-<DD>INTEGER.  The number of rows in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER.  The actual number of rows in the matrix.  That is,
+if the matrix was transformed into dense format, this is the number of rows
+it would have.
+<em>This parameter applies to sparse matrices only.</em></DD>
 
 <DT>col_dim</DT>
-<DD>INTEGER.  The number of columns in the sparse matrix (sparse matrices only). </DD>
+<DD>INTEGER.  The actual number of columns in the matrix.  That is,
+if the matrix was transformed into dense format, this is the number of columns
+it would have. 
+<em>This parameter applies to sparse matrices only.</em></DD>
+
+@note The parameters 'row_dim' and 'col_dim' could actually be inferred from the 
+sparse matrix representation, so they will be removed in the future.
+For now they are maintained for backward compatability so you must enter them.
+Making 'row_dim' or 'col_dim' larger than the actual matrix has the effect of padding it with 
+zeros, which is probably not useful.
 
 <DT>residual_table (optional)</DT>
 <DD>TEXT, default: NULL.  Name of the optional residual table.
@@ -143,7 +160,7 @@ The <em>result_summary_table</em> contains information about the performance tim
 <table class="output">
     <tr>
         <th>exec_time</th>
-        <td>Wall clock time (ms) of the function.</td>
+        <td>Elapsed time (ms) for execution of the function.</td>
     </tr>
     <tr>
         <th>residual_norm</th>
@@ -158,12 +175,12 @@ The <em>result_summary_table</em> contains information about the performance tim
 
 @anchor examples
 @examp
--# View online help for the PCA projection function.
+-# View online help for the PCA projection function:
 <pre class="example">
 SELECT madlib.pca_project();
 </pre>
 
--# Create the sample data.
+-# Create the sample data:
 <pre class="example">
 DROP TABLE IF EXISTS mat;
 CREATE TABLE mat (
@@ -178,35 +195,69 @@ INSERT INTO mat VALUES
 (5, ARRAY[8,5,7]),
 (6, ARRAY[0,5,5]);
 </pre>
--# Run the PCA function and keep only the top two PCs:
+-# Run the PCA function and keep only the top two principle components:
 <pre class="example">
-DROP TABLE IF EXISTS result_table;
-SELECT pca_train ( 'mat',
-                   'result_table',
-                   'row_id',
-                   2
-                 );
+DROP TABLE IF EXISTS result_table, result_table_mean;
+SELECT madlib.pca_train ( 'mat',
+                        'result_table',
+                        'row_id',
+                        2
+                        );
+SELECT * FROM result_table;
 </pre>
--# Project the original data into a low-dimensional representation.
+<pre class="result">
+ row_id |                    principal_components                     |     std_dev      |    proportion     
+--------+-------------------------------------------------------------+------------------+-------------------
+      1 | {-0.995725178022077,0.0921925100100751,0.00564897786728818} |  3.7757341932744 | 0.745095924995985
+      2 | {0.0900421470942019,0.955231794466691,0.281823758023718}    | 1.97776947254051 | 0.204437565497132
+</pre>
+-# Project the original data into a low-dimensional representation:
 <pre class="example">
 DROP TABLE IF EXISTS residual_table, result_summary_table, out_table;
-SELECT pca_project( 'mat',
-                    'result_table',
-                    'out_table'
-                    'row_id',
-                    'residual_table',
-                    'result_summary_table'
-                  );
+SELECT madlib.pca_project( 'mat',
+                            'result_table',
+                            'out_table',
+                            'row_id',
+                            'residual_table',
+                            'result_summary_table'
+                            );
+</pre>
+-# View dense matrix with the projection onto the principal components:
+<pre class="example">
+SELECT * FROM out_table ORDER BY row_id;
+</pre>
+<pre class="result">
+ row_id |                row_vec                
+--------+---------------------------------------
+      1 | {1.09098309337665,-2.63145496174091}
+      2 | {3.61719607739251,2.41483045187516}
+      3 | {-2.17841894858709,0.24593773840028}
+      4 | {-4.3542543246514,1.97631703314526}
+      5 | {-3.06500468299723,-1.64480747723177}
+      6 | {4.88949878544481,-0.360822784430716}
 </pre>
--# Check the error in the projection.
+-# Check the error in the projection:
 <pre class="example">
 SELECT * FROM result_summary_table;
 </pre>
-Result:
 <pre class="result">
-   exec_time   | residual_norm | relative_residual_norm
+   exec_time   | residual_norm | relative_residual_norm 
 ---------------+---------------+------------------------
- 5685.40501595 | 2.19726255664 |         0.099262204234
+ 56.8881034851 | 2.19726255664 |         0.099262204234
+</pre>
+-# Check the residuals:
+<pre class="example">
+SELECT * FROM residual_table ORDER BY row_id;
+</pre>
+<pre class="result">
+ row_id |                          row_vec                           
+--------+------------------------------------------------------------
+      1 | {0.0160441468047001,0.219103418411008,-0.747769465736052}
+      2 | {-0.0141636064722857,-0.193422226365899,0.660123132354738}
+      3 | {0.0197048332985021,0.269094791232932,-0.918383061897929}
+      4 | {0.00897783310632772,0.122603834748268,-0.418429820364218}
+      5 | {-0.0333376637524658,-0.455268589780183,1.55376831915842}
+      6 | {0.00277445701511336,0.037888771752409,-0.129309103509956}
 </pre>
 
 @anchor notes
@@ -232,7 +283,7 @@ If mixed-case or multi-byte characters are desired for entity names then the
 string should be double-quoted; in this case the input would be '"MyTable"').
 
 
-@anchor background
+@anchor background_project
 @par Technical Background
 
 Given a table containing some principal components \f$ \boldsymbol P \f$ and