Rあんなときこんなとき
~いつか役に立つ(かもしれない)Tips~

       2011年3月5日
       第12回 TokyoR
         @sfchaos
本発表の趣旨

� Rに初めて触れた頃,それまでに使っていたCや
  C++に比べて利便性が高いと思ったものの,お作
  法など分からないことがたくさんありました.
� 本発表では,特に私がRを触れた初期の頃に調べ
  たりつまづいたポイントを中心に,6つのTipsに
  ついてクイズ形式で議論したいと思います.




                         1
アジェンダ

1. 自己紹介
2.クイズで議論! RのTips
3. まとめ




                   2
アジェンダ

1. 自己紹介
2.クイズで議論! RのTips
3. まとめ




                   3
自己紹介

� TwitterID: @sfchaos
� 出身地: 埼玉県
� 職業:コンサルタント
  � 数年間,金融工学のモデル構築・データ解析
  � 最近,大規模データ解析に着手(Hadoop/Mahout)
� 趣味:登山
� 学生時代の専攻は物理・応用数学(非線形力学
  系・カオス)




                                    4
� 私とR
   � データ解析の仕事に携わりRを使い始めた.
   � 最近はRでの大規模データ解析に興味がある.
2007         2008     2009      2010            2011

                    データ解析
                    (金融工学)

                                         大規模
                                         データ
                                         解析

          Rの基礎とプログラミング技法
                                Software for
       R Tips                   data analysis
       (Webサイト)
         RjpWiki        CRANマニュアル
         (Webサイト)
                                                   5
� 私とR
   � データ解析の仕事に携わりRを使い始めた.
   � 最近はRでの大規模データ解析に興味がある.
2007          2008      2009        2010         2011

                     データ解析
                     (金融工学)
          今
          日                                大規模
          の                                データ
          発                                解析
          表
            の
            Rの基礎とプログラミング技法
              範
                囲                Software for
       R Tips                    data analysis
       (Webサイト)
         RjpWiki        CRANマニュアル
         (Webサイト)
                                                    6
アジェンダ

1. 自己紹介
2.クイズで議論! RのTips
3. まとめ




                   7
問題1
【ファイルの読み込み】


              8
� 自分で作成した関数を格納したファイルを読み
  込んでいます.
� 量が多くて大変です.
� どうすれば良いでしょうか.


> source("a.r")
> source("b.r")
> source("c.r")
> source("d.r")
...
> source("z.r")




                          9
【答え】
読み込み用の関数を別途作成する



                  10
� 読み込み用関数を作成
readfile.r
readfile <- function()
{
  fn.all <- c("a.r", "b.r", (中略), "z.r")
  for (fn in fn.all) {
    source(fn)
    cat(fn, "n")
  }
}


� 次のコマンドを実行
> source("readfile.r")
> readfile()


                                           11
� 読み込み用関数を作成
readfile.r
readfile <- function()
{
  fn.all <- c("a.r", "b.r", (中略), "z.r")
  for (fn in fn.all) {
    source(fn)
    cat(fn, "n")
  }
}


� 次のコマンドを実行

> source("readfile.r"); readfile()
                                           実は1行で書ける!

                                                       12
(ご参考)

� 毎回,必ず読み込むファイルがある場合は,作
  業フォルダ直下の.Rprofileファイルの.First関
  数に記述しておくことも一つの手.
.Rprofile
.First <- function()
{
  inputdir <- "C:UserssfchaoslibR"
  fn.all <- paste(inputdir, c("lib.r", "util.r"))
  for (fn in fn.all) {
    source(fn)
    cat(fn, "n")
  }
}

C:UserssfchaoslibRlib.r
C:UserssfchaoslibRutil.r
>

                                                    13
あまり派手にやると,
不要な関数を読み込んで時間がかかるので
     おススメしません!




                  14
第2問
【データ・ファイルの管理】


            15
� Rを使用してデータ解析を行っています.
� 次のコードは,データをファイルから読み込み,データ
  の一部を変更し,ファイルに書き出しています.
� 実行すると,望みどおりの動作をします.
� このコードには問題はないでしょうか?


