Removed 'Written by John Darrington' lines which got checked in with
[pspp-builds.git] / src / language / stats / chisquare.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    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, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20 #include <libpspp/compiler.h>
21 #include <libpspp/assertion.h>
22
23 #include <stdlib.h>
24
25 #include <data/case.h>
26 #include <data/casefile.h>
27 #include <data/casefilter.h>
28 #include <data/variable.h>
29 #include <data/dictionary.h>
30 #include <data/procedure.h>
31
32 #include <libpspp/message.h>
33 #include <libpspp/hash.h>
34 #include <libpspp/alloc.h>
35
36 #include <gsl/gsl_cdf.h>
37
38 #include <output/table.h>
39 #include <data/value-labels.h>
40
41 #include "npar.h"
42 #include "chisquare.h"
43 #include "freq.h"
44
45 #include <math.h>
46
47 #include "gettext.h"
48 #define _(msgid) gettext (msgid)
49
50
51
52
53 /* Return a hash table containing the frequency counts of each 
54    value of VAR in CF .
55    It is the caller's responsibility to free the hash table when 
56    no longer required.
57 */
58 static struct hsh_table *
59 create_freq_hash_with_range (const struct dictionary *dict, 
60                              const struct casefile *cf, 
61                              struct casefilter *filter,
62                              const struct variable *var, 
63                              double lo, 
64                              double hi)
65 {
66   bool warn = true;
67   float i_d;
68   struct ccase c;
69   struct casereader *r = casefile_get_reader (cf, filter);
70
71   struct hsh_table *freq_hash = 
72     hsh_create (4, compare_freq, hash_freq, 
73                 free_freq_mutable_hash,
74                 (void *) var);
75
76   /* Populate the hash with zero entries */
77   for (i_d = trunc (lo); i_d <= trunc (hi); i_d += 1.0 ) 
78     {
79       union value the_value;
80       struct freq_mutable *fr = xmalloc (sizeof (*fr));
81
82       the_value.f = i_d;
83
84       fr->value = value_dup (&the_value, 0);
85       fr->count = 0;
86
87       hsh_insert (freq_hash, fr);
88     }
89
90   while (casereader_read(r, &c))
91     {
92       union value obs_value;
93       struct freq **existing_fr;
94       struct freq *fr = xmalloc(sizeof  (*fr));
95       fr->value = case_data (&c, var);
96
97       if ( casefilter_variable_missing (filter, &c, var))
98         {
99           free (fr);
100           continue;
101         }
102
103       fr->count = dict_get_case_weight (dict, &c, &warn);
104
105       obs_value.f = trunc (fr->value->f);
106
107       if ( obs_value.f < lo || obs_value.f > hi) 
108         {
109           free (fr);
110           case_destroy (&c);
111           continue;
112         }
113
114       fr->value = &obs_value;
115
116       existing_fr = (struct freq **) hsh_probe (freq_hash, fr);
117
118       /* This must exist in the hash, because we previously populated it 
119          with zero counts */
120       assert (*existing_fr);
121
122       (*existing_fr)->count += fr->count;
123       free (fr);
124
125       case_destroy (&c);
126     }
127   casereader_destroy (r);
128
129   return freq_hash;
130 }
131
132
133 /* Return a hash table containing the frequency counts of each 
134    value of VAR in CF .
135    It is the caller's responsibility to free the hash table when 
136    no longer required.
137 */
138 static struct hsh_table *
139 create_freq_hash (const struct dictionary *dict, 
140                   const struct casefile *cf, 
141                   struct casefilter *filter, 
142                   const struct variable *var)
143 {
144   bool warn = true;
145   struct ccase c;
146   struct casereader *r = casefile_get_reader (cf, filter);
147
148   struct hsh_table *freq_hash = 
149     hsh_create (4, compare_freq, hash_freq, 
150                 free_freq_hash,
151                 (void *) var);
152
153   while (casereader_read(r, &c))
154     {
155       struct freq **existing_fr;
156       struct freq *fr = xmalloc(sizeof  (*fr));
157       fr->value = case_data (&c, var );
158
159       if ( casefilter_variable_missing (filter, &c, var))
160         {
161           free (fr);
162           continue;
163         }
164
165       fr->count = dict_get_case_weight (dict, &c, &warn);
166
167       existing_fr = (struct freq **) hsh_probe (freq_hash, fr);
168       if ( *existing_fr) 
169         {
170           (*existing_fr)->count += fr->count;
171           free (fr);
172         }
173       else
174         {
175           *existing_fr = fr;
176         }
177
178       case_destroy (&c);
179     }
180   casereader_destroy (r);
181
182   return freq_hash;
183 }
184
185
186
187 static struct tab_table *
188 create_variable_frequency_table (const struct dictionary *dict, 
189                                  const struct casefile *cf, 
190                                  struct casefilter *filter,
191                                  const struct chisquare_test *test, 
192                                  int v, 
193                                  struct hsh_table **freq_hash)
194
195 {
196   int i;
197   const struct one_sample_test *ost = (const struct one_sample_test*)test;
198   int n_cells;
199   struct tab_table *table ;
200   const struct variable *var =  ost->vars[v];
201
202   *freq_hash = create_freq_hash (dict, cf, filter, var);
203       
204   n_cells = hsh_count (*freq_hash);
205
206   if ( test->n_expected > 0 && n_cells != test->n_expected ) 
207     {
208       msg(ME, _("CHISQUARE test specified %d expected values, but"
209                 " %d distinct values were encountered in variable %s."), 
210           test->n_expected, n_cells, 
211           var_get_name (var)
212           );
213       return NULL;
214     }
215
216   table = tab_create(4, n_cells + 2, 0);
217   tab_dim (table, tab_natural_dimensions);
218
219   tab_title (table, var_to_string(var));
220   tab_text (table, 1, 0, TAB_LEFT, _("Observed N"));
221   tab_text (table, 2, 0, TAB_LEFT, _("Expected N"));
222   tab_text (table, 3, 0, TAB_LEFT, _("Residual"));
223         
224   tab_headers (table, 1, 0, 1, 0);
225
226   tab_box (table, TAL_1, TAL_1, -1, -1, 
227            0, 0, table->nc - 1, tab_nr(table) - 1 );
228
229   tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 1);
230
231   tab_vline (table, TAL_2, 1, 0, tab_nr(table) - 1);
232   for ( i = 2 ; i < 4 ; ++i ) 
233     tab_vline (table, TAL_1, i, 0, tab_nr(table) - 1);
234
235
236   tab_text (table, 0, table->nr - 1, TAB_LEFT, _("Total"));
237
238   return table;
239 }
240
241
242 static struct tab_table *
243 create_combo_frequency_table (const struct chisquare_test *test)
244 {
245   int i;
246   const struct one_sample_test *ost = (const struct one_sample_test*)test;
247
248   struct tab_table *table ;
249
250   int n_cells = test->hi - test->lo + 1;
251
252   table = tab_create(1 + ost->n_vars * 4, n_cells + 3, 0);
253   tab_dim (table, tab_natural_dimensions);
254
255   tab_title (table, _("Frequencies"));
256   for ( i = 0 ; i < ost->n_vars ; ++i ) 
257     {
258       const struct variable *var = ost->vars[i];
259       tab_text (table, i * 4 + 1, 1, TAB_LEFT, _("Category"));
260       tab_text (table, i * 4 + 2, 1, TAB_LEFT, _("Observed N"));
261       tab_text (table, i * 4 + 3, 1, TAB_LEFT, _("Expected N"));
262       tab_text (table, i * 4 + 4, 1, TAB_LEFT, _("Residual"));
263
264       tab_vline (table, TAL_2, i * 4 + 1, 
265                  0, tab_nr (table) - 1);
266
267       tab_vline (table, TAL_1, i * 4 + 2, 
268                  0, tab_nr (table) - 1);
269
270       tab_vline (table, TAL_1, i * 4 + 3, 
271                  1, tab_nr (table) - 1);
272
273       tab_vline (table, TAL_1, i * 4 + 4, 
274                  1, tab_nr (table) - 1);
275
276
277       tab_joint_text (table, 
278                       i * 4 + 1, 0,
279                       i * 4 + 4, 0,
280                       TAB_CENTER, 
281                       var_to_string (var));
282     }
283
284   for ( i = test->lo ; i <= test->hi ; ++i ) 
285     tab_float (table, 0, 2 + i - test->lo, 
286                TAB_LEFT, 1 + i - test->lo, 8, 0);
287         
288   tab_headers (table, 1, 0, 2, 0);
289
290   tab_box (table, TAL_1, TAL_1, -1, -1, 
291            0, 0, table->nc - 1, tab_nr(table) - 1 );
292
293   tab_hline (table, TAL_1, 1, tab_nc(table) - 1, 1);
294   tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 2);
295
296   tab_text (table, 0, table->nr - 1, TAB_LEFT, _("Total"));
297
298   return table;
299 }
300
301
302 static struct tab_table *
303 create_stats_table (const struct chisquare_test *test)
304 {
305   const struct one_sample_test *ost = (const struct one_sample_test*) test;
306   
307   struct tab_table *table = tab_create (1 + ost->n_vars, 4, 0);
308   tab_dim (table, tab_natural_dimensions);
309   tab_title (table, _("Test Statistics"));
310   tab_headers (table, 1, 0, 1, 0);
311
312   tab_box (table, TAL_1, TAL_1, -1, -1,
313            0, 0, tab_nc(table) - 1, tab_nr(table) - 1 );
314
315   tab_box (table, -1, -1, -1, TAL_1,
316            1, 0, tab_nc(table) - 1, tab_nr(table) - 1 );
317
318
319   tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
320   tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1);
321   
322
323   tab_text (table, 0, 1, TAB_LEFT, _("Chi-Square"));
324   tab_text (table, 0, 2, TAB_LEFT, _("df"));
325   tab_text (table, 0, 3, TAB_LEFT, _("Asymp. Sig."));
326
327   return table;
328 }
329
330
331 void 
332 chisquare_execute (const struct dataset *ds,
333                    const struct casefile *cf, 
334                    struct casefilter *filter,
335                    const struct npar_test *test)
336 {
337   const struct dictionary *dict = dataset_dict (ds);
338   int v, i;
339   struct one_sample_test *ost = (struct one_sample_test *) test;
340   struct chisquare_test *cst = (struct chisquare_test *) test;
341   struct tab_table *stats_table = create_stats_table (cst);
342   int n_cells = 0;
343   double total_expected = 0.0;
344
345   double *df = xzalloc (sizeof (*df) * ost->n_vars);
346   double *xsq = xzalloc (sizeof (*df) * ost->n_vars);
347   
348   for ( i = 0 ; i < cst->n_expected ; ++i ) 
349     total_expected += cst->expected[i];
350
351   if ( cst->ranged == false ) 
352     {
353       for ( v = 0 ; v < ost->n_vars ; ++v ) 
354         {
355           double total_obs = 0.0;
356           struct hsh_table *freq_hash = NULL;
357           struct tab_table *freq_table = 
358             create_variable_frequency_table(dict, cf, filter, cst, 
359                                             v, &freq_hash);
360
361           struct freq **ff = (struct freq **) hsh_sort (freq_hash);
362
363           if ( NULL == freq_table ) 
364             {
365               hsh_destroy (freq_hash);
366               continue;
367             }
368
369           n_cells = hsh_count (freq_hash);
370
371           for ( i = 0 ; i < n_cells ; ++i ) 
372             total_obs += ff[i]->count;
373
374           xsq[v] = 0.0;
375           for ( i = 0 ; i < n_cells ; ++i ) 
376             {
377               double exp;
378               const union value *observed_value = ff[i]->value;
379
380               /* The key */
381               tab_text (freq_table, 0, i + 1, TAB_LEFT, 
382                         var_get_value_name (ost->vars[v], observed_value));
383
384               /* The observed N */
385               tab_float (freq_table, 1, i + 1, TAB_NONE,
386                          ff[i]->count, 8, 0);
387
388               if ( cst->n_expected > 0 )
389                 exp = cst->expected[i] * total_obs / total_expected ; 
390               else
391                 exp = total_obs / (double) n_cells; 
392
393               tab_float (freq_table, 2, i + 1, TAB_NONE,
394                          exp, 8, 2);
395
396               /* The residual */
397               tab_float (freq_table, 3, i + 1, TAB_NONE,
398                          ff[i]->count - exp, 8, 2);
399
400               xsq[v] += (ff[i]->count - exp) * (ff[i]->count - exp) / exp;
401             }
402
403           df[v] = n_cells - 1.0;
404
405           tab_float (freq_table, 1, i + 1, TAB_NONE,
406                      total_obs, 8, 0);
407
408           tab_submit (freq_table);
409
410           hsh_destroy (freq_hash);
411         }
412     }
413   else  /* ranged == true */
414     {
415       struct tab_table *freq_table = create_combo_frequency_table (cst);
416       
417       n_cells = cst->hi - cst->lo + 1;
418
419       for ( v = 0 ; v < ost->n_vars ; ++v ) 
420         {
421           double total_obs = 0.0;
422           struct hsh_table *freq_hash = 
423             create_freq_hash_with_range (dict, cf, filter, ost->vars[v], 
424                                          cst->lo, cst->hi);
425
426           struct freq **ff = (struct freq **) hsh_sort (freq_hash);
427
428           assert ( n_cells == hsh_count (freq_hash));
429
430           for ( i = 0 ; i < hsh_count (freq_hash) ; ++i ) 
431             total_obs += ff[i]->count;
432
433           xsq[v] = 0.0;
434           for ( i = 0 ; i < hsh_count (freq_hash) ; ++i ) 
435             {
436               double exp;
437
438               const union value *observed_value = ff[i]->value;
439
440               /* The key */
441               tab_text  (freq_table, v * 4 + 1, i + 2 , TAB_LEFT, 
442                          var_get_value_name (ost->vars[v], observed_value));
443
444               /* The observed N */
445               tab_float (freq_table, v * 4 + 2, i + 2 , TAB_NONE,
446                          ff[i]->count, 8, 0);
447
448               if ( cst->n_expected > 0 )
449                 exp = cst->expected[i] * total_obs / total_expected ; 
450               else
451                 exp = total_obs / (double) hsh_count (freq_hash); 
452
453               /* The expected N */
454               tab_float (freq_table, v * 4 + 3, i + 2 , TAB_NONE,
455                          exp, 8, 2);
456
457               /* The residual */
458               tab_float (freq_table, v * 4 + 4, i + 2 , TAB_NONE,
459                          ff[i]->count - exp, 8, 2);
460
461               xsq[v] += (ff[i]->count - exp) * (ff[i]->count - exp) / exp;
462             }
463
464           
465           tab_float (freq_table, v * 4 + 2, tab_nr (freq_table) - 1, TAB_NONE,
466                      total_obs, 8, 0);
467           
468           df[v] = n_cells - 1.0;
469           
470           hsh_destroy (freq_hash);
471         }
472
473       tab_submit (freq_table);
474     }
475
476
477   /* Populate the summary statistics table */
478   for ( v = 0 ; v < ost->n_vars ; ++v ) 
479     {
480       const struct variable *var = ost->vars[v];
481
482       tab_text (stats_table, 1 + v, 0, TAB_CENTER, var_get_name (var));
483
484       tab_float (stats_table, 1 + v, 1, TAB_NONE, xsq[v], 8,3);
485       tab_float (stats_table, 1 + v, 2, TAB_NONE, df[v], 8,0);
486
487       tab_float (stats_table, 1 + v, 3, TAB_NONE, 
488                  gsl_cdf_chisq_Q (xsq[v], df[v]), 8,3);
489     }
490
491   free (xsq);
492   free (df);
493
494   tab_submit (stats_table);
495 }
496