2011-01-21 10 views
35

私はいくつかのRスクリプトを用意しています。できるだけ早くRでいくつかのデータフレームをロードする必要があります。これは非常に重要です。なぜなら、データを読むことが手続きの中で最も遅いからです。たとえば、さまざまなデータフレームからのプロット。 sav(SPSS)形式のデータを取得しますが、推奨どおりに任意の形式に変換できます。残念ながら、データフレームをマージすることは選択肢ではありません。Rにデータを素早くロードするには?

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

  • 初めてでバイナリRオブジェクト(RDATA)にSAVから変換し、それがread.spssよりたくさん速く思えるよう後で必ず、これをロードします。
  • SAVにCSVファイルから変換しthisトピックで説明指定されたパラメータで、それらからデータを読み込み、
  • またはそのからローカルホストと負荷データにMySQLバックエンドをセットアップする価値がありますか?それはより速いかもしれませんか?その場合は、変数の値をattrに保存することもできます(たとえば、変数.Labels、Spssインポートファイルから)。またはこれは別のテーブルで行う必要がありますか?

他の考えを歓迎します。事前にお寄せいただきありがとうございます。


は、私はあなたが与えた回答に基づいて少し実験 belowを行い、また、特別の(24/01/2011)かなり「ハック」が、本当に迅速なソリューションの読み込みのみいくつかの変数/列の追加しますバイナリーファイル。後者は私が今想像できる最速の方法だと思われるので、この機能に対処するために savesという名前の小さなパッケージを作成しました(05/03/2011:ver。0.3)。パッケージは "重い"開発の下にあり、どんな勧告も歓迎です!

私はすぐにmicrobenchmarkパッケージの助けを借りて、正確なベンチマーク結果を持つビネットを投稿します。

+2

おめでとうございます:光っている新しいSSDのビジネスケースがあります。 –

+1

@リッチー・コットン:そうです:)しかし、真実を伝えるために、私はSSDを取り付けたマシンでスクリプトを実行しますが、コードを微調整したいと思います。 – daroczig

答えて

19

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

すべての種類のテキストファイルは、必ずオーバーヘッドを含めるので、別の話です。テキストファイルを読み込むたびに、データをバイナリRオブジェクトに変換する必要があります。私はそれらを忘れるだろう。これらは、あるアプリケーションから別のアプリケーションへのデータセットの移植にのみ役立ちます。

データのさまざまな部分が必要な場合や、さまざまな組み合わせの異なるサブセットが必要な場合は、MySQLバックエンドを設定すると非常に便利です。特に巨大なデータセットを扱う場合、行/列の選択を開始する前にデータセット全体に読み込む必要がないという事実は、かなりの時間を得ることができます。しかし、これは巨大なデータセットでしか動作しません。バイナリファイルを読むことは、データベースを検索するよりもかなり高速です。

データが大きすぎない場合は、1つのRDataファイルに異なるデータフレームを保存することができます。これにより、物事をより合理化する機会が与えられます。私はしばしば、リストや別個の環境の中に一連のデータフレームを持っています(いくつかの簡単な例については?environmentも参照してください)。これにより、lapply/eapplyのソリューションで複数のデータフレームを同時に処理できます。

+5

+1 "1つのRDataファイル内の異なるデータフレーム"。 'my_data <-new.env(); load(" my_data.RData "、my_data)は安全です(既存のオブジェクトを一掃することなく)。オブジェクトをRにロードします。 – Marek

+0

あなたの答えに感謝します!バイナリオブジェクトからデータを2列だけ読み込む方法を示す詳細を誰もがもっと創造的な答えが得られない場合、私はこれを受け入れます:)私は少し実験を行いました。また、バイナリファイルからの読み取りがこの「競争」で多く勝ったことを示しています。 MySQLの部分的な負荷は、その重要性とスピードも証明しました。 – daroczig

+0

余分な創造的な答えは到着しなかったので、ポイントはあなたに、ありがとう! :)私はまだいくつかの列が必要だった場合、オブジェクトの読み込みを高速化する特別な保存関数(例:バイナリオブジェクトを分離するすべての列を保存する)を書くかどうか疑問に思っています。実験の結果を掲載します。 – daroczig

1

私はRMySQLに非常に満足しています。あなたの質問が正しいかどうかはわかりませんが、ラベルは問題ではありません。既定のSQLテーブルと行の名前を使用する便利な機能がいくつかありますが、もちろんいくつかのSQL文を使用することもできます。