> getwd()
[1] "C:/Users/sfchaos/TokyoR/R_Tips(TokyoR#12)/work"
> my.iris <- read.table("iris.csv", sep=",") # データの入力
> my.iris[1:5, 1] <- 3
> write.table(my.iris, "my_iris.csv", sep=",") # データの出力




                                                          16
【答え】
      問題あり!!
  入力データ格納フォルダ,
     作業フォルダ,
  出力データ格納フォルダが
すべて同じフォルダになっている
                  17
� データ解析は次のフローに従って行う.

 入力データ     解析     出力データ




                          18
� フォルダも対応して別々に作ると良い.

 入力データ     解析     出力データ




  data    work    output




                           19
� では,入力データ格納フォルダ("data"フォル
  ダ)のデータを作業フォルダで扱うには?
� 2つの方法がある.
 1)入力データ格納フォルダで作成したオブジェクトを
   作業フォルダで読み込む
 2)作業フォルダで,関数の引数に読み込む入力データ
   のファイル名を指定する




                             20
1) 入力データ格納フォルダで作成したオブジェク
  トを作業フォルダで読み込む

入力データ格納フォルダでの作業

> getwd()
[1] "C:/Users/sfchaos/TokyoR/R_Tips(TokyoR#12)/data"
> my.iris <- read.table("iris.csv", sep=",")
> assign("my.iris", my.iris, pos=1) # 現在の環境にオブジェクトを作成
> quit # 保存してから終了する




                                                        21
作業フォルダでの作業
> getwd()
[1] "C:/Users/sfchaos/TokyoR/R_Tips(TokyoR#12)/work"
> attach("../data/.RData")
> ls()
character(0)
> search()
[1] ".GlobalEnv"           "file:../data/.RData"
...
> ls(pos=2)
[1] "my.iris"




                                                       22
2) 作業フォルダで,関数の引数に読み込む入力
  データのファイル名を指定する
work/hoge.r
hoge <- function(fn="../data/my_iris.csv")
{
  my.iris <- read.table(fn, sep=",")
  (後略)
}




> source("hoge.r")
> hoge()




                                             23
データフォルダを複数作成する場合は,こうすると良い
work/hoge2.r
hoge2 <- function(datadir="../data/", fn="my_iris.csv")
{
  my.iris <- read.table(paste(datadir, fn, sep=""), sep=",")
  (後略)                    「入力データフォルダ名」と
}
                          「入力データファイル名」を分離




                                                               24
第3問
【NA/NaN/Infの判定】

                  25
� データの中に存在するNAやNaNに加えて,Infも
  調べようとしています.
� ところが,is.na関数やis.nan関数を使っても
  Infは検出できません.
� NA, NaNも調べられて,なおかつInfも調べるた
  めにはどうすれば良いでしょうか?

> x
[1]   1    5 NA    3 NaN   9   6 Inf
> is.nan(x)
[1] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
> is.na(x)
[1] FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE




                                                     26
【答え】
is.finite関数を使用する



                   27
> x
[1]   1   5 NA  3 NaN  9   6 Inf
> is.finite(x)
[1] TRUE TRUE FALSE TRUE FALSE TRUE   TRUE FALSE




                                                   28
第4問
【総称型関数】


          29
� Rにも慣れてきて,パッケージの関数の中身を確
  認したいと思うようになりました.
� ところが,次の表示が出て中身が確認できませ
  ん.
� 中身を確認する関数を調べるにはどうすれば良
  いでしょうか?

> install.packages("randomForest")
> library(randomForest)
> randomForest
function (x, ...)
UseMethod("randomForest")
<environment: namespace:randomForest>



                                        30
【答え】
methods関数で調べる



                31
� 総称型関数とは?(plot関数の例)

> x <- runif(10)
> class(x)
[1] "numeric"
> print(x)
 [1] 0.03060976 0.78413098 0.79548343 0.15108456 0.70864539 0.10040559
 [7] 0.18165933 0.90008356 0.46093800 0.52717448
