關卡 1

這門課程要介紹R 語言的迴圈,以及常見的應用案例。

關卡 2

迴圈是一種寫程式時很泛用的技巧,可以幫助我們用 簡短的程式碼來執行重複的動作。

關卡 3

在做機器學習時,有些演算法是透過不停的重複做一樣 的計算,而每次計算都能把學習的結果再改善一些。這類的動 作就很適合用迴圈實做。

關卡 4

讓我們用一個數學上的小應用來練習。假設我們要找 出一個數x ,使得f(x) = x^2的值最小。雖然我們知道這個 問題的答案是x=0 ,但是這裡讓我們用數值方法來逼近答案。

關卡 5

請同學先把數字3 存入變數x0

x0 <- 3

關卡 6

先讓我們輸入x0^2,計算f(x0)的結果。

x0^2

關卡 7

接著,我們把x0 - 0.2 * x0 存到變數x1

x1 <- x0 - 0.2 * x0

關卡 8

請同學計算f(x1)的值。

x1^2

關卡 9

請問同學,f(x0)和f(x1),何者較小?

f(x1)

關卡 10

事實上,數學可以證明如果我們把x1 - 0.2 * x1存到x2x2 - 0.2 * x2存到x3… 以此類推,x1、x2、x3… 就會越來越 靠近最終的答案,也就是0 。讓我們用迴圈來驗證這件事。

關卡 11

首先,假定我們要重複算99次。請同學先建立一個長度 為100 的數值向量,並且把它存到變數x 之中。

x <- numeric(100)

關卡 12

請把3 存到x 的第一個element

x[1] <- 3

關卡 13

請把x[1] - 0.2 * x[1] 存到x 的第二個element

x[2] <- x[1] - 0.2 * x[1]

關卡 14

同學可能已經瞭解,類似x[1] - 0.2 * x[1]的運算會 一直重複。差別只在於x[1] - 0.2 * x[1]中的x[1]需要做 改變。

關卡 15

其實x[1]在這裡,可以看成是x[1] - 0.2 * x[1]的運算 的輸入位置,是x 的第一個element 。理解了這一點之後,為了讓R 可以在改變x[1] 的情形下重複x[1] - 0.2 * x[1] 這樣的運算, 我們可以利用一個變數i 來代表現在要運算的位置。請同學把1 存入變數i

i <- 1

關卡 16

接著,我們可以把x[2] <- x[1] - 0.2 * x[1]這樣的運算 用i 改寫,請同學試試看。請注意,這裡x[2] 的意義,是x[1] 的「下一個位置」。

x[i + 1] <- x[i] - 0.2 * x[i]

關卡 17

在完成上一個問題之後,我們只要讓i=1 的時候跑一次運算、 i=2 再跑一次運算、一直重複這個動作到i=99。在R 裡面,我們可 運用for 這個語法來達成這個目的。下一個指令,我們先讓同學複製 貼上一個R 的迴圈指令,再跟同學解釋。

關卡 18

請同學輸入:for(i in 1:99) x[i + 1] <- x[i] - 0.2 * x[i]

for(i in 1:99) x[i + 1] <- x[i] - 0.2 * x[i]

關卡 19

請同學輸入x ,就可以看看計算結果了。x 越後面的element, 就越靠近0 。

x

關卡 20

請問同學,這裡1:99的長度是多少?

99

關卡 21

在R 中,for(i in 1:99) expr的語法代表的,就是讓i是 為1:99的第一個element,也就是i=1 的狀況下去運算expr。接著, 讓i1:99的第二個element,也就是i=2的狀況下去運算expr。 重複這個動作,直到i1:99的最後一個element,也就是i=99的狀況。 提醒同學,這裡的expr就是x[i + 1] <- x[i] - 0.2 * x[i]

關卡 22

