用公共数据讲好一个科研故事
跟完这篇,您能把一个具体问题,落成「选数据 → 差异 → 预后 → 免疫 / 机制」的一条逻辑链:知道每一环回答什么、用什么证据、和上一环怎么扣起来,最后写出一段前后自洽、就算没做实验也站得住的结果,并且清楚这类分析的边界在哪。
先想清楚:一个能讲的故事长什么样
零实验的公共数据分析,最怕的不是不会跑,而是跑出一堆图却串不成话——差异分析一张、生存曲线一张、免疫热图一张,各说各的,读者看完不知道您到底想说什么。
一个能讲的故事,本质是一条环环相扣的逻辑链:每一步只回答一个小问题,且它的结论正好是下一步的前提。最常用、也最好复现的一条链是这样:
| 环节 | 回答的问题 | 主要证据 | 承接上一环 |
|---|---|---|---|
| 现象 | 我的对象(某基因 / 通路)在病与正常之间真有差别吗 | 差异分析、表达箱线图 | —— |
| 重要性 | 这个差别和临床结局有关吗,值不值得看 | 生存曲线、Cox | 用「有差异」的对象来分组 |
| 机制线索 | 它可能通过什么起作用 | 富集、免疫浸润、相关性 | 解释「为什么预后不同」 |
| 收口 | 综合起来能提出什么假设 | 一段自洽的论述 | 把前三环并成一句话 |
把这张表记住,后面每一节就是在填其中一行。注意:这条链给的是「相关证据 + 合理假设」,不是因果证明——这点决定了结尾该怎么写,本文最后一节会专门讲。
第一步:把问题写成一句可检验的假设
故事的起点不是数据,是一句话。含糊的「我想研究基因 X 在肝癌里的作用」没法照着做;把它收敛成一句带对象、带背景、带方向的假设,才知道下一步要什么数据、跑什么分析。
一句好假设通常含三个要素:
- 对象——具体到一个基因、一条通路或一个评分(如
GENEX); - 背景——哪个疾病、哪种组织、和谁比(如「肝癌肿瘤组织 vs 癌旁」);
- 方向性主张——您预期看到什么(如「高表达、且与更差的总生存相关」)。
拼起来就是一句可检验的话:
GENEX在肝癌中相对癌旁高表达,其高表达与更差的总生存相关,且可能与肿瘤免疫浸润的改变有关。
这句话本身就是您整条逻辑链的目录:「高表达」对应差异分析,「更差的总生存」对应预后分析,「免疫浸润」对应机制那一环。写不出这样一句话,往往是问题还没想清楚——先补这一步,别急着下载数据。
第二步:按问题选数据,而不是按数据凑问题
有了假设,才谈得上选数据。顺序千万别反:先有问题、再找匹配的数据,而不是先下一套热门数据、再回头看能凑出什么结论——后者做出来的故事往往牵强,也最容易被审稿人看穿。
对着假设,用一张清单核对候选数据集够不够用:
| 要核对的 | 为什么重要 | 不满足会怎样 |
|---|---|---|
| 有没有您要的分组 | 差异分析需要「病 vs 正常」或「高 vs 低」 | 立不起「现象」这一环 |
有没有随访信息(time / event) | 预后分析必须要生存数据 | 做不了 KM / Cox,重要性无从谈起 |
| 样本量够不够 | 太小则差异、预后都不稳 | 结论偶然性大,验证集易翻车 |
| 有没有配套临床信息 | 分期、年龄用于多因素校正 | 无法排除混杂,说服力打折 |
| 平台与注释是否清楚 | 关系到能否和其他集比较 | 合并 / 验证时对不齐 |
还有一条几乎决定成败的原则:至少准备两套数据——一套发现(discovery),一套验证(validation)。只在一套数据里好看的结论,说服力有限;能在独立数据集上重复出来,故事才真正立得住。公共数据里,常见组合是用一个 TCGA 队列做发现、另一个 GEO 数据集做验证。
数据从哪找、关键词怎么写、怎么判断一个 GEO 数据集能不能用,见 GEO 数据库检索入门。下载后怎么整理成「行基因、列样本」的规范矩阵加分组表,见 表达矩阵与分组表整理规范。
第三步:差异分析,立起「现象」这一环
链条第一环,是证明您的对象真的在两组间有差别——这是后面一切的地基。用哪个包取决于数据类型:RNA-seq 的 raw counts 用 DESeq2 或 edgeR,芯片或已经标准化的表达量用 limma。
以 DESeq2 为例,核心就几行:
library(DESeq2)
dds <- DESeqDataSetFromMatrix(countData = counts, # 行基因、列样本的 raw counts
colData = coldata, # 含分组列 condition
design = ~ condition)
dds <- DESeq(dds)
res <- results(dds, contrast = c("condition", "tumor", "normal"))
deg <- subset(as.data.frame(res),
padj < 0.05 & abs(log2FoldChange) > 1) # 阈值是常用惯例,非铁律
padj < 0.05 且 |log2FC| > 1(约 2 倍变化)是最常见的惯例、不是铁律:信号弱或样本少时可放宽到 |log2FC| > 0.585(1.5 倍),要按您的数据和领域调,并如实写出用了什么阈值。方法细节见 DESeq2 差异表达分析怎么做对;用哪个包更合适,见 edgeR、limma-voom、DESeq2 怎么选。
对讲故事来说,这一环要盯两件事:
- 您的目标基因在不在差异表里、方向对不对。如果假设说「高表达」,就该看到它
log2FoldChange > 0且padj显著。对不上,别硬掰,回头修假设。 - 配一张最直观的图。目标基因在两组的表达箱线图,或整体的火山图,是「现象」这一环最好懂的证据。火山图的标准画法见 火山图:差异基因可视化的标准做法。
第四步:预后,回答「这个差别重要吗」
有差异,不等于有意义。第二环要说明:这个差异和临床结局挂钩,所以值得看。做法是把样本按目标基因表达高低分两组,比生存。
分组最常用、也最好复现的切法是按表达量中位数:
library(survival)
library(survminer)
clin$group <- ifelse(expr["GENEX", ] > median(expr["GENEX", ]),
"high", "low") # 中位数切:简单、事先确定、易复现
fit <- survfit(Surv(time, event) ~ group, data = clin)
ggsurvplot(fit, data = clin, pval = TRUE, risk.table = TRUE)
几点要留心:
- 中位数是常用惯例、不是铁律。 它简单、事先确定、不看结局,最好复现。也有人用最佳截断(如
survminer::surv_cutpoint),但那是从结局里挑切点,天生偏向让 p 变小、容易高估显著性,用了务必如实说明并在验证集复核。 time与event的定义要交代清楚:随访时长的单位、结局是总生存(OS)还是无病生存(DFS)。这些是能不能复现的关键。- 想控制混杂,上多因素 Cox:把目标基因和分期、年龄一起放进
coxph,看它是不是独立于这些临床因素仍与预后相关。这一步能显著增强说服力。
cox <- coxph(Surv(time, event) ~ group + stage + age, data = clin)
summary(cox)$coefficients # 看 group 的 HR 与 p,判断是否独立预后因素
KM 曲线怎么读、log-rank 和中位生存怎么写,见 生存分析:KM 曲线与 log-rank 检验;Cox 的单 / 多因素做法见 Cox 回归:单因素与多因素。如果您的对象不是单个基因而是一组,想压成一个风险评分,见 预后 signature 与风险模型。
第五步:机制线索,回答「它可能怎么起作用」
前两环讲清了「有差异、且重要」,读者自然会追问:为什么? 第三环给的是机制线索——注意是「线索」不是「机制」,公共数据能提供的是相关性证据,不是通路被激活的直接证明。
两条最常用的路子,可择一或并用:
一、富集分析,看功能层面。 把样本按目标基因高 / 低表达重新分两组,做一次差异分析,再把差异基因拿去做 GO / KEGG 富集,看「目标基因高的样本」整体上哪些通路被带动:
library(clusterProfiler)
library(org.Hs.eg.db)
ego <- enrichGO(gene = entrez_of_deg, # 高低组之间的差异基因(转成 ENTREZID)
OrgDb = org.Hs.eg.db,
ont = "BP",
pAdjustMethod = "BH", # 多重检验校正,BH 最常用
pvalueCutoff = 0.05)
ORA 与 GSEA 怎么选、气泡图怎么读、怎么不过度解读,见 富集分析:GO / KEGG / GSEA。
二、免疫浸润,看微环境。 如果假设涉及免疫,就估计每个样本的免疫细胞构成(CIBERSORT、ssGSEA 等),再看目标基因表达和某类免疫细胞比例是否相关:
# immune 为免疫细胞浸润矩阵(行样本、列细胞类型),来自 CIBERSORT / ssGSEA
cor.test(as.numeric(expr["GENEX", ]),
immune[, "T cells CD8"],
method = "spearman") # 秩相关,对非正态更稳健
浸润怎么估、CIBERSORT 与 ssGSEA 的区别和坑,见 免疫浸润分析:CIBERSORT / ssGSEA。
这一环的措辞要格外克制。 相关只能说「相关」「提示」「可能」,不能写成「GENEX 抑制了 CD8 T 细胞浸润」——那是因果句,公共数据支撑不了。守住这条线,恰恰是让分析站得住的关键。
第六步:把三环扣成一条逻辑链
三环都跑完,最后一步是把它们并成一段自洽的话,而不是把三张图并排一贴。检验故事扣没扣紧,用一张「主张 — 证据 — 图」的对照表过一遍:
| 环节 | 主张(写进正文的一句) | 支撑证据 | 对应图 |
|---|---|---|---|
| 现象 | GENEX 在肿瘤中显著高表达 | padj、log2FC | 火山图 / 箱线图 |
| 重要性 | 高表达组总生存显著更差,且独立于分期 | log-rank p、Cox HR | KM 曲线 |
| 机制线索 | 高表达组富集于某通路,并与 CD8 T 浸润负相关 | 富集 padj、相关 r 与 p | 气泡图 / 相关图 |
每一行的「主张」串起来,就是一段合格的结果论述(数字请换成您自己的真实结果):
在发现队列中,
GENEX于肿瘤组织显著高表达(log2FC与padj达到阈值);按其表达中位数分组,高表达组总生存显著更差(log-rankp),多因素 Cox 提示该差异独立于肿瘤分期。进一步分析显示,高表达组富集于某通路,且GENEX表达与 CD8 T 细胞浸润呈负相关(Spearmanr、p)。上述结果在独立验证队列中方向一致,提示GENEX可能通过影响免疫微环境参与该病的不良预后,值得后续实验验证。
注意结尾落在「提示……值得后续实验验证」,而不是「证明」。这既是学术诚实,也让审稿人挑不出「过度解读」的毛病。
第七步:老实交代边界,故事才真站得住
零实验分析最大的软肋,是容易把「相关」讲成「因果」、把「一套数据好看」当成「普遍成立」。主动把边界写清楚,反而让结论更可信。至少交代四件事:
- 相关不是因果。 全篇是观察性、关联性证据,不能推断因果与调控方向,需实验(如敲低 / 过表达)验证。这句话该明明白白写进讨论。
- 独立验证是底线。 关键结论——尤其是预后——必须在没参与建模的独立数据集上复核,方向一致才算数。只在发现集里显著的,多半靠不住。
- 批次与平台差异。 跨数据集比较、合并前要留意批次效应,否则「差异」可能来自平台而非生物学。见 公共数据常见坑与避雷。
- 注释与研究偏倚。 热门基因、热门通路注释更全,天然更容易「中」;上榜未必等于在您的体系里最关键。
一句话原则:把公共数据分析当成「生成并支撑一个假设」的工具,而不是「盖章一个结论」的工具。它告诉您往哪看、给出多角度的旁证,真正的因果还得靠后续实验。
在平台上跑一遍
以上从选数据、差异、预后到免疫 / 机制这整条链,在百沐一下都不用写代码:上传表达矩阵、分组表和带 time / event 的临床表,用一句话说清您的假设——例如「先看 GENEX 在肿瘤与癌旁的差异,再按其表达中位数分高低组做 KM 和多因素 Cox,最后看它与免疫浸润的相关性,并在验证集复核」——组学智能体会按标准流程逐环分析、出图,并给出可复现的 R 代码;想换阈值、切点或验证方式,直接在对话里说明即可。上手见 组学智能体 · 使用指南 与 智能统计 · 使用指南。
相关
- GEO 数据库检索入门 —— 按问题找数据、判断一个数据集能不能用
- DESeq2 差异表达分析怎么做对 —— 立起「现象」这一环
- 预后 signature 与风险模型 —— 把一组基因压成能验证的风险评分
- 公共数据常见坑与避雷 —— 批次、验证、过度解读的通用避雷