LoginSignup
30
37

More than 5 years have passed since last update.

100MB超えたらnysolが良さそう

Last updated at Posted at 2014-12-09

野球データを速く集計したい (R vs nysol)

はじめに

R advent calendar, 12月10日分です.

nysolを使ってみた, という話です.

速度比較の記事を見ると, nysol使いたくなりますよね.

使ってみたら案外イケました. コードも書きやすいです.

野球データ解析のコードを例に, plyr, dplyr, nysolのコードと処理速度を比較してみました.

メジャーリーグ: 大チャンスでの得点率

メジャーリーグで, 犠牲フライでも点が入る場面で, ちゃんと得点を挙げてくれる選手を調べます.

2013年メジャーリーグの全打席結果データ(77MB)を利用して, 集計してみます.

データはretrosheetからダウンロード出来ますし, githubにもあります. .

集計は, 以下の3つの方法で行います.

  • data.frame + plyr

  • data.table + dplyr

  • nysol

集計からランキング表示まで, どの方法が一番速いでしょうか.

data.frame + plyrで集計

何も工夫せずに書いている感じです. 去年の私の知識で頑張ったのでしょう.

start = proc.time()
library(plyr)
library(stringr)
# データ読み込み
read_time = system.time(data2013 <- read.csv("all2013.csv"))

# 打者結果だけ
data2013 <- subset(data2013, BAT_EVENT_FL == TRUE)

# 大チャンス場面かどうかをSuperChanceに入れる
data2013$SuperChance <- with(data2013, ifelse(OUTS_CT<2 & BASE3_RUN_ID!="" , 1,0 ))

# 大チャンス場面で点が入ったかどうかをSuperChanceScoredに入れる
data2013$SuperChanceScored <- with(data2013, ifelse(OUTS_CT<2 & BASE3_RUN_ID!="" & str_detect(EVENT_TX,"3-H"), 1,0 ))

# ddplyで要約
data2013.SuperChance <- ddply(data2013, .(BAT_ID), summarize, 
                              SuperChance = sum(SuperChance),
                              SuperChanceScored = sum(SuperChanceScored),
                              SuperChanceScoredRate = SuperChanceScored/SuperChance)
# 10打席以上
data2013.SuperChance.over10chance <- subset(data2013.SuperChance, SuperChance>10)
# 得点ゲット率で並び替え 
data2013.SuperChance.over10chance.arranged <- arrange(data2013.SuperChance.over10chance, desc(SuperChance))
# ランキング
head(data2013.SuperChance.over10chance.arranged, 10)
##      BAT_ID SuperChance SuperChanceScored SuperChanceScoredRate
## 1  philb001          65                39             0.6000000
## 2  brucj001          54                30             0.5555556
## 3  pedrd001          54                33             0.6111111
## 4  vottj001          53                21             0.3962264
## 5  fielp001          50                27             0.5400000
## 6  mccua001          50                22             0.4400000
## 7  canor001          49                28             0.5714286
## 8  napom001          47                21             0.4468085
## 9  andre001          46                24             0.5217391
## 10 belta001          46                21             0.4565217
end = proc.time()

処理時間

## 全体の処理時間
end - start
##    user  system elapsed 
##  21.422   0.570  22.051
## データ読み込み時間
read_time
##    user  system elapsed 
##  18.810   0.385  19.238

読み込みに19.238秒, 全体の処理時間が22.051秒.

大半がデータ読み込み時間だ, ということでした.

subsetとかddplyとか, 久しぶりに見ました. 2度と使わないと思います.

data.table + dplyrで集計

freadで読み込んでdplyrで集計しましょう.

start2 = proc.time()
library(data.table)
library(dplyr)
library(stringr)

## データ読み込み
read_time2 = system.time(data2013 <- fread("all2013.csv"))

## 大チャンスに強い打者ランキング作成
data2013 %>% 
  filter(BAT_EVENT_FL=="T") %>% 
  mutate(SUPER_CHANCE=ifelse((OUTS_CT<2 & BASE3_RUN_ID!=""), 1, 0)) %>% 
  mutate(SUPER_CHANCE_SCORED = 
           ifelse(OUTS_CT<2 & BASE3_RUN_ID!="" & str_detect(EVENT_TX,"3-H"), 1, 0)) %>% 
  group_by(BAT_ID) %>% 
  summarise(SUPER_CHANCE=sum(SUPER_CHANCE), 
            SUPER_CHANCE_SCORED = sum(SUPER_CHANCE_SCORED)) %>% 
  mutate(SUPER_CHANCE_SCORED_RATE = SUPER_CHANCE_SCORED/SUPER_CHANCE) %>%
  filter(SUPER_CHANCE>10) %>% 
  arrange(desc(SUPER_CHANCE_SCORED_RATE)) 
