Skip to content

Latest commit

 

History

History
150 lines (116 loc) · 5.79 KB

ch2.4.md

File metadata and controls

150 lines (116 loc) · 5.79 KB

R 的流程控制

很多生物或生態背景的人看到「程式設計」都會有點恐懼,其實程式設計並不難,基本上就是了解語法及邏輯。在這節我們會用簡單的例子來介紹 R 的程式設計,尤其是流程控制(flow control)這部份。 相信許多人都會畫簡易的流程圖,這部份的流程控制就是把流程圖轉換成文字來告訴 R 該怎麼執行。流程控制在程式語言中有個專有名詞稱為「控制結構(control structure)」,通常在一般的程式語言中,有循序(sequence)、選擇(selection)以及重複(repitition)三種類別。「循序」就是由上至下一行一行的依照順序執行,我們在寫 R 程式碼時大部分都是循序的執行;「選擇」則是有許多不同的條件,如果符合條件的話, 就會依照條件下來執行;「重複」字面上來看就是不斷地重複執行某些工作。

我們用生活中的例子來說來協助理解,例如使用洗衣機洗衣服,在 R 程式設計中該怎麼用控制結構呢?

控制結構:

  1. 洗衣機有插電嗎?
    有:進行步驟 2
    無:插上插頭後,進行步驟 2
  2. 放髒衣服進洗衣槽

在 R 的流程控制中,即使是像洗衣機插上插頭這種細節都必須要寫進去。 所以我們接下來先看一下 R 裡頭的控制結構有哪些,再分別一個一個來仔細說明。

邏輯判斷

R 中的控制結構總覽

在 R 裡頭的控制結構總覽請參見下表,細節將會在後面的部份解釋

表 2-1. R 的控制總覽表

R 的控制結構 類型 解釋 語法
if ... else 選擇 如果 ... 然後 if ( condition ) expression else expression
ifelse 選擇 如果 ... 然後 ifelse(testCondition, yes, no)
switch 選擇 根據條件切換 switch(expression, ...)
for 重複 變數在某序列下,重複執行 for ( variable in sequence) expression
while 重複 根據某些條件下,重複執行 while ( condition ) expression

選擇:ifelse, if-else 及 switch

在選擇的控制結構中,簡單來說就是「**如果(if)發生一件事情然後(then)**做些什麼」, 例如:如果今天下雨,然後出門你要記得帶傘。若把它翻譯成 R 可以理解的語言,我們可以這樣寫

如果 ( 下雨了 ) {
   出門記得帶傘
}

注意,上面的程式碼(code)並非可以直接執行的,只是示意,我們通常稱這樣的程式碼為 虛擬程式碼(pseudocode)。 使用虛擬程式碼可以幫助你先將複雜的演算法(algorithm,或籠統稱為「作法」) 的概念用常人比較容易懂的方式寫出來,之後就可以轉換成該語言之程式碼。

R 的語法如下:

ifelse( testCondition, yes, no)

如果有個變數 val 的數值,我們想判斷這個變數是否大於 10,在 R 可以寫成

ifelse( val > 10, 'Yes', 'No')

如果變數 val 大於 10, R 就會顯示 "Yes",反之則是 "No"

若選擇的控制結構比較複雜,可以用大括號把 expression 包起來,如下:

if ( condition ) {
    expression
} else {
    expression
}

其中 condition 指的是判斷的條件。而 expression 則是要陳述的表示式(字面上有點難理解,不過就是諸如運算式、 印出資料等都是 expression)。你也可以只寫 if 而不用加上 else。若你需要做條件判斷的情形比較複雜, 即超過兩個以上的條件判斷,可以使用 if 加上 elseif ,最後再使用 else來處理,例如:

# 隨機產生一個數值
a = rnorm(1)
# if-elseif-else 選擇
if ( a < 5 ) {
  print("a is less than 5")
} else if ( a > 0 ) {
  print("a is between 0 to 5")
} else {
  print("a is greater than 5")
}

重複

重複執行某些動作,在 R 的語法可以使用 for 迴圈(loop)或 while 迴圈。 迴圈代表重複執行某些動作,例如我想在 R console 中印出 1, 2, 3, ... 一直到 100:

# 印出 1, 2, 3
> print(1)
[1] 1
> print(2)
[1] 2
> print(3)
[1] 3
> print(4)
[1] 4
... (以下省略) ...
> print(100)
[1] 100

這個時候如果每印出一個數字,就要輸入 print(n),不就要 100 行 code 才能完成嗎? 所以迴圈就可以解決這類重複執行的動作,同樣印出 1 至 100,使用 for 迴圈可以這樣做:

for ( i in 1:100 ){
    print(i)
}

for 迴圈的語法如下,括號內包的是執行動作時的序列:

for ( 序列 ){
    執行動作
}

另外一個迴圈則是 while,如果同樣印出 1 至 100 的數字,while 迴圈則要寫成:

# 先把 i 的起始數值設定為 1
i <- 1
while ( i <= 100 ){
    # 印出 i 的數值
    print(i)
    # 接下來設定 i' = i + 1,也就是每印完一個數字後,
    # i 自動加 1
    i <- i + 1
}

有注意到嗎?在 for 迴圈中,括號內要設定好一個序列,例如 1 至 100 (R 的語法 1:100), 但 while 則是限定在某個條件下,以本例來說就是 i 小於等於 100 時, R 才會重複大括號內的執行動作。如果今天寫 while ( 1+1 == 2 ) 時, 這個迴圈就會變成「無窮迴圈」了,R 會一直執行他到天荒地老永遠都不會停! 如果你不幸的沒寫好讓它變成無窮迴圈的話,你只要按 RStudio 的 R console 右上角的 stop 就可以停止執行, 或是在非 RStudio 介面下,按 Ctrl + c 來強迫中斷執行。

RStudio 停止執行 R Console 內的動作