如何从fasta文件中随机提取200个字符的子字符串

如何从fasta文件中随机提取200个字符的子字符串

有没有可以用来从文件中提取序列的 Linux 命令?例如,一个文件包含一百万行,我们只想从该文件中随机采样 200 个字符的序列(不考虑标头)。

对于随机,我的意思是每 200 个序列都有相同的被选择概率,并且选择的子串都不重复。

我正在考虑从这样的 fasta 文件中随机提取 200 个字符的序列(不考虑标头):

>NC_001416.1 Enterobacteria phage lambda, complete genome
GGGCGGCGACCTCGCGGGTTTTCGCTATTTATGAAAATTTTCCGGTTTAAGGCGTTTCCGTTCTTCTTCG
TCATAACTTAATGTTTTTATTTAAAATACCCTCTGAAAAGAAAGGAAACGACAGGTGCTGAAAGCGAGGC
TTTTTGGCCTCTGTCGTTTCCTTTCTCTGTTTTTGTCCGTGGAATGAACAATGGAAGTCAACAAAAAGCA
GCTGGCTGACATTTTCGGTGCGAGTATCCGTACCATTCAGAACTGGCAGGAACAGGGAATGCCCGTTCTG
CGAGGCGGTGGCAAGGGTAATGAGGTGCTTTATGACTCTGCCGCCGTCATAAAATGGTATGCCGAAAGGG
ATGCTGAAATTGAGAACGAAAAGCTGCGCCGGGAGGTTGAAGAACTGCGGCAGGCCAGCGAGGCAGATCT
CCAGCCAGGAACTATTGAGTACGAACGCCATCGACTTACGCGTGCGCAGGCCGACGCACAGGAACTGAAG
AATGCCAGAGACTCCGCTGAAGTGGTGGAAACCGCATTCTGTACTTTCGTGCTGTCGCGGATCGCAGGTG
AAATTGCCAGTATTCTCGACGGGCTCCCCCTGTCGGTGCAGCGGCGTTTTCCGGAACTGGAAAACCGACA
TGTTGATTTCCTGAAACGGGATATCATCAAAGCCATGAACAAAGCAGCCGCGCTGGATGAACTGATACCG
GGGTTGCTGAGTGAATATATCGAACAGTCAGGTTAACAGGCTGCGGCATTTTGTCCGCGCCGGGCTTCGC
TCACTGTTCAGGCCGGAGCCACAGACCGCCGTTGAATGGGCGGATGCTAATTACTATCTCCCGAAAGAAT
CCGCATACCAGGAAGGGCGCTGGGAAACACTGCCCTTTCAGCGGGCCATCATGAATGCGATGGGCAGCGA
CTACATCCGTGAGGTGAATGTGGTGAAGTCTGCCCGTGTCGGTTATTCCAAAATGCTGCTGGGTGTTTAT
GCCTACTTTATAGAGCATAAGCAGCGCAACACCCTTATCTGGTTGCCGACGGATGGTGATGCCGAGAACT
TTATGAAAACCCACGTTGAGCCGACTATTCGTGATATTCCGTCGCTGCTGGCGCTGGCCCCGTGGTATGG
CAAAAAGCACCGGGATAACACGCTCACCATGAAGCGTTTCACTAATGGGCGTGGCTTCTGGTGCCTGGGC
GGTAAAGCGGCAAAAAACTACCGTGAAAAGTCGGTGGATGTGGCGGGTTATGATGAACTTGCTGCTTTTG
ATGATGATATTGAACAGGAAGGCTCTCCGACGTTCCTGGGTGACAAGCGTATTGAAGGCTCGGTCTGGCC
AAAGTCCATCCGTGGCTCCACGCCAAAAGTGAGAGGCACCTGTCAGATTGAGCGTGCAGCCAGTGAATCC
CCGCATTTTATGCGTTTTCATGTTGCCTGCCCGCATTGCGGGGAGGAGCAGTATCTTAAATTTGGCGACA
AAGAGACGCCGTTTGGCCTCAAATGGACGCCGGATGACCCCTCCAGCGTGTTTTATCTCTGCGAGCATAA
TGCCTGCGTCATCCGCCAGCAGGAGCTGGACTTTACTGATGCCCGTTATATCTGCGAAAAGACCGGGATC

