如何有效地从 Linux 中的大文件中获取 10% 的随机行?



我想随机输出文件总行的 10% 行。例如,文件 a 有 1,000,000 行,那么我想从文件中随机输出 100,000 行(100,000 是 1,000,000 的 10%)。

假设文件很小,这很容易做到:

randomLine=`wc -l a | awk '{printf("%dn",($1/10))}'`
sort -R a | head -n $randomLine

但是使用 sort -R 非常慢。它将执行专用的随机计算。我的文件有 10,000,000 行。排序需要太多时间。有没有办法存档一个不那么专用且不那么随机但有效的采样?

编辑想法:

  1. 每十行采样一行是可以接受的。但是我不知道如何使用shell脚本来做到这一点。
  2. 逐行阅读,如果

    echo $RANDOM%100 | bc
    

大于20输出线(使用大于10的数字保证得到不少于10%的线),一旦输出10%线则停止。但是我不知道如何使用shell脚本逐行阅读。

编辑说明

我想使用 shell 脚本的原因是我的文件包含 \r 字符。文件中的新行字符应该是,但Python和Java中的readline()函数将\r和视为换行符,这不符合我的需要。

让我们创建一个从 1 到 Y 的 X 数字的随机列表。您可以通过以下方式做到这一点:

shuf -i 1-Y -nX

在您的情况下,

shuf -i 1-1000000 -n10000

然后将其存储在变量(空格分隔)中并传递给awk,以便打印这些行号:

awk 'FNR==NR {a[$1]; next} {if (FNR in a) print}' <(shuf -i 1-1000000 -n10000) file

解释

  • FNR==NR {a[$1]; next}遍历shuf结果并将其存储在a[]数组中。
  • {if (FNR in a) print}如果在数组中找到第二个参数(file)的行号a[],请打印它。

样本 Y=10, X=2

$ cat a
1 hello
2 i am
3 fe
4 do
5 rqui
6 and
7 this
8 is 
9 sample
10 text
$ awk 'FNR==NR {a[$1]; next} {if (FNR in a) print}' <(shuf -i 1-10 -n2) a
2 i am
9 sample
$ awk 'FNR==NR {a[$1]; next} {if (FNR in a) print}' <(shuf -i 1-10 -n2) a
4 do
6 and

起色

正如普伦德拉在评论中建议的那样:

shuf -n $(( $(wc -l < $FILENAME) / 10 )) $FILENAME

我认为这是最好的方法:

file=your file here
lines_in_file=`wc -l < $file`
lines_wanted=$(($lines_in_file/10))
shuf -n $lines_wanted $file

另一个创造性的解决方案:

echo $RANDOM生成一个介于 0 和 32767 之间的随机数

然后,您可以执行以下操作:

echo $(($RANDOM*100000/32767+1))

.. 获得 1 到 100000 之间的随机数(正如 Nwellnhof 在下面的评论中指出的那样,它不是 1 到 100000 之间的任何数字,而是 1 到 100000 之间的 32768 个可能数字之一,所以这是一种投影......

所以:

file=your file here
lines_in_file=`wc -l $file | awk {'print $1'}`
lines_wanted=$(($lines_in_file/10))
for i in `seq 1 $lines_wanted`
do line_chosen=$(($RANDOM*${lines_in_file}/32767+1))
sed "${line_chosen}q;d" $file
done

我有这个脚本,可以给你大致1/x行。

#!/usr/bin/perl -w
use strict;
my $ratio = shift;
while (<>) {
print if ((rand) <= 1 / $ratio);
}

对于足够大的$ratio,假设rand的输出均匀分布。

假设你称之为random_select_ratio.pl,像这样运行它以获得 10% 的行:

random_select_ratio.pl 10 my_file

cat my_file | random_select_ratio.pl 10

只需使用文件作为输入运行此 awk 脚本即可。

BEGIN { srand() }{ if (rand() < 0.10) print $0; }

自从我使用 awk 以来已经有一段时间了,但我相信应该这样做。

事实上,它确实完全按预期工作。大约 10% 的线路被输出。在我使用 GNU awk 的 Windows 机器上,我运行了:

awk "BEGIN { srand() }{ if (rand() < 0.10) print $0; }" <numbers.txt >nums.txt

数字.txt包含数字 1 到 1,000,000,每行一个。在多次运行中,文件编号.txt通常包含大约 100,200 个项目,即 10.02%。

如果 awk 认为是一行的内容有问题,您可以随时更改记录分隔符。这是RS = "n";但这应该是Linux机器上的默认设置。

这是编辑想法 1的一种方法。 在 bash 中:

while readarray -n10 a; do
[ ${#a[@]} = 0 ] && break
printf "%s" "${a[${RANDOM: -1:1}]}"
done < largefile.txt

有点慢,尽管它比我机器上的sort -R方法快约 2.5 倍。

我们使用readarray一次从输入流中读取 10 行到数组中。 然后我们使用$RANDOM的最后一位数字作为该数组的索引并打印结果行。

使用readarray/printf组合应确保r字符在不修改的情况下传递,如编辑要求中所述。

相关内容

  • 没有找到相关文章

最新更新