29. 条件分岐


条件分岐 : if ,else

ある条件で場合分けをして処理を行いたい場合は if 文,else 文を使う.以下の「条件式」には TRUE や FALSE の論理値を一つだけ返す式を入れなければならない.

 
 x <- 2
 if (x > 0) {                 # if ( 条件式 )
   sum(1:x)                   #  条件式が TRUE  のときに実行される部分
 } else {
   x <- -x                    #  条件式が FALSE のときに実行される部分
   sum(1:x)                   # 
 }

if と else を括弧無しで複数行に分けるとエラーとなる(下:3 〜 4 行目).また,} と else の間で改行するとエラーとなる(下:5 〜 6 行目).R は,

の時点で「一連の式が終わった」と思うので,その次に else が出ると「 if が無いのに else が来た!」と思ってエラーを出す.

 
 a <- rnorm(1)
 if (a >= 0) {
   if (a == 0) b <- "zero"
   else b <- a                # エラーが出る!
 }
 else b <- -a                 # エラーが出る!

よって,「一連の式はここからここまで」ということを R に教えるためには,括弧で括って複合式とするか,if の評価が終了して改行するまでに else を書く必要がある.

 
 { 
   if (a >= 0) { 
     if (a == 0) b <- "zero" 
     else b <- a
   } 
   else b <- -a               # エラーは出ない 
 }

以上の理由により,関数定義内で以下の様にやってもエラーは出ない.

 
 myfunc <- function(a) {
   if (a >= 0) {
     if (a == 0) b <- "zero"
     else b <- a              # エラーは出ない
   }
   else b <- -a               # エラーは出ない
   return(c(a,b))
 } 

R は 型変換のルール により 「0 でない数 → TRUE 」 と解釈してしまう.例えば if (3.14) などは TRUE になり,if 文の命令が実行されることになる.よくあるエラーが,if 文の条件 x <- 2 をくっ付けて書いてしまったために代入文と勘違いされ,「代入文=0 でない数」 となり if の条件式が TRUE になってしまうことである.

 
 x <- -3
 if (x<-2) print(x)           # x<-2 は x に -2 を代入するという意味

[1] 2                         # 0 でないので TRUE になってしまう!

演算子や数値,関数などの間には空白 (スペース) を適宜入れる習慣を付けた方が良いという例である.

ところで,条件分岐 if や else は以下の様な書き方も出来る.

 
 if (a < 0) {                 # 普通の文中
   print(0)
 } else if (a < 1) {
   print(1)
 } else print(2)

 myfunc <- function(a) {      # 関数定義中
   if (a < 0)  print(0)
   else if (a < 1) print(1)
   else print(2)
 }

また,関数 ifelse(条件式, 式1, 式2) というものもある.条件式の部分にはオブジェクトを入れることが出来る.

 
 x <- c(-2:3)
 sqrt(x)

[1]      NaN      NaN 0.000000 1.000000 1.414214 1.732051
警告メッセージ:
NaN が生成されました in: sqrt(x) 

 sqrt(ifelse(x >= 0, x, NA))

[1]       NA       NA 0.000000 1.000000 1.414214 1.732051

条件分岐 : switch

条件式の評価結果がケース 1 ,ケース 2 ,ケース 3 ,・・・ と多数あり,その結果によって場合分けを行いたい場合には switch 文を使う.例えば文字列で条件を分けた場合の switch 文は左下のような形になる.また,整数で条件を分けた場合の switch 文は右下のようになる.ただし,整数で条件を分けた場合は 「一致するものがない時に実行される部分」 は指定出来ない点,整数が 1 ... n でなければ NULL が返される点に注意.

 
 a <- 1
 switch(a,               # switch(文字列,
   "1" = print("one"),   #  "1" のときに実行
   "2" = print("two"),   #  "2" のときに実行
   print("?")            #  一致するものが
 )                       #      ない時に実行

[1] "one"

 a <- 2
 switch(a,               # switch(整数,
   print("one"),         #   1 のときに実行
   print("two")          #   2 のときに実行
 )

[1] "two"

演算子 && ,||

条件式に2つ以上の条件が組み合わさった様な条件判定をさせたい場合は &&(かつ) や ||(または) を用いる.

 
 a <- 2
 b <- -3
 if ((a > 0) && (b > 0)) {
   c <- a*b
 } else c <- -a*b
 c

[1] 6

 a <- 2
 b <- -3
 if ((a < 0) || (b < 0)) {
   c <- -a*b
 } else c <- a*b
 c

[1] 6

上記の例は,一見 「 a と b の積の絶対値」 を計算しているように見えますが,ロジックに穴があります・・・.ご注意下さい.