rあんなときこんなとき(tokyo r#12)
DESCRIPTION
TRANSCRIPT
Rあんなときこんなとき~いつか役に立つ(かもしれない)Tips~
2011年3月5日
第12回 TokyoR
@sfchaos
1
本発表の趣旨
� Rに初めて触れた頃,それまでに使っていたCやC++に比べて利便性が高いと思ったものの,お作法など分からないことがたくさんありました.
� 本発表では,特に私がRを触れた初期の頃に調べたりつまづいたポイントを中心に,6つのTipsについてクイズ形式で議論したいと思います.
2
アジェンダ
1. 自己紹介
2.クイズで議論! RのTips
3. まとめ
3
アジェンダ
1. 自己紹介
2.クイズで議論! RのTips
3. まとめ
4
自己紹介
� TwitterID: @sfchaos
� 出身地: 埼玉県
� 職業:コンサルタント
� 数年間,金融工学のモデル構築・データ解析
� 最近,大規模データ解析に着手(Hadoop/Mahout)
� 趣味:登山
� 学生時代の専攻は物理・応用数学(非線形力学系・カオス)
5
� 私とR� データ解析の仕事に携わりRを使い始めた.
� 最近はRでの大規模データ解析に興味がある.
20082007 2009 2010 2011
データ解析(金融工学)
大規模データ解析
Rの基礎とプログラミング技法
R Tips(Webサイト)
RjpWiki(Webサイト)
Software fordata analysis
CRANマニュアル
6
� 私とR� データ解析の仕事に携わりRを使い始めた.
� 最近はRでの大規模データ解析に興味がある.
20082007 2009 2010 2011
データ解析(金融工学)
大規模データ解析
Rの基礎とプログラミング技法
R Tips(Webサイト)
RjpWiki(Webサイト)
Software fordata analysis
CRANマニュアル
今日の発表の範囲
7
アジェンダ
1. 自己紹介
2.クイズで議論! RのTips
3. まとめ
8
問題1【ファイルの読み込み】
9
� 自分で作成した関数を格納したファイルを読み込んでいます.
� 量が多くて大変です.
� どうすれば良いでしょうか.
> source("a.r")> source("b.r")> source("c.r")> source("d.r")...> source("z.r")
10
【答え】
読み込み用の関数を別途作成する
11
readfile.rreadfile <- function(){ fn.all <- c("a.r", "b.r", (中略), "z.r") for (fn in fn.all) { source(fn) cat(fn, "\n") }}
> source("readfile.r")> readfile()
� 読み込み用関数を作成
� 次のコマンドを実行
12
readfile.rreadfile <- 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行で書ける!
13
(ご参考)
� 毎回,必ず読み込むファイルがある場合は,作業フォルダ直下の.Rprofileファイルの.First関数に記述しておくことも一つの手.
.Rprofile
.First <- function(){ inputdir <- "C:\Users\sfchaos\lib\R" fn.all <- paste(inputdir, c("lib.r", "util.r")) for (fn in fn.all) { source(fn) cat(fn, "\n") }}
C:\Users\sfchaos\lib\R\lib.rC:\Users\sfchaos\lib\R\util.r>
14
あまり派手にやると,
不要な関数を読み込んで時間がかかるので
おススメしません!
15
第2問【データ・ファイルの管理】
16
� 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=",") # データの出力
17
【答え】
問題あり!!
入力データ格納フォルダ,
作業フォルダ,
出力データ格納フォルダが
すべて同じフォルダになっている
18
� データ解析は次のフローに従って行う.
入力データ 解析 出力データ
19
� フォルダも対応して別々に作ると良い.
入力データ 解析 出力データ
data work output
20
� では,入力データ格納フォルダ("data"フォルダ)のデータを作業フォルダで扱うには?
� 2つの方法がある.1)入力データ格納フォルダで作成したオブジェクトを作業フォルダで読み込む
2)作業フォルダで,関数の引数に読み込む入力データのファイル名を指定する
21
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 # 保存してから終了する
入力データ格納フォルダでの作業
22
> 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"
作業フォルダでの作業
23
work/hoge.rhoge <- function(fn="../data/my_iris.csv"){ my.iris <- read.table(fn, sep=",") (後略)}
> source("hoge.r")> hoge()
2) 作業フォルダで,関数の引数に読み込む入力 データのファイル名を指定する
24
work/hoge2.rhoge2 <- function(datadir="../data/", fn="my_iris.csv"){ my.iris <- read.table(paste(datadir, fn, sep=""), sep=",") (後略)}
「入力データフォルダ名」と「入力データファイル名」を分離
データフォルダを複数作成する場合は,こうすると良い
25
第3問【NA/NaN/Infの判定】
26
� データの中に存在する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
27
【答え】
is.finite関数を使用する
28
> x[1] 1 5 NA 3 NaN 9 6 Inf> is.finite(x)[1] TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE
29
第4問【総称型関数】
30
� Rにも慣れてきて,パッケージの関数の中身を確認したいと思うようになりました.
� ところが,次の表示が出て中身が確認できません.
� 中身を確認する関数を調べるにはどうすれば良いでしょうか?
> install.packages("randomForest")> library(randomForest)> randomForestfunction (x, ...) UseMethod("randomForest")<environment: namespace:randomForest>
31
【答え】
methods関数で調べる
32
� 総称型関数とは?(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関数で表示できる!
33
> printfunction (x, ...) UseMethod("print")<environment: namespace:base>
print関数
34
> print.defaultfunction (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>
ベクトル用print関数
35
> print.tablefunction (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>
table用print関数
36
� 総称型関数はmethods関数で調べられる
> methods(randomForest)[1] randomForest.default* randomForest.formula*
Non-visible functions are asterisked
37
第5問【総称型関数(続き)】
38
� 第4問で調べるべき関数が分かったので,中身を表示させようとしました.
� ところが,次の表示が出ます.
� どうすれば良いでしょうか?
> randomForest.default エラー: オブジェクト 'randomForest.default' がありません> randomForest.formula エラー: オブジェクト 'randomForest.formula' がありません
39
【答え】
マスクされた関数の中身は,
getFromNamespace関数,
またはパッケージ名:::関数名で
表示する
40
� 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>
41
� パッケージ名:::関数名
> randomForest:::randomForest.defaultfunction (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>
42
� そもそもrandomForest.default関数がrandomForestパッケージにあることをどのように知ればよいか?
> randomForestfunction (x, ...) UseMethod("randomForest")<environment: namespace:randomForest>
43
� 入っているパッケージが分からないときは?> getAnywhere("randomForest.default")A single object matching ‘randomForest.default’ was foundIt was found in the following places registered S3 method for randomForest from namespace randomForest namespace:randomForestwith 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>
44
第6問【デバッグ】
45
� パッケージをインストールして,関数がどのような動きをするか確めます.
� インプットとアウトプットだけでなく,途中でどのような処理をしているか知りたくなりました.
� しかし,パッケージの関数の中に直接cat関数やprint関数を埋め込むことは出来ません.
� 仕方ないので,パッケージの関数をコピーして,catやprintを埋め込みました.
� 何か問題はあるでしょうか?
46
work/my_randomForest.rmy.randomForest <- function (x, ...) UseMethod("my.randomForest")
my.randomForest.default <- functionfunction (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?") } (中略)}
47
【答え】
関数の中身を調べたいときは,
デバッグ用の関数を使う
48
� デバッグモードの設定
> randomForest(iris[, -5])Browse[2]> debug: addclass <- is.null(y)Browse[2]> ndebug: classRF <- addclass || is.factor(y)Browse[2]> addclass[1] TRUE
� デバッグモードでの実行
> debug(randomForest:::randomForest.default)
49
アジェンダ
1. 自己紹介
2.クイズで議論! RのTips
3. まとめ
50
� Rは使いやすい統計ツールですが,効率的に使うためのテクニックがいろいろとあります.
� 自分で試行錯誤したり,RjpWikiなどで調べることが「自分にとって使いやすい」Tipsをためることにつながります.
� Rに少し慣れてきたら,「Rの基礎とプログラミング技法」は必ず読みましょう!