跳转至

统计学习路线(生信方向)

面向2026届生信工程师面试 | 从描述统计到贝叶斯统计

为什么生信要学统计?(白话版)

生信不学统计,就像做饭不放盐——出来的东西没法吃。你跑完分析得到一堆数字,哪些是真正的差异,哪些是随机波动?全靠统计来判断。面试官最爱问:"你这个结果可靠吗?怎么证明?"——答案就是统计。

一句话总结:统计学决定了你的分析结果是"科学发现"还是"随机噪声"。


阶段一:描述统计(1周)

目标:能用数字和图形描述数据的基本特征

1.1 集中趋势

# === 均值、中位数、众数 ===
expression <- c(2.3, 5.1, 3.8, 45.2, 4.5, 3.9, 5.0, 4.2)  # 基因表达量

mean(expression)     # 均值:9.25(被离群值45.2拉高了!)
median(expression)   # 中位数:4.35(不受离群值影响,更"靠谱")

# 白话解释:
# 均值 = 所有数加起来除以个数(容易被极端值带偏)
# 中位数 = 排好序后最中间的数(对离群值免疫)
# 生信中:表达量数据通常右偏(少数基因极高表达),所以常看中位数

1.2 离散程度

# === 方差、标准差、四分位距 ===
var(expression)      # 方差:样本方差(偏差的平方的平均)
sd(expression)       # 标准差:方差开根号(和原数据同单位)
IQR(expression)      # 四分位距:Q3-Q1(中间50%数据的范围)

# 白话解释:
# 方差/标准差 = 数据有多"散"(越大越散)
# 标准差的好处 = 单位和原数据一样(方差的单位是"平方",不直观)
# IQR = 不受离群值影响的"散度"指标

# === CV(变异系数)—— 比较不同量纲数据的离散度 ===
cv <- sd(expression) / mean(expression) * 100  # CV = 标准差/均值 × 100%
# 白话:相对于均值,数据波动了百分之多少
# 生信中:CV常用来评估技术重复之间的一致性

1.3 数据分布

# === 正态分布(高斯分布)===
# 白话:大部分数据集中在中间,越往两边越少,像一口钟
# 性质:均值±1SD包含68%数据,±2SD包含95%,±3SD包含99.7%

# 检验数据是否正态分布
shapiro.test(expression)    # Shapiro-Wilk检验(p>0.05表示不拒绝正态假设)

# === log转换 ===
# 生信中基因表达数据通常是右偏的(少数基因表达量极高)
# log转换后更接近正态分布,更适合做统计检验
log2_expr <- log2(expression + 1)  # +1避免log(0)

# === 可视化分布 ===
par(mfrow = c(1, 2))               # 一行两列画图
hist(expression, main = "原始数据", breaks = 20)      # 直方图
hist(log2_expr, main = "log2转换后", breaks = 20)     # log2后的直方图

# QQ图(判断正态性的可视化方法)
qqnorm(log2_expr)       # 画QQ图
qqline(log2_expr)       # 加参考线(点在线上 = 接近正态)

阶段二:假设检验(2周)

目标:掌握 p 值的含义,能选择正确的检验方法

2.1 假设检验基础

# === 核心概念 ===
# H0(零假设):两组没差异("无罪推定")
# H1(备择假设):两组有差异("有罪")
# p值:在H0成立的情况下,观察到当前结果(或更极端)的概率
# p < 0.05:拒绝H0,认为差异"统计显著"
# p >= 0.05:不能拒绝H0(注意:不是"证明没差异"!)

# 白话类比:
# 你怀疑硬币被动了手脚(H1),H0是"硬币公平"
# 你扔了100次,正面90次,这个概率极低(p非常小)
# 所以你拒绝"硬币公平"的假设,认为硬币有问题

# === 两类错误 ===
# I类错误(假阳性):实际没差异,你说有差异(冤枉好人)
# II类错误(假阴性):实际有差异,你说没差异(放过坏人)
# alpha(显著性水平):允许的I类错误率,通常0.05
# beta:II类错误率
# power(统计功效)= 1 - beta:检测到真实差异的能力

2.2 常用检验方法

# === t检验(比较两组均值)===
# 前提:数据近似正态分布,方差齐性
wt_expr <- c(12.3, 15.6, 14.1, 13.8, 15.2)    # WT组表达量
ko_expr <- c(3.2, 2.8, 4.1, 3.5, 2.9)          # KO组表达量

# 独立样本t检验(两组独立样本)
t.test(wt_expr, ko_expr)
# 白话:比较WT和KO的平均表达量是否有显著差异

# 配对t检验(同一样本处理前后)
t.test(before, after, paired = TRUE)

