關卡 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
存到x2
、 x2 - 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
。接著, 讓i
為1:99
的第二個element,也就是i=2
的狀況下去運算expr
。 重複這個動作,直到i
到1: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 只有 在expr1
為TRUE
的時候,才會執行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 中的for
和if
兩個功能。適當的使用這兩個功能,我們可以讓R 來完 成許多複雜的任務。