R言語で関数の定義の仕方を解説していきます。
この記事では以下の内容が学べます。
この記事で学べる事
- 関数の作り方
- 再帰関数の作り方
- 関数の値渡しと参照渡し
- 関数のスコープ
通常の関数だけでなく再帰関数や関数の値渡しや参照渡しについてもみていきます。
また、functionの中で関数外の変数に代入しても値が変わらない理由と、その対処法についても紹介します。
この記事で解説するRスクリプトは以下からダウンロードできます。
function
Rで関数を定義するには次のfunctionを用います。
functionを構成する要素は以下の通りです。
arglist | 引数。空または1つ以上のname=expressionから成る要素。 |
expr | 関数の内容を表すコード。 |
value | 関数の戻り値。 |
実行例
functionの使い方についてまとめました。
再帰関数などの特殊な関数の作り方もまとめています。
関数の定義
Rで任意の関数を定義するには、次のようにfunctionを用います。
二乗和の関数をfunctionで定義しています。
1 2 3 | squaredSum <- function(x) { return(sum(x^2)) } |
以下、実行例です。
1 2 3 4 5 | > squaredSum(c(4, 5, 8, 2, 7, 6, 1, 3)) [1] 204 > > squaredSum(seq_len(5)) [1] 55 |
ポイント
関数の引数は「,」区切りで複数指定することが可能です。
1 2 3 | chr_join <- function(a, b) { return(paste0(a, b)) } |
1 2 3 4 | > a <- "abc" > b <- "def" > chr_join(a, b) [1] "abcdef" |
次のようにifやfor文を使って複雑な関数を与えることもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | foobar <- function(x) { foobars <- NULL for (x_i in x) { if (x_i %% 2 == 0 & x_i %% 3 == 0) { foobars <- append(foobars, "foobar") } else if (x_i %% 2 == 0) { foobars <- append(foobars, "foo") } else if (x_i %% 3 == 0) { foobars <- append(foobars, "bar") } else { foobars <- append(foobars, "") } } return(foobars) } |
1 2 | > foobar(seq_len(15)) [1] "" "foo" "bar" "foo" "" "foobar" "" "foo" "bar" "foo" "" "foobar" "" "foo" "bar" |
また以下のように、expressionの中にreturnを書かないで、戻り値のない関数を定義することもできます。
1 2 3 4 | writeData <- function(id, x) { dataset <- data.frame(id, x) write.csv(dataset, "dataset.csv") } |
上を実行すると関数内で作ったデータフレームがcsvファイルへ出力されます。
1 2 3 4 | > id <- paste("id:", seq_len(10)) > x <- sample(seq_len(10), 10) > > writeData(id, x) |
再帰関数
続いて再帰関数の作り方について解説します。
Rの再帰関数は、関数の中に同じ関数を呼び出すことで定義することができます。
次の関数はフィボナッチ数列の各項を求めるものです。
1 2 3 4 5 6 7 8 | fibonacciNumber <- function(n) { if (n == 0 | n == 1) { return(n) } else { return(fibonacciNumber(n - 1) + fibonacciNumber(n - 2)) } } |
以下、実行例です
1 2 3 4 5 | > fibonacciNumber(5) [1] 5 > > fibonacciNumber(10) [1] 55 |
再帰関数について詳しく見たい方は次の記事を参照してください。
【R言語】再帰関数の作り方
今回は、Rで再帰関数を作る方法を解説していきます。 R言語でも、他の言語と同様に再帰関数を書くことができますが、若干分かりづらい部分もあります。 特にvoid型の再帰関数を作るときに、ちょっとした工夫 ...
続きを見る
値渡しと参照渡し
次に値渡しと参照私について見ていきます。
Rではデフォルトで関数の引数に渡すオブジェクトは値渡しとなっています。
そのため、リストなどのオブジェクトを関数の引数に渡し、関数内で要素の変更を行っても関数内のリストが変わるだけとなります。
次のリストに要素を追加する関数insertを例に値渡しと参照渡しについて解説します。
1 2 3 | insert <- function(x, name, y) { x[[name]] <- y } |
値渡し
ふつうに関数listを使ってリストxを定義し、名前が"a"である要素1をxに追加します。
1 2 3 | #値渡し x <- list() x$a <- 1 |
次に先ほどの関数insertを使って、名前"a"の要素に0を代入してもxの要素は変わらないことが分かります。
1 2 3 4 | > insert(x, "a", 0) > > x$a [1] 1 |
値渡しとなっているため、このように関数の引数に変数を渡しても変更されません。
参照渡し
関数new.envを用いて参照可能な新たな環境xを定義し、名前が"a"であるオブジェクトを追加します。
1 2 3 | #参照渡し x <- new.env() x$a <- 1 |
insertを実行すると、ちゃんと0に変更されているのが確認できます。
1 2 3 4 | > insert(x, "a", 0) > > x$a [1] 0 |
関数のスコープ
最後に関数のスコープについて紹介します。
グローバル変数とローカル変数
1 2 3 4 5 6 | x <- 1 y <- 2 plus_y1 <- function(a) { a + y } |
上の関数を実行するとグローバル変数のyを足した値が計算されます。
1 2 | > plus_y1(x) #グローバル変数のyが使われる [1] 3 |
次の関数のようにローカル変数にyを宣言した場合、ローカル変数が優先されます。
1 2 3 4 | plus_y2 <- function(a) { y <- 3 a + y } |
以下、実行例です。
1 2 | > plus_y2(x) #ローカル変数のyが使われる [1] 4 |
関数内でのグローバル変数の変更
次に、関数内でグローバル変数を変更する例を紹介します。
Rでfunctionを使って自作の関数をつくるときに、関数の外のオブジェクトの変数を変更することができなくて困ることが多々あります。
次のように関数の外にあるオブジェクトを変更するには、「<-」ではなく「<<-」を用います。
ポイント
1 2 3 4 5 6 7 8 9 10 | counter <- 0 count <- function(x, chr) { counter <- 0 for (x_i in unlist(strsplit(x, ""))) { if (x_i == chr) { counter <- counter + 1 #ローカルなcounterをインクリメント } } counter <<- counter #countの外の変数を更新 } |
そのため関数中でcounterをインクリメントしていますが、関数の外にあるグローバル変数counterは更新されず、ローカルな関数の中のcounterが増えます。
関数countの最後に書いてあるように、「<<-」を用いることで関数の外の変数に代入することが可能です。
関数countを実行した後counterを参照すると、2に変わっていることが確認できます。
1 2 3 | > count("abbcdeee", "b") > counter [1] 2 |
まとめ
Rで関数を定義する方法について見ていきました。
functionを用いることで任意の関数を定義することが可能です。