ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OrthoFinder实战指南:泛基因家族聚类与直系同源分析全流程

OrthoFinder实战指南:泛基因家族聚类与直系同源分析全流程 先说结论如果现在让我给做比较基因组的人推荐一个工具OrthoFinder会排在我列表的第一位。我手里攒着二十几个物种的蛋白组序列要回答的问题其实就一个——这些基因里哪些是同一个祖先基因在不同物种里的直系后代这个问题说白了就是泛基因家族聚类分析OrthoFinder就是专门干这个的。这篇文章写给谁一种是刚入坑比较基因组、泛基因组分析的硕士博士手里有若干物种的基因组注释文件但不知道怎么把“基因家族”这个概念落地另一种是已经跑过OrthoMCL或BLAST best hit流程想升级到更可靠的直系同源推断方案的研究者。我会把从输入数据准备、参数选择、结果解读到下游泛基因家族统计的完整链路都拆开讲最后再分享几个实际项目中踩过的坑。这里先提醒一句OrthoFinder做的“聚类”和你平时在SPSS里做的k-means聚类、电商分析里用的DBSCAN完全是两码事它聚的是进化意义上的直系同源组orthogroup不是算距离矩阵再划分簇理解了这一点后面的逻辑就顺了。1. 我为什么从OrthoMCL切到OrthoFinder做泛基因家族聚类1.1 泛基因家族聚类到底在“聚”什么泛基因家族分析本质上是对多个物种或者同一物种多个品系的全部蛋白序列做正交关系推断。每一条蛋白序列来自一个基因基因和基因之间可能有三种关系直系同源ortholog、旁系同源paralog、异源同源xenolog。泛基因家族聚类的目标是把“来源于同一祖先基因”的所有序列归到同一个组里这个组就是orthogroup。举个例子拟南芥里有一个基因AT1G01010水稻里有一个基因LOC_Os01g01010如果它们都来自一个共同的祖先基因在 speciation 之后分别保留在两个物种里那它们就该落到同一个orthogroup里。但麻烦在于很多基因家族在演化中经历过复制——祖先基因复制出一份拷贝一份保留原功能一份获得新功能这就是旁系同源。如果用最朴素的“序列两两比对相似度最高就是同源”思路很容易把旁系同源误判成直系同源或者把丢失事件、快速演化导致的差异误判成“没有同源基因”。OrthoFinder把这个问题拆成了几步我后面细讲。理解它的核心逻辑比直接跑命令重要得多。1.2 纯BLAST best hit为什么不够用我早期做基因家族分析时用过一套很朴素的流程把所有物种的蛋白序列合并做BLASTP取best hit然后根据序列相似性阈值聚类。听起来好像没毛病实际操作就知道多坑了。最大的问题是基因复制带来的“一对多”和“多对多”关系。比如某物种里一个基因家族扩张成了5个拷贝另一个物种里只有1个拷贝那么5个拷贝里的每一个可能都和对方那1个拷贝有较高的相似性。如果只取best hit只能保留相似性最高的一对其余4个拷贝就成了“孤儿基因”。但事实上这5个拷贝都应该算在同一个orthogroup里。OrthoFinder的做法是用DIAMOND做全对全相似性搜索把所有超过阈值的相似性关系都保留下来再交给MCL聚类算法处理MCL天然支持“多对多”的图聚类不会像best hit那样把关系切断。还有一层是系统发育信号的利用。OrthoFinder不是比对完直接聚类就结束它还会为每个orthogroup构建基因树结合物种树推断基因复制和丢失事件最终在“直系同源组”的层面上区分真正的ortholog和paralog。这一步是OrthoMCL和老式流程没有的。OrthoMCL虽然也用MCL但它不构建基因树输出的只是聚类结果而OrthoFinder额外给出了每个组的进化关系这个信息做下游分析时太有用了。2. 输入数据这一关蛋白组序列的准备与质控2.1 每个物种该交什么格式的文件OrthoFinder要求的输入很简单一个目录目录下每个物种一个FASTA文件文件里是蛋白序列。就这么简单确实就这么简单但恰恰是这一步让很多人栽了跟头。官方推荐的文件后缀包括.fa、.fasta、.faa、.pep等目录里最好只放蛋白序列文件别混入其他文件。文件命名建议用物种缩写比如Ath.fa、Osa.fa、Sly.fa。OrthoFinder会把文件名当作物种ID后面所有结果里显示的就是这个名字所以你取的名字要能让自己一眼认出来。每个FASTA文件内部序列的标识符后面的部分要保证唯一。多个物种的文件之间基因ID可以重复但OrthoFinder内部会把物种ID拼到基因ID上所以同一个文件里绝对不能出现重复的基因ID。我做的一次项目里队友从不同数据库下载了两个版本的注释合并时没做去重结果同一个ID对应了两条蛋白序列OrthoFinder跑完以后某些orthogroup里出现了“一个基因有两个拷贝”的假象排查了半天才发现是输入文件的问题。2.2 基因命名、转录本筛选与格式规范命名规范直接影响聚类质量。这里给出我总结的几条硬规则基因ID不能包含空格、竖线、星号、括号等特殊字符建议用物种缩写_基因ID的格式例如Ath_AT1G01010。蛋白序列中不能出现*终止密码子、U硒代半胱氨酸但OrthoFinder处理不稳定、小写的非标准字母。每个基因只保留一条蛋白序列。如果基因组注释包含可变剪接每个基因往往有多条转录本不筛选直接把所有转录本丢进去会让OrthoFinder把一个基因的不同剪接体当成不同基因膨胀基因家族大小。我常用的做法是每个基因只保留最长转录本对应的蛋白序列。可以用seqkit或者 AGAT 工具来做# 如果注释是GFF/GTF可用AGAT提取最长转录本并输出蛋白序列 agat_sp_keep_longest_isoform.pl -g annotation.gff -f genome.fa -o longest.iso.fa # 如果已经是蛋白FASTA但想按基因去冗余可以用脚本按基因ID前缀聚合 seqkit fx2tab protein.fa | \ awk {split($1,a,.); print a[1]\tlength($2)\t$2} | \ sort -k1,1 -k2,2nr | \ awk !seen[$1] | \ awk {print $1\n$3} protein.longest.fa第二种方法假设基因ID里以.分隔转录本编号比如evm.model.Scaffold1.100.1截断到第一段就能归到基因水平。实际项目中命名规则五花八门需要根据你自己的注释格式调整拆分的分隔符。2.3 序列质控的实操命令输入序列的质量再怎么强调都不过分。OrthoFinder对序列长度没有硬性要求但如果序列里混着大量残缺的假基因、提前终止的蛋白、或者被错误预测出来的无功能片段聚类结果会往上掺沙子。我的质控流程是用seqkit stats看每个文件的序列总数、总长度、N50。过滤长度小于30个氨基酸的序列太短的片段基本不可能是完整蛋白。过滤含有终止密码子*的序列除非你明确知道自己在做什么。用seqkit rmdup去冗余避免同一条序列在文件里出现多次。seqkit seq -m 30 -g -v -i protein.longest.fa -o protein.filtered.fa # -m 30 长度至少30 # -g 只保留标准氨基酸字符排除有* # -v 反向匹配去掉含终止密码子的 # -i 忽略大小写等你把这些蛋白文件准备好proteomes/目录下每个物种一个文件总计物种数从几个到几十个都可以跑。我建议在正式全量跑之前先用3到5个代表性物种做一次小规模测试确认输入没问题再去申请集群资源跑全量数据这个习惯帮我省掉了无数次排队失败。3. OrthoFinder运行全流程从命令到输出目录逐层拆解3.1 安装与参数选择的逻辑安装OrthoFinder最省事的方式是conda官方源和bioconda源都有conda create -n orthofinder -c bioconda -c conda-forge orthofinder conda activate orthofinder orthofinder --help如果想用最新版本或者集群上没有conda权限可以去GitHub下载源码编译依赖项包括DIAMOND、MCL、FastME、IQ-TREE、MAFFT等编译过程也不复杂但conda一条命令能搞定的事情没必要折腾。参数选择是我最想聊聊的部分。OrthoFinder默认参数在大多数情况下表现不错但理解每个参数的含义能帮你避免“默认参数跑完全场才发现结果不可用”的尴尬。3.2 完整运行命令与硬件预估我的常用命令是这样的orthofinder -f ./proteomes -t 16 -a 16 -S diamond -M msa -A mafft -T iqtree各参数含义拆开看参数作用我的建议-f指定输入目录目录下是各物种的蛋白FASTA-t相似性搜索线程数等于你的CPU核数DIAMOND阶段最关键-a分析阶段线程数基因树构建、物种树推断等和-t可以分开设置-S序列搜索程序默认diamond千万别改回blast慢到你怀疑人生-M msa生成多序列比对下游想看基因树就必须保留-A mafft比对器mafft在速度和准确性之间权衡最好-T iqtree基因树构建器iqtree比fasttree慢但更准物种数多时慎重硬件预估方面我实测过一批数据12个植物物种每个约3到4万条蛋白序列用16核跑DIAMOND相似性搜索大约40分钟MCL聚类加正交推断约20分钟但后面MSA和基因树构建阶段用了将近6个小时。如果物种数翻倍到24个基因树构建时间可能翻两到三倍因为成对比较的复杂度是物种数的平方级别。所以如果是几十个物种的大规模泛基因组分析建议先用-og参数只跑orthogroup推断跳过基因树和物种树部分确认聚类合理再全量跑。3.3 运行过程会经历哪几个阶段OrthoFinder的运行日志会明确告诉你它正在做什么我整理成一句话版流程用DIAMOND对全部蛋白序列做全对全相似性搜索。根据相似性得分生成基因图用MCL聚类得到初始orthogroup。对每个orthogroup做多序列比对构建基因树。结合所有基因树用STAG算法推断物种树。用STRIDE和DLC算法在基因树上标定基因复制和丢失事件校正orthogroup。很多人以为OrthoFinder就是“比对MCL”两步实际上第3到第5步才是它比OrthoMCL强的地方。为什么MCL聚类出来的“组”可能因为基因复制事件而混淆——比如一个组里既有直系同源也有旁系同源OrthoFinder会在基因树层面把它们分开并在输出中明确标注哪些基因是ortholog、哪些是paralog。这个信息是OrthoMCL给不了的。等命令行结束你会在输入目录下看到一个以日期命名的结果目录比如Results_Feb18所有输出文件都在里面。别急着看Orthogroups.tsv先把目录结构搞清楚。4. 结果目录解读Orthogroups.tsv与泛基因组统计4.1 输出目录里到底有啥一个典型的OrthoFinder结果目录结构如下Results_Feb18/ ├── Orthogroups/ │ ├── Orthogroups.tsv │ ├── Orthogroups.txt │ ├── Orthogroups_UnassignedGenes.tsv │ ├── Orthogroups_UnassignedGenes.txt │ └── Orthogroups_UnassignedGenes.tsv ├── Comparative_Genomics_Statistics/ │ ├── Statistics_Overall.tsv │ ├── Statistics_PerSpecies.tsv │ ├── Orthogroups_SpeciesOverlaps.tsv │ └── ... ├── Gene_Trees/ ├── Resolved_Gene_Trees/ ├── Species_Tree/ │ └── SpeciesTree_rooted.txt ├── Orthologues/ │ ├── Orthologues_Ath/ │ └── ... ├── Single_Copy_Orthologue_Sequences/ ├── Multiple_Sequence_Alignments/ └── WorkingDirectory/我平时用得最多的几个文件Orthogroups/Orthogroups.tsv核心文件每一行是一个orthogroup每一列是一个物种单元格里是该物种在该家族中的全部基因ID。Comparative_Genomics_Statistics/Statistics_Overall.tsv每个物种的基因总数、落入orthogroup的基因数、单拷贝基因家族数等统计量一眼看出数据质量。Phylogenetic_Hierarchical_Orthogroups/N0.tsv当运行完整流程时生成的层级直系同源组文件区分了不同进化层级上的ortholog/paralog关系这是下游做精细分析时最该关注的。Orthologues/目录两两物种之间的直系同源基因对应表格。4.2 Orthogroups.tsv怎么变成核心、可变、特有基因家族先看Orthogroups.tsv长什么样我用一个三物种的小例子展示Orthogroup Ath Osa Sly OG0000000 AT1G01010,AT1G01020 LOC_Os01g01010,LOC_Os01g01020 Solyc01g01010 OG0000001 AT1G01030 Solyc01g01020 OG0000002 LOC_Os01g01030 OG0000003 AT1G01040 LOC_Os01g01040 Solyc01g01030每一行按列统计就能得到每个基因家族在不同物种里的存在情况核心基因家族Core在所有物种中都至少有一个成员。可变/辅助基因家族Dispensable/Accessory在部分物种中存在但在至少一个物种中缺失。特有基因家族Specific只在一个物种中存在。这个“泛基因组三分法”在细菌泛基因组里很常见植物和动物泛基因组分析也直接借用。OrthoFinder本身不画这个分类需要自己写几行代码。我写了一个简单的Python脚本逻辑上就是把TSV按物种列统计import pandas as pd df pd.read_csv(Orthogroups.tsv, sep\t, index_col0) species_cols df.columns # 是否在某物种中存在 presence df[species_cols].notna() n_species presence.sum(axis1) total_species len(species_cols) core df[(n_species total_species)].shape[0] accessory df[((n_species 1) (n_species total_species))].shape[0] specific df[(n_species 1)].shape[0] print(f核心基因家族: {core}) print(f可变基因家族: {accessory}) print(f特有基因家族: {specific})跑完你就得到了泛基因组层面的“三桶结构”。但注意这里的“核心”是按物种数量算的不是按个体数量。如果某个物种注释质量差基因缺失多很多本应保守的家族会被误判成“可变”所以前面输入的质控直接决定这个分类的可靠性。Statistics_Overall.tsv里还有一个我特别关注的指标——每个物种落入orthogroup的基因比例。正常情况下应该超过80%如果某个物种低于75%说明它的蛋白注释质量可能存在问题要么是基因结构预测不全要么是序列污染。我会回到输入文件重新检查这个物种而不是硬着头皮继续下游分析。5. 我不建议跳过的一步Orthogroups与泛基因组曲线的联动5.1 泛基因组规模曲线和核心基因组曲线做完“三桶结构”只是泛基因家族分析的第一步真正有价值的是看“随着样本量增加新基因家族数量是否还在增长”也就是泛基因组曲线pan-genome curve和核心基因组曲线core-genome curve。OrthoFinder没有内置画图功能但我们可以基于Orthogroups.tsv做随机重抽样每次随机抽取n个物种统计这些物种里存在多少个不同的orthogroup泛基因组大小以及多少个在所有抽取物种中都存在的orthogroup核心基因组大小。重复几十次取平均就能画出曲线。我在一个10个物种的泛基因组项目里画过这条曲线发现当物种数少于6个时曲线还在明显上升拉到9到10个才趋于平缓这说明我们的物种采样基本覆盖了该属的主要基因库。如果你的采样是随机的但曲线在物种数还很少时就“平台”那要么是这几个物种亲缘关系太近要么是注释方式高度一致导致基因集趋同这本身就是值得讨论的生物学信息。画曲线的代码也不复杂核心代码片段如下import random import pandas as pd def sample_pan_core(presence_matrix, sample_sizes, reps20): results [] for n in sample_sizes: for _ in range(reps): chosen random.sample(list(presence_matrix.columns), n) sub presence_matrix[chosen] pan (sub.sum(axis1) 0).sum() core (sub.sum(axis1) n).sum() results.append((n, pan, core)) return pd.DataFrame(results, columns[n_species, pan, core])把presence_matrix用上一节那个TSV转成布尔矩阵即可。5.2 从Orthogroups表格跳到某个具体基因家族的功能分析泛基因家族聚类最大的价值之一是“按图索骥”。比如我研究某个物种的NBS-LRR抗病基因家族传统做法是用已知的NBS-LRR结构域序列做HMMER搜索然后逐条验证。但有了OrthoFinder的orthogroup表我可以直接在Orthogroups.tsv里找包含目标物种已知NBS-LRR基因的那几行这些行对应的整个orthogroup就是跨物种的完整NBS-LRR基因家族。我第一次用这个思路时发现一个意外的结果某个物种的注释文件里有一批NBS-LRR基因没有被标准HMMER流程识别出来但它们在OrthoFinder聚类时明确落进了NBS-LRR家族的orthogroup。原因是这些基因的NB-ARC结构域已经高度退化HMM模型的保守位点不够但跨物种的同源关系和多个物种的序列证据把它们捞了回来。这个泛基因家族聚类的“纠错”功能比单纯做单个家族搜索更能避免漏检。下游如果想对这个筛选出的家族做进一步分析直接从Orthogroups.tsv里提取对应家族的所有序列ID去原始蛋白文件里取序列然后走MAFFT比对、IQ-TREE建树、MEME motif分析、TBtools画基因结构图和常规基因家族分析流程完全衔接。OrthoFinder在这里扮演的角色就是一个高质量的“基因家族成员筛选器”。6. 我在实际项目中踩过的坑每个都让聚类结果偏差很大6.1 不同物种的注释版本混乱导致ID重复有一次做六倍体小麦的泛基因家族分析我用了来自三个数据库的注释文件结果发现不同数据库对同一个基因的命名规则完全不同有些甚至用了完全相同的数字ID但指向不同基因。OrthoFinder启动时没报错但运行完后我在结果里看到一些异常——某个orthogroup里出现了同一个“基因名”在两个不同物种列里都出现看起来很像直系同源实际上是ID冲突把两条无关序列硬塞到了同一个组里。排查方案输入OrthoFinder之前强制给所有基因ID加物种前缀。用seqkit replace或者简单的awk即可seqkit replace -p ^ -r Ath_ Ath_raw.fa Ath.fa永远不要嫌ID长。OrthoFinder运行一次不容易宁可名字难看了点也不能让ID冲突污染整个聚类结果。6.2 蛋白序列里藏着终止密码子聚类出来全是“假直系同源”有一批基因组注释文件来自早期自动注释流程很多基因模型不完整蛋白序列里带着*终止密码子。OrthoFinder默认会在比对前把*当作普通字符处理但DIAMOND的评分矩阵里根本没有终止密码子的匹配结果就是序列相似性被错误估计聚类结果出现大量短序列聚集的“垃圾orthogroup”。在输入前统一过滤掉含终止密码子的序列或者至少把序列截断到*之前seqkit seq -g -v protein.fa protein.clean.fa如果注释工具支持也可以重新用gffread从GFF和基因组提取一次蛋白序列比在已有蛋白文件上修修补补更稳妥。6.3 同一个物种放了多个品系结果被“样品效应”带偏泛基因组分析有时候想用OrthoFinder看同一物种多个品系的基因家族分布。这个想法本身没问题但有个隐藏风险同物种不同品系之间的序列相似性远高于物种间MCL聚类时它们几乎总是被聚到同一个orthogroup里这没问题问题在于后续的“核心/可变”分类如果你有几个品系注释质量差基因丢失多它们会拉低核心基因家族数量并把大量家族推到“可变”那一桶。我的经验是如果目的是研究物种间的基因家族演化就每个物种只放一个代表品系如果目的是研究种内泛基因组最好把品系数控制在合理范围内同时在解读结果时单独检查品系特异的基因家族是否只是注释误差导致的假阳性。OrthoFinder不会替你区分生物学信号和注释噪声这点只能靠你自己。6.4 盲目调MCL inflation参数泛基因组分类瞬间崩坏OrthoFinder通过-I参数控制MCL的inflation值默认1.5。有人为了把orthogroup切得更细会把inflation调到2.0甚至3.0意图是减少“组内混入旁系同源”。但实际效果往往是过度分裂——一个本该完整的基因家族被拆成好几个子家族泛基因组核心家族数量暴涨无数家族变成“单物种特有”结果完全不可解释。我做过一次系统性测试同一个10物种数据集inflation从1.2调到2.5核心基因家族数量从约8000个变成约11000个可变基因家族从3000个变成1800个。哪个对没有绝对标准但如果你的下游分析要计算基因家族扩张收缩不同inflation下同一个家族可能被判为“扩张”或“收缩”结论完全反转。我的建议是默认1.5起步只有在有明显证据表明某个特定家族被错误合并时才考虑调整而且调整后要人工验证几个家族再做全量决策。6.5 只跑了-og模式以为拿到了完整结果-og参数能大幅缩短运行时间它只做orthogroup推断不构建基因树和物种树。适合快速检查输入数据是否合理。但它的输出里没有Phylogenetic_Hierarchical_Orthogroups/N0.tsv没有Resolved_Gene_Trees/不能做基因复制/丢失事件推断。如果论文里需要报告基因家族扩张收缩就必须跑完整流程。我见过有人把-og的结果拿去分析扩张收缩结果被审稿人一眼看穿方法学有误。记住-og是调试工具不是最终分析工具。如果想要更快的完整流程可以适当放宽基因树构建工具比如用默认的FastTree而不是IQ-TREE或者只对单拷贝直系同源组构建树这样能在保证核心结论的同时把时间压缩不少。我个人的习惯是小规模数据直接用完整流程大规模数据先用-og确认正交组数量合理再提交完整流程过夜跑。OrthoFinder这个工具用好了是泛基因组分析和基因家族演化的利器用不好就是一堆看不出问题的陌生号码。把输入数据管好把每一步输出都看一遍尤其是Statistics_Overall.tsv里的基因覆盖比例和单拷贝家族数量它们会在你被结果坑到之前就发出预警。
返回列表