> y <- sample(1:10, 100, replace=TRUE)
> y.tbl <- table(y)
> class(y)
[1] "table"
> print(y.tbl)
 1 2 3 4 5 6 7 8 9 10
11 16 13 8 11 15 9 7 8 2

                                       ベクトルでも行列でも
                                       同じprint関数で表示できる!
                                                                   32
print関数

> print
function (x, ...)
UseMethod("print")
<environment: namespace:base>




                                33
ベクトル用print関数

> print.default
function (x, digits = NULL, quote = TRUE, na.print = NULL, print.gap = NULL,
    right = FALSE, max = NULL, useSource = TRUE, ...)
{
    noOpt <- missing(digits) && missing(quote) && missing(na.print) &&
        missing(print.gap) && missing(right) && missing(max) &&
        missing(useSource) && length(list(...)) == 0L
    .Internal(print.default(x, digits, quote, na.print, print.gap,
        right, max, useSource, noOpt))
}
<environment: namespace:base>




                                                                               34
table用print関数
> print.table
function (x, digits = getOption("digits"), quote = FALSE, na.print = "",
    zero.print = "0", justify = "none", ...)
{
    xx <- format(unclass(x), digits = digits, justify = justify)
    if (any(ina <- is.na(x)))
        xx[ina] <- na.print
    if (zero.print != "0" && any(i0 <- !ina & x == 0) && all(x ==
        round(x)))
        xx[i0] <- sub("0", zero.print, xx[i0])
    if (is.numeric(x) || is.complex(x))
        print(xx, quote = quote, right = TRUE, ...)
    else print(xx, quote = quote, ...)
    invisible(x)
}
<environment: namespace:base>



                                                                           35
� 総称型関数はmethods関数で調べられる


> methods(randomForest)
[1] randomForest.default* randomForest.formula*

   Non-visible functions are asterisked




                                                  36
第5問
【総称型関数(続き)】


              37
� 第4問で調べるべき関数が分かったので,中身を
  表示させようとしました.
� ところが,次の表示が出ます.
� どうすれば良いでしょうか?


> randomForest.default
 エラー: オブジェクト 'randomForest.default' がありません
> randomForest.formula
 エラー: オブジェクト 'randomForest.formula' がありません




                                             38
【答え】
 マスクされた関数の中身は,
  getFromNamespace関数,
またはパッケージ名:::関数名で
         表示する

                        39
� getFromNamespace関数

> getFromNamespace("randomForest.default", "randomForest")
function (x, y = NULL, xtest = NULL, ytest = NULL, ntree = 500,
    mtry = if (!is.null(y) && !is.factor(y)) max(floor(ncol(x)/3),
        1) else floor(sqrt(ncol(x))), replace = TRUE, classwt = NULL,
    cutoff, strata, sampsize = if (replace) nrow(x) else ceiling(0.632 *
        nrow(x)), nodesize = if (!is.null(y) && !is.factor(y)) 5 else 1,
    maxnodes = NULL, importance = FALSE, localImp = FALSE, nPerm = 1,
    proximity, oob.prox = proximity, norm.votes = TRUE, do.trace = FALSE,
    keep.forest = !is.null(y) && is.null(xtest), corr.bias = FALSE,
    keep.inbag = FALSE, ...)
{
  中略
}
<environment: namespace:randomForest>




                                                                            40
� パッケージ名:::関数名

> randomForest:::randomForest.default
function (x, y = NULL, xtest = NULL, ytest = NULL, ntree = 500,
    mtry = if (!is.null(y) && !is.factor(y)) max(floor(ncol(x)/3),
        1) else floor(sqrt(ncol(x))), replace = TRUE, classwt = NULL,
    cutoff, strata, sampsize = if (replace) nrow(x) else ceiling(0.632 *
        nrow(x)), nodesize = if (!is.null(y) && !is.factor(y)) 5 else 1,
    maxnodes = NULL, importance = FALSE, localImp = FALSE, nPerm = 1,
    proximity, oob.prox = proximity, norm.votes = TRUE, do.trace = FALSE,
    keep.forest = !is.null(y) && is.null(xtest), corr.bias = FALSE,
    keep.inbag = FALSE, ...)
{
  中略
}
<environment: namespace:randomForest>




                                                                            41
