☰
协同进化分析实战:AKtoolbox从多序列比对到突变位点排查
2026/10/18 18:41:33 网站建设 项目流程

简介:AKtoolbox是一款面向蛋白质多序列比对(MSA)协同进化分析的开源Matlab工具箱,适合生物信息学研究人员与进阶开发者使用。它独立于Matlab生物信息工具箱,目前内置统计耦合分析(SCA)、互信息(MI)、直接耦合分析(DCA)等多种方法,并附带不同生物信息学矩阵存档,可帮助用户从序列比对中挖掘残基协同演化关系。资源包共116个文件,以103个m脚本为主,辅以mex编译文件、txt说明、pdb/dssp结构文件及fasta序列样例,整体压缩后仅264KB,轻量易部署。该资源已吸引13958人浏览学习,社区认可度较高。对需要开展共进化分析或扩展Matlab工具链的研究者而言,这份开源代码提供了可直接运行的函数集合与完整示例数据,便于快速上手和二次开发。

1. 多序列比对里藏着共变信号:AKtoolbox到底能帮你做什么

做过蛋白突变筛选的人都有体会:对着多序列比对看保守性,保守位点确实重要,但它只告诉你不让动;真正困扰你的是——哪两个位点一动就会互相牵连,改了一个另一个必须跟着调整。这类位点用单点突变一个个实验验证,周期长、成本高、还容易漏。协同进化分析解决的就是这个问题:从一批同源序列的比对结果里,用统计方法找出那些「一起变化」的位点对,进而推断它们在功能或结构上可能存在关联。AKtoolbox就是把这个分析流程封装成开源Matlab工具箱的一套方案,输入多序列比对,输出位点耦合矩阵和显著边列表。

这套思路最早在蛋白质领域被验证过多次,后来也延伸到RNA结构预测、突变设计、耐药位点发现等场景。我最初接触它是因为要排突变优先级,实验组没时间做全扫描,只能靠序列谱筛候选位点。用下来最大的感受是:协同进化分析的统计门槛不高,但坑在数据清洗和阈值标定上,一把脏MSA进去,结果能漂亮到让你误判。这篇笔记就按我自己跑通这个方向的顺序来写:先讲清楚它在算什么,再给可复现的最小流程,然后是必调参数和翻车现场,最后是一个接结构信息的进阶用法。适合用Matlab做日常分析、又不想为一次分析专门转Python生态的人。

2. 协同进化分析在算什么:从MSA到耦合矩阵的三层拆解

2.1 直接耦合与间接耦合:为什么共变不等于相互作用

多序列比对里判断两个位点是否协同进化,直觉做法是看它们是否总是一起变异。A位点出现氨基酸X的序列里,B位点通常也出现氨基酸Y,这就构成一个候选的共变对。问题是:这个共变关系可能是真实的——A和B在三维结构上挨着,一个突变会影响另一个的选择压力;也可能是间接的——A和C耦合,C和B耦合,A和B只是统计上被牵着走。后者在数据量大时特别常见,尤其是同源序列来自物种关系很近的分支时,共享的系统发育历史会让大量位点表现出虚假相关。

所以现在的主流方法在处理这个问题时,分成了两个层次。第一层是「相关性」:用互信息、相关性系数这类测度找出所有统计上有信号的位点对,它的优点是快、直观,缺点就是会把间接耦合一起捞进来。第二层是「直接耦合」:用全局模型把序列中所有位点的联合分布建模,反推出在排除其他位点影响之后,某两位点之间是否存在直接依赖。这就是DCA(直接耦合分析)做的事情。实际项目里我的做法是两层都跑:先用相关性测度找候选,再用全局模型过滤,最后用结构信息验证。单独拿一层的结果去指导实验,翻车概率不低。

2.2 互信息、SCA与DCA:三种测度怎么选

把三种最常用的测度放在一张表里对比,选型心里就有底了。

测度核心思想输出形式主要弱点适用场景
MI(互信息)两个位点氨基酸分布的联合独立程度位点对分数矩阵偏爱高变位点,小样本下有系统性高估初步筛选、数据量大的家族
SCA(统计耦合分析)对MSA做特征值分解,找与保守模式相关的共变特征向量与位点权重线性假设强,检出的位点偏保守核心研究与保守性相关的功能偶联
DCA(直接耦合分析)对全局序列分布建模,分离直接与间接耦合直接耦合分数矩阵计算量大,序列多样性不足时不稳定区分真实相互作用、突变预测

