教程

SplitAligner:从头到尾走一遍

把一棵物种树和一组基因树,变成一张枝坐标矩阵——每根枝要么携带数值,要么带有明确的缺失状态:结构性、融合相关、拓扑导致,或残余 NA。本教程使用随附的示例,你可以在自己的机器上复现每一份输出。

SplitAligner 是一个小巧、几乎无依赖的 Perl 程序。无需编译——克隆仓库、运行 SplitAligner.pl 即可。下面的命令对应 examples/run.sh 中的实际步骤。
思想

一根枝,就是它所作的那个划分

SplitAligner 识别一根枝,靠的不是它画在哪里、也不是节点顺序,而是它在类群上诱导出的二分划分(split)。对于只采样了部分类群 Tg 的基因 g,把物种树的每根枝 b 投影到实际存在的类群上:

σg(b) = ( Ab ∩ Tg | Bb ∩ Tg )

在与物种树限制拓扑一致的基准层中,两根未被删除的原始枝投影划分相同,当且仅当它们落到同一条约化枝上。这并不是说两根原始枝变成了同一根;而是它们在该基因的类群集合下无法再独立区分,形成融合。若投影后有一侧为空,则是结构性缺失。对于经验 free 拓扑基因树,SplitAligner 还会另行判断每个可独立观测的投影划分是否被找回。

显示根不是坐标。SplitAligner 的生物学坐标是规范化无根 split,而不是绘制出来的根位置、内部节点编号、遍历顺序或子节点顺序。若两个 Newick 表示编码的是同一个加权无根 split 对象,那么仅改变显示根或序列化方式,并不会改变底层的生物学 split 身份。

便于阅读的 B 别名是序列化局部的,在独立序列化的物种树之间可能不同。比较独立表示时,权威身份是规范化 split key,而不是 B 编号本身。

在需要方向或祖先关系的分析中,生根仍然可以承载生物学含义;它只是不定义 SplitAligner 的枝坐标身份。

表示 A — 在内部边上生根 AB CD 表示 B — 在枝 A 上生根 AB CD 规范化 split key 相同 A,B | C,D B 别名可能不同

整个流程有两个模式:matrix 构建坐标系并把所有基因投影上去;finalize 再根据成对证据区分缺失状态。

1

安装

你需要 Perl 5(macOS 和大多数 Linux 自带)。SplitAligner 只用核心模块——无需安装任何 CPAN 包。

# 克隆仓库
git clone https://github.com/wujiaqi06/SplitAligner
cd SplitAligner

# 确认可运行(会打印用法说明)
perl SplitAligner.pl

安装到此为止。主控脚本是 SplitAligner.pl;各步骤的辅助脚本在 scripts/ 中,会被自动调用。

2

准备输入

物种树 —— 一棵 Newick 树。允许带枝长和支持度,在基于划分的映射中会被直接忽略。

((A:0.1,B:0.2):0.2,(C:0.1,D:0.1):0.1):0.1;

基因树 —— Newick 格式,一行一条记录,每行以基因标识符开头,紧接着是该基因的树。类群名必须与物种树一致。

GeneA((A:0.1,B:0.2):0.2,(C:0.1,D:0.1):0.1):0.1;
GeneB((A:0.2,C:0.1):0.1,(B:0.1,D:0.2):0.1):0.1;

SplitAligner 区分两类基因树输入,通常两者都要提供:

  • free —— 每个基因独立推断的树(拓扑可以与物种树不一致);
  • fix —— 在物种树拓扑约束下推断的树(只有枝长)。

比较这两者,正是之后区分覆盖度导致的缺失与不一致导致的缺失的关键。

3

快速开始:示例数据

仓库在 examples/302mammal/ 下附带了一个小示例(free / fix 基因树的子集),用于快速的端到端冒烟测试。在仓库根目录下运行:

bash examples/run.sh toy

它会依次运行下面三次程序调用。教程余下部分逐一拆解每一步做了什么、产出什么。

4

matrix 模式 —— 构建坐标系

每组基因树运行一次 matrix。它给物种树的枝打标签,把所有基因投影上去,写出一张基因 × 枝矩阵。

# 从仓库根目录开始
cd examples/302mammal

perl ../../SplitAligner.pl --mode matrix \
  --species input/speciesTree302.nwk \
  --gene input/free_tree.examples.nwk \
  --label free

perl ../../SplitAligner.pl --mode matrix \
  --species input/speciesTree302.nwk \
  --gene input/fix_tree.examples.nwk \
  --label fix

主要输出(以 --label 为前缀):

  • species_tree.splits.txt —— 标准的枝坐标系(物种树骨架上的 B1B2……)。这是所有基因据以度量的共同坐标轴。
  • <label>.matrix_no_fuse.txt —— 仅原始枝。
  • <label>.matrix_with_fuse.txt —— 在此基础上,额外加入显式的融合枝列(如 B12|B47),对应因类群修剪而合并的枝。
  • <label>_splits/<label>_split_branch_label/ —— 每个基因的划分表示,及其到骨架的映射。