� そもそもrandomForest.default関数が
  randomForestパッケージにあることをどのよう
  に知ればよいか?
> randomForest
function (x, ...)
UseMethod("randomForest")
<environment: namespace:randomForest>




                                        42
� 入っているパッケージが分からないときは?
> getAnywhere("randomForest.default")
A single object matching ‘randomForest.default’ was found
It was found in the following places
  registered S3 method for randomForest from namespace randomForest
  namespace:randomForest
with value

function (x, y = NULL, xtest = NULL, ytest = NULL, ntree = 500,
    mtry = if (!is.null(y) && !is.factor(y)) max(floor(ncol(x)/3),
        1) else floor(sqrt(ncol(x))), replace = TRUE, classwt = NULL,
    cutoff, strata, sampsize = if (replace) nrow(x) else ceiling(0.632 *
        nrow(x)), nodesize = if (!is.null(y) && !is.factor(y)) 5 else 1,
    maxnodes = NULL, importance = FALSE, localImp = FALSE, nPerm = 1,
    proximity, oob.prox = proximity, norm.votes = TRUE, do.trace = FALSE,
    keep.forest = !is.null(y) && is.null(xtest), corr.bias = FALSE,
    keep.inbag = FALSE, ...)
{
  中略
}
<environment: namespace:randomForest>
                                                                            43
第6問
【デバッグ】


         44
� パッケージをインストールして,関数がどのよ
  うな動きをするか確めます.
� インプットとアウトプットだけでなく,途中で
  どのような処理をしているか知りたくなりまし
  た.
� しかし,パッケージの関数の中に直接cat関数や
  print関数を埋め込むことは出来ません.
� 仕方ないので,パッケージの関数をコピーして,
  catやprintを埋め込みました.
� 何か問題はあるでしょうか?




                        45
work/my_randomForest.r
my.randomForest <- function (x, ...)
UseMethod("my.randomForest")

my.randomForest.default <- function
function (x, y = NULL, xtest = NULL, ytest = NULL, ntree = 500,
    mtry = if (!is.null(y) && !is.factor(y)) max(floor(ncol(x)/3),
        1) else floor(sqrt(ncol(x))), replace = TRUE, classwt = NULL,
    cutoff, strata, sampsize = if (replace) nrow(x) else ceiling(0.632 *
        nrow(x)), nodesize = if (!is.null(y) && !is.factor(y)) 5 else 1,
    maxnodes = NULL, importance = FALSE, localImp = FALSE, nPerm = 1,
    proximity, oob.prox = proximity, norm.votes = TRUE, do.trace = FALSE,
    keep.forest = !is.null(y) && is.null(xtest), corr.bias = FALSE,
    keep.inbag = FALSE, ...)
{
    addclass <- is.null(y)
    cat(addclass, "n")
    classRF <- addclass || is.factor(y)
    print(classRF)
    if (!classRF && length(unique(y)) <= 5) {
        warning("The response has five or fewer unique values. Are you sure you want to
do regression?")
    }
   (中略)
}

                                                                                          46
【答え】
関数の中身を調べたいときは,
  デバッグ用の関数を使う



                 47
� デバッグモードの設定
> debug(randomForest:::randomForest.default)


� デバッグモードでの実行

> randomForest(iris[, -5])
Browse[2]> debug: addclass <- is.null(y)
Browse[2]> n
debug: classRF <- addclass || is.factor(y)
Browse[2]> addclass
[1] TRUE




                                               48
アジェンダ

1. 自己紹介
2.クイズで議論! RのTips
3. まとめ




                   49
� Rは使いやすい統計ツールですが,効率的に使う
  ためのテクニックがいろいろとあります.
� 自分で試行錯誤したり,RjpWikiなどで調べるこ
  とが「自分にとって使いやすい」Tipsをためる
  ことにつながります.
� Rに少し慣れてきたら,「Rの基礎とプログラミ
  ング技法」は必ず読みましょう!




                          50

Rあんなときこんなとき(tokyo r#12)