什么相当于Haskell中Ruby的pnormaldist统计函数?

前端之家收集整理的这篇文章主要介绍了什么相当于Haskell中Ruby的pnormaldist统计函数?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
如下所示: http://www.evanmiller.org/how-not-to-sort-by-average-rating.html

这是Ruby代码本身,在Statistics2库中实现:

# inverse of normal distribution ([2])
# Pr( (-\infty,x] ) = qn -> x
def pnormaldist(qn)
  b = [1.570796288,0.03706987906,-0.8364353589e-3,-0.2250947176e-3,0.6841218299e-5,0.5824238515e-5,-0.104527497e-5,0.8360937017e-7,-0.3231081277e-8,0.3657763036e-10,0.6936233982e-12]

  if(qn < 0.0 || 1.0 < qn)
    $stderr.printf("Error : qn <= 0 or qn >= 1  in pnorm()!\n")
    return 0.0;
  end
  qn == 0.5 and return 0.0

  w1 = qn
  qn > 0.5 and w1 = 1.0 - w1
  w3 = -Math.log(4.0 * w1 * (1.0 - w1))
  w1 = b[0]
  1.upto 10 do |i|
    w1 += b[i] * w3**i;
  end
  qn > 0.5 and return Math.sqrt(w1 * w3)
  -Math.sqrt(w1 * w3)
end

解决方法

翻译非常简单:
module PNormalDist where

pnormaldist :: (Ord a,Floating a) => a -> Either String a
pnormaldist qn
  | qn < 0 || 1 < qn = Left "Error: qn must be in [0,1]"
  | qn == 0.5        = Right 0.0
  | otherwise        = Right $
      let w3 = negate . log $4 * qn * (1 - qn)
          b = [ 1.570796288,0.6936233982e-12]
          w1 = sum . zipWith (*) b $iterate (*w3) 1
      in (signum $qn - 0.5) * sqrt (w1 * w3)

首先,让我们看一下ruby – 它返回一个值,但有时它会输出一条错误信息(当给出一个不正确的参数时).这不是很滑稽,所以
让我们的返回值为字符串a – 如果给出不正确的参数,我们将返回带有错误消息的Left String,否则返回Right a.

现在我们检查顶部的两个案例:

> qn< 0 || 1< qn =左“错误:qn必须在[0,1]” - 这是错误条件,当qn超出范围时.
> qn == 0.5 =正确0.0 – 这是ruby检查qn == 0.5并返回* 0.0

接下来,我们在ruby代码中定义w1.但是我们稍后重新定义了几行,这不是非常ruby.我们第一次存储在w1中的值
在w3的定义中立即使用,为什么我们不跳过将它存储在w1中?我们甚至不需要做qn> 0.5和w1 = 1.0 – w1步,因为
我们在w3的定义中使用了产品w1 *(1.0 – w1).

所以我们跳过所有这些,直接进入定义w3 =否定. log $4 * qn *(1 – qn).

接下来是b的定义,它是ruby代码的直接提升(ruby的数组文字语法是haskell的列表语法).

这是最棘手的一点 – 定义w3的最终价值. ruby代码的作用

w1 = b[0]
1.upto 10 do |i|
  w1 += b[i] * w3**i;
end

是什么称为折叠 – 将一组值(存储在ruby数组中)减少为单个值.我们可以使用Array#reduce更功能地(但仍然在ruby中)重述这个:

w1 = b.zip(0..10).reduce(0) do |accum,(bval,i)|
  accum + bval * w3^i
end

注意我是如何使用标识b [0] == b [0] * w3 ^ 0将b [0]推入循环.

现在我们可以直接将它移植到haskell,但它有点难看

w1 = foldl 0 (\accum (bval,i) -> accum + bval * w3**i) $zip b [0..10]

相反,我把它分成了几个步骤 – 首先,我们不需要我,我们只需要w3的功能(从w3 ^ 0 == 1开始),所以
让我们用迭代(* w3)1计算那些.

然后,我们最终只需要他们的产品,而不是将这些元素与b元素成对,我们可以将它们拉入其中
使用zipWith(*)b的每对产品.

现在我们的折叠功能非常简单 – 我们只需要总结产品,我们可以使用总和.

最后,根据qn是大于还是小于0.5,我们决定是否返回正负sqrt(w1 * w3)(我们
已经知道它不相等).因此,不要像在ruby代码中那样计算两个不同位置的平方根,
我计算了一次,并根据qn – 0.5(signum just returns the sign of a value)的符号将其乘以1或-1.

猜你在找的Ruby相关文章