# Reject reads with low quality bases from a Bam file through pysam

I have a code below:

def FilterReads(in_file, out_file):

"""
returns: True if the read is ok
"""
if any([ord(c)-33 < _BASE_QUAL_CUTOFF for c in list(read.qual)]):
return False
else:
return True

_BASE_QUAL_CUTOFF = 30

bam_in = pysam.Samfile(in_file, 'rb')
bam_out = pysam.Samfile(out_file, 'wb', template=bam_in)



This code works fine by

• Rejecting reads having a base with phred quality score below five
• But it first takes a BAM file
• And then creates a filtered BAM file for further analysis but this takes a lot of time.

So is there a way to reject these reads using pileup in pysam so that I may not have to create a file then sort it and again read it? Or can I modify this code to perform the same function

• Why are you sorting the file prior to iterating over it? Your function doesn't require it to be sorted and since you are not using the random indexing pysam doesn't require it either. Jul 31 '17 at 21:11
• if …: return False else: return True is an anti-pattern. Just write return not …. Or, better yet, logically invert the condition; in your case, you could write return all([ord(c) - 33 >= _BASE_QUAL_CUTOFF for c in list(read.qual)]) (this follows from straightforward application of de Morgan’s laws). Aug 24 '17 at 12:20
• This is probably not the cause of the slowdown, but you can avoid two list creations per read by refactoring line 9 as any(ord(c)-33 < _BASE_QUAL_CUTOFF for c in read.qual): Nov 23 '18 at 9:26
• I don't think pileup is going to save you any time here, as it has to load the same data that you are loading with the fetch method. Nov 23 '18 at 9:32

For can do this by accessing the basecall qualities from PileupRead.alignment. For example:

_BASE_QUAL_CUTOFF = 30
with pysam.Samfile(in_file, 'rb') as bam_in:
for column in bam_in.pileup():
if all([ord(c)-33 >= _BASE_QUAL_CUTOFF for c in qual]):
# do some stuff


This involves checking every read at every position. You could memoise this task:

def check_quality(read):
try:
except KeyError:
passed = all([ord(c)-33 >= _BASE_QUAL_CUTOFF for c in qual])

_BASE_QUAL_CUTOFF = 30
passed_quality = dict()
with pysam.Samfile(in_file, 'rb') as bam_in:
for column in bam_in.pileup():
# do some stuff


Or, using functools.lru_cache (thanks @winni2k):

from functools import lru_cache

@lru_cache(maxsize=1000)