파일에서 시퀀스를 추출하는 데 사용할 수 있는 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
와 의 조합을 선택하면 문자열이 추출됩니다.head
tail
-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.8GB 파일에서 임의의 단일 문자 200개를 검색할 수 있습니다. (비교하자면, wc -l
파일을 읽는 데 2분 28초가 걸렸습니다.) 이 질문은 처음 등장했을 때부터 명확했지만 이 방법은 멀티바이트 시퀀스도 검색할 수 있습니다. 줄 바꿈 등을 처리하려면 약간의 추가 바이트가 필요할 수 있으며 tr -d '\n'
이러한 작은 부분만 잘라낼 수 있습니다.
예상되는 파일 크기로 인해 몇 가지 산술 제한 사항을 확인했습니다. shuf는 부호 없는 정수를 최대 64비트까지 처리할 수 있고, Bash는 dd처럼 부호 있는 정수를 최대 64비트까지 처리할 수 있습니다.
나는 또한 shuf에 대한 몇 가지 통계를 실행했습니다. 각 실행마다 자체 시드가 적용되었으며 결과 시리즈는 편견이 없는 것처럼 보였습니다.