0

我编写了一个基于 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)

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

谢谢,马库斯

4

2 回答 2

3

我仍然不知道为什么 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)

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

于 2012-07-05T08:11:33.610 回答
0

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

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 并将并行后端连接到它以并行化该任务(但是,如果您尝试多次并行读取,您的磁盘可能会成为瓶颈)。

希望有帮助。

最好的问候,马丁

于 2012-07-02T18:42:12.217 回答