data.tableパッケージで
⼤規模データをサクッと処理する
2013年11⽉9⽇
第35回Tokyo.R
@sfchaos
⾃⼰紹介

� TwitterID:@sfchaos
� お仕事:データマイニング

1
1. イントロダクション

2
データフレームは,
Rの最重要なデータ構造の⼀つ

データフレームとは,
Excelのワークシートのような
⾏列形式のデータ構造
3
例えば,
いつもよく出てくるirisデータセット
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1
5.1
3.5
1.4
0.2 setosa
2
4.9
3.0
1.4
0.2 setosa
3
4.7
3.2
1.3
0.2 setosa
4
4.6
3.1
1.5
0.2 setosa
5
5.0
3.6
1.4
0.2 setosa
6
5.4
3.9
1.7
0.4 setosa

アヤメの茎の⻑さ・幅と種類に関するデータ

4
reshape2パッケージ,
plyrパッケージなどを⽤いることにより,
ピボットテーブルなどの柔軟な処理も可能

5
天下のExcel様も
gkbrのデータフレーム!!

with data.frame
6
そんなデータフレームも,
結構処理が遅いことがある
> # データの読み込み
> system.time(usc.df <read.csv("../data/USCensus1990.data.txt"))
ユーザ
システム
経過
65.588 3.152
68.868

⽶国の1990年の国勢調査データ
出典:US Census(1990) Data Set
http://archive.ics.uci.edu/ml/datasets/US
+Census+Data+%281990%29
7
こんなとき,data.tableパッケージが
役⽴つかもしれない
> library(data.table)
data.table 1.8.10 For help type: help("data.table")
> system.time(usc.dt <fread("../data/USCensus1990.data.txt"))
ユーザ
システム
経過
3.244
0.040
3.300

出典:http://cran.r-project.org/web/packages/data.table/index.html

8
data.tableパッケージを⽤いることにより,
以下のような処理を⾼速に実現
�
�
�
�

データの読み込み
条件に合致した要素の抽出
層別の集計
テーブルのジョイン 等

9
2. data.tableパッケージひとめぐり

10
データ分析の流れ
外部からデータを
読み込むケース
データ

データの
⼊⼒
データ
加⼯・集計

マイニング

結果の
出⼒

結果

データの
⽣成
データを⽣成するケース

data.tableパッケージの
守備範囲
11
各⼯程の処理例とdata.tableの関数
⼯程
データの⼊⼒・変換

処理
データの読み込み

data.tableの関数
�fread

通常のRの関数
�read.csv/read.table
�scan 等

データフレームからのデータ
変換
データの加⼯・集計

�data.table

キーの付加

�setkey

--

グループ化の処理

�添字表記[[]], by引数

--

テーブルのジョイン

�merge

�merge

複数のリストの結合

�rbindlst

�do.call("rbind", リスト)

--

�do.call("cbind", リスト)
部分集合の取り出し

�subset

�subset

⾏の重複のチェック

�duplicated

�duplicated
※data.tableパッケージについては,
 他にも様々な関数がある

12
データの⼊⼒
� データ読み込み(fread関数を使⽤)
> library(data.table)
data.table 1.8.10 For help type: help("data.table")
> system.time(usc.dt <fread("../data/USCensus1990.data.txt"))
ユーザ システム 経過
3.244 0.040 3.300

13
データの⼊⼒
� ⽐較)データ読み込み(通常のread.csv関数)
> # データの読み込み
> system.time(usc.df <read.csv("../data/USCensus1990.data.txt"))
ユーザ   システム  経過
65.588 3.152
68.868

fread関数を⽤いることで20倍以上の⾼速化
14
データの⼊⼒
� 読み込んだデータテーブルの確認(⾏頭・⾏末)
> head(usc.dt)
caseid dAge dAncstry1 dAncstry2 iAvail iCitizen iClass dDepart ...
1: 10000
5
0
1
0
0
5
3 ...
2: 10001
6
1
1
0
0
7
5 ...
3: 10002
3
1
2
0
0
7
4 ...
4: 10003
4
1
2
0
0
1
3 ...
5: 10004
7
1
1
0
0
0
0 ...
6: 10005
1
1
2
0
0
0
0 ...
> tail(usc.dt)
caseid dAge dAncstry1 dAncstry2 iAvail iCitizen iClass dDepart ...
1: 2468279
3
3
1
0
0
1
5 ...
2: 2468280
7
1
2
0
0
0
0 ...
3: 2468281
1
1
2
0
0
0
0 ...
4: 2468282
3
3
1
0
0
1
2 ...
5: 2468283
6
0
1
0
0
1
3 ...
6: 2468284
2
3
1
0
4
0
0 ...

