X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Faggregate.c;h=02257f9434f29555bcb2538f5b321a961d099788;hb=ed09f0f21add5e56e8395a5e8589cda6f96420bf;hp=18d78f238ae1f3038168cad0538d119c8903a0c5;hpb=707848060e414fe93458834446dd7cdbf800667f;p=pspp diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index 18d78f238a..02257f9434 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2008 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 @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include "minmax.h" #include "xalloc.h" @@ -75,12 +77,17 @@ struct agr_var char *string; bool saw_missing; struct moments1 *moments; + double cc; + + struct variable *subject; + struct variable *weight; + struct casewriter *writer; }; /* Aggregation functions. */ enum { - NONE, SUM, MEAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN, + NONE, SUM, MEAN, MEDIAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN, FOUT, N, NU, NMISS, NUMISS, FIRST, LAST, N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS, FUNC = 0x1f, /* Function mask. */ @@ -92,7 +99,7 @@ struct agr_func { const char *name; /* Aggregation function name. */ size_t n_args; /* Number of arguments. */ - enum var_type alpha_type; /* When given ALPHA arguments, output type. */ + enum val_type alpha_type; /* When given ALPHA arguments, output type. */ struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */ }; @@ -102,26 +109,27 @@ static const struct agr_func agr_func_tab[] = {"", 0, -1, {0, 0, 0}}, {"SUM", 0, -1, {FMT_F, 8, 2}}, {"MEAN", 0, -1, {FMT_F, 8, 2}}, + {"MEDIAN", 0, -1, {FMT_F, 8, 2}}, {"SD", 0, -1, {FMT_F, 8, 2}}, - {"MAX", 0, VAR_STRING, {-1, -1, -1}}, - {"MIN", 0, VAR_STRING, {-1, -1, -1}}, - {"PGT", 1, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"PLT", 1, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"PIN", 2, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"POUT", 2, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"FGT", 1, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"FLT", 1, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"FIN", 2, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"FOUT", 2, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NUMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"FIRST", 0, VAR_STRING, {-1, -1, -1}}, - {"LAST", 0, VAR_STRING, {-1, -1, -1}}, + {"MAX", 0, VAL_STRING, {-1, -1, -1}}, + {"MIN", 0, VAL_STRING, {-1, -1, -1}}, + {"PGT", 1, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"PLT", 1, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"PIN", 2, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"POUT", 2, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"FGT", 1, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FLT", 1, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FIN", 2, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FOUT", 2, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NUMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"FIRST", 0, VAL_STRING, {-1, -1, -1}}, + {"LAST", 0, VAL_STRING, {-1, -1, -1}}, {NULL, 0, -1, {-1, -1, -1}}, - {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, + {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, }; /* Missing value types. */ @@ -135,7 +143,7 @@ enum missing_treatment struct agr_proc { /* Break variables. */ - struct case_ordering *sort; /* Sort criteria. */ + struct subcase sort; /* Sort criteria (break variables). */ const struct variable **break_vars; /* Break variables. */ size_t break_var_cnt; /* Number of break variables. */ struct ccase break_case; /* Last values of break variables. */ @@ -149,6 +157,7 @@ struct agr_proc static void initialize_aggregate_info (struct agr_proc *, const struct ccase *); + static void accumulate_aggregate_info (struct agr_proc *, const struct ccase *); /* Prototypes. */ @@ -182,6 +191,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) agr.dict = dict_create (); agr.src_dict = dict; + subcase_init_empty (&agr.sort); dict_set_label (agr.dict, dict_get_label (dict)); dict_set_documents (agr.dict, dict_get_documents (dict)); @@ -220,13 +230,10 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) int i; lex_match (lexer, '='); - agr.sort = parse_case_ordering (lexer, dict, - - &saw_direction); - if (agr.sort == NULL) + if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars, + &saw_direction)) goto error; - case_ordering_get_vars (agr.sort, - &agr.break_vars, &agr.break_var_cnt); + agr.break_var_cnt = subcase_get_n_fields (&agr.sort); for (i = 0; i < agr.break_var_cnt; i++) dict_clone_var_assert (agr.dict, agr.break_vars[i], @@ -277,10 +284,10 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) } input = proc_open (ds); - if (agr.sort != NULL && !presorted) + if (!subcase_is_empty (&agr.sort) && !presorted) { - input = sort_execute (input, agr.sort); - agr.sort = NULL; + input = sort_execute (input, &agr.sort); + subcase_clear (&agr.sort); } for (grouper = casegrouper_create_vars (input, agr.break_vars, @@ -344,7 +351,8 @@ error: /* Parse all the aggregate functions. */ static bool -parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, struct agr_proc *agr) +parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, + struct agr_proc *agr) { struct agr_var *tail; /* Tail of linked list starting at agr->vars. */ @@ -478,12 +486,12 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s if (lex_token (lexer) == T_STRING) { arg[i].c = ds_xstrdup (lex_tokstr (lexer)); - type = VAR_STRING; + type = VAL_STRING; } else if (lex_is_number (lexer)) { arg[i].f = lex_tokval (lexer); - type = VAR_NUMERIC; + type = VAL_NUMERIC; } else { @@ -545,7 +553,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s variables. */ for (i = 0; i < n_dest; i++) { - struct agr_var *v = xmalloc (sizeof *v); + struct agr_var *v = xzalloc (sizeof *v); /* Add variable to chain. */ if (agr->agr_vars != NULL) @@ -573,12 +581,12 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s v->string = xmalloc (var_get_width (src[i])); } - if (function->alpha_type == VAR_STRING) + if (function->alpha_type == VAL_STRING) destvar = dict_clone_var (agr->dict, v->src, dest[i]); else { assert (var_is_numeric (v->src) - || function->alpha_type == VAR_NUMERIC); + || function->alpha_type == VAL_NUMERIC); destvar = dict_create_var (agr->dict, dest[i], 0); if (destvar != NULL) { @@ -684,7 +692,7 @@ agr_destroy (struct agr_proc *agr) { struct agr_var *iter, *next; - case_ordering_destroy (agr->sort); + subcase_destroy (&agr->sort); free (agr->break_vars); case_destroy (&agr->break_case); for (iter = agr->agr_vars; iter; iter = next) @@ -703,6 +711,10 @@ agr_destroy (struct agr_proc *agr) } else if (iter->function == SD) moments1_destroy (iter->moments); + + var_destroy (iter->subject); + var_destroy (iter->weight); + free (iter); } if (agr->dict != NULL) @@ -755,6 +767,25 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->dbl[0] += v->f * weight; iter->dbl[1] += weight; break; + case MEDIAN: + { + double wv ; + struct ccase cout; + case_create (&cout, 2); + + case_data_rw (&cout, iter->subject)->f = + case_data (input, iter->src)->f; + + wv = dict_get_case_weight (agr->src_dict, input, NULL); + + case_data_rw (&cout, iter->weight)->f = wv; + + iter->cc += wv; + + casewriter_write (iter->writer, &cout); + case_destroy (&cout); + } + break; case SD: moments1_add (iter->moments, v->f, weight); break; @@ -911,6 +942,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) { union value *v = case_data_rw (&c, i->dest); + if (agr->missing == COLUMNWISE && i->saw_missing && (i->function & FUNC) != N && (i->function & FUNC) != NU && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS) @@ -919,6 +951,9 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) memset (v->s, ' ', var_get_width (i->dest)); else v->f = SYSMIS; + + casewriter_destroy (i->writer); + continue; } @@ -930,6 +965,25 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) case MEAN: v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS; break; + case MEDIAN: + { + struct casereader *sorted_reader; + struct order_stats *median = percentile_create (0.5, i->cc); + + sorted_reader = casewriter_make_reader (i->writer); + + order_stats_accumulate (&median, 1, + sorted_reader, + i->weight, + i->subject, + i->exclude); + + v->f = percentile_calculate ((struct percentile *) median, + PC_HAVERAGE); + + statistic_destroy ((struct statistic *) median); + } + break; case SD: { double variance; @@ -1044,6 +1098,23 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) case MAX | FSTRING: memset (iter->string, 0, var_get_width (iter->src)); break; + case MEDIAN: + { + struct subcase ordering; + + if ( ! iter->subject) + iter->subject = var_create_internal (0); + + if ( ! iter->weight) + iter->weight = var_create_internal (1); + + subcase_init_var (&ordering, iter->subject, SC_ASCEND); + iter->writer = sort_create_writer (&ordering, 2); + subcase_destroy (&ordering); + + iter->cc = 0; + } + break; case SD: if (iter->moments == NULL) iter->moments = moments1_create (MOMENT_VARIANCE);