# === Wilcoxon检验(非参数,不要求正态分布)===
# 白话:数据不是正态分布时,用这个代替t检验
wilcox.test(wt_expr, ko_expr)
# 生信中:样本量小或数据明显偏斜时,优先用非参数检验

# === 卡方检验(比较比例/频数)===
# 例:某突变在病人和正常人中的出现频率是否不同?
observed <- matrix(c(30, 70, 10, 90), nrow = 2)  # 2x2列联表
# 病人组:30有突变,70无突变
# 正常组:10有突变,90无突变
chisq.test(observed)

# === Fisher精确检验(小样本时代替卡方检验)===
fisher.test(observed)
# 白话:样本少的时候卡方检验不准,用Fisher更靠谱

# === ANOVA(方差分析,比较3组及以上的均值)===
# 白话:t检验只能比两组,ANOVA能比多组
group <- factor(c(rep("A", 5), rep("B", 5), rep("C", 5)))  # 3组
values <- c(rnorm(5, 10), rnorm(5, 12), rnorm(5, 15))      # 模拟数据
anova_result <- aov(values ~ group)
summary(anova_result)

# 事后检验(ANOVA显著后,看具体哪两组之间有差异)
TukeyHSD(anova_result)

2.3 选择检验方法的决策树

你要比较什么?
├── 两组均值
│   ├── 数据正态? → 是 → t检验(独立/配对)
│   └── 数据不正态? → Wilcoxon检验
├── 三组及以上均值
│   ├── 数据正态? → 是 → ANOVA + 事后检验
│   └── 数据不正态? → Kruskal-Wallis检验
├── 比例/频数
│   ├── 样本量大? → 卡方检验
│   └── 样本量小? → Fisher精确检验
└── 两变量相关性
    ├── 线性关系? → Pearson相关
    └── 非线性/有序? → Spearman相关

阶段三:多重检验校正(1-2周)

目标:理解为什么差异分析必须做多重检验校正,面试高频!

3.1 多重检验问题

# === 为什么需要校正? ===
# 白话类比:
# 你扔1次硬币,出现正面的概率是50%
# 你扔20次硬币,至少有1次正面的概率是 1 - 0.5^20 ≈ 99.9999%

# 生信中的问题:
# 基因组有 20000 个基因,每个都做一次假设检验
# 即使所有基因都没差异,alpha=0.05 也会有 20000 × 0.05 = 1000 个假阳性!
# 这就叫"多重检验问题"

# === Bonferroni 校正(最严格)===
p_values <- c(0.001, 0.01, 0.03, 0.04, 0.06, 0.10)  # 6个p值
p_bonferroni <- p.adjust(p_values, method = "bonferroni")
# 原理:每个p值乘以检验次数(n=6)
# 0.001 × 6 = 0.006 < 0.05 → 显著
# 0.01 × 6 = 0.06 > 0.05 → 不显著了!
# 缺点:太严格了,很多真正的差异也会被"冤枉"

# === BH校正(Benjamini-Hochberg,生信最常用!)===
p_bh <- p.adjust(p_values, method = "BH")
# 原理:控制的是FDR(False Discovery Rate,假发现率)
# FDR = 在你报告的"显著"结果中,预期有多少比例是假阳性
# padj < 0.05 意味着:你报告的显著基因中,最多5%是假的

# === 对比 ===
comparison <- data.frame(
  p_value = p_values,
  Bonferroni = p_bonferroni,
  BH_FDR = p_bh
)
print(comparison)
# 可以看到:BH校正比Bonferroni宽松,保留更多真阳性

3.2 FDR 的直觉理解

# === 白话版 FDR ===
# 场景:你做了差异分析,发现200个"显著"基因
# p_adj < 0.05(FDR < 5%)意味着:
# 这200个基因中,大约 200 × 0.05 = 10 个可能是假阳性
# 其他 190 个大概率是真正的差异基因

# === 面试常问:p-value 和 adjusted p-value 的区别?===
# p-value:单个检验的显著性(只考虑这一个基因)
# adjusted p-value(padj/FDR):考虑了你同时做了几万次检验后的校正值
# 生信差异分析中,必须看 padj,不能只看 p-value!

# === q-value(另一种FDR衡量方式)===
# q-value ≈ BH adjusted p-value
# 生信论文中 q-value 和 padj 经常互换使用
# DESeq2 输出的 padj 就是 BH 校正后的 p 值

阶段四:回归分析(2周)

目标:理解线性回归和逻辑回归,能在生信中正确使用

4.1 线性回归

