web-dev-qa-db-ja.com

CSVファイルを分割して読み込むための戦略は?

中程度のサイズのファイル(4GB CSV)があり、それを読み取るのに十分なRAM(64ビットWindowsでは8GB)がありません)。以前は、それをクラスターノードにロードして読み込みましたが、私の新しいクラスターはプロセスを任意に4GBのRAM(マシンあたり16GBのハードウェアにもかかわらず)に制限しているようです)なので、短いものが必要です-用語の修正。

利用可能なメモリ制限に合わせるために、CSVファイルの一部をRに読み込む方法はありますか?そうすれば、一度にファイルの3分の1を読み取り、必要な行と列にサブセット化してから、次の3分の1を読み取ることができますか?

いくつかの大きなメモリトリックを使用してファイル全体を読み取ることができる可能性があることを指摘してくれたコメント提供者に感謝します: Rのデータフレームとして非常に大きなテーブルをすばやく読み取る

他のいくつかの回避策を考えることができます(たとえば、優れたテキストエディターで開き、観測値の2/3を切り取ってから、Rにロードします)が、可能であればそれらを避けたいと思います。

ですから、それをバラバラに読むことは、今のところ最善の方法のように思えます。

19
Ari B. Friedman

たとえば、RSQLiteを使用してデータベースに読み込み、SQLステートメントを使用して一部を取得できます。

必要な部分が1つだけの場合は、sqldfパッケージのread.csv.sqlがデータをsqliteデータベースに読み込みます。まず、データベースが作成され、データはRを通過しないため、Rの制限は適用されません(このシナリオでは主にRAM))。次に、データをにロードした後データベース、sqldfは、指定されたsqlステートメントの出力をRに読み込み、最終的にデータベースを破棄します。データの処理速度によっては、複数ある場合は、各部分に対してプロセス全体を繰り返すことができる場合があります。

1行のコードだけで3つのステップすべてを実行できるため、試してみるのは簡単です。

DF <- read.csv.sql("myfile.csv", sql=..., ...other args...)

?read.csv.sql?sqldf、および sqldfホームページ も参照してください。

11
G. Grothendieck

これは非常に古いスレッドであることを私は知っています。しかし、私は最近、同様の問題を抱えていたので、それに遭遇しました。このスレッドを確認した後、この問題の目立った解決策が言及されていないことに気づきました。接続を使用してください!

1)ファイルへの接続を開きます

_con = file("file.csv", "r")
_

2)read.csvを使用してコードのチャンクを読み込みます

_read.csv(con, nrows="CHUNK SIZE",...)
_

補足:colClassesを定義すると、処理が大幅に高速化されます。不要な列は必ずNULLとして定義してください。

3)あなたがする必要があることは何でもしなさい

4)繰り返します。

5)接続を閉じます

_close(con)
_

このアプローチの利点は接続です。この手順を省略すると、処理速度が少し遅くなる可能性があります。接続を手動で開くことにより、基本的にデータセットを開き、close関数を呼び出すまでデータセットを閉じません。これは、データセットをループするときに、場所を失うことは決してないことを意味します。 1e7行のデータセットがあると想像してください。また、一度に1e5行のチャンクをロードしたいとします。接続を開くと、read.csv(con, nrow=1e5,...)を実行して最初の1e5行を取得し、次にread.csv(con, nrow=1e5,...)を実行して2番目のチャンクを取得します。

接続を使用しなかった場合、最初のチャンクは同じ方法でread.csv("file.csv", nrow=1e5,...)を取得しますが、次のチャンクではread.csv("file.csv", skip = 1e5, nrow=2e5,...)を取得する必要があります。明らかにこれは非効率的です。 1e5行を読んだだけなのに、1e5 +1行をもう一度見つけなければなりません。

最後に、_data.table::fread_は素晴らしいです。ただし、接続を渡すことはできません。したがって、このアプローチは機能しません。

これが誰かに役立つことを願っています。

[〜#〜]更新[〜#〜]

人々はこの投稿に賛成し続けているので、もう1つ簡単な考えを追加したいと思いました。新しい_readr::read_csv_は、_read.csv_のように、接続を渡すことができます。ただし、約10倍高速であるため アドバタイズ です。

23
Jacob H