使用神经网络与5折交叉验证进行基因组预测:完整指南

使用神经网络与5折交叉验证进行基因组预测:完整指南

在本篇博客中,我们将带您了解如何使用神经网络模型与5折交叉验证进行基因组预测。此方法通过基因组数据和环境因子预测表型(phenotype)。该实现使用了 Keras 库和 TensorFlow 后端,并且通过交叉验证评估模型表现,计算性能指标如相关性和均方根误差(RMSE)。此外,我们还将展示如何可视化训练过程和预测结果。

1. 引言

基因组预测旨在基于个体的基因数据预测其表型值。在本教程中,我们将使用 Keras 构建神经网络,通过 5折交叉验证 训练并评估该模型。数据包括基因型(SNP)、环境因子和表型数据。训练结束后,我们将计算模型的性能指标,并展示训练历史和预测结果的可视化图表。

2. 环境准备

在开始之前,请确保已安装以下软件和库:

  • R:版本 4.0 或更高
  • RStudio(推荐使用)
  • KerasTensorFlow:用于构建和训练神经网络
  • 其他必备库data.tableggplot2dplyrcaret

可以通过以下命令安装所需的 R 包:

r 复制代码
install.packages(c("keras", "tensorflow", "data.table", "ggplot2", "dplyr", "caret"))

安装 Keras 和 TensorFlow 后,运行以下命令进行配置:

r 复制代码
library(keras)
install_keras()  # 安装 Keras 和 TensorFlow

3. 数据加载与预处理

我们将从在线资源加载基因型(SNP)、环境协变量和表型数据。数据源已公开,脚本将直接从给定的 URL 下载数据。

加载数据

r 复制代码
# 加载基因型(SNP)数据
myGD <- read.table(file = "http://zzlab.net/GAPIT/data/mdp_numeric.txt", head = TRUE)

# 加载环境协变量数据
myCV <- read.table(file = "http://zzlab.net/GAPIT/data/mdp_env.txt", head = TRUE)

# 加载表型数据
myY <- read.csv(file = "http://zzlab.net/StaGen/2025/Data/my_y.csv", head = TRUE)

数据预处理

  • 基因型数据:去除 ID 列,并对基因型数据进行主成分分析(PCA),以捕捉种群结构。
  • 协变量数据:去除 ID 列。
  • 表型数据:对表型数据进行标准化。
r 复制代码
# 准备基因型数据
genotypes <- myGD
genotypes <- genotypes[, -1]  # 移除 ID 列

# 对基因型数据进行 PCA 处理
pcs <- prcomp(myGD[,-1])  # 排除 ID 列
pca <- as.data.frame(pcs$x[, 1:3])  # 取前3个主成分

# 准备环境协变量数据
covariates <- myCV
covariates <- covariates[, -1]  # 移除 ID 列

# 将 PCA 组件与环境协变量数据合并
covariates <- cbind(pca, covariates)

# 将基因型数据和协变量数据合并为输入矩阵 X
X <- as.matrix(cbind(genotypes, covariates))

# 对输入数据进行标准化
X <- scale(X)
X[is.na(X)] <- 0  # 将缺失值替换为 0

# 加载并标准化表型数据
y <- myY$Sim
y <- scale(y)

4. 设置5折交叉验证

我们使用 5折交叉验证 来训练和评估模型。数据集被划分为5个子集,每个子集轮流作为验证集,其余4个子集作为训练集。

r 复制代码
# 设置随机种子,保证结果可复现
set.seed(123)

# 创建5折交叉验证的折叠
folds <- createFolds(y, k = 5, returnTrain = TRUE)

# 初始化存储预测结果和性能指标的列表
predictions <- list()
correlations <- numeric(5)
rmse_values <- numeric(5)

5. 构建与训练神经网络模型

我们使用 Keras 库构建神经网络模型。模型包括:

  • 输入层 :根据 X 的特征数量设置。
  • 隐藏层:使用 ReLU 激活函数,并添加 Dropout 层进行正则化。
  • 输出层:一个单节点输出预测值。