所以我可以获得这样的序列子集作为示例:

GCATACCAGGAAGGGCGCTGGGAAACACTGCCCTTTCAGCGGGCCATCATGAATGCGATGGGCAGCGACTACATCCGTGAGGTGAATGTGGTGAAGTCTGCCCGTGTCGGTTATTCCAAAATGCTGCTGGGTGTTTATGCCTACTTTATAGAGCATAAGCAGCGCAACACCCTTATCTGGTTGCCGACGGATGGTGATGC

答案1

为了能够对随机 200 个字符长度的序列进行多次快速选择,可以方便地保存不带换行符的 fasta 文件副本(也不包括标头)。

< file.fasta tail -n+2 | tr -d '\n' > newfile

因此,您将随机选择起始字符,而无需命中任何换行符和/或进行任何计算来处理它。另外,我假设wc -c < file(或wc -m) 并stat -c "%s" file给出相同的结果(对于通常的内容、区域设置等,请先检查它),所以我们使用stat返回速度更快的方法。

对于包含字符的文件n,可用的选择是n-200,我们从可能的起始位置排除最后 200 个字符,因为它们无法形成 200 个字符的长字符串。

shuf选择范围的随机数,并且和的1,n-200组合将提取字符串。headtail-c

n=$(stat -c "%s" newfile)
r=$(shuf -i1-"$((n-200+1))" -n1)
< newfile tail -c+"$r" | head -c200

你可以多次调用它以获得许多不同的结果独立的随机选择,这意味着甚至相同或重叠的序列。

如果您希望您的选择遵循其他标准,例如不在文件中的同一位置和/或不重叠,则必须从同一shuf命令解析随机数(具有更高的-n值)。或者,为了不重叠,丢弃任何与现有值接近 200 的新值。

如果你想随机选择x独立的但是您可以开始生成随机行的独特序列,删除重复项并将其中的 x 保留为head,例如获取其中的 10 个:

while true; do sh test.sh; printf "\n"; done | awk '!seen[$0]++' | head

答案2

shuf随机重新排列文件行。如果要随机采样字符,请使用折叠将每个字符排成一行。

fold -w 1 file | shuf -n 200 | tr -d '\n'

tr将它们重新排成一行。

如果您想跳过标题:

tail -n+2 | fold -w 1 | shuf -n 200 | tr -d '\n'

答案3

不是很高效,但是这会提取序列中 200 字节长度的随机子字符串:

n=200                                             # number of bytes to extract
num_bytes=$(tail -n+2 file | tr -d '\n' | wc -c)  # remove header and newlines, save nr. of bytes
offset=$(shuf -n1 -i0-$(( num_bytes - n )))       # random offset, between 0 and num_bytes - n
tail -n+2 file | tr -d '\n' |                     # remove header and newlines
  dd count="$n" bs=1 skip="$offset" 2>/dev/null   # extract substring

我们需要事先知道没有标题和换行符的序列的大小,因此需要对输入文件(或临时文件)进行两次传递。

答案4

我注意到引用的文件大小为 100 万行,1-2GB。复制整个数据以删除换行符,并读取整个数据以使用head和对其进行剪辑tail,似乎是不必要的开销。

另一种方法是通过以下方式确定文件大小:

szFn="$( stat --format=%s "${Fn}" )"

然后在文件中生成一系列随机字节偏移量:

shuf --input-range=0-$(( szFn - 1 )) -n "${Count}" | sort -n

并迭代这些偏移量以在所需的查找偏移处读取文件:

dd status=none bs=1 skip="${Skip}" count="${Lth}" if="${Fn}"

此方法可以在大约 1.5 秒内检索 HDD 上 10.8 GB 文件中的 200 个单个随机字符。 (为了比较,wc -l读取文件需要 2 分 28 秒。)这个问题自从第一次出现以来就已经被澄清了,但是这个方法也可以检索多字节序列。为了处理换行符等,它可能需要一些额外的字节并且只是tr -d '\n'剪辑这些小部分。

由于预期的文件大小,我检查了一些算术限制。 shuf 最多可处理 64 位无符号整型,Bash 最多可处理 64 位有符号整型,就像 dd 一样。

我还在 shuf 上运行了一些统计数据:它在每次运行时都会进行自我播种,并且生成的序列似乎没有偏差。

相关内容