【发布时间】:2009-06-23 19:55:30
【问题描述】:
我有一个包含内容的文件
abc
def
high
lmn
...
...
文件中有超过 200 万行。
我想从文件中随机采样行并输出 50K 行。关于如何解决这个问题的任何想法?我在思考 Perl 及其 rand 函数的思路(或者一个方便的 shell 命令会很整洁)。
相关(可能重复)问题:
【问题讨论】:
-
您要输出的行数是准确的还是算法可以输出大约 2.5% 的行数?
我有一个包含内容的文件
abc
def
high
lmn
...
...
文件中有超过 200 万行。
我想从文件中随机采样行并输出 50K 行。关于如何解决这个问题的任何想法?我在思考 Perl 及其 rand 函数的思路(或者一个方便的 shell 命令会很整洁)。
相关(可能重复)问题:
【问题讨论】:
假设您基本上想要输出大约 2.5% 的行,这样可以:
print if 0.025 > rand while <$input>;
【讨论】:
外壳方式:
sort -R file | head -n 50000
【讨论】:
来自perlfaq5: "How do I select a random line from a file?"
除了将文件加载到数据库或预先索引文件中的行之外,您还可以做几件事。
这是来自骆驼书的水库采样算法:
srand;
rand($.) < 1 && ($line = $_) while <>;
与读取整个文件相比,这在空间上具有显着优势。您可以在 计算机编程的艺术,第 2 卷,第 3.4.2 节中找到此方法的证明,作者 Donald E . 克努特。
您可以使用为该算法提供函数的 File::Random 模块:
use File::Random qw/random_line/;
my $line = random_line($filename);
另一种方法是使用 Tie::File 模块,它将整个文件视为一个数组。只需访问一个随机数组元素。
【讨论】:
k 项目的简单方法:stackoverflow.com/a/12733515/2016618
Perl 方式:
使用 CPAN。有一个模块 File::RandomLine 可以满足您的需求。
【讨论】:
如果您需要提取准确的行数:
use strict;
use warnings;
# Number of lines to pick and file to pick from
# Error checking omitted!
my ($pick, $file) = @ARGV;
open(my $fh, '<', $file)
or die "Can't read file '$file' [$!]\n";
# count lines in file
my ($lines, $buffer);
while (sysread $fh, $buffer, 4096) {
$lines += ($buffer =~ tr/\n//);
}
# limit number of lines to pick to number of lines in file
$pick = $lines if $pick > $lines;
# build list of N lines to pick, use a hash to prevent picking the
# same line multiple times
my %picked;
for (1 .. $pick) {
my $n = int(rand($lines)) + 1;
redo if $picked{$n}++
}
# loop over file extracting selected lines
seek($fh, 0, 0);
while (<$fh>) {
print if $picked{$.};
}
close $fh;
【讨论】:
rand 返回的值小于参数,所以它不会选择最后一行。愚蠢的基于 1 的变量...我添加了一个 +1 来修复两种极端情况。