跳转至

多组学因子分析MOFA

一句话概述

使用MOFA+(Multi-Omics Factor Analysis)和MCIA等方法对多组学数据(转录组、蛋白组、甲基化组等)进行联合降维与因子分析,发现跨组学共享的生物学变异模式。


核心知识点总览

知识点关键内容重要程度
MOFA+模型原理贝叶斯因子分析/稀疏先验/ARD⭐⭐⭐⭐⭐
多组学数据准备各组学标准化/缺失值处理/特征选择⭐⭐⭐⭐⭐
因子解释因子-组学关联/权重分析/功能富集⭐⭐⭐⭐⭐
MCIA方法多重共惯量分析/组学整合⭐⭐⭐⭐
多组/时间序列MOFA+支持多组/时间点设计⭐⭐⭐⭐
方差分解各因子在各组学中解释的方差比例⭐⭐⭐⭐
下游分析因子与表型关联/生存分析⭐⭐⭐
与其他方法比较MOFA vs iCluster vs JIVE vs intNMF⭐⭐⭐

各步骤详解

第一步:理解多组学整合的动机与挑战

白话解释: 现代生物医学研究中,我们常对同一批样本测量多个层面的数据——基因表达(转录组)、蛋白丰度(蛋白组)、DNA甲基化(表观基因组)等。每种组学都只看到了"大象的一部分",将它们整合在一起才能看到"完整的大象"。但不同组学的数据类型、量纲、噪声特征各不相同,直接拼接不可行,需要用专门的数学模型来提取跨组学的共同变异模式。

技术细节: 多组学整合的核心挑战: 1. 异质性:不同组学数据量纲不同(如counts vs methylation beta值) 2. 维度差异:特征数差异巨大(如2万基因 vs 50万CpG位点) 3. 缺失数据:不是所有样本都有所有组学数据 4. 非对称关联:某些变异模式可能只在部分组学中存在

MOFA+通过贝叶斯因子模型优雅地解决这些问题:假设数据可以分解为少量隐含因子(latent factors),每个因子在不同组学中有不同的权重(weights/loadings),从而实现降维和跨组学特征提取。

# 多组学整合方法分类
# 1. 早期整合(Early integration):拼接特征矩阵后降维
# 2. 晚期整合(Late integration):各组学独立分析后合并结果
# 3. 中间整合(Intermediate integration):联合建模 — MOFA属于此类

# MOFA+模型的数学表达
# Y_m = W_m × Z^T + ε_m
# Y_m: 第m个组学的数据矩阵 (features × samples)
# W_m: 第m个组学的权重矩阵 (features × factors)
# Z:   因子矩阵 (samples × factors),跨组学共享
# ε_m: 噪声

第二步:数据准备与标准化

白话解释: 在送入MOFA之前,每种组学数据需要单独做适当的预处理和标准化。就像把不同语言翻译成同一种语言才能交流一样,需要把不同组学数据"翻译"到可比较的尺度上。

技术细节: 各组学推荐的预处理方式: - RNA-seq:log2(CPM+1)或variance stabilizing transformation (VST) - 蛋白组:log2转换,批次校正 - 甲基化:M值(log2(beta/(1-beta)))比beta值更适合统计分析 - ATAC-seq:log2(normalized counts+1)

特征选择:只保留高变异特征(如top 5000最可变基因),减少噪声和计算量。

# === 数据准备示例 ===
library(MOFA2)

# 模拟三组学数据准备
# 1. RNA-seq数据(已为log2 CPM)
rna_data <- read.csv("rna_log2cpm.csv", row.names = 1)
# 取top 5000高变异基因
rna_var <- apply(rna_data, 1, var)
rna_top <- rna_data[names(sort(rna_var, decreasing = TRUE)[1:5000]), ]

# 2. 蛋白组数据(已为log2强度)
prot_data <- read.csv("protein_log2.csv", row.names = 1)
# 去除缺失>50%的蛋白
prot_missing <- rowMeans(is.na(prot_data))
prot_filtered <- prot_data[prot_missing < 0.5, ]

