Создание функции хи-квадрат в lisp. [новичок]

Прежде всего, я прошу прощения за такой вопрос новичка. Моя цель — не просто создать функцию хи-квадрат, но и понять, как избежать общей проблемы, с которой я сталкиваюсь.

Мой код выглядит так:

(defun chi-square (expected-list observed-list)
(cond ((not (= (length expected-list) (length observed-list))) (print "Lists do not match in length.~%"))
    ((and (null expected-list) (null observed-list)) 0)
    (+ (/ (square (- (car observed-list) (car expected-list))) (car expected-list)) 
       (chi-square (cdr expected-list) (cdr observed-list)))
)
)

Я думаю, что третье условие работает нормально, за исключением случаев, когда оно вызывает хи-квадрат на nil, а на выходе nil просто читается 0. Я понимаю, почему это происходит (из-за второго условия), но я не знаю, как этого избежать . Например, если я даю ему ожидаемый список (100 50) и наблюдаемый список (90 60), я хочу, чтобы он выводил (+ 1 (+ 2 0)) = 3. Как я могу дать (хи-квадрат nil nil) значение 0, не завершая функцию прямо здесь и сейчас?

отказ от ответственности: я уверен, что есть лучшие способы сделать это и, возможно, функции, которые уже делают это. Я пишу эту функцию только в учебных целях.


person Thomas DeGreve    schedule 20.07.2016    source источник


Ответы (2)


В третьем случае cond есть ошибка: t отсутствует перед суммой:

(defun chi-square (expected-list observed-list)
  (cond ((not (= (length expected-list) (length observed-list)))
         (print "Lists do not match in length.~%"))
        ((and (null expected-list) (null observed-list)) 0)
        (t (+ (/ (square (- (car observed-list) (car expected-list))) (car expected-list))
              (chi-square (cdr expected-list) (cdr observed-list))))))

Вы можете найти синтаксис макроса cond в спецификации.

person Renzo    schedule 20.07.2016
comment
Спасибо, что нашли время ответить на мой вопрос. Это решило мою проблему. - person Thomas DeGreve; 20.07.2016

В общем, вы хотите избежать вызова чего-то вроде length внутри процедуры, когда вы повторяете один и тот же список. Это связано с тем, что время выполнения length пропорционально длине списка, который вы ему даете, и вы получите алгоритм O (N ^ 2), потому что вы вызываете его для каждого хвоста исходного списка. Это нормально, если ваш список всегда короткий. Лучше проверить длину списка только один раз в начале подпрограммы или отключиться в конце, когда один из списков равен null, а другой — нет. Во всяком случае, вот несколько других способов написать эту функцию:

;using built-in recursion combinators (mapcar & reduce)
(defun χ² (expected observed)
  (reduce #'+ (mapcar (lambda (e o) (/ (square (- o e)) e)) expected observed)))

;using loop
(defun chi-sqr (expected observed)
  (loop
     for e in expected
     for o in observed
     summing (/ (square (- o e)) e)))
person Greg Buchholz    schedule 20.07.2016