3b6af22d6d512bc14fd6285fb9ac08ce878f643c
[pspp-builds.git] / src / language / stats / cochran.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "cochran.h"
20 #include "npar.h"
21 #include <stdbool.h>
22 #include <libpspp/cast.h>
23 #include <libpspp/message.h>
24 #include <libpspp/misc.h>
25
26 #include <data/procedure.h>
27 #include <data/dictionary.h>
28 #include <data/variable.h>
29 #include <data/val-type.h>
30 #include <data/casereader.h>
31
32 #include <gsl/gsl_cdf.h>
33
34 #include <data/format.h>
35 #include <output/tab.h>
36 #include "gettext.h"
37 #define _(msgid) gettext (msgid)
38
39
40 struct cochran
41 {
42   double success;
43   double failure;
44
45   double *hits;
46   double *misses;
47
48   const struct dictionary *dict;
49   double cc;
50   double df;
51   double q;
52 };
53
54 static void show_freqs_box (const struct one_sample_test *ost, const struct cochran *ch);
55 static void show_sig_box (const struct cochran *ch);
56
57 void
58 cochran_execute (const struct dataset *ds,
59               struct casereader *input,
60               enum mv_class exclude,
61               const struct npar_test *test,
62               bool exact UNUSED, double timer UNUSED)
63 {
64   struct one_sample_test *ct = UP_CAST (test, struct one_sample_test, parent);
65   int v;
66   struct cochran ch;
67   const struct dictionary *dict = dataset_dict (ds);
68   const struct variable *weight = dict_get_weight (dict);
69
70   struct ccase *c;
71   double rowsq = 0;
72   ch.cc = 0.0;
73   ch.dict = dict;
74   ch.success = SYSMIS;
75   ch.failure = SYSMIS;
76   ch.hits = xcalloc (ct->n_vars, sizeof *ch.hits);
77   ch.misses = xcalloc (ct->n_vars, sizeof *ch.misses);
78
79   for (; (c = casereader_read (input)); case_unref (c))
80     {
81       double case_hits = 0.0;
82       const double w = weight ? case_data (c, weight)->f: 1.0;
83       for (v = 0; v < ct->n_vars; ++v)
84         {
85           const struct variable *var = ct->vars[v];
86           const union value *val = case_data (c, var);
87
88           if ( var_is_value_missing (var, val, exclude))
89             continue;
90
91           if ( ch.success == SYSMIS)
92             {
93               ch.success = val->f;
94             }
95           else if (ch.failure == SYSMIS && val->f != ch.success)
96             {
97               ch.failure = val->f;
98             }
99           if ( ch.success == val->f)
100             {
101               ch.hits[v] += w;
102               case_hits += w;
103             }
104           else if ( ch.failure == val->f)
105             {
106               ch.misses[v] += w;
107             }
108           else
109             {
110               msg (MW, _("More than two values encountered.  Cochran Q test will not be run."));
111               goto finish;
112             }
113         }
114       ch.cc += w;
115       rowsq += pow2 (case_hits);
116     }
117   casereader_destroy (input);
118   
119   {
120     double c_l = 0;
121     double c_l2 = 0;
122     for (v = 0; v < ct->n_vars; ++v)
123       {
124         c_l += ch.hits[v];
125         c_l2 += pow2 (ch.hits[v]);
126       }
127
128     ch.q = ct->n_vars * c_l2;
129     ch.q -= pow2 (c_l);
130     ch.q *= ct->n_vars - 1;
131
132     ch.q /= ct->n_vars * c_l - rowsq;
133   
134     ch.df = ct->n_vars - 1;
135   }
136
137   show_freqs_box (ct, &ch);
138   show_sig_box (&ch);
139
140  finish:
141
142   free (ch.hits);
143   free (ch.misses);
144 }
145
146 static void
147 show_freqs_box (const struct one_sample_test *ost, const struct cochran *ct)
148 {
149   int i;
150   const struct variable *weight = dict_get_weight (ct->dict);
151   const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
152
153   const int row_headers = 1;
154   const int column_headers = 2;
155   struct tab_table *table =
156     tab_create (row_headers + 2, column_headers + ost->n_vars);
157
158   tab_headers (table, row_headers, 0, column_headers, 0);
159
160   tab_title (table, _("Frequencies"));
161
162   /* Vertical lines inside the box */
163   tab_box (table, 1, 0, -1, TAL_1,
164            row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
165
166   /* Box around the table */
167   tab_box (table, TAL_2, TAL_2, -1, -1,
168            0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
169
170   tab_joint_text (table, 1, 0, 2, 0,
171                   TAT_TITLE | TAB_CENTER, _("Value"));
172
173   tab_text_format (table, 1, 1, 0, _("Success (%g)"), ct->success);
174   tab_text_format (table, 2, 1, 0, _("Failure (%g)"), ct->failure);
175
176   tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers);
177   tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
178
179   for (i = 0 ; i < ost->n_vars ; ++i)
180     {
181       tab_text (table, 0, column_headers + i,
182                 TAB_LEFT, var_to_string (ost->vars[i]));
183
184       tab_double (table, 1, column_headers + i, 0,
185                   ct->hits[i], wfmt);
186
187       tab_double (table, 2, column_headers + i, 0,
188                   ct->misses[i], wfmt);
189     }
190
191   tab_submit (table);
192 }
193
194
195
196 static void
197 show_sig_box (const struct cochran *ch)
198 {
199   const struct variable *weight = dict_get_weight (ch->dict);
200   const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
201
202   const int row_headers = 1;
203   const int column_headers = 0;
204   struct tab_table *table =
205     tab_create (row_headers + 1, column_headers + 4);
206
207   tab_headers (table, row_headers, 0, column_headers, 0);
208
209   tab_title (table, _("Test Statistics"));
210
211   tab_text (table,  0, column_headers,
212             TAT_TITLE | TAB_LEFT , _("N"));
213
214   tab_text (table,  0, 1 + column_headers,
215             TAT_TITLE | TAB_LEFT , _("Cochran's Q"));
216
217   tab_text (table,  0, 2 + column_headers,
218             TAT_TITLE | TAB_LEFT, _("df"));
219
220   tab_text (table,  0, 3 + column_headers,
221             TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
222
223   /* Box around the table */
224   tab_box (table, TAL_2, TAL_2, -1, -1,
225            0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
226
227   tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
228   tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
229
230   tab_double (table, 1, column_headers, 
231               0, ch->cc, wfmt);
232
233   tab_double (table, 1, column_headers + 1, 
234               0, ch->q, 0);
235
236   tab_double (table, 1, column_headers + 2, 
237               0, ch->df, &F_8_0);
238
239   tab_double (table, 1, column_headers + 3, 
240               0, gsl_cdf_chisq_Q (ch->q, ch->df), 
241               0);
242
243   tab_submit (table);
244 }