2014-03-14 38 views
3

我想计算perl中每行数字的方差。我写这个子程序:如何计算perl中的方差?

################################################################ 
# variance 
# 
# 
# A subroutine to compute the variance of an array 
# division by n-1 i s used 
# 
sub var{ 
    my ($data) = @_; 
    if (@$data ==1) { 
     return 0; 
    } 
    my $mean = mean ($data); 
    my $sqtotal = 0; 
    foreach (@$data) { 
     $sqtotal += ($_ - $mean) ** 2 
    } 
    my $var = $sqtotal/(scalar @$data - 1); 
    return $var; 
} 

如果我有相同数量的

[0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98的58元给了这阵, 0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98, 0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98,0.98]

计算给了我1.25421964097639e-30。

我也尝试使用Statistics :: Descriptive模块(http://metacpan.org/pod/Statistics::Descriptive),它给了我2.11916254524942e-15。

而且我也试过这个网站(http://www.alcula.com/calculators/statistics/variance/),其结果是2.2438191655582E-15。

为什么结果是不一样的......我可以只使用了模块,但它是非常内存密集型不知何故我的文件,该文件主要包括万线58号

。我不确定它为什么耗尽这么多的记忆。

有人能告诉我为什么我的计算给出了与模块不同的数字,以及如何使模块以更少的内存工作?内存密集的东西只是该模块的固有缺陷。几个帖子似乎表明这一点。

谢谢!

+0

所有这些数字本质上都是零模浮点算术。而你自己的尝试似乎是最精确的。它也看起来会做正确的计算,如果它使用较少的内存,我建议你可以使用你自己的子。编辑:哦,对不起,我刚刚意识到我的派对有多晚。 ^^ – DeVadder

回答

5

一个常数序列的方差是零,所以你的计算或多或少都是正确的,都差不多一样。

由于您使用有限精度浮点数执行许多操作,因此您会得到与零稍有不同的结果。让我们利用这个代码:

$z = 0; 
$z += 0.98 for 1..58; 
$mean = $z/58; 
printf "%.20f", $mean; 

有了这个代码,我们采取了数0.98的58个实例的总和,然后除以58的总和这是有道理的,这个代码将打印0.98000000000000000000,对不对?不,我实际得到的是

0.97999999999999887201 

(和您的结果可能会有所不同)。

规范What Every Programmer Should Know About Floating-Point Arithmetic可以向你解释血淋淋的细节。

+0

知道了,再次浮点..谢谢 – olala

1

定点算术

您的数据是否使用0.01(1/100)的精度?你提供了我的建议的例子。

YES =>您可以使用定点运算代替浮点运算来减少舍入误差的累积。使用1 /(100 ** 2)= 1/10_000比例因子。

https://en.wikipedia.org/wiki/Fixed-point_arithmetic


sub var4{ 
    my ($data) = @_; 
    if (@$data ==1) { 
     return 0; 
    } 
    my $totalD2 = 0; 
    foreach (@$data) { 
     $totalD2 += $_*100 
    } 
    my $meanD2 = $totalD2/(scalar @$data); 

    my $sqtotalD4 = 0; 
    foreach (@$data) { 
     $sqtotalD4 += ($_*100 - $meanD2) ** 2; 
    } 
    my $varD4 = $sqtotalD4/(scalar @$data - 1); 
    return $varD4/10_000; # convert from fixed point to floating point 
} 
1

我是在等人只是做出浮点运算(TY暴徒)的职位,因为这是最终的答案。

但是,您链接到的统计::描述性模块是version 2.6,而当前是version 3.0607

如果你看一下2.6的源代码,它使用了一些陌生人的数学计算的均值和方差:

sub add_data { 
    .... 

    ##Calculate new mean, pseudo-variance, min and max; 
    foreach (@{ $aref }) { 
    $oldmean = $self->{mean}; 
    $self->{sum} += $_; 
    $self->{count}++; 

    .... 

    $self->{mean} += ($_ - $oldmean)/$self->{count}; 
    $self->{pseudo_variance} += ($_ - $oldmean) * ($_ - $self->{mean}); 
    } 

现在计算运行这个方法的意思是数学精确和同为Sum(A1..An)/n 。然而,由于浮点运算,你会看到一个区别,如果它只是从总和/计数中得到平均值。此外,我怀疑这种运行方差可能在数学上是相同的(不会打扰做纸证明),但由于浮点算术,您也会看到轻微的差异。

尽管模块的最新版本确实使用了更简单的方法来计算均值和方差,并且还通过实用模块(如List :: Util)提高了效率。所以,如果你连接到版本2.6只是一个oversite,那么我建议你升级到最新版本。

+0

是的,新版本的内存少得多!谢谢! – olala