Perl:计算百分位数的最有效方法

5
我有一个perl脚本,它遍历几个吉字节的文件并生成报告。
为了计算百分位数,我正在执行以下操作。
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)))];

这显然是将所有值预先保存在数组中,然后计算百分位数,对于内存来说可能较重(假设有数百万个值),是否有更节省内存的方法?

1个回答

3
你可以对文件进行两次处理:第一次只计算行数($.)。从这个数字中,你可以计算出滑动窗口的大小,它将仅保留需要查找百分位数的最高数字(对于小于50的百分位数,您应该反转逻辑)。
#!/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] < $_ and $i < $#window(这是否等效?)。 - amon
@amon:可能会有一个偏差。TITS - 试一下就知道 :-) - choroba
我在编辑中加入了 chomp @window 和简化的循环。改变测试顺序导致警告大幅减少。 - amon
@amon:我修复了你的打字错误。我没有收到任何警告。 - choroba
谢谢 Choroba,确实解决了内存占用过高的问题。不过现在速度比以前慢了。我猜你不能拥有一切。 - ZOXIS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接