Rのプログラム開発に欠かせないデバッグ、OSとのインタラクション(作業ディレクトリの変更、ファイルの存在確認など)、いくつかのライブラリについて学びます
学習項目です
プログラムを作るための最良の方法は「一遍に大きなプログラムを作らない」ことである。 つまり、プログラムを意味的に小さなカタマリに分割し、そのカタマリごとにちゃんと動くことを確かめ、最後にそのカタマリを組み合わせる、という方法である。
普通のプログラミング言語であれば、このプログラムの(小さな)カタマリはサブルーチンとか関数と呼ばれるものである。「関数」としてこのカタマリを作っていくことは価値がある。なぜなら、関数は、計算に必要なものが何かを「引数」として明示的に表し、それをどのように計算するかというアルゴリズムをコードとして表された本体があり、最後に何を値として返すか(出力、もしくは結果)がはっきりしているからである。
Rはインタプリタ型の言語である。そのため、そのカタマリや、それよりも小さな単位のコードを実際に試しながら、プログラムを作ることが容易である。
[インタプリタ型の言語とは]
例として(標本)標準偏差を求める関数s.sdを作る工程を示そう(Rの組み込みとして標準偏差を求める関数sdがあるが、sdは不偏分散の正の平方根であり、標本の標準偏差とは異なる)。その計算の過程は次のようになる:
s.sd <- function(x) { m <- xの平均 v <- xの(標本)分散をxの平均を用いて求める s <- vの正の平方根 return(s) }この一行一行が「意味的なカタマリ」である。このプログラムを作るには、実際にデータを使いながら行うのがやりやすい。ここでは以下のデータを用いるものとする:
set.seed(0) # 同じ乱数をいつも発生させるためのもの---例題なので同じ結果がいつも得られるようにするための措置 data <- rnorm(30,0,1) # rnorm(n,m,d) は平均0、分散1の正規分布から乱数をn個生成する関数このdataは作られ方から、平均が0で分散および標準偏差はともに1に近いと考えることができる。この事実は、試しに作った関数の値の検査に役に立つ。得られた結果がこれとかなり離れた値を返した場合に、意味的な問題が生じたことがわかるからである。
まず「xの平均」を求めてみよう。それには次のようにRを実行すればよい。
> x <- data # xの値としてdataの値を代入 > ( m <- mean(x) ) [1] 0.08331833yには0.08というかなり0に近い値が入ったので、平均値が求められたと考えられる(もちろん、meanという組み込み関数を使ったのだからそうでないと困るのだが)。
次に「v <- xの(標本)分散をxの平均を用いて求める」のコードを書く。「分散」とは、「xの要素と平均値との差」の自乗の総和から求めることを思い出す。 そこで次のように書いてみよう。
> (v <- (x - m)^2 [1] 1.0905112707 2.9173870696 0.5924946087 0.7780870630 0.3488318806 [6] 2.5206025164 0.5554994293 4.0051943705 0.7155737916 0.2136054231 [11] 0.1414342549 2.2786344191 1.1288472969 0.9186234518 0.7475653825 [16] 0.1477034281 0.4797374218 0.0047967739 2.0255688416 0.3688306885 [21] 1.2633099540 0.0173108802 0.4092461570 0.0003777597 0.6897168796 [26] 0.7149848505 1.1755287558 0.7508797520 1.0007665306 0.7592551308あれあれ、分散は1個の数値のはずなのに、ベクトルの結果が出てしまった。これは「xの要素と平均値の自乗」は求めたのだけど、「その和」を求めるのを忘れていたからである。そこで、次のように修正する。
> (v <- sum( (x - m)^2 ) # 先の値に関数sumを適用 [1] 28.76091今度はちゃんと一個の数値が求まったけれど、28.8というのは分散1と比べてとても大きな数である。何かがおかしい…
そこで「分散」の定義を調べてみると、分散は「「xの要素と平均値との差」の自乗の総和」を要素数(不偏分散は「要素数−1」)で割った値」であったことがわかる。 そこで次のように修正する:
> (v <- sum( (x - m)^2 )/length(x) ) # 先の値にxの要素数(length(x))で割る [1] 0.9586969今度はかなり1に近い値になった。これは正解に近づいたことが確信できる。 そこで最後に、この平方根を求めるコードを書く:
> (s <- sqrt(v) ) # vの値に関数sqrtを適用 [1] 0.9791307これも予想通り1に近い値になった。そこで、今まで書いてきたコードを改めてs.sdの関数定義の中に書き入れて、s.sdを定義する。
s.sd <- function(x) { m <- mean(x) # xの平均 v <- sum( (x - m)^2 )/length(x) # xの(標本)分散をxの平均を用いて求める s <- sqrt(v) # vの正の平方根 return(s) }実はこのコードの正しさを確認するには数式の定義やアルゴリズムの検証が必要になるが、簡単にできるが重要な方法としては、例題にあげたデータ以外のデータをいくつか与えてみて、その値が正しい値を返すことを確認する、ということがある。とても重要なことなので是非実践してほしい。
以上が正道なのだが、こういう方法が正しいとわかっていても、いきなり関数の定義を書いてからバグに悩まされる人も少なくない(かくいう著者も時々これをやってしまう)。そのためのバグ除去の手段として、Rではdebug、およびbrowser関数が用意されている。
debugもbrowserも「デバッグモード」という特殊なモードで関数の実行を可能にしている。両者の違いは、その関数が呼び出された時にデバッグモードで実行するか(debugの場合)、それとも関数実行の途中でデバッグモードに入るのか(実行途中でbrowser関数を呼び出す。バグがありそうなところがわかっている場合に有効)、という違いである。
デバッグモードでは、次の命令が使える:
> debug(s.sd) # s.sdが呼ばれたらdebug開始を指示 > s.sd(data) debugging in: s.sd(data) # debugが始まる。s.sdの関数定義が表示される #1 の debug: { m <- mean(x) v <- sum((x - m)^2)/length(x) s <- sqrt(v) return(s) } Browse[2]> n # 次の行を実行 #1 の debug: m <- mean(x) Browse[2]> n # 次の行を実行 #2 の debug: v <- sum((x - m)^2)/length(x) Browse[2]> ls() # どのような変数に値が入ったかを確認 [1] "m" "x" # 関数内の局所変数だけが表示される Browse[2]> m # mの値の確認 [1] 0.08331833 Browse[2]> c # 関数の最後まで実行 exiting from: s.sd(data) [1] 0.9791307 > undebug(s.sd) # s.sdに対するデバッグを終了
そこでRではファイルメニューから「ディレクトリの変更」(ディレクトリとはフォルダのこと)を選んで、「作業ディレクトリ」を設定しておくことができる。これにより、例えば
残念なことに、「ディレクトリの変更」はいつもコンピュータの一番上の階層から始まる。
もしも探すべきフォルダがかなり下にある場合には、これはなかなか面倒な操作が必要になる。それに対して、Rの次のコマンドを行うと、「スクリプトを開く」ことも、Rの中からデータファイルを読み込むのも楽になることが期待できる。使用するのは次の関数である:
> getwd() # 現在の作業ディレクトリを確認 [1] "C:/Users/sirai/Documents" # 作業ディレクトリの表示 > dir() # 作業ディレクトリの下にあるファイルやフォルダを表示 > dir(pattern="Ro") # 作業ディレクトリの下の名前にRoを含むファイルやフォルダを表示 [1] "HandbookOfRobotics" "ProbabilisticRobotics" "Robot" [4] "RobotArm" "RobotBasic" "Roomba" > dir(pattern="ro") # 作業ディレクトリの下の名前にroを含むファイルやフォルダを表示 [1] "Android" "ProbabilisticRobotics" # Roとroでは違うファイルが表示される [3] "Processing" "roman" [5] "RubyInternetProgramming" > setwd("R") # 作業ディレクトリを、今のフォルダの下のRフォルダに変更 > getwd() # 現在の作業ディレクトリを確認 [1] "C:/Users/sirai/Documents/R" # 変更された > dir() # 作業ディレクトリの下にあるファイルやフォルダを表示 [1] "3067_Code.zip" [2] "anovakun_433.txt" [3] "DataMiningWithR-Torgo2011" (以下省略) > setwd("../Robot") # 作業ディレクトリを現在より上のフォルダの下にあるRobotに変更---..は上の階層を表す > dir() # 作業ディレクトリの下にあるファイルやフォルダを表示 [1] "AutonomousMobileRobot" "RobotMotionPlanningAndControl.pdf" > cat("this is a dummy file.\n",file="dummy.txt") # cat関数によりdummy.txtを作成 > dir() # 作業ディレクトリの下にあるファイルやフォルダを表示 [1] "AutonomousMobileRobot" "dummy.txt" # dummy.txtが作成された [3] "RobotMotionPlanningAndControl.pdf" > readLines("dummy.txt") # ファイルの読み込み---作業ディレクトリのファイルが読み込まれる [1] "this is a dummy file." > unlink("dummy.*") # 名前にdummyという文字を含むファイルを削除(unlinkは削除を意味) > dir() # 作業ディレクトリの下にあるファイルやフォルダを表示 [1] "AutonomousMobileRobot" "RobotMotionPlanningAndControl.pdf"
CRANというRの情報源のサイトの、 Task Viewsというパッケージの紹介ページには、次のような分野のライブラリがあることが紹介されている(ここでは、ごく一部のみにとどめている):
以下はdeepnetパッケージをインストールし、ライブラリdeepnetを使えるようにした様子である。ただし、ここでは既にミラーサイトTokyoを設定してあるものとする。
> install.packages("deepnet") Installing package into ‘C:/Users/sirai/Documents/R/win-library/3.0’ (as ‘lib’ is unspecified) URL 'http://cran.md.tsukuba.ac.jp/bin/windows/contrib/3.0/deepnet_0.7-8.zip' を試しています Content type 'application/zip' length 282099 bytes (275 Kb) 開かれた URL downloaded 275 Kb パッケージ ‘deepnet’ は無事に展開され、MD5 サムもチェックされました ダウンロードされたパッケージは、以下にあります C:\Users\sirai\AppData\Local\Temp\RtmpUXgLxG\downloaded_packages > library("deepnet")
samples <- sample(1:150,75) # 1から150までの範囲で75個選ぶ iris.train <- iris[samples,] iris.test <- iris[-samples,]次に、iris.trainデータを用いてニューラルネットを作る:
library(nnet) # nnetライブラリの読み込み iris.nnet <- nnet(Species~., size=3, decay=0.1,data=iris.train)ここで
iris.predict <- predict(iris.nnet, iris.test[,-5],type="class") table(iris.test[,5], iris.predict)上で