關卡 1
這門課程想要跟同學介紹R 中如何建立自己的函數。
關卡 2
R 中已經有非常多很方便的工具,例如mean
、sd
等各種 幫助使用者計算平均值、標準差的「函數」。而R 也可以讓使用者 建立自己的函數。
關卡 3
舉例來說,如果我們有一個矩陣m
和一個向量y
,我們 想要找到一個向量x
,讓m %*% x
很靠近y
。 這裡的m
可能是過去的一些資訊,而y
可能是我們感興趣的數 字,我們想預測的數字,或是我們想要了解它是如何變化的數字。 舉例來說,m
是車速,而y
則是煞車的滑行距離。 我們需要了解兩者的關係,才能建議合適的車速,以及與前車之間 要保持的安全距離。
關卡 4
首先我們先看看m 的值。請同學輸入m
m
關卡 5
我們再看看y 的值。請同學輸入y
y
關卡 6
因為m
是一個50 * 2 的矩陣,所以在R 裡面找一個長度為2 的向量, 例如c(-17, 4)
,我們就可以用m %*% c(-17, 4)
來當作是對y 的趨近。 請同學算算看m %*%
c(-17, 4)`
m %*% c(-17, 4)
關卡 7
接著我們來評估c(-17, 4)
是不是一個好的答案。請同學計算m %*% c(-17, 4) - y
的平方的和(Sum of Square)
sum((m %*% c(-17, 4) - y)^2)
關卡 8
通常在比較這個指標的時候,我們可以拿mean(y) - y
的平方的和作為一個參考值。 這因為y
的平均是一個趨近y 最最普通的一種方式,所以我們對y
的逼近應該要比mean(y)
來的好。請同學計算以mean(y) - y
的平方的和。
sum((mean(y) - y)^2)
關卡 9
請問同學,m %*% c(-17, 4)
和mean(y)
,哪一個趨近y
的效果比較好?(以誤差的平方和來評估)
m %*% c(-17, 4)
關卡 10
在上面兩個操作的時候,同學重複的計算兩次和y
相差的平方的和。這樣重複的計算, 在R 中是可以透過「撰寫函數」來簡化的。我們可以建立一個R 的函數物件f
,讓上述的兩個 計算的程式碼從sum((<???> - y)^2)
變成f(<???>)
的。
關卡 11
請同學輸入f <- function(x) sum((x - y)^2)
f <- function(x) sum((x - y)^2)
關卡 12
我們先試試看f
的效果。請同學輸入f(m %*% c(-17, 4))
,看看得到的答案是不是仍然是11491, 也就是我們之前算sum((m %*% c(-17, 4) - y)^2)
的答案。
f(m %*% c(-17, 4))
關卡 13
接著請同學輸入:f(mean(y))
,看看答案是不是32538.98,也就是sum((mean(y) - y)^2)
的結果。
f(mean(y))
關卡 14
我們來解釋一下:f <- function(x) sum((x - y)^2)
的效果。當我們輸入:f(mean(y))
時, R 就會進入到「函數的領域」(行話叫做「環境」,這部份在未來的RProgramming 課程中會仔細解釋) mean(y)
是f
的第一個參數,也就是x ,所以R 在計算sum((x - y)^2)
時,會用mean(y)
的值 替換掉x
,所以我們才能拿到和sum((mean(y) - y)^2)
一樣的計算結果。
關卡 15
同樣的道理,R 在計算f(m %*% c(-17, 4))
時,他會拿某個運算結果代入sum((x - y)^2)
的 x
。請問同學,下列哪一個運算結果是R 代入x
呢?
m %*% c(-17, 4)
關卡 16
透過f
,我們就可以很方便的計算估計的誤差的平方和。
關卡 17
但是回到原本的問題,我們是想要找一個長度為2 的向量,讓m 和這個向量相乘後,可以很靠近y 。 可是f
的參數x
,代表的意義已經是對y
的估計了,這樣在使用上還是不夠方便。我們可以利用f
來建立更方便的計算函數。請同學輸入:f1 <- function(x) f(m %*% x)
f1 <- function(x) f(m %*% x)
關卡 18
請同學輸入:f1(c(-17, 4))
,是不是再次得到一樣的答案:11491呢?但是我們輸入的程式碼更短了。
f1(c(-17, 4))
關卡 19
請同學輸入f1(c(1, 1))
,我們可以很快的得到如果拿m %*% c(1, 1)
逼近y
後得到的結果好不好。
f1(c(1, 1))
關卡 20
把f1(c(1, 1))
的結果與f(mean(y))
的答案32538.98相比,請問哪一個逼近的效果比較好?
mean(y)
關卡 21
一般來說,如果要靠瞎猜,猜到一組參數x
讓m %*% x
的估計比mean(y)
好也不會太容易。
關卡 22
另外我們剛剛透過定義f
和f1
來簡化重複的動作。當我們在撰寫複雜的程式時,這類簡化的動作 可以讓未來的工作效率。函數的設計,在近代軟體工程的領域中,也是有許多好的規範。這份教材只是介紹 R 的函數功能,如果未來同學有需要寫複雜的R 程式,建議還是查查相關的資料後再動手,會讓自己的工作 效率更高。
關卡 23
在R 之中我們可以利用optim
來尋找一個函數的最小值。 請同學輸入:optim(c(0,0), f1)
並且把結果儲存到變數 r
之中。我們先讓同學玩一玩r
之後,再解釋optim
。這段 玩的過程,也是當我們第一次使用R 強大的計算功能後,得到的結 果。
r <- optim(par = c(0,0), f1)
關卡 24
這裡的optim 函數很厲害,可以找到一個向量讓f1
的輸出最小。 這些資訊現在都在變數r
之中。請同學檢查一下r
的型態。
class(r)
關卡 25
接著,請同學列出所有r
元素的名稱。
names(r)
關卡 26
請同學輸入?optim
讀一讀optim
的說明,尤其是下一個問題 是要參考Value 這個段落中的說明文字。
?optim
關卡 27
請問同學,哪一個r
的元素代表著產生最小值的beta
?
par
關卡 28
我們回來看看原先計算r
的程式碼:optim(c(0,0), f1)
。 請問同學,c(0, 0)
對應到optim
這個函數的哪一個參數?請參考 optim 的說明文件作答。
par
關卡 29
另外一個R 很重要的特色是,函數本身也是一種物件。R 其實是「函數式語言」,而這是所有函數式語言 的一個重要特色。所以,「函數可以當成參數給另外一個函數的」。
關卡 30
請問同學,在optim(c(0,0), f1)
中,f1
對應到optim
這個函數的哪一個參數? 請參考optim 的說明文件作答。
fn
關卡 31
請問f1
的型態(class)是什麼?
class(f1)
關卡 32
在optim
的範例中,我們運用f1
告訴R 我們在乎的指標(也就是透過和m
做相乘後與y
的差別), 這裡的f1
是一個動態的動作:R 每猜一個,例如c(0,0)
的值,就會用f1
來評估猜的好不好。 透過一些最佳化的演算法,R 就可以找到最好的猜測。
關卡 33
請同學輸入r$par
看看optim
找到的最佳解
r$par
關卡 34
讓我們用迴歸分析的方法找到最好的解。請同學輸入solve(t(m) %*% m, t(m) %*% y)
solve(t(m) %*% m, t(m) %*% y)
關卡 35
找到的解是不是非常接近呢?
關卡 36
以上就是對於R 的函數功能的簡單簡介。