裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

fread はお勧め,それ以外は...

2015年11月26日 | ブログラミング

たぶん,前のページを読んだ人は,「なぜ fread を使わないのだ」と,怒りに震えていることだろうwww

> library(data.table)
> system.time(dat1 <- read.csv("aq"))
   ユーザ   システム       経過  
    44.938      1.164     45.952

に対して

> system.time(dat2 <- fread("aq"))
Read 15300000 rows and 6 (of 6) columns from 0.266 GB file in 00:00:05
f 6) columns from 0.266 GB file in 00:00:05
   ユーザ   システム       経過  
     4.785      0.131      4.856

なので,10倍速い。AWK なんていうものも,及びが付かない(当たり前だ。AWK はインタプリタでしかも数値も内部では文字として保持しているのだから)。

key を設定しておくといろいろ便利なこともあるが,しておかなくても十分高速だ。

> system.time(setkey(dat2, Month))
   ユーザ   システム       経過  
     0.538      0.025      0.559

「データテーブル[i, j, その他いろいろな引数]」という書式で,かなりのデータ処理が出来る。

しかも,「by reference」でやるので,余計なメモリを使わない。by reference(参照渡し) は,プログラム言語をやった人は知っている人が多い。関数に引数をわたすとき,call by value と call by reference の区別がある。普通の R 関数は call by value(値渡し) で引数を受けるので,関数内部で値を変更しても,呼び出した側の値は変わらない。大元を変えるためには,関数の戻り値を代入してやらないといけない。そんなこんなで,メモリも(コピーを含む)処理時間もコストがかかる。call by reference は,メモリ番地を引き渡すので,ある番地を書き換えたら,大元が書き換わる(というか,大元しかないのだが)。

なんやかやいったけど,結局何がいいたいかといえば,「以下のようにすれば,高速処理が出来る」。

> system.time(print(dat2[, list(m=mean(Temp), s=sd(Temp)), by=Month]))
   Month        m        s
1:     5 65.54839 6.743403
2:     6 79.10000 6.487682
3:     7 83.90323 4.245338
4:     8 83.96774 6.478172
5:     9 76.90000 8.215231
   ユーザ   システム       経過  
     0.281      0.015      0.284

また,dplyr というやつを使えば,(好き嫌いはあるが)以下のようにして,ある程度高速処理ができる。

> library(dplyr)
> system.time(dat2 %>% group_by(Month) %>% summarize(m=mean(Temp), s=sd(Temp)) %>% print)
Source: local data table [5 x 3]

  Month        m        s
  (int)    (dbl)    (dbl)
1     5 65.54839 6.743403
2     6 79.10000 6.487682
3     7 83.90323 4.245338
4     8 83.96774 6.478172
5     9 76.90000 8.215231
   ユーザ   システム       経過  
     0.397      0.046      0.431

しかし,そんなことしなくてもねぇ!
data.frame で split,sapply を使って,Month ごとの Temp の平均値と標準偏差を計算してみても,結構速い。2,3倍遅いと言っても,これだけの計算を1秒未満でやれているのだから,無問題。

> system.time(print(sapply(split(dat1$Temp, dat1$Month), function(x) c(m=mean(x), s=sd(x)))))
          5         6         7         8         9
m 65.548387 79.100000 83.903226 83.967742 76.900000
s  6.743403  6.487682  4.245338  6.478172  8.215231
   ユーザ   システム       経過  
     0.929      0.129      1.041

お勧めは,入力だけは fread でさっさと済ませて,あとは慣れ親しんだdata.frame で処理する。
data.table は setDF で data.frame に,by reference で変換できる(as.data.frame を使う例を示している人が多いけど,as.data.frame では,by value なのでね)。

> class(dat2)
[1] "data.table" "data.frame"
> setDF(dat2)
> class(dat2)
[1] "data.frame"

data.frame に読み込むには,data.table=FALSE オプションをつければよい(これも,言及している人が少ない。オンラインヘルプを隅から隅まで読めば,目から鱗がポロポロ落ちる...ということもあるものだ)。

> system.time(dat3 <- fread("aq", data.table=FALSE))
Read 15300000 rows and 6 (of 6) columns from 0.266 GB file in 00:00:06
f 6) columns from 0.266 GB file in 00:00:06
   ユーザ   システム       経過  
     4.903      0.153      4.950
> class(dat3)
[1] "data.frame"

逆に data.frame を data.table にするには,setDT を使う。

> class(dat1)
[1] "data.frame"
> setDT(dat1)
> class(dat1)
[1] "data.table" "data.frame"

コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« ちょっとしたことをやるなら ... | トップ | フェイスブック利用者 »
最新の画像もっと見る

コメントを投稿

ブログラミング」カテゴリの最新記事