【问题标题】:Perl: Most efficent way to calculate percentilePerl:计算百分位数的最有效方法
【发布时间】:2013-08-15 00:55:45
【问题描述】:

我有一个 perl 脚本,它会检查几个 gig 的文件并生成报告。

为了计算百分位数,我正在执行以下操作

my @values = 0;
while (my $line = <INPUTFILE>){
    .....
    push(@values, $line);

}
# Sort
@values = sort {$a <=> $b} @values; 

# Print 95% percentile
print $values[sprintf("%.0f",(0.95*($#values)))];

这显然将所有值预先保存在一个数组中,然后计算百分位数,这可能会占用大量内存(假设有数百万个值),是否有更节省内存的方法?

【问题讨论】:

    标签: performance perl memory percentile


    【解决方案1】:

    您可以处理文件两次:第一次运行只计算行数 ($.)。根据该数字,您可以计算滑动窗口的大小,它只会保留找到百分位数所需的最高数字(对于百分位数

    #!/usr/bin/perl
    use warnings;
    use strict;
    
    my $percentile = 95;
    
    my $file = shift;
    open my $IN, '<', $file or die $!;
    
    1 while <$IN>;             # Just count the number of lines.
    my $line_count = $.;
    seek $IN, 0, 0;            # Rewind.
    
    # Calculate the size of the sliding window.
    my $remember_count = 1 + (100 - $percentile) * $line_count / 100;
    
    # Initialize the window with the first lines.
    my @window = sort { $a <=> $b }
                 map scalar <$IN>,
                 1 .. $remember_count;
    chomp @window;
    
    while (<$IN>) {
        chomp;
        next if $_ < $window[0];
        shift @window;
        my $i = 0;
        $i++ while $i <= $#window and $window[$i] <= $_;
        splice @window, $i, 0, $_;
    }
    print "$window[0]\n";
    

    【讨论】:

    • 内部的while 可能更容易理解为$i++ while $window[$i] &lt; $_ and $i &lt; $#window(是等价的吗?)。
    • @amon:可能,可能有 1 个错误。山雀 - 试试看 :-)
    • 我冒昧地编辑了chomp @window 和简化的循环。更改测试顺序导致警告数量急剧减少。
    • @amon:我修正了你的错字。我没有收到任何警告。
    • 感谢 Choroba,它确实解决了高内存消耗问题。但是现在比以前慢。我想你不能拥有一切。
    猜你喜欢
    • 2017-04-26
    • 2011-09-13
    • 1970-01-01
    • 2011-12-29
    • 2013-06-20
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    • 2016-07-28
    相关资源
    最近更新 更多