在R中导入数百万个文件的最快方法?

时间:2012-03-23 16:21:13

标签: r csv import

我有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 %d\n", 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天才能完成。有更快的方法吗?

编辑:我添加了有关我的代码的更多详细信息。

4 个答案:

答案 0 :(得分:7)

我不清楚您的目标,但如果您尝试将所有这些文件读入单个R数据结构,那么我会看到两个主要的性能问题:

  1. 文件访问时间 - 从您请求read.csv的那一刻起,在您的机器上启动了无数复杂的进程,包括查看该文件是否存在,在内存或磁盘上查找该文件的位置(以及将数据读入内存) ,如果需要的话),然后解释R中的数据。当你阅读数百万个文件时,我预计这将是一个几乎不变的减速。
  2. 在读取每个新文件的情况下发展您的单一数据结构。每次要向矩阵添加几行时,您可能需要重新分配类似大小的内存块才能存储更大的矩阵。如果你的阵列增长了1500万次,你肯定会注意到这里的性能下降。遇到这个问题,随着您在更多文件中的阅读,性能将逐渐变差。
  3. 所以做一些快速分析,看看这些阅读需要多长时间。如果他们在阅读更多文件时逐渐放慢速度,那么让我们关注问题#2。如果它一直很慢,那么让我们担心问题#1。

    关于解决方案,我想你可以从两件事开始:

    1. 使用其他编程语言合并CSV文件。如果您只是循环浏览文件并将它们连接成一个大文件,那么简单的shell脚本可能会为您完成这项工作。正如Joshua和Richie在下面提到的那样,您可以通过使用效率更高的scan()readlines()函数来优化它,而不必偏离其他语言。
    2. 预先调整统一数据结构的大小。例如,如果您正在使用矩阵,请将行数设置为~1,500万x 100.这将确保您只需要为此对象在内存中找到一次空间,其余操作将只插入数据进入预先确定的矩阵。
    3. 添加您的代码的更多详细信息(您使用的列表是什么样的?),我们可能会更有帮助。

答案 1 :(得分:6)

使用scan(在评论中作为Joshua状态)可能更快(3-4次):

scan(fileName, what=list(0L,0.0), sep=",", dec=".", quiet=TRUE)

主要区别在于scan返回包含两个元素的列表,read.csv返回data.frame

答案 2 :(得分:2)

这个一般工作流程怎么样?但是没有经过测试。

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)

答案 3 :(得分:0)

正如杰夫所说,这里有好几件事可能需要很长时间。当RAM中有1500万个数据帧时,问题可能是文件访问,或读取文件或内存不足。为了解决这个问题,botleneck可能会因机器的规格而异(例如,慢速硬盘驱动器会降低文件读取速度,缺少RAM会导致文件数量过高)。要弄清楚问题,你必须做一些分析。

只需阅读10000个左右的文件,然后使用system.time调用rbenchmark或更为复杂,以查看花费的时间最多。

然后看看joran的链接

Quickly reading very large tables as dataframes in R

并查看是否有任何技术可以帮助您。