1
$\begingroup$

I got the following error:

attempting to use to_dict to index a multiple sequence FASTA file with duplicate keys.

Are there methods for working around duplicate keys in biopython? I was thinking to simply remove the duplicate entries, but I would need to delete the entire entry associated with the keys.

$\endgroup$
3
  • $\begingroup$ Hi @Mike are you looking to rename the duplicate keys? $\endgroup$ – M__ Aug 30 '20 at 12:41
  • $\begingroup$ yes, I was thinking of appending the keys with digits incrementally or something? The keys are uniprot IDs, but the renamed duplicates wouldn't do anything harmful to my output. Might just be best to remove them using a set method or something. Still quite new to this. $\endgroup$ – Mike Aug 30 '20 at 12:52
  • $\begingroup$ Removing keys via a dictionary is easy, it should be automatic (they will overwrite). Pandas will enable duplicate keys are preserved by shifting the index $\endgroup$ – M__ Aug 30 '20 at 17:19
2
$\begingroup$

Yes, Biopython deliberately does not allow duplicate keys with .to_dict(), e.g.

Input file:

$ cat test.fa 
>1
ATG
>2
AAA
>1
CG

Code:

from Bio import SeqIO

print(SeqIO.to_dict(SeqIO.parse("test.fa", "fasta")))

Traceback:

  File "script.py", line 3, in <module>
    print(SeqIO.to_dict(SeqIO.parse("test.fa", "fasta")))
  File "/path/lib/python3.7/site-packages/Bio/SeqIO/__init__.py", line 789, in to_dict
    raise ValueError("Duplicate key '%s'" % key)
ValueError: Duplicate key '1'

However, you can easily write your own function, e.g.:

from Bio import SeqIO

def to_dict_remove_dups(sequences):
    return {record.id: record for record in sequences}

print(to_dict_remove_dups(SeqIO.parse("test.fa", "fasta")))

Output:

{'1': SeqRecord(seq=Seq('CG', SingleLetterAlphabet()), id='1', name='1', description='1', dbxrefs=[]), '2': SeqRecord(seq=Seq('AAA', SingleLetterAlphabet()), id='2', name='2', description='2', dbxrefs=[])}

Alternatively, you Biopython's .to_dict() accepts a key_function argument, e.g. if you wish to make all the headers unique

from Bio import SeqIO
from itertools import count

c = count()

print(SeqIO.to_dict(SeqIO.parse("test.fa", "fasta"),
                    key_function = lambda x: f"{x.id}_seqNum{next(c)}"))

Output:

{'1_seqNum0': SeqRecord(seq=Seq('ATG', SingleLetterAlphabet()), id='1', name='1', description='1', dbxrefs=[]), '2_seqNum1': SeqRecord(seq=Seq('AAA', SingleLetterAlphabet()), id='2', name='2', description='2', dbxrefs=[]), '1_seqNum2': SeqRecord(seq=Seq('CG', SingleLetterAlphabet()), id='1', name='1', description='1', dbxrefs=[])}
$\endgroup$
4
  • $\begingroup$ thank you; return {record.id: record for record in sequences} so the expression garners us only unique IDs it seems, is this the case? $\endgroup$ – Mike Aug 31 '20 at 8:50
  • $\begingroup$ Well, obviously it does, but I guess my question is, what is determining the order (in the first solution)? $\endgroup$ – Mike Aug 31 '20 at 9:27
  • $\begingroup$ @Mike The last key,value pair is nearly* always retained *stackoverflow.com/questions/39678672/… $\endgroup$ – Chris_Rands Sep 2 '20 at 17:05
  • $\begingroup$ Hi Chris, got it thank you! $\endgroup$ – Mike Sep 3 '20 at 7:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.