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

ushi-goroshiの雑記帳

統計や機械学習の話題を中心に、思うがままに

Microsoft R Clientによる大規模データの分析

Revolution Analyticsを買収したMicrosoftが、Revolution R Openに代わりMicrosoft R OpenというRのラッパーのようなものを出している。それに更に大規模データ分析用の独自開発パッケージを追加したMicrosoft R Client(MRC)というツールがあり、MRCの独自パッケージ{MicrosoftML}に実装されているrxGLMを用いて簡単な動作テストを実行したのでその結果を記しておく。MRCのインストールについてはこちらを参照:

bigdata4people.blogspot.jp

まずは大規模データを読み込むために{readr}パッケージをインストール。なお今回はAWSに新しく立てたWindows Serverを使うので、{tidyverse}を使って必要そうなパッケージをまとめてインストールすることにする。

install.packages("tidyverse")

続いてライブラリの読み込みと作業ディレクトリの変更を行う。

library(readr)
library(MicrosoftML)
library(RevoScaleR)
library(lattice)

wk_dir <-"C:/Users/Administrator/Desktop/MicrosoftML"
setwd(wk_dir)


データを読み込む。{MicrosoftML}がハイパフォーマンスやスケーラブルを謳っているので、そこそこの大規模データ(500万行×18列、2GB程度)を使用してみた。サンプルデータはこちらから取得した。

UCI Machine Learning Repository

### 大規模データの読み込みにreadr::read_csvを使用
### ヘッダーがないのでcol_namesはFALSEにする
datTmp <- read_csv("Data/SUSY.csv",
                   col_names = FALSE)

### X1が目的変数、X2〜X5を説明変数として使用した
### 全カラムを使用した時の結果は後日

### まずは結果の比較用にglmを実行。まぁ、動かないだろうと予想
start_time <- Sys.time()
res_GLM    <- glm(X1 ~ X2 + X3 + X4 + X5, 
                  family = binomial("logit"), 
                  data = datTmp)
end_time   <- Sys.time()
print(end_time - start_time)
# 予想通りメモリの割り当てに失敗した旨のエラーメッセージを受け取る。。。

### MicrosoftMLではどうか。rxGLMが{MicrosoftML}におけるGLMに相当する関数。
start_time <- Sys.time()
res_rxGLM  <- rxGlm(X1 ~ X2 + X3 + X4 + X5, 
                    family = binomial("logit"), 
                    data = datTmp)
end_time   <- Sys.time()
> print(end_time - start_time)
Time difference of 9.806952 secs

なんと、500万行のデータのglmが10秒足らずで実行できた。なおWindowsインスタンスAWSでのt2.medium(64bit、RAM4GB)を使用しており、特別スペックが良いという訳ではない。

このままではglmとの比較ができないので、もう少しデータを減らして再挑戦してみる。

### gcを使ってメモリを解放しておく
gc()
gc()

### 使用データを100万行にする
datTmp_1MM <- datTmp[1:1000000, ]

### 再実行
start_time <- Sys.time()
res_rxGLM_02  <- rxGlm(X1 ~ X2 + X3 + X4 + X5, 
                      family = binomial("logit"), 
                      data = datTmp_1MM)
end_time   <- Sys.time()
print(end_time - start_time)
# Time difference of 1.839989 secs

gc()
gc()
start_time <- Sys.time()
res_GLM_02    <- glm(X1 ~ X2 + X3 + X4 + X5, 
                    family = binomial("logit"), 
                    data = datTmp_1MM)
end_time   <- Sys.time()
>print(end_time - start_time)
# Time difference of 7.471947 secs

今度はglmでも10秒かからず実行できた。
そこで両者の結果が一致するかを確認する。

coef(res_GLM_02) 
  (Intercept)            X2            X3            X4            X5 
-1.7128408655  2.6384939818  0.0002822391 -0.0012571389 -0.9573449310 

coef(res_rxGLM_02)
  (Intercept)            X2            X3            X4            X5 
-1.7128408655  2.6384939818  0.0002822391 -0.0012571389 -0.9573449310 

回帰係数は両者で一致しており、問題なさそうだ。
続いてsummaryを実行する。

### まずはrxGLM
> summary(res_rxGLM_02)
Call:
rxGlm(formula = X1 ~ X2 + X3 + X4 + X5, data = datTmp_1MM, family = binomial("logit"))

Generalized Linear Model Results for: X1 ~ X2 + X3 + X4 + X5
Data: datTmp_1MM
Dependent variable(s): X1
Total independent variables: 5 
Number of valid observations: 1e+06
Number of missing observations: 0 
Family-link: binomial-logit 
 
Residual deviance: 1160233.9234 (on 999995 degrees of freedom)
 
Coefficients:
              Estimate Std. Error  z value Pr(>|z|)    
(Intercept) -1.7128409  0.0052066 -328.976 2.22e-16 ***
X2           2.6384940  0.0079644  331.285 2.22e-16 ***
X3           0.0002822  0.0022039    0.128    0.898    
X4          -0.0012571  0.0022356   -0.562    0.574    
X5          -0.9573449  0.0062846 -152.332 2.22e-16 ***
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

Condition number of final variance-covariance matrix: 7.0668 
Number of iterations: 6

### 続いてglm
> summary(res_GLM_02)
Call:
glm(formula = X1 ~ X2 + X3 + X4 + X5, family = binomial("logit"), 
    data = datTmp_1MM)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-8.4904  -0.8894  -0.7140   1.0654   3.0185  

Coefficients:
              Estimate Std. Error  z value Pr(>|z|)    
(Intercept) -1.7128409  0.0052066 -328.977   <2e-16 ***
X2           2.6384940  0.0079644  331.287   <2e-16 ***
X3           0.0002822  0.0022039    0.128    0.898    
X4          -0.0012571  0.0022356   -0.562    0.574    
X5          -0.9573449  0.0062846 -152.333   <2e-16 ***
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 1379205  on 999999  degrees of freedom
Residual deviance: 1160234  on 999995  degrees of freedom
AIC: 1160244

Number of Fisher Scoring iterations: 5

summaryの結果も両者で大きく異なる様子はない。rxGLMの方でもう少し情報を追加したぐらいか。

一旦動作テストは以上である。{MicrosoftML}は少なくともオリジナルのRのglmと比較して大規模データに強いというのは間違いなさそうで、Rの弱点をカバーできる作りになっているようだ。従来MicrosoftSQL ServerとRを連携させることで大規模データへの対応を行ってきたイメージがあったが、R単体(と言えないかもしれないが)でこれぐらいの規模のデータを処理できるのであれば、ウェブログを触るような状況とならない限りR一本で大抵の処理はできるように思う。RユーザーとしてはMRCを含めて近年のMicrosoftのRへの貢献はかなり大きいと感じている。

また今回の記事では割愛したが、{MicrosoftML}ではrxGLM以外にも様々な関数が用意されており、特に二項分類のための”Fast Tree"と呼ばれるアルゴリズムを実装した関数はかなり強力な感触を受けた。こちらの検証結果も後日書いてみようと思う。