Bash 使用awk进行无需更换的采样

Bash 使用awk进行无需更换的采样,bash,shell,awk,Bash,Shell,Awk,我有很多这样的文本文件: >ALGKAHOLAGGATACCATAGATGGCACGCCCT >BLGKAHOLAGGATACCATAGATGGCACGCCCT >HLGKAHOLAGGATACCATAGATGGCACGCCCT >DLGKAHOLAGGATACCATAGATGGCACGCCCT >ELGKAHOLAGGATACCATAGATGGCACGCCCT >FLGKAHOLAGGATACCATAGATGGCACGCCCT >JGGKAHOLAGG

我有很多这样的文本文件:

>ALGKAHOLAGGATACCATAGATGGCACGCCCT
>BLGKAHOLAGGATACCATAGATGGCACGCCCT
>HLGKAHOLAGGATACCATAGATGGCACGCCCT
>DLGKAHOLAGGATACCATAGATGGCACGCCCT
>ELGKAHOLAGGATACCATAGATGGCACGCCCT
>FLGKAHOLAGGATACCATAGATGGCACGCCCT
>JGGKAHOLAGGATACCATAGATGGCACGCCCT
>POGKAHOLAGGATACCATAGATGGCACGCCCT
>FLGKAHOLAGGATACCATAGATGGCACGCCCT
>POGKAHOLAGGATACCATAGATGGCACGCCCT    
>ALGKAHOLAGGATACCATAGATGGCACGCCCT
>BLGKAHOLAGGATACCATAGATGGCACGCCCT
有没有一种不用awk进行更换的采样方法

例如,我有这8行代码,我只想在一个新文件中随机抽取其中的4行,而不需要替换。 输出应如下所示:

>ALGKAHOLAGGATACCATAGATGGCACGCCCT
>BLGKAHOLAGGATACCATAGATGGCACGCCCT
>HLGKAHOLAGGATACCATAGATGGCACGCCCT
>DLGKAHOLAGGATACCATAGATGGCACGCCCT
>ELGKAHOLAGGATACCATAGATGGCACGCCCT
>FLGKAHOLAGGATACCATAGATGGCACGCCCT
>JGGKAHOLAGGATACCATAGATGGCACGCCCT
>POGKAHOLAGGATACCATAGATGGCACGCCCT
>FLGKAHOLAGGATACCATAGATGGCACGCCCT
>POGKAHOLAGGATACCATAGATGGCACGCCCT    
>ALGKAHOLAGGATACCATAGATGGCACGCCCT
>BLGKAHOLAGGATACCATAGATGGCACGCCCT

提前感谢

对你10%的线路进行随机抽样怎么样

awk 'rand()>0.9' yourfile1 yourfile2 anotherfile
我不知道你说的“替换”是什么意思。。。这里没有替换,只是随机选择

基本上,它会精确地查看每个文件的每一行,并在0到1之间生成一个随机数。如果随机数大于0.9,则输出该行。因此,基本上它是为每行滚动一个10面骰子,并且只有当骰子显示为10时才打印它。一行不可能被打印两次——当然,除非它在您的文件中出现两次

为了增加随机性(!),您可以按照@klashxx的建议,在开始处添加一个
srand()

awk 'BEGIN{srand()} rand()>0.9' yourfile(s)

是的,但我不会。我会使用
shuf
sort-R
(两者都不是POSIX)对文件进行随机化,然后使用
head
选择第一行
n


如果您真的想使用
awk
,您需要使用
rand
函数,正如Mark Setchell指出的那样。

也许最好使用固定模式对文件进行采样,比如每10行采样一条记录。您可以使用此
awk
一行程序执行此操作:

awk '0==NR%10' filename
如果您想对总数的某个百分比进行采样,那么您可以编程一种方法来计算
awk
一行应该使用的行数,以便打印的记录数与该数量/百分比相匹配


我希望这有帮助

从文本文件中获取随机样本而不进行替换,意味着一旦随机选择(采样)了一行,就不能再选择它。因此,如果要选择100行中的10行,则十个随机行号必须是唯一的

下面是一个脚本,用于从文本
文件
生成
NUM
随机(不替换)样本:

#!/usr/bin/env bash
# random-samples.sh NUM FILE
# extract NUM random (without replacement) lines from FILE

num=$(( 10#${1:?'Missing sample size'} ))
file="${2:?'Missing file to sample'}"

lines=`wc -l <$file`   # max num of lines in the file

# get_sample MAX
#
# get a random number between 1 .. max
# (see the bash man page on RANDOM

get_sample() {
  local max="$1"
  local rand=$(( ((max * RANDOM) / 32767) + 1 ))
  echo "$rand"
}

# select_line LINE FILE
#
# select line LINE from FILE

select_line() {
  head -n $1 $2 | tail -1
}

declare -A samples     # keep track of samples

for ((i=1; i<=num; i++)) ; do
  sample=
  while [[ -z "$sample" ]]; do
    sample=`get_sample $lines`               # get a new sample
    if [[ -n "${samples[$sample]}" ]]; then  # already used?
      sample=                                # yes, go again
    else
      (( samples[$sample]=1 ))               # new sample, track it
    fi
  done
  line=`select_line $sample $file`           # fetch the sampled line
  printf "%2d: %s\n" $i "$line"
done
exit

你说的重采样是什么意思?对不起,这是一个打字错误,我的意思是“采样而不替换”。我要编辑它。谢谢。你说的“不替换采样”是什么意思?示例输出是什么样子的,为什么?嗯。。。那么“抽样”是什么意思?是否要从文件中删除重复的行?您想删除每个文件中的重复项还是所有文件中的重复项?我不熟悉
shuf
,但是
sort-R
将创建一个与原始文件一样大的文件对象(在磁盘上,或者在内存中,如果通过管道),这对于大文件可能会有问题。@cmh我确信
shuf
也会这样做。但是,虽然OP说他有几个文件,但他并没有说这些文件很大。@kojiro,当然,这只是未来考虑使用大文件的这种方法的任何人的一个脚注。不需要
head-n4 | shuf
,您可以使用
shuf-n4
很好的解决方案,我会添加一个对srand的调用,以便“获取真正不可预测的随机数。”awk'BEGIN{srand()}rand()>0.9'不,如果你按照我说的方式来做,你的开场白是不正确的。基本上,它会精确地查看每个文件的每一行,并在0到1之间生成一个随机数。如果随机数大于0.9,则输出该行。因此,基本上,它是为每一行滚动一个10面骰子,并且只有在骰子出现时才打印它们这是10。一行不可能被打印两次。@Mark Setchell哦,我明白了。谢谢你的澄清。我已经编辑了我的答案,所以没有误解。但是,由于随机是随机的(D'Oh!),所以可能所有的都是随机的(也就是整个文件)得到打印…或者没有一个得到打印…这就是为什么我给出了一个不依赖于随机性的想法,而是取决于你想要输出的记录的数量。