/* PSPP - a program for statistical analysis.
- Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010, 2011, 2012, 2014 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <gsl/gsl_eigen.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_sort_vector.h>
+#include <gsl/gsl_cdf.h>
#include "data/casegrouper.h"
#include "data/casereader.h"
#include "language/lexer/lexer.h"
#include "language/lexer/value-parser.h"
#include "language/lexer/variable-parser.h"
+#include "libpspp/cast.h"
#include "libpspp/message.h"
#include "libpspp/misc.h"
#include "math/correlation.h"
ROT_VARIMAX = 0,
ROT_EQUAMAX,
ROT_QUARTIMAX,
+ ROT_PROMAX,
ROT_NONE
};
*y = c ;
}
-static const rotation_coefficients rotation_coeff[3] = {
+static const rotation_coefficients rotation_coeff[] = {
varimax_coefficients,
equamax_coefficients,
- quartimax_coefficients
+ quartimax_coefficients,
+ varimax_coefficients /* PROMAX is identical to VARIMAX */
};
+/* return diag (C'C) ^ {-0.5} */
+static gsl_matrix *
+diag_rcp_sqrt (const gsl_matrix *C)
+{
+ int j;
+ gsl_matrix *d = gsl_matrix_calloc (C->size1, C->size2);
+ gsl_matrix *r = gsl_matrix_calloc (C->size1, C->size2);
+
+ assert (C->size1 == C->size2);
+
+ gsl_linalg_matmult_mod (C, GSL_LINALG_MOD_TRANSPOSE,
+ C, GSL_LINALG_MOD_NONE,
+ d);
+
+ for (j = 0 ; j < d->size2; ++j)
+ {
+ double e = gsl_matrix_get (d, j, j);
+ e = 1.0 / sqrt (e);
+ gsl_matrix_set (r, j, j, e);
+ }
+
+ gsl_matrix_free (d);
+
+ return r;
+}
+
+
+
+/* return diag ((C'C)^-1) ^ {-0.5} */
+static gsl_matrix *
+diag_rcp_inv_sqrt (const gsl_matrix *CCinv)
+{
+ int j;
+ gsl_matrix *r = gsl_matrix_calloc (CCinv->size1, CCinv->size2);
+
+ assert (CCinv->size1 == CCinv->size2);
+
+ for (j = 0 ; j < CCinv->size2; ++j)
+ {
+ double e = gsl_matrix_get (CCinv, j, j);
+ e = 1.0 / sqrt (e);
+ gsl_matrix_set (r, j, j, e);
+ }
+
+ return r;
+}
+
+
+
+
+
struct cmd_factor
{
size_t n_vars;
enum extraction_method extraction;
enum plot_opts plot;
enum rotation_type rotation;
+ int rotation_iterations;
+ int promax_power;
/* Extraction Criteria */
int n_factors;
double min_eigen;
double econverge;
- int iterations;
+ int extraction_iterations;
double rconverge;
int n_extractions;
gsl_vector *msr ; /* Multiple Squared Regressions */
+
+ double detR; /* The determinant of the correlation matrix */
};
static struct idata *
gsl_matrix_free (id->evec);
if (id->cov != NULL)
gsl_matrix_free (id->cov);
+ if (id->corr != NULL)
+ gsl_matrix_free (CONST_CAST (gsl_matrix *, id->corr));
free (id);
}
+static gsl_matrix *
+anti_image (const gsl_matrix *m)
+{
+ int i, j;
+ gsl_matrix *a;
+ assert (m->size1 == m->size2);
+
+ a = gsl_matrix_alloc (m->size1, m->size2);
+
+ for (i = 0; i < m->size1; ++i)
+ {
+ for (j = 0; j < m->size2; ++j)
+ {
+ double *p = gsl_matrix_ptr (a, i, j);
+ *p = gsl_matrix_get (m, i, j);
+ *p /= gsl_matrix_get (m, i, i);
+ *p /= gsl_matrix_get (m, j, j);
+ }
+ }
+
+ return a;
+}
+
+
+/* Return the sum of all the elements excluding row N */
+static double
+ssq_od_n (const gsl_matrix *m, int n)
+{
+ int i, j;
+ double ss = 0;
+ assert (m->size1 == m->size2);
+
+ assert (n < m->size1);
+
+ for (i = 0; i < m->size1; ++i)
+ {
+ if (i == n ) continue;
+ for (j = 0; j < m->size2; ++j)
+ {
+ ss += pow2 (gsl_matrix_get (m, i, j));
+ }
+ }
+
+ return ss;
+}
+
+
+
#if 0
static void
dump_matrix (const gsl_matrix *m)
}
}
-
static void
dump_matrix_permute (const gsl_matrix *m, const gsl_permutation *p)
{
rotate (const struct cmd_factor *cf, const gsl_matrix *unrot,
const gsl_vector *communalities,
gsl_matrix *result,
- gsl_vector *rotated_loadings
+ gsl_vector *rotated_loadings,
+ gsl_matrix *pattern_matrix,
+ gsl_matrix *factor_correlation_matrix
)
{
int j, k;
/* Now perform the rotation iterations */
prev_sv = initial_sv (normalised);
- for (i = 0 ; i < cf->iterations ; ++i)
+ for (i = 0 ; i < cf->rotation_iterations ; ++i)
{
double sv = 0.0;
for (j = 0 ; j < normalised->size2; ++j)
h_sqrt, normalised, 0.0, result);
gsl_matrix_free (h_sqrt);
+ gsl_matrix_free (normalised);
+
+ if (cf->rotation == ROT_PROMAX)
+ {
+ /* general purpose m by m matrix, where m is the number of factors */
+ gsl_matrix *mm1 = gsl_matrix_calloc (unrot->size2, unrot->size2);
+ gsl_matrix *mm2 = gsl_matrix_calloc (unrot->size2, unrot->size2);
+
+ /* general purpose m by p matrix, where p is the number of variables */
+ gsl_matrix *mp1 = gsl_matrix_calloc (unrot->size2, unrot->size1);
+
+ gsl_matrix *pm1 = gsl_matrix_calloc (unrot->size1, unrot->size2);
+
+ gsl_permutation *perm = gsl_permutation_alloc (unrot->size2);
+
+ int signum;
+
+ int i, j;
+
+ /* The following variables follow the notation by SPSS Statistical Algorithms
+ page 342 */
+ gsl_matrix *L = gsl_matrix_calloc (unrot->size2, unrot->size2);
+ gsl_matrix *P = clone_matrix (result);
+ gsl_matrix *D ;
+ gsl_matrix *Q ;
+
+
+ /* Vector of length p containing (indexed by i)
+ \Sum^m_j {\lambda^2_{ij}} */
+ gsl_vector *rssq = gsl_vector_calloc (unrot->size1);
+
+ for (i = 0; i < P->size1; ++i)
+ {
+ double sum = 0;
+ for (j = 0; j < P->size2; ++j)
+ {
+ sum += gsl_matrix_get (result, i, j)
+ * gsl_matrix_get (result, i, j);
+
+ }
+
+ gsl_vector_set (rssq, i, sqrt (sum));
+ }
+
+ for (i = 0; i < P->size1; ++i)
+ {
+ for (j = 0; j < P->size2; ++j)
+ {
+ double l = gsl_matrix_get (result, i, j);
+ double r = gsl_vector_get (rssq, i);
+ gsl_matrix_set (P, i, j, pow (fabs (l / r), cf->promax_power + 1) * r / l);
+ }
+ }
+
+ gsl_vector_free (rssq);
+
+ gsl_linalg_matmult_mod (result,
+ GSL_LINALG_MOD_TRANSPOSE,
+ result,
+ GSL_LINALG_MOD_NONE,
+ mm1);
+
+ gsl_linalg_LU_decomp (mm1, perm, &signum);
+ gsl_linalg_LU_invert (mm1, perm, mm2);
+
+ gsl_linalg_matmult_mod (mm2, GSL_LINALG_MOD_NONE,
+ result, GSL_LINALG_MOD_TRANSPOSE,
+ mp1);
+
+ gsl_linalg_matmult_mod (mp1, GSL_LINALG_MOD_NONE,
+ P, GSL_LINALG_MOD_NONE,
+ L);
+
+ D = diag_rcp_sqrt (L);
+ Q = gsl_matrix_calloc (unrot->size2, unrot->size2);
+
+ gsl_linalg_matmult_mod (L, GSL_LINALG_MOD_NONE,
+ D, GSL_LINALG_MOD_NONE,
+ Q);
+
+ gsl_matrix *QQinv = gsl_matrix_calloc (unrot->size2, unrot->size2);
+
+ gsl_linalg_matmult_mod (Q, GSL_LINALG_MOD_TRANSPOSE,
+ Q, GSL_LINALG_MOD_NONE,
+ QQinv);
+
+ gsl_linalg_cholesky_decomp (QQinv);
+ gsl_linalg_cholesky_invert (QQinv);
+
+
+ gsl_matrix *C = diag_rcp_inv_sqrt (QQinv);
+ gsl_matrix *Cinv = clone_matrix (C);
+
+ gsl_linalg_cholesky_decomp (Cinv);
+ gsl_linalg_cholesky_invert (Cinv);
+
+
+ gsl_linalg_matmult_mod (result, GSL_LINALG_MOD_NONE,
+ Q, GSL_LINALG_MOD_NONE,
+ pm1);
+
+ gsl_linalg_matmult_mod (pm1, GSL_LINALG_MOD_NONE,
+ Cinv, GSL_LINALG_MOD_NONE,
+ pattern_matrix);
+
+
+ gsl_linalg_matmult_mod (C, GSL_LINALG_MOD_NONE,
+ QQinv, GSL_LINALG_MOD_NONE,
+ mm1);
+
+ gsl_linalg_matmult_mod (mm1, GSL_LINALG_MOD_NONE,
+ C, GSL_LINALG_MOD_TRANSPOSE,
+ factor_correlation_matrix);
+
+ gsl_linalg_matmult_mod (pattern_matrix, GSL_LINALG_MOD_NONE,
+ factor_correlation_matrix, GSL_LINALG_MOD_NONE,
+ pm1);
+
+ gsl_matrix_memcpy (result, pm1);
+
+
+ gsl_matrix_free (QQinv);
+ gsl_matrix_free (C);
+ gsl_matrix_free (Cinv);
+
+ gsl_matrix_free (D);
+ gsl_matrix_free (Q);
+ gsl_matrix_free (L);
+ gsl_matrix_free (P);
+
+ gsl_permutation_free (perm);
+
+ gsl_matrix_free (mm1);
+ gsl_matrix_free (mm2);
+ gsl_matrix_free (mp1);
+ gsl_matrix_free (pm1);
+ }
/* reflect negative sums and populate the rotated loadings vector*/
{
double s = gsl_matrix_get (result, j, i);
ssq += s * s;
- sum += gsl_matrix_get (result, j, i);
+ sum += s;
}
gsl_vector_set (rotated_loadings, i, ssq);
int
cmd_factor (struct lexer *lexer, struct dataset *ds)
{
- bool extraction_seen = false;
const struct dictionary *dict = dataset_dict (ds);
-
+ int n_iterations = 25;
struct cmd_factor factor;
factor.n_vars = 0;
factor.vars = NULL;
factor.extraction = EXTRACTION_PC;
factor.n_factors = 0;
factor.min_eigen = SYSMIS;
- factor.iterations = 25;
+ factor.extraction_iterations = 25;
+ factor.rotation_iterations = 25;
factor.econverge = 0.001;
factor.blank = 0;
{
factor.rotation = ROT_QUARTIMAX;
}
+ else if (lex_match_id (lexer, "PROMAX"))
+ {
+ factor.promax_power = 5;
+ if (lex_match (lexer, T_LPAREN))
+ {
+ lex_force_int (lexer);
+ factor.promax_power = lex_integer (lexer);
+ lex_get (lexer);
+ lex_force_match (lexer, T_RPAREN);
+ }
+ factor.rotation = ROT_PROMAX;
+ }
else if (lex_match_id (lexer, "NOROTATE"))
{
factor.rotation = ROT_NONE;
goto error;
}
}
+ factor.rotation_iterations = n_iterations;
}
else if (lex_match_id (lexer, "CRITERIA"))
{
if ( lex_force_match (lexer, T_LPAREN))
{
lex_force_int (lexer);
- factor.iterations = lex_integer (lexer);
+ n_iterations = lex_integer (lexer);
lex_get (lexer);
lex_force_match (lexer, T_RPAREN);
}
{
factor.n_factors = 0;
factor.min_eigen = 1;
- factor.iterations = 25;
+ n_iterations = 25;
}
else
{
}
else if (lex_match_id (lexer, "EXTRACTION"))
{
- extraction_seen = true;
lex_match (lexer, T_EQUALS);
while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
{
goto error;
}
}
+ factor.extraction_iterations = n_iterations;
}
else if (lex_match_id (lexer, "FORMAT"))
{
{
factor.print |= PRINT_INITIAL;
}
-#if FACTOR_FULLY_IMPLEMENTED
else if (lex_match_id (lexer, "KMO"))
{
+ factor.print |= PRINT_KMO;
}
+#if FACTOR_FULLY_IMPLEMENTED
else if (lex_match_id (lexer, "REPR"))
{
}
tab_text (t, c++, i + heading_rows, TAT_TITLE, var_to_string (factor->vars[i]));
if (factor->print & PRINT_INITIAL)
- tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (initial, i), NULL);
+ tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (initial, i), NULL, RC_OTHER);
if (factor->print & PRINT_EXTRACTION)
- tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (extracted, i), NULL);
+ tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (extracted, i), NULL, RC_OTHER);
}
tab_submit (t);
show_factor_matrix (const struct cmd_factor *factor, struct idata *idata, const char *title, const gsl_matrix *fm)
{
int i;
+
const int n_factors = idata->n_extractions;
const int heading_columns = 1;
if ( fabs (x) < factor->blank)
continue;
- tab_double (t, heading_columns + j, heading_rows + i, 0, x, NULL);
+ tab_double (t, heading_columns + j, heading_rows + i, 0, x, NULL, RC_OTHER);
}
}
nc += 3;
if (factor->print & PRINT_ROTATION)
- nc += 3;
+ {
+ nc += factor->rotation == ROT_PROMAX ? 1 : 3;
+ }
/* No point having a table with only headings */
if ( nc <= heading_columns)
if (factor->print & PRINT_ROTATION)
{
- tab_joint_text (t, c, 0, c + 2, 0, TAB_CENTER | TAT_TITLE, _("Rotation Sums of Squared Loadings"));
- c += 3;
+ const int width = factor->rotation == ROT_PROMAX ? 0 : 2;
+ tab_joint_text (t, c, 0, c + width, 0, TAB_CENTER | TAT_TITLE, _("Rotation Sums of Squared Loadings"));
+ c += width + 1;
}
- for (i = 0; i < (nc - heading_columns) / 3 ; ++i)
+ for (i = 0; i < (nc - heading_columns + 2) / 3 ; ++i)
{
tab_text (t, i * 3 + 1, 1, TAB_CENTER | TAT_TITLE, _("Total"));
+
+ tab_vline (t, TAL_2, heading_columns + i * 3, 0, nr - 1);
+
+ if (i == 2 && factor->rotation == ROT_PROMAX)
+ continue;
+
/* xgettext:no-c-format */
tab_text (t, i * 3 + 2, 1, TAB_CENTER | TAT_TITLE, _("% of Variance"));
tab_text (t, i * 3 + 3, 1, TAB_CENTER | TAT_TITLE, _("Cumulative %"));
-
- tab_vline (t, TAL_2, heading_columns + i * 3, 0, nr - 1);
}
for (i = 0 ; i < initial_eigenvalues->size; ++i)
const double e_lambda = gsl_vector_get (extracted_eigenvalues, i);
double e_percent = 100.0 * e_lambda / e_total ;
- const double r_lambda = gsl_vector_get (rotated_loadings, i);
- double r_percent = 100.0 * r_lambda / e_total ;
-
c = 0;
tab_text_format (t, c++, i + heading_rows, TAB_LEFT | TAT_TITLE, _("%zu"), i + 1);
i_cum += i_percent;
e_cum += e_percent;
- r_cum += r_percent;
/* Initial Eigenvalues */
if (factor->print & PRINT_INITIAL)
{
- tab_double (t, c++, i + heading_rows, 0, i_lambda, NULL);
- tab_double (t, c++, i + heading_rows, 0, i_percent, NULL);
- tab_double (t, c++, i + heading_rows, 0, i_cum, NULL);
+ tab_double (t, c++, i + heading_rows, 0, i_lambda, NULL, RC_OTHER);
+ tab_double (t, c++, i + heading_rows, 0, i_percent, NULL, RC_OTHER);
+ tab_double (t, c++, i + heading_rows, 0, i_cum, NULL, RC_OTHER);
}
if (i < idata->n_extractions)
{
/* Sums of squared loadings */
- tab_double (t, c++, i + heading_rows, 0, e_lambda, NULL);
- tab_double (t, c++, i + heading_rows, 0, e_percent, NULL);
- tab_double (t, c++, i + heading_rows, 0, e_cum, NULL);
+ tab_double (t, c++, i + heading_rows, 0, e_lambda, NULL, RC_OTHER);
+ tab_double (t, c++, i + heading_rows, 0, e_percent, NULL, RC_OTHER);
+ tab_double (t, c++, i + heading_rows, 0, e_cum, NULL, RC_OTHER);
}
}
- if (factor->print & PRINT_ROTATION)
- {
- if (i < idata->n_extractions)
- {
- tab_double (t, c++, i + heading_rows, 0, r_lambda, NULL);
- tab_double (t, c++, i + heading_rows, 0, r_percent, NULL);
- tab_double (t, c++, i + heading_rows, 0, r_cum, NULL);
- }
- }
+ if (rotated_loadings != NULL)
+ {
+ const double r_lambda = gsl_vector_get (rotated_loadings, i);
+ double r_percent = 100.0 * r_lambda / e_total ;
+
+ if (factor->print & PRINT_ROTATION)
+ {
+ if (i < idata->n_extractions)
+ {
+ r_cum += r_percent;
+ tab_double (t, c++, i + heading_rows, 0, r_lambda, NULL, RC_OTHER);
+ if (factor->rotation != ROT_PROMAX)
+ {
+ tab_double (t, c++, i + heading_rows, 0, r_percent, NULL, RC_OTHER);
+ tab_double (t, c++, i + heading_rows, 0, r_cum, NULL, RC_OTHER);
+ }
+ }
+ }
+ }
+ }
+
+ tab_submit (t);
+}
+
+
+static void
+show_factor_correlation (const struct cmd_factor * factor, const gsl_matrix *fcm)
+{
+ size_t i, j;
+ const int heading_columns = 1;
+ const int heading_rows = 1;
+ const int nr = heading_rows + fcm->size2;
+ const int nc = heading_columns + fcm->size1;
+ struct tab_table *t = tab_create (nc, nr);
+
+ tab_title (t, _("Factor Correlation Matrix"));
+
+ tab_headers (t, heading_columns, 0, heading_rows, 0);
+
+ /* Outline the box */
+ tab_box (t,
+ TAL_2, TAL_2,
+ -1, -1,
+ 0, 0,
+ nc - 1, nr - 1);
+ /* Vertical lines */
+ tab_box (t,
+ -1, -1,
+ -1, TAL_1,
+ heading_columns, 0,
+ nc - 1, nr - 1);
+
+ tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
+ tab_hline (t, TAL_1, 1, nc - 1, 1);
+
+ tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+
+
+ if ( factor->extraction == EXTRACTION_PC)
+ tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Component"));
+ else
+ tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Factor"));
+
+ for (i = 0 ; i < fcm->size1; ++i)
+ {
+ tab_text_format (t, heading_columns + i, 0, TAB_CENTER | TAT_TITLE, _("%zu"), i + 1);
+ }
+
+ for (i = 0 ; i < fcm->size2; ++i)
+ {
+ tab_text_format (t, 0, heading_rows + i, TAB_CENTER | TAT_TITLE, _("%zu"), i + 1);
+ }
+
+
+ for (i = 0 ; i < fcm->size1; ++i)
+ {
+ for (j = 0 ; j < fcm->size2; ++j)
+ tab_double (t, heading_columns + i, heading_rows +j, 0,
+ gsl_matrix_get (fcm, i, j), NULL, RC_OTHER);
}
tab_submit (t);
for (i = 0; i < factor->n_vars; ++i)
{
for (j = 0; j < factor->n_vars; ++j)
- tab_double (t, heading_columns + i, y + j, 0, gsl_matrix_get (idata->corr, i, j), NULL);
+ tab_double (t, heading_columns + i, y + j, 0, gsl_matrix_get (idata->corr, i, j), NULL, RC_OTHER);
}
}
if (i == j)
continue;
- tab_double (t, heading_columns + i, y + j, 0, significance_of_correlation (rho, w), NULL);
+ tab_double (t, heading_columns + i, y + j, 0, significance_of_correlation (rho, w), NULL, RC_PVALUE);
}
}
}
if (factor->print & PRINT_DETERMINANT)
{
- int sign = 0;
- double det = 0.0;
-
- const int size = idata->corr->size1;
- gsl_permutation *p = gsl_permutation_calloc (size);
- gsl_matrix *tmp = gsl_matrix_calloc (size, size);
- gsl_matrix_memcpy (tmp, idata->corr);
-
- gsl_linalg_LU_decomp (tmp, p, &sign);
- det = gsl_linalg_LU_det (tmp, sign);
- gsl_permutation_free (p);
- gsl_matrix_free (tmp);
-
-
tab_text (t, 0, nr, TAB_LEFT | TAT_TITLE, _("Determinant"));
- tab_double (t, 1, nr, 0, det, NULL);
+
+ tab_double (t, 1, nr, 0, idata->detR, NULL, RC_OTHER);
}
tab_submit (t);
if (idata->cov == NULL)
{
msg (MW, _("The dataset contains no complete observations. No analysis will be performed."));
+ covariance_destroy (cov);
goto finish;
}
var_matrix = covariance_moments (cov, MOMENT_VARIANCE);
mean_matrix = covariance_moments (cov, MOMENT_MEAN);
idata->n = covariance_moments (cov, MOMENT_NONE);
+
if ( factor->method == METHOD_CORR)
{
idata->corr = correlation_from_covariance (idata->cov, var_matrix);
+
analysis_matrix = idata->corr;
}
else
analysis_matrix = idata->cov;
+
+ if (factor->print & PRINT_DETERMINANT
+ || factor->print & PRINT_KMO)
+ {
+ int sign = 0;
+
+ const int size = idata->corr->size1;
+ gsl_permutation *p = gsl_permutation_calloc (size);
+ gsl_matrix *tmp = gsl_matrix_calloc (size, size);
+ gsl_matrix_memcpy (tmp, idata->corr);
+
+ gsl_linalg_LU_decomp (tmp, p, &sign);
+ idata->detR = gsl_linalg_LU_det (tmp, sign);
+ gsl_permutation_free (p);
+ gsl_matrix_free (tmp);
+ }
+
if ( factor->print & PRINT_UNIVARIATE)
{
+ const struct fmt_spec *wfmt = factor->wv ? var_get_print_format (factor->wv) : & F_8_0;
const int nc = 4;
int i;
- const struct fmt_spec *wfmt = factor->wv ? var_get_print_format (factor->wv) : & F_8_0;
-
const int heading_columns = 1;
const int heading_rows = 1;
const int nr = heading_rows + factor->n_vars;
struct tab_table *t = tab_create (nc, nr);
+ tab_set_format (t, RC_WEIGHT, wfmt);
tab_title (t, _("Descriptive Statistics"));
tab_headers (t, heading_columns, 0, heading_rows, 0);
const struct variable *v = factor->vars[i];
tab_text (t, 0, i + heading_rows, TAB_LEFT | TAT_TITLE, var_to_string (v));
- tab_double (t, 1, i + heading_rows, 0, gsl_matrix_get (mean_matrix, i, i), NULL);
- tab_double (t, 2, i + heading_rows, 0, sqrt (gsl_matrix_get (var_matrix, i, i)), NULL);
- tab_double (t, 3, i + heading_rows, 0, gsl_matrix_get (idata->n, i, i), wfmt);
+ tab_double (t, 1, i + heading_rows, 0, gsl_matrix_get (mean_matrix, i, i), NULL, RC_OTHER);
+ tab_double (t, 2, i + heading_rows, 0, sqrt (gsl_matrix_get (var_matrix, i, i)), NULL, RC_OTHER);
+ tab_double (t, 3, i + heading_rows, 0, gsl_matrix_get (idata->n, i, i), NULL, RC_WEIGHT);
}
tab_submit (t);
}
+ if (factor->print & PRINT_KMO)
+ {
+ int i;
+ double sum_ssq_r = 0;
+ double sum_ssq_a = 0;
+
+ double df = factor->n_vars * ( factor->n_vars - 1) / 2;
+
+ double w = 0;
+
+
+ double xsq;
+
+ const int heading_columns = 2;
+ const int heading_rows = 0;
+
+ const int nr = heading_rows + 4;
+ const int nc = heading_columns + 1;
+
+ gsl_matrix *a, *x;
+
+ struct tab_table *t = tab_create (nc, nr);
+ tab_title (t, _("KMO and Bartlett's Test"));
+
+ x = clone_matrix (idata->corr);
+ gsl_linalg_cholesky_decomp (x);
+ gsl_linalg_cholesky_invert (x);
+
+ a = anti_image (x);
+
+ for (i = 0; i < x->size1; ++i)
+ {
+ sum_ssq_r += ssq_od_n (x, i);
+ sum_ssq_a += ssq_od_n (a, i);
+ }
+
+ gsl_matrix_free (a);
+ gsl_matrix_free (x);
+
+ tab_headers (t, heading_columns, 0, heading_rows, 0);
+
+ /* Outline the box */
+ tab_box (t,
+ TAL_2, TAL_2,
+ -1, -1,
+ 0, 0,
+ nc - 1, nr - 1);
+
+ tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+
+ tab_text (t, 0, 0, TAT_TITLE | TAB_LEFT, _("Kaiser-Meyer-Olkin Measure of Sampling Adequacy"));
+
+ tab_double (t, 2, 0, 0, sum_ssq_r / (sum_ssq_r + sum_ssq_a), NULL, RC_OTHER);
+
+ tab_text (t, 0, 1, TAT_TITLE | TAB_LEFT, _("Bartlett's Test of Sphericity"));
+
+ tab_text (t, 1, 1, TAT_TITLE, _("Approx. Chi-Square"));
+ tab_text (t, 1, 2, TAT_TITLE, _("df"));
+ tab_text (t, 1, 3, TAT_TITLE, _("Sig."));
+
+
+ /* The literature doesn't say what to do for the value of W when
+ missing values are involved. The best thing I can think of
+ is to take the mean average. */
+ w = 0;
+ for (i = 0; i < idata->n->size1; ++i)
+ w += gsl_matrix_get (idata->n, i, i);
+ w /= idata->n->size1;
+
+ xsq = w - 1 - (2 * factor->n_vars + 5) / 6.0;
+ xsq *= -log (idata->detR);
+
+ tab_double (t, 2, 1, 0, xsq, NULL, RC_OTHER);
+ tab_double (t, 2, 2, 0, df, NULL, RC_INTEGER);
+ tab_double (t, 2, 3, 0, gsl_cdf_chisq_Q (xsq, df), NULL, RC_PVALUE);
+
+
+ tab_submit (t);
+ }
+
show_correlation_matrix (factor, idata);
+ covariance_destroy (cov);
-#if 1
{
+ gsl_matrix *am = matrix_dup (analysis_matrix);
gsl_eigen_symmv_workspace *workspace = gsl_eigen_symmv_alloc (factor->n_vars);
- gsl_eigen_symmv (matrix_dup (analysis_matrix), idata->eval, idata->evec, workspace);
+ gsl_eigen_symmv (am, idata->eval, idata->evec, workspace);
gsl_eigen_symmv_free (workspace);
+ gsl_matrix_free (am);
}
gsl_eigen_symmv_sort (idata->eval, idata->evec, GSL_EIGEN_SORT_ABS_DESC);
-#endif
idata->n_extractions = n_extracted_factors (factor, idata);
if (idata->n_extractions == 0)
{
- msg (MW, _("The FACTOR criteria result in zero factors extracted. Therefore no analysis will be performed."));
+ msg (MW, _("The %s criteria result in zero factors extracted. Therefore no analysis will be performed."), "FACTOR");
goto finish;
}
if (idata->n_extractions > factor->n_vars)
{
- msg (MW, _("The FACTOR criteria result in more factors than variables, which is not meaningful. No analysis will be performed."));
+ msg (MW,
+ _("The %s criteria result in more factors than variables, which is not meaningful. No analysis will be performed."),
+ "FACTOR");
goto finish;
}
{
gsl_matrix *rotated_factors = NULL;
+ gsl_matrix *pattern_matrix = NULL;
+ gsl_matrix *fcm = NULL;
gsl_vector *rotated_loadings = NULL;
const gsl_vector *extracted_eigenvalues = NULL;
gsl_vector_memcpy (initial_communalities, idata->msr);
- for (i = 0; i < factor->iterations; ++i)
+ for (i = 0; i < factor->extraction_iterations; ++i)
{
double min, max;
gsl_vector_memcpy (diff, idata->msr);
{
rotated_factors = gsl_matrix_calloc (factor_matrix->size1, factor_matrix->size2);
rotated_loadings = gsl_vector_calloc (factor_matrix->size2);
+ if (factor->rotation == ROT_PROMAX)
+ {
+ pattern_matrix = gsl_matrix_calloc (factor_matrix->size1, factor_matrix->size2);
+ fcm = gsl_matrix_calloc (factor_matrix->size2, factor_matrix->size2);
+ }
+
- rotate (factor, factor_matrix, extracted_communalities, rotated_factors, rotated_loadings);
+ rotate (factor, factor_matrix, extracted_communalities, rotated_factors, rotated_loadings, pattern_matrix, fcm);
}
-
+
show_explained_variance (factor, idata, idata->eval, extracted_eigenvalues, rotated_loadings);
factor_matrix_workspace_free (fmw);
factor->extraction == EXTRACTION_PC ? _("Component Matrix") : _("Factor Matrix"),
factor_matrix);
+ if ( factor->rotation == ROT_PROMAX)
+ {
+ show_factor_matrix (factor, idata, _("Pattern Matrix"), pattern_matrix);
+ gsl_matrix_free (pattern_matrix);
+ }
+
if ( factor->rotation != ROT_NONE)
{
show_factor_matrix (factor, idata,
- factor->extraction == EXTRACTION_PC ? _("Rotated Component Matrix") : _("Rotated Factor Matrix"),
+ (factor->rotation == ROT_PROMAX) ? _("Structure Matrix") :
+ (factor->extraction == EXTRACTION_PC ? _("Rotated Component Matrix") : _("Rotated Factor Matrix")),
rotated_factors);
gsl_matrix_free (rotated_factors);
}
+ if ( factor->rotation == ROT_PROMAX)
+ {
+ show_factor_correlation (factor, fcm);
+ gsl_matrix_free (fcm);
+ }
-
+ gsl_matrix_free (factor_matrix);
+ gsl_vector_free (rotated_loadings);
gsl_vector_free (initial_communalities);
gsl_vector_free (extracted_communalities);
}
}
-