0

複数の .xls ファイルの列を読み取り、それらを 1 つのデータ フレームに結合し、負の値を検索し、これらの値とファイルの名前を含む .txt ファイルを書き込む for ループに基づくスクリプトを作成しました。
スクリプトは基本的に動作しますが、数百のファイルを処理する必要があり、少し遅いです。このバージョンのスクリプトは、後で統計分析を行うための基本的なフレームワークにすぎません。実行を並列化して高速化したいと考えています。
lapply と plyr-package を介して関数を適用することで for ループを回避しようとしましたが、ファイル リストを "readWorkSheetFromFile" に渡す際に問題がありました (path.expand (ファイル名) のエラー: 無効な 'path' 引数)。

作業スクリプトは次のとおりです。

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)

よろしくお願いします、
Markus

于 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)

アイデアは、後でdata.framesをrbindしないことです。これにより、処理が遅くなります(data.framesのサイズによって異なります)。あなたの場合、lapply を介して読み取りとサブセットを実行し、サブセットを結合してファイルに書き込むことをお勧めします。また、lapply を plyr の llply などに簡単に切り替えて、そのタスクを並列化するために並列バックエンドをフックすることもできます (ただし、多くの並列読み取りを試みると、ディスクがボトルネックになる可能性があります)。

それが役立つことを願っています。

よろしく、マーティン

于 2012-07-02T18:42:12.217 に答える