--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2010 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "cochran.h"
+#include "npar.h"
+#include <stdbool.h>
+#include <libpspp/cast.h>
+#include <libpspp/message.h>
+#include <libpspp/misc.h>
+
+#include <data/procedure.h>
+#include <data/dictionary.h>
+#include <data/variable.h>
+#include <data/val-type.h>
+#include <data/casereader.h>
+
+#include <gsl/gsl_cdf.h>
+
+#include <data/format.h>
+#include <output/tab.h>
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+
+struct cochran
+{
+ double success;
+ double failure;
+
+ double *hits;
+ double *misses;
+
+ const struct dictionary *dict;
+ double cc;
+ double df;
+ double q;
+};
+
+static void show_freqs_box (const struct one_sample_test *ost, const struct cochran *ch);
+static void show_sig_box (const struct cochran *ch);
+
+void
+cochran_execute (const struct dataset *ds,
+ struct casereader *input,
+ enum mv_class exclude,
+ const struct npar_test *test,
+ bool exact UNUSED, double timer UNUSED)
+{
+ struct one_sample_test *ct = UP_CAST (test, struct one_sample_test, parent);
+ int v;
+ struct cochran ch;
+ const struct dictionary *dict = dataset_dict (ds);
+ const struct variable *weight = dict_get_weight (dict);
+
+ struct ccase *c;
+ double rowsq = 0;
+ ch.cc = 0.0;
+ ch.dict = dict;
+ ch.success = SYSMIS;
+ ch.failure = SYSMIS;
+ ch.hits = xcalloc (ct->n_vars, sizeof *ch.hits);
+ ch.misses = xcalloc (ct->n_vars, sizeof *ch.misses);
+
+ for (; (c = casereader_read (input)); case_unref (c))
+ {
+ double case_hits = 0.0;
+ const double w = weight ? case_data (c, weight)->f: 1.0;
+ for (v = 0; v < ct->n_vars; ++v)
+ {
+ const struct variable *var = ct->vars[v];
+ const union value *val = case_data (c, var);
+
+ if ( var_is_value_missing (var, val, exclude))
+ continue;
+
+ if ( ch.success == SYSMIS)
+ {
+ ch.success = val->f;
+ }
+ else if (ch.failure == SYSMIS && val->f != ch.success)
+ {
+ ch.failure = val->f;
+ }
+ if ( ch.success == val->f)
+ {
+ ch.hits[v] += w;
+ case_hits += w;
+ }
+ else if ( ch.failure == val->f)
+ {
+ ch.misses[v] += w;
+ }
+ else
+ {
+ msg (MW, _("More than two values encountered. Cochran Q test will not be run."));
+ goto finish;
+ }
+ }
+ ch.cc += w;
+ rowsq += pow2 (case_hits);
+ }
+ casereader_destroy (input);
+
+ {
+ double c_l = 0;
+ double c_l2 = 0;
+ for (v = 0; v < ct->n_vars; ++v)
+ {
+ c_l += ch.hits[v];
+ c_l2 += pow2 (ch.hits[v]);
+ }
+
+ ch.q = ct->n_vars * c_l2;
+ ch.q -= pow2 (c_l);
+ ch.q *= ct->n_vars - 1;
+
+ ch.q /= ct->n_vars * c_l - rowsq;
+
+ ch.df = ct->n_vars - 1;
+ }
+
+ show_freqs_box (ct, &ch);
+ show_sig_box (&ch);
+
+ finish:
+
+ free (ch.hits);
+ free (ch.misses);
+}
+
+static void
+show_freqs_box (const struct one_sample_test *ost, const struct cochran *ct)
+{
+ int i;
+ const struct variable *weight = dict_get_weight (ct->dict);
+ const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
+
+ const int row_headers = 1;
+ const int column_headers = 2;
+ struct tab_table *table =
+ tab_create (row_headers + 2, column_headers + ost->n_vars);
+
+ tab_headers (table, row_headers, 0, column_headers, 0);
+
+ tab_title (table, _("Frequencies"));
+
+ /* Vertical lines inside the box */
+ tab_box (table, 1, 0, -1, TAL_1,
+ row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+ /* Box around the table */
+ tab_box (table, TAL_2, TAL_2, -1, -1,
+ 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+ tab_joint_text (table, 1, 0, 2, 0,
+ TAT_TITLE | TAB_CENTER, _("Value"));
+
+ tab_text_format (table, 1, 1, 0, _("Success (%g)"), ct->success);
+ tab_text_format (table, 2, 1, 0, _("Failure (%g)"), ct->failure);
+
+ tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers);
+ tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+ for (i = 0 ; i < ost->n_vars ; ++i)
+ {
+ tab_text (table, 0, column_headers + i,
+ TAB_LEFT, var_to_string (ost->vars[i]));
+
+ tab_double (table, 1, column_headers + i, 0,
+ ct->hits[i], wfmt);
+
+ tab_double (table, 2, column_headers + i, 0,
+ ct->misses[i], wfmt);
+ }
+
+ tab_submit (table);
+}
+
+
+
+static void
+show_sig_box (const struct cochran *ch)
+{
+ const struct variable *weight = dict_get_weight (ch->dict);
+ const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
+
+ const int row_headers = 1;
+ const int column_headers = 0;
+ struct tab_table *table =
+ tab_create (row_headers + 1, column_headers + 4);
+
+ tab_headers (table, row_headers, 0, column_headers, 0);
+
+ tab_title (table, _("Test Statistics"));
+
+ tab_text (table, 0, column_headers,
+ TAT_TITLE | TAB_LEFT , _("N"));
+
+ tab_text (table, 0, 1 + column_headers,
+ TAT_TITLE | TAB_LEFT , _("Cochran's Q"));
+
+ tab_text (table, 0, 2 + column_headers,
+ TAT_TITLE | TAB_LEFT, _("df"));
+
+ tab_text (table, 0, 3 + column_headers,
+ TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
+
+ /* Box around the table */
+ tab_box (table, TAL_2, TAL_2, -1, -1,
+ 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+ tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
+ tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+ tab_double (table, 1, column_headers,
+ 0, ch->cc, wfmt);
+
+ tab_double (table, 1, column_headers + 1,
+ 0, ch->q, 0);
+
+ tab_double (table, 1, column_headers + 2,
+ 0, ch->df, &F_8_0);
+
+ tab_double (table, 1, column_headers + 3,
+ 0, gsl_cdf_chisq_Q (ch->q, ch->df),
+ 0);
+
+ tab_submit (table);
+}
#include <language/lexer/value-parser.h>
#include <language/stats/binomial.h>
#include <language/stats/chisquare.h>
+#include <language/stats/cochran.h>
#include <language/stats/runs.h>
#include <language/stats/friedman.h>
#include <language/stats/kruskal-wallis.h>
/* Count variables indicating how many
of the subcommands have been given. */
int chisquare;
+ int cochran;
int binomial;
int wilcoxon;
int sign;
static int npar_binomial (struct lexer *, struct dataset *, struct npar_specs *);
static int npar_runs (struct lexer *, struct dataset *, struct npar_specs *);
static int npar_friedman (struct lexer *, struct dataset *, struct npar_specs *);
+static int npar_cochran (struct lexer *, struct dataset *, struct npar_specs *);
static int npar_wilcoxon (struct lexer *, struct dataset *, struct npar_specs *);
static int npar_sign (struct lexer *, struct dataset *, struct npar_specs *);
static int npar_kruskal_wallis (struct lexer *, struct dataset *, struct npar_specs *);
{
npt->binomial = 0;
npt->chisquare = 0;
+ npt->cochran = 0;
npt->friedman = 0;
npt->kruskal_wallis = 0;
npt->mann_whitney = 0;
memset (npt->a_statistics, 0, sizeof npt->a_statistics);
for (;;)
{
- if (lex_match_hyphenated_word (lexer, "FRIEDMAN"))
+ if (lex_match_hyphenated_word (lexer, "COCHRAN"))
+ {
+ npt->cochran++;
+ switch (npar_cochran (lexer, ds, nps))
+ {
+ case 0:
+ goto lossage;
+ case 1:
+ break;
+ case 2:
+ lex_error (lexer, NULL);
+ goto lossage;
+ default:
+ NOT_REACHED ();
+ }
+ }
+ else if (lex_match_hyphenated_word (lexer, "FRIEDMAN"))
{
npt->friedman++;
switch (npar_friedman (lexer, ds, nps))
return 1;
}
+static int
+npar_cochran (struct lexer *lexer, struct dataset *ds,
+ struct npar_specs *specs)
+{
+ struct one_sample_test *ft = pool_alloc (specs->pool, sizeof (*ft));
+ struct npar_test *nt = &ft->parent;
+
+ nt->execute = cochran_execute;
+ nt->insert_variables = one_sample_insert_variables;
+
+ lex_match (lexer, '=');
+
+ if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
+ &ft->vars, &ft->n_vars,
+ PV_NO_SCRATCH | PV_NO_DUPLICATE | PV_NUMERIC))
+ {
+ return 2;
+ }
+
+ specs->n_tests++;
+ specs->test = pool_realloc (specs->pool,
+ specs->test,
+ sizeof (*specs->test) * specs->n_tests);
+
+ specs->test[specs->n_tests - 1] = nt;
+
+ return 1;
+}
+
static int
npar_chisquare (struct lexer *lexer, struct dataset *ds,