Was macht Phylogenetik?
Übersicht
Die phylogenetische Analyse rekonstruiert die Evolutionsgeschichte biologischer Sequenzen (Gene, Proteine, Genome), indem sie das Verzweigungsmuster der Abstammung ableitet. Diese Skill deckt die Standard-Pipeline ab:
- MAFFT — Multiples Sequenzalignment
- IQ-TREE 2 — Maximum-Likelihood-Bauminferenz mit Modellauswahl
- FastTree — Schnelle approximative Maximum Likelihood (für große Datensätze)
- ETE3 — Python-Bibliothek zur Baummanipulation und -visualisierung
Installation:
# Conda (empfohlen für CLI-Werkzeuge)
conda install -c bioconda mafft iqtree fasttree
uv pip install ete3
# ete3's TreeStyle/NodeStyle-Rendering benötigt das Qt-Backend; Bildausgabe
# benötigt daher PyQt5; Baumparsing und -statistiken funktionieren auch ohne.
uv pip install PyQt5
Wann diese Skill verwenden
Verwende Phylogenetik, wenn:
- Evolutionsbeziehungen: Welcher Organismus / welches Gen ist am nächsten mit meiner Sequenz verwandt?
- Virale Phylodynamik: Verfolge die Ausbreitung von Ausbrüchen und schätze Übertragungsdaten
- Proteinfamilienanalyse: Leite evolutive Beziehungen innerhalb einer Genfamilie ab
- Erkennung horizontalen Gentransfers: Identifiziere Gene mit nicht übereinstimmenden Arten-/Genbäumen
- Rekonstruktion von Ahnen-Sequenzen: Leite ancestrale Proteinsequenzen ab
- Molekulare Uhrenanalyse: Schätze Divergenzdaten mittels zeitlicher Stichproben
- Begleitanalyse zu GWAS: Platziere Varianten im evolutionären Kontext (z.B. SARS-CoV-2-Varianten)
- Mikrobiologie: Speziesphylogenie anhand von 16S rRNA oder Kerngenom-Phylogenie
Standardarbeitsablauf
1. Multiples Sequenzalignment mit MAFFT
import subprocess
import os
def run_mafft(input_fasta: str, output_fasta: str, method: str = "auto",
n_threads: int = 4) -> str:
"""
Aligniere Sequenzen mit MAFFT.
Args:
input_fasta: Pfad zur nicht-alignierten FASTA-Datei
output_fasta: Pfad für die Ausgabe des Alignments
method: 'auto' (automatische Auswahl), 'einsi' (genau), 'linsi' (genau, langsam),
'fftnsi' (mittel), 'fftns' (schnell), 'retree2' (schnell)
n_threads: Anzahl der CPU-Threads
Returns:
Pfad zur alignierten FASTA-Datei
"""
methods = {
"auto": ["mafft", "--auto"],
"einsi": ["mafft", "--genafpair", "--maxiterate", "1000"],
"linsi": ["mafft", "--localpair", "--maxiterate", "1000"],
"fftnsi": ["mafft", "--fftnsi"],
"fftns": ["mafft", "--fftns"],
"retree2": ["mafft", "--retree", "2"],
}
cmd = methods.get(method, methods["auto"])
cmd += ["--thread", str(n_threads), "--inputorder", input_fasta]
with open(output_fasta, 'w') as out:
result = subprocess.run(cmd, stdout=out, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
raise RuntimeError(f"MAFFT fehlgeschlagen:\n{result.stderr}")
# Zähle alignierte Sequenzen
with open(output_fasta) as f:
n_seqs = sum(1 for line in f if line.startswith('>'))
print(f"MAFFT: {n_seqs} Sequenzen aligniert → {output_fasta}")
return output_fasta
# Leitfaden zur MAFFT-Methodenauswahl:
# Wenige Sequenzen (<200), genau: linsi oder einsi
# Viele Sequenzen (<1000), moderat: fftnsi
# Große Datensätze (>1000): fftns oder auto
# Ultra-schnell (>10000): mafft --retree 1
2. Alignment trimmen (optional, aber empfohlen)
def trim_alignment_trimal(aligned_fasta: str, output_fasta: str,
method: str = "automated1") -> str:
"""
Trimme schlecht alignierte Spalten mit TrimAl.
Methoden:
- 'automated1': Automatische Heuristik (empfohlen)
- 'gappyout': Entferne Lücken-Spalten
- 'strict': Strenger Lücken-Schwellenwert
"""
cmd = ["trimal", f"-{method}", "-in", aligned_fasta, "-out", output_fasta, "-fasta"]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"TrimAl-Warnung: {result.stderr}")
# Fallback: Verwende das ungetrimmte Alignment
import shutil
shutil.copy(aligned_fasta, output_fasta)
return output_fasta
3. IQ-TREE 2 — Maximum-Likelihood-Baum
def run_iqtree(aligned_fasta: str, output_prefix: str,
model: str = "TEST", bootstrap: int = 1000,
n_threads: int = 4, extra_args: list = None) -> dict:
"""
Erstelle einen Maximum-Likelihood-Baum mit IQ-TREE 2.
Args:
aligned_fasta: Alignierte FASTA-Datei
output_prefix: Präfix für Ausgabedateien
model: 'TEST' für automatische Modellauswahl, oder spezifisch (z.B. 'GTR+G' für DNA,
'LG+G4' für Proteine, 'JTT+G' für Proteine)
bootstrap: Anzahl der Ultra-Schnell-Bootstrap-Replikate (1000 empfohlen)
n_threads: Anzahl der Threads ('AUTO' zur automatischen Erkennung)
extra_args: Zusätzliche IQ-TREE-Argumente
Returns:
Dict mit Pfaden zu Ausgabedateien
"""
cmd = [
"iqtree2",
"-s", aligned_fasta,
"--prefix", output_prefix,
"-m", model,
"-B", str(bootstrap), # Ultra-Fast Bootstrap
"-T", str(n_threads),
"--redo" # Überschreibe vorhandene Ergebnisse
]
if extra_args:
cmd.extend(extra_args)
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"IQ-TREE fehlgeschlagen:\n{result.stderr}")
# Gib Ergebnis der Modellauswahl aus
log_file = f"{output_prefix}.log"
if os.path.exists(log_file):
with open(log_file) as f:
for line in f:
if "Best-fit model" in line:
print(f"IQ-TREE: {line.strip()}")
output_files = {
"tree": f"{output_prefix}.treefile",
"log": f"{output_prefix}.log",
"iqtree": f"{output_prefix}.iqtree", # Vollständiger Bericht
"model": f"{output_prefix}.model.gz",
}
print(f"IQ-TREE: Baum gespeichert unter {output_files['tree']}")
return output_files
# Leitfaden zur IQ-TREE-Modellauswahl:
# DNA: TEST → GTR+G, HKY+G, TrN+G
# Protein: TEST → LG+G4, WAG+G, JTT+G, Q.pfam+G
# Codon: TEST → MG+F3X4
# Für zeitliche (molekulare Uhren) Analyse, füge hinzu:
# extra_args = ["--date", "dates.txt", "--clock-test", "--date-CI", "95"]
4. FastTree — Schnelle approximative ML
Für große Datensätze (>1000 Sequenzen), bei denen IQ-TREE zu langsam ist:
def run_fasttree(aligned_fasta: str, output_tree: str,
sequence_type: str = "nt", model: str = "gtr",
n_threads: int = 4) -> str:
"""
Erstelle einen schnellen approximativen ML-Baum mit FastTree.
Args:
sequence_type: 'nt' für Nukleotide oder 'aa' für Aminosäuren
model: Für nt: 'gtr' (empfohlen) oder 'jc'; für aa: 'lg', 'wag', 'jtt'
"""
if sequence_type == "nt":
cmd = ["FastTree", "-nt", "-gtr"]
else:
cmd = ["FastTree", f"-{model}"]
cmd += [aligned_fasta]
with open(output_tree, 'w') as out:
result = subprocess.run(cmd, stdout=out, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
raise RuntimeError(f"FastTree fehlgeschlagen:\n{result.stderr}")
print(f"FastTree: Baum gespeichert unter {output_tree}")
return output_tree
5. Baumanalyse und -visualisierung mit ETE3
from ete3 import Tree, TreeStyle, NodeStyle, TextFace, PhyloTree
import matplotlib.pyplot as plt
def load_tree(tree_file: str) -> Tree:
"""Lade eine Newick-Baumdatei."""
t = Tree(tree_file)
print(f"Baum: {len(t)} Blätter, {len(list(t.traverse()))} Knoten")
return t
def basic_tree_stats(t: Tree) -> dict:
"""Berechne grundlegende Baumstatistiken."""
leaves = t.get_leaves()
distances = [t.get_distance(l1, l2) for l1 in leaves[:min(50, len(leaves))]
for l2 in leaves[:min(50, len(leaves))] if l1 != l2]
stats = {
"n_leaves": len(leaves),
"n_internal_nodes": len(t) - len(leaves),
"total_branch_length": sum(n.dist for n in t.traverse()),
"max_leaf_distance": max(distances) if distances else 0,
"mean_leaf_distance": sum(distances)/len(distances) if distances else 0,
}
return stats
def find_mrca(t: Tree, leaf_names: list) -> Tree:
"""Finde den letzten gemeinsamen Vorfahren einer Menge von Blättern."""
return t.get_common_ancestor(*leaf_names)
def visualize_tree(t: Tree, output_file: str = "tree.png",
show_branch_support: bool = True,
color_groups: dict = None,
width: int = 800) -> None:
"""
Rendere den phylogenetischen Baum als Bild.
Args:
t: ETE3 Tree-Objekt
color_groups: Dict, das Blattname → Farbe abbildet (zum Einfärben von Taxa)
show_branch_support: Zeige Bootstrap-Werte
"""
ts = TreeStyle()
ts.show_leaf_name = True
ts.show_branch_support = show_branch_support
ts.mode = "r" # 'r' = rechteckig, 'c' = kreisförmig
if color_groups:
for node in t.traverse():
if node.is_leaf() and node.name in color_groups:
nstyle = NodeStyle()
nstyle["fgcolor"] = color_groups[node.name]
nstyle["size"] = 8
node.set_style(nstyle)
t.render(output_file, tree_style=ts, w=width, units="px")
print(f"Baum gespeichert unter: {output_file}")
def midpoint_root(t: Tree) -> Tree:
"""Wurzel den Baum am Mittelpunkt (verwenden, wenn keine Außengruppe bekannt ist)."""
t.set_outgroup(t.get_midpoint_outgroup())
return t
def prune_tree(t: Tree, keep_leaves: list) -> Tree:
"""Beschneide den Baum, sodass nur die angegebenen Blätter erhalten bleiben."""
t.prune(keep_leaves, preserve_branch_length=True)
return t
6. Vollständiges Analysescript
import subprocess, os
from ete3 import Tree
def full_phylogenetic_analysis(
input_fasta: str,
output_dir: str = "phylo_results",
sequence_type: str = "nt",
n_threads: int = 4,
bootstrap: int = 1000,
use_fasttree: bool = False
) -> dict:
"""
Vollständige phylogenetische Pipeline: alignieren → trimmen → Baum → visualisieren.
Args:
input_fasta: Nicht-alignierte FASTA-Datei
sequence_type: 'nt' (Nukleotid) oder 'aa' (Aminosäure/Protein)
use_fasttree: Verwende FastTree anstelle von IQ-TREE (schneller für große Datensätze)
"""
os.makedirs(output_dir, exist_ok=True)
prefix = os.path.join(output_dir, "phylo")
print("=" * 50)
print("Schritt 1: Multiples Sequenzalignment (MAFFT)")
aligned = run_mafft(input_fasta, f"{prefix}_aligned.fasta",
method="auto", n_threads=n_threads)
print("\nSchritt 2: Bauminferenz")
if use_fasttree:
tree_file = run_fasttree(
aligned, f"{prefix}.tree",
sequence_type=sequence_type,
model="gtr" if sequence_type == "nt" else "lg"
)
else:
model = "TEST" if sequence_type == "nt" else "TEST"
iqtree_files = run_iqtree(
aligned, prefix,
model=model,
bootstrap=bootstrap,
n_threads=n_threads
)
tree_file = iqtree_files["tree"]
print("\nSchritt 3: Baumanalyse")
t = Tree(tree_file)
t = midpoint_root(t)
stats = basic_tree_stats(t)
print(f"Baumstatistiken: {stats}")
print("\nSchritt 4: Visualisierung")
visualize_tree(t, f"{prefix}_tree.png", show_branch_support=True)
# Speichere gewurzelten Baum
rooted_tree_file = f"{prefix}_rooted.nwk"
t.write(format=1, outfile=rooted_tree_file)
results = {
"aligned_fasta": aligned,
"tree_file": tree_file,
"rooted_tree": rooted_tree_file,
"visualization": f"{prefix}_tree.png",
"stats": stats
}
print("\n" + "=" * 50)
print("Phylogenetische Analyse abgeschlossen!")
print(f"Ergebnisse in: {output_dir}/")
return results
IQ-TREE-Modellguide
DNA-Modelle
| Modell | Beschreibung | Anwendungsfall |
|---|---|---|
GTR+G4 | General Time Reversible + Gamma | Flexibelstes DNA-Modell |
HKY+G4 | Hasegawa-Kishino-Yano + Gamma | Zwei-Raten-Modell (häufig) |
TrN+G4 | Tamura-Nei | Ungleiche Transitionen |
JC | Jukes-Cantor | Einfachstes; alle Raten gleich |
Protein-Modelle
| Modell | Beschreibung | Anwendungsfall |
|---|---|---|
LG+G4 | Le-Gascuel + Gamma | Bestes durchschnittliches Proteinmodell |
WAG+G4 | Whelan-Goldman | Weit verbreitet |
JTT+G4 | Jones-Taylor-Thornton | Klassisches Modell |
Q.pfam+G4 | Pfam-trainiert | Für Pfam-ähnliche Proteinfamilien |
Q.bird+G4 | Vogelspezifisch | Wirbeltierproteine |
Tipp: Verwende -m TEST, damit IQ-TREE automatisch das beste Modell auswählt.
Best Practices
- Alignment-Qualität zuerst: Schlechtes Alignment → unzuverlässige Bäume; überprüfe das Alignment manuell
- Verwende
linsifür kleine (<200 Seq.),fftnsoderautofür große Alignments - Modellauswahl: Verwende immer
-m TESTfür IQ-TREE, es sei denn, du hast einen spezifischen Grund - Bootstrap: Verwende ≥1000 Ultra-Fast-Bootstraps (
-B 1000) für Astunterstützung - Wurzel den Baum: Ungewurzelte Bäume können irreführend sein; verwende Außengruppe oder Midpoint-Wurzelung
- FastTree für >5000 Sequenzen: IQ-TREE wird langsam; FastTree ist 10–100× schneller
- Lange Alignments trimmen: TrimAl entfernt unzuverlässige Spalten; verbessert die Baumgenauigkeit
- Prüfe auf Rekombination in viralen/bakteriellen Sequenzen, bevor du Bäume erstellst (
RDP4,GARD)
Zusätzliche Ressourcen
- MAFFT: https://mafft.cbrc.jp/alignment/software/
- IQ-TREE 2: http://www.iqtree.org/ | Tutorial: https://www.iqtree.org/workshop/molevol2022
- FastTree: http://www.microbesonline.org/fasttree/
- ETE3: http://etetoolkit.org/
- FigTree (GUI-Visualisierung): https://tree.bio.ed.ac.uk/software/figtree/
- iTOL (Web-Visualisierung): https://itol.embl.de/
- MUSCLE (alternativer Aligner): https://www.drive5.com/muscle/
- TrimAl (Alignment-Trimming): https://vicfero.github.io/trimal/