选型上有两条经验。如果你手里的序列数超过5000、比对质量又好,优先DCA类方法,它能帮你在三维结构没解出来之前猜哪些残基对在空间上靠近。如果序列只有一两百条,DCA的全局模型参数太多,容易过拟合,这时MI配合背景校正更稳。SCA在Matlab生态里有现成实现,和AKtoolbox这类工具的思路不同,它关注的不是「哪个位点对共变最强」,而是「哪些位点一起构成一个保守的功能模块」,适合做方向性探索,不适合直接输出突变候选。

2.3 AKtoolbox的数据流:输入、中间量与输出

无论工具箱内部用哪种测度,数据流是一致的。输入是多序列比对结果,我强调一点:它接收的是「已经做过比对的序列」,不是原始序列。同一行序列逐个位置对应残基,比对列就是位点。第一步清洗,去掉gap比例过高的列、高度保守的列、重复序列,得到干净比对。第二步统计,计算每列氨基酸频率、两两联合频率,这是互信息和DCA共同依赖的基础量。第三步打分,按你选的测度生成一个L×L的耦合矩阵,L是保留的位点数量。第四步后处理,做背景校正、z-score标准化,再从矩阵里提取top N位点对。

实际跑的时候还有一个前置动作值得花时间:找到已知功能位点做校验。比如某个酶的研究里已经报道过两个残基共同突变才能恢复活性,那就拿这个工具箱跑一遍同样输入,看看这对位点是不是排在前面。这一步能快速验证参数是否合理,也能帮你判断这个工具箱在你的数据上偏保守还是偏激进。我每次换数据源都会先做这个校验,比直接信任热图靠谱得多。

3. 用自己的MSA跑通AKtoolbox:最小工作流与输入边界

3.1 输入可以是任何FASTA吗:多序列比对与raw序列的差别

很多第一次上手的人直接把NCBI下载的FASTA丢进去跑,这是最常见的操作错误。AKtoolbox类的协同进化分析默认输入是已经比对好的多序列比对——所有序列等长、每个位置代表同源位点。原始FASTA里每条序列长度不同,直接读进去会导致位点错位,算出来的耦合分数全是噪声。判断输入合不合格有两个硬标准:所有序列删掉gap后长度一致;比对列数至少占序列长度的70%以上。

我一般会在本地维护一个清洗脚本,把原始序列先做对齐再送进工具箱。比对可以用任何你熟悉的工具完成,Express、MUSCLE这类基础工具都导出FASTA格式,Matlab本身的Bioinformatics Toolbox也提供比对函数,但大序列集会慢。清洗这一步不要省,我的经验是:比对质量直接决定协同进化分析结果质量,比选MI还是DCA影响更大。输入文件里每条序列的描述行也建议规范一点——大于号后面只跟序列名,不要塞物种名、组织来源那些附加信息,后面排查的时候会省很多事。

清洗后的输入文件长这样,这是最基本的格式要求:

>seq001 MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQ >seq002 MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQ >seq003 MKTAYI-KQRQISFVKSHFSRQLEERLGLIEV

注意第三行中间出现了一个gap(-)。多序列比对里允许这种符号,代表该序列在此位点缺失。后续分析里gap会被单独处理,不能直接当第21种氨基酸。

3.2 一条命令跑完分析:调用方式与参数速查

AKtoolbox这类Matlab工具箱的常规调用方式是:先添加路径,再读取数据,然后调用主分析函数。接口命名会因为版本不同有变化,下面这段代码按常见习惯给出,重点看参数逻辑,函数名如果对不上,打开工具箱的README对照一下。

%% 添加工具箱路径 addpath('path/to/AKtoolbox'); %% 读取FASTA格式的多序列比对 msaData = akt_readfasta('your_alignment.fasta'); %% 清理高gap列,保留覆盖度≥70%的位点 msaClean = akt_filtercols(msaData, 'maxGapRatio', 0.3); %% 运行协同进化分析 [scoreMat, info] = akt_coevolve(msaClean, ... 'method', 'DCA', ... % 可选 'MI' / 'SCA' / 'DCA' 'pseudoCount', 0.5, ... % 伪计数参数,小样本调大 'nBootstrap', 100, ... % 自抽样次数 'output', 'zscore'); % 输出标准化后的分数 %% 提取排名前50的位点对 pairs = akt_toppairs(scoreMat, 'topN', 50);

