我有1500万个CSV文件,每个文件有两列(整数和浮点),行数在5到500行之间。每个文件看起来像:
3453,0.034
31,0.031
567,0.456
...
目前,我正在迭代所有文件,并使用read.csv()
将每个文件导入到一个大列表中。这是一个简化版本:
allFileNames = Sys.glob(sprintf("%s/*/*/results/*/*", dir))
s$scores = list()
for (i in 1:length(allFileNames)){
if ((i %% 1000) == 0){
cat(sprintf("%d of %dn", i, length(allFileNames)))
}
fileName = allFileNames[i]
approachID = getApproachID(fileName)
bugID = getBugID(fileName)
size = file.info(fileName)$size
if (!is.na(size) && size > 0){ # make sure file exists and is not empty
tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric"))
colnames(tmp) = c("fileCode", "score")
s$scores[[approachID]][[bugID]] = tmp
} else {
# File does not exist, or is empty.
s$scores[[approachID]][[bugID]] = matrix(-1, ncol=2, nrow=1)
}
}
tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric")
稍后在我的代码中,我将遍历列表中的每个矩阵,并计算一些度量。
启动此导入过程后,似乎需要3到5天才能完成订单。有更快的方法吗?
编辑:我添加了有关代码的更多详细信息。
我不清楚你的目标,但如果你试图将所有这些文件读取到一个R数据结构中,那么我会看到两个主要的性能问题:
- 文件访问时间-从你请求read.csv的那一刻起,你的机器上就开始了无数复杂的过程,包括查看该文件是否存在,在内存或磁盘上找到该文件的位置(如果需要,将数据读取到内存中),然后在R中解释数据
- 随着每次新文件的读取,增加您的单个数据结构。每当你想在矩阵中添加几行时,你可能需要重新分配一块大小相似的内存来存储更大的矩阵。如果您的阵列增长了1500万次,您肯定会注意到这里的性能有所下降。有了这个问题,性能会随着读取更多文件而逐渐变差
因此,进行一些快速分析,看看读取需要多长时间。如果它们随着您读取更多文件而逐渐变慢,那么让我们关注问题2。如果它一直很慢,那么让我们担心问题1。
关于解决方案,我想说你可以从两件事开始:
- 用另一种编程语言组合CSV文件。如果你只是在文件中循环并将它们连接到一个大文件中,那么一个简单的shell脚本可能会为你完成这项工作。正如Joshua和Richie在下面提到的,通过使用更高效的
scan()
或readlines()
函数,您可以在不必偏离另一种语言的情况下对此进行优化 - 预先确定统一数据结构的大小。例如,如果使用矩阵,请将行数设置为~1500万x 100。这将确保您只需在内存中为该对象查找一次空间,其余操作只需将数据插入预先确定大小的矩阵中
添加更多代码的详细信息(您正在使用的列表是什么样子的?),我们可能会提供更多帮助。
使用scan
(如注释中的约书亚状态)可能会更快(3-4倍):
scan(fileName, what=list(0L,0.0), sep=",", dec=".", quiet=TRUE)
主要区别在于scan
返回具有两个元素的列表,而read.csv
返回data.frame
。
这个通用工作流程怎么样?不过没有经过测试。
my.list.of.files <- list.files(pattern = ".txt") # char vector of filenames
my.data <- sapply(my.list.of.files, FUN = function(x) {
# read file using scan, craft the output to two columns
}) # result is merged
#or if you use simplify= FALSE
my.data <- sapply(my.list.of.files, FUN = function(x) {
# read file using scan (or some other method), craft the output to two columns
}, simplify = FALSE) #you get a list
my.data <- do.call("rbind", my.data)
正如Jeff提到的,这里有几件事可能需要很长时间。当RAM中有1500万个数据帧时,问题可能是文件访问、读取文件或内存不足。更为复杂的是,botleneck可能会根据您机器的规格而有所不同(例如,硬盘驱动器速度慢会减慢文件读取速度,缺少RAM会导致文件计数高)。要解决这个问题,你必须做一些分析。
试着一开始只读取10000个左右的文件,然后调用system.time
,或者更确切地说,使用rbenchmark
来查看什么最耗时。
然后看看joran的链接
在R 中将非常大的表作为数据帧快速读取
看看那里的技术是否对你有帮助。