我想输出一个文件总行的随机10%行。例如,文件a有1,000,000行,然后我想从文件中输出随机的100,000行(100,000是1,000,000的10%)。
有一个很容易做的事情,假设文件很小:
randomLine=`wc -l a | awk '{printf("%d\n",($1/10))}'`
sort -R a | head -n $randomLine
但是使用sort -R非常慢。它将执行专门的随机计算。我的文件有10,000,000行。排序需要太多时间。无论如何归档一个不那么专注但不那么随机但有效的采样?
修改提示
逐行阅读
echo $RANDOM%100 | bc
大于20比输出线(使用大于10的数字以确保得到不小于10%的线)并且一旦输出10%线然后停止。但我不知道如何使用shell脚本逐行阅读。
修改说明
我想使用shell脚本的原因是我的文件包含\ r \ n字符。文件中的新行字符应为\ n,但Python和Java中的readline()函数将\ r和\ n视为新行字符,这不符合我的需要。
答案 0 :(得分:2)
让我们创建一个从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[]
)的行号,请将其打印出来。$ 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
正如plundra建议in comments:
shuf -n $(( $(wc -l < $FILENAME) / 10 )) $FILENAME
答案 1 :(得分:1)
我认为这是最好的方法:
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,而是在32768之间可能的数字之一1和100000,所以它是一种投影......)
所以:
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
答案 2 :(得分:0)
我有这个脚本,它会给你大约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
答案 3 :(得分:0)
只需以文件作为输入运行此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
numbers.txt包含数字1到1,000,000,每行一个。在多次运行中,文件nums.txt通常包含大约100,200个项目,达到10.02%。
如果awk认为某行有问题,您可以随时更改记录分隔符。那是RS = "\n";
但这应该是Linux机器上的默认值。
答案 4 :(得分:0)
以下是bash中修改主题1。的一种方法:
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
字符未经修改即通过,如编辑后的要求。