【问题标题】:Learning LISP - Defining a stdev function学习 LISP - 定义 stdev 函数
【发布时间】:2016-09-11 17:26:51
【问题描述】:

我对 LISP 非常陌生(如有任何愚蠢的错误请见谅),今年的第一个实验室指出:

定义一个函数,STDEV,它将计算数字列表的标准差(查找公式)

我写了这段代码,但我不知道为什么它拒绝工作:

(defun stdev (x)
  (sqrt (/ (apply '+ (expt (- x (/ (apply '+ x)
                                   (length x)))
                           2))
           (length x))))


(setq a '(1 2 3 4 5))

(STDEV a)

但在运行时会产生错误:"(1 2 3 4 5) is not a number"

我相信我已经正确地模拟了标准差公式(尽管我不会把它放在自己身上犯一个愚蠢的错误),但是为什么我的程序不喜欢我给它评估的数字列表?这种新编码风格的输入很可能是一个简单的错误,但非常感谢任何和所有帮助!

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

    使用缩进。我已经编辑了你的问题:

    (defun stdev (x)
      (sqrt (/ (apply '+ (expt (- x (/ (apply '+ x)
                                       (length x)))
                               2))
               (length x))))
    

    expt 返回一个数字。你打电话给(apply '+ some-number)

    你也可以从一个列表中减去一个数字。

    为什么?

    一般来说,我建议使用 Lisp 侦听器(又名 REPL)来获取工作代码:

    计算平均值:

    CL-USER 21 > (let ((l (list 1 2 3 4 5)))
                   (/ (reduce #'+ l)
                      (length l)))
    3
    

    使用mapcar 减去平均值和平方:

    CL-USER 22 > (mapcar (lambda (item)
                           (expt (- item 3) 2))
                         (list 1 2 3 4 5))
    (4 1 0 1 4)
    

    将方差计算为上面的平均值:

    CL-USER 23 > (let ((l (list 4 1 0 1 4)))
                   (/ (reduce #'+ l)
                      (length l)))
    2
    

    取平方根得到标准差

    CL-USER 24 > (sqrt 2)
    1.4142135
    

    那么你只需要组装成几个函数:averagevariancestandard-deviation

    【讨论】:

    • 我的理由是我需要对 x 实例的每个实例进行平方 - 均值:(xi - xmean)^2。然后总结所有这些结果值。因为正如您所说,expt 返回一个数字,也许我需要在 lambda 表达式中执行 expt 以实现对列表中每个实例进行平方的目标。
    • @JohnBucher:但apply 不会那样做。见mapcar
    • 我是 LISP 的超级新手,因此只学习过 mapcar、lambda 和 defun,也不是很深入。我怎样才能使程序接受一个列表,而不是使用代码中给出的列表。第一个很简单,应该是:(defun avg(x)(/ (reduce '+ x) (length x)))。但第二部分给我带来了问题。我不知道(项目)是什么,它是重要的还是只是一个控股名称。然后代替 (list 1 2 3 4 5)) 我尝试将其替换为我的 A 列表,但它似乎不喜欢我的做法 (list 'x)/('x)/(x) ,那些不起作用
    • @JohnBucher:至少做三个函数:平均值、方差和标准差。
    • 我几乎完成了,只是遇到了一个问题。我的三个语句是:(setq a '(1 2 3 4 5))、(defun avg(x)(/ (reduce '+ x) (length x))) 和 (defun STDEV (x)(sqrt(/ (reduce '+ (mapcar (lambda(x) (expt (- x (avg a) ) 2)) a) ) (length x)))) 这将起作用并产生正确的输出,但这仅仅是因为 a 被硬编码为stdev 如此处所示:(expt (- x (avg a) ) 2)) a) )。我尝试将 a 更改为 x,然后更改为 'x,但程序不喜欢这样并引发错误。如何使程序在运行时使用给定的列表而不是硬编码的列表?
    【解决方案2】:

    a 是您的列表时,您将选择- a ...

    不是一个完整的答案,因为这是家庭作业,但是:你想先计算平均值,你可以实现一个 sum 函数,你需要两次,折叠,你可以应用一个辅助函数或 lambda 表达式使用映射到列表的每个元素。

    【讨论】: