R起動時にpackageを自動ロードする
よく使うパッケージを起動のたびにlibrary()やrequire()をするのは面倒かと思います。その時は.Rprofile内に
suppressMessages(library(hoge))
の一文を入れておきましょう。(違いました。追記を見て下さい。)
suppressMessages()はなくても構いませんが、出力として表示されるはずのメッセージを表示しないようにしてくれます。
この類似としてsuppressWarnings()という警告メッセージのみを抑制する関数も存在しています。
(追記)
上のコードで読み込んだ際のサーチパスが思うように行きませんでした。ここではdplyrパッケージをロードしたのですが、下の実行結果を見て下さい。
> search() [1] ".GlobalEnv" "tools:rstudio" "package:stats" "package:graphics" [5] "package:grDevices" "package:utils" "package:datasets" "package:dplyr" [9] "JapanEnv" "package:methods" "Autoloads" "package:base"
本来(Rコンソールからロードした時)ならば、2つ目の要素に "package:dplyr" が来ていなければなりません。dplyrパッケージの場合はfilter()とlag()がpackage:statsにマスクされているので、このサーチパスのおかしい状態で関数を呼ぶとpackage:statsのfilter()とlag()が呼び出されてしまいます。
ならどうしたらいいの?
ということで試行錯誤しましたが、Startupのhelpマニュアルを見たらちゃんと書いてありました。不要なところをはしょると、.Rprofileの中身を読み込んでから.First.sys()を実行するという順序になっています。
.First.sys()はoptions("defaultPackages")にあるパッケージをロードする関数で、つまりは
「.Rprofileでdplyrをロード → デフォルトパッケージをロード」
の順になっているわけです。
問題を解決するためには、デフォルトパッケージと同時にdplyrをロードするようなコードにする必要があります。
ですから、初めのコードの修正としてはデフォルトパッケージ自体を修正する
options(defaultPackages = c(getOption("defaultPackages"), "dplyr"))
というコードになります。
これでもう一度確認すると、正しいサーチパスになっていることがわかります。
> search() [1] ".GlobalEnv" "tools:rstudio" "package:dplyr" "package:stats" [5] "package:graphics" "package:grDevices" "package:utils" "package:datasets" [9] "JapanEnv" "package:methods" "Autoloads" "package:base"
永続代入(スーパーアサインメント)演算子
Rのお話です。
永続代入演算子(<<-)というのがあります。
これを「グローバル変数への代入演算子」と勘違いして覚えてしまうような扱いをよく見る気がします。それでも基本困ることはないと思いますが、ここで正しい意味を覚えてしまいましょう。
説明
下の実行結果を見てください。
> x <- 5 # グローバル変数 > func <- function() { + super <- function() { + x <<- x + 10 # ローカル変数(super) + } + x <- 3 # ローカル変数(func) + super() + return(x) # 出力1へ + } > func() # 関数の実行 [1] 13 # 出力1 > x [1] 5 # 出力2
基本的にローカル変数に限らず、Rはその現在の環境にないオブジェクトを扱おうとすると、まずその1つ上の環境に同じ名前のオブジェクトはないか探します。あればそれを、なければさらに上の環境を探すといったところです。今回のテーマもそれに近いところがあります。
出力1, 2を見てください。永続代入演算子によってfunc関数内のローカル変数xには13が代入されていますが、グローバル変数xは実行前と変わりません。これは、代入する変数xがあるかどうか、最も近い上の環境から1つずつ順に調べていった結果、初めに見つけたfunc関数内のローカル変数xに代入を実行しているからです。
よくわからないですね。では、もしもfunc関数内のローカル変数xがなければどうなるでしょう。
> x <- 5 # グローバル変数 > func <- function() { + super <- function() { + x <<- x + 10 # ローカル変数(super) + } + # x <- 3 # ローカル変数(func) + super() + return(x) # 出力1へ + } > func() # 関数の実行 [1] 15 # 出力1 > x [1] 15 # 出力2
func関数の実行結果とグローバル変数xの出力が同じになりました。これは、super関数より上の環境におけるxの代入先が、グローバル変数xのみになってしまったためです。
ならばグローバル変数xもなくしてしまえばどうなるでしょう。グローバル環境は変数サーチの終点になります。よってこれ以上、上の環境を探すことはありませんが、変数がないので新たに変数xを生成して代入します。
Rの関数の中身を知りたい
Rの関数の中身を知りたい時のお話です。
基本的には、
> 関数名
としてしまえば下のmatrix関数のように参照することができます。
> matrix function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) { if (is.object(data) || !is.atomic(data)) data <- as.vector(data) .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), missing(ncol))) } <bytecode: 0x7f8ffc2bad78> <environment: namespace:base>
しかし、aggregate関数のように
> aggregate function (x, ...) UseMethod("aggregate") <bytecode: 0x7fa16dab4f18> <environment: namespace:stats>
と参照できない場合があります。このような関数は総称的関数といい、様々なクラスに対応させるため、引数に入れる変数のクラスごとの関数(メソッドという)をまとめた関数になります。これは総称的関数の中に複数のメソッドを含む形となります。総称的関数を実行すると、その時に入れた引数のクラスによって適切なメソッドが選択され、実行されます。
UseMethodにあるのが総称的関数ですので、その中のメソッドを見るためにはmethods関数で呼び出しましょう。
> methods(aggregate) [1] aggregate.data.frame aggregate.default aggregate.formula* aggregate.ts Non-visible functions are asterisked
これで、aggregate関数はaggregate.data.frame、aggregate.default、aggregate.formula*、aggregate.tsの4つのメソッドで構成されていることがわかりました。
このうち、「*」のついているメソッドは中身が隠蔽されており、matrix関数のように参照することができません。この場合は、getS3method関数で(またはgetAnywhere関数)
> getS3method("メソッド名", "クラス名")
とすると参照できます。
> getS3method("aggregate", "formula") function (formula, data, FUN, ..., subset, na.action = na.omit) { if (missing(formula) || !inherits(formula, "formula")) stop("'formula' missing or incorrect") if (length(formula) != 3L) # 以下略
NAを含む時のdist関数
Rのdist関数において、対象とするベクトル内にNAが含まれている場合を調べました。
初めはNAで返ってくるのか考えていましたが、どうやらNAがあっても数値として計算して返してくれるようです。
計算過程がわかりやすいようにmanhattan距離で計算してみました。
> (dist.na <- matrix(c(1,2,4,NA,7,5,4,1,8,NA,9,10),3,4)) [,1] [,2] [,3] [,4] [1,] 1 NA 4 NA [2,] 2 7 1 9 [3,] 4 5 8 10 > dist(dist.na, method = "manhattan") 1 2 2 8 3 14 12
確かにNAが含まれている1行目との距離もしっかり数値で返ってきていますね。
helpマニュアルを参照すると、
「 If some columns are excluded in calculating a Euclidean, Manhattan, Canberra or Minkowski distance, the sum is scaled up proportionally to the number of columns used.」
とあります。列数に比例して和を取ってくれるとのこと。
これは、NAの含まれていない列の計算結果の平均を、NAの含まれている列の計算結果としているみたいです。言い換えると、平均値代入しているということです。
ここで先ほどのmanhattan距離の例を見てみますと、
# 1,2行間のmanhattan距離 > abs(1-2) + abs(4-1) + ((abs(1-2) + abs(4-1)) / 2) * 2 [1] 8 # 1,3行間のmanhattan距離 > abs(1-4) + abs(4-8) + ((abs(1-4) + abs(4-8)) / 2) * 2 [1] 14
と、一致しました。
ちなみに、euclidean距離もこのとおり正しい結果であることがわかります。
> dist(dist.na, method = "euclidean") 1 2 2 4.472136 3 7.071068 7.615773 # 1,2行間のeuclidean距離 > sqrt((1-2)^2 + (4-1)^2 + (((1-2)^2 + (4-1)^2) / 2) * 2) [1] 4.472136 # 1,3行間のeuclidean距離 > sqrt((1-4)^2 + (4-8)^2 + (((1-4)^2 + (4-8)^2) / 2) * 2) [1] 7.071068