代码逻辑拆开看:第一步addpath把工具箱放进当前会话搜索路径,属于常规动作;第二步读取比对文件,工具箱内部会把FASTA解析成序列矩阵,序列缺失位点用特殊符号标记;第三步是关键清洗,maxGapRatio设为0.3,含义是删除超过30%序列在该位点都是gap的列,具体设多少在下一章展开说;第四步调用核心分析,method决定你用互信息还是直接耦合分析,pseudoCount控制小样本稳定性,nBootstrap控制抽样次数,output设成zscore是为了后续跨位点比较。最后一步从矩阵里抽出显著边,给实验设计做候选。

3.3 输出怎么读:耦合分数矩阵与显著位点对

跑完以后你会拿到两个核心结果。第一个是scoreMat,一个L×L的方阵,L是经过清洗后保留的位点数量。scoreMat(i,j)代表第i个和第j个位点的耦合强度,数值越大说明这两个位点越倾向协同进化。对角线是自己和自己,直接用不上,看的时候忽略。标准化为zscore之后,分数具有跨位点可比性,一般|z|>3的位点对可以进入候选列表。

第二个是pairs,一个N×3的表格或者数组,三列分别是位点A序号、位点B序号、耦合分数。把它按分数降序排列,就是你的突变候选列表。我习惯把这个表单独存一份CSV,丢给做实验的同事去核对已知位点。实际项目里一般top 50的位点对就够了——实验验证的位点对通常也就验证二三十对,排名更靠后的即使有真实信号,也容易被噪声淹没。另外注意:scoreMat是成对的,所以矩阵对称,读表的时候避免重复计数。

4. 决定结果质量的关键参数:gap阈值、伪计数与保守位点过滤

4.1 maxGapRatio:0.3还是0.5,不同数据特征怎么定

gap阈值是清洗阶段第一个要动的参数,它的作用是删掉那些大多数序列都存在大段缺失的比对列。这类列如果不删,会引入大量虚假共变。比如某位点在80%的序列里都是gap,那么剩下20%有残基的序列如果恰好来自同一分支,这位点和该分支特有的其他位点会产生完美共变——而这个共变只是系统发育历史的影子,不是功能耦合。

设多少合适,取决于比对里序列的保守程度。我的一般做法是:先跑一遍0.3,看看保留了多少列、删掉了多少列。如果删掉的比例超过一半,说明你的输入比对质量太差,不是调参数能解决的,回到比对阶段重新审查序列;如果删掉的比例不到10%,可以考虑收紧到0.2,去掉更多潜在噪声。领域里常见的范围是0.2到0.5。对于序列数少(少于500条)的数据,我倾向保持0.3偏松,因为删列太多会让剩余位点数不足,统计效力下降。序列数多的大家族,可以放到0.5,信息冗余足够,删狠一点反而干净。

4.2 pseudo count与bootstrap:小样本数据怎么救

互信息和DCA都有一个隐藏问题:在样本量小的时候,它们会系统性高估耦合强度。想象一个极端情况——只有20条序列,任意两个位点只要有少数几次共变事件,算出来的互信息就很高,但其实只是偶然。伪计数(pseudo count)是缓解这个问题的常规手段:在计算频率时给每种氨基酸人为增加一个小计数,起到平滑作用。

伪计数设多大,和序列数量直接相关。序列超过2000条时,我会把它调到0.1甚至更低,因为真实统计量本身就稳定了,加多了会抹掉真实信号。序列少于300条时,0.5到1是合理范围,配合bootstrap抽样来估计每个耦合分数的稳定性。bootstrap的逻辑是重采样原始序列,跑多轮看分数分布,分布越宽说明该位点对越不稳定。nBootstrap设100次作为起点,如果某个候选位点对在100次抽样里排名波动特别大,我不会把它放进实验列表。这个操作看似拖慢速度,实际帮你挡掉大部分假阳性。

4.3 保守位点过滤:哪些列必须提前删掉

