跳转至

随机森林在生信应用

一句话概述:随机森林(Random Forest)是基于多棵决策树投票的集成学习方法,在生信中广泛用于疾病分类、生物标志物筛选、微生物组分析等场景,具有不易过拟合、可解释性强的优点。

核心知识点速查表

概念说明
随机森林多棵决策树投票决定结果(白话:让100个专家投票,少数服从多数)
BaggingBootstrap Aggregating,有放回抽样建多棵树
特征随机每次分裂只考虑部分特征(减少树之间的相关性)
OOB误差Out-of-Bag误差,用未被抽到的样本评估(自带验证)
特征重要性Mean Decrease Gini / Mean Decrease Accuracy
ntree树的数量(通常500-1000)
mtry每次分裂考虑的特征数(分类√p,回归p/3)

一、R语言实操

1.1 基本随机森林

# === 随机森林分类 ===
library(randomForest)

# 准备数据(假设:基因表达 + 疾病状态)
set.seed(42)
rf_model <- randomForest(
  x = gene_expr,                               # 特征矩阵(基因表达)
  y = factor(disease_group),                    # 目标变量(疾病/正常)
  ntree = 500,                                  # 树的数量
  mtry = sqrt(ncol(gene_expr)),                  # 每次分裂考虑的特征数
  importance = TRUE,                             # 计算特征重要性 ★
  proximity = TRUE                               # 计算样本相似度
)

# 查看结果
print(rf_model)                                  # 模型摘要
# OOB错误率、混淆矩阵

# OOB误差随树数变化
plot(rf_model)                                    # 误差收敛图
legend("topright", colnames(rf_model$err.rate),
       col=1:3, lty=1)

1.2 特征重要性(生物标志物筛选)

# === 特征重要性排序 ===
# 提取重要性
importance_df <- data.frame(
  Gene = rownames(importance(rf_model)),
  MeanDecreaseAccuracy = importance(rf_model)[, "MeanDecreaseAccuracy"],
  MeanDecreaseGini = importance(rf_model)[, "MeanDecreaseGini"]
)

# 按重要性排序
importance_df <- importance_df[order(-importance_df$MeanDecreaseAccuracy), ]

# 查看前20个重要基因
head(importance_df, 20)

# 可视化
varImpPlot(rf_model, n.var=20, main="Top 20 Important Genes")  # ★重要性图

# 用ggplot2美化
library(ggplot2)
top20 <- head(importance_df, 20)
ggplot(top20, aes(x=reorder(Gene, MeanDecreaseAccuracy),
                   y=MeanDecreaseAccuracy)) +
  geom_bar(stat="identity", fill="steelblue") +      # 柱状图
  coord_flip() +                                       # 横向
  labs(x="Gene", y="Mean Decrease Accuracy",
       title="Random Forest Feature Importance") +
  theme_minimal()

1.3 参数调优

# === 调优mtry参数 ===
tuneRF(
  x = gene_expr,                                # 特征
  y = factor(disease_group),                     # 标签
  stepFactor = 1.5,                              # mtry调整步长
  improve = 0.01,                                # 最小改进阈值
  ntreeTry = 300,                                # 每次尝试的树数
  plot = TRUE                                     # 绘制调优曲线
)

# === 使用caret完整调参 ===
library(caret)
ctrl <- trainControl(method="cv", number=10,
                      classProbs=TRUE,
                      summaryFunction=twoClassSummary)

rf_tuned <- train(
  x = gene_expr,
  y = factor(disease_group),
  method = "rf",                                 # 随机森林
  trControl = ctrl,
  tuneGrid = expand.grid(mtry=c(5,10,20,50)),    # 调优mtry
  metric = "ROC",                                 # 优化AUC
  ntree = 500
)
print(rf_tuned)                                   # 最优参数
plot(rf_tuned)                                    # AUC vs mtry

二、Python实操

# === Python随机森林 ===
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score, GridSearchCV
from sklearn.metrics import classification_report, roc_auc_score
import numpy as np

