1 /* PSPP - a program for statistical analysis. -*-c-*-
2 Copyright (C) 2010, 2011 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include "language/stats/friedman.h"
22 #include <gsl/gsl_cdf.h>
25 #include "data/casereader.h"
26 #include "data/dataset.h"
27 #include "data/dictionary.h"
28 #include "data/format.h"
29 #include "data/variable.h"
30 #include "libpspp/message.h"
31 #include "libpspp/misc.h"
32 #include "output/tab.h"
35 #define _(msgid) gettext (msgid)
44 const struct dictionary *dict;
47 static void show_ranks_box (const struct one_sample_test *ost,
48 const struct friedman *fr);
50 static void show_sig_box (const struct one_sample_test *ost,
51 const struct friedman *fr);
60 cmp_x (const void *a_, const void *b_)
62 const struct datum *a = a_;
63 const struct datum *b = b_;
72 cmp_posn (const void *a_, const void *b_)
74 const struct datum *a = a_;
75 const struct datum *b = b_;
77 if (a->posn < b->posn)
80 return (a->posn > b->posn);
84 friedman_execute (const struct dataset *ds,
85 struct casereader *input,
86 enum mv_class exclude,
87 const struct npar_test *test,
91 double numerator = 0.0;
92 double denominator = 0.0;
95 const struct dictionary *dict = dataset_dict (ds);
96 const struct variable *weight = dict_get_weight (dict);
98 struct one_sample_test *ost = UP_CAST (test, struct one_sample_test, parent);
99 struct friedman_test *ft = UP_CAST (ost, struct friedman_test, parent);
102 double sigma_t = 0.0;
103 struct datum *row = xcalloc (ost->n_vars, sizeof *row);
106 fr.rank_sum = xcalloc (ost->n_vars, sizeof *fr.rank_sum);
109 for (v = 0; v < ost->n_vars; ++v)
112 fr.rank_sum[v] = 0.0;
115 input = casereader_create_filter_weight (input, dict, &warn, NULL);
116 input = casereader_create_filter_missing (input,
117 ost->vars, ost->n_vars,
120 for (; (c = casereader_read (input)); case_unref (c))
122 double prev_x = SYSMIS;
125 const double w = weight ? case_data (c, weight)->f: 1.0;
129 for (v = 0; v < ost->n_vars; ++v)
131 const struct variable *var = ost->vars[v];
132 const union value *val = case_data (c, var);
136 qsort (row, ost->n_vars, sizeof *row, cmp_x);
137 for (v = 0; v < ost->n_vars; ++v)
140 /* Replace value by the Rank */
146 for (i = v - run_length; i < v; ++i)
148 row[i].x *= run_length ;
150 row[i].x /= run_length + 1;
152 row[v].x = row[v-1].x;
159 double t = run_length + 1;
160 sigma_t += w * (pow3 (t) - t);
168 double t = run_length + 1;
169 sigma_t += w * (pow3 (t) - t );
172 qsort (row, ost->n_vars, sizeof *row, cmp_posn);
174 for (v = 0; v < ost->n_vars; ++v)
175 fr.rank_sum[v] += row[v].x * w;
177 casereader_destroy (input);
181 for (v = 0; v < ost->n_vars; ++v)
183 numerator += pow2 (fr.rank_sum[v]);
188 numerator *= 12.0 / (fr.cc * ost->n_vars * ( ost->n_vars + 1));
189 numerator -= 3 * fr.cc * ( ost->n_vars + 1);
191 denominator = 1 - sigma_t / ( fr.cc * ost->n_vars * ( pow2 (ost->n_vars) - 1));
193 fr.chi_sq = numerator / denominator;
198 fr.w -= 3 * pow2 (fr.cc) *
199 ost->n_vars * pow2 (ost->n_vars + 1);
201 fr.w /= pow2 (fr.cc) * (pow3 (ost->n_vars) - ost->n_vars)
207 show_ranks_box (ost, &fr);
208 show_sig_box (ost, &fr);
217 show_ranks_box (const struct one_sample_test *ost, const struct friedman *fr)
220 const int row_headers = 1;
221 const int column_headers = 1;
222 struct tab_table *table =
223 tab_create (row_headers + 1, column_headers + ost->n_vars);
225 tab_headers (table, row_headers, 0, column_headers, 0);
227 tab_title (table, _("Ranks"));
229 /* Vertical lines inside the box */
230 tab_box (table, 1, 0, -1, TAL_1,
231 row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
233 /* Box around the table */
234 tab_box (table, TAL_2, TAL_2, -1, -1,
235 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
238 tab_text (table, 1, 0, 0, _("Mean Rank"));
240 tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers);
241 tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
243 for (i = 0 ; i < ost->n_vars ; ++i)
245 tab_text (table, 0, row_headers + i,
246 TAB_LEFT, var_to_string (ost->vars[i]));
248 tab_double (table, 1, row_headers + i,
249 0, fr->rank_sum[i] / fr->cc, 0);
257 show_sig_box (const struct one_sample_test *ost, const struct friedman *fr)
259 const struct friedman_test *ft = UP_CAST (ost, const struct friedman_test, parent);
262 const struct variable *weight = dict_get_weight (fr->dict);
263 const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
265 const int row_headers = 1;
266 const int column_headers = 0;
267 struct tab_table *table =
268 tab_create (row_headers + 1, column_headers + (ft->kendalls_w ? 5 : 4));
270 tab_headers (table, row_headers, 0, column_headers, 0);
272 tab_title (table, _("Test Statistics"));
274 tab_text (table, 0, column_headers + row++,
275 TAT_TITLE | TAB_LEFT , _("N"));
278 tab_text (table, 0, column_headers + row++,
279 TAT_TITLE | TAB_LEFT , _("Kendall's W"));
281 tab_text (table, 0, column_headers + row++,
282 TAT_TITLE | TAB_LEFT , _("Chi-Square"));
284 tab_text (table, 0, column_headers + row++,
285 TAT_TITLE | TAB_LEFT, _("df"));
287 tab_text (table, 0, column_headers + row++,
288 TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
290 /* Box around the table */
291 tab_box (table, TAL_2, TAL_2, -1, -1,
292 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
295 tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
296 tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
299 tab_double (table, 1, column_headers + row++,
303 tab_double (table, 1, column_headers + row++,
306 tab_double (table, 1, column_headers + row++,
309 tab_double (table, 1, column_headers + row++,
310 0, ost->n_vars - 1, &F_8_0);
312 tab_double (table, 1, column_headers + row++,
313 0, gsl_cdf_chisq_Q (fr->chi_sq, ost->n_vars - 1),