信息论角度很好理解:一个所有序列都是丙氨酸的位点,氨基酸分布没有任何变化,它与任何其他位点的互信息天然为零,但DCA这类全局模型会花大量参数去拟合这种无信息位点,反而干扰其他位点的耦合估计。常规做法是计算每个位点的序列熵,低于阈值就删除。阈值没有绝对标准,我一般这样设:位点熵小于最大理论熵的5%时视为保守位点,直接过滤;如果过滤后位点数不到100,放宽到10%。

这一步在AKtoolbox里可以在清洗阶段一起做。我自己的流程是gap过滤、保守位点过滤、去重三步连续执行,生成一个清洗报告,记录每步删了多少列,方便复现和审查。清洗报告看起来机械,但它能帮你判断是数据问题还是参数问题——看到某一步异常删除,优先回看原始比对比闷头调参数更有效。注意保守位点过滤和gap过滤是两步,不要合并:gap过滤管覆盖度,保守位点过滤管变异度,两者删掉的是不同类型的列。

4.4 用已知功能位点校准阈值,别让热图骗你

热图永远是漂亮的,矩阵对角线永远是最亮的,关键问题是top列表里的位点靠不靠谱。我的做法是:每一批新数据分析前,先建一个已知功能位点列表——文献里报道过、实验验证过的突变敏感位点、耐药位点、或结合界面残基。跑完打分后用这个列表做校准,统计已知位点对出现在top 50的比例,这个比例叫召回率。

如果召回率接近零,先不要怀疑数据,多半是参数出了问题,最常见的可能是gap阈值过松、伪计数太小、或者序列多样性不够。如果召回率在20%到40%之间,属于正常范围,协同进化信号本来就是部分覆盖功能位点,剩下的要靠结构信息和其他实验手段补。我还会专门看一下已知位点对在scoreMat里的原始分数分布,给它画个分布图,如果已知位点对集中在高分区域,说明打分方向是对的;如果均匀散布在整个分数范围,这个参数组合就该推倒重来。校准这一步不花多少时间,但能让你对工具箱输出建立判断力。

5. AKtoolbox避坑指南:五个常见翻车现场与排查办法

5.1 现象:序列只有一百多条,热图却异常漂亮,top耦合分数高得惊人

遇到这种结果先别高兴。序列数少的情况下,互信息和DCA都有小样本系统性高估问题,尤其是DCA,全局模型参数数量远大于数据量,很容易过拟合。我见过有人拿着200条序列跑出来的热图,整个矩阵一片通红,差点以为发现了关键耦合网络。

原因:序列数量不足以支撑两两联合分布的高维统计估计,模型把噪声当信号拟合了。解决:先加伪计数到1附近看分数是否明显下降;再加bootstrap,看top位点对在抽样里是否稳定;最后回到序列采样——如果同源序列只有这么少,要么扩大搜索范围,要么换方法,用MI替代DCA,配合APC背景校正比强行跑DCA可靠。我的判断线是序列数低于300条时,DCA结果只能当参考,不能直接指导突变设计。

5.2 现象:清洗时gap处理方向搞反,结果全面倒挂

有一次我把maxGapRatio理解成「保留gap比例超过阈值的位点」,跑出来所有位点的耦合分数都奇低,已知功能位点对全部沉底。排查到清洗报告才发现保留的列全是那些绝大多数序列都有gap的垃圾列。

原因:参数方向理解错误,导致分析建立在最不可信的比对列上。解决:确认工具箱清洗函数的语义——maxGapRatio指「该列gap比例超过此阈值就删除」,所以值越小删得越狠。任何工具拿到手,先用已知位点对跑通再上正式数据,这个习惯帮我挡掉过很多次这种低级参数错误。另外建议把清洗后的结果导出看一眼,数一下列数,确认没有把整个比对删空或者留下明显全是gap的列。

5.3 现象:bootstrap次数设大之后,内存直接爆掉

bootstrap抽样本身没有问题,问题出在实现方式上。如果按循环写——每轮抽样生成一个L×L矩阵存到cell数组里——L是500时还好,L超过1000、抽样次数1000,要同时保存1000个1000×1000的double矩阵,内存直接到8GB。服务器还好,本地笔记本直接卡死。