# === 简单线性回归 ===
# 白话:找一条直线,最好地描述x和y的关系
# 例:基因表达量 vs 药物浓度
drug_dose <- c(0, 0.1, 0.5, 1, 2, 5, 10)        # 药物浓度
gene_expr <- c(1.2, 1.5, 2.3, 3.1, 4.8, 8.2, 12.5)  # 基因表达量

model <- lm(gene_expr ~ drug_dose)   # lm = linear model
summary(model)
# 关键输出:
# Coefficients: 截距(Intercept)和斜率(drug_dose)
# R-squared: 决定系数,0-1之间,越接近1拟合越好
# p-value: 斜率是否显著不为0

# === 多元线性回归 ===
# 白话:多个因素同时影响结果
# 例:表达量 = β0 + β1×年龄 + β2×BMI + β3×性别
model_multi <- lm(expression ~ age + BMI + sex, data = clinical_df)
summary(model_multi)

# === 生信应用:批次效应校正 ===
# 用线性模型把批次效应从表达数据中"减掉"
library(limma)
# 设计矩阵:包含感兴趣的变量(condition)和要去掉的变量(batch)
design <- model.matrix(~ condition + batch, data = sample_info)
# removeBatchEffect 去除批次效应
corrected_expr <- removeBatchEffect(expr_matrix, batch = sample_info$batch)

4.2 逻辑回归

# === 逻辑回归(用于二分类问题)===
# 白话:预测"是/否"类结果的概率
# 例:根据微生物组特征预测是否患有T2D

model_logistic <- glm(
  disease ~ Bacteroides + Prevotella + Faecalibacterium,
  data = microbiome_df,
  family = binomial    # binomial = 二分类(逻辑回归)
)
summary(model_logistic)
# 关键输出:
# Coefficients: 每个特征的系数(正=增加患病风险,负=降低)
# Odds Ratio = exp(coefficient):优势比
# 例:exp(0.5) = 1.65,表示该菌每增加1单位,患病几率增加65%

# 预测
probabilities <- predict(model_logistic, newdata = test_df, type = "response")
predictions <- ifelse(probabilities > 0.5, "T2D", "Control")

# === 面试:线性回归 vs 逻辑回归 ===
# 线性回归:预测连续值(表达量、浓度)
# 逻辑回归:预测分类结果(患病/健康、响应/不响应)

阶段五:生存分析(1-2周)

目标:理解 KM 曲线和 Cox 回归,能解读临床生信结果

5.1 Kaplan-Meier 生存分析

library(survival)     # 生存分析核心包
library(survminer)    # 好看的生存曲线

# === KM生存分析 ===
# 白话:比较两组病人"谁活得更久"
# time: 随访时间(月)
# status: 是否发生事件(1=死亡, 0=存活/失访)
# group: 分组(如基因高表达 vs 低表达)

surv_obj <- Surv(time = clinical$time, event = clinical$status)  # 创建生存对象

# KM拟合
fit <- survfit(surv_obj ~ group, data = clinical)

# 画KM曲线
ggsurvplot(
  fit,
  data = clinical,
  pval = TRUE,                    # 显示log-rank检验p值
  conf.int = TRUE,                # 显示置信区间
  risk.table = TRUE,              # 显示风险表
  palette = c("#E41A1C", "#377EB8"),  # 自定义颜色
  xlab = "Time (months)",
  ylab = "Survival probability",
  title = "Overall Survival by Gene Expression"
)

# === 中位生存时间 ===
print(fit)  # 输出中包含 median survival time

5.2 Cox 回归

# === Cox比例风险模型 ===
# 白话:分析哪些因素影响生存时间,每个因素的"风险比"是多少
cox_model <- coxph(
  Surv(time, status) ~ age + stage + gene_expr_high,
  data = clinical
)
summary(cox_model)
# 关键输出:
# HR (Hazard Ratio):风险比
# HR > 1: 增加死亡风险(危险因素)
# HR < 1: 降低死亡风险(保护因素)
# HR = 1: 无影响
# 例:HR = 2.5 表示该因素使死亡风险增加150%

# 森林图(展示多个变量的HR)
ggforest(cox_model, data = clinical)

阶段六:贝叶斯统计入门(1-2周)

目标:理解贝叶斯思维,了解在生信中的应用

6.1 贝叶斯基础

# === 贝叶斯定理(白话版)===
# P(A|B) = P(B|A) × P(A) / P(B)

# 白话类比:
# 你做了一个基因检测,结果显示"阳性"
# 这个检测的灵敏度(真阳性率)= 95%
# 特异度(真阴性率)= 90%
# 人群中这个病的发病率 = 1%

# 问:检测阳性,你真的有病的概率是多少?

