web-dev-qa-db-ja.com

Rにデータをすばやくロードする方法は?

いくつかのRスクリプトがあり、Rにいくつかのデータフレームをできるだけ早くロードする必要があります。データの読み取りは手順の最も遅い部分であるため、これは非常に重要です。例:異なるデータフレームからのプロット。データはsav(SPSS)形式で取得しますが、提案されているように任意の形式に変換できます。残念ながら、データフレームのマージはオプションではありません。

データをロードする最も速い方法は何でしょうか?私は次のことを考えていました:

  • savからバイナリRオブジェクト(Rdata)に最初に変換し、後でこれを常にロードするread.spssよりも高速です。
  • savからcsvファイルに変換し、 this トピックで説明されている特定のパラメーターを持つファイルからデータを読み取る
  • または、localhostにMySQLバックエンドを設定し、そこからデータをロードする価値はありますか?それはもっと速いのでしょうか?その場合、変数のカスタムattr値も保存できますか(例:variable.labelsSpssインポートファイルから)または、これは別のテーブルで行う必要がありますか?

他の考えは大歓迎です。よろしくお願いします!


私は少し実験をしました あなたが与えた答えに基づいて、そしてまた追加しました(24/01/2011)かなり「ハッキー」ですが特別なものからいくつかの変数/列のみをロードする本当に高速なソリューションバイナリーファイル。後者は、私が今想像できる最も速い方法のようです。そのため、この機能に対処するために saves という名前の小さなパッケージを作成しました(2011年5月3日:バージョン0.3)。パッケージは「重い」開発中であり、どんな推薦でも大歓迎です!

microbenchmark パッケージを使用して、正確なベンチマーク結果のビネットを間もなく投稿します。

36
daroczig

それは、何をしたいか、そしてデータをさらに処理する方法に依存します。いずれの場合でも、常に同じデータセットが必要であれば、バイナリRオブジェクトからのロードは常に高速になります。ここでの制限速度は、Rではなくハードドライブの速度です。バイナリ形式は、ワークスペース内のデータフレームの内部表現であるため、変換は必要ありません。

オーバーヘッドが必ず含まれるため、テキストファイルの種類は異なります。テキストファイルを読み取るたびに、データをバイナリRオブジェクトに変換する必要があります。私はそれらを忘れてしまいます。これらは、アプリケーション間でデータセットを移植する場合にのみ役立ちます。

MySQLバックエンドの設定は、データのさまざまな部分、またはさまざまな組み合わせのさまざまなサブセットが必要な場合に非常に役立ちます。特に巨大なデータセットを扱う場合、行/列の選択を開始する前にデータセット全体をロードする必要がないという事実により、かなりの時間が得られます。ただし、バイナリファイルの読み取りはデータベースの検索よりもかなり高速であるため、これは巨大なデータセットでのみ機能します。

データが大きすぎない場合は、1つのRDataファイルにさまざまなデータフレームを保存して、もう少し効率化することができます。多くの場合、リストまたは個別の環境に一連のデータフレームがあります(簡単な例については、?environmentも参照してください)。これにより、lapply/eapplyソリューションで複数のデータフレームを一度に処理できます。

19
Joris Meys

ヒントと回答をありがとうございました。それに基づいて要約と実験を行いました。

以下の公開データベースを使用した小さなテスト( ハンガリーのESS 2008 )を参照してください。データベースには1508のケースと508の変数があるため、中規模のデータになる可能性があります。これは(私にとって)テストを実行するための良い例かもしれませんが、もちろん特別なニーズでは、適切なデータを使った実験が必要になります。

変更を加えずにSPSSsavファイルからデータを読み取る:

> system.time(data <- read.spss('ESS_HUN_4.sav'))
   user  system elapsed 
  2.214   0.030   2.376 

変換されたバイナリオブジェクトの読み込み:

> save('data',file='ESS_HUN_4.Rdata')
> system.time(data.Rdata <- load('ESS_HUN_4.Rdata'))
   user  system elapsed 
   0.28    0.00    0.28 

csvで試す:

> write.table(data, file="ESS_HUN_4.csv")
> system.time(data.csv <- read.csv('ESS_HUN_4.csv'))
   user  system elapsed 
  1.730   0.010   1.824 

「微調整された」csvの読み込みを試す:

> system.time(data.csv <- read.table('ESS_HUN_4.csv', comment.char="", stringsAsFactors=FALSE, sep=","))
   user  system elapsed 
  1.296   0.014   1.362 

また、パッケージsqldfを使用すると、csvファイルの読み込みがはるかに高速になるようです。

> library(sqldf)
> f <- file("ESS_HUN_4.csv")
>  system.time(bigdf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F, sep="\t")))
   user  system elapsed 
  0.939   0.106   1.071 

また、localhostで実行されているMySQLデータベースからデータをロードします。

> library(RMySQL) 
> con <- dbConnect(MySQL(), user='root', dbname='test', Host='localhost', password='')
> dbWriteTable(con, "data", as.data.frame(data), overwrite = TRUE)
> system.time(data <- dbReadTable(con, 'data'))
   user  system elapsed 
  0.583   0.026   1.055 
