27. 関数事始


関数の使用方法

R には特定の機能を果たす命令が多数あり,関数という形で呼び出すことが出来る.例えば関数 date() を実行すると,現在の日付が出力される.

  
 date()                           # 現在の日時を得る:引数が一つもない関数の例

[1] "Mon Jul 21 16:31:52 2003"    # 引数が一つもない場合でも,名前の後ろの括弧は必要である

対数を計算する関数 log(x) は『 x の値の対数を計算する関数』であるが,関数に x の値を知らせる場合には引数という形で関数に与える.

  
 x <- 10                          # x に 10 を代入
 log(x)                           # x を引数に与えて log(x) を計算させる

[1] 2.302585

引数に式や関数を指定すれば,それを評価した値が引数として使われる.また,引数が 2 個以上ある場合はコンマ  で区切って並べればよい.

  
 x <- 10                          # x に 10 を代入
 log(x^2)                         # x^2 を計算した値を log に渡して計算

[1] 4.60517

 log(x^2, base=10)                # 底を指定する引数 base に 10 を指定して対数を計算

[1] 2

引数の省略

関数の引数には省略可能なものがある.引数が省略できるか否かは関数のヘルプに載っている.例えば,関数 log() の定義は以下のようになっており,引数 base の値を指定しない場合は,自然対数 e が自動的に指定されることになる.

 
log(x, base = exp(1))

引数名を指定しなくても引数の順番さえあっていればよいので,base の文字を省略して以下のように計算しても良い.

  
 x <- 10
 log(x, 10)                       # log(x, base=10) と同じ

名前で引数を指定する場合,指定位置はどこでも OK .これは引数が名前で指定されるので,順番が違っていてもどの引数が指定されたのか判断出来るからである.

  
 x <- 10
 log(base=10, x)

[1] 1

以下のように関数呼び出し時の引数中にも代入式を書くことができるが,この方法は混乱の原因になるので避けた方がよい.つまり,代入式と関数呼び出しは別々に行なうのが良い.

悪い方法 : x に 10 を代入してから log(x) を計算する

 
 log(x <- 10)

上の例を改善 : 関数呼び出しを分けて書くのが良い

  
 x <- 10
 log(x)

関数の定義を見る

関数がどのような式で定義されているかを見る場合,昔は関数の名前のみ(括弧なし)を入力すれば良かった.例えば関数 order() の定義を見る場合は以下のように入力すればよかった.

 
 order

function (..., na.last = TRUE, decreasing = FALSE) 
{
    if (!is.na(na.last)) 
        .Internal(order(na.last, decreasing, ...))
    else {
        z <- list(...)
        if (any(diff(sapply(z, length)) != 0)) 
            stop("argument lengths differ")
        ans <- sapply(z, is.na)
        ok <- if (is.matrix(ans)) 
            !apply(ans, 1, any)
        else !any(ans)
        if (all(!ok)) 
            return(integer(0))
        z[[1]][!ok] <- NA
        ans <- do.call("order", c(z, decreasing = decreasing))
        keep <- seq(along = ok)[ok]
        ans[ans %in% keep]
    }
}
<environment: namespace:base>

これは自分で定義した関数,元から R に用意されている関数のどちらにも使える方法である.

しかし,この方法では定義を見ることが出来ない場合が多い.この場合,関数 methods() と関数 getS3method() を組み合わせることで関数定義を見ることが出来る場合がある.

 
 mean

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

 methods("mean")

[1] mean.data.frame mean.Date       mean.default    mean.difftime  
[5] mean.POSIXct    mean.POSIXlt   

 getS3method("mean", "default")

function (x, trim = 0, na.rm = FALSE, ...) 
{
(関数定義は略)

最悪,直接ソースコードを読みに行く方法がある・・・

複合式

関数を定義する上で必須の概念が複合式である.複合式とはいくつかの式を { と } で括ったものである(これをグループ化という).{ と } の式の数は 1 つだけでも構わないし,改行・空白・タブを好きなだけ入れても動作や計算結果には影響しない.また,セミコロンで式の区切りを表すことが出来るが,1 行で 2 つ以上の式を書かないのならば,文の最後にはセミコロンを書かずにそのまま改行しても良い.

「文の最後にはセミコロンを書かずにそのまま改行しても良い」は C や JAVA などと異なる

複合式の中身は先頭の式から順に評価され,最後の式の値が複合式の値となる.

 
 {
   x <- 2 ; y <- 50      # 文の最後にセミコロンをつけてもよいし
   z <- 10               # 文の最後にセミコロンをつけなくてもよい
   log(x*y, base=z)      # この式の結果が複合式全体の値として返る
 } 

[1] 2

自作の関数を定義する

自分で関数を定義したい場合の基本的な形式は以下のようなものである.

 
 関数名 <- function( 引数1, ・・・ , 引数n ) {

   <関数本体> 

 }

以下に自作の関数を定義する例を挙げる.

 
 myfunc <- function(x) ifelse(x > 0, 1, -1)
 myfunc(1)

[1] 1

 myfunc(-2)

[1] -1

自分で関数を定義する場合は R に既に用意されている関数と同じ名前の関数を定義しないように注意しなければならない.定義してしまった場合,R では警告が表示されないことが多いので気付かないことになる.この場合は関数 rm() などでそのオブジェクトを消去する必要がある.

 
 sin <- function(x) ifelse(x > 0, 1, -1)
 sin(1)        # 警告は出ない!

[1] 1

 rm(sin)       # オブジェクトを消去
 sin(1)

[1] 0.841471