如何加快数据加载到R?

时间:2013-11-08 16:05:46

标签: r

问题:

数据集需要6-12个小时才能加载到R.更多大型数据集即将推出 我目前的进口过程显然还没有为他们做好准备。一旦它全部存在于数据中 框架尺寸不是问题;大多数操作只需几秒钟,所以我的 硬件可能不是问题。

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

数据:

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

20  -0.5    1   2   1   1   19  0   119 30  exp(-31.3778)

加载数据:

我已经定义了一些函数,这些函数一起循环遍历文件以加载 将数据转换为单个数据帧,然后将其另存为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)
}

解决方案

所需时间从几小时减少到几秒钟。

  1. 使用shell脚本连接数据文件(所需时间约为12秒)
  2. 使用sqldf加载连接文件(所需时间约为6秒)
  3. 使用shell脚本连接数据文件(所需时间约为12秒) 然后完全按照JD Long's answer to a related question中所述并按照blog post中的描述加载sqldf()。

    经验教训

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

1 个答案:

答案 0 :(得分:5)

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

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


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