> query <-('SELECT * FROM data')
> system.time(data.sql <- dbGetQuery(con, query))
   user  system elapsed 
  0.270   0.020   0.473 

ここでは、データへの接続も考慮されるため、2つのsystem.timeを追加する必要があると思います。誤解した場合はコメントしてください。

しかし、たとえば、いくつかの変数のみをクエリする場合を見てみましょう。プロット中、ほとんどの場合、すべてのデータフレームは必要ありません。2つの変数をクエリするだけで、それらのニースプロットを作成できます。

> query <-('SELECT c1, c19 FROM data')
> system.time(data.sql <- dbGetQuery(con, query))
   user  system elapsed 
  0.030   0.000   0.112 

本当に素晴らしいようです!もちろん、dbReadTableでテーブルをロードした直後

概要:バイナリファイルからデータ全体を読み取るのに勝るものはありませんが、sameデータベーステーブルも一部の特殊なケースで重み付けされる場合があります。

テスト環境:ローエンドSSDを搭載したHP 6715bラップトップ(AMD X2 2Ghz、4 Gb DDR2)。


UPDATE(24/01/2011):バイナリオブジェクトのいくつかの列のみをロードする、かなりハッキーですが非常に「クリエイティブ」な方法を追加しました-これは、上記のどの方法よりもはるかに高速に見えます。

注意してください:コードは本当に見栄えが悪くなりますが、それでも非常に効果的です:)

まず、次のループを介してdata.frameのすべての列を異なるバイナリオブジェクトに保存します。

attach(data)
for (i in 1:length(data)) {
    save(list=names(data)[i],file=paste('ESS_HUN_4-', names(data)[i], '.Rdata', sep=''))
}
detach(data)

次に、データの2つの列を読み込みます。

> system.time(load('ESS_HUN_4-c19.Rdata')) + 
>     system.time(load('ESS_HUN_4-c1.Rdata')) + 
>     system.time(data.c1_c19 <- cbind(c1, c19))
    user  system elapsed 
    0.003   0.000   0.002 

「超高速」メソッドのように見えます! :)注:これは、上記の最速の(バイナリオブジェクト全体をロードする)メソッドよりも100倍速くロードされました。

私は非常に小さなパッケージ(名前: saves )を作成しました。詳細については github を参照してください。


UPDATE(06/03/2011):私の小さなパッケージの新しいバージョン( saves )がCRANにアップロードされましたユーザーがデータフレームまたはリストで使用可能な変数のサブセットのみを必要とする場合のみ、変数をより速く保存およびロードすることができます。詳細については、パッケージソースの vignette または my homepage のパッケージを参照してください。また、いくつかのベンチマークのニースボックスプロットも紹介します。

Comparison of different data frame/list loading mechanism by speed

このボックスプロットは、savesパッケージを使用して、loadおよびread.tableまたはread.csvに対して変数のサブセットのみをベースからロードする利点を示しています。 read.spss外部パッケージ、sqldfまたはRMySQLパッケージから。

39
daroczig

RMySQLにはかなり満足しています。質問の答えが正しいかどうかはわかりませんが、ラベルに問題はありません。デフォルトのSQLテーブルと行名だけを使用する便利な関数がいくつかありますが、もちろんいくつかのSQLステートメントを使用できます。

(騒ぎを正当化する大きなデータセットは別として)RMySQLを使用する主な理由の1つは、Rデータジャグリング関数よりもSQL構文に精通していることです。個人的には、集約よりもGROUP BYを優先します。 R内部からのストアドプロシージャの使用は、特にうまく機能しないことに注意してください。

つまり、MySQLローカルホストの設定はそれほど手間がかかりません。試してみてください。速度については正確には言えませんが、もっと速い可能性があると感じています。しかし、私はここに戻ろうとします。

編集:ここにテストがあります...そして勝者は:spacedmanです

# SQL connection
source("lib/connect.R")

dbQuery <- "SELECT * FROM mytable"
mydata <- dbGetQuery(con,dbQuery)
system.time(dbGetQuery(con,dbQuery))
# returns
#user  system elapsed 
# 0.999   0.213   1.715 

save.image(file="speedtest.Rdata")
system.time(load("speedtest.Rdata"))
#user  system elapsed 
#0.348   0.006   0.358 

ここでは、ファイルサイズは約1 MBしかありませんでした。 MacBook Pro 4 GB Ram 2.4 GHZ Intel Core Duo、Mac OSX 10.6.4、MySQL 5.0.41通常はより大きなデータセットを使用していて、読み込みに問題はなく、処理に時間がかかるため、これを試したことがない...時間に問題がある場合まったく。 Qの+1!

1
Matt Bannert

可能な場合は、データをcsvまたはその他の「単純な」形式に変換して、可能な限り高速に読み取ります(Jorisの回答を参照)。私はcsvファイルをインポートしますen masseapply関数を使って、

list.of.files <- as.list(list.files("your dir"))
lapply(list.of.files, FUN = function(x) {
    my.object <- read.table(...) # or some other function, like read.spss
})
1
Roman Luštrik