]> code.delx.au - gnu-emacs/blob - lisp/calc/calc-stat.el
Add new functions for the root mean square of a (Calc) vector
[gnu-emacs] / lisp / calc / calc-stat.el
1 ;;; calc-stat.el --- statistical functions for Calc
2
3 ;; Copyright (C) 1990-1993, 2001-2015 Free Software Foundation, Inc.
4
5 ;; Author: David Gillespie <daveg@synaptics.com>
6 ;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;;; Code:
26
27 ;; This file is autoloaded from calc-ext.el.
28
29 (require 'calc-ext)
30 (require 'calc-macs)
31
32 ;;; Statistical operations on vectors.
33
34 (defun calc-vector-count (arg)
35 (interactive "P")
36 (calc-slow-wrapper
37 (calc-vector-op "coun" 'calcFunc-vcount arg)))
38
39 (defun calc-vector-sum (arg)
40 (interactive "P")
41 (calc-slow-wrapper
42 (if (calc-is-hyperbolic)
43 (calc-vector-op "vprd" 'calcFunc-vprod arg)
44 (calc-vector-op "vsum" 'calcFunc-vsum arg))))
45
46 (defun calc-vector-product (arg)
47 (interactive "P")
48 (calc-hyperbolic-func)
49 (calc-vector-sum arg))
50
51 (defun calc-vector-max (arg)
52 (interactive "P")
53 (calc-slow-wrapper
54 (if (calc-is-inverse)
55 (calc-vector-op "vmin" 'calcFunc-vmin arg)
56 (calc-vector-op "vmax" 'calcFunc-vmax arg))))
57
58 (defun calc-vector-min (arg)
59 (interactive "P")
60 (calc-invert-func)
61 (calc-vector-max arg))
62
63 (defun calc-vector-mean (arg)
64 (interactive "P")
65 (calc-slow-wrapper
66 (if (calc-is-hyperbolic)
67 (if (calc-is-inverse)
68 (calc-vector-op "harm" 'calcFunc-vhmean arg)
69 (calc-vector-op "medn" 'calcFunc-vmedian arg))
70 (if (calc-is-inverse)
71 (calc-vector-op "meae" 'calcFunc-vmeane arg)
72 (calc-vector-op "mean" 'calcFunc-vmean arg)))))
73
74 (defun calc-vector-rms (arg)
75 (interactive "P")
76 (calc-slow-wrapper
77 (calc-vector-op "rms" 'calcFunc-rms arg)))
78
79 (defun calc-vector-mean-error (arg)
80 (interactive "P")
81 (calc-invert-func)
82 (calc-vector-mean arg))
83
84 (defun calc-vector-median (arg)
85 (interactive "P")
86 (calc-hyperbolic-func)
87 (calc-vector-mean arg))
88
89 (defun calc-vector-harmonic-mean (arg)
90 (interactive "P")
91 (calc-invert-func)
92 (calc-hyperbolic-func)
93 (calc-vector-mean arg))
94
95 (defun calc-vector-geometric-mean (arg)
96 (interactive "P")
97 (calc-slow-wrapper
98 (if (calc-is-hyperbolic)
99 (calc-binary-op "geom" 'calcFunc-agmean arg)
100 (calc-vector-op "geom" 'calcFunc-vgmean arg))))
101
102 (defun calc-vector-sdev (arg)
103 (interactive "P")
104 (calc-slow-wrapper
105 (if (calc-is-hyperbolic)
106 (if (calc-is-inverse)
107 (calc-vector-op "pvar" 'calcFunc-vpvar arg)
108 (calc-vector-op "var" 'calcFunc-vvar arg))
109 (if (calc-is-inverse)
110 (calc-vector-op "psdv" 'calcFunc-vpsdev arg)
111 (calc-vector-op "sdev" 'calcFunc-vsdev arg)))))
112
113 (defun calc-vector-pop-sdev (arg)
114 (interactive "P")
115 (calc-invert-func)
116 (calc-vector-sdev arg))
117
118 (defun calc-vector-variance (arg)
119 (interactive "P")
120 (calc-hyperbolic-func)
121 (calc-vector-sdev arg))
122
123 (defun calc-vector-pop-variance (arg)
124 (interactive "P")
125 (calc-invert-func)
126 (calc-hyperbolic-func)
127 (calc-vector-sdev arg))
128
129 (defun calc-vector-covariance (arg)
130 (interactive "P")
131 (calc-slow-wrapper
132 (let ((n (if (eq arg 1) 1 2)))
133 (if (calc-is-hyperbolic)
134 (calc-enter-result n "corr" (cons 'calcFunc-vcorr
135 (calc-top-list-n n)))
136 (if (calc-is-inverse)
137 (calc-enter-result n "pcov" (cons 'calcFunc-vpcov
138 (calc-top-list-n n)))
139 (calc-enter-result n "cov" (cons 'calcFunc-vcov
140 (calc-top-list-n n))))))))
141
142 (defun calc-vector-pop-covariance (arg)
143 (interactive "P")
144 (calc-invert-func)
145 (calc-vector-covariance arg))
146
147 (defun calc-vector-correlation (arg)
148 (interactive "P")
149 (calc-hyperbolic-func)
150 (calc-vector-covariance arg))
151
152 (defun calc-vector-op (name func arg)
153 (setq calc-aborted-prefix name
154 arg (prefix-numeric-value arg))
155 (if (< arg 0)
156 (error "Negative arguments not allowed"))
157 (calc-enter-result arg name (cons func (calc-top-list-n arg))))
158
159
160
161
162 ;;; Useful statistical functions
163
164 ;;; Sum, product, etc., of one or more values or vectors.
165 ;;; Each argument must be either a number or a vector. Vectors
166 ;;; are flattened, but variables inside are assumed to represent
167 ;;; non-vectors.
168
169 (defun calcFunc-vsum (&rest vecs)
170 (math-reduce-many-vecs 'calcFunc-add 'calcFunc-vsum vecs 0))
171
172 (defun calcFunc-vprod (&rest vecs)
173 (math-reduce-many-vecs 'calcFunc-mul 'calcFunc-vprod vecs 1))
174
175 (defun calcFunc-vmax (&rest vecs)
176 (if (eq (car-safe (car vecs)) 'sdev)
177 '(var inf var-inf)
178 (if (eq (car-safe (car vecs)) 'intv)
179 (nth 3 (math-fix-int-intv (car vecs)))
180 (math-reduce-many-vecs 'calcFunc-max 'calcFunc-vmax vecs
181 '(neg (var inf var-inf))))))
182
183 (defun calcFunc-vmin (&rest vecs)
184 (if (eq (car-safe (car vecs)) 'sdev)
185 '(neg (var inf var-inf))
186 (if (eq (car-safe (car vecs)) 'intv)
187 (nth 2 (math-fix-int-intv (car vecs)))
188 (math-reduce-many-vecs 'calcFunc-min 'calcFunc-vmin vecs
189 '(var inf var-inf)))))
190
191 (defun math-reduce-many-vecs (func whole-func vecs ident)
192 (let ((const-part nil)
193 (symb-part nil)
194 val vec)
195 (let ((calc-internal-prec (+ calc-internal-prec 2)))
196 (while vecs
197 (setq val (car vecs))
198 (and (eq (car-safe val) 'var)
199 (eq (car-safe (calc-var-value (nth 2 val))) 'vec)
200 (setq val (symbol-value (nth 2 val))))
201 (cond ((Math-vectorp val)
202 (setq vec (append (and const-part (list const-part))
203 (math-flatten-vector val)))
204 (setq const-part (if vec
205 (calcFunc-reducer
206 (math-calcFunc-to-var func)
207 (cons 'vec vec))
208 ident)))
209 ((or (Math-objectp val) (math-infinitep val))
210 (setq const-part (if const-part
211 (funcall func const-part val)
212 val)))
213 (t
214 (setq symb-part (nconc symb-part (list val)))))
215 (setq vecs (cdr vecs))))
216 (if const-part
217 (progn
218 (setq const-part (math-normalize const-part))
219 (if symb-part
220 (funcall func const-part (cons whole-func symb-part))
221 const-part))
222 (if symb-part (cons whole-func symb-part) ident))))
223
224
225 ;;; Return the number of data elements among the arguments.
226 (defun calcFunc-vcount (&rest vecs)
227 (let ((count 0))
228 (while vecs
229 (setq count (if (Math-vectorp (car vecs))
230 (+ count (math-count-elements (car vecs)))
231 (if (Math-objectp (car vecs))
232 (1+ count)
233 (if (and (eq (car-safe (car vecs)) 'var)
234 (eq (car-safe (calc-var-value
235 (nth 2 (car vecs))))
236 'vec))
237 (+ count (math-count-elements
238 (symbol-value (nth 2 (car vecs)))))
239 (math-reject-arg (car vecs) 'numvecp))))
240 vecs (cdr vecs)))
241 count))
242
243 (defun math-count-elements (vec)
244 (let ((count 0))
245 (while (setq vec (cdr vec))
246 (setq count (if (Math-vectorp (car vec))
247 (+ count (math-count-elements (car vec)))
248 (1+ count))))
249 count))
250
251
252 (defun math-flatten-many-vecs (vecs)
253 (let ((p vecs)
254 (vec (list 'vec)))
255 (while p
256 (setq vec (nconc vec
257 (if (Math-vectorp (car p))
258 (math-flatten-vector (car p))
259 (if (Math-objectp (car p))
260 (list (car p))
261 (if (and (eq (car-safe (car p)) 'var)
262 (eq (car-safe (calc-var-value
263 (nth 2 (car p)))) 'vec))
264 (math-flatten-vector (symbol-value
265 (nth 2 (car p))))
266 (math-reject-arg (car p) 'numvecp)))))
267 p (cdr p)))
268 vec))
269
270 (defun calcFunc-vflat (&rest vecs)
271 (math-flatten-many-vecs vecs))
272
273 (defun math-split-sdev-vec (vec zero-ok)
274 (let ((means (list 'vec))
275 (wts (list 'vec))
276 (exact nil)
277 (p vec))
278 (while (and (setq p (cdr p))
279 (not (and (consp (car p))
280 (eq (car (car p)) 'sdev)))))
281 (if (null p)
282 (list vec nil)
283 (while (setq vec (cdr vec))
284 (if (and (consp (setq p (car vec)))
285 (eq (car p) 'sdev))
286 (or exact
287 (setq means (cons (nth 1 p) means)
288 wts (cons (nth 2 p) wts)))
289 (if zero-ok
290 (setq means (cons (nth 1 p) means)
291 wts (cons 0 wts))
292 (or exact
293 (setq means (list 'vec)
294 wts nil
295 exact t))
296 (setq means (cons p means)))))
297 (list (nreverse means)
298 (and wts (nreverse wts))))))
299
300
301 ;;; Return the arithmetic mean of the argument numbers or vectors.
302 ;;; (If numbers are error forms, computes the weighted mean.)
303 (defun calcFunc-vmean (&rest vecs)
304 (let* ((split (math-split-sdev-vec (math-flatten-many-vecs vecs) nil))
305 (means (car split))
306 (wts (nth 1 split))
307 (len (1- (length means))))
308 (if (= len 0)
309 (math-reject-arg nil "*Must be at least 1 argument")
310 (if (and (= len 1) (eq (car-safe (nth 1 means)) 'intv))
311 (let ((x (math-fix-int-intv (nth 1 means))))
312 (calcFunc-vmean (nth 2 x) (nth 3 x)))
313 (math-with-extra-prec 2
314 (if (and wts (> len 1))
315 (let* ((sqrwts (calcFunc-map '(var mul var-mul) wts wts))
316 (suminvsqrwts (calcFunc-reduce
317 '(var add var-add)
318 (calcFunc-map '(var div var-div)
319 1 sqrwts))))
320 (math-div (calcFunc-reduce '(var add var-add)
321 (calcFunc-map '(var div var-div)
322 means sqrwts))
323 suminvsqrwts))
324 (math-div (calcFunc-reduce '(var add var-add) means) len)))))))
325
326 (defun calcFunc-rms (a)
327 "Return the root-mean-square of the vector A."
328 (math-sqrt
329 (calcFunc-vmean
330 (calcFunc-map '(var abssqr var-abssqr) a))))
331
332 (defun math-fix-int-intv (x)
333 (if (math-floatp x)
334 x
335 (list 'intv 3
336 (if (memq (nth 1 x) '(2 3)) (nth 2 x) (math-add (nth 2 x) 1))
337 (if (memq (nth 1 x) '(1 3)) (nth 3 x) (math-sub (nth 3 x) 1)))))
338
339 ;;; Compute the mean with an error estimate.
340 (defun calcFunc-vmeane (&rest vecs)
341 (let* ((split (math-split-sdev-vec (math-flatten-many-vecs vecs) nil))
342 (means (car split))
343 (wts (nth 1 split))
344 (len (1- (length means))))
345 (if (= len 0)
346 (math-reject-arg nil "*Must be at least 1 argument")
347 (math-with-extra-prec 2
348 (if wts
349 (let* ((sqrwts (calcFunc-map '(var mul var-mul) wts wts))
350 (suminvsqrwts (calcFunc-reduce
351 '(var add var-add)
352 (calcFunc-map '(var div var-div)
353 1 sqrwts))))
354 (math-make-sdev
355 (math-div (calcFunc-reduce '(var add var-add)
356 (calcFunc-map '(var div var-div)
357 means sqrwts))
358 suminvsqrwts)
359 (list 'calcFunc-sqrt (math-div 1 suminvsqrwts))))
360 (let ((mean (math-div (calcFunc-reduce '(var add var-add) means)
361 len)))
362 (math-make-sdev
363 mean
364 (list 'calcFunc-sqrt
365 (math-div (calcFunc-reducer
366 '(var add var-add)
367 (calcFunc-map '(var pow var-pow)
368 (calcFunc-map '(var abs var-abs)
369 (calcFunc-map
370 '(var add var-add)
371 means
372 (math-neg mean)))
373 2))
374 (math-mul len (1- len)))))))))))
375
376
377 ;;; Compute the median of a list of values.
378 (defun calcFunc-vmedian (&rest vecs)
379 (let* ((flat (copy-sequence (cdr (math-flatten-many-vecs vecs))))
380 (p flat)
381 (len (length flat))
382 (hlen (/ len 2)))
383 (if (= len 0)
384 (math-reject-arg nil "*Must be at least 1 argument")
385 (if (and (= len 1) (memq (car-safe (car flat)) '(sdev intv)))
386 (calcFunc-vmean (car flat))
387 (while p
388 (if (eq (car-safe (car p)) 'sdev)
389 (setcar p (nth 1 (car p))))
390 (or (Math-anglep (car p))
391 (math-reject-arg (car p) 'anglep))
392 (setq p (cdr p)))
393 (setq flat (sort flat 'math-lessp))
394 (if (= (% len 2) 0)
395 (math-div (math-add (nth (1- hlen) flat) (nth hlen flat)) 2)
396 (nth hlen flat))))))
397
398
399 (defun calcFunc-vgmean (&rest vecs)
400 (let* ((flat (math-flatten-many-vecs vecs))
401 (len (1- (length flat))))
402 (if (= len 0)
403 (math-reject-arg nil "*Must be at least 1 argument")
404 (math-with-extra-prec 2
405 (let ((x (calcFunc-reduce '(var mul math-mul) flat)))
406 (if (= len 2)
407 (math-sqrt x)
408 (math-pow x (list 'frac 1 len))))))))
409
410
411 (defun calcFunc-agmean (a b)
412 (cond ((Math-equal a b) a)
413 ((math-zerop a) a)
414 ((math-zerop b) b)
415 (calc-symbolic-mode (math-inexact-result))
416 ((not (Math-realp a)) (math-reject-arg a 'realp))
417 ((not (Math-realp b)) (math-reject-arg b 'realp))
418 (t
419 (math-with-extra-prec 2
420 (setq a (math-float (math-abs a))
421 b (math-float (math-abs b)))
422 (let (mean)
423 (while (not (math-nearly-equal-float a b))
424 (setq mean (math-mul-float (math-add-float a b) '(float 5 -1))
425 b (math-sqrt-float (math-mul-float a b))
426 a mean))
427 a)))))
428
429
430 (defun calcFunc-vhmean (&rest vecs)
431 (let* ((flat (math-flatten-many-vecs vecs))
432 (len (1- (length flat))))
433 (if (= len 0)
434 (math-reject-arg nil "*Must be at least 1 argument")
435 (math-with-extra-prec 2
436 (math-div len
437 (calcFunc-reduce '(var add math-add)
438 (calcFunc-map '(var inv var-inv) flat)))))))
439
440
441
442 ;;; Compute the sample variance or standard deviation of numbers or vectors.
443 ;;; (If the numbers are error forms, only the mean part of them is used.)
444 (defun calcFunc-vvar (&rest vecs)
445 (if (and (= (length vecs) 1)
446 (memq (car-safe (car vecs)) '(sdev intv)))
447 (if (eq (car-safe (car vecs)) 'intv)
448 (math-intv-variance (car vecs) nil)
449 (math-sqr (nth 2 (car vecs))))
450 (math-covariance vecs nil nil 0)))
451
452 (defun calcFunc-vsdev (&rest vecs)
453 (if (and (= (length vecs) 1)
454 (memq (car-safe (car vecs)) '(sdev intv)))
455 (if (eq (car-safe (car vecs)) 'intv)
456 (if (math-floatp (car vecs))
457 (math-div (math-sub (nth 3 (car vecs)) (nth 2 (car vecs)))
458 (math-sqrt-12))
459 (math-sqrt (calcFunc-vvar (car vecs))))
460 (nth 2 (car vecs)))
461 (math-sqrt (math-covariance vecs nil nil 0))))
462
463 ;;; Compute the population variance or std deviation of numbers or vectors.
464 (defun calcFunc-vpvar (&rest vecs)
465 (if (and (= (length vecs) 1)
466 (memq (car-safe (car vecs)) '(sdev intv)))
467 (if (eq (car-safe (car vecs)) 'intv)
468 (math-intv-variance (car vecs) t)
469 (math-sqr (nth 2 (car vecs))))
470 (math-covariance vecs nil t 0)))
471
472 (defun calcFunc-vpsdev (&rest vecs)
473 (if (and (= (length vecs) 1)
474 (memq (car-safe (car vecs)) '(sdev intv)))
475 (if (eq (car-safe (car vecs)) 'intv)
476 (if (math-floatp (car vecs))
477 (math-div (math-sub (nth 3 (car vecs)) (nth 2 (car vecs)))
478 (math-sqrt-12))
479 (math-sqrt (calcFunc-vpvar (car vecs))))
480 (nth 2 (car vecs)))
481 (math-sqrt (math-covariance vecs nil t 0))))
482
483 (defun math-intv-variance (x pop)
484 (or (math-constp x) (math-reject-arg x 'constp))
485 (if (math-floatp x)
486 (math-div (math-sqr (math-sub (nth 3 x) (nth 2 x))) 12)
487 (let* ((x (math-fix-int-intv x))
488 (len (math-sub (nth 3 x) (nth 2 x)))
489 (hlen (math-quotient len 2)))
490 (math-div (if (math-evenp len)
491 (calcFunc-sum '(^ (var X var-X) 2) '(var X var-X)
492 (math-neg hlen) hlen)
493 (calcFunc-sum '(^ (- (var X var-X) (/ 1 2)) 2)
494 '(var X var-X)
495 (math-neg hlen) (math-add hlen 1)))
496 (if pop (math-add len 1) len)))))
497
498 ;;; Compute the covariance and linear correlation coefficient.
499 (defun calcFunc-vcov (vec1 &optional vec2)
500 (math-covariance (list vec1) (list vec2) nil 1))
501
502 (defun calcFunc-vpcov (vec1 &optional vec2)
503 (math-covariance (list vec1) (list vec2) t 1))
504
505 (defun calcFunc-vcorr (vec1 &optional vec2)
506 (math-covariance (list vec1) (list vec2) nil 2))
507
508
509 (defun math-covariance (vec1 vec2 pop mode)
510 (or (car vec2) (= mode 0)
511 (progn
512 (if (and (eq (car-safe (car vec1)) 'var)
513 (eq (car-safe (calc-var-value (nth 2 (car vec1)))) 'vec))
514 (setq vec1 (symbol-value (nth 2 (car vec1))))
515 (setq vec1 (car vec1)))
516 (or (math-matrixp vec1) (math-dimension-error))
517 (or (= (length (nth 1 vec1)) 3) (math-dimension-error))
518 (setq vec2 (list (math-mat-col vec1 2))
519 vec1 (list (math-mat-col vec1 1)))))
520 (math-with-extra-prec 2
521 (let* ((split1 (math-split-sdev-vec (math-flatten-many-vecs vec1) nil))
522 (means1 (car split1))
523 (wts1 (nth 1 split1))
524 split2 means2 (wts2 nil)
525 (sqrwts nil)
526 suminvsqrwts
527 (len (1- (length means1))))
528 (if (< len (if pop 1 2))
529 (math-reject-arg nil (if pop
530 "*Must be at least 1 argument"
531 "*Must be at least 2 arguments")))
532 (if (or wts1 wts2)
533 (setq sqrwts (math-add
534 (if wts1
535 (calcFunc-map '(var mul var-mul) wts1 wts1)
536 0)
537 (if wts2
538 (calcFunc-map '(var mul var-mul) wts2 wts2)
539 0))
540 suminvsqrwts (calcFunc-reduce
541 '(var add var-add)
542 (calcFunc-map '(var div var-div) 1 sqrwts))))
543 (or (= mode 0)
544 (progn
545 (setq split2 (math-split-sdev-vec (math-flatten-many-vecs vec2)
546 nil)
547 means2 (car split2)
548 wts2 (nth 2 split1))
549 (or (= len (1- (length means2))) (math-dimension-error))))
550 (let* ((diff1 (calcFunc-map
551 '(var add var-add)
552 means1
553 (if sqrwts
554 (math-div (calcFunc-reduce
555 '(var add var-add)
556 (calcFunc-map '(var div var-div)
557 means1 sqrwts))
558 (math-neg suminvsqrwts))
559 (math-div (calcFunc-reducer '(var add var-add) means1)
560 (- len)))))
561 (diff2 (if (= mode 0)
562 diff1
563 (calcFunc-map
564 '(var add var-add)
565 means2
566 (if sqrwts
567 (math-div (calcFunc-reduce
568 '(var add var-add)
569 (calcFunc-map '(var div var-div)
570 means2 sqrwts))
571 (math-neg suminvsqrwts))
572 (math-div (calcFunc-reducer '(var add var-add) means2)
573 (- len))))))
574 (covar (calcFunc-map '(var mul var-mul) diff1 diff2)))
575 (if sqrwts
576 (setq covar (calcFunc-map '(var div var-div) covar sqrwts)))
577 (math-div
578 (calcFunc-reducer '(var add var-add) covar)
579 (if (= mode 2)
580 (let ((var1 (calcFunc-map '(var mul var-mul) diff1 diff1))
581 (var2 (calcFunc-map '(var mul var-mul) diff2 diff2)))
582 (if sqrwts
583 (setq var1 (calcFunc-map '(var div var-div) var1 sqrwts)
584 var2 (calcFunc-map '(var div var-div) var2 sqrwts)))
585 (math-sqrt
586 (math-mul (calcFunc-reducer '(var add var-add) var1)
587 (calcFunc-reducer '(var add var-add) var2))))
588 (if sqrwts
589 (if pop
590 suminvsqrwts
591 (math-div (math-mul suminvsqrwts (1- len)) len))
592 (if pop len (1- len)))))))))
593
594 (provide 'calc-stat)
595
596 ;;; calc-stat.el ends here