若枝的投影划分被找回,单元格即为其枝长(数值);否则为 NA——但只是暂时的。为这些 NA 命名,就是下一步。

gene   B1           B2   B3           B4           ...
A1BG   0.1809315089 NA   0.0047384154 0.0057110032 ...
A1CF   0.0376651404 0.0583312140 0.0032591533 ...
free.matrix_with_fuse.txt(节选)
5

finalize 模式 —— 区分缺失状态

把两张矩阵都交给 finalize。它先识别由数值融合坐标解释的原始枝 NA,标为 NA_fuse;再在共享基因上比较 free 与 fix 矩阵,把结构性缺失(NA_struct)与拓扑导致的缺失(NA_topo)分开。若 fix 侧没有可供判断的数值证据,则保留残余 NA。传入 --species_tree 时,还会计算枝级支持度。

perl ../../SplitAligner.pl --mode finalize \
  --free free.matrix_with_fuse.txt \
  --fix  fix.matrix_with_fuse.txt \
  --final_label final \
  --species_tree species_tree.forSplit.nwk

输出:

  • final.free.na_classified.txt / final.fix.na_classified.txt —— 完成状态分类的矩阵;fix 侧缺少数值证据时会保留残余 NA;
  • <input>.na_fuse.txt —— 融合救回的中间表;
  • final.support_b.txtspecies_tree.support_b.nwk —— 枝级支持度(见第 7 步)。

比较只对两个输入都存在的基因有定义;若没有共享基因,SplitAligner 会直接报错停止,而不去猜。

gene   B1           B2         B3           ...
A1BG   0.1809315089 NA_struct  0.0047384154 ...
final.free.na_classified.txt —— B2 处那个笼统的 NA 现在有了名字
6

读懂各状态

每个基因 × 枝单元格最终都恰好取下列一种值。残余 NA 是有意保留的记账状态:没有 fix 侧数值证据时,不能把它升级为 NA_topo

单元格取值含义
数值Mapped(已映射)。该枝的投影划分在此基因中被观测到;数值即其枝长。
NA_fuse类群修剪后,该原始枝不再能被独立观测。一个融合坐标可以带有数值枝长,但该数值不是这根原始枝的独立估计。
NA_struct投影后有一侧为空,该枝对此基因没有投影身份、无法评估(覆盖度效应)。
NA_topofix 侧有原始枝数值证据,但该投影划分没有在推断出的 free 拓扑树中找回——与拓扑导致的不一致相符。
NA残余:当 fix 侧没有可据以判定的数值证据时保留。

这些类别对坐标轴构成一个划分——加起来就是整本台账:

|C| = Mapped + NA_fuse + NA_struct + NA_topo + 残余 NA

一旦 NA原因拆开,下游的速率或选择分析就能明确地处理、过滤和审计各类状态,而不是把所有缺失都压成同一个不透明的值。

7

枝级 Support

当你传入 --species_tree,finalize 会写出 final.support_b.txt:对骨架上的每根枝,给出它在共享基因上、free 树相对 fix 树保留了多少数值证据。

branch_id  branch_type  n_shared_genes  n_fix_non_na  n_free_non_na  support_percent  discordance_percent
B1         terminal     5               5             5              100.0000000000   0.0000000000
B2         terminal     5               4             4              100.0000000000   0.0000000000
B3         terminal     5               4             4              100.0000000000   0.0000000000
final.support_b.txt(表头)

配套的 species_tree.support_b.nwk 是一棵标准 Newick 树,把每根内部枝的 Support 写在自展值(bootstrap)位置上,可在任意树浏览器(如 FigTree)中打开,直接把一致度映射到拓扑上查看。

8

扩展到全量

同样这两个模式,在全量规模上照样运行。随附的 preprint 示例使用了 302 种哺乳类、2,275 棵 free 拓扑与 2,275 棵 fix 拓扑基因树:

bash examples/run.sh preprint

在共享的一致性子问题上,SplitAligner 的 Support(b)PhyParts 高度一致(299 根内部枝上 Pearson r = 0.99997)。在论文报告的同机测试中,SplitAligner 完整流程用时 9 分 52 秒,PhyParts 的快速一致性设置用时 1 小时 50 分 53 秒——在这套数据上约快 11 倍。这是校准与运行时间比较,并不表示两种方法功能等价。

9

动手玩 Catnip10

这里只让类群缺失发生,不引入基因树不一致。完整的 B1–B17 坐标轴始终冻结;每次删除后,由图决定的台账会更新为 observedNA_fuseNA_struct。在这个实验里,NA_topo 始终为零。