原因:在内存里同时保留了所有抽样结果,而不是只留统计量。解决:改成增量更新,每轮抽样只保留sum和sum of squares,最后用这两个量算均值和方差。也就是不在循环里保存全部scoreMat,而是更新累加器。如果你看到工具箱文档支持并行计算,也要注意并行池里每条worker复制一份数据,内存消耗会翻多倍,实际用的时候按worker数预留内存。

5.4 现象:FASTA里混入了同一家族的不同亚型序列,共变信号被稀释

对比对文件做多样性统计时,偶尔会发现序列一致性集中在几个簇里——即序列高度相似,甚至只有几个位点差异。这种现象在病毒序列和基因家族数据里特别常见。如果不去重直接跑分析,高度相似的序列会主导频率统计,把一个分支里偶然的位点搭配放大成全局共变。

原因:选样偏差。序列集合没有覆盖多样性的均匀空间,而是被某几个亚型大量重复填充。解决:按序列一致性做去冗余,常用的做法是对序列两两比较,95%以上一致性的序列只保留一条代表。如果工具箱没有内置去冗余,可以用其他聚类工具先处理,输出清洗后的代表性序列集合再输入。做完去冗余之后,序列数会缩水,这是正常现象,别有心理负担,缩水后的结果才更接近真实的协同进化网络。

5.5 现象:高耦合位点对在三维结构上距离很远,对不上

这是协同进化分析被问到最多的问题。两个位点在序列谱上共变很强,但解析出来的蛋白结构里Cα距离超过30Å,怎么看都不像有直接接触。

原因:共变信号来源不只是空间接触。同一结构域里的所有位点共享类似的系统发育历史,会产生背景共变;另外,变构调节、亚基界面间的远程协调也会产生真实但非接触的共变。所以高耦合不等于空间邻近。解决:用结构距离做第二层过滤,把结构上邻近的位点对单独列表,用于界面预测;把远程但高耦合的位点对保留在另一张表里,作为变构候选。现实经验是:如果所有高耦合位点对在结构上都离得很远,先检查系统发育背景,可以做系统树修剪或加入背景校正;如果在结构上有明显富集,说明信号质量高,可以放心往实验推。

6. 进阶技巧:把共变分数接进突变优先级排序

协同进化分析的落地点,是把耦合分数变成一条可执行的突变优先级列表。我常做的一件事是:先选出每列的最大耦合分数,加和得到每个位点的「共变压力」指标;再结合该位点在结构上接触的残基数、保守性得分,做一个加权排序。不是单纯看耦合总分,而是把「一个位点是否被许多伙伴位点拉着走」当成它参与功能网络程度的代理指标。具体命令可以写成这样:

% 计算每个位点的共变压力:行方向最大耦合分数之和 covPressure = sum(max(scoreMat, [], 2)); % 归一化到0-1 covPressure = (covPressure - min(covPressure)) / (max(covPressure) - min(covPressure)); % 综合打分,单纯让耦合分数领先还不够 priorityScore = 0.6 * covPressure + 0.4 * conservationScore; [~, order] = sort(priorityScore, 'descend'); candidateList = order(1:20);

解释一下:max(scoreMat, [], 2)取的是每行最大耦合值,这个「位点最强的耦合伙伴」比平均值更能代表功能性约束——一个位点即使普遍耦合弱,但只要有一个强耦合伙伴,就值得关注。加权的逻辑是我自己调出来的习惯:协同进化信号等于告诉你哪里牵一发动全身,保守性是在此基础上叠加的第二重确认。如果你想做得更细,还可以在最后用已知功能位点画ROC曲线来校准建议名额,我一般建议直接看top 20位点里已知功能位点的占比,占比超过30%就可以进入实验阶段。

关于这个方向,我也走了一些弯路。早期我盯着一对高分位点做了两个月的定点突变,结果没有任何表型差异,后来才发现是因为序列集里没有剪掉一个相近物种的分支,那对高分位点只是物种分化的副产品。之后我养成一个习惯:每次跑完协同进化,先剪系统树看背景,再去看耦合表。现在这个习惯仍然保留,它替我挡掉了至少三次同类假阳性。AKtoolbox这类工具真正有价值的地方,不在于热图多漂亮,而在于它把耗时半天的手工统计压缩成可复现的几条命令,让分析重点回到做判断上。希望这篇笔记能帮你在自己的数据上少踩几个坑,把时间省下来去验证真正值得做的位点。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询