如何加快数据加载到R?

Gre*_*ory 3 r

问题:

数据集需要6-12个小时才能加载到R中.大量的数据集即将出现,我目前的导入过程显然还没有为他们做好准备.一旦它在数据框中全部,大小就不是问题; 大多数操作只需几秒钟,因此我的硬件可能不是问题.

注意:这个问题不是类似问题的重复,因为我已经实现了相关线程的大部分建议,例如指定colClasses.

数据:

制表符分隔文本文件中的行如下所示:

20  -0.5    1   2   1   1   19  0   119 30  exp(-31.3778)
Run Code Online (Sandbox Code Playgroud)

加载数据:

我已经定义了几个函数,它们一起循环文件以将数据加载到单个数据框中,然后将其保存为blob.这个过程需要数小时.该过程可预测地减慢并在进展时使用更多内存; top表示在使用数据文件的一半时,R正在使用> 95%的CPU和(更重要的是?)> 1.5 GB的实内存.

# get numeric log from character data
extract_log <- function(x) {
  expr <- "exp\\((.*)\\)"
  substring <- sub(expr, "\\1", x)
  log <- as.numeric(substring)
  return(log)

# reads .dat files into data frames
read_dat <- function(x, colClasses = c(rep("numeric", 10), "character")) {
  df <- read.table(x, header = TRUE, sep = "\t", comment.char = "",
                   colClasses = colClasses)
  df <- cbind(df, log_likelihood = sapply(df$likelihood, extract_log))
  df$likelihood <- exp(df$log_likelihood)
  # drop nat. log col, add log10 column shifting data to max = 0
  df <- transform(df,
                  rlog_likelihood = log10(likelihood) - max(log10(likelihood)))
  return(df)
}

# creates a single data frame from many .dat files
df_blob <- function(path = getwd(), filepattern = "*.dat$",
                    outfile = 'df_blob.r', ...) {
  files <- list.files(path = path, pattern = filepattern, full.names = TRUE)
  progress_bar <- {
    txtProgressBar(min = 0, max = length(files),
                    title = "Progress",
                    style = 3)
  }
  df <- read_dat(files[1])
  setTxtProgressBar(progress_bar, 1)
  for (f in 2:length(files)) {
    df <- rbind(df, read_dat(files[f]))
    setTxtProgressBar(progress_bar, f)
  }
  close(progress_bar)
  save(df, file = outfile)
}
Run Code Online (Sandbox Code Playgroud)

解决方案

所需时间从几小时减少到几秒.

  1. 使用shell脚本连接数据文件(所需时间约为12秒)
  2. 使用sqldf加载连接文件(所需时间约为6秒)

使用shell脚本连接数据文件(所需时间约为12秒),然后使用sqldf()完全按照JD Long对相关问题的回答中所述加载它们,如他的博客文章中所述.

得到教训

Justin和Joran的评论显着提高了read.table()方法的效率,对于较小的数据集,这种方法应该可以正常工作.特别是Justin建议更换循环rbind(df, read_dat(files[f]))文件,do.call(rbind, lapply(files, read_dat))将执行时间减少大约2/3.其他建议的改进虽然仍然值得,但更为温和.

Ric*_*ton 5

根本你遇到的一个大问题read.table是速度不是很快.您可以通过设置调整它colClassesnrows,但在这一天结束时,如果您的数据需要12个小时来加载,你需要使用不同的技术.

更快的方法是将数据导入数据库,然后将其读入R. JD Long演示了使用sqlite数据库和本答案中sqldf包的方法.MonetDB和软件包是专为快速完成此类工作而设计的,值得研究.MonetDB.R


正如Justin和Joran所发现的那样,在循环中逐步增长数据框架rbind(df, read_dat(files[f]))是一个巨大的瓶颈.如果完整数据集适合RAM,则可以使用更好的appraoch do.call(files, read.table).(如果没有,请使用上面的方法将所有内容删除到数据库中,然后将所需内容拉到R中.)

  • 我认为这些都是很好的建议,但我不确定我是否同意他的基本问题是"read.table".我认为他目前的瓶颈是(按降序排列):通过`rbind`增加df,调用`transform` 7000次(即重复执行所有转换而不是一次),最后触摸他的磁盘7000次.如果一个使用read.table的好解决方案至少速度快,我不会感到惊讶. (2认同)