關卡 1

這門課程想要跟同學介紹R 中如何建立自己的函數。

關卡 2

R 中已經有非常多很方便的工具,例如meansd等各種 幫助使用者計算平均值、標準差的「函數」。而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

一般來說,如果要靠瞎猜,猜到一組參數xm %*% x的估計比mean(y)好也不會太容易。

關卡 22

另外我們剛剛透過定義ff1來簡化重複的動作。當我們在撰寫複雜的程式時,這類簡化的動作 可以讓未來的工作效率。函數的設計,在近代軟體工程的領域中,也是有許多好的規範。這份教材只是介紹 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 的函數功能的簡單簡介。