【问题标题】:Passing a list of files to XLConnect将文件列表传递给 XLConnect
【发布时间】:2012-07-02 11:23:50
【问题描述】:

我已经编写了一个基于 for 循环的脚本来读取多个 .xls 文件的列,将它们组合成一个数据框,搜索负值并使用这些值和名称编写一个 .txt 文件文件。
该脚本基本上可以运行,但是我要处理数百个文件,而且速度有点慢。这个版本的脚本只是后期统计分析的一个基本框架,我想并行执行以加快速度。
我试图通过 lapply 和 plyr-package 应用函数来避免 for 循环,但是在将文件列表传递给“readWorkSheetFromFile”时遇到问题(path.expand(文件名)中的错误:“路径”参数无效)。

这是工作脚本:

require(XLConnect)
setwd(choose.dir())

input = list.files(pattern = ".xls$")

# creates empty data frame 
df = data.frame(Name=NULL, PCr=NULL, bATP=NULL, Pi=NULL)

for(i in seq(along=input)){
    data = data.frame(readWorksheetFromFile(input[i], sheet="Output Data", 
    startRow=2, startCol=c(10, 13, 16), endCol=c(10, 13, 16), header=TRUE))

    head(data, n = -1L)

    colnames(data) = c("PCr", "bATP", "Pi")
    data$Name = file.path(input[i])

    attach(data)
    df = rbind(data, df)
    attach(df)
    rm(data)
}

# searches for negative values in df and writes to txt file 
neg_val = subset(df, bATP<0 | Pi<0 | PCr<0)
write.table(neg_val, file = "neg_val.txt", sep = "\t", quote=F)

这个问题的任何解决方案,或其他加快执行速度的建议?

谢谢, 马库斯

【问题讨论】:

  • 您的速度问题可能是由于您的lack of preallocation,而不是 for 循环。 (在 R 中 for 循环本来就很慢的想法有点神话。)

标签: r for-loop


【解决方案1】:

我仍然不知道为什么 Martins 代码无法处理我的数据,但我找到了另一种解决方案。在第一次测试中,它比我原来的方法快了大约 4 倍。

# load required packages
require(XLConnect)
# set working dir
setwd(choose.dir())

# creates list of files of chosen dir and all subdirectories
files = list.files(pattern = ".xls$", recursive=T, full.names=T)

data = do.call("rbind", lapply(files, function(fl) {
   # Read data from file
   data.tmp = data.frame(readWorksheetFromFile(file = fl, sheet="Output Data", 
                         startRow=2, startCol=c(10, 13, 16), 
                         endCol=c(10, 13, 16), header=TRUE))

  # deletes last row of data frame
  head(data.tmp, n = -1L)

  # add file names as column 
  data.tmp$File = file.path(fl)
  data.tmp
}))

# rename columns
colnames(data) = c("PCr", "bATP", "Pi", "File")
# list negative values 
neg.val = subset(data, bATP<0 | Pi<0 | PCr<0)
# write output file
write.table(neg.val, file = "neg_val.txt", sep = "\t", quote=F)

感谢所有和最好的问候,
马库斯

【讨论】:

    【解决方案2】:

    请在下面找到有关如何潜在改进的建议。请注意,我在这里提供了一个更通用的示例,以便其他人可以轻松复制。

    require(XLConnect)
    
    # *** Generate some dummy files ***
    
    for(i in 1:10) {
      data = as.data.frame(matrix(rnorm(10000), ncol = 10))
      names(data) = LETTERS[1:10]
      writeWorksheetToFile(file = sprintf("test%s.xls", i), data = data, sheet = "data", header = TRUE)
    }
    
    
    # *** Process files ***
    
    # Get files to process
    files = list.files(pattern = "^test[0-9]+.xls$")
    # Read chunks of data from files and subset
    data.negative = lapply(files, function(fl) {
      # Read data from file
      data = readWorksheetFromFile(file = fl, sheet = "data", header = TRUE)
      # Which rows have all values < 0
      idx = apply(data, 1, function(x) all(x < 0))
      data[idx,]
    })
    # How many rows of all zeros does each chunk have?
    nrows = sapply(data.negative, nrow)
    # Combine data.negative into one data.frame
    data.negative = do.call(rbind, data.negative)
    # For each row add from which file it is originating
    data.negative$File = rep(files, times = nrows)
    # Write output file
    write.table(data.negative, file = "neg_val.txt", sep = "\t", quote = FALSE)
    

    这个想法是不要随后 rbind data.frames 这会使事情变慢(取决于你的 data.frames 的大小)。在您的情况下,我建议通过 lapply 进行读取和子集,然后将子集组合在一起以写入文件。另请注意,您可以轻松地将 lapply 切换到例如plyr 的 llply 并将并行后端连接到它以并行化该任务(但是,如果您尝试多次并行读取,您的磁盘可能会成为瓶颈)。

    希望对您有所帮助。

    最好的问候, 马丁

    【讨论】:

    • 感谢您的帮助,并为我的愚蠢感到抱歉,但到目前为止我还没有让它工作。如果我尝试读取我的文件,我会收到错误消息:data.negative = lapply(files, function(fl) { + data = readWorksheetFromFil .... [TRUNCATED] Error in apply(data, 1, function(x) all(x &lt; 0)) : dim(X) must have a positive length。如果我尝试制作data = as.data.frame(readWorkSheetFromFile ...,我不会收到任何错误消息,而是一个空文件。希望您能再次提供帮助!
    • 您使用的是哪个版本的 XLConnect?最新的(0.1-9)?
    • 我正在使用最新的 R 和包版本。顺便说一句,您的示例运行良好。
    • 您是否像示例中那样调整了 readWorksheetFromFile 调用(相应地指定开始/结束行/列?)
    猜你喜欢
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 2015-01-26
    • 2019-06-27
    • 2020-08-09
    • 2016-07-24
    • 1970-01-01
    相关资源
    最近更新 更多