From: John Darrington Date: Thu, 28 Oct 2010 13:24:05 +0000 (+0200) Subject: Added implementation for the Cochran Q test X-Git-Tag: v0.7.7~163 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=257609763a5728ce3d18d6a31d2a15b6e1dba4ed;p=pspp-builds.git Added implementation for the Cochran Q test --- diff --git a/src/language/stats/automake.mk b/src/language/stats/automake.mk index 32a5c228..01bdf886 100644 --- a/src/language/stats/automake.mk +++ b/src/language/stats/automake.mk @@ -15,6 +15,7 @@ language_stats_sources = \ src/language/stats/autorecode.c \ src/language/stats/binomial.c src/language/stats/binomial.h \ src/language/stats/chisquare.c src/language/stats/chisquare.h \ + src/language/stats/cochran.c src/language/stats/cochran.h \ src/language/stats/correlations.c \ src/language/stats/descriptives.c \ src/language/stats/factor.c \ diff --git a/src/language/stats/cochran.c b/src/language/stats/cochran.c new file mode 100644 index 00000000..3b6af22d --- /dev/null +++ b/src/language/stats/cochran.c @@ -0,0 +1,244 @@ +/* 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 . */ + +#include + +#include "cochran.h" +#include "npar.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#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); +} diff --git a/src/language/stats/cochran.h b/src/language/stats/cochran.h new file mode 100644 index 00000000..1ea75053 --- /dev/null +++ b/src/language/stats/cochran.h @@ -0,0 +1,34 @@ +/* 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 . */ + +#if !cochran_h +#define cochran_h 1 + +#include +#include +#include + + + +void cochran_execute (const struct dataset *ds, + struct casereader *input, + enum mv_class exclude, + const struct npar_test *test, + bool, + double); + + +#endif diff --git a/src/language/stats/npar.c b/src/language/stats/npar.c index 053f021d..6bac48de 100644 --- a/src/language/stats/npar.c +++ b/src/language/stats/npar.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -79,6 +80,7 @@ struct cmd_npar_tests /* Count variables indicating how many of the subcommands have been given. */ int chisquare; + int cochran; int binomial; int wilcoxon; int sign; @@ -123,6 +125,7 @@ static int npar_chisquare (struct lexer *, struct dataset *, struct npar_specs * 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 *); @@ -139,6 +142,7 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests { npt->binomial = 0; npt->chisquare = 0; + npt->cochran = 0; npt->friedman = 0; npt->kruskal_wallis = 0; npt->mann_whitney = 0; @@ -152,7 +156,23 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests 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)) @@ -611,6 +631,35 @@ npar_friedman (struct lexer *lexer, struct dataset *ds, 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,