読者です 読者をやめる 読者になる 読者になる

300億円欲しい

メジャーリーグのデータ解析します

data.tableでmelt的な処理をしたい

Rの話です.

ggplotしたいのでreshape2のmeltをする場面って結構ありますよね.
meltはdataframeの処理です.

しかし, 時は2014年. dataframeからdata.tableに移行していきたいですよね.
http://cran.r-project.org/web/packages/data.table/vignettes/datatable-intro.pdf

今回は, data.tableでmelt的な処理をします.

data.tableでmelt的な処理

トライアスロンの記録が入っているcsvがありました.
http://chrisladroue.com/files/stratford.csv
これを例に取ります.

まずは読み込み. freadにアドレスを渡すだけです.

> library(data.table)
> times =  fread(http://chrisladroue.com/files/stratford.csv)
> times[,list(Position, Swim, Cycle, Run, Total)]
     Position StartingPosition StartingTime Age Category     Swim    Cycle      Run    Total
  1:        1              441     08:44:45  32        F 00:06:04 00:36:46 00:19:11 01:02:01
  2:        2                5     08:46:00  35        G 00:05:55 00:37:23 00:20:18 01:03:36
  3:        3               26     08:56:00  23        D 00:06:28 00:37:39 00:19:30 01:03:37
  4:        4              443     10:35:30  31        F                   00:20:51 01:04:09
  5:        5              445     10:36:00  27        E 00:06:43 00:37:26 00:21:36 01:05:45
 ---                                                                                        
389:      389               24     08:50:45  32        F                            02:12:32
390:      390              253     09:48:00  31        F 00:06:52                   02:41:39
391:      391               45     08:56:00  39        G                            03:24:28
392:      392               46     08:56:15  42        H                            03:29:02
393:      393                8     08:46:45  35        G                            03:49:43

トライアスロンなので, 水泳, 自転車, マラソン, 総合タイムと総合順位が入っています.
最後の方はNAばかりです. 途中棄権ですね.

各種目の名前を列に入れて,
時間を新しく列に入れたデータのほうが扱いやすいことがあります. ggplotしたいときとか.
今までなら, reshape2のmeltを使います.

> library(reshape2)
>meltedTimes<-melt( times,
  c("StartingPosition","Category","Position"),
  c("Swim","Cycle","Run","Total"),
  variable_name="Discipline")
>head(meltedTimes)
  StartingPosition Category Position Discipline value
1              441        F        1       Swim  6.07
2                5        G        2       Swim  5.92
3               26        D        3       Swim  6.47
4              445        E        5       Swim  6.72
5               32        F        6       Swim  6.42
6                2        H        7       Swim  6.03

> class(meltedTimes)
[1] "data.frame"

...めんどくさいですし,
出力は欲しい形になっていますが, data.frameになっていてウザいです.

data.tableに移行しましょう.
data.tableの中で書くと, こんな感じです.

>times = times[ , list(Discipline=names(.SD), Time=unlist(.SD)), 
            key=list(Position, StartingPosition, StartingTime, Age, Category)]
> times
      Position StartingPosition StartingTime Age Category Discipline     Time
   1:        1              441     08:44:45  32        F       Swim 00:06:04
   2:        1              441     08:44:45  32        F      Cycle 00:36:46
   3:        1              441     08:44:45  32        F        Run 00:19:11
   4:        1              441     08:44:45  32        F      Total 01:02:01
   5:        2                5     08:46:00  35        G       Swim 00:05:55
  ---                                                                        
1568:      392               46     08:56:15  42        H      Total 03:29:02
1569:      393                8     08:46:45  35        G       Swim         
1570:      393                8     08:46:45  35        G      Cycle         
1571:      393                8     08:46:45  35        G        Run         
1572:      393                8     08:46:45  35        G      Total 03:49:43

残す列名をkeyに指定すれば, 残りの列をmeltしてくれます.
.SDという変数がよく分かりませんが, これはkeyに指定しなかった列が勝手に入っているらしいです.

出力もdata.tableなので扱いやすいです.

追記: meltでmelt的な処理

dplyr特有のキモい記法である %.% を使ってmeltに流せることが分かりました.
r - reshape2: multiple results of aggregation function? - Stack Overflow

> time_melted = time %.% select(Position, Swim, Cycle, Run) %.% melt('Position')
> head(time_melted)
  Position variable    value
1        1     Swim 00:06:04
2        2     Swim 00:05:55
3        3     Swim 00:06:28
4        4     Swim         
5        5     Swim 00:06:43
6        6     Swim 00:06:25

%.%でmelt関数にパイプして, 引数をIDとして扱ってくれるみたいです.
今回は, Positionをidとして, Swim, Cycle, Runの列をmeltしてくれました.
ただ, 出力はdataframeになるので, 注意が必要になる場合があります.
大きなデータを呼び出すと死にます.