问题:
数据集需要 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)
}
解决方案
所需时间已从几小时减少到几秒钟。
- 使用 shell 脚本连接数据文件(所需时间约 12 秒)
- 使用 sqldf 加载连接文件(所需时间 ~6 秒)
使用 shell 脚本连接数据文件(需要大约 12 秒的时间),然后使用 sqldf() 完全按照JD Long 对相关问题的回答中的描述和他的博客文章中的描述来加载它们。
得到教训
Justin 和 Joran 的评论显着提高了我的 read.table() 方法的效率,对于较小的数据集,该方法应该可以正常工作。特别是贾斯汀的建议是将执行时间减少约 2/3来替换rbind(df, read_dat(files[f]))
文件的循环。do.call(rbind, lapply(files, read_dat))
其他建议的改进较为温和,但仍然值得。