A BLOSUM substitution matrix is estimated from conserved, ungapped blocks of related protein sequences. Closely related sequences are clustered to reduce overrepresentation, and aligned amino acid pairs from different clusters are counted. Let be their normalized observed pair frequency, and the frequency expected from independent draws at the background amino acid frequencies. With unordered pairs, and for .
For BLOSUM62, scores are rounded half-bit logarithms of these odds:A positive entry means that the aligned pair occurs more often in related sequences than the independent-background model predicts; a negative entry means less often. Adding these scores accumulates evidence across aligned positions. A score is neither a percentage identity nor a direct substitution probability.[ref]
The statistics of sequence similarity scores by National Center for Biotechnology Information. The choice of substitution scores; The PAM and BLOSUM amino acid substitution matrices
A diagonal substitution matrix score measures enrichment over a background match, rather than simply rewarding an identical letter. tryptophan residues are comparatively rare, so a W–W match has a small chance background frequency . Its observed conservation produces a much larger ratio than the corresponding ratio for the more common leucine. The BLOSUM62 diagonal therefore awards W–W more than L–L. Both the background frequency and the observed pair frequency matter; rarity alone does not determine a diagonal score.[ref]
The number specifies the sequence-identity threshold used when clustering related sequences before deriving a BLOSUM substitution matrix. At 62%, sufficiently similar sequences are grouped and their within-cluster comparisons are excluded. Lowering the threshold merges more sequences, emphasizing comparisons across greater divergence.
Consequently BLOSUM80 is suited to closer relatives, BLOSUM45 to more divergent sequences, and BLOSUM62 is intermediate. The numbers do not specify a required identity of the query and target, nor a number of evolutionary time steps.[ref]
Amino acid substitution matrices from protein blocks by Steven Henikoff and Jorja G. Henikoff. pp. 10916–10917, clustering levels and performance across divergence
Read the ten residue–residue columns from the BLOSUM62 substitution matrix. In their order in the supplied sequence alignment, their contributions areThere are three gap positions, each incurring the stated linear gap penalty of four, including the leading gap. Therefore the alignment score is .
Use the supplied BLOSUM62 entry for every diagonal move in the Smith-Waterman algorithm, while retaining the stipulated linear gap penalty of . If and are the current amino acids, the dynamic programming recurrence isThe zero option permits a new local start. The following original implementation also records the traceback coordinates needed in part (c); its tie ordering is left, up, diagonal, and an equal overall maximum replaces the previous best cell, as in the supplied convention:
def local_alignment(query,reference,alphabet,scores,gap=-1):
lookup={aa:i for i,aa in enumerate(alphabet)}
table=np.asarray(scores,dtype=int)
height,width=len(query)+1,len(reference)+1
H=np.zeros((height,width),dtype=int)
back=np.zeros((height,width),dtype=np.int8)
best=(0,0,0)
for i,a in enumerate(query,1):
for j,b in enumerate(reference,1):
# Order implements the printed LEFT, UP, DIAGONAL tie priority.
candidates=(0,H[i,j-1]+gap,H[i-1,j]+gap,
H[i-1,j-1]+int(table[lookup[a],lookup[b]]))
value=max(candidates);H[i,j]=value
back[i,j]=0 if value==0 else candidates.index(value)
if value>=best[0]:best=(value,i,j)
score,i,j=best;query_end,ref_end=i,j
aq=[];ar=[]
while H[i,j]>0:
step=back[i,j]
if step==1:aq.append('-');ar.append(reference[j-1]);j-=1
elif step==2:aq.append(query[i-1]);ar.append('-');i-=1
elif step==3:aq.append(query[i-1]);ar.append(reference[j-1]);i-=1;j-=1
qa=''.join(reversed(aq));ra=''.join(reversed(ar));length=len(qa)
identities=sum(a==b and a!='-' for a,b in zip(qa,ra))
similarities=sum(a!='-' and b!='-' and table[lookup[a],lookup[b]]>0 for a,b in zip(qa,ra))
gaps=sum(a=='-' or b=='-' for a,b in zip(qa,ra))
return dict(query=qa,reference=ra,score=int(score),query_start=i+1,query_end=query_end,
reference_start=j+1,reference_end=ref_end,query_length=len(query),reference_length=len(reference),
alignment_length=length,identities=int(identities),similarities=int(similarities),gaps=int(gaps),
identity_percent=100*identities/length if length else 0.,
similarity_percent=100*similarities/length if length else 0.,gap_percent=100*gaps/length if length else 0.)
queries = {"baboon": baboon, "squirrel_monkey": squirrel_monkey,
"dingo": dingo, "goldfish": goldfish}
alignments = {
name: local_alignment(seq, reference_epo_receptor_human, amino_acids, bmat)
for name, seq in queries.items()
}
for name, result in alignments.items():
print(name, "score", result["score"])
print(result["query"])
print(result["reference"])The resulting local sequence alignments, with the query above the reference, are:
baboon; score 314
SLLTPSDLDPLILTLSLILVLIVVLLTVLALLSHRRALKQKIWPGIPSPESEFEGLFTTHKG-FQL
SLLTPSDLDPLILTLSLILVVILVLLTVLALLSHRRALKQKIWPGIPSPESEFEGLFTTHKGNFQLsquirrel monkey; score 278
VCFWEEAASAGMGPDNYSFSYQL-DNEPWKR-CRLHQTPTARGVVRFWCSLPRADTSS
VCFWEEAASAGVGPGNYSFSYQLED-EPWK-LCRLHQAPTARGAVRFWCSLPTADTSSdingo; score 301
MNHLW--THLWPG-VGSLCLLLAGAAWASLPKP-L-DPKFESKAALLAARAPEELLCFTERLEDLVCFWEE
MDHL-GAS-LWP-QVGSLCLLLAGAAWAP-P-PNLPDPKFESKAALLAARGPEELLCFTERLEDLVCFWEEgoldfish; score 190
L--LVLSIGLILC--L-LSLTVI-L-SHQKFLLK-KLWPDIPTPEHKFPGLFTVYKGDFKE-WMSH-NNGSM
LDPLILTLSLILVVILVL-LTVLALLSHRR-ALKQKIWPGIPSPESEFEGLFTTHKGNF-QLWL-YQNDGCLThe several short gaps are a consequence of the specified inexpensive linear gap penalty; substituting a different default or an affine gap penalty would solve a different scoring problem.
Use the number of alignment columns, including gap columns, as the denominator. A column contributes to sequence identity when its two nongap letters are equal, to sequence similarity when its two nongap letters have a strictly positive BLOSUM62 score, and to the gap fraction when either letter is a gap. A zero substitution score is not counted as similar.
The implementation in part (a) computes each numerator directly during its final pass through the aligned strings:
for name, a in alignments.items():
print(name, a["alignment_length"], a["identities"],
a["similarities"], a["gaps"])
print(a["identity_percent"], a["similarity_percent"], a["gap_percent"])Identical columns also count as similar for these data, so these percentages are overlapping summaries rather than three categories summing to 100%.