ARTICLE DETAIL

资讯详情

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

Scissor实战:单细胞与bulkRNA关联分析识别预后关键亚群

Scissor实战:单细胞与bulkRNA关联分析识别预后关键亚群 1. 为什么我会在单细胞分析里搬出Scissor1.1 一个让我卡了两周的分析场景先说让我入坑Scissor的那个场景。当时我在处理一批肿瘤组织的单细胞转录组数据细胞注释都做完了CD4T、CD8T、巨噬细胞、成纤维细胞这些亚群也分得清清楚楚。但是客户提了一个需求这批单细胞数据来自30例患者手头还有这30例患者对应的bulkRNA表型数据里面有生存时间、复发状态、病理分级这些临床信息。客户想让我找出“到底哪个单细胞亚群和患者预后显著相关”。这个需求听起来不复杂但真正做起来非常折磨人。常规做法无非是先把单细胞聚成亚群然后做所谓的“伪bulk”分析把每个亚群的表达谱聚合起来再和临床表型做相关性分析。问题在于伪bulk本质上只看“比例”和“平均表达量”大量细胞内部异质性被合并掉了。同一个亚群里可能有的细胞和预后相关有的细胞完全无关一平均就全糊了。当时我换了好几种聚类分辨率出来的结果都不一样给客户的汇报PPT改了四版整个人都快麻了。后面我才认真去翻文献找到了Scissor这个工具。它的全称很拗口翻译过来大概是“基于条件协方差识别表型相关单细胞亚群”发布于Nature Biotechnology。简单说它能把bulkRNA的表型信息作为监督信号直接作用到单细胞层面在不用预先聚类的情况下从成千上万个细胞里挑出和表型真正相关的那些细胞。这个思路一下子解决了我“先聚类再验证”的老路子里最大的痛点不需要提前猜哪个亚群重要让数据自己说。1.2 Scissor到底解决了什么问题传统单细胞分析通常有两个方向。一个是无监督的先聚类、再找marker、注释细胞类型整个过程完全不看样本的临床信息另一个是“先分群再关联”把分好的亚群和外部表型做统计检验本质上还是在用亚群的平均信号去拟合表型。这两种方法都有一个隐藏假设同一个注释亚群里的细胞是“同质”的。但做过单细胞的人都明白一个所谓“CD8T细胞”亚群里可能有耗竭状态、效应记忆状态、naive状态甚至还有少量污染细胞它们的预后意义可能完全相反。Scissor的出现就是来打破这个假设的。它做的事情可以这样理解把每一个单细胞当成一个“候选变量”把bulk样本表型当成“标签”然后训练一个稀疏回归模型。模型最后会留下少数系数非零的细胞这些细胞就是与表型显著相关的“关键细胞”。再把这些关键细胞映射回原来的细胞图谱你就能看到它们集中在哪些注释亚群里甚至还能看出这个亚群里哪些细胞状态才是真正驱动表型的那一部分。这个思路非常巧妙因为它不再要求你先有准确的细胞注释也绕开了“亚群粒度选择”这个老大难问题。聚类分辨率不管怎么调只要模型选出了细胞集合结论就是相对稳定的。1.3 适合谁读读到什么算学会如果你手头也有单细胞和bulkRNA配对数据想回答“哪个细胞亚群和生存、分期、用药响应这些临床指标相关”那这篇文章应该能帮你省下至少两周的摸索时间。文章会从原理讲起但不会堆数学公式更多是从应用角度解释这个算法“到底在算什么”第二部分给出完整的数据预处理清单第三部分是实战代码包括Seurat对象怎么转成Scissor输入、参数怎么选、结果怎么看最后是我在实际跑数据过程中踩过的坑和排查经验。读完这篇文章你能达到的状态是拿到一份单细胞数据和一份带表型的bulk数据知道怎么把Scissor跑通并且能够判断结果靠不靠谱而不是盲目信任一版参数输出的结果。2. 算法思路拆解单细胞当“特征”bulk表型当“标签”2.1 核心思想把每个细胞当作一个回归变量我第一次看Scissor的原始论文时被里面“偏相关”“条件协方差”这些词绕得有点晕。后来自己动手复现了一遍才意识到底层逻辑并没有那么玄乎。它本质上是把问题转成了这样一个回归模型我们有N个bulk样本每个样本有一条临床表型比如生存时间、是否复发。同时我们有M个单细胞每个细胞有一条基因表达谱。Scissor做的事情是构造一个“bulk样本 × 单细胞”的矩阵然后在这个矩阵上跑一个带稀疏惩罚的回归去预测样本的表型。这个构造过程很关键。一个bulk样本在某个“单细胞变量”上的取值并不是简单的表达量高低而是这个bulk样本的表达谱和那个单细胞的表达谱之间的相似度。用生活化的例子说每个单细胞相当于一个“模板”每个bulk样本相当于一个“房间”我拿着模板去各个房间里比对看这个模板在哪个房间里最“适配”适配程度就是矩阵里的数值。这样一来每个细胞都变成了一个可回归的特征而表型是我们要预测的目标。稀疏回归的作用则是“做减法”。M个单细胞里绝大多数和表型没关系如果不加惩罚模型会把噪声也一起拟合结果解释不了。Scissor用的是带L1惩罚的正则化回归让大量对表型没有贡献的细胞系数被压缩成0最后只有少数细胞留下来。留下来的这套细胞就是Scissor认为“与表型相关”的细胞集合官方叫Scissor细胞。2.2 相似度矩阵怎么构建实务中Scissor不是拿原始的几万个基因直接算相似度的那样计算量太夸张噪声也太明显。它一般会先对单细胞表达矩阵做降维取一个合适的特征维度然后基于这个降维后的空间计算bulk样本和单细胞的相似度。你可以把它理解成先找到细胞之间的主干差异方向再在这个压缩后的空间里考察“bulk样本落在细胞图谱的哪个位置”。原始论文里相似度用的是基于相关性的度量实际操作中Scissor包已经把这些细节封装好了。你只需要提供表达矩阵和注释信息函数内部会完成标准化和相似度计算。但有一点需要特别注意如果你手头的bulk数据批次比较重或者单细胞和bulk来自完全不同平台的测序相似度矩阵会被技术差异污染算出来的“适配度”可能反映的是测序深度差异而非真实的生物学相似性。所以数据预处理阶段该做的校正不能省。2.3 图正则化为什么能保住细胞结构如果只是单纯跑一个稀疏回归选出来的细胞可能是零零散散、东一个西一个的缺乏生物学解释。Scissor比普通稀疏回归高明的地方是加了一个图正则化约束。这个约束的思路是如果两个细胞在单细胞表达图谱上本来就靠得很近那么它们被选中或者被剔除的倾向应该是一致的反之如果两个细胞离得很远就不应该被强行“绑在一起”。理解图正则化可以想象成一根橡皮筋网络每个细胞是一个节点相近的细胞之间有弹力连接。回归模型在挑选细胞时会受到这个弹力网络的牵制不可能完全无视细胞之间的结构关系单独做决定。这样选出来的Scissor细胞通常不会是随机散落的孤立点而是表现为图谱上成片、成簇的“有组织”细胞群。这也是为什么下游把Scissor细胞映射回UMAP时往往能很清晰地看到它们集中在一两个区域。这一步对整个分析的可解释性提升非常大。你最后跟别人汇报时可以直接说“Scissor选出来的细胞富集在CD8T耗竭亚群”而不是支支吾吾地说“模型选了137个不连续的细胞”。2.4 哪些场景适合哪些场景别碰Scissor不是万能药它有一个隐含前提bulkRNA的表型差异必须在单细胞组成或者细胞状态上有对应的反映。如果表型差异纯粹是由微环境里的可溶性因子造成的或者单细胞数据只覆盖了组织的一小部分、代表性很差那Scissor的效果就会大打折扣。我自己的筛选标准是这样的如果单细胞数据量足够细胞类型覆盖较全而且bulk表型是生存、复发、疗效这类“整体层面”的临床指标那非常适合用Scissor反之如果表型是一个纯分子层面的指标比如某个通路的得分而单细胞数据又很稀疏那我更倾向于直接用单细胞本身的通路评分去做不一定非要绕一道bulk。另外还要提醒一句Scissor要求bulk样本和单细胞样本在生物学上是对应的。最理想的情况是同一批患者的肿瘤组织一部分做了bulkRNA一部分做了单细胞。如果两者来自完全不同的队列那只能算“跨队列关联”需要在结论层面非常谨慎。3. 前菜数据准备与预处理3.1 三类输入数据的最低要求跑Scissor之前你要先把三类数据备齐。第一类是单细胞表达矩阵我建议直接用Seurat对象里的标准化数据格式是基因在行、细胞在列的矩阵第二类是single cell的注释信息至少要包含细胞barcode和对应的样本来源有细胞类型注释更好这一步是为了后面把Scissor细胞映射回亚群第三类是bulk表达矩阵和对应的临床表型bulk矩阵要保证基因命名规范和单细胞一致临床表型要和bulk样本一一对应。很多人忽略的是“样本对应关系”。Scissor在计算bulk样本和单细胞的相似度时没有要求每个单细胞必须知道来自哪个bulk样本但你至少要在下游知道单细胞来自哪些患者不然选出来的细胞结果没法解释更没法做外部验证。我通常会在单细胞meta里保存“orig.ident”这类样本来源信息这属于有备无患。3.2 基因ID统一与矩阵对齐这是整个流程里最枯燥但也最容易翻车的一步。单细胞数据如果用Ensembl IDbulk数据如果用Symbol两者对不上后续分析根本没法进行。我的做法是写一个小脚本把两边的基因ID都统一转换成Symbol然后取交集。注意这个过程中要处理重复Symbol同一个基因有多个Ensembl ID时我习惯取平均表达量或者取最大表达量不建议直接删掉否则可能丢掉重要信息。取完交集之后还要检查一下交集基因的数量。一般规律是如果交集少于8000个基因说明数据源可能有问题要么是注释版本不一致要么是某一端做了强过滤。我处理过一批数据交集只剩4000多个基因后来发现是bulk那边用了旧的注释文件跟单细胞新版本的Symbol对不上换掉之后交集就正常了。另外一个细节是矩阵的数值类型。Scissor内部的回归函数一般要求数值矩阵不能是稀疏矩阵类型。我遇到过直接拿dgCMatrix塞进去报错的情况处理办法是先用as.matrix()转成稠密矩阵。但如果细胞数特别多超过5万转稠密矩阵会很占内存建议先对单细胞做一轮粗过滤或者抽meta-cell后面会细说。3.3 单细胞低质量细胞过滤Scissor对单个细胞的质量其实比较敏感。如果一个细胞测序深度极低、基因检出数非常少它的表达谱和任何bulk样本的相似度都会非常低但这类细胞在回归里往往会因为“极端值效应”造成干扰。我建议在跑Scissor之前先按常规质控标准过滤掉质量差的细胞UMI总数过低或过高的、线粒体基因比例过高的、双细胞预测概率高的都先清出去。这里特别提一下“过高UMI”的情况。有些细胞可能是双细胞或者倍型异常表达量是普通细胞的两倍以上它们的表达谱容易和bulk样本产生虚高的相似度从而被Scissor误选。我自己在跑一个头颈癌数据时一开始没过滤高UMI细胞Scissor选出来的细胞里有一小簇一直无法注释后来检查发现这些细胞就是双细胞过滤之后结果干净很多。3.4 批次效应处理建议单细胞数据如果来自多个样本、多个批次批次效应会严重影响相似度计算的准确性。你肯定不希望Scissor选出来的细胞只是因为“某个批次的文库深度偏高”才聚到一起。我的建议是如果单细胞测了多个样本跑Scissor之前先用Harmony或者Seurat的整合流程做批次校正用校正后的降维坐标重建表达矩阵再作为Scissor输入。不过这里有个矛盾点批次校正后的表达矩阵虽然去除了技术差异但也会模糊掉一部分真实的生物学差异。如果单细胞数据本身批次设计合理比如每个条件下都有多个样本我更倾向于用更柔和的校正方式比如只做标准化、不做强整合或者至少对比一下校正前后的Scissor结果是否一致。结果稳健性分析永远是这类工具的灵魂后面专门讲。4. 正式上桌Scissor实战完整流程4.1 R包安装与依赖Scissor是一个R包安装路径在GitHub上不依赖复杂的环境。安装之前需要先把Seurat装好因为Scissor很多数据结构和Seurat是打通的。另外建议装一下survival包cox模型家族会用到。我在Linux服务器上安装时没有遇到编译报错比较顺利Windows环境下个别依赖可能要吃Rtools提前装好就行。一个提醒Scissor的GitHub版本更新不算频繁但不同commit之间的参数名可能有小差异。跑之前建议看看GitHub仓库里的README和函数帮助文档确认当前版本的参数签名。我自己踩过一次坑按老版本的教程写参数结果新版本已经不识别那个参数了报错信息又比较隐晦排查了半天。4.2 从Seurat到Scissor输入假设你的单细胞数据已经保存在Seurat对象里名为sce。第一步是取出表达矩阵并转成普通矩阵。我通常用NormalizeData之后的data槽位而不是counts因为Scissor的核心是相似度计算标准化后的表达值更合适。代码大致是这样# 取出单细胞标准化表达矩阵基因在行细胞在列 sce_expr - as.matrix(GetAssayData(sce, assay RNA, slot data)) # 细胞注释信息至少包含样本ID和细胞类型 sce_meta - scemeta.data然后是bulk数据。假设bulk表达矩阵是bulk_expr基因在行、样本在列临床表型数据是phenotype至少包含样本ID、表型变量。注意要把bulk_expr的基因顺序和sce_expr对齐只保留两边都有的基因。这一步我会额外做一次逻辑检查用identical()或者all()确认两个矩阵的行名交集大小然后检查表型的样本名是否全部存在于bulk_expr的列名里。不要省这个检查后面报错往往就是这里埋下的雷。4.3 核心调用cox模型定位预后相关亚群如果表型是生存数据包括生存时间time和生存状态status就用cox家族。Scissor包里的核心函数调用方式大致是library(Scissor) scissor_result - Scissor( expr sce_expr, meta sce_meta, bulk bulk_expr, phenotype data.frame(time survival_time, status survival_status), pval 0.05, alpha 0.05, family cox, dims 10, plot TRUE )参数里expr是单细胞表达矩阵meta是细胞注释信息bulk是bulk表达矩阵phenotype是你要关联的表型数据。familycox表示用Cox比例风险回归拟合生存表型如果表型是二分类比如响应与否可以换成familylogistic如果是连续数值则用familylinear。alpha是一个正则化相关参数默认0.05控制模型压缩的力度。dims是构造相似度矩阵时使用的降维维度论文里一般建议10到20之间。我通常会用dims10作为默认值数据量大的时候加大到15或者20也不会差太多。函数运行结束后结果对象里有几个关键字段。scissor_result$Scissor_select是模型选中的细胞barcode列表scissor_result$Scissor_pos和scissor_result$Scissor_neg分别表示正向和负向相关的细胞集合简单理解就是Scissor细胞和Scissor-细胞。scissor_result$para是拟合的参数信息可以用于后续判断模型收敛情况。4.4 结果对象里有什么跑完之后第一件事不是画图而是先看选了哪些细胞。我一般会这样处理# 查看选中细胞数量 length(scissor_result$Scissor_pos) length(scissor_result$Scissor_neg) # 把Scissor结果写回Seurat对象方便后续可视化 sce$scissor_group - Unselected sce$scissor_group[colnames(sce) %in% scissor_result$Scissor_pos] - Scissor sce$scissor_group[colnames(sce) %in% scissor_result$Scissor_neg] - Scissor-选中的细胞数量通常不会太多几十到几百个都算正常。如果一开始就选出来一大半比如总细胞2万个、选出来8000个那要么是alpha太小导致惩罚力度不够要么就是数据里存在很强的批次结构。反之如果一个都没选中多半是表型和单细胞之间本来就没关系或者相似度矩阵构建出了问题。如果meta里带了细胞类型注释可以做一个简单的列联表看看Scissor和Scissor-细胞主要落在哪些注释亚群里。这一步能给你最直观的第一印象选出来的细胞到底富集在什么细胞类型里。4.5 可视化把Scissor细胞映射回UMAP把scissor_group这个变量加到Seurat对象后直接在DimPlot里按这个分组着色就能看到非常直观的分布效果。我通常这样画DimPlot(sce, group.by scissor_group, cols c(Scissor #E64B35, Scissor- #4DBBD5, Unselected grey90))画完之后重点看两个方面。第一Scissor细胞是否聚成明显的块而不是星星点点散得到处都是。如果选出来的细胞在UMAP上非常零散、看不出结构即使统计上显著生物学解释也会很困难。第二Scissor细胞与Scissor-细胞是否落在同一个注释亚群里。如果是说明那个亚群内部存在明显的功能分化这往往是最有意思的发现。这里我要强调一个实战心得不要只画一张图就下结论。我至少会把Scissor细胞分别投影到不同条件下的UMAP比如按样本分组、按疾病分期分组确认这个信号不是被某个极端样本单点驱动的。多维度检查能让结果更可信。5. 参数调优alpha、family、cutoff怎么定5.1 family选择cox / logistic / linearScissor支持三种常见的回归家族选择依据完全取决于表型数据的类型。生存数据优先选cox二分类标签用logistic连续型指标选linear。这个直觉判断大部分时候是对的但有两点需要额外提醒。cox家族对样本量的要求比较严格。如果你的bulk样本只有十几例Cox模型的统计功效很低Scissor选出来的细胞结果可能受一两个事件样本影响很大。遇到这种情况我会优先换成logistic模型比如把生存数据按中位生存时间切成高低两组或者按3年生存状态划分虽然损失了一些信息量但稳定性好很多。logistic则要注意类别平衡。如果响应组只有3例非响应组有27例模型很容易倾向于选择与非响应相关的细胞而不是真正区分两组的细胞。解决思路是尽量找更多样本或者至少在下游解读时不要把“负向相关细胞”机械地理解成“不响应相关”要结合方向和生物学背景去看。5.2 alpha到底在控制什么Scissor里的alpha参数是核心正则化参数它决定模型压缩到多狠。我的理解是alpha越大惩罚越重选出来的细胞越少、越精炼alpha越小模型越宽松选出来的细胞会变多。默认值0.05在大多数场景下是一个不错的起点但我从来不会只跑一个alpha值就收工。实操时我会跑一组alpha序列比如0.001、0.01、0.05、0.1、0.2看选出的细胞数量变化和富集亚群是否稳定。如果在一定范围内比如0.01到0.1选出的细胞富集的注释亚群始终一致说明这个结论相对可靠如果alpha稍微变一点富集亚群就从T细胞跳到巨噬细胞那基本可以断定这个分析是脆弱的不能作为核心结论输出。5.3 怎样判断结果是“稳”的稳健性检验是整个Scissor分析里最容易被忽略、但最该认真对待的部分。我总结了一个“三个一”策略换一个alpha、抽一次样本、换一次降维维度。换alpha前面提过了抽一次样本是把bulk样本做bootstrap重采样比如每次抽80%的样本跑Scissor重复10次看选出的细胞集合重叠率有多高换降维维度是改dims参数对比结果。这三个维度如果都还算稳定那这个Scissor细胞集合就可以拿来深入分析了。如果某一个维度稍微变一下就结果大翻转说明数据本身支撑不了这个结论别硬做。5.4 敏感性分析模板给一个我常用的敏感性分析模板方便直接套用检查项操作方式可接受标准alpha稳定性跑0.01、0.05、0.1三档富集亚群保持一致样本稳定性80%样本bootstrap重复10次细胞集合重叠率大于50%降维鲁棒性dims分别取5、10、20结论方向一致批次影响校正前后各跑一次富集亚群不变基因过滤影响高变基因数量改为2000/3000关键亚群不变这张表做完之后如果全部通过那这个分析基本上可以支撑论文里的一个子图甚至一个独立发现。如果有一两项不过别急着发先回到数据预处理看看是不是有隐藏问题。6. 下游分析从细胞集合到生物学结论6.1 Scissor vs Scissor-差异表达拿到Scissor和Scissor-细胞集合后最自然的下一步就是做差异表达分析看看这两组细胞在分子层面到底差在哪里。这里不推荐直接用Seurat的FindMarkers因为Scissor细胞往往只有几百个Scissor-可能有几千个样本量不平衡可能导致很多假阳性我更推荐用伪bulk加DESeq2的分析策略把Scissor和Scissor-分别按样本聚合然后做组间差异。不过要注意一个细胞数太少的问题。如果一个Scissor集合只有50个细胞分散在10个样本里按样本聚合后每个样本平均只有5个细胞表达值波动非常大。这种情况我宁可做单细胞层面的差异表达但事后一定要注释里可重复的marker去验证不能只凭一个Wilcoxon检验的p值就下结论。差异表达完成之后把上调基因的列表拿出来做富集分析。我习惯用clusterProfiler做GO和KEGG同时也看一下关键marker基因在两组之间的表达差异比如CD8T细胞相关的GZMB、PRF1或者巨噬细胞相关的APOE、C1QA直接在小提琴图上看趋势。6.2 功能富集与通路得分除了传统的富集分析我建议给每个细胞算一下通路活性得分然后用Scissor和Scissor-来做对比。方法可以用UCell、AUCell或者Seurat自带的AddModuleScore选一个你顺手的方式就行。算完之后直接比较两组细胞的通路得分分布能非常直观地看出Scissor和Scissor-在功能表型上的差异。我遇到过一个典型案例Scissor的细胞注释上是巨噬细胞但通路得分显示这群细胞里糖酵解通路显著高表达而Scissor-的巨噬细胞更多是氧化磷酸化特征。如果只看注释你不会发现同一个巨噬细胞类群内部存在这么明确的功能分化而Scissor把细胞按表型相关性分成了两个集合后这种代谢重编程的特征就浮出水面了。6.3 外部验证思路Scissor的结果毕竟是从有限样本里学出来的最好能用外部数据验证一下。最直接的验证方式是用另一个单细胞数据集看同一个亚群里的Scissor特征基因是否也在那个数据集中有类似的功能倾向。但这往往不太现实因为很难找到完全匹配的表型数据。退一步的做法是回到bulk层面验证。从Scissor细胞里提取差异表达特征基因做一个基因签名然后在独立的bulkRNA数据集中计算这个签名的得分看它和临床表型是否显著相关。如果签名得分和生存显著相关就相当于从另一个角度验证了Scissor选出的细胞集合确实有预后指示价值。这也是目前很多文章的通行做法实操落地比较容易。7. 我踩过的坑与排查记录7.1 基因交集只剩3000个我第一次跑Scissor的时候取了单细胞和bulk的表达矩阵后直接做交集结果发现只有3000多个基因而且大部分是核糖体蛋白基因和管家基因。当时没放在心上直接用了这个交集跑分析结果Scissor选中了一堆没有生物学意义的细胞怎么看都不对劲。后来排查发现bulk矩阵里基因ID是Ensembl版本号比较旧的格式单细胞那边是新版的Symbol两者之间有很大一部分对不上。解决方法是重新用biomaRt做ID转换统一之后再取交集交集恢复到15000多个基因。从那以后我给自己定了一条规矩任何矩阵合并前先检查基因符号格式再检查交集数量少于8000个不往下走。7.2 报错说细胞名对不上Scissor跑的时候报错提示找不到某些细胞名或者样本名这个问题多半出在给phenotype赋值时样本名格式不一致。bulk表达矩阵的列名可能是“S1_Sample”而phenotype里的行名是“S1-Sample”一个下划线一个横杠肉眼不容易看出来但代码就是匹配不上。我的排查办法是打印出两边的列名和行名逐一检查有没有空格、横杠、下划线这些细微差异。批量处理的时候建议用make.names()统一转一遍或者干脆自定义一个规范化函数把所有样本名里的特殊符号全部替换成下划线。这样虽然丑一点但能确保后面不再出类似的幺蛾子。7.3 bulk样本太少怎么办bulk样本数少于15的话Scissor的结果会非常不稳定。我试过一个只有12个bulk样本的数据集生存状态下的事件数只有4个跑出来的Scissor细胞每次重启都稍微不一样换一个alpha更是差异巨大。后来我调整策略把生存数据按中位生存时间切成二分类用logistic家族跑稳定性明显改善。如果连二分类组的样本数都很少那就别硬跑Scissor了退回到“先聚类再关联”的老办法至少还能控制一下统计自由度。这不是在否定Scissor的价值而是任何模型都需要足够的样本支撑Scissor也一样。7.4 全部细胞都被选中或都没被选中全部细胞被选中大概率是alpha设得太小惩罚力度不足或者表达矩阵没有标准化相似度计算被极大值主导。全部没被选中则要检查表型数据是否有问题比如生存状态列全是0或者表型方差接近0。还有一个容易被忽略的点phenotype的样本名顺序和bulk表达矩阵的列名顺序不一致导致数据错位模型自然学不到任何东西。这种错位有时候不会报错只会默默输出一个全零结果特别坑。7.5 换epoch后结果飘了Scissor的结果依赖相似度矩阵的计算而降维步骤PCA或者类似方法对不同版本的Seurat或者不同种子数的结果会有微小影响。我在两台服务器上跑同一个数据结果选出的细胞有20%左右的差异这让我一度怀疑代码出了问题。后来发现是其中一台服务器上Seurat的PCA实现因为BLAS线程设置不同导致浮点运算顺序有差异。解决办法是在分析开始时固定随机种子并且尽量保证运行环境的R包版本一致。对于那种“换环境结果变化但核心亚群一致”的情况我一般是可以接受的但如果核心亚群都变了那说明数据本身对参数太敏感需要回到预处理重新排查。7.6 内存爆炸单细胞数据动辄几万细胞如果直接as.matrix()转成稠密矩阵非常吃内存。我试过42000个细胞、16000个基因的表达矩阵转成稠密矩阵大概需要5GB左右内存跑Scissor时峰值内存冲到30GB以上服务器差点崩了。后来我在跑之前先做了一个粗过滤去掉表达量低于一定阈值的细胞、去掉低频表达的基因同时考虑在细胞数特别多的时候先分群采样。如果你只有一台普通笔记本建议先把细胞数控制在两万以内不然跑起来确实费劲。8. 几条实在的使用心得Scissor这个工具说神奇也神奇说朴素也朴素。神奇在于它能把bulk层面的表型信号传导到单细胞尺度直接从细胞图谱上圈出关键人群朴素在于它本质上还在做稀疏回归模型输出的可靠性完全取决于输入数据的质量和样本量。你会发现真正决定分析天花板的往往不是算法本身而是数据预处理做得够不够细致、稳健性验证做得够不够充分。我自己的习惯是拿到一批新数据先不急着跑Scissor而是花半天把样本对应关系、基因ID格式、批次设计这些基础信息摸清楚。这一步看似枯燥却能避免后面80%的返工。跑的时候也不要只盯着一个默认参数alpha序列、dims变化、bootstrap重采样这些稳健性检验必须做一套不然你拿出去的结果经不起同行质疑。如果你在做单细胞数据分析时也遇到了“亚群和表型对不上”的困境不妨试试Scissor。把细胞当成特征让模型替你去挑有时候比自己趴在UMAP上猜半天靠谱得多。
返回列表