3

問題:

データ セットを 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)
}

ソリューション

所要時間が数時間から数秒に短縮されました。

  1. シェルスクリプトでデータファイルを連結(所要時間~12秒)
  2. 連結ファイルを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 短縮します。他の提案による改善はより控えめでしたが、それでも価値があります。

4

1 に答える 1

5

基本的なあなたが抱えている大きな問題は、それread.tableがあまり速くないことです。colClassesとを設定することで微調整できますがnrows、結局のところ、データの読み込みに 12 時間かかる場合は、別のテクノロジを使用する必要があります。

より高速なアプローチは、データをデータベースにインポートしてから R に読み込むことです。JD Long は、この回答でsqliteデータベースとsqldfパッケージを使用する方法を示しています。MonetDB とパッケージは、この種のことを非常に迅速に行うように設計されており、調査する価値があります。MonetDB.R


Justin と Joran の両方が発見したように、使用してループ内でデータ フレームを段階的に成長させることrbind(df, read_dat(files[f]))は大きなボトルネックです。完全なデータセットが RAM に収まる場合、はるかに優れたアプローチは を使用することdo.call(files, read.table)です。(そうでない場合は、上記の方法を使用して、すべてをデータベースに消去し、必要なものだけを R に取り込みます。)

于 2013-11-08T16:25:35.163 に答える