View
2.577
Download
5
Category
Preview:
Citation preview
14.07.02 Kashiwa.R #10
巨大な表を高速に扱うdata.table について
@yuifu
自己紹介• @yuifu
• 大学院生
• バイオインフォマティクス
http://www.slideshare.net/yuifu/fdr-kashiwar-3
data.table を紹介するスライドはすでに色々ありますが…
http://www.slideshare.net/sfchaos/datatable
(簡潔で分かりやすかったです)
でも、 data.table さんって data.frame さんとかなり違うの…
• data.frame で当たり前だと思ってたことが、当たり前じゃなかったり…
• そこで本発表では
• data.table を使おうとしたら data.frameと色々違ってて面倒だった点に重点を置いて紹介する
表
• データ解析でよく使われる
• 理解しやすい
イントロ
表には data.frame がよく使われる• 外部の表形式データを read.table, read.csv で読み込んだり
…
• R に用意されてるデータセットもたいてい data.frame
> class(USArrests)[1] "data.frame"> head(USArrests) Murder Assault UrbanPop RapeAlabama 13.2 236 58 21.2Alaska 10.0 263 48 44.5Arizona 8.1 294 80 31.0Arkansas 8.8 190 50 19.5California 9.0 276 91 40.6Colorado 7.9 204 78 38.7
イントロ
data.frame さんはちょっと…• data.frame で巨大な表を読み込むと…
• 読み込みが遅い• いちいち動作が重い• うっかり全行表示してしまうと辛い(固まる)
イントロ
遅くても待てばいい?
• ルーチンの作業を実行するならそうかもしれない
• データ解析だとルーチンでない作業が多い
• データ読み込んだり
• 加工したり
• 層別したり
• 集計したり
• → 対話的にデータをいじくるには速いに越したことはない
イントロ
そこで data.table
• 速い!
• 便利!
• うっかり全行表示しない!
http://photozou.jp/photo/show/1934405/188750786
イントロ
表の作成が速い
> grpsize = ceiling(1e8/26^2)> tt=system.time( DF <- data.frame(+ x=rep(LETTERS,each=26*grpsize),+ y=rep(letters,each=grpsize),+ v=runif(grpsize*26^2),+ stringsAsFactors=FALSE) + )> tt ユーザ システム 経過 18.319 9.352 35.238
> head(DF) x y v1 A a 0.52291182 A a 0.89705093 A a 0.63021304 A a 0.54247605 A a 0.21110726 A a 0.6619162
> grpsize = ceiling(1e8/26^2)> tt=system.time( DT <- data.table(+ x=rep(LETTERS,each=26*grpsize),+ y=rep(letters,each=grpsize),+ v=runif(grpsize*26^2)) + )> tt ユーザ システム 経過 6.866 0.980 8.787
> head(DT) x y v1: A a 0.43856272: A a 0.65080533: A a 0.79258304: A a 0.42202875: A a 0.84656196: A a 0.5719564
data.frame data.table
data.table の方が表の作成が速い!
data.tableの使い方
data.frame を data.table に変換
> dt_car <- data.table(cars)> head(dt_car) speed dist1: 4 22: 4 103: 7 44: 7 225: 8 166: 9 10
data.tableの使い方
表の読み込みが速い
> system.time(df <- read.table(filename, sep="\t", fill=T)) ユーザ システム 経過 7.472 0.176 7.738
> dim(df)[1] 626393 7
> system.time(dt <- fread(filename, sep="\t")) ユーザ システム 経過 0.387 0.028 0.416
> dim(dt)[1] 773042 7
data.frame data.table
data.table の方が表の読み込みが速い!
data.tableの使い方
全行表示しない
> dim(DT)[1] 100000004 3
> DT x y v1e+00: A a 0.43856272e+00: A a 0.65080533e+00: A a 0.79258304e+00: A a 0.42202875e+00: A a 0.8465619 --- 1e+08: Z z 0.27105131e+08: Z z 0.10012151e+08: Z z 0.71904531e+08: Z z 0.36776811e+08: Z z 0.4660653
data.tableの使い方
うっかり全行表示しようとしない!→ 安心!
tables() でメモリ上にある data.table オブジェクトを確認
> tables() NAME NROW MB COLS KEY [1,] ans2 147,929 4 x,y,v [2,] ans3 147,929 4 x,y,v x,y [3,] dt 773,042 40 method,V2,platform,source,V5,V6,year platform,method[4,] DT 100,000,004 2289 x,y,v x,y [5,] dt_car 50 1 speed,dist [6,] ss 26 1 x,V1 x Total: 2,339MB
data.tableの使い方
data.frame のようには要素にアクセスできない例
> dt method V2 platform source V5 V6 year 1: - - - - - - 2009 2: - - - - - - 2009 3: - - - - - - 2009 4: - - - - - - 2009 5: - - - - - - 2009 --- 773038: WGS Other unspecified GENOMIC - - 2012773039: WGS Other unspecified GENOMIC - - 2012773040: WGS Other unspecified GENOMIC - - 2012773041: WGS Other unspecified GENOMIC - - 2012773042: WGS Other unspecified GENOMIC - - 2012> dt[1,] method V2 platform source V5 V6 year1: - - - - - - 2009> dt[1,3][1] 3> dt[,3][1] 3
data.tableの使い方
[ ] の中の扱いが違う
• data.frame では、行と列の数字を入れる
> dt[i, j, ]
expression をいれる
key をいれる その他の引数を入れる
data.tableの使い方
i: 行へのアクセス
> dt x v1: b -1.079072452: b 0.925151703: b -0.023398634: a 2.064985475: a -1.03080796> dt[2,] x v1: b 0.9251517> dt[dt$x=="b",] x v1: b -1.079072452: b 0.925151703: b -0.02339863> dt["b",] 以下にエラー `[.data.table`(dt, "b", ) : When i is a data.table (or character vector), x must be keyed (i.e. sorted, and, marked as sorted) so data.table knows which columns to join to and take advantage of x being sorted. Call setkey(x,...) first, see ?setkey.
data.tableの使い方
i: キーによる行へのアクセス> setkey(dt, x)> tables() NAME NROW MB COLS KEY[1,] dt 5 1 x,v x [2,] dt_car 50 1 speed,dist Total: 2MB> dt["b",] x v1: b -1.079072452: b 0.925151703: b -0.02339863
data.tableの使い方
i: キーによる行へのアクセスは速い
> tt=system.time(+ ans1 <- DF[DF$x=="R" & DF$y=="h",])> tt ユーザ システム 経過 15.840 1.042 17.046
> tt=system.time(ans2 <- DT[DT$x=="R" & DT$y=="h",])> tt ユーザ システム 経過 6.756 0.368 7.124
data.frame data.table
> system.time(setkey(DT, x, y)) ユーザ システム 経過 0.688 0.178 0.871 > system.time(ans3 <- DT[J("R","h")]) ユーザ システム 経過 0.006 0.002 0.009
ベクトルを先頭からスキャンする場合
キーを設定し、二分探索を行う場合
キーを設定した方が速い!
data.tableの使い方
j: 集計する(例)
> DT[,sum(v)][1] 49994142
data.tableの使い方
> DT[,sum(v),by=x] x V1 1: A 1922034 2: B 1922008 3: C 1923013 4: D 1922349 5: E 1922904 6: F 1923302 7: G 1922370 8: H 1923551 9: I 192272710: J 192257311: K 192227612: L 192284313: M 192283714: N 192313715: O 192295816: P 192393717: Q 192278418: R 192324819: S 192278120: T 192296521: U 192416122: V 192255423: W 192300924: X 192265125: Y 192254326: Z 1922629 x V1
by で列名を指定すると指定した変数の値により行をグループ分けした上でsum(v) を行う
sum(v) を行う
j の位置では、列名は引用符で囲まない
> system.time(tt <- tapply(DT$v,DT$x,sum)) ユーザ システム 経過 35.287 14.561 56.807 > system.time(ss <- DT[,sum(v),by=x]) ユーザ システム 経過 1.704 0.441 2.395
tapply より速い!
j: expression を入れる
> dt_car[, plot(speed, dist)]NULL
> dt_car[, dist/speed] [1] 0.5000000 2.5000000 0.5714286 3.1428571 2.0000000 1.1111111 1.8000000 2.6000000 3.4000000 1.5454545[11] 2.5454545 1.1666667 1.6666667 2.0000000 2.3333333 2.0000000 2.6153846 2.6153846 3.5384615 1.8571429[21] 2.5714286 4.2857143 5.7142857 1.3333333 1.7333333 3.6000000 2.0000000 2.5000000 1.8823529 2.3529412[31] 2.9411765 2.3333333 3.1111111 4.2222222 4.6666667 1.8947368 2.4210526 3.5789474 1.6000000 2.4000000[41] 2.6000000 2.8000000 3.2000000 3.0000000 2.3478261 2.9166667 3.8333333 3.8750000 5.0000000 3.4000000
変数同士の計算ができたり
別の関数を実行したり
data.tableの使い方
data.frame と data.tabledata.tableの使い方
タスク data.table data.frame
表の作成 data.table data.frame
表の読み込み fread read.table
行の名前の設定 setkey rowname
列の名前の設定 setnames colnames
複数の表の結合 rbindlistcbind
rbindcbind
列の追加 :=cbind
data.frame
名前・発想が違うものについて
メモリ消費量はほぼ同じ
> dim(DF)[1] 100000004 3> object.size(DF)2400003488 bytes
> dim(DT)[1] 100000004 3> object.size(DT)2400004008 bytes
data.frame data.table
> system.time(setkey(DT, x, y)) ユーザ システム 経過 0.817 0.228 1.049 > object.size(DT)2400004272 bytes
10 億行 × 3列の表の場合
2つの列(変数)をキーに設定した後
速いのに、メモリ消費量はほぼ同じ!キーを設定した後でも、メモリ消費量はほぼ同じ!
実用例応用例
> dt <- fread("sra.list", sep=“\t")> setnames(dt, "V3", "platform")> setnames(dt, "V7", "year")> setnames(dt, "V1", "method")> setnames(dt, "V4", "source")> setkey(dt, source)> dat <- dt["GENOMIC", nrow(.SD), by=list(platform, source, year)]> dat <- dat[!grep("-|unsp", platform),]> library(ggplot2)> g <- ggplot(data.table(dat), aes(x=year, y=V1)) + + geom_bar(stat = "identity") ++ facet_wrap(~ platform) + + xlim(2008,2013) > print(g)
SRA で、 source がゲノム配列であるデータがよく読まれている platform は?
実用例応用例
> library(ggplot2)> g <- ggplot(data.table(dat), aes(x=year, y=V1)) + + geom_bar(stat = "identity") ++ facet_wrap(~ platform) + + xlim(2008,2013) > print(g)
まとめ
• 巨大な表は data.table で扱いましょう
参考文献
• CRAN の data.table パッケージのページ
• http://cran.r-project.org/web/packages/data.table/index.html
• 英語で詳しく書いてある
• R 言語上級ハンドブック
• 日本語で詳しく書いてある
Recommended