This is a test version of Biostars. For the public version, visit https://www.biostars.org.
Extracting specific sequences from a big fasta file using ids of the sequences to be excluded

I have a huge fasta file of around 20 GB size. I also have some sequence IDS from the same fasta file in text format. Now, I want to retrieve those sequences which don't have those particular ids in the text file.

How shall I proceed? I use Ubuntu 12. I am a novice and have very little knowledge of bash, shell or perl. Any Linux or Samtools or Bioperl command will be helpful.

Thanks.

rna-seq samtools faidx bioperl perl

4 answers

This would work:

git clone https://github.com/BioInf-Wuerzburg/SeqFilter.git
cd SeqFilter
make  # just fetches some libraries, no root or anything required

bin/SeqFilter big.fasta --ids idx.txt --ids-exclude --out big-filtered.fasta

Simple way is to get a list of IDs that you would like to fetch from fasta. This could be done with 'grep' .

grep "^>" input.fasta | sed 's/>//' | grep -v - -f Ids.txt > retreive_IDs.txt

Then you could use something like pyfaidx or samtools

samtools faidx input.fasta `cat retreive_IDs.txt` 

and also faSomeRecords

./faSomeRecords input.fa retreive_IDs.txt output.fa

Thanks for the commands.

I am a beginner in this field. Can you please tell me what does each component of your command does?

Thanks

Execute each command on your own, then you will understand very easily what each command is doing.

Boy, this really comes up a lot. Using the BBMap package:

filterbyname.sh in=file.fasta out=filtered.fasta names=names.txt include=f

Always important to keep busy ;)

You could execute an awk statement that excludes a set of sequence IDs:

$ awk '!/\<idA\>/ && !/\<idB\>/ && ... && !/\<idN\>/' RS='>' ORS='>' seqs.fa > filtered_seqs.fa

Each exclusion pattern looks like:

!/\<idA\>/

The exclamation point excludes whatever matches the inside of the pattern. Inside the pattern is the sample ID value idA, which is wrapped in word boundary markers \< and \> to enforce an exact match on the string idA. This avoids excluding records with partial ID matches.

The RS value separates input by record via the > character. The ORS value prints output with the > as a separator.

While it might look a bit convoluted, it's a pretty straightforward awk call. It would be easy to write a bash, Perl or other shell script to construct this statement, given a text file of IDs you need to exclude.

Since you're streaming through the file one record at a time (or one small buffer containing a few records), and only reading the 20 GB file once, awk should use very little memory and run very quickly.

Other approaches may require preprocessing a very large file into something else, indexing it, or reading large chunks of the file into memory for parsing, which could take a while with a 20 GB input.

Hi, thanks for the reply. I have a text file with the ids I want to exclude from the bigger file. How can I provide the txt file as an input to the awk command provided above?

You can't. But you can write a quick script to generate the awk command from your text file. For instance, you could modify a script like this to match your filenames:

#!/usr/bin/env python                                                                                                                                                                                               

import sys

ids = []
for line in sys.stdin:
    ids.append('!/\<' + line.strip() + '\>/')
exclusion_string = ' && '.join(ids)
cmd_components = ['awk', '\'', exclusion_string, '\'', 'RS=\'>\'', 'ORS=\'>\'', 'seqs.fa', '>', 'filtered_seqs.fa']
print ' '.join(cmd_components)

Then run the script on your IDs to get the awk command:

build_awk_command.py < list_of_ids.txt

Log in to answer this question.