問題:
データ セットを R に読み込むには 6 ~ 12 時間かかります。さらに大きなデータ セットが来る予定であり、現在のインポート プロセスでは明らかに準備ができていません。すべてがデータ フレームに入れば、サイズは問題になりません。ほとんどの操作は数秒しかかからないので、私のハードウェアはおそらく問題ではありません。
注:この質問は、関連するスレッドからのアドバイスのほとんどを既に実装しているため、同様の質問の複製ではありません。たとえば、colClasses を指定します。
データ:
タブ区切りのテキスト ファイルの行は次のようになります。
20 -0.5 1 2 1 1 19 0 119 30 exp(-31.3778)
データのロード:
ファイルをまとめてループしてデータを単一のデータ フレームにロードし、それを BLOB として保存する関数をいくつか定義しました。これは何時間もかかるプロセスです。プロセスは予想どおり遅くなり、進行するにつれてより多くのメモリを使用します。top は、R がデータ ファイルの途中までに CPU の 95% を超え、(さらに重要なことに?) 1.5 GB を超える実メモリを使用していることを示しています。
# get numeric log from character data
extract_log <- function(x) {
expr <- "exp\\((.*)\\)"
substring <- sub(expr, "\\1", x)
log <- as.numeric(substring)
return(log)
# reads .dat files into data frames
read_dat <- function(x, colClasses = c(rep("numeric", 10), "character")) {
df <- read.table(x, header = TRUE, sep = "\t", comment.char = "",
colClasses = colClasses)
df <- cbind(df, log_likelihood = sapply(df$likelihood, extract_log))
df$likelihood <- exp(df$log_likelihood)
# drop nat. log col, add log10 column shifting data to max = 0
df <- transform(df,
rlog_likelihood = log10(likelihood) - max(log10(likelihood)))
return(df)
}
# creates a single data frame from many .dat files
df_blob <- function(path = getwd(), filepattern = "*.dat$",
outfile = 'df_blob.r', ...) {
files <- list.files(path = path, pattern = filepattern, full.names = TRUE)
progress_bar <- {
txtProgressBar(min = 0, max = length(files),
title = "Progress",
style = 3)
}
df <- read_dat(files[1])
setTxtProgressBar(progress_bar, 1)
for (f in 2:length(files)) {
df <- rbind(df, read_dat(files[f]))
setTxtProgressBar(progress_bar, f)
}
close(progress_bar)
save(df, file = outfile)
}
ソリューション
所要時間が数時間から数秒に短縮されました。
- シェルスクリプトでデータファイルを連結(所要時間~12秒)
- 連結ファイルをsqldfで読み込む(所要時間~6秒)
データ ファイルをシェル スクリプト (所要時間 ~12 秒) で連結し、関連する質問に対する JD Long の回答と彼のブログ投稿で説明されているとおりに、sqldf() でそれらをロードします。
学んだ教訓
Justin と Joran のコメントにより、私の read.table() アプローチの効率が大幅に改善されました。小さなデータ セットの場合、このアプローチはうまく機能するはずです。rbind(df, read_dat(files[f]))
特に、オーバー ファイルのループを置き換えるという Justin のアドバイスはdo.call(rbind, lapply(files, read_dat))
、実行時間を約 2/3 短縮します。他の提案による改善はより控えめでしたが、それでも価値があります。