# 基本模型
rf = RandomForestClassifier(
    n_estimators=500,                             # 树的数量
    max_features='sqrt',                          # 每次分裂特征数
    random_state=42,                              # 随机种子
    n_jobs=-1,                                    # 使用所有CPU
    oob_score=True                                # 计算OOB评分
)
rf.fit(X_train, y_train)                          # 训练
print(f"OOB准确率: {rf.oob_score_:.3f}")          # OOB评分

# 特征重要性
importances = rf.feature_importances_             # 获取重要性
indices = np.argsort(importances)[::-1][:20]      # 前20个最重要的
for i, idx in enumerate(indices):
    print(f"{i+1}. {gene_names[idx]}: {importances[idx]:.4f}")

# 交叉验证
scores = cross_val_score(rf, X, y, cv=10, scoring='roc_auc')
print(f"10-fold CV AUC: {scores.mean():.3f} ± {scores.std():.3f}")

三、微生物组随机森林

# === 微生物组分类/回归 ===
library(randomForest)

# 读取OTU/ASV表
otu_table <- read.csv("otu_table.csv", row.names=1)   # OTU丰度表
metadata <- read.csv("metadata.csv")                     # 样本分组信息

# CLR转换(处理组成数据)
library(compositions)
otu_clr <- clr(otu_table + 0.5)                          # CLR转换,加伪计数

# 随机森林分类(疾病vs健康)
rf_micro <- randomForest(
  x = as.data.frame(otu_clr),
  y = factor(metadata$group),
  ntree = 1000,
  importance = TRUE
)

# 提取关键物种(生物标志物)
imp <- importance(rf_micro)
top_species <- rownames(imp)[order(-imp[,"MeanDecreaseAccuracy"])][1:20]
cat("前20个标志性微生物:\n")
print(top_species)

# Boruta特征选择(更严格的筛选)
library(Boruta)
boruta_result <- Boruta(
  x = as.data.frame(otu_clr),
  y = factor(metadata$group),
  maxRuns = 300                                   # 最大迭代次数
)
confirmed <- getSelectedAttributes(boruta_result)  # 确认重要的特征
print(confirmed)

四、面试高频考点

Q1: 随机森林为什么不容易过拟合?

  • 每棵树用不同的随机样本(Bagging减少方差)
  • 每次分裂只用部分特征(降低树间相关性)
  • 多棵树投票,单棵树的错误被平均掉
  • 白话:一个人可能判断错误,但100个人投票通常是对的

Q2: 特征重要性的两种指标?

  • MeanDecreaseAccuracy(MDA):去掉某特征后准确率下降多少。下降越多→越重要
  • MeanDecreaseGini(MDG):某特征对Gini不纯度的贡献。贡献越大→越重要
  • 推荐:MDA更可靠(但计算更慢),MDG有偏向连续变量的倾向

Q3: 随机森林 vs LASSO 在生物标志物筛选中怎么选?

随机森林LASSO
特征选择排序重要性自动选择(系数=0)
非线性能捕获不能
可解释性特征重要性系数大小+方向
适用场景复杂关系、交互效应线性关系、需要回归系数
常见组合RF筛选→RF/SVM建模LASSO筛选→Cox/Logistic建模

常见报错与解决

报错原因解决方案
内存不足数据太大减少ntree或特征数
OOB误差很高数据不可分或特征无关检查数据质量、增加特征
类别不平衡样本量差异大classwtsampsize调整
运行太慢数据量大用ranger包替代(更快)

速查表

# === 随机森林速查 ===
library(randomForest)

# 分类
rf <- randomForest(x, factor(y), ntree=500, importance=TRUE)
varImpPlot(rf, n.var=20)          # 重要性图

# 回归
rf <- randomForest(x, y, ntree=500, importance=TRUE)

# 参数调优
tuneRF(x, factor(y), stepFactor=1.5)  # mtry调优

# 快速版本(ranger)
library(ranger)
rf <- ranger(y ~ ., data=df, num.trees=500, importance="impurity")

# 默认mtry: 分类=√p, 回归=p/3
# 默认ntree: 500 (通常足够)