# 3. 甲基化数据(转为M值)
meth_beta <- read.csv("methylation_beta.csv", row.names = 1)
meth_m <- log2(meth_beta / (1 - meth_beta))
# 取top 5000高变异CpG
meth_var <- apply(meth_m, 1, var, na.rm = TRUE)
meth_top <- meth_m[names(sort(meth_var, decreasing = TRUE)[1:5000]), ]

# 确保样本ID一致
common_samples <- Reduce(intersect, list(
  colnames(rna_top),
  colnames(prot_filtered),
  colnames(meth_top)
))

# 中心化(每个特征减去均值)
rna_centered <- t(scale(t(rna_top[, common_samples]), center = TRUE, scale = FALSE))
prot_centered <- t(scale(t(prot_filtered[, common_samples]), center = TRUE, scale = FALSE))
meth_centered <- t(scale(t(meth_top[, common_samples]), center = TRUE, scale = FALSE))

# 创建数据列表
data_list <- list(
  RNA = as.matrix(rna_centered),
  Protein = as.matrix(prot_centered),
  Methylation = as.matrix(meth_centered)
)

第三步:MOFA+模型训练

白话解释: MOFA+用一种叫做"变分推断"的算法来训练模型。它会自动学习数据中的隐含因子——你可以把因子想象成"主题",就像一堆文章可以归纳出几个主题一样,多组学数据也可以归纳出几个主要的变异模式(因子)。

技术细节: MOFA+使用自动相关性确定(ARD, Automatic Relevance Determination)先验来自动学习每个因子在每个组学中是否活跃。如果某因子对某组学的方差贡献为零,ARD会自动"关闭"该因子在该组学中的权重,实现因子的组学特异性解释。

# === MOFA+ 模型构建与训练 ===
library(MOFA2)

# 创建MOFA对象
mofa <- create_mofa(data_list)

# 查看数据概况
print(mofa)
plot_data_overview(mofa)

# 设置数据选项
data_opts <- get_default_data_options(mofa)
data_opts$scale_views <- TRUE  # 是否对各组学做方差缩放
# TRUE: 各组学等权重贡献;FALSE: 高方差组学贡献更大

# 设置模型选项
model_opts <- get_default_model_options(mofa)
model_opts$num_factors <- 15  # 初始因子数(会自动删减非活跃因子)
model_opts$likelihoods <- c("gaussian", "gaussian", "gaussian")
# 可选: gaussian(连续), poisson(count), bernoulli(二元)

# 设置训练选项
train_opts <- get_default_training_options(mofa)
train_opts$convergence_mode <- "slow"  # slow更精确,fast更快
train_opts$maxiter <- 1000
train_opts$seed <- 42
train_opts$gpu_mode <- FALSE  # 有GPU则设为TRUE

# 训练模型
mofa <- prepare_mofa(
  mofa,
  data_options = data_opts,
  model_options = model_opts,
  training_options = train_opts
)

# 使用Python后端训练(需要mofapy2)
mofa <- run_mofa(mofa, outfile = "mofa_model.hdf5", use_basilisk = TRUE)

第四步:因子解读与方差分解

白话解释: 模型训练完成后,最关键的步骤是解读每个因子代表什么生物学意义。首先看方差分解——每个因子在各组学中解释了多少方差。如果某因子在所有组学中都有贡献,说明它代表一种跨组学的共同变异模式;如果只在某个组学中有贡献,说明它是该组学特有的变异。

技术细节:

# === 模型质量评估 ===

# 方差分解
plot_variance_explained(mofa, max_r2 = 15)
plot_variance_explained(mofa, plot_total = TRUE)  # 各因子总方差

# 查看因子值分布
plot_factor(mofa, factor = 1, color_by = "group_label")

# 因子间相关性(应该接近零)
plot_factor_cor(mofa)

# === 因子权重(Weights)分析 ===

# 各组学中每个因子的top权重特征
plot_weights(mofa, view = "RNA", factor = 1, nfeatures = 20, scale = TRUE)
plot_weights(mofa, view = "Protein", factor = 1, nfeatures = 20, scale = TRUE)

# 权重热图
plot_top_weights(mofa, view = "RNA", factor = 1, nfeatures = 30)

# 提取权重矩阵
weights <- get_weights(mofa, views = "all", factors = "all", as.data.frame = TRUE)

