2012-07-02 31 views
0

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

这里是工作的脚本:

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) 

任何解决问题的对策,或其他建议加快执行?

感谢, 马库斯

+0

你的速度问题可能是由于你的[缺乏预分配的(http://www.burns-stat.com/pages/Tutor/ R_inferno.pdf),而不是for循环。 (这个想法对于R来说本质上是慢的,这有点神话。) – joran

+0

感谢您的链接! – Markus

回答

3

我仍然不知道为什么马丁斯代码是不是我的数据的工作,但我发现另一种解决办法。第一次测试比我原先的方法快了约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) 

感谢所有和问候,
马库斯

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) 

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

希望有所帮助。

最好的问候, 马丁

+0

感谢您的帮助,并为我的愚蠢感到抱歉,但迄今为止我没有得到它的工作。如果我尝试在我的文件中读取,我收到错误消息:'data.negative = lapply(files,function(fl){ + data = readWorksheetFromFil .... [TRUNCATED] 错误apply(data,1 ,函数(x)全部(x <0)): dim(X)必须具有正值长度,如果我尝试使'data = as.data.frame(readWorkSheetFromFile ...',我没有错误信息,但是一个空文件,希望你能再帮一次! – Markus

+0

你使用的是什么版本的XLConnect?最新的(0.1-9)? –

+0

我正在使用最新的R和包版本。 ,顺便说一下 – Markus