其實大部分機器學習算法的核心,是非常類似我們上述所做的動作: 「不停的改善既有的答案」。一開始我們先猜 3,然後我們得出一個可以改 善答案的方法(x[i + 1] <- x[i] - 0.2 * x[i]),最後得到一個「夠用」 的答案。

關卡 23

除了上述的範例之外,for迴圈也常常用於處理各種資料處理的工作。 舉例來說,如果我知道所有要讀資料的檔案名稱,依序是:“data/1.csv”、 “data/2.csv”和、“data/3.csv”,那我們要如何用for迴圈讀取所有的資料呢?

關卡 24

這類的應用,我們需要懂一點用R 產生字串的函數,才能做出來。 請同學先輸入:paste0("data/", 1, ".csv")

paste0("data/", 1, ".csv")

關卡 25

這裡的paste0函數可以把輸入的R 物件粘接成一個字串。另一個非常相似 的函數是:paste。兩者最主要的差異,在於paste0 是直接粘接,而paste 在粘接時預設會插入空格。

關卡 26

另一個問題,是跑迴圈時,要如何儲存每一次執行expr後得到的結果。 當輸出結果是數字時,我們可以像上述的範例,先建立一個向量來儲存。更一般 的狀況中,可以建立一個list來儲存結果。提醒同學,list可以儲存任何的 R 物件。

關卡 27

假設我們先建立一個list()並取名為retval,接著我們想 用for(i in <??>) retval[[i]] <- read.table(paste0("data/", i, ".csv"))來 一口氣讀取“data/1.csv”、“data/2.csv”、“data/3.csv”。請問同學, <??>應該要填入什麼呢?

c(1,2,3)

關卡 28

上述的兩個例子,大致上呈現R 的迴圈功能,以及在使用上所需要 搭配的一些小撇步。

關卡 29

接著,再讓我們回到第一個範例。在實務上,我們不可能無窮無盡的 讓改善答案的過程一直做下去。當答案「夠用」的時候,我們就想停止這個過程。 除了用預先規劃跑99 次的方式之外,另外一種常用的方式,是衡量每次改善的幅 度,並且當改善幅度太小的時候,中斷執行的程序。

關卡 30

通常,我們會拿這次的答案和上一次的答案做比較,如果差異過小,就 代表能改善的幅度已經太小,答案可能已經夠用了。 在這裡,我們利用abs(x[2] - x[1])可以計算第一次計算後答案的差異。這 裡的abs是取絕對值的運算。abs可以保證回傳的都是正數,在比大小時很常用。 同理,請同學計算第二次計算後答案的差異。

abs(x[3] - x[2])

關卡 31

一個實務上常常採用的策略是:我們希望在答案差異小於0.01的時候, 終止迴圈運算,否則就會一直計算。同時,我們希望迴圈最多跑99次。

關卡 32

要達到這樣的功能,我們需要先解決:「在改善幅度小於0.01的時候, 終止迴圈運算,否則就會一直計算」的程式。 在R 之中,我們可以利用if (expr1) expr2來寫出這樣的程式。這樣,R 只有 在expr1TRUE的時候,才會執行expr2。否則就會略過。

關卡 33

在R 的break函數則可以中斷迴圈。

關卡 34

回到原本的問題,我們可能會寫出這樣的程式碼。 請同學在R 打開編輯器之後,閱讀程式碼,再回到swirl中 輸入submit()

# 重新初始化x 的內容
x <- numeric(100)
x[1] <- 3
# 尋找x^2的最小值
for(i in 1:99) {
  x[i + 1] <- x[i] - 0.2 * x[i]
  if (abs(x[i + 1] - x[i]) < 0.01) break
}

關卡 35

請同學先印出x 得值

x

關卡 36

請問同學,這個計算在執行多少次就停止了?

20

關卡 37

這份課程利用兩個常見的範例來跟同學介紹R 中的forif兩個功能。適當的使用這兩個功能,我們可以讓R 來完 成許多複雜的任務。