# 提取因子值
factors <- get_factors(mofa, factors = "all", as.data.frame = TRUE)

# === 因子-特征数据热图 ===
plot_data_heatmap(mofa, view = "RNA", factor = 1,
                   features = 50, cluster_rows = TRUE,
                   show_rownames = FALSE, annotation_samples = "group_label")

第五步:因子的功能注释与生物学解释

白话解释: 知道了每个因子包含哪些基因/蛋白/CpG位点后,需要做功能富集分析来理解其生物学意义。比如Factor 1的RNA权重集中在免疫相关基因,蛋白权重集中在炎症蛋白,甲基化权重集中在启动子区域——那Factor 1可能代表"炎症/免疫激活"这个生物学过程。

技术细节:

# === 功能富集分析 ===
library(MOFA2)

# GSEA富集(需要msigdbr或自定义基因集)
library(msigdbr)

# 获取Hallmark基因集
hallmark <- msigdbr(species = "Homo sapiens", category = "H") %>%
  dplyr::select(gs_name, gene_symbol) %>%
  as.data.frame()

# MOFA内置的GSEA
enrichment_results <- run_enrichment(mofa,
  view = "RNA",
  feature.sets = hallmark,
  sign = "all",  # all, positive, negative
  statistical.test = "parametric"
)

# 富集结果可视化
plot_enrichment(enrichment_results, factor = 1, max.pathways = 15)
plot_enrichment_heatmap(enrichment_results)

# === 因子与临床表型关联 ===
# 添加样本元数据
samples_metadata(mofa) <- merge(
  samples_metadata(mofa),
  clinical_data,
  by.x = "sample", by.y = "sample_id"
)

# 因子与连续变量关联
plot_factor(mofa, factor = 1, color_by = "age", add_violin = FALSE,
            dodge = TRUE)

# 因子与分类变量关联
plot_factor(mofa, factor = 1, color_by = "tumor_stage",
            dodge = TRUE, add_violin = TRUE)

# 因子与生存分析
library(survival)
library(survminer)

factors_df <- get_factors(mofa, as.data.frame = TRUE) %>%
  tidyr::spread(factor, value)

surv_data <- merge(factors_df, clinical_data, by.x = "sample", by.y = "sample_id")
surv_data$Factor1_group <- ifelse(surv_data$Factor1 > median(surv_data$Factor1),
                                   "High", "Low")

fit <- survfit(Surv(OS_time, OS_status) ~ Factor1_group, data = surv_data)
ggsurvplot(fit, data = surv_data, pval = TRUE, risk.table = TRUE)

第六步:MCIA多重共惯量分析

白话解释: MCIA(Multiple Co-Inertia Analysis)是另一种多组学整合方法,来自生态学的统计学思想。如果MOFA是"找共同主题",MCIA则更像是"找共同趋势"——它寻找不同组学数据之间最大化协方差的方向,从而揭示组学间的一致性变异模式。

技术细节: MCIA首先对每个数据集独立做对应分析或PCA,然后通过共惯量分析找到最优的公共空间。与MOFA不同,MCIA是频率学派方法,不需要指定先验分布,计算速度更快。

# === MCIA 分析流程 ===
library(omicade4)

# 准备数据列表(每个元素为基因×样本矩阵)
data_mcia <- list(
  RNA = as.data.frame(rna_centered),
  Protein = as.data.frame(prot_centered),
  Methylation = as.data.frame(meth_centered)
)

# 运行MCIA
mcia_result <- mcia(data_mcia, cia.nf = 10)

# 查看各轴解释的方差
plot(mcia_result$mcoa, what = "eigenvalues")

# 样本空间投影(整合视图)
plot(mcia_result, axes = c(1, 2), phenovec = group_labels,
     sample.lab = FALSE)

# 各组学的一致性评估(RV系数)
# RV系数衡量两个数据集之间的全局相似性,值越高越一致
mcia_result$mcoa$RV

# 提取MCIA得分(类似因子值)
mcia_scores <- mcia_result$mcoa$SynVar  # 综合变量得分

第七步:MOFA+多组设计与时间序列分析

