我有一个有5000万行的文件,我必须从其中随机抽取1000行。
首先,我创建1000个随机数;然后我使用
sed -n "$random{p;q}" file
它真的很慢;一行输出至少需要5-6秒。
所以我想我应该优化打印的特定线速。
我们有很多方法可以打印特定的行:
sed -n "$line{p;q}" file
awk "NR==$line{print}" file
head -$line file | tail -1
打印一行代码只需要5-6秒,全部都是slow...cost。
在shell中有没有其他打印特定行的方法?或者python,perl可以比shell更快?或者我解决这个问题的方式是错误的?
迭代1000个随机数,每次使用shell一次,可能会生成1000次io operations.Maybe,我应该先使用一个数组来保存随机数,然后迭代文件一次。
random_array=()
awk '{if ( NR in $random_array ) print;}' file
好吧,我将以这种方式进行测试,并在以后粘贴结果
发布于 2013-04-17 00:04:11
为了避免读取整个文件,您可以获取文件的大小,然后生成一个介于0和该数字之间的1000个偏移量的列表。这些位置通常位于一行中间,但您可以通读到下一个换行符,然后读取并打印以下行。但是,这引入了对文件第一行的偏见。如果您对平均行长度有一个猜测,您可以从生成的偏移量中减去这个数字(任何负的结果都意味着从偏移量0开始读取和打印)。
这里有一个概念的快速证明。为了说明起见,我假设平均行长约为75个字符。这也会影响公平性(选择长行之后的一行的概率更高)。最后一行的处理也不公平;如果它少于75个字符,就永远不能被选中(!) --您可以尝试通过计算实际读取的行的实际平均行长来解决这个问题,但为了使这个示例相当紧凑,我将其保留为练习。
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl (qw(SEEK_SET SEEK_CUR SEEK_END));
my $n = (defined @ARGV ? shift @ARGV : '--help');
die "Syntax: $0 number file\n" unless @ARGV == 1 and $n =~ m/^[0-9]+$/;
open (F, "<", $ARGV[0]) or die "$0: Could not open $ARGV[0]: $!\n";
seek (F, 0, SEEK_END) or die "$0: Could not SEEK_END $ARGV[0]: $!\n";
my $max = tell(F);
my %seen;
for (my $i=0; $i < $n; ++$i)
{
my $offset = int(rand($max))-75;
my $first = 0;
if ($offset < 0)
{
$offset = 0;
$first = 1;
}
seek (F, $offset, SEEK_SET)
or die "$0: Could not SEEK_SET $ARGV[0]: $!\n";
<F> unless $first;
redo if eof (F); # Cheap trick, just retry if at eof
redo if $seen{tell(F)}++;
print scalar(<F>);
}
我添加了代码以避免重复;这就是%seen
散列。
发布于 2013-04-16 13:44:00
按照文件中行的顺序,不包括内存中的所有行:
awk '
NR==FNR { next }
FNR==1{
srand;
n=NR-1
for(i=1; i<=1000; i++) {
line=0
while(!line || line in A) line=int(rand*n)+1
A[line]
}
}
FNR in A
' infile infile
发布于 2013-04-16 14:14:21
无论您使用哪种工具,查找这些线都会产生固有的成本。本质上,您每次都需要遍历这个大文件,查找并计算换行符。
我可以看到两种解决方案:
lseek
查找并打印它们。您可以每隔100或1000行偏移量存储一次,以预先保存space.这两种方法在shell中都很难做到。对于仅适用于shell的解决方案,请尝试devnull的建议shuf
。但是如果不是1,你会希望使用1000:
shuf -n 1000 file
https://stackoverflow.com/questions/16028610
复制相似问题