r 复制代码
for (fold_idx in seq_along(folds)) {
  cat("Training fold", fold_idx, "of 5\n")
  
  # 分割训练集和验证集
  train_idx <- folds[[fold_idx]]
  val_idx <- setdiff(1:nrow(X), train_idx)
  X_train <- X[train_idx, ]
  y_train <- y[train_idx]
  X_val <- X[val_idx, ]
  y_val <- y[val_idx]
  
  # 构建神经网络模型
  model <- keras_model_sequential() %>%
    layer_dense(units = 48, activation = "relu", input_shape = ncol(X), 
                kernel_regularizer = regularizer_l2(0.08)) %>%
    layer_batch_normalization() %>%
    layer_dropout(rate = 0.25) %>%
    layer_dense(units = 24, activation = "relu", 
                kernel_regularizer = regularizer_l2(0.08)) %>%
    layer_batch_normalization() %>%
    layer_dropout(rate = 0.25) %>%
    layer_dense(units = 1)
  
  # 编译模型
  model %>% compile(
    optimizer = optimizer_adam(learning_rate = 0.0003),
    loss = "mean_squared_error"
  )
  
  # 设置回调函数(学习率调整与提前停止)
  lr_scheduler <- callback_reduce_lr_on_plateau(
    monitor = "val_loss",
    factor = 0.3,
    patience = 5,
    min_lr = 1e-6
  )
  
  early_stopping <- callback_early_stopping(
    monitor = "val_loss",
    patience = 5,
    restore_best_weights = TRUE
  )
  
  # 训练模型
  history <- model %>% fit(
    X_train, y_train,
    epochs = 500,
    batch_size = 154,
    validation_data = list(X_val, y_val),
    callbacks = list(early_stopping, lr_scheduler),
    verbose = 1
  )
  
  # 对验证集进行预测
  y_pred <- model %>% predict(X_val, batch_size = 154)
  
  # 存储预测结果
  predictions[[fold_idx]] <- data.frame(
    Fold = fold_idx,
    True = y_val,
    Predicted = as.vector(y_pred)
  )
  
  # 计算性能指标(相关性与RMSE)
  correlations[fold_idx] <- cor(y_val, y_pred)^2
  rmse_values[fold_idx] <- sqrt(mean((y_val - y_pred)^2))
  
  # 可视化训练历史
  library(ggplot2)
  df_history <- as.data.frame(history)
  p <- ggplot(df_history, aes(x = epoch, y = value, color = data)) +
    geom_line(size = 1.2) +
    facet_wrap(~metric, scales = "free_y") +
    theme_minimal(base_size = 14) +
    labs(
      title = paste("Training History - Fold", fold_idx),
      x = "Epoch",
      y = "Metric"
    )
  ggsave(
    filename = paste0("training_history_fold_", fold_idx, ".png"),
    plot = p,
    width = 6,
    height = 5,
    dpi = 150
  )
}

6. 评估模型表现

完成所有 5 折训练后,结合所有折叠的预测结果,并计算模型的平均性能指标(相关性与 RMSE)。

r 复制代码
# 合并所有折叠的预测结果
predictions_df <- do.call(rbind, predictions)

# 保存预测结果到 CSV 文件
write.csv(predictions_df, "genomic_predictions_epi.csv", row.names = FALSE)

# 打印预测表现摘要
cat("Prediction performance across folds:\n")
cat("Mean correlation:", mean(correlations), "\n")
cat("Correlation SD:", sd(correlations), "\n")
cat("Mean RMSE:", mean(rmse_values), "\n")
cat("RMSE SD:", sd(rmse_values), "\n")

7. 相关性可视化

我们为每个折叠生成一个散点图,显示预测与真实表型值之间的关系,并添加回归线进行拟合。

r 复制代码
# 为每个折叠生成相关性散点图

corr <- numeric(5)

for (fold_idx in 1:5) {
fold_data <- predictions_df[predictions_df$Fold == fold_idx, ]
y_true <- fold_data$True
y_pred <- fold_data$Predicted

计算相关性

r 复制代码
corr[fold_idx] <- cor(y_true, y_pred)^2

p <- ggplot(fold_data, aes(x = True, y = Predicted)) +
geom_point(color = "blue", alpha = 0.6) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(
title = paste("Fold", fold_idx, ": Predicted vs. True Phenotypes"),
x = "True Phenotype",
y = "Predicted Phenotype"
) +
annotate(
"text",
x = min(y_true) + 0.1 * (max(y_true) - min(y_true)),
y = max(y_pred) - 0.1 * (max(y_pred) - min(y_pred)),
label = sprintf("Correlation: %.3f", corr[fold_idx]),
hjust = 0,
vjust = 1
) +
theme_minimal()

ggsave(
filename = paste0("correlation_plot_fold_epi_", fold_idx, ".png"),
plot = p,
width = 6,
height = 5,
dpi = 150
)
}

cat("Correlation across folds:\n")
cat("Mean Cor:", mean(corr), "\n")

8. 结论

  • 最终模型:训练好的模型可以保存,并用于预测新的基因组数据。
  • 性能评估:通过5折交叉验证,我们计算了模型的平均相关性和 RMSE 值,帮助我们了解模型的泛化能力。