第3講 - 関数の定義とプログラムの作成
(Press ?
for help, n
and p
for next and previous slide)
村田 昇
関数の呼び出し方の例
f(arg1 = value1, arg2 = value2) # 擬似コード #' arg1, arg2 は引数の名前,value1, value2 は引数に渡す値を表す f(value1, value2) # 上と同値.順序に注意
正弦関数の計算
sin(x = pi/2) # "引数名 = 値" で指定 sin(pi/2) # 上と同値 (引数と値の関係が明かなら引数名は省略可能)
対数関数の計算
help(log) # ヘルプを表示して使い方を確認する x <- 16; b <- 2 # xやbに適当な数値を代入する.1行で複数の処理を行う場合は ; を用いて並べる log(x = x, base = b) # 底をbとする対数 log(x, b) # 上と同値 log(base = b, x = x) # 上と同値 log(b, x) # 上と異なる (=log(x = b, base = x)) log(x) # 自然対数 (既定値による計算 =log(x, base = exp(1)))
ヘルプによる関数仕様の表示の例
#' 正規乱数を生成する関数 help(rnorm) # Help タブから指定しても良い #' ヒストグラムを表示する関数 ?hist # help(hist) と同値
正規乱数の生成
rnorm(5) # 平均0 分散1 の正規乱数を5個生成 rnorm(5, mean = 10) # 平均10 分散1 の正規乱数を5個生成 rnorm(sd = 0.1, n = 5) # 平均0 分散0.01 の正規乱数を5個生成 rnorm(n = 5, mean = 2, sd = 2) # 平均2 分散4 の正規乱数を5個生成
[1] 0.6649633 -0.6512622 1.1532188 -0.6692962 -1.0033647 [1] 10.425935 10.355327 11.210261 8.652895 9.955703 [1] -0.104365389 0.005089714 -0.186644901 0.037613879 0.019709784 [1] 1.1453795 5.0746946 1.2349134 4.9771802 0.4217371
ヒストグラムの表示
foo <- rnorm(n = 10000, mean = 50, sd = 10) # 平均50 標準偏差10 の正規乱数 hist(foo) # データ以外全て既定値で表示 hist(foo, # 既定値のいくつかを変更する breaks = 30, # ビンを30程度に調整する col = "lightgreen", # 色の指定 main = "mathematics", # タイトルの指定 xlab = "score") # x軸ラベルの指定 #' Plots タブで描画結果を確認
help(),?
)
を用いて関数 sample()
を調べてみようreplace
を調べよprob
を調べよ
関数の定義には関数 function()
を利用する
#' 関数 function() 記法 (擬似コード) 関数名 <- function(引数){ # 計算ブロックの開始 #' このブロック内に必要な手続きを記述する.複数行に渡って構わない return(返値) # 計算結果を明示的に示す } # ブロックの終了
半径 r から球の体積と表面積を求める関数
foo <- function(r){ volume <- (4/3) * pi * r^3 # 球の体積 surface <- 4 * pi * r^2 # 球の表面積 out <- c(volume, surface) # 返り値のベクトルを作る names(out) <- c("volume", "surface_area") # 返り値の要素に名前を付ける return(out) # 値を返す } foo(r = 2) # 実行 foo(3)
volume surface_area 33.51032 50.26548 volume surface_area 113.0973 113.0973
初項 a 公比 r の等比数列の最初のn項 (既定値は5)
bar <- function(a, r, n = 5){ out <- a*r^(1:n-1) # 1:n-1 と 1:(n-1) は異なるので注意 return(out) # 値を返す } bar(1, 2) # 初項1 公比2 の最初の5項 bar(1, 2, 10) # 初項1 公比2 の最初の10項 bar(n = 10, 1, 2) # 変数名を指定すると引数の位置を変えることができる bar(r = 0.5, n = 10, a = 512) # 同上
[1] 1 2 4 8 16 [1] 1 2 4 8 16 32 64 128 256 512 [1] 1 2 4 8 16 32 64 128 256 512 [1] 512 256 128 64 32 16 8 4 2 1
参考: ヘロンの公式 より
\begin{equation} S=\sqrt{s(s-x)(s-y)(s-z)},\quad s=\frac{x+y+z}{2} \end{equation}
が成り立つ.
解答例
my_heron <- function(x, y, z){ #' 関数名は上書きされるので独特の名前にするのがお薦め s <- (x+y+z)/2 # 補助変数 s の計算 S <- sqrt(s*(s-x)*(s-y)*(s-z)) # ヘロンの公式による面積の計算 return(S) # 面積を返す } my_heron(3, 4, 5) # よく知られた直角三角形を使って計算結果を確認する my_heron(12, 13, 5)
[1] 6 [1] 30
sum()
を調べよ (help(sum)
)prod()
を調べよ (help(prod)
)R言語を含む多くの計算機言語では
if
(条件分岐)for
(繰り返し・回数指定)while
(繰り返し・条件指定)などの 制御文 が利用可能
if
文条件Aが 真 のとき処理Xを実行する
if(条件A) {処理X} # 括弧内は複数行に渡ってよい
上記の if
文に条件Aが 偽 のとき処理Yを実行することを追加する
if(条件A) {処理X} else {処理Y} # 複数行で記述する場合は改行位置に注意
if
文の例今日の日付が19で割り切れるか?
today <- 20240426 # 今日の日付 if(today %% 19 == 0) {# %% は余りを計算 print("割り切れます.商は以下の値です.") print(today %/% 19) # 商を表示 } else { # {}で囲まれたブロックが1つのまとまった処理に対応する print("割り切れません.余りは以下の値です.") print(today %% 19) # 余りを表示 }
[1] "割り切れません.余りは以下の値です." [1] 11
for
文
ベクトル V
の要素を 順に 変数 i
に代入して
処理Xを繰り返し実行する
for(i in V) {処理X} # V の要素はどんなデータ型でも良い
i
によって実行内容が変わってよいfor
文の例アルファベットの20,15,11,25,15番目を表示
print(LETTERS) # LETTERS ベクトルの内容を表示 for(i in c(20,15,11,25,15)) { print(LETTERS[i]) # 順番に表示 }
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" [19] "S" "T" "U" "V" "W" "X" "Y" "Z" [1] "T" [1] "O" [1] "K" [1] "Y" [1] "O"
while
文条件Aが 真 である限り処理Xを繰り返す
while(条件A) {処理X}
repeat
文というものもあるので調べてみよwhile
文の例素因数分解する
(n <- 2*11*17*31) # 分解の対象.今日の日付や my_fact(5) なども試してみよ p <- 2 # 最初に調べる数 while(n != 1){ # 商(for文の中で計算している)が1になるまで計算する if(n%%p == 0) { # 余りが0か確認 print(p) # 割り切った数を表示 n <- n/p # 商を計算して分解の対象を更新 } else { p <- p+1 # 割り切れない場合は次の数を調べる } # 更新される p は素数とは限らないのに上手く動く理由を考えてみよう }
[1] 11594 [1] 2 [1] 11 [1] 17 [1] 31
prod()
を用いないこと.
for
文を用いた解答例
my_fact1 <- function(n){ val <- 1 # 初期値の代入 for(i in 1:n){ # 1からnまで順に掛ける val <- val*i } return(val) # 計算結果を返す } my_fact1(4) # 正しい my_fact1(3) # 正しい my_fact1(2) # 正しい my_fact1(1) # 正しい my_fact1(0) # 間違い (0!=1)
[1] 24 [1] 6 [1] 2 [1] 1 [1] 0
if
文を用いた修正版
my_fact2 <- function(n){ if(n==0){ # n=0 か確認して分岐する return(1) } else { val <- 1 for(i in 1:n){ val <- val*i } return(val) } } my_fact2(4) # 正しい my_fact2(3) # 正しい my_fact2(2) # 正しい my_fact2(1) # 正しい my_fact2(0) # 正しい
[1] 24 [1] 6 [1] 2 [1] 1 [1] 1
while
文を用いた解答例
my_fact3 <- function(n){ val <- 1 # 初期値の代入 while(n>0){ # nから1まで順に掛ける.nが0なら計算しない val <- val*n n <- n-1 } return(val) } my_fact3(4) # 正しい my_fact3(3) # 正しい my_fact3(2) # 正しい my_fact3(1) # 正しい my_fact3(0) # 正しい
[1] 24 [1] 6 [1] 2 [1] 1 [1] 1
Fibonacci 数は以下の漸化式で計算される
\begin{align} F_{0}&=0\\ F_{1}&=1\\ F_{n}&=F_{n-1}+F_{n-2} \end{align}
is.vector()
が利用できる