【问题标题】:Using perl to find median, mode, Standard deviation?使用perl查找中位数、众数、标准差?
【发布时间】:2011-02-25 15:25:18
【问题描述】:

我有一个数字数组。计算数据集的中位数、众数和标准差的最简单方法是什么?

【问题讨论】:

    标签: perl statistics


    【解决方案1】:

    【讨论】:

    • 为什么该模块中没有Statistics::Basic::MaxStatistics::Basic::Min
    • 因为它们在 List::Util 中,在 Core 中。
    【解决方案2】:
    #!/usr/bin/perl
    #
    # stdev - figure N, min, max, median, mode, mean, & std deviation
    #
    # pull out all the real numbers in the input
    # stream and run standard calculations on them.
    # they may be intermixed with other test, need
    # not be on the same or different lines, and 
    # can be in scientific notion (avagadro=6.02e23).
    # they also admit a leading + or -.
    #
    # Tom Christiansen
    # tchrist@perl.com
    
    use strict;
    use warnings;
    
    use List::Util qw< min max >;
    
    sub by_number {
        if ($a < $b){ -1 } elsif ($a > $b) { 1 } else { 0 }
    }
    
    
    #
    my $number_rx = qr{
    
      # leading sign, positive or negative
        (?: [+-] ? )
    
      # mantissa
        (?= [0123456789.] )
        (?: 
            # "N" or "N." or "N.N"
            (?:
                (?: [0123456789] +     )
                (?:
                    (?: [.] )
                    (?: [0123456789] * )
                ) ?
          |
            # ".N", no leading digits
                (?:
                    (?: [.] )
                    (?: [0123456789] + )
                ) 
            )
        )
    
      # abscissa
        (?:
            (?: [Ee] )
            (?:
                (?: [+-] ? )
                (?: [0123456789] + )
            )
            |
        )
    }x;
    
    my $n = 0;
    my $sum = 0;
    my @values = ();
    
    my %seen = ();
    
    while (<>) {
        while (/($number_rx)/g) {
            $n++;
            my $num = 0 + $1;  # 0+ is so numbers in alternate form count as same
            $sum += $num;
            push @values, $num;
            $seen{$num}++;
        } 
    } 
    
    die "no values" if $n == 0;
    
    my $mean = $sum / $n;
    
    my $sqsum = 0;
    for (@values) {
        $sqsum += ( $_ ** 2 );
    } 
    $sqsum /= $n;
    $sqsum -= ( $mean ** 2 );
    my $stdev = sqrt($sqsum);
    
    my $max_seen_count = max values %seen;
    my @modes = grep { $seen{$_} == $max_seen_count } keys %seen;
    
    my $mode = @modes == 1 
                ? $modes[0] 
                : "(" . join(", ", @modes) . ")";
    $mode .= ' @ ' . $max_seen_count;
    
    my $median;
    my $mid = int @values/2;
    my @sorted_values = sort by_number @values;
    if (@values % 2) {
        $median = $sorted_values[ $mid ];
    } else {
        $median = ($sorted_values[$mid-1] + $sorted_values[$mid])/2;
    } 
    
    my $min = min @values;
    my $max = max @values;
    
    printf "n is %d, min is %g, max is %g\n", $n, $min, $max;
    printf "mode is %s, median is %g, mean is %g, stdev is %g\n", 
        $mode, $median, $mean, $stdev;
    

    【讨论】:

    • 这是否比sub by_number { return $a &lt;=&gt; $b }更好,对于“更好”的一些定义?
    • my @sorted_values = sort {$a &lt;=&gt; $b} @values; 有什么问题?
    • @hepcat72 这是个好问题,真的。我不再记得我为什么这样做了。
    • 如果你刚刚对数据进行了排序,调用 min 和 max 函数有什么价值吗?
    【解决方案3】:

    根据您需要走多远,erickb 的答案可能会奏效。但是对于 Perl 中的数字功能,有 PDL。您将使用 pdl 函数创建一个 piddle(包含您的数据的对象)。从那里您可以使用this page 上的操作来进行您需要的统计。

    编辑:环顾四周,我发现两个函数调用完全符合您的需要。 statsover 提供 piddle 的一维统计信息,而 stats 对整个 piddle 进行相同的统计。

    my $piddle = pdl @data;
    my ($mean,$prms,$median,$min,$max,$adev,$rms) = statsover $piddle;
    

    【讨论】:

    • 我之前实际上没有听说过 PDL,我想因为我所做的大部分工作都是系统管理员工具开发等等。这实际上真的很酷,谢谢你的提示。
    • @BadFileMagic,在看到关于 NumPy/SciPy 的演讲后,我真的很沮丧,认为这最终意味着我不得不离开 Perl 转而使用 Python。然后我找到了PDL。都很好。
    • 以前从未听说过。看起来不可思议!
    猜你喜欢
    • 2012-02-24
    • 2020-01-06
    • 2017-12-14
    • 2019-02-02
    • 2021-04-14
    • 1970-01-01
    • 2018-10-30
    • 2010-12-02
    • 2015-02-06
    相关资源
    最近更新 更多