白话解释: MOFA+的一大优势是支持多组(multi-group)设计,比如"多个时间点"或"多个疾病亚型"。它可以学习哪些变异模式在所有组中共享,哪些是某些组特有的。重要注意:多组框架的目的不是捕捉组间均值差异(那是差异表达分析的任务),而是比较驱动各组变异的来源。如果你的目标是找到"区分组的因子",不应使用多组框架,而应将所有样本放在同一组中训练。多组框架下,特征会在每个组内分别中心化。

技术细节:

# === MOFA+ 多组设计 ===

# 准备多组数据(关键:用groups参数指定分组,而非嵌套列表)
# 假设有两个时间点的多组学数据,样本名分别带有T1/T2前缀
# 方法1:用矩阵列表 + groups向量
data_list_views <- list(
  RNA = rbind(rna_data_T1, rna_data_T2),        # 合并两个时间点
  Protein = rbind(prot_data_T1, prot_data_T2)
)
# groups向量:每个样本属于哪个组
groups <- c(rep("Timepoint1", ncol(rna_data_T1)),
            rep("Timepoint2", ncol(rna_data_T2)))

# 创建多组MOFA对象(通过groups参数传入分组信息)
mofa_multi <- create_mofa(data_list_views, groups = groups)

# 方法2:用长格式data.frame(含group列)
# df_long <- data.frame(sample, feature, view, group, value)
# mofa_multi <- create_mofa(df_long)

# 训练(同上设置)
mofa_multi <- prepare_mofa(mofa_multi,
  data_options = data_opts,
  model_options = model_opts,
  training_options = train_opts)
mofa_multi <- run_mofa(mofa_multi)

# 比较因子在不同组中的方差贡献
plot_variance_explained(mofa_multi, split_by = "group")

# 查看因子值在不同组中的分布
plot_factor(mofa_multi, factor = 1, color_by = "group",
            dodge = TRUE, add_violin = TRUE)

# 注意:compare_factors()用于比较不同MOFA模型间的因子相关性,
# 而非同一模型内的组间比较。组间比较应通过plot_factor()可视化
# 或提取因子值后用统计检验(如Wilcoxon test)进行

# 组特异性因子识别:查看各因子在各组各组学中的方差贡献
plot_variance_explained(mofa_multi, split_by = "group")

实战命令速查

# === 安装 ===
# R包
# install.packages("BiocManager")
# BiocManager::install("MOFA2")
# BiocManager::install("omicade4")

# Python后端
pip install mofapy2

# === 常用R函数速查 ===
# create_mofa()                    # 创建MOFA对象
# prepare_mofa()                   # 设置参数
# run_mofa()                       # 训练模型
# plot_data_overview()             # 数据概览
# plot_variance_explained()        # 方差分解
# get_factors() / get_weights()    # 提取结果
# plot_weights() / plot_top_weights()  # 权重可视化
# run_enrichment()                 # GSEA富集分析
# plot_factor() / plot_factors()   # 因子可视化

面试常问点

Q1: MOFA+的数学原理是什么?

A: MOFA+是一个贝叶斯因子模型。假设每个组学的数据矩阵Y_m可以分解为因子矩阵Z(样本×因子,跨组学共享)和权重矩阵W_m(特征×因子,组学特异)的乘积加噪声。使用稀疏先验(spike-and-slab或ARD)约束权重矩阵,使得每个因子只关联少数特征,便于解释。通过变分推断(variational inference)近似后验分布来学习参数。

Q2: MOFA+中因子数如何选择?

A: 实际操作中,建议设置较大的初始因子数(如15-25),MOFA+会通过ARD先验自动删减方差贡献极低的因子。训练完成后,保留解释方差>1%的因子。也可以通过交叉验证评估预测误差来选择最优因子数。

Q3: MOFA+如何处理缺失数据?

A: MOFA+天然支持缺失数据——不要求所有样本都有所有组学。缺失值在似然函数中被简单忽略(marginal likelihood),不会影响其他观测值的推断。这使得MOFA+非常适合真实世界中组学不完整的多组学数据集。

Q4: MOFA+与iCluster/intNMF等方法有什么区别?

