从文件中随机选择行
问题内容:
我有一堆文件,而且文件头有5行。在文件的其余部分,双行构成一个条目。我需要从这些文件中随机选择条目。如何选择随机文件和随机条目(每行,不包括标题)?
问题答案:
如果文件足够小,则将成对的行读取到内存中,然后从该数据结构中随机选择。如果文件太大,则Eugene
Y提供正确的答案:使用储层采样。
这是该算法的直观解释。
Process the file line by line.
pick = line, with probability 1/N, where N = line number
换句话说,在第1行,我们将以1/1
概率选择第1行。在第2行,我们将选择权 更改
为第2行1/2
。在第3行,我们将按1/3
概率将选择权更改为第3行。等等。
为了直观地证明,想象一下一个包含3行的文件:
1 Pick line 1.
/ \
.5 .5
/ \
2 1 Switch to line 2?
/ \ / \
.67 .33 .33 .67
/ \ / \
2 3 1 Switch to line 3?
每个结果的概率:
Line 1: .5 * .67 = 1/3
Line 2: .5 * .67 = 1/3
Line 3: .5 * .33 * 2 = 1/3
从那里开始,剩下的就是归纳法。例如,假设文件有4行。我们已经说服自己,从第3行开始,到目前为止的每一行(1、2、3)都有相等的机会成为我们 当前的
选择。当我们前进到第4行时,将有1/4
机会被选中-正好是应该的位置,从而将前3行的概率降低为正确的数量(1/3 * 3/4 = 1/4
)。
这是Perl常见问题解答,适用于您的问题。
use strict;
use warnings;
# Ignore 5 lines.
<> for 1 .. 5;
# Use reservoir sampling to select pairs from remaining lines.
my (@picks, $n);
until (eof){
my @lines;
$lines[$_] = <> for 0 .. 1;
$n ++;
@picks = @lines if rand($n) < 1;
}
print @picks;