15
データの⼊⼒
� 読み込んだデータテーブルの確認(サイズ,表頭・表側)
> dim(usc.dt)
[1] 2458285
69
> dimnames(usc.dt)
[[1]]
NULL
[[2]]
[1] "caseid"
[7] "iClass"
[13] "iFertil"
[19] "dIncome2"
[25] "dIncome8"
[31] "iMay75880"
[37] "iOthrserv"
[43] "dRearning"
[49] "iRownchld"
[55] "iSchool"
[61] "dTravtime"
[67] "iYearsch"

"dAge"
"dDepart"
"dHispanic"
"dIncome3"
"dIndustry"
"iMeans"
"iPerscare"
"iRelat1"
"dRpincome"
"iSept80"
"iVietnam"
"iYearwrk"

表側はつかない

"dAncstry1"
"iDisabl1"
"dHour89"
"dIncome4"
"iKorean"
"iMilitary"
"dPOB"
"iRelat2"
"iRPOB"
"iSex"
"dWeek89"
"dYrsserv"

"dAncstry2"
"iDisabl2"
"dHours"
"dIncome5"
"iLang1"
"iMobility"
"dPoverty"
"iRemplpar"
"iRrelchld"
"iSubfam1"
"iWork89"

"iAvail"
"iEnglish"
"iImmigr"
"dIncome6"
"iLooking"
"iMobillim"
"dPwgt1"
"iRiders"
"iRspouse"
"iSubfam2"
"iWorklwk"

"iCitizen"
"iFeb55"
"dIncome1"
"dIncome7"
"iMarital"
"dOccup"
"iRagechld"
"iRlabor"
"iRvetserv"
"iTmpabsnt"
"iWWII"

16
データの⼊⼒
� メモリ上に⽣成されたデータテーブルのリストの確認
オブジェクト名
> tables()
NAME
NROW MB
[1,] usc.dt 2,458,285 648
⾏数
COLS
[1,]
caseid,dAge,dAncstry1,dAncstry2,iAvail,iCitizen,iClass,
dDepart,iDisabl1,iDisabl2
KEY
[1,]
表側(の⼀部)
Total: 648MB

17
データの変換
� データフレームからデータテーブルへの変換(data.table関数)
> system.time(usc.dt <- data.table(usc.df))
ユーザ
システム
経過
1.180
1.072
2.255

18
データ加⼯・集計
� キーの付加(setkey関数)
# キーの付加(dAge, dIncome1 をキーにする)
setkey(usc.dt, dAge, dIncome1)
# オブジェクトのリストの中にもキーが表⽰されている
tables()
NAME
NROW MB
[1,] usc.dt 2,458,285 648
COLS
[1,]
caseid,dAge,dAncstry1,dAncstry2,iAvail,iCitizen,iClass,
dDepart,iDisabl1,iDisabl2
KEY
キーが付加された
[1,] dAge,dIncome1
Total: 648MB
>
>
>
>

19
データ加⼯・集計
� バイナリサーチを⽤いた⾼速な要素抽出
> # 2つのキーの値によりデータの要素へのアクセスが可能
> system.time(x <- usc.dt[1, 1])
ユーザ
システム
経過
0.000
0.000
0.001

dAge=1 かつ
dIncome1=1の
⾏の取得

> # ⽐較: 通常のデータフレームを⽤いた場合
> system.time(y <- usc.df[usc.df$dAge==1 &
usc.df$dIncome1==1, ])
ユーザ
システム
経過
1.536
0.096
1.637

20
データ加⼯・集計
� グループ化処理による集計
> # キーの値ごとの層別集計
> system.time(x <- usc.dt[, sum(dIncome1), by=dAge])
ユーザ
システム
経過
0.032
0.000
0.033
> x
第2引数には集計処理を,
dAge
V1
by引数には集計軸を指定
1:
0
0
2:
1
0
3:
2 89043
4:
3 462080
5:
4 638323
6:
5 525549
7:
6 415373
8:
7 74411
21
データ加⼯・集計
� グループ化処理による集計
> # ⽐較: 通常のデータフレームを⽤いた場合
> system.time(y <- tapply(usc.df$dIncome1, usc.df$dAge,
sum))
ユーザ
システム
経過
1.580 0.004
1.584
> y
0
1
2
3
4
5
6
7
0
0 89043 462080 638323 525549 415373 74411

22
その他の機能
� テーブルの⾼速ジョイン(merge関数)
� テーブルの要素の抽出(subset関数)
� リファレンスによるオブジェクトの要素の値変更 等

23
3. まとめ

24
� データフレームは,とても便利なRのデータ
構造だが,⼤規模データの読み込みや処
理が遅いことがある.
� そんなときは,data.tableパッケージを⽤
いて,データの読み込み,集計,検索な
どの⾼速化を検討すべし.
25
� data.tableパッケージについては,R⾔語
上級ハンドブックにより詳しい説明がありま
す.

26

data.tableパッケージで大規模データをサクッと処理する