A: iCluster侧重于发现样本聚类(分型),使用联合潜变量模型;intNMF通过非负矩阵分解实现整合,要求数据非负。MOFA+的优势在于:(1) 贝叶斯框架自动因子选择和不确定性估计;(2) 稀疏先验使因子更易解释;(3) 天然支持缺失数据和多组设计;(4) 提供完善的R包和下游分析工具。

Q5: 各组学数据是否需要scale到相同尺度?

A: 可以通过scale_views = TRUE选项让MOFA+内部对各组学进行方差缩放,使各组学贡献均等。如果不缩放,高方差的组学会主导因子学习。具体选择取决于研究问题:如果各组学同等重要则scale,如果认为某组学信号更强则不scale。

Q6: MOFA+与PCA/MFA的区别?

A: PCA是单数据集降维。MFA(Multiple Factor Analysis)对多数据集做加权PCA,但缺乏稀疏性和贝叶斯推断。MOFA+的因子是稀疏的(每个因子只关联少数特征),有组学特异的ARD先验,支持缺失数据和非高斯似然。MOFA+的因子在生物学上更易解释。


易错点

1. 输入数据未中心化

MOFA+要求输入数据每个特征中心化(均值为零)。如果不中心化,模型的第一个因子会捕捉均值差异而非有意义的变异。使用prepare_mofa时设置center_groups = TRUE

2. 特征选择不当导致过拟合

使用全部特征(如45万CpG位点)会导致计算慢且噪声主导因子。应进行高变异特征选择(如top 2000-5000),但选择标准应在MOFA训练之前独立于结果确定(避免circular selection)。

3. 组学间样本不匹配

不同组学的样本ID格式不一致(如RNA-seq用"TCGA-A1-A0SK-01"而蛋白组用"TCGA.A1.A0SK.01"),导致MOFA认为没有配对样本。务必统一样本命名。

4. 因子解释的主观性

因子的生物学解释依赖于富集分析和领域知识,具有一定主观性。不同的基因集数据库、统计检验方法可能给出不同的解释。建议使用多个数据库交叉验证。

5. 忽略似然函数类型选择

对count数据使用高斯似然,或对二元数据使用高斯似然,会影响模型拟合。RNA-seq原始counts应使用Poisson似然(或先VST变换后用高斯),甲基化beta值可用高斯或beta似然。

6. 模型未收敛

训练迭代次数不够或收敛阈值过松导致模型未收敛。应检查ELBO(Evidence Lower Bound)曲线是否平稳,必要时增加maxiter或使用"slow"收敛模式。


补充知识

其他多组学整合方法

  • JIVE (Joint and Individual Variation Explained):将变异分解为联合和个体部分
  • DIABLO (Data Integration Analysis for Biomarker discovery using Latent cOmponents):mixOmics包中的有监督多组学整合
  • SNF (Similarity Network Fusion):基于网络融合的整合方法
  • MINT:mixOmics中的多组学独立样本整合

MEFISTO(时空多组学整合)

MEFISTO是MOFA2中的时空扩展框架,可在因子分析中纳入样本的时间或空间信息: - 学习沿时间/空间平滑变化的因子 - 支持插值和外推(预测未测量时间点/空间位置的因子值) - 要求MOFA2 >= 1.1.4 和 mofapy2 >= 0.5.8

单细胞多组学整合

MOFA+支持单细胞多组学数据(如CITE-seq: RNA+蛋白, SHARE-seq: RNA+ATAC)。单细胞版MOFA的特殊考量: - 数据更稀疏,需要更强的稀疏先验 - 细胞数远大于bulk,计算效率需考虑 - 可结合Seurat/Scanpy的WNN(weighted nearest neighbor)方法

多组学整合资源

  • LinkedOmics:TCGA多组学关联分析平台
  • mixOmics:R包提供多种整合方法
  • TCGA多组学数据:免费获取的多组学benchmark数据集
  • NCI-60/CCLE:细胞系多组学数据集

引用推荐

  • MOFA+: Argelaguet et al., Genome Biology, 2020
  • MOFA: Argelaguet et al., Molecular Systems Biology, 2018
  • MCIA: Meng et al., BMC Bioinformatics, 2014
  • mixOmics: Rohart et al., PLoS Computational Biology, 2017