资讯动态

空间转录组多样本合并:spaceranger aggr实战与避坑指南

发布时间:2026/10/14 10:18:46 来源:尧图企业网站定制
空间转录组做到第五讲终于到了多样本合并这一步。前面几讲分别cover了样本制备、spaceranger count运行、基础质控和数据可视化再往后走基本就是白天测完几张切片晚上回来对着四五个outs目录发愁的场景。单张切片各有各的聚类和降维看单张还行想统一比较这一群spot在几个样本间怎么共变就得先把多个矩阵合并到一张表上。spaceranger aggr就是官方管线里专门干这步的工具。这篇就写写我怎么用它把多个Visium样本合并起来以及合并之前、之中、之后要注意哪些细节。适合谁来读如果你已经能用spaceranger count跑通单个样本但还没试过aggr或者你试过但发现合并后样本间的深度差异很扎眼再或者你正纠结是用aggr还是自己写脚本硬拼矩阵这篇都有用。命令本身短得怀疑人生难点全在参数理解和对各种隐性坑的预判上。1. 为什么要用spaceranger aggr合并样本1.1 什么场景下你真正需要 aggr先说个我踩过的反面例子。模拟项目X里我收了同一处理条件下三个样本的空间转录组数据刚开始偷懒每个样本单独跑完spaceranger count然后在R里分别分析最后想把三张切片拼在同一张feature plot上。结果三个样本的UMI计数范围差出一个数量级聚类结果肉眼看着相似但基因表达数值根本没法直接放在同一个颜色标尺下比较。这时候aggr的价值就体现出来了——它不是简单地把矩阵拼接在一起而是在拼接之前先做样本间归一化让测序深度差异对后续联合聚类的影响降到最低。所以第一个问题什么场景才需要aggr答案不是“只要我有多个样本就必须用它”。当你只是想逐张切片做探索性分析或者样本是不同组织类型、差异极大、你完全接受各自独立分析时不合并反而更干净。aggr最适合的是样本来源一致、实验明确要求跨样本比较、需要一组共同聚类标签和降维坐标的场景。比如同一个疾病模型的不同生物学重复或者同一空间区域的连续切片时间序列又或者你想把多个样本放进同一个embedding里看细胞类型的空间共定位这类需求就是aggr的主场。另外要提醒一个常见心理不要因为看到教程里都在讲aggr就觉得它是唯一答案。空间转录组样本的合并从来不是一道只有正解的题工具选型取决于下游问题。如果核心问题是“每个样本内部有哪些domain”那分开跑完全合理只有当问题变成“不同样本之间的同一个domain会不会表达不同的marker”时跨样本合并才真正不可避免。1.2 aggr和手动拼接矩阵的本质区别很多初学者会把aggr理解成一个把两份矩阵按行拼接起来的脚本这其实低估了它。手动拼接矩阵你只能解决“数据能不能放进同一个Seurat对象”的问题解决不了“样本间测序深度不同导致的技术噪声”问题。如果聚合操作只是把两个矩阵纵向堆叠深度高的样本会主导聚类方向深度低的样本信号会被稀释dropout模式也会干扰下游差异分析。aggr的做法更接近“对齐后在同一个坐标系下重新衡量”。它基于molecule_info.h5保留每个UMI原始barcode信息而不是直接拿汇总好的矩阵硬拼。这也是为什么它要求输入不是每个样本的filtered_feature_bc_matrix而是那个看起来不起眼的molecule_info.h5。这个设计从根上决定了aggr能做mapped归一化能在同一个平台假设下统一处理多个样本也能在输出矩阵中保留样本来源信息。后面我会详细拆解这个文件到底存了什么。还有一个容易忽略的设计点是版本一致性。spaceranger aggr要求参与合并的样本都由同一大版本的spaceranger count产生最好是同一版本参考转录组生成。不同版本产出的molecule_info.h5在格式细节上有差异轻则日志出现警告重则直接报错或者输出异常。我见过有人把旧版样本和新版样本混在一起合并结果旧样本的spot数量几乎全部丢失排查了很久才意识到是版本差异。这条规矩遵守好能省掉一大半隐性错误。2. 输入文件与参数选型的底层逻辑2.1 molecule_info.h5到底存了什么先说结论molecule_info.h5是spaceranger count运行过程中保留的一张“分子流水账”。它不是基因表达矩阵的压缩版而是记录了每一个检测到的moleculeUMI的barcode、feature id、UMI序列、count次数以及比对信息。换句话说它比最终矩阵多保留了“可以重新汇总”的元数据。为什么aggr需要这个级别的信息而不是直接读矩阵因为跨样本归一化本质上是一次“重新抽卡”——要把不同样本的测序深度拉齐就必须知道每个样本里每种分子被观测到几次才能决定按什么比例做降采样。filtered_feature_bc_matrix已经丢掉UMI层面的信息只剩每个spot最终的count值拿它没法做mapped归一化。这个细节决定了aggr的输入路径必须指向每个样本的outs/molecule_info.h5。实操中我建议每次运行完spaceranger count后第一件事就是把outs目录里的molecule_info.h5绝对路径记录下来。别等分析阶段再翻目录样本一多结构很容易乱。我自己习惯在项目样本表里维护一列h5路径后面直接喂给aggr的CSV。这列路径哪怕不急着用也能在归档时帮你快速定位每个样本的原始产出。2.2 normalize参数mapped和none的分歧点aggr的--normalize参数只有两个取值mapped和none但选错的影响不小。mapped是默认值也是绝大多数场景下的正确选择。原理是把每个样本的测序深度映射到一个共同水平具体做法是对高深度样本做UMI降采样使所有样本的总有效分子数大致相当。好处是后续联合聚类不会被某个深度特别高的样本主导。但mapped不是万能的。如果几个样本的测序深度差异巨大比如一个样本平均每spot只有2000 UMI另一个有8000mapped会强制把8000的样本降到接近2000的水平这时原本在8000深度下能检测到的低表达基因就会丢失。我遇到过的情况是高深度样本中一些稀有细胞类型的marker基因因为被降采样过于狠联合聚类里几乎看不到了。所以什么时候选none当你后续有更精细的批次校方案或者你明确知道样本间的计数差异是生物学因素而非技术因素时可以用none保留原始计数再通过Seurat的SCTransform、Harmony之类做自己的归一化。简化原则想省事、想让官方结果直接可比选mapped想保留全量信息自己深度处理选none。我在正式项目里几乎都是跑一遍mapped用于快速浏览同时保留每样本单独count的矩阵用于精细分析。2.3 输出文件里有什么哪些值得关心跑完aggr之后输出目录东西不少但不是每样都需要仔细读。按优先级我最先看aggr_report.html它会把每个样本的测序饱和度和过滤后的spot数放在一起一眼看出哪张切片拖了后腿。其次才是合并后的矩阵文件和cloupe可视化文件。合并矩阵部分会自动生成feature matrix、barcodes、features三件套barcode会自动带上样本前缀下游分析能轻松溯源某个spot来自哪张切片。cloupe文件是给Loupe Browser用的适合手动点开看某个marker基因在合并后的空间图中是否只富集在某个样本区域。如果你习惯纯编程分析cloupe可能无所谓但团队里只要有人喜欢看图形界面这步千万别省。另外aggr输出里还会保留每个样本的聚类结果和降维投影。这些结果对快速验证样本间混合程度很有用。我一般不太关注默认的整图聚类标签因为下游多半还会用Seurat重新调参但官方输出的这些中间文件可以作为“标准答案”参考特别是当你的分析结果和官方聚类差异很大时先排查自己的预处理哪里出了问题。2.4 参数速查与内存预估把常用参数整理成速查表直接存起来当cheat sheet用参数作用我的建议--id输出目录名带日期和项目缩写例如ctrl_202501_merge--csv样本清单文件路径写绝对路径文件用纯ASCII无BOM头--normalize跨样本归一化默认mapped深度差异大时考虑none加自建整合--dryrun只校验不运行正式运行前先跑一遍能省大把试错时间--localcores线程数按机器实际核数给别把超线程全算进去--localmem内存上限显式指定不建议依赖默认探测内存需求方面我的经验是合并三到六个Visium样本内存需求通常在64GB到128GB区间。如果你只有一台16GB内存笔记本基本可以放弃用aggr跑全流程要么换机器要么走前文说的自建Seurat整合。时间上四张典型切片、16核64GB内存大概三到六小时但具体还是要看每张切片的spot数和有效barcode量。3. 完整实操流程与脚本化技巧3.1 批量构造CSV清单的脚本方法aggr的入口是一个两列的CSV文件列名分别是sample_id和molecule_h5。sample_id是你能一眼认出的样本标记molecule_h5是h5文件绝对路径。看着简单但命名规范比想象中重要。sample_id只允许字母、数字、连字符和下划线不能以数字开头也不要带点号和空格。我第一次给样本起名叫sample_1.v2结果后续路径解析出现歧义排查半天才发现是点号在作怪。样本数量少的时候手工写CSV没问题但数量一多最好脚本化。下面这个示例假设每个样本的outs目录都在独立文件夹里我用find找到所有molecule_info.h5再用目录名做sample_idfind /data/visium_run -maxdepth 3 -name molecule_info.h5 h5_files.txt echo sample_id,molecule_h5 aggr.csv while read f; do sample$(basename $(dirname $(dirname $f))) echo $sample,$f aggr.csv done h5_files.txt注意最后一步的basename和dirname要根据你自己的目录层级调整不同项目文件夹结构不一样不要无脑复制。脚本生成后用head -5 aggr.csv看一遍确认sample_id没有重复路径都是绝对路径。运行前我还会做一次文件存在性检查把漏掉路径的问题拦在前面tail -n 2 aggr.csv | while IFS, read -r sid h5; do if [ ! -f $h5 ]; then echo missing: $sid - $h5 fi done这个检查除了能发现路径写错还能顺便发现CSV里有没有空行、字段错位之类的问题。别嫌这一步幼稚我在正式跑aggr前用这个套路拦住过不止一个样本的路径错漏。3.2 运行命令与关键节点观察准备完成后命令本身短得不像一个生信工具spaceranger aggr --idctrl_202501_merge \ --csvaggr.csv \ --normalizemapped \ --localcores16 \ --localmem64第一次跑的时候强烈建议加一个--dryrun它只校验CSV和输入文件是否存在不跑真正的分析。我见过不少人在正式环境里直接跑长任务结果跑了半小时才发现CSV里有明显错误纯浪费机时。dryrun通过后去掉参数正式运行。运行过程中spaceranger会打印每个样本的barcode数、测序深度、降采样比例等日志。这些输出别急着划过去。我习惯把标准输出和标准错误重定向到log文件一方面便于追溯另一方面后续写方法部分或者向导师汇报时这些数字直接能当论据。spaceranger aggr --idctrl_202501_merge \ --csvaggr.csv \ --normalizemapped \ --localcores16 \ --localmem64 aggr.log 21如果你在集群上跑记得把作业提交命令里的内存限制和--localmem保持一致否则可能出现“作业被限制内存在运行中途被杀掉”的情况。我在某个排队等待已久的任务上栽过这个跟头集群限了32GB本地参数写了128GB结果系统把任务直接OOM kill了白白等了一天队列。3.3 输出验证从报告到矩阵跑完不能只看到outs目录存在就欢呼先打开aggr_report.html看三件事有没有样本因为质量差被警告合并后的总spot数量是否和每个样本单独跑时加总一致每样本的测序饱和度是否处在合理区间。如果总spot数远低于单独样本之和多半是某个样本的过滤标准异常或者h5路径指向错误。第二步是加载合并矩阵做快速的spot计数检查。我习惯直接在R里读barcodes文件按样本前缀统计每个样本的spot数。一个粗略思路是先按分隔符切分barcode再统计前缀出现次数。这一步虽然原始但能第一时间发现样本串位或者某些样本spot丢失的问题。第三步才轮到聚类验证。在Seurat里跑标准流程看UMAP上样本间的混合程度。如果发现某个样本聚成一团独立cluster、完全和其他样本不重叠先别急着下结论说这是生物学差异回头检查它的测序深度是否异常低或者log里的降采样比例是否高得离谱。空间转录组的batch效应不一定会以经典batch形式出现有时候就是挤在一起的一团spot。4. 常见问题与排查技巧实录4.1 CSV编码与命名问题aggr报错里最常见一类就是找不到文件或者格式不识别。除了路径绝对化之外还有一个容易踩的坑是CSV编码。如果你在Windows下用Excel编辑CSV再传到Linux服务器文件很可能是带BOM头的UTF-8编码CSV第一列第一个字段会额外多一个不可见字符导致sample_id解析错乱。解决方法很直接上传后用file命令检查编码或者用sed去掉开头三个字节。我用过一次sed处理后就彻底改了习惯所有给aggr用的CSV都在Linux里用命令行生成不在Windows那边碰。另一个必须防的命名问题是sample_id重复。如果两个样本用了相同IDspaceranger未必优雅报错但可能在输出阶段互相覆盖。我在批量生成CSV时习惯把实验批次加进ID比如ctrl_rep1这种既保证唯一性也让下游追踪更清晰。4.2 软件版本与参考转录组不一致这个问题在我踩坑列表里排前三。某次我把旧版本spaceranger count跑的样本和新版本样本放在同一个aggr里结果新版本样本spot数正常旧版本样本被识别后只输出极少数spot下游分析一度以为样本本身数据坏了。后来逐项排查才确认是版本差异导致h5内部结构解析不一致。所以现在每次启动新样本我都会在项目说明里写清spaceranger版本和参考转录组版本并检查所有样本是否一致。如果确实混用了版本最干净的做法是统一版本重新count旧样本而不是在aggr层面将就。aggr文档本身也不建议把不同版本的count输出混入同一个合并任务这条规矩值得当成铁律。顺便提一句参考转录组版本不一致带来的问题更隐蔽。如果两个样本一个用旧版注释一个用新版注释基因ID可能对不齐合并矩阵里会出现大量空行或者特征缺失。这种问题在日志里往往只表现为warning不仔细看就会被忽略。所以我在CSV清单里除了记录h5路径还会额外加一列spaceranger版本和参考版本合并前用脚本统一检查。4.3 测序深度差异导致的降采样过度合并后最常见的现象是每张切片单独看都正常合并后却发现某个样本的spot永远挤在UMAP边缘或者单独成簇。这时我第一反应是测序深度差异和mapped归一化强度叠加造成的而不是直接断言这个样本存在生物学差异。处理方法不是马上放弃aggr而是先看日志里的降采样比例如果某个样本被降到了原来的三分之一以下它的低表达信号损失会非常严重。我就在一个模拟项目里碰到过类似情况其中一个样本深度显著低于其他三个mapped降采样后它在联合分析里几乎失去所有稀有基因信号。最后我改用了更稳妥的路线保留每样本单独count的矩阵读入Seurat后用SCTransform做样本内归一化再用Harmony做样本间的批次整合。这个方法步骤多一些但对深度差异极大的样本更友好。如果项目里样本深度差在3倍以内我还是推荐直接用aggr的mapped省事且结果稳定。另外要记住mapped降采样的输出仍然是整数count矩阵适合直接下游分析。但如果你的核心关注点是高深度样本的稀有亚群建议保留一份未经aggr降采样的原始矩阵做平行分析避免不可逆的信息损失。4.4 资源占用与运行时长管理aggr对内存的胃口比spaceranger count温和但它仍然不是一台16GB笔记本能轻松扛住的任务。以我的经验合并三到六个Visium样本时内存需求通常落在64GB到128GB区间时间从两小时到十小时不等。如果你在集群上没有显式指定localmemspaceranger可能按物理内存自动估算与其他任务同时跑时会互相挤爆。所以我建议不管在哪儿都显式写--localmem。如果样本量特别大比如十几张切片单机跑通aggr会很吃力。一个自然的想法是先分批合并再二次合并但这条路径在aggr里并不稳妥因为输入必须是最初的molecule_info.h5二次合并格式不保证支持。更可靠的做法是直接上更大的机器或者集群。我在大规模样本场景下更倾向于放弃aggr改用自建Seurat对象再整合主要为了灵活性和可复现性。4.5 合并后的barcode追溯与计数合并矩阵里barcode会自动带上样本前缀这个设计很好用但也需要你提前知道分割规则。常见格式类似sample1_AAACCTGGT...我通常用字符串拆分前取第一个分隔符之前的字段来还原样本来源。如果你用的sample_id本身带下划线比如ctrl_rep1拆分时就要小心别把样本ID拆断了。有一次我在统计各样本spot比例时因为sample_id里带了多余的下划线分割逻辑写错导致所有spot都被归到一个样本名下。查了很久才发现是分隔符选择不当。后来我统一了规则sample_id里不再使用下划线作为内部连接符只用连字符这样分割barcode时只要按第一个下划线切开前段一定是完整样本名。这种小约定能省掉大量下游麻烦。5. 合并后的下游分析建议5.1 什么时候应该绕过aggr虽然这篇重点在aggr但我不鼓励无条件使用。如果项目核心是识别不同样本间共享的细胞类型但其中一个样本明显离群比如组织坏死严重或者数据质量极差把它一起塞进aggr只会拉低整体聚类分辨率。这种时候我更倾向先对每个样本单独分析把离群样本剔除后再做多样本整合。另一个绕开aggr的典型场景是多模态数据也就是除了转录组还想同时分析空间蛋白组、形态学图像等额外维度。aggr管道围绕Visium标准分析设计不会额外处理自定义类型数据。当你需要把其他模态信息与转录本矩阵对齐时自建分析流程往往是唯一选择。不要因为aggr是官方工具就强行套用适合才是第一原则。5.2 合并矩阵进入Seurat后的标准体检清单拿到合并矩阵后我一般按清单快速过一遍总spot数是否符合预期每个样本spot数占比是否和单独count时一致一个在全球都高表达的基因在合并矩阵里的值是否符合直觉随机取一个已知空间模式的marker看它的空间分布是否和单独count结果一致。这些检查看起来基础但能拦住一半“捷径后遗症”。如果用的是mapped归一化注意后续分析里不要再用Seurat的NormalizeData把每个样本重新归一化到默认scale factor上否则等于把aggr降采样过的深度差异重新放大。更合理的做法是直接把合并矩阵读入做log1p变换再进入降维聚类。这个细节很容易在对比两个流程时露馅我有一次就在这里绕了弯路花了两天对比分析才意识到问题是重复归一化搞出来的。5.3 跨样本空间变化可视化思路合并后的一个高频需求是把某个基因在不同样本上的空间表达并列展示。这时候aggr输出的cloupe够用但如果你想在R里统一控制配色和排列我一般用Seurat的SpatialFeaturePlot按样本拆分或者自己写一个按坐标排列的分面图。关键是要注意不同样本的组织形状可能差异很大图上坐标不能硬性对齐只要保证同一个embedding的降维投影一致就行。另一个我经常做的可视化是跨样本比例堆叠图。比如把合并后的cluster或domain标签按样本切分统计每个样本里各个domain的spot占比画成百分比堆叠条形图。这种图对展示“同一结构在不同样本间的大小变化”非常直观。别忘了给每个样本在图上标注它的降采样比例让读者知道这种占比差异有多少来自技术因素。6. 写在最后的一点体会写到这里spaceranger aggr从定位、参数、实操到避坑基本串了一遍。我个人实际体会是aggr的价值不在于帮你省写脚本而在于它把“样本间技术差异”这个最容易让新手栽跟头的问题提前规范化了。你能不能用好它前提始终是样本质量靠谱、版本一致、样本间差异控制在合理范围如果输入本身有硬伤任何参数和flag都救不回来。最后再分享一个小技巧不管项目多赶我一定保存每次运行的日志和aggr报告并在合并后样本名里带上日期。空间转录组数据规模只会越来越大几周后再跑一次新的合并是常态没有日志就只能对着模糊记忆调试。把过程文档化这件事比选参数本身更重要它决定的是你之后能不能快速复现这次分析的所有决策。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