1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2011, 2012 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 "data/case.h"
21 #include "data/casegrouper.h"
22 #include "data/casereader.h"
23 #include "data/dataset.h"
24 #include "data/dictionary.h"
25 #include "data/format.h"
26 #include "data/variable.h"
28 #include "language/command.h"
29 #include "language/lexer/lexer.h"
30 #include "language/lexer/variable-parser.h"
32 #include "libpspp/misc.h"
33 #include "libpspp/pool.h"
35 #include "math/categoricals.h"
36 #include "math/interaction.h"
37 #include "math/moments.h"
39 #include "output/tab.h"
44 #define _(msgid) gettext (msgid)
45 #define N_(msgid) (msgid)
57 typedef void *stat_create (const struct means *, struct pool *pool);
59 typedef void stat_update (const struct means *, void *stat, double w, double x);
61 typedef double stat_get (const struct means *, struct per_var_data *, void *aux);
66 /* Printable title for output */
69 /* Keyword for syntax */
86 harmonic_create (const struct means *means UNUSED, struct pool *pool)
88 struct harmonic_mean *hm = pool_alloc (pool, sizeof *hm);
98 harmonic_update (const struct means *means UNUSED, void *stat, double w, double x)
100 struct harmonic_mean *hm = stat;
107 harmonic_get (const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
109 struct harmonic_mean *hm = stat;
111 return hm->n / hm->rsum;
116 struct geometric_mean
124 geometric_create (const struct means *means UNUSED, struct pool *pool)
126 struct geometric_mean *gm = pool_alloc (pool, sizeof *gm);
136 geometric_update (const struct means *means UNUSED, void *stat, double w, double x)
138 struct geometric_mean *gm = stat;
139 gm->prod *= pow (x, w);
145 geometric_get (const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
147 struct geometric_mean *gm = stat;
149 return pow (gm->prod, 1.0 / gm->n);
155 sum_create (const struct means *means UNUSED, struct pool *pool)
161 sum_get (const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
165 moments1_calculate (pvd->mom, &n, &mean, 0, 0, 0);
172 n_create (const struct means *means UNUSED, struct pool *pool)
178 n_get (const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
182 moments1_calculate (pvd->mom, &n, 0, 0, 0, 0);
188 arithmean_create (const struct means *means UNUSED, struct pool *pool)
194 arithmean_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
198 moments1_calculate (pvd->mom, &n, &mean, 0, 0, 0);
204 stddev_create (const struct means *means UNUSED, struct pool *pool)
210 variance_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
212 double n, mean, variance;
214 moments1_calculate (pvd->mom, &n, &mean, &variance, 0, 0);
221 stddev_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
223 return sqrt (variance_get (means, pvd, stat));
230 skew_create (const struct means *means UNUSED, struct pool *pool)
236 skew_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
240 moments1_calculate (pvd->mom, NULL, NULL, NULL, &skew, 0);
246 sekurt_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
250 moments1_calculate (pvd->mom, &n, NULL, NULL, NULL, NULL);
252 return calc_sekurt (n);
258 seskew_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
262 moments1_calculate (pvd->mom, &n, NULL, NULL, NULL, NULL);
264 return calc_seskew (n);
270 kurt_create (const struct means *means UNUSED, struct pool *pool)
277 kurt_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
281 moments1_calculate (pvd->mom, NULL, NULL, NULL, NULL, &kurt);
288 semean_get (const struct means *means, struct per_var_data *pvd, void *stat)
292 moments1_calculate (pvd->mom, &n, NULL, &var, NULL, NULL);
294 return sqrt (var / n);
302 min_create (const struct means *means UNUSED, struct pool *pool)
304 double *r = pool_alloc (pool, sizeof *r);
312 min_update (const struct means *means UNUSED, void *stat, double w UNUSED, double x)
321 min_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
329 max_create (const struct means *means UNUSED, struct pool *pool)
331 double *r = pool_alloc (pool, sizeof *r);
339 max_update (const struct means *means UNUSED, void *stat, double w UNUSED, double x)
348 max_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
364 range_create (const struct means *means UNUSED, struct pool *pool)
366 struct range *r = pool_alloc (pool, sizeof *r);
375 range_update (const struct means *means UNUSED, void *stat, double w UNUSED, double x)
377 struct range *r = stat;
387 range_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
389 struct range *r = stat;
391 return r->max - r->min;
397 last_create (const struct means *means UNUSED, struct pool *pool)
399 double *l = pool_alloc (pool, sizeof *l);
405 last_update (const struct means *means UNUSED, void *stat, double w UNUSED, double x)
413 last_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
422 first_create (const struct means *means UNUSED, struct pool *pool)
424 double *f = pool_alloc (pool, sizeof *f);
432 first_update (const struct means *means UNUSED, void *stat, double w UNUSED, double x)
441 first_get (const const struct means *means UNUSED, struct per_var_data *pvd, void *stat)
450 /* Table of cell_specs */
451 static const struct cell_spec cell_spec[] = {
452 {N_("Mean"), "MEAN", NULL, NULL, arithmean_get},
453 {N_("N"), "COUNT", NULL, NULL, n_get},
454 {N_("Std. Deviation"), "STDDEV", NULL, NULL, stddev_get},
456 {N_("Median"), "MEDIAN", NULL, NULL, NULL},
457 {N_("Group Median"), "GMEDIAN", NULL, NULL, NULL},
459 {N_("S.E. Mean"), "SEMEAN", NULL, NULL, semean_get},
460 {N_("Sum"), "SUM", NULL, NULL, sum_get},
461 {N_("Min"), "MIN", min_create, min_update, min_get},
462 {N_("Max"), "MAX", max_create, max_update, max_get},
463 {N_("Range"), "RANGE", range_create, range_update, range_get},
464 {N_("Variance"), "VARIANCE", NULL, NULL, variance_get},
465 {N_("Kurtosis"), "KURT", NULL, NULL, kurt_get},
466 {N_("S.E. Kurt"), "SEKURT", NULL, NULL, sekurt_get},
467 {N_("Skewness"), "SKEW", NULL, NULL, skew_get},
468 {N_("S.E. Skew"), "SESKEW", NULL, NULL, seskew_get},
469 {N_("First"), "FIRST", first_create, first_update, first_get},
470 {N_("Last"), "LAST", last_create, last_update, last_get},
472 {N_("Percent N"), "NPCT", NULL, NULL, NULL},
473 {N_("Percent Sum"), "SPCT", NULL, NULL, NULL},
475 {N_("Harmonic Mean"), "HARMONIC", harmonic_create, harmonic_update, harmonic_get},
476 {N_("Geom. Mean"), "GEOMETRIC", geometric_create, geometric_update, geometric_get}
479 #define n_C (sizeof (cell_spec) / sizeof (struct cell_spec))
485 casenumber non_missing;
489 /* The thing parsed after TABLES= */
493 const struct variable **dep_vars;
495 size_t n_interactions;
496 struct interaction **interactions;
497 struct summary *summary;
499 size_t *n_factor_vars;
500 const struct variable ***factor_vars;
506 struct categoricals *cats;
511 const struct dictionary *dict;
513 struct mtable *table;
516 /* Missing value class for categorical variables */
517 enum mv_class exclude;
519 /* Missing value class for dependent variables */
520 enum mv_class dep_exclude;
522 /* an array indicating which statistics are to be calculated */
528 /* Pool on which cell functions may allocate data */
534 run_means (struct means *cmd, struct casereader *input,
535 const struct dataset *ds);
537 /* Append all the variables belonging to layer and all subsequent layers
538 to iact. And then append iact to the means->interaction.
539 This is a recursive function.
542 iact_append_factor (struct mtable *means, int layer,
543 const struct interaction *iact)
546 const struct variable **fv;
548 if (layer >= means->n_layers)
551 fv = means->factor_vars[layer];
553 for (v = 0; v < means->n_factor_vars[layer]; ++v)
555 struct interaction *nexti = interaction_clone (iact);
557 interaction_add_variable (nexti, fv[v]);
559 iact_append_factor (means, layer + 1, nexti);
561 if (layer == means->n_layers - 1)
563 means->interactions[means->ii++] = nexti;
569 parse_means_table_syntax (struct lexer *lexer, const struct means *cmd, struct mtable *table)
573 table->factor_vars = NULL;
574 table->n_factor_vars = NULL;
576 /* Dependent variable (s) */
577 if (!parse_variables_const (lexer, cmd->dict,
578 &table->dep_vars, &table->n_dep_vars,
579 PV_NO_DUPLICATE | PV_NUMERIC))
582 /* Factor variable (s) */
583 while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
585 if (lex_match (lexer, T_BY))
589 xrealloc (table->factor_vars,
590 sizeof (*table->factor_vars) * table->n_layers);
592 table->n_factor_vars =
593 xrealloc (table->n_factor_vars,
594 sizeof (*table->n_factor_vars) * table->n_layers);
596 if (!parse_variables_const (lexer, cmd->dict,
597 &table->factor_vars[table->n_layers - 1],
598 &table->n_factor_vars[table->n_layers -
610 If the match succeeds, the variable will be placed in VAR.
611 Returns true if successful */
613 lex_is_variable (struct lexer *lexer, const struct dictionary *dict,
617 if (lex_next_token (lexer, n) != T_ID)
620 tstr = lex_next_tokcstr (lexer, n);
622 if (NULL == dict_lookup_var (dict, tstr) )
630 cmd_means (struct lexer *lexer, struct dataset *ds)
636 bool more_tables = true;
638 means.exclude = MV_ANY;
639 means.dep_exclude = MV_ANY;
643 means.dict = dataset_dict (ds);
646 means.cells = xcalloc (means.n_cells, sizeof (*means.cells));
649 /* The first three items (MEAN, COUNT, STDDEV) are the default */
650 for (i = 0; i < 3; ++i)
654 /* Optional TABLES = */
655 if (lex_match_id (lexer, "TABLES"))
657 lex_force_match (lexer, T_EQUALS);
662 /* Parse the "tables" */
666 means.table = xrealloc (means.table, means.n_tables * sizeof (*means.table));
668 if (! parse_means_table_syntax (lexer, &means,
669 &means.table[means.n_tables - 1]))
674 /* Look ahead to see if there are more tables to be parsed */
676 if ( T_SLASH == lex_next_token (lexer, 0) )
678 if (lex_is_variable (lexer, means.dict, 1) )
681 lex_force_match (lexer, T_SLASH);
686 /* /MISSING subcommand */
687 while (lex_token (lexer) != T_ENDCMD)
689 lex_match (lexer, T_SLASH);
691 if (lex_match_id (lexer, "MISSING"))
694 If no MISSING subcommand is specified, each combination of
695 a dependent variable and categorical variables is handled
698 lex_match (lexer, T_EQUALS);
699 if (lex_match_id (lexer, "INCLUDE"))
702 Use the subcommand "/MISSING=INCLUDE" to include user-missing
703 values in the analysis.
706 means.exclude = MV_SYSTEM;
707 means.dep_exclude = MV_SYSTEM;
709 else if (lex_match_id (lexer, "TABLE"))
711 This is the default. (I think).
712 Every case containing a complete set of variables for a given
713 table. If any variable, categorical or dependent for in a table
714 is missing (as defined by what?), then that variable will
715 be dropped FOR THAT TABLE ONLY.
718 means.exclude = MV_ANY;
719 means.dep_exclude = MV_ANY;
721 else if (lex_match_id (lexer, "DEPENDENT"))
723 Use the command "/MISSING=DEPENDENT" to
724 include user-missing values for the categorical variables,
725 while excluding them for the dependent variables.
727 Cases are dropped only when user-missing values
728 appear in dependent variables. User-missing
729 values for categorical variables are treated according to
732 Cases are ALWAYS dropped when System Missing values appear
733 in the categorical variables.
736 means.dep_exclude = MV_ANY;
737 means.exclude = MV_SYSTEM;
741 lex_error (lexer, NULL);
745 else if (lex_match_id (lexer, "CELLS"))
747 lex_match (lexer, T_EQUALS);
749 /* The default values become overwritten */
751 while (lex_token (lexer) != T_ENDCMD
752 && lex_token (lexer) != T_SLASH)
755 for (k = 0; k < n_C; ++k)
757 if (lex_match_id (lexer, cell_spec[k].keyword))
760 xrealloc (means.cells,
761 ++means.n_cells * sizeof (*means.cells));
763 means.cells[means.n_cells - 1] = k;
769 lex_error (lexer, NULL);
776 lex_error (lexer, NULL);
781 means.pool = pool_create ();
784 for (t = 0; t < means.n_tables; ++t)
786 struct mtable *table = &means.table[t];
787 table->n_interactions = 1;
788 for (l = 0; l < table->n_layers; ++l)
790 const int n_vars = table->n_factor_vars[l];
791 table->n_interactions *= n_vars;
794 table->interactions =
795 xcalloc (table->n_interactions, sizeof (*table->interactions));
798 xcalloc (table->n_dep_vars * table->n_interactions, sizeof (*table->summary));
801 if (table->n_layers > 0)
802 iact_append_factor (table, 0, interaction_create (NULL));
804 table->interactions[0] = interaction_create (NULL);
810 struct casegrouper *grouper;
811 struct casereader *group;
814 grouper = casegrouper_create_splits (proc_open (ds), means.dict);
815 while (casegrouper_get_next_group (grouper, &group))
817 run_means (&means, group, ds);
819 ok = casegrouper_destroy (grouper);
820 ok = proc_commit (ds) && ok;
833 is_missing (const struct means *cmd,
834 const struct variable *dvar,
835 const struct interaction *iact,
836 const struct ccase *c)
838 if ( interaction_case_is_missing (iact, c, cmd->exclude) )
842 if (var_is_value_missing (dvar,
850 static void output_case_processing_summary (const struct mtable *);
852 static void output_report (const struct means *, int, const struct mtable *);
857 struct per_var_data *pvd;
863 create_n (const void *aux1, void *aux2)
866 const struct means *means = aux1;
867 struct mtable *table = aux2;
868 struct per_cat_data *per_cat_data = xmalloc (sizeof *per_cat_data);
870 struct per_var_data *pvd = xcalloc (table->n_dep_vars, sizeof *pvd);
872 for (v = 0; v < table->n_dep_vars; ++v)
874 enum moment maxmom = MOMENT_KURTOSIS;
875 struct per_var_data *pp = &pvd[v];
877 pp->cell_stats = xcalloc (means->n_cells, sizeof *pp->cell_stats);
880 for (i = 0; i < means->n_cells; ++i)
882 int csi = means->cells[i];
883 const struct cell_spec *cs = &cell_spec[csi];
886 pp->cell_stats[i] = cs->sc (means, means->pool);
889 pp->mom = moments1_create (maxmom);
893 per_cat_data->pvd = pvd;
894 per_cat_data->warn = true;
899 update_n (const void *aux1, void *aux2, void *user_data, const struct ccase *c)
903 const struct means *means = aux1;
904 struct mtable *table = aux2;
905 struct per_cat_data *per_cat_data = user_data;
907 double weight = dict_get_case_weight (means->dict, c, &per_cat_data->warn);
909 for (v = 0; v < table->n_dep_vars; ++v)
911 struct per_var_data *pvd = &per_cat_data->pvd[v];
913 const double x = case_data (c, table->dep_vars[v])->f;
915 for (i = 0; i < table->n_interactions; ++i)
917 if ( is_missing (means, table->dep_vars[v], table->interactions[i], c))
921 for (i = 0; i < means->n_cells; ++i)
923 const int csi = means->cells[i];
924 const struct cell_spec *cs = &cell_spec[csi];
933 moments1_add (pvd->mom, x, weight);
941 calculate_n (const void *aux1, void *aux2, void *user_data)
945 struct per_cat_data *per_cat_data = user_data;
946 const struct means *means = aux1;
947 struct mtable *table = aux2;
949 for (v = 0; v < table->n_dep_vars; ++v)
951 struct per_var_data *pvd = &per_cat_data->pvd[v];
952 for (i = 0; i < means->n_cells; ++i)
954 int csi = means->cells[i];
955 const struct cell_spec *cs = &cell_spec[csi];
958 cs->sd (means, pvd, pvd->cell_stats[i]);
965 run_means (struct means *cmd, struct casereader *input,
966 const struct dataset *ds)
969 const struct variable *wv = dict_get_weight (cmd->dict);
971 struct casereader *reader;
973 struct payload payload;
974 payload.create = create_n;
975 payload.update = update_n;
976 payload.destroy = calculate_n;
978 for (t = 0; t < cmd->n_tables; ++t)
980 struct mtable *table = &cmd->table[t];
982 = categoricals_create (table->interactions,
983 table->n_interactions, wv, cmd->exclude);
985 categoricals_set_payload (table->cats, &payload, cmd, table);
988 for (reader = casereader_clone (input);
989 (c = casereader_read (reader)) != NULL; case_unref (c))
991 for (t = 0; t < cmd->n_tables; ++t)
994 struct mtable *table = &cmd->table[t];
996 for (v = 0; v < table->n_dep_vars; ++v)
999 for (i = 0; i < table->n_interactions; ++i)
1001 const bool missing =
1002 is_missing (cmd, table->dep_vars[v],
1003 table->interactions[i], c);
1005 table->summary[v * table->n_interactions + i].missing++;
1007 table->summary[v * table->n_interactions + i].non_missing++;
1010 categoricals_update (table->cats, c);
1013 casereader_destroy (reader);
1015 for (t = 0; t < cmd->n_tables; ++t)
1017 struct mtable *table = &cmd->table[t];
1019 categoricals_done (table->cats);
1023 for (t = 0; t < cmd->n_tables; ++t)
1025 const struct mtable *table = &cmd->table[t];
1027 output_case_processing_summary (table);
1029 for (i = 0; i < table->n_interactions; ++i)
1031 output_report (cmd, i, table);
1034 categoricals_destroy (table->cats);
1040 output_case_processing_summary (const struct mtable *table)
1043 const int heading_columns = 1;
1044 const int heading_rows = 3;
1045 struct tab_table *t;
1047 const int nr = heading_rows + table->n_interactions * table->n_dep_vars;
1050 t = tab_create (nc, nr);
1051 tab_title (t, _("Case Processing Summary"));
1053 tab_headers (t, heading_columns, 0, heading_rows, 0);
1055 tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
1057 tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
1058 tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
1061 tab_joint_text (t, heading_columns, 0,
1062 nc - 1, 0, TAB_CENTER | TAT_TITLE, _("Cases"));
1064 tab_joint_text (t, 1, 1, 2, 1, TAB_CENTER | TAT_TITLE, _("Included"));
1065 tab_joint_text (t, 3, 1, 4, 1, TAB_CENTER | TAT_TITLE, _("Excluded"));
1066 tab_joint_text (t, 5, 1, 6, 1, TAB_CENTER | TAT_TITLE, _("Total"));
1068 tab_hline (t, TAL_1, heading_columns, nc - 1, 1);
1069 tab_hline (t, TAL_1, heading_columns, nc - 1, 2);
1072 for (i = 0; i < 3; ++i)
1074 tab_text (t, heading_columns + i * 2, 2, TAB_CENTER | TAT_TITLE,
1076 tab_text (t, heading_columns + i * 2 + 1, 2, TAB_CENTER | TAT_TITLE,
1080 for (v = 0; v < table->n_dep_vars; ++v)
1082 const struct variable *var = table->dep_vars[v];
1083 const char *dv_name = var_to_string (var);
1084 for (i = 0; i < table->n_interactions; ++i)
1086 const int row = v * table->n_interactions + i;
1087 const struct interaction *iact = table->interactions[i];
1091 ds_init_cstr (&str, dv_name);
1092 ds_put_cstr (&str, ": ");
1094 interaction_to_string (iact, &str);
1096 tab_text (t, 0, row + heading_rows,
1097 TAB_LEFT | TAT_TITLE, ds_cstr (&str));
1100 n_total = table->summary[row].missing +
1101 table->summary[row].non_missing;
1103 tab_double (t, 1, row + heading_rows,
1104 0, table->summary[row].non_missing, &F_8_0);
1106 tab_text_format (t, 2, row + heading_rows,
1108 table->summary[row].non_missing / (double) n_total * 100.0);
1111 tab_double (t, 3, row + heading_rows,
1112 0, table->summary[row].missing, &F_8_0);
1115 tab_text_format (t, 4, row + heading_rows,
1117 table->summary[row].missing / (double) n_total * 100.0);
1120 tab_double (t, 5, row + heading_rows,
1121 0, table->summary[row].missing +
1122 table->summary[row].non_missing, &F_8_0);
1124 tab_text_format (t, 6, row + heading_rows,
1126 n_total / (double) n_total * 100.0);
1139 output_report (const struct means *cmd, int iact_idx,
1140 const struct mtable *table)
1145 const struct interaction *iact = table->interactions[iact_idx];
1147 const int heading_columns = 1 + iact->n_vars;
1148 const int heading_rows = 1;
1149 struct tab_table *t;
1151 const int n_cats = categoricals_n_count (table->cats, iact_idx);
1153 const int nr = n_cats * table->n_dep_vars + heading_rows;
1155 const int nc = heading_columns + cmd->n_cells;
1157 t = tab_create (nc, nr);
1158 tab_title (t, _("Report"));
1160 tab_headers (t, heading_columns, 0, heading_rows, 0);
1162 tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
1164 tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
1165 tab_vline (t, TAL_2, iact->n_vars, 0, nr - 1);
1167 for (i = 0; i < iact->n_vars; ++i)
1169 tab_text (t, 1 + i, 0, TAB_CENTER | TAT_TITLE,
1170 var_to_string (iact->vars[i]));
1173 for (i = 0; i < cmd->n_cells; ++i)
1175 tab_text (t, heading_columns + i, 0,
1176 TAB_CENTER | TAT_TITLE,
1177 gettext (cell_spec[cmd->cells[i]].title));
1181 for (i = 0; i < n_cats; ++i)
1184 const struct ccase *c =
1185 categoricals_get_case_by_category_real (table->cats, iact_idx, i);
1187 for (dv = 0; dv < table->n_dep_vars; ++dv)
1190 heading_rows + dv * n_cats,
1191 TAB_RIGHT | TAT_TITLE,
1192 var_get_name (table->dep_vars[dv])
1196 tab_hline (t, TAL_1, 0, nc - 1, heading_rows + dv * n_cats);
1198 for (v = 0; v < iact->n_vars; ++v)
1200 const struct variable *var = iact->vars[v];
1201 const union value *val = case_data (c, var);
1203 ds_init_empty (&str);
1204 var_append_value_name (var, val, &str);
1206 tab_text (t, 1 + v, heading_rows + dv * n_cats + i,
1207 TAB_RIGHT | TAT_TITLE, ds_cstr (&str));
1214 for (grp = 0; grp < n_cats; ++grp)
1217 struct per_cat_data *per_cat_data =
1218 categoricals_get_user_data_by_category_real (table->cats, iact_idx, grp);
1220 for (dv = 0; dv < table->n_dep_vars; ++dv)
1222 const struct per_var_data *pvd = &per_cat_data->pvd[dv];
1223 for (i = 0; i < cmd->n_cells; ++i)
1225 const int csi = cmd->cells[i];
1226 const struct cell_spec *cs = &cell_spec[csi];
1228 double result = cs->sd (cmd, pvd, pvd->cell_stats[i]);
1230 tab_double (t, heading_columns + i,
1231 heading_rows + grp + dv * n_cats,