RMyを使用する主な理由の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 4GBのRAM 2.4GHZ Intel Core Duo、Mac OSX 10.6.4、MySQL 5.0.41 大容量のデータセットで通常作業し、読み込みに問題はなく、時間がある場合は、問題は全くありません。 +1のQ!

+3

RDBMSがローカルのハードディスクから.RDataファイルをピックアップするよりも速くなることは想像もできません(SSDの場合は二重になります)。実際のテストを見るのを待つことはできません。 MySQLの電線形式からRへのあらゆる種類のオーバーヘッドが必要です。 – Spacedman

+0

答えもテストもありがとう!私もいくつかの実験をしました、私の答えを見てください。本当にバイナリデータが勝つようです:) – daroczig

1

可能であれば、可能な限り速く読むためにデータをcsvまたは他の「シンプル」形式に変換してください(Jorisの回答を参照)。私は、apply機能で一斉エンcsvファイルをインポートするの線に沿って何か:

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 
}) 
+0

あなたの答えと複数のファイルを一度に読み込むヒントをありがとう!私の答えでは、バイナリオブジェクトの読み込みは、他のどの部分よりもはるかに高速です。 – daroczig

+2

'list.files'の代わりに' dir'を使います。キーストロークを保存します。ある日、あなたが年をとって関節の関節症に苦しむと、あなたは私の言葉を思い出します。=) – aL3xa

36

は、私はそれに基づいて、いくつかの概要と実験を行った、ヒントと回答ありがとうございました。

以下の公開データベース(ESS 2008 in Hungary)を使用して、少しテストを参照してください。データベースには1508のケースと508の変数があるため、中規模のデータになる可能性があります。それは(私のために)テストを行う良い例かもしれませんが、もちろん特別なニーズは適切なデータを使った実験を必要とします。変換されたバイナリオブジェクトと

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

読み込ん:

> 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 

> 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と試みるそのままSPSS SAVファイルからデータを読み取る

T

> 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 

もからデータをロード:CSVが速くたくさんのファイルをロードするように思わパッケージsqldf、と

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

: "微調整" CSVロードでryingローカルホスト上で実行されている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私たちのケースでは、データへの接続も重要です。私が何かを誤解した場合は、コメントしてください。

しかし、たとえばいくつかの変数だけを照会する場合は、本当に素晴らしいと思われる

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

:私たちは、ほとんどの場合、すべてのデータフレームを必要としないプロット、および2つの変数のみを照会しながら、それらの素敵なプロットを作成するのに十分です!もちろん、ただdbReadTable

まとめて表をロードした後:バイナリファイルからの全データを読み込むビートに何が、同じデータベーステーブルからわずか数の列(またはその他のフィルタリングされたデータ)を読み込むこともあるかもしれません特別な場合には重み付けされる。

テスト環境:ローエンドSSD搭載のHP 6715bラップトップ(AMD X2 2Ghz、4Gb 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(2011年6月3日):私の小さなパッケージ(saves)の新しいバージョンは、さらに高速の変数を保存してロードすることも可能である、CRANにアップロードされた - 唯一のユーザーならばデータフレームまたはリスト内の使用可能な変数のサブセットのみが必要です。詳細については、パッケージのソースまたはmy homepage上の1でvignetteを参照してください、と私も行われ、いくつかのベンチマークの素敵な箱ひげをご紹介しましょう:

Comparison of different data frame/list loading mechanism by speed

この箱ひげ図はを使用する利点は、ロードするためにパッケージを節約示し基底からのloadおよびread.tableまたはread.csvに対する変数のサブセット、sqldfまたはRMySQLパッケージからのread.spssの変数のサブセットのみです。

+5

テストを実行して結果を提示してくれてありがとう。これは私の先入観と一致していますが、経験豊かな経験主義者として、テストを見るのは素晴らしいことです。 –

+4

結果を公開したことは素晴らしいことです。しかし、1回の試行で結論を出すべきではありません。私は通常、スクリプトを書いて、それをn回繰り返す、散歩に出かけ、私が戻ったときにデータをクランチする。 =)とにかく... 'read.csv'は著しく遅く、' colClasses'引数を指定した方が速く実行できるようにすることができます。そうしないと、関数は各カラムのクラスをチェックします!そして、それは抗力です。さらに、 'stringsAsFactors'のデフォルト動作をバイパスすると、オブジェクトはより多くのメモリを占めます。とにかく、詳細をありがとう! =) – aL3xa

+1

そして自由にダウンロード可能なデータセットを私たちに指し示す+1! =) – aL3xa

関連する問題