3. 数据格式要求:理解MOFA输入数据的结构
开始调MOFA模型之前,有一件事你必须搞明白——数据长什么样才能往里喂。
我见过不少同学,代码跑得飞起,结果一读数据直接报错。说白了,MOFA对输入格式有自己的一套规矩。
这一章,我们就把它彻底捋清楚。
3.1 宽表格:横着摆,竖着读
MOFA的核心输入,是一种叫“宽表格”的东西。你想想看,其实就是行是样本、列是特征。
举个例子:
Gene1 Gene2 Gene3 ... Metabolite1 Metabolite2 ...
Sample_1 5.2 3.1 0.8 0.45 1.23
Sample_2 4.8 2.9 1.1 0.52 1.18
Sample_3 6.1 3.5 0.9 0.39 1.31
Sample_4 5.5 3.0 1.0 0.48 1.27
看到没?每个sample一行,所有特征横着排开。如果你的数据是长表格(每个sample多行),那必须先做pivot。
3.2 样本×特征:必须搞清楚的方向
MOFA的文档里反复强调“samples × features”的结构。其实说白了就是:行是样本,列是特征。
我曾经在一个代谢组学项目里吃过这个亏。数据导出来是特征×样本的格式,我没注意直接往里灌,模型跑了三天,结果全是垃圾。后来一查才发现,方向搞反了。
所以,这里有三种方法帮你确认方向:
- 看索引:样本名通常在行索引里
- 看列名:特征名通常在列名里
- 看数值范围:同一特征的数值量级通常接近
如果你拿不准,手动检查几行就明白了。
3.3 缺失值处理:不是填个0就完事了
MOFA模型支持缺失值,但不代表你可以随便处理。我记得刚入行时,导师丢给我一句“缺失值用0填充就行”,结果模型一发散,收敛不了。
缺失值分三种情况:
| 缺失类型 | 含义 | 处理方法(我建议) |
|---|---|---|
| 完全随机缺失(MCAR) | 缺失和任何变量无关 | 可以直接用均值/中位数填充 |
| 随机缺失(MAR) | 缺失和其他变量有关 | 用模型预测填充,比如KNN或MICE |
| 非随机缺失(MNAR) | 缺失和自身值有关 | 这比较棘手,建议保留缺失标记,交给MOFA内部处理 |
实操中,我常用这个简单的处理方法:
import pandas as pd
import numpy as np
# 假设 df 是你的数据,缺失用 NaN 表示
# 先看看缺失比例
missing_ratio = df.isnull().mean()
print(missing_ratio[missing_ratio > 0])
# 删除缺失超过50%的特征
df_clean = df.loc[:, missing_ratio < 0.5]
# 剩余缺失用特征均值填充
df_filled = df_clean.fillna(df_clean.mean())
3.4 标准化:不同模态必须统一量纲
MOFA的一个核心假设是:不同特征之间可以比较。但基因表达量可能是0.1~10,代谢物浓度可能是100~1000,直接放一起,结果会被量级大的特征主导。
说实话,这个问题我踩过很多次坑。有一次做多组学整合,转录组和蛋白组量级差了两个数量级,出来的因子全部被转录组占了,蛋白组的信息一点没体现。
标准化这里,有两种主流方式:
| 方法 | 公式 | 适用场景(我的经验) |
|---|---|---|
| Z-score | (x - mean) / std | 大多数情况都用这个,模型稳定 |
| Min-Max | (x - min) / (max - min) | 数据波动很大,或者有明确边界时用 |
具体代码:
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Z-score 标准化
scaler_z = StandardScaler()
df_zscore = pd.DataFrame(scaler_z.fit_transform(df_filled),
index=df_filled.index,
columns=df_filled.columns)
# Min-Max 标准化
scaler_mm = MinMaxScaler()
df_minmax = pd.DataFrame(scaler_mm.fit_transform(df_filled),
index=df_filled.index,
columns=df_filled.columns)
重要提醒:标准化一定要在填充缺失值之后做。否则均值和标准差会被缺失值带偏。
3.5 完整的数据预处理流程
好了,我们把前面这几步串起来。这是我个人习惯的一套流程:
- 读数据:确认宽表格结构,样本×特征方向
- 检查缺失:查看每列缺失比例,删除高缺失特征
- 填充缺失:用均值或中位数填充剩余缺失值
- 标准化:对每列做Z-score标准化
- 最终检查:确认无缺失、均值为0、方差为1
用代码实现就是:
def preprocess_for_mofa(df, missing_threshold=0.5):
# 1. 删除高缺失特征
df = df.loc[:, df.isnull().mean() < missing_threshold]
# 2. 均值填充
df = df.fillna(df.mean())
# 3. Z-score标准化
scaler = StandardScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df),
index=df.index,
columns=df.columns)
return df_scaled
嗯,这样处理完的数据,MOFA模型跑起来很顺。
3.6 数据基础设施总览
我画了一张图,帮你把整个数据准备流程串起来。你看一眼就明白了:
总结一下这章的核心:数据格式是MOFA的门槛,宽表格、样本×特征、缺失值处理和标准化,四步缺一不可。