You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

评估并优化R中加载大量CSV数据集至列表的运行效率

大规模CSV数据集加载效率优化(26万份Monte Carlo合成数据)

问题背景

本研究需对比新型最优变量选择统计学习算法与LASSO、向后逐步回归、向前逐步回归三种基准算法的性能,数据集为26万个通过Monte Carlo Simulation生成的CSV合成文件。当前加载流程的前置代码与加载代码如下,核心问题:加载5.85万个同类数据集仅需约2小时,但加载26万个数据集已运行54小时仍未完成。设备为升级至32GB内存的2022款中等性能HP笔记本,代码经小数据集(10个、40个)测试无语法问题,无并行版本因设备耗电中断,现需效率评估与优化方案。

当前前置代码

# 创建数据集文件夹中所有文件名的字符列表
folderpath <- "C:/Users/Spencer/Documents/EER Project/datasets folder"
filepaths_list <- list.files(path = folderpath, full.names = TRUE, 
                             recursive = TRUE)
# 重新格式化CSV数据集的名称
DS_names_list <- basename(filepaths_list)
DS_names_list <- tools::file_path_sans_ext(DS_names_list)

# 对两个文件名列表进行排序,确保顺序正确
my_order = DS_names_list |> 
  # 拆分数字并转换为数值型
  strsplit(split = "-", fixed = TRUE) |>  unlist() |> as.numeric() |>
  # 转换为数据框
  matrix(nrow = length(DS_names_list), byrow = TRUE) |> as.data.frame() |>
  # 获取合适的排序规则
  do.call(order, args = _)
DS_names_list = DS_names_list[my_order]
filepaths_list = filepaths_list[my_order]

当前加载代码

# 读取所有CSV文件中的数据并存储到列表
CL <- makeCluster(detectCores() - 1L)
clusterExport(CL, c('filepaths_list'))
system.time( datasets <- lapply(filepaths_list, read.csv) )
stopCluster(CL)

效率瓶颈分析

  1. 并行机制完全失效:代码创建了计算集群,但实际用的是串行的lapply而非并行版的parLapply,等于白开集群,这是效率暴跌的核心原因——之前5.85万的快速加载大概率是误触了其他优化,这次完全串行导致时间呈非线性增长。
  2. read.csv读取效率低下:基础R的read.csv是最慢的CSV读取方式之一,没有利用底层优化或多线程读取。
  3. 文件名排序冗余:26万个文件名的排序流程用了多次类型转换,额外消耗了预处理时间。
  4. 内存压力拖慢速度:一次性加载26万个数据集到内存,即使32GB内存也会触发频繁的垃圾回收(GC),导致CPU资源浪费在内存管理上。

优化方案

1. 修复并行计算逻辑

直接用parLapply替代lapply,并简化集群操作:

library(parallel)
# 创建集群(保留1核给系统)
CL <- makeCluster(detectCores() - 1L)
# 直接将文件路径列表传给parLapply,无需额外导出
system.time( datasets <- parLapply(CL, filepaths_list, read.csv) )
stopCluster(CL)

2. 替换高效CSV读取函数

用data.table::fread或readr::read_csv替代read.csv,速度可提升2-10倍,推荐fread(性能最优):

data.table方案:

library(parallel)
library(data.table)
CL <- makeCluster(detectCores() - 1L)
# 在每个集群节点加载data.table
clusterEvalQ(CL, library(data.table))
# 并行读取
system.time( datasets <- parLapply(CL, filepaths_list, fread) )
stopCluster(CL)

3. 简化文件名排序逻辑

原排序代码冗余,改用更高效的数字提取排序:

# 假设文件名格式为"xxx-数字1-数字2",提取数字段排序
num_segments <- sapply(strsplit(DS_names_list, "-", fixed = TRUE), 
                       function(x) as.numeric(x))
# 直接用矩阵生成排序规则,跳过不必要的data.frame转换
my_order <- do.call(order, as.data.frame(num_segments))
DS_names_list <- DS_names_list[my_order]
filepaths_list <- filepaths_list[my_order]

# 更简洁的stringr版本(需加载stringr包)
# library(stringr)
# nums <- str_extract_all(DS_names_list, "\\d+", simplify = TRUE) |> as.numeric()
# my_order <- order(nums[,1], nums[,2]) # 根据实际数字段数量调整

4. 内存优化:分批次处理

如果一次性加载所有数据导致内存过载,分批次处理可避免频繁GC:

library(parallel)
library(data.table)

batch_size <- 10000 # 每批次加载1万个文件
total_files <- length(filepaths_list)
num_batches <- ceiling(total_files / batch_size)

for (batch_idx in 1:num_batches) {
  # 计算当前批次的文件索引
  start_pos <- (batch_idx - 1) * batch_size + 1
  end_pos <- min(batch_idx * batch_size, total_files)
  batch_paths <- filepaths_list[start_pos:end_pos]
  
  # 并行加载当前批次
  CL <- makeCluster(detectCores() - 1L)
  clusterEvalQ(CL, library(data.table))
  batch_data <- parLapply(CL, batch_paths, fread)
  stopCluster(CL)
  
  # 在这里加入你的算法逻辑,处理当前批次的数据
  # ...
  
  # 释放内存,准备下一批次
  rm(batch_data)
  gc(verbose = FALSE)
}

5. 硬件与系统层面优化

  • 确认数据集存储在SSD上:机械硬盘的随机读取速度是大规模文件加载的最大瓶颈,换SSD可将读取速度提升10-100倍。
  • 关闭后台占用资源的程序:比如浏览器、视频软件等,避免CPU和内存被分流。
  • 调整R的内存限制:memory.limit(size = 28000)(分配28GB给R,留4GB给系统运行)。

内容的提问来源于stack exchange,提问作者Marlen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 17:30:21