如何在Perl中给出正态分布的点计算概率?

时间:2009-09-04 02:57:01

标签: perl r statistics probability

Perl中是否有一个包允许您计算每个给定点的概率分布高度。例如,这可以用R这样做:

> dnorm(0, mean=4,sd=10)
> 0.03682701

即,点x = 0的概率属于正态分布,均值= 4且sd = 10,为0.0368。 我看了Statistics::Distribution,但它没有给出那个 这样做的功能。

7 个答案:

答案 0 :(得分:8)

dnorm(0,mean = 4,sd = 10) not 给你这样一个点发生的概率。在probability density function

上引用维基百科
  

在概率论中,概率   密度函数(pdf) - 参考   作为概率分布   函数1 - 或随机密度   变量是描述的函数   每个人的概率密度   指向样本空间。该   随机变量的概率   属于给定集合的是由。给出的   它的密度积分超过   集。

你提到的概率是

R> pnorm(0, 4, 10)
[1] 0.3446

或从N(4,10)分布中获得等于或小于0的值的34.46%。

关于你的Perl问题:如果你知道如何在R中完成它,但是需要它来自Perl,也许你需要编写一个基于R的libRmath的Perl扩展(在Debian中由r-mathlib包提供)来获取那些Perl的功能?这不需要R解释器。

否则,您可以尝试使用GNU GSL或Cephes库来访问这些特殊功能。

答案 1 :(得分:3)

为什么不沿着这些方向发展(我在R中写作,但可以在perl with Statistics :: Distribution中完成):

dn <- function(x=0 # value
               ,mean=0 # mean 
               ,sd=1 # sd
               ,sc=10000 ## scale the precision
               ) {
  res <- (pnorm(x+1/sc, mean=mean, sd=sd)-pnorm(x, mean=mean, sd=sd))*sc
  res
}
> dn(0,4,10,10000)
0.03682709
> dn(2.02,2,.24)
1.656498

[编辑:1]我应该提到这种近似可能会在远处变得非常可怕。根据您的申请,它可能会也可能不重要。

[edit:2] @foolishbrat将代码转换为函数。结果应始终是积极的。也许你忘了你在perl模块中提到函数返回概率1-F,R返回F?

[edit:3]修复了复制并粘贴错误。

答案 2 :(得分:3)

如果你真的想要密度功能,为什么不直接使用它?

$pi = 3.141593;
$x = 2.02;
$mean = 2;
$sd = .24;
print 1/($sd * sqrt(2*$pi)) * exp(-($x-$mean)**2 / (2 * $sd**2));

它给出1.65649768474891与R中的dnorm大致相同。

答案 3 :(得分:2)

我不认为Jouni是对的。这似乎给出了PDF的合理版本(如果你只想要一个特定的x-y点,则提取循环的中间位置):

!/usr/bin/perl

use strict;
use Getopt::Std;
use POSIX qw(ceil floor);

# Usage
# Outputs normal density function given a mean and sd
# -s standard deviation
# -m mean
# -n normalization factor (multiply result by this amount), optional

my %para = ();
getopts('s:m:n:', \%para);
if (!exists ($para{'s'}) || !exists ($para{'m'})) {
   die ("mean and standard deviation required");
}

my $norm = 1.0;
if (exists ($para{'n'})) {
   $norm = $para{'n'};
}

my $sd = $para{'s'};
my $mean = $para{'m'};

my $start = floor($mean - ($sd * 5));
my $end = ceil($mean + ($sd * 5));

my $pi = 3.141593;

my $var = $sd**2;

for (my $x = $start; $x < $end; $x+=0.1) {
    my $e = exp( -1 * (($x-$mean)**2) / (2*$var));
    my $d = sqrt($var) * sqrt(2*$pi);
    my $y = 1.0/$d*$e * $norm;
    printf ("%5.5f %5.5f\n", $x, $y);
}

答案 4 :(得分:1)

正如其他人所指出的,你可能想要累积分布函数。这可以通过error function(通过平均值移动并按正态分布的标准差缩放)获得,该标准数学库中存在并且可以通过Math::Libm在Perl中访问。

答案 5 :(得分:1)

使用Perl的Statistics :: Distributions,您可以通过以下方式实现此目的:

#!/usr/bin/perl

use strict; use warnings;
use Statistics::Distributions qw(uprob);

my $x       = 0;
my $mean    = 4;
my $stdev   = 10;

print "Height of probablility distribution at point $x = "
    . (1-uprob(($x-$mean)/$stdev))."\n";

“0点可能性分布的高度= 0.34458”

的结果

答案 6 :(得分:0)

以下是使用CPAN中Math::SymbolicX::Statistics::Distributions模块在​​Perl中使用R执行相同操作的方法:

use strict; use warnings;

use Math::SymbolicX::Statistics::Distributions qw/normal_distribution/;

my $norm = normal_distribution(qw/mean sd/);
print $norm->value(mean => 4, sd => 10, x => 0), "\n";

# curry it with the parameter values
$norm->implement(mean => 4, sd => 10);
print $norm->value(x => 0),"\n"; # prints the same as above

该模块的normal_distribution()函数是函数的生成器。 $ norm将是您可以修改的Math::Symbolic(:: Operator)对象。例如,使用 implements ,在上例中,用常量替换两个参数变量。

但是,请注意,正如Dirk指出的那样,您可能需要正态分布的累积函数。或者更一般地说是一定范围内的积分。

不幸的是,Math :: Symbolic不能象征性地进行集成。因此,您必须使用Math::Integral::Romberg之类的数值集成。 (或者,搜索CPAN以实现错误功能。)这可能很慢,但仍然很容易做到。将其添加到上面的代码段:

use Math::Integral::Romberg 'integral';

my ($int_sub) = $norm->to_sub(); # compile to a faster Perl sub
print $int_sub->(0),"\n";  # same number as above

print "p=" . integral($int_sub, -100., 0) . "\n";
# -100 is an arbitrary, small number

这应该从Dirk的答案中给你~0.344578258389676。