第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.7987612 0.4284254 -0.7624699 -0.1197531 -1.0761344 [1] 10.38788 10.53880 11.08746 10.18092 11.45359 [1] -0.066675654 -0.135083640 0.008429749 0.005835604 -0.181368959 [1] -0.7958739 3.6377440 6.5379324 1.3335692 2.3699861
ヒストグラムの表示
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" [18] "R" "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()
が利用できる