New module src/math/correlation
[pspp-builds.git] / src / language / stats / correlations.c
index 3cadb8d1116bf33af6c993107ad83eabb4a0c97f..605609a7d68cc559e42cc605cf2543f49e9a441d 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <libpspp/assertion.h>
 #include <math/covariance.h>
+#include <math/correlation.h>
 #include <math/design-matrix.h>
 #include <gsl/gsl_matrix.h>
 #include <data/casegrouper.h>
 #define N_(msgid) msgid
 
 
-static double
-significance_of_correlation (double rho, double w)
-{
-  double t = w - 2;
-  t /= 1 - MIN (1, pow2 (rho));
-  t = sqrt (t);
-  t *= rho;
-  
-  if (t > 0)
-    return  gsl_cdf_tdist_Q (t, w - 2);
-  else
-    return  gsl_cdf_tdist_P (t, w - 2);
-}
-
-
 struct corr
 {
   size_t n_vars_total;
@@ -174,7 +160,8 @@ output_descriptives (const struct corr *corr, const gsl_matrix *means,
 
 static void
 output_correlation (const struct corr *corr, const struct corr_opts *opts,
-                   const gsl_matrix *cm, const gsl_matrix *samples)
+                   const gsl_matrix *cm, const gsl_matrix *samples,
+                   const gsl_matrix *cv)
 {
   int r, c;
   struct tab_table *t;
@@ -188,7 +175,10 @@ output_correlation (const struct corr *corr, const struct corr_opts *opts,
   const int heading_columns = 2;
   const int heading_rows = 1;
 
-  const int rows_per_variable = opts->missing_type == CORR_LISTWISE ? 2 : 3;
+  int rows_per_variable = opts->missing_type == CORR_LISTWISE ? 2 : 3;
+
+  if (opts->statistics & STATS_XPROD)
+    rows_per_variable += 2;
 
   /* Two header columns */
   nc += heading_columns;
@@ -230,8 +220,16 @@ output_correlation (const struct corr *corr, const struct corr_opts *opts,
       tab_text (t, 1, 1 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Pearson Correlation"));
       tab_text (t, 1, 2 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, 
                (opts->tails == 2) ? _("Sig. (2-tailed)") : _("Sig. (1-tailed)"));
+
+      if (opts->statistics & STATS_XPROD)
+       {
+         tab_text (t, 1, 3 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Cross-products"));
+         tab_text (t, 1, 4 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Covariance"));
+       }
+
       if ( opts->missing_type != CORR_LISTWISE )
-       tab_text (t, 1, 3 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("N"));
+       tab_text (t, 1, rows_per_variable + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("N"));
+
       tab_hline (t, TAL_1, 0, nc - 1, r * rows_per_variable + 1);
     }
 
@@ -247,13 +245,13 @@ output_correlation (const struct corr *corr, const struct corr_opts *opts,
       for (c = 0 ; c < matrix_cols ; ++c)
        {
          unsigned char flags = 0; 
-         int col_index = corr->n_vars_total - corr->n_vars1 + c;
+         const int col_index = corr->n_vars_total - corr->n_vars1 + c;
          double pearson = gsl_matrix_get (cm, r, col_index);
          double w = gsl_matrix_get (samples, r, col_index);
          double sig = opts->tails * significance_of_correlation (pearson, w);
 
          if ( opts->missing_type != CORR_LISTWISE )
-           tab_double (t, c + heading_columns, row + 2, 0, w, wfmt);
+           tab_double (t, c + heading_columns, row + rows_per_variable - 1, 0, w, wfmt);
 
          if ( c != r)
            tab_double (t, c + heading_columns, row + 1, 0,  sig, NULL);
@@ -262,37 +260,21 @@ output_correlation (const struct corr *corr, const struct corr_opts *opts,
            flags = TAB_EMPH;
          
          tab_double (t, c + heading_columns, row, flags, pearson, NULL);
-       }
-    }
-
-  tab_submit (t);
-}
 
+         if (opts->statistics & STATS_XPROD)
+           {
+             double cov = gsl_matrix_get (cv, r, col_index);
+             const double xprod_dev = cov * w;
+             cov *= w / (w - 1.0);
 
-static gsl_matrix *
-correlation_from_covariance (const gsl_matrix *cv, const gsl_matrix *v)
-{
-  size_t i, j;
-  gsl_matrix *corr = gsl_matrix_calloc (cv->size1, cv->size2);
-  
-  for (i = 0 ; i < cv->size1; ++i)
-    {
-      for (j = 0 ; j < cv->size2; ++j)
-       {
-         double rho = gsl_matrix_get (cv, i, j);
-         
-         rho /= sqrt (gsl_matrix_get (v, i, j))
-           * 
-           sqrt (gsl_matrix_get (v, j, i));
-         
-         gsl_matrix_set (corr, i, j, rho);
+             tab_double (t, c + heading_columns, row + 2, 0, xprod_dev, NULL);
+             tab_double (t, c + heading_columns, row + 3, 0, cov, NULL);
+           }
        }
     }
-  
-  return corr;
-}
-
 
+  tab_submit (t);
+}
 
 
 static void
@@ -323,7 +305,8 @@ run_corr (struct casereader *r, const struct corr_opts *opts, const struct corr
 
   output_correlation (corr, opts,
                      corr_matrix,
-                     samples_matrix );
+                     samples_matrix,
+                     cov_matrix);
 
   covariance_destroy (cov);
   gsl_matrix_free (corr_matrix);
@@ -409,8 +392,16 @@ cmd_correlation (struct lexer *lexer, struct dataset *ds)
                opts.statistics = STATS_DESCRIPTIVES;
              else if (lex_match_id (lexer, "XPROD"))
                opts.statistics = STATS_XPROD;
-             else
-               opts.statistics = STATS_ALL;
+             else if (lex_token (lexer) == T_ALL)
+               {
+                 opts.statistics = STATS_ALL;
+                 lex_get (lexer);
+               }
+             else 
+               {
+                 lex_error (lexer, NULL);
+                 goto error;
+               }
 
               lex_match (lexer, ',');
            }