Day 9: Molecular Phylogenetics: Tree Construction, Evolutionary Models & Bootstrapping
Tested Stacks:
GATK 4.6.1
Samtools 1.21
Nextflow 24.10
Seurat v5.1
Python 3.12
Prerequisites: Basic Linux CLI & Sequencing Formats
📚 Chapter 9 of 15
0% Course Completed
1. Evolutionary Foundations of Molecular Phylogenetics
Molecular phylogenetics reconstructs the historical evolutionary relationships among biological entities (genes, genomes, or species) through comparative mathematical analysis of aligned nucleotide or protein sequences. A phylogenetic tree is a formal graph composed of:
- External Nodes (Leaves/Taxa): Observed contemporary biological sequences (Operational Taxonomic Units, OTUs).
- Internal Nodes: Hypothetical common ancestors inferred through divergence points.
- Branches: Lineages connecting nodes. In phylograms, branch lengths are quantitatively proportional to the amount of inferred evolutionary change (e.g. substitutions per site).
- Roots: The deepest internal node representing the most recent common ancestor of all taxa in the tree (established using an outgroup).
2. Methodological Taxonomy of Tree Reconstruction
| Reconstruction Method | Underlying Mathematical Paradigm | Key Assumptions | Computational Speed | Primary Advantages & Limitations |
|---|---|---|---|---|
| UPGMA (Distance) | Unweighted Pair Group Method with Arithmetic Mean; hierarchical clustering of pairwise distance matrix. | Strict Molecular Clock: assumes identical mutation rates across all lineages (ultrametric tree). | Ultra-fast: $O(N^2)$ | Severely distorted if evolutionary rates vary across branches. Generally obsolete for real biological trees. |
| Neighbor-Joining (NJ) (Distance) | Star-decomposition algorithm based on the Minimum Evolution criterion; relaxes the molecular clock. | Branch lengths reflect independent lineage substitution rates without clock constraints. | Very fast: $O(N^3)$ | Generates reliable trees rapidly for thousands of taxa; susceptible to long-branch attraction if divergence is extreme. |
| Maximum Parsimony (MP) (Character) | Occam's Razor: finds tree topology requiring the minimum total number of evolutionary mutational steps. | Evolutionary changes are rare events. | Slow: NP-hard heuristic search. | Intuitive; performs poorly when evolutionary rates are high (vulnerable to Felsenstein long-branch attraction). |
| Maximum Likelihood (ML) (Character) | Calculates the log-likelihood of observing the sequence alignment under an explicit nucleotide/amino acid substitution model: $L = P(\text{Data} \mid \text{Tree}, \text{Model})$. | Explicit probabilistic evolutionary model (e.g. GTR + $\Gamma$ + I). | Computationally intensive (IQ-TREE, RAxML). | Current Gold Standard: statistically consistent, accounts for rate heterogeneity and back-mutations. |
3. Nucleotide Substitution Models
Raw sequence distances underestimate true evolutionary divergence because multiple mutations frequently occur at the same nucleotide site over millions of years (homoplasy, transitions, transversions, back-mutations). Mathematical substitution models correct for these hidden mutations:
| Model Name | Author / Year | Base Frequencies | Transition / Transversion Rates | Free Parameters |
|---|---|---|---|---|
| JC69 | Jukes & Cantor (1969) | Equal: $\pi_A = \pi_T = \pi_G = \pi_C = 0.25$ | Equal: $\alpha = \beta$ (all substitutions identical) | 0 |
| K80 (K2P) | Kimura (1980) | Equal: all bases $0.25$ | Unequal: Transition rate $\alpha \ne$ Transversion rate $\beta$ | 1 ($\kappa = \alpha/\beta$) |
| HKY85 | Hasegawa et al. (1985) | Unequal: $\pi_A \ne \pi_T \ne \pi_G \ne \pi_C$ | Unequal: transitions $\ne$ transversions | 4 |
| GTR | Tavaré (1986) | Unequal variable frequencies | All 6 reversible substitution pairs independent ($r_{AC}, r_{AG}, r_{AT}, r_{CG}, r_{CT}, r_{GT}$) | 8 |
4. Statistical Tree Assessment: Felsenstein Non-Parametric Bootstrapping
To assess how confident we are in individual internal nodes/clades, Joe Felsenstein introduced non-parametric bootstrapping:
- The original alignment of length $L$ is randomly resampled with replacement to generate a pseudo-replicate alignment of length $L$.
- A tree is reconstructed from this pseudo-replicate.
- Steps 1 and 2 are repeated 1,000 times.
- The Bootstrap Value on an internal node represents the percentage of replicate trees (e.g. $98\%$) in which that exact bipartition of taxa was recovered. Nodes with bootstrap support $\ge 70-80\%$ are considered statistically well-supported.
Production Python Script: Tree Building & Newick Visualization with Bio.Phylo
#!/usr/bin/env python3
"""
Day 9 Practical: Distance Matrix Calculation & Neighbor-Joining Tree Construction
"""
from Bio import AlignIO
from Bio.Phylo.TreeConstruction import DistanceCalculator, DistanceTreeConstructor
from Bio import Phylo
import sys
def build_nj_phylogenetic_tree(msa_file: str):
"""Compute distance matrix and construct Neighbor-Joining phylogenetic tree."""
print(f"Loading alignment from {msa_file}...")
alignment = AlignIO.read(msa_file, "fasta")
# 1. Compute pairwise identity distance matrix
calculator = DistanceCalculator("identity")
distance_matrix = calculator.get_distance(alignment)
print("
Pairwise Evolutionary Distance Matrix:")
print(distance_matrix)
# 2. Construct Neighbor-Joining Tree
constructor = DistanceTreeConstructor(calculator, "nj")
tree = constructor.build_tree(alignment)
tree.rooted = True
# 3. Print ASCII phylogram to terminal
print("
Inferred Neighbor-Joining Phylogenetic Tree:")
Phylo.draw_ascii(tree)
# 4. Save Newick format
Phylo.write(tree, "inferred_tree.nwk", "newick")
print("Saved Newick tree to inferred_tree.nwk (compatible with FigTree / iTOL).")
if __name__ == "__main__":
# Test on insulin homologues from Day 8
build_nj_phylogenetic_tree("insulin_homologues.fasta")
⚠️
Common Pitfalls & Troubleshooting Checklist
- Java Heap Exhaustion (GATK / Picard): If processes terminate with
java.lang.OutOfMemoryError, set your environment variable explicitly:export _JAVA_OPTIONS="-Xmx16g -Djava.io.tmpdir=/tmp". - Index Timestamp Mismatch: If tools complain that a BAM index is missing or out of date, regenerate with
samtools index -@ 4 sample.bam. - Conda Channel Conflicts: Avoid ABI incompatibilities between bioconda and conda-forge by setting strict priority:
conda config --set channel_priority strict. - Chromosome Naming Contamination: Always verify whether reference FASTA headers use
chr1or1; divergent naming causes silent alignment drops.
Was this guide helpful to your research?
Help us maintain 100% accurate, peer-reviewed bioinformatics standards.