質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

1回答

1465閲覧

Rubyでのデータ処理を高速化したい CSV->GDBM->読み込んで計算のプロセス

kzd847686

総合スコア53

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2019/02/21 07:17

Rubyでデータ処理を高速化したいと思っています。

CSVのデータは、次の様に90000行で各20個のデータがあります。

Number,p1,p2,p3,p4,...,p20
00001,48,74,32,74,...,144
00002,98,78,62,71,...,164
00003,49,84,36,41,...,149
.
.
.
89000,78,44,37,81,...,18
90000,88,79,34,15,...,14

※Numberは必ずしも1-90000まであるわけではなく、抜けがあります。またこの例では全て数値ですが意味のある文字が入っていることもあります

これをまずはGDBMへ変換し、その後Marshalで読み込んで使用しています。
読み込みは、Number=00005のとき、p14とp18をひっぱる、Number=00006のときp9とp20をひっぱる、のようにNumberが00001⇒90000まで各行で事前に決めたアルゴリズムに沿って必要なpの値をひっぱってきます。

この、Numberが00001⇒90000までの処理を、ひっぱってくるpの位置を変え数百回繰り返すのですが、処理に時間がかかってしまいこれを高速化したいです。

数百回する部分をThreadで並列処理を試みましたが高速化の効果は得られませんでした。
何かコードに工夫を加えるか、それをも別の方法を使って高速化できないものなのでしょうか。(narrayを使うとか?)。もしくは、rubyで大量のデータ処理は不向きなので、C言語等に取り組むべきなのでしょうか。(rubyは扱いやすく好きなので、できればrubyで達成したいです)

実行しているコードのサンプル

Ruby

1require 'gdbm' 2require "csv" 3 4#DBファイルの作成 5list = GDBM.open("data.db",0664,GDBM::NEWDB) 6 7#CSVからDBファイルへ書き換え 8CSV.foreach("data.csv", headers: true) do |row| 9 key = row["Number"] 10 list[key] ||= Marshal.dump([]) 11 list[key] = Marshal.dump( Marshal.load(list[key]) << row ) 12end 13 14#ここまでの時間は気にならない 15#これより下記の作業をxとyの値を変えて百回繰り返す 16#nowを1から90000まで変えて各行の必要なpをひっぱりだす 17 18100.times{ 19 20now = 1 21answer = [] 22loop{ 23 24 #listにnowの値のキーがあるか確認 25 i = 0 26 until list.has_key?(((now + i).to_i.to_s)) == true 27 i +=1 28 end 29 now = now + i 30 31 #nowが90000に近かったら終わりにさせる 32 if Marshal.load(list[(now + i).to_i.to_s] )[0]["Number"].to_f > 89500 33 exit 34 end 35 36 #Listからpの値をひっぱてくる 37 start = Marshal.load(list[now.to_i.to_s] )[0]["p#{x}"].to_f 38 finish = Marshal.load(list[now.to_i.to_s] )[0]["p#{y}"].to_f 39 answer << [now, start + finish] 40 41 now += 1 42 43} 44 45}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

計測はしていませんし、どの程度の高速化が必要かも分かりませんが、見るからにMarshal.loadのやりすぎな気がします。
Marshal.dumpで出した文字列を解釈してオブジェクトを新しく作っているので、それなりに時間がかかる処理なはずです。

GDBMは文字列しか扱えないのでこうしているのだとは思いますが、そもそもGDMBはkey-valueストアなので表形式のデータの格納にはあまり向いていません。
どうしても使いたいのであれば、キーを[Numberの値]_[p(n)]といった形にして、値を一つ一つ保存したほうがまだいいと思います。

とはいえ、高速に処理したいということであれば、データをすべてメモリに載せることが必要不可欠です。
メモリが十分にあるマシンを用意してHashを使うなどして処理したほうがいいと思います。

投稿2019/02/21 21:40

Kta-M

総合スコア456

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kzd847686

2019/02/24 16:54

ありがとうございます。 全て独学で基礎が抜けているので大変参考になります。 >キーを[Numberの値]_[p(n)]といった形にして、値を一つ一つ保存したほうがまだいいと思います。 これは全てをキーにして保存してしまうという事でしょうか。もしそういった場合であれば、コードの書き方を教えて頂けますと大変助かります。 >高速に処理したいということであれば、データをすべてメモリに載せることが必要不可欠です。 現状の私のコードだと全てのデータをメモリに載せていなかったのでしょうか。 >メモリが十分にあるマシンを用意してHashを使うなどして処理 CSVのファイルの容量から必要なメモリの量を求める方法はありますでしょうか。今は4MBですが、これをどれほど大きくすれば良いのかわからず…
Kta-M

2019/02/24 23:13

> 現状の私のコードだと全てのデータをメモリに載せていなかったのでしょうか。 https://docs.ruby-lang.org/ja/latest/class/GDBM.html 「GDBMファイルをアクセスするクラス」とあります。 詳細な内部の挙動までは確認していませんが、おそらくファイルから読み込んでいるのではないかと思います。全データがメモリに乗っているということはありません。 全データをメモリに乗せるのが不安だからわざわざGDBMを選択したのだと思っていました。。 > 今は4MBですが、 元データが4MBであれば普通にメモリだけで処理できると思います。GDBMはやめてHashで処理しましょう。 それから、基礎が抜けていると認識しているのであればちゃんと基礎から勉強しましょう。 ここはあなたの抜けている基礎をカバーするためにコードを代わりに書いてあげる場ではありません。成長を願って回答しています。
kzd847686

2019/02/26 13:04

無事にhashでメモリ上に載せることができ速く処理をすることができました。GDBMで6時間かかっていた処理がhashではなんと10分でできました! 大変参考になりました。ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問