R言語の関数について、詳しく解説します。

Rの関数について

関数は、各処理の手順を一つにまとめたものとなります。一般的にプログラミングは関数の組み合わせにより成し遂げたいことを構築していくため、関数の概念を習得することは必須になります。
プログラミング初級者の場合、関数を作成するよりも関数を使用する機会の方が多いので、まずは関数の使い方をお伝えします。そのために、関数の概要から押さえます。

関数の概要

Rの関数は次のようなコードで作成されます。ここで重要なことは関数の作成方法ではなく、「関数名」「引数」「処理」「処理結果の返却」という部分に分かれているという認識を持つことです。


関数名 <- function(引数) {
    処理1
    処理2
    ・・・
    処理結果の返却
}

関数の名前

関数には名前が付いています。Rに標準で搭載されている関数や外部パッケージに搭載されている関数にもそれぞれの名前が付いています。重要なことは、関数名はその関数内の処理を上手く説明していることが多いです。例えば、Rの標準で搭載されているsum()は数値の和に関する処理を行う関数であることが推察でき、そしてそれは正しいです。

関数の引数

引数は関数の処理にあたって、あらかじめ処理に必要となるデータを与える場所のことです。例えば、Rに標準で搭載されているsum()は数値の和に関する処理を行う関数ですが、sum()単体ではどの数値の和を計算すれば良いのか分かりません。このようなときには、sum(数値のベクトル)として、あらかじめ処理に必要となるデータを与えます。重要なことは、引数の書き方は関数に依存するということです。関数の引数は絶対に必要となるものではなく、引数がない関数も存在します。

関数の処理

関数を使用する立場からすると、関数の処理に意識を向ける必要はほぼありません。例えば、Rに標準で搭載されているsum()は数値の和に関する処理を行う関数ですが、具体的にどのような処理が記述されているのかは分からなくても、数値の和に関する結果を得ることができます。このように、Rおよび外部パッケージには様々な人の多大な貢献により自分で処理を記述する量を減らすことのできる関数が数多くあります。ありがたく使用させてもらいましょう。

処理結果の返却

関数の処理が実行されたのち、処理結果を返却する必要があります。例えば、Rに標準で搭載されているsum()は数値の和に関する処理を行う関数ですが、数値の和を計算させて結果を得ることができなければ何のためにsum()を実行したのか意味が分かりません。そのため、関数は何らかの処理結果を返します。

関数の引数で覚えるべき用語および用法

データサイエンスにおいては、行いたい処理を叶える関数をインターネットなどで検索することが多いと思います。このとき、実際に使用するためには引数を記述する必要があります。そのため、必要となる用語および用法を数値の和を計算するsum()とRオブジェクトの構造を表示するstr()の引数を例にとりお伝えします。


sum(..., na.rm = FALSE)

str(object, max.level = NA,
    vec.len  = strO$vec.len, digits.d = strO$digits.d,
    nchar.max = 128, give.attr = TRUE,
    drop.deparse.attr = strO$drop.deparse.attr,
    give.head = TRUE, give.length = give.head,
    width = getOption("width"), nest.lev = 0,
    indent.str = paste(rep.int(" ", max(0, nest.lev + 1)),
                       collapse = ".."),
    comp.str = "$ ", no.list = FALSE, envir = baseenv(),
    strict.width = strO$strict.width,
    formatNum = strO$formatNum, list.len = strO$list.len,
    deparse.lines = strO$deparse.lines, ...)

第一引数、第二引数、…

引数はいくつかの場所に分かれており、その区切りを「,」で表します。そして、区切られた場所を「関数名(第一引数, 第二引数, ・・・)」といいます。str()の場合では第一引数は「object」、第二引数は「max.level」となります。

引数名

str()の第一引数は「object」であることが分かります。このような引数の場所に記述されている名前を引数名といいます。例えば、str()の第二引数名は「max.level」となります。

必須引数

必須引数という言葉はないと思いますが、伝えたいこととしてはstr()において、第一引数であるobjectはstr()を実行するためには必須の引数となります。必須引数であるかどうかを見極めるポイントとしては、下記で説明するデフォルト引数ではないことです。

デフォルト引数

str()の第二引数「max.level = NA」を見ると、「= NA」が記述されています。これは、第二引数「max.level」にデータを与えなければ「NA」が与えられたものとする、という意味になります。このようなあらかじめ関数作成者が初期値を与えている引数のことをデフォルト引数といいます。

三点リーダー(…)

sum()とstr()の引数に「…」が記述されていますが、これは、どのようなデータでもいくつでも与えることができることを意味しています。注意すべきこととしては、どのようなデータでもいくつ与えても、どのように処理するかは関数の処理次第ということです。そのため、実際の仕様にあたってはヘルプで確認する必要があります。

引数名の省略

str()の引数を見ると大量にあることが分かります。このとき、第一引数と第二引数のみを使用する場合は次のように記述できます。


str(object, 1)

これと全く同じコードが次になります。


str(object, max.level = 1)

つまり、第一引数、第二引数、・・・と引数の順序通りにデータを与えるときは、「引数名 = 」を記述する必要がありません。しかし、必須引数の「object」と第三引数の「vec.len」のデータを与えるときには、「引数名 = 」を省略することはできません。これは引数名をしないと、どの引数にデータを与えているのか関数には分からないためです。


str(object, vec.len = 1)

関数の使用例

例:三点リーダー(…)の挙動

sum()の>三点リーダー(…)の挙動を実際のコードで確認してみます。


sum(1, 2, 3)
(out)[1] 6
(out)
sum(c(1, 2, 3))
(out)[1] 6
(out)
sum(1, c(2, 3))
(out)[1] 6

関数の作成方法

ここまでは、主に関数を使用する立場から関数について説明してきました。ここからは、主に関数を作成する立場から関数を説明します。とはいえ、ここまでで関数のおおよそのことを説明してきたので、関数の作成において新たに覚えるべき点は「処理結果の返却」の部分だけです。具体例として、2つの数値の和を計算する関数my_sum()を次のように作成します。


my_sum <- function(x1, x2) {
    x1 + x2
}

実際に、my_sum()を使用した結果は次になります。


my_sum(1, 2)
(out)[1] 3

Rの関数の重要な特性として、関数内の最後の処理で得られた結果が自動的に関数の処理結果として得られます。例えば、my_sum1()を次のように作成します。


my_sum1 <- function(x1, x2) {
    x1 + x2
    1
}

これは、最後の処理が「1」だけとなっているため、どのような引数を与えても、関数の処理結果としては「1」が得られます。実際にmy_sum1()を使用すると次になります。


my_sum1(1, 2)
(out)[1] 1

Rの関数にはこのような特性がありますが、他のプログラミング言語と同様にreturn()を使用して明示的に関数の処理結果を返す方法もあります。例えば、my_sum2()を次のように作成します。


my_sum2 <- function(x1, x2) {
    return(x1 + x2)
}

このmy_sum2()を使用すると次になります。


my_sum2(1, 2)
(out)[1] 3

ちなみに、my_sum1()の正しい箇所にreturn()を使用したmy_sum3()を次のように作成します。


my_sum3 <- function(x1, x2) {
    return(x1 + x2)
    1
}

このmy_sum3()を使用すると次になります。


my_sum3(1, 2)
(out)[1] 3

このようにreturn()があるときは、return()の結果が関数の処理結果として返却されます。

R入門 関数