Common Lispで統計関数を車輪の再発明

Common Lispで統計関数を書いてみました。和・平均・標本分散・平方和くらいが計算できれば、まずは何かできるのでは、という感じです。

;; Sum
;; (sum '(1 2 3 4)) ==> 10
;;
(defun sum (x)
  (if (null x)
      0
      (+ (first x) (sum (rest x)))))


;; Arithmetic Mean
;; (mean '(1 2 3 4)) ==> 2.5
;;
(defun mean (x)
  (/ (sum x) (length x)))


;; Sample Variance
;; (vars '(1 2 3 4)) ==> 5/3
;;
(defun vars-sub (x mu)
  (if (null x)
      0
      (+ (expt (- (first x) mu) 2 ) (vars-sub (rest x) mu))))
(defun vars (x)
  (/ (vars-sub x (mean x)) (- (length x) 1)))

;; Sum of Squares
;; (sum-of-squares '(1 2 3 4)) ==> 30
;;
(defun sum-of-squares (x)
  (if (null x)
      0
      (+ (* (first x) (first x)) (sum-of-squares (rest x)))))

ただ、内積を定義すれば、(inner-product x x)とすれば良くなるので、平方和は必要なくなってしまいますね。

;; Inner Product
;; (inner-product '(1 2 3 4) '(5 6 7 8)) ==> 70
;; (inner-product '(1 2 3 4) '(5 6 7)) ==> nil (because lengths differ)
;;
(defun inner-product-sub (x y)
  (if (or (null x)
	  (null y)
	  (/= (length x) (length y)))
      nil
      (cons (* (first x) (first y)) (inner-product-sub (rest x) (rest y)))))
(defun inner-product (x y)
  (sum (inner-product-sub x y)))

sum-of-squaresもinner-productも末尾再帰ではないので、長いベクトルの計算をするときにはメモリ効率がとても悪くなります。どうにかしないといけませんね。