sensitivity <- 0.95     # 灵敏度:有病检出阳性的概率
specificity <- 0.90     # 特异度:没病检出阴性的概率
prevalence <- 0.01      # 发病率

# 贝叶斯计算
p_positive <- sensitivity * prevalence +     # 真阳性
              (1 - specificity) * (1 - prevalence)  # 假阳性
ppv <- (sensitivity * prevalence) / p_positive  # 阳性预测值

cat(sprintf("检测阳性后真的有病的概率: %.1f%%\n", ppv * 100))
# 结果约:8.8%!(远低于直觉的95%!)
# 原因:发病率太低,大部分阳性都是假阳性

# === 生信中的贝叶斯应用 ===
# 1. DESeq2 内部:用贝叶斯收缩(shrinkage)估计log2FC
#    - 低表达/高方差的基因,FC被"拉"向0(更保守)
# 2. 系统发育分析:MrBayes 用贝叶斯方法推断进化树
# 3. 变异检测:GATK 用贝叶斯模型判断真突变 vs 测序错误
# 4. 宏基因组:Kraken2 用贝叶斯分类器对reads分类

6.2 先验和后验的直觉

# === 白话理解 ===
# 先验(Prior):你在看到数据之前的"预判"
# 似然(Likelihood):数据支持各个假设的程度
# 后验(Posterior):综合先验和数据后的"更新判断"

# 后验 ∝ 先验 × 似然
# 白话:你原来的想法 + 新看到的证据 → 更新后的想法

# === 例子:DESeq2 的 shrinkage ===
# 先验:大部分基因不会有巨大的表达变化
# 数据:某个低表达基因看起来FC=10(但可能只是测了3个reads变成30个)
# 后验:考虑到低表达高方差,把FC收缩为更保守的估计

# 这就是为什么 DESeq2 的 lfcShrink() 比原始 log2FC 更可靠

面试速查表

统计基础高频问题

问题答案要点
p值到底是什么?假设H0成立时,观察到当前结果(或更极端)的概率。不是"H0为真的概率"!
p < 0.05 就一定有生物学意义吗?不一定。统计显著 ≠ 生物学显著。效应量(如FC)同样重要
I类错误和II类错误?I类=假阳性(说有差异但实际没有),II类=假阴性(说没差异但实际有)
统计功效是什么?1 - beta = 检测到真实差异的能力,通常要求 ≥ 0.8
参数检验和非参数检验区别?参数检验假设数据分布(如正态),非参数不假设(更稳健但功效略低)

多重检验高频问题

问题答案要点
为什么要多重检验校正?同时检验几万个基因,不校正会有大量假阳性
Bonferroni 和 BH 的区别?Bonferroni控制FWER(更严格),BH控制FDR(更宽松,生信常用)
FDR = 0.05 是什么意思?在你报告的显著结果中,预期最多5%是假阳性
DESeq2 用什么校正?BH校正,输出的padj就是FDR

回归分析高频问题

问题答案要点
R-squared 是什么?模型能解释的因变量变异比例,0-1之间,越接近1越好
逻辑回归的 Odds Ratio?OR=1无影响,OR>1增加风险,OR<1降低风险
多重共线性问题?自变量之间高度相关导致系数不稳定,用VIF检测(VIF>10需警惕)

检验方法选择速查

数据类型两组比较多组比较相关性
正态连续t检验ANOVAPearson
非正态连续WilcoxonKruskal-WallisSpearman
分类数据卡方/Fisher卡方
生存数据log-ranklog-rankCox回归

学习路线时间表

阶段内容时间验证标准
描述统计均值/中位数/标准差/分布1周能描述数据分布特征
假设检验t检验/卡方/ANOVA2周能选择正确的检验方法
多重检验Bonferroni/BH/FDR1-2周能解释padj的含义
回归分析线性/逻辑回归2周能做简单的回归分析
生存分析KM曲线/Cox回归1-2周能画生存曲线并解读
贝叶斯入门先验/后验/生信应用1-2周能解释DESeq2的shrinkage

推荐学习资源(2025-2026最新)

资源类型推荐指数
StatQuest (YouTube Josh Starmer)视频讲解必看(PCA视频看20遍都不嫌多)
Modern Statistics for Modern Biology免费在线书生物统计最佳
Discovering Statistics with R有趣易懂的统计入门
An Introduction to Statistical Learning免费在线书统计学习经典(有R和Python版)
Khan Academy Statistics免费视频基础补课
Data Analysis for Life Sciences在线课程生科统计实战
3Blue1Brown 概率统计 (YouTube)可视化讲解直觉理解

最后更新:2026-05 | 适用于2026届生信工程师面试准备