## Source: local data table [340 x 4]
## 
##      BAT_ID SUPER_CHANCE SUPER_CHANCE_SCORED SUPER_CHANCE_SCORED_RATE
## 1  robeb003           15                  14                0.9333333
## 2  blank002           11                  10                0.9090909
## 3  bourm001           20                  17                0.8500000
## 4  reyej001           12                  10                0.8333333
## 5  peres002           21                  17                0.8095238
## 6  suzuk001           15                  12                0.8000000
## 7  lombs002           14                  11                0.7857143
## 8  utlec001           29                  22                0.7586207
## 9  carpm001           20                  15                0.7500000
## 10 encae001           20                  15                0.7500000
## ..      ...          ...                 ...                      ...
end2 = proc.time()

処理時間

## 全体の処理時間
end2 - start2
##    user  system elapsed 
##   3.348   0.343   3.791
## データ読み込み時間
read_time2
##    user  system elapsed 
##   1.105   0.078   1.219

読み込みに1.219秒, 全体の処理時間が3.791秒.

だいぶ速くなりました.

nysolで集計

# 処理に使うコード
cat ./superChance.bash
## #!/bin/bash
## 
## cat ./all2013.csv | 
##   mselstr f=BAT_EVENT_FL v=T | 
##   mcal c='if(${OUTS_CT}<2 && $s{BASE3_RUN_ID}!="", 1, 0)' a="SUPER_CHANCE" | 
##   mcal c='if(${OUTS_CT}<2 && $s{BASE3_RUN_ID}!="" && regexs($s{EVENT_TX}, "3-H"),1, 0)' \
##     a="SUPER_CHANCE_SCORED" | 
##   mcut f=BAT_ID,SUPER_CHANCE,SUPER_CHANCE_SCORED | 
##   msum k=BAT_ID f=SUPER_CHANCE,SUPER_CHANCE_SCORED | 
##   mcal c='${SUPER_CHANCE_SCORED}/${SUPER_CHANCE}' a="SUPER_CHANCE_SCORED_RATE" | 
##   msel c='${SUPER_CHANCE}>10' | 
##   msortf f=SUPER_CHANCE_SCORED_RATE%nr | 
##   head -n 10

dplyrで書いたコードと, ほとんど同じ頭の使い方で書けます.

処理時間を測ってみます.

# 処理時間の計測
time ./superChance.bash
## BAT_ID,SUPER_CHANCE,SUPER_CHANCE_SCORED,SUPER_CHANCE_SCORED_RATE%0nr
## robeb003,15,14,0.9333333333
## blank002,11,10,0.9090909091
## bourm001,20,17,0.85
## reyej001,12,10,0.8333333333
## peres002,21,17,0.8095238095
## suzuk001,15,12,0.8
## lombs002,14,11,0.7857142857
## utlec001,29,22,0.7586206897
## encae001,20,15,0.75
## 
## real 0m1.950s
## user 0m2.134s
## sys  0m0.345s

あまり変わらないような... データが数10MBですからね. こんなもんかと.

ここまでのまとめ

nysolが1番速いですが, そこまで性能差を感じません.

データの大きさに依存すると思います.

10MBオーダーなら, data.table::freadしてdplyrでいいと思いました.

追加実験: 野球データ(80年分:4.3GB)を集計したい

これまでは2013年の結果データ(77MB)を使っていました.

データを大きくして, 同じ処理を行ってみます.

1921年から2013年までのメジャーリーグ打席結果データを全て繋げて, 集計してみます. 4.3GBあります. ビッグデータです.

コードは同じです. 結果だけ載せます. 手元では, こうなりました.

  • data.frame + plyr 実行不可能

  • data.table + dplyr 20分

  • nysol 1分16秒

なるほど. nysol. 凄い.

まとめ

100MBを超えたくらいから, Rへのデータ読み込みがキツくなってくると思います.

そこでnysol. dplyrのノリでなかなか自由に書けて楽しいです.

データが大きくになるにつれて, nysolが強くなっていきます.

nysolのmコマンドを覚えておいて, 状況に応じてRと使い分けていくといいかな, と思いました.

以上です.

30
37
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
37