Re-implement MEANS.
[pspp] / src / language / stats / means-calc.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011, 2012, 2013, 2019 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 "data/case.h"
20 #include "data/format.h"
21 #include "data/variable.h"
22
23 #include "libpspp/bt.h"
24 #include "libpspp/hmap.h"
25 #include "libpspp/misc.h"
26 #include "libpspp/pool.h"
27
28 #include "math/moments.h"
29 #include "output/pivot-table.h"
30
31 #include <math.h>
32
33 #include "means.h"
34
35 #include "gettext.h"
36 #define _(msgid) gettext (msgid)
37 #define N_(msgid) (msgid)
38
39 struct statistic
40 {
41 };
42
43 struct statistic_simple
44 {
45   struct statistic parent;
46   double acc;
47 };
48
49 struct statistic_moment
50 {
51   struct statistic parent;
52   struct moments1 *mom;
53 };
54
55 static struct statistic *
56 default_create (struct pool *pool)
57 {
58   struct statistic_moment *pvd = pool_alloc (pool, sizeof *pvd);
59
60   pvd->mom = moments1_create (MOMENT_KURTOSIS);
61
62   return (struct statistic *) pvd;
63 }
64
65 static void
66 default_update (struct statistic *stat, double w, double x)
67 {
68   struct statistic_moment *pvd = (struct statistic_moment *) stat;
69
70   moments1_add (pvd->mom, x, w);
71 }
72
73 static void
74 default_destroy (struct statistic *stat)
75 {
76   struct statistic_moment *pvd = (struct statistic_moment *) stat;
77   moments1_destroy (pvd->mom);
78 }
79
80 static void
81 simple_destroy (struct statistic *stat UNUSED)
82 {
83 }
84
85 \f
86
87 /* HARMONIC MEAN: The reciprocal of the sum of the reciprocals:
88    1 / ( 1/(x_0) + 1/(x_1) + ... + 1/(x_{n-1}) ) */
89
90 struct harmonic_mean
91 {
92   struct statistic parent;
93   double rsum;
94   double n;
95 };
96
97 static struct statistic *
98 harmonic_create (struct pool *pool)
99 {
100   struct harmonic_mean *hm = pool_alloc (pool, sizeof *hm);
101
102   hm->rsum = 0;
103   hm->n = 0;
104
105   return (struct statistic *) hm;
106 }
107
108
109 static void
110 harmonic_update (struct statistic *stat, double w, double x)
111 {
112   struct harmonic_mean *hm = (struct harmonic_mean *) stat;
113   hm->rsum  += w / x;
114   hm->n += w;
115 }
116
117
118 static double
119 harmonic_get (const struct statistic *pvd)
120 {
121   const struct harmonic_mean *hm = (const struct harmonic_mean *) pvd;
122
123   return hm->n / hm->rsum;
124 }
125
126 \f
127
128 /* GEOMETRIC MEAN:  The nth root of the product of all n observations
129    pow ((x_0 * x_1 * ... x_{n - 1}), 1/n)  */
130 struct geometric_mean
131 {
132   struct statistic parent;
133   double prod;
134   double n;
135 };
136
137 static struct statistic *
138 geometric_create (struct pool *pool)
139 {
140   struct geometric_mean *gm = pool_alloc (pool, sizeof *gm);
141
142   gm->prod = 1.0;
143   gm->n = 0;
144
145   return (struct statistic *) gm;
146 }
147
148 static void
149 geometric_update (struct statistic  *pvd, double w, double x)
150 {
151   struct geometric_mean *gm = (struct geometric_mean *)pvd;
152   gm->prod  *=  pow (x, w);
153   gm->n += w;
154 }
155
156
157 static double
158 geometric_get (const struct statistic *pvd)
159 {
160   const struct geometric_mean *gm = (const struct geometric_mean *)pvd;
161   return pow (gm->prod, 1.0 / gm->n);
162 }
163
164 \f
165
166 static double
167 sum_get (const struct statistic *pvd)
168 {
169   double n, mean;
170
171   moments1_calculate (((struct statistic_moment *)pvd)->mom, &n, &mean, 0, 0, 0);
172
173   return mean * n;
174 }
175
176
177 static double
178 n_get (const struct statistic *pvd)
179 {
180   double n;
181
182   moments1_calculate (((struct statistic_moment *)pvd)->mom, &n, 0, 0, 0, 0);
183
184   return n;
185 }
186
187 static double
188 arithmean_get (const struct statistic *pvd)
189 {
190   double n, mean;
191
192   moments1_calculate (((struct statistic_moment *)pvd)->mom, &n, &mean, 0, 0, 0);
193
194   return mean;
195 }
196
197 static double
198 variance_get (const struct statistic *pvd)
199 {
200   double n, mean, variance;
201
202   moments1_calculate (((struct statistic_moment *)pvd)->mom, &n, &mean, &variance, 0, 0);
203
204   return variance;
205 }
206
207
208 static double
209 stddev_get (const struct statistic *pvd)
210 {
211   return sqrt (variance_get (pvd));
212 }
213
214
215 \f
216
217 static double
218 skew_get (const struct statistic *pvd)
219 {
220   double skew;
221
222   moments1_calculate (((struct statistic_moment *)pvd)->mom, NULL, NULL, NULL, &skew, 0);
223
224   return skew;
225 }
226
227 static double
228 sekurt_get (const struct statistic *pvd)
229 {
230   double n;
231
232   moments1_calculate (((struct statistic_moment *)pvd)->mom, &n, NULL, NULL, NULL, NULL);
233
234   return calc_sekurt (n);
235 }
236
237 static double
238 seskew_get (const struct statistic *pvd)
239 {
240   double n;
241
242   moments1_calculate (((struct statistic_moment *)pvd)->mom, &n, NULL, NULL, NULL, NULL);
243
244   return calc_seskew (n);
245 }
246
247 static double
248 kurt_get (const struct statistic *pvd)
249 {
250   double kurt;
251
252   moments1_calculate (((struct statistic_moment *)pvd)->mom, NULL, NULL, NULL, NULL, &kurt);
253
254   return kurt;
255 }
256
257 static double
258 semean_get (const struct statistic *pvd)
259 {
260   double n, var;
261
262   moments1_calculate (((struct statistic_moment *)pvd)->mom, &n, NULL, &var, NULL, NULL);
263
264   return sqrt (var / n);
265 }
266
267 \f
268
269 /* MIN: The smallest (closest to minus infinity) value. */
270
271 static struct statistic *
272 min_create (struct pool *pool)
273 {
274   struct statistic_simple *pvd = pool_alloc (pool, sizeof *pvd);
275
276   pvd->acc = DBL_MAX;
277
278   return (struct statistic *) pvd;
279 }
280
281 static void
282 min_update (struct statistic *pvd, double w UNUSED, double x)
283 {
284   double *r = &((struct statistic_simple *)pvd)->acc;
285
286   if (x < *r)
287     *r = x;
288 }
289
290 static double
291 min_get (const struct statistic *pvd)
292 {
293   double *r = &((struct statistic_simple *)pvd)->acc;
294
295   return *r;
296 }
297
298 /* MAX: The largest (closest to plus infinity) value. */
299
300 static struct statistic *
301 max_create (struct pool *pool)
302 {
303   struct statistic_simple *pvd = pool_alloc (pool, sizeof *pvd);
304
305   pvd->acc = -DBL_MAX;
306
307   return (struct statistic *) pvd;
308 }
309
310 static void
311 max_update (struct statistic *pvd, double w UNUSED, double x)
312 {
313   double *r = &((struct statistic_simple *)pvd)->acc;
314
315   if (x > *r)
316     *r = x;
317 }
318
319 static double
320 max_get (const struct statistic *pvd)
321 {
322   double *r = &((struct statistic_simple *)pvd)->acc;
323
324   return *r;
325 }
326
327 \f
328
329 struct range
330 {
331   struct statistic parent;
332   double min;
333   double max;
334 };
335
336 static struct statistic *
337 range_create (struct pool *pool)
338 {
339   struct range *r = pool_alloc (pool, sizeof *r);
340
341   r->min = DBL_MAX;
342   r->max = -DBL_MAX;
343
344   return (struct statistic *) r;
345 }
346
347 static void
348 range_update (struct statistic *pvd, double w UNUSED, double x)
349 {
350   struct range *r = (struct range *) pvd;
351
352   if (x > r->max)
353     r->max = x;
354
355   if (x < r->min)
356     r->min = x;
357 }
358
359 static double
360 range_get (const struct statistic *pvd)
361 {
362   const struct range *r = (struct range *) pvd;
363
364   return r->max - r->min;
365 }
366
367 \f
368
369 /* LAST: The last value (the one closest to the end of the file).  */
370
371 static struct statistic *
372 last_create (struct pool *pool)
373 {
374   struct statistic_simple *pvd = pool_alloc (pool, sizeof *pvd);
375
376   return (struct statistic *) pvd;
377 }
378
379 static void
380 last_update (struct statistic *pvd, double w UNUSED, double x)
381 {
382   struct statistic_simple *stat = (struct statistic_simple *) pvd;
383
384   stat->acc = x;
385 }
386
387 static double
388 last_get (const struct statistic *pvd)
389 {
390   const struct statistic_simple *stat = (struct statistic_simple *) pvd;
391
392   return stat->acc;
393 }
394
395 /* FIRST: The first value (the one closest to the start of the file).  */
396
397 static struct statistic *
398 first_create (struct pool *pool)
399 {
400   struct statistic_simple *pvd = pool_alloc (pool, sizeof *pvd);
401
402   pvd->acc = SYSMIS;
403
404   return (struct statistic *) pvd;
405 }
406
407 static void
408 first_update (struct statistic *pvd, double w UNUSED, double x)
409 {
410   struct statistic_simple *stat = (struct statistic_simple *) pvd;
411
412   if (stat->acc == SYSMIS)
413     stat->acc = x;
414 }
415
416 static double
417 first_get (const struct statistic *pvd)
418 {
419   const struct statistic_simple *stat = (struct statistic_simple *) pvd;
420
421   return stat->acc;
422 }
423
424 /* Table of cell_specs */
425 const struct cell_spec cell_spec[n_MEANS_STATISTICS] = {
426   {N_("Mean"),           "MEAN",      PIVOT_RC_OTHER,   default_create,   default_update,   arithmean_get, default_destroy},
427   {N_("N"),              "COUNT",     PIVOT_RC_COUNT,   default_create,   default_update,   n_get,         default_destroy},
428   {N_("Std. Deviation"), "STDDEV",    PIVOT_RC_OTHER,   default_create,   default_update,   stddev_get,    default_destroy},
429 #if 0
430   {N_("Median"),         "MEDIAN",    PIVOT_RC_OTHER,   default_create,   default_update,   NULL,          default_destroy},
431   {N_("Group Median"),   "GMEDIAN",   PIVOT_RC_OTHER,   default_create,   default_update,   NULL,          default_destroy},
432 #endif
433   {N_("S.E. Mean"),      "SEMEAN",    PIVOT_RC_OTHER,   default_create,   default_update,   semean_get,    default_destroy},
434   {N_("Sum"),            "SUM",       PIVOT_RC_OTHER,   default_create,   default_update,   sum_get,       default_destroy},
435   {N_("Minimum"),        "MIN",       PIVOT_RC_OTHER,   min_create,       min_update,       min_get,       simple_destroy},
436   {N_("Maximum"),        "MAX",       PIVOT_RC_OTHER,   max_create,       max_update,       max_get,       simple_destroy},
437   {N_("Range"),          "RANGE",     PIVOT_RC_OTHER,   range_create,     range_update,     range_get,     simple_destroy},
438   {N_("Variance"),       "VARIANCE",  PIVOT_RC_OTHER,   default_create,   default_update,   variance_get,  default_destroy},
439   {N_("Kurtosis"),       "KURT",      PIVOT_RC_OTHER,   default_create,   default_update,   kurt_get,      default_destroy},
440   {N_("S.E. Kurt"),      "SEKURT",    PIVOT_RC_OTHER,   default_create,   default_update,   sekurt_get,    default_destroy},
441   {N_("Skewness"),       "SKEW",      PIVOT_RC_OTHER,   default_create,   default_update,   skew_get,      default_destroy},
442   {N_("S.E. Skew"),      "SESKEW",    PIVOT_RC_OTHER,   default_create,   default_update,   seskew_get,    default_destroy},
443   {N_("First"),          "FIRST",     PIVOT_RC_OTHER,   first_create,     first_update,     first_get,     simple_destroy},
444   {N_("Last"),           "LAST",      PIVOT_RC_OTHER,   last_create,      last_update,      last_get,      simple_destroy},
445 #if 0
446   {N_("Percent N"),      "NPCT",      PIVOT_RC_PERCENT, default_create,   default_update,   NULL,          default_destroy},
447   {N_("Percent Sum"),    "SPCT",      PIVOT_RC_PERCENT, default_create,   default_update,   NULL,          default_destroy},
448 #endif
449   {N_("Harmonic Mean"),  "HARMONIC",  PIVOT_RC_OTHER,   harmonic_create,  harmonic_update,  harmonic_get,  simple_destroy},
450   {N_("Geom. Mean"),     "GEOMETRIC", PIVOT_RC_OTHER,   geometric_create, geometric_update, geometric_get, simple_destroy}
451 };