關卡 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的平方的和(SumofSquare)

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的函數功能的簡單簡介。