關卡 1
這門課程是要介紹R 的線性代數運算系統。線性代數在許多現代的統計方法、Data Mining方法上都很重要。 理解R 的線性代數系統,無論是對於撰寫自己的演算法,或是了解Open Source的演算法,都是非常重要的。
關卡 2
我們先來複習R 中的向量。請同學建立一個型態為numeric,由1到18的向量。
1:18
關卡 3
我們可以利用matrix
這個函數來建立一個矩陣。舉例來說,matrix(1:18, 6, 3)
就可以建立一個6 乘3 的矩陣。 請同學試試看,並把這個矩陣寫入變數x 。
x <- matrix(1:18, 6, 3)
關卡 4
要了解matrix
,請先打開matrix的說明頁面。
help(matrix)
關卡 5
根據matrix的說明頁面,請問以下哪些不是matrix的參數呢?
dim
關卡 6
數學上來說,一個矩陣除了值之外,需要的就是維度的定義。而matrix
這個函數中,data
的參數代表該矩陣的值, nrow
的部份代表該矩陣的列數,而ncol
的部份則代表該矩陣的行數。 根據上述的邏輯,matrix(1:18, 6, 3)
會產生一個6 列3 行(簡稱6 乘3 )的矩陣。 請同學輸入x
看一下R 是如何印出x 這個6 乘3 的矩陣。
x
關卡 7
請同學看看x 的屬性。
attributes(x)
關卡 8
有一個名字叫做“dim”的屬性,值是c(6, 3)
,代表這是一個6 乘3 的矩陣。
關卡 9
重要的屬性,R 都會提供內建函數來方便存取。dim
就是可以存取矩陣維度的函數。 請同學試試看:dim(x)
dim(x)
關卡 10
也可以利用dim(x) <- c(3, 6)
來更改x 的維度。請同學試試看。
dim(x) <- c(3, 6)
關卡 11
我們可以把x 印出來看看。
x
關卡 12
R 的除了矩陣(matrix)之外,還有高維度的陣列。 我們可以直接更改x 的維度到更高維。請同學試試看:dim(x) <- c(3, 3, 2)
。
dim(x) <- c(3, 3, 2)
關卡 13
請同學把x 印出來看看。
x
關卡 14
也可以利用array(1:18, c(3, 3, 2))
來建立一個高維矩陣。這裡很清楚可以看到,array
的第二個參數就是維度。 我們請同學試試看輸入array(1:18, c(3, 3, 2))
。
array(1:18, c(3, 3, 2))
關卡 15
在RBasic-02-Data-Structure-Vectors的課程中,我們有提過兩種方式,可以從向量中挑選一部分的值。 一種是用座標,另外一種則是使用邏輯向量。 在矩陣和陣列上,還是可以用這兩種方式從矩陣或陣列中挑選一部分的值。
關卡 16
我們可以利用中括號[
來取出矩陣或陣列中部分的值。舉例來說,如果x 是矩陣,x[2,1]
會取出x 第二列第一行的值。 陣列的狀況也是類似的。 x[1,2,3]
則會拿出第一個維度的第1 個方向,第二個維度的第2 個方向,第三個維度的第3 個方向。 這就是以座標的方式做挑選。
關卡 17
我們來測測看同學是否理解剛剛的說明。 目前相當於array(1:18, c(3, 3, 2))
的x , x[1,2,2]
的值會是多少呢?
13
關卡 18
在R 中,矩陣的資料順序是:c(x[1,1], x[2,1], x[3,1], ...)
。也就是說,如果我們下指令:matrix(1:18, 3, 6)
, 則x[1,1]會是1, x[2,1]會是2, x[3,1]是3, x[1,2]是4, 以此類推。高維度的矩陣也是類似。 我們來試試看,目前的x 是一個高維陣列,請問:x[3,1,1]的值會是多少呢?
3
關卡 19
如果給一個陣列,而只是要取單一個方向的向量,也可以適當的使用[
完成取出。 請同學再印出x 一次。
x
關卡 20
我們可以看到,在螢幕上的, , 2
之後,顯示出一個3 乘3 的矩陣。 這個矩陣即是沿著第三個維度的第2個方向所切面出來的矩陣。 也是螢幕上, , 2
所代表的意思。 而在R 中,我們可以利用x[,,2]
取得這個矩陣。請取得這個矩陣,並把它存到變數x2中。
x2 <- x[,,2]
關卡 21
我們先印出x2來看看。
x2
關卡 22
如果我們要選出第一列,只要輸入x2[1,]
就可以了。請看一下x2的輸出,在第一列的左方有[1,]
的圖示,即是提示可以用x2[1,]
來選出第一列。 我們請同學試試看選出x2[1,]
x2[1,]
關卡 23
如果要直接從x 中,呼叫, , 2
之下矩陣裡的第一列,我們可以使用:x[1,,2]
。 這裡的矩陣,在左方有[1,]
、[2,]
和[3,]
,代表著若要取出對應的列,我們要分別使用:x[1,]
、x[2,]
和x[3,]
這樣的符號。 由於目前x 是一個三個維度的陣列,最後,還需要加上上述的:, , 2
。 所以若是要執行「呼叫, , 2
之下矩陣裡的第一列」,就會變成:x[1, , 2]
。請同學試試看。
x[1,,2]
關卡 24
回答下一個問題之前,我們先印出x。
x
關卡 25
請問x[,3,1]
的值會是什麼呢?
c(7,8,9)
關卡 26
也可以利用中括號[]
搭配邏輯向量,取出矩陣或陣列中的值。 R 會根據邏輯向量在[]
中的位置,選擇該維度,只挑出該邏輯向量為TRUE的座標。
關卡 27
請問同學,依照上述的說明,x[c(TRUE, TRUE, FALSE), , ]
的效果等同於以下哪一個程式碼呢?
x[1:2,,]
關卡 28
接著我們介紹如何修改矩陣和陣列的元素。
關卡 29
如果我們要修改矩陣的值,只需要搭配使用[]
和<-
就可以了。 首先,如果我們要將x[1,1,1]
的值更改為2, 我們可以使用x[1,1,1] <- 2
。請同學試試看。
x[1,1,1] <- 2
關卡 30
我們可以印出x[1,1,1]
(不是印出全部的x)確認數值是否被修改成功。
x[1,1,1]
關卡 31
要更改一整排的資料也是類似的方法。 舉例來說,x[,1,1] <- 3
可以把, , 1
底下矩陣的[,1]
該行改成c(3,3,3)
向量。 這樣的運算也是向量式,R 會自動重複3 直到把x[,1,1]填滿。
x[,1,1] <- 3
關卡 32
我們可以把x[,,1]
印出來看看更改後的效果。
x[,,1]
關卡 33
希望這樣的說明可以讓同學了解R 如何存取矩陣和陣列的資料。
關卡 34
接下來說明的是陣列和矩陣的向量式運算。 先複習一下在向量的狀況下,R 的向量式運算。
關卡 35
請問c(1,2,3) + c(2,4,6)
的結果會是?
c(3,6,9)
關卡 36
請問c(1,2,3) + 2
的結果會是?
c(3,4,5)
關卡 37
先針對矩陣的向量式運算進行說明。它和向量的運算非常類似,在運算時R 也會自動比對位置,並且在相同運算位置上做運算。 請同學先印出x[,,1]
。
x[,,1]
關卡 38
再請同學印出x[,,2]
。
x[,,2]
關卡 39
再請同學試試看:x[,,1] + x[,,2]
x[,,1] + x[,,2]
關卡 40
這裡相加的結果,就是將x[,,1]
和x[,,2]
對應的位置做相加。同學可以比對前面的輸出結果。
關卡 41
而當維度不相同的時候,R 會自動重複維度較低的那方。 舉例來說,當一邊是矩陣,一邊是單值的時候,運算相對簡單。 請同學試試看:x[,,1] + 1
x[,,1] + 1
關卡 42
但是,當兩邊都是矩陣或陣列,並且長度不一樣時,就不容易了。 先跟同學複習一下,陣列的值的排列方式。 如果y <- array(1:8, c(2, 2, 2))
,那y[1,1,1]
是1 、y[2,1,1]
是2 。 R 會將1:8
的值依照第一個維度(列)、第二個維度(行)到第三個維度,一個一個填入。 以此類推,所以y[1,2,1]
的值會是?
3
關卡 43
當陣列和向量相加的時候,R 會一直重複向量,直到向量的長度和陣列需要的長度相符合。舉例來說,一個3 乘2 乘2 的陣列需要12個值。 接著,R 會把這個向量轉換成和陣列一樣的維度,然後在對應的位置做相加。請同學試試看:matrix(1:4, 2, 2) + 1:2
matrix(1:4, 2, 2) + 1:2
關卡 44
另外提及一件重要的事情,是關於上一個課程中有提到屬性的概念。 現在的變數x 也是個R 物件,也有屬性。請同學查一下它的屬性。
attributes(x)
關卡 45
同學是否有看到名稱叫做dim 的一個整數向量呢?這個dim 屬性非常重要,所有的矩陣和陣列,都是一般的向量加上dim 這個屬性。 R 也提供了dim
這個函數讓使用者可以存取dim 屬性。 舉例來說,dim(x)
會印出x 的維度。而我們可以透過dim(x) <- NULL
來移除x 的dim 屬性。 請同學試試看dim(x) <- NULL
。
dim(x) <- NULL
關卡 46
請同學印出x
來看看。
x
關卡 47
是不是就變成向量了呢?
關卡 48
R 中的陣列和向量的向量式運算,也可以回到兩個向量的運算。 差別在於它們多了維度的屬性,所以當維度差異太大的時候,R 會認為向量式運算無效。 所以一般來說只會拿單值或向量去和陣列做運算,或是維度相同的矩陣或陣列進行運算。
關卡 49
基本上,+
、-
、*
和/
都會使用向量式運算。
關卡 50
在R 中,使用cbind
和rbind
則可以合併兩個矩陣。 舉例來說,cbind(matrix(1:4, 2, 2), matrix(1:4, 2, 2))
會將兩個矩陣的行合併,運算之後會變成2 乘 4的矩陣。請同學試試看。
cbind(matrix(1:4, 2, 2), matrix(1:4, 2, 2))
關卡 51
使用rbind(matrix(1:4, 2, 2), matrix(1:4, 2, 2))
則會把兩個矩陣的列合併, 運算之後會變成4 乘 2的矩陣。請同學試試看。
rbind(matrix(1:4, 2, 2), matrix(1:4, 2, 2))
關卡 52
最後,我們介紹一些和線性代數相關的運算子和函數。 如果對線性代數不熟悉的同學,可以在看過反矩陣之後跳過(使用skip()
)後面的課程。
關卡 53
在R 中兩個矩陣要作矩陣乘法,就是使用%*%
這個運算符號。請同學試試看:matrix(1:6, 2, 3) %*% matrix(3:8, 3, 2)
matrix(1:6, 2, 3) %*% matrix(3:8, 3, 2)
關卡 54
當兩個向量使用%*%
做運算,會得到他們的內積。 舉例來說:1:3 %*% 1:3
會得到什麼呢?請同學試試看。
1:3 %*% 1:3
關卡 55
當矩陣乘向量的時候,單一向量會被視為行向量,最後會得到矩陣每個列和單一向量的內積,形成一個新的行向量。 舉例來說:matrix(1:9,3,3) %*% 1:3
會得到什麼呢?請同學試試看。
matrix(1:9,3,3) %*% 1:3
關卡 56
在R 中,線性代數運算的底層是透過BLAS等函式庫做運算的,所以效能遠勝過自己用C 寫的線性代數運算。 另外,R 預設的BLAS庫為比較被廣泛驗證過正確性的版本,而非效能比較快版本。 這是因為,R core Team認為正確性比較重要,所以目前是採用比較舊,但是也比較可靠的BLAS庫。
關卡 57
在R 中,要對一個矩陣做轉置,可以用t
這個函數。請同學先印出matrix(1:4, 2, 2)
matrix(1:4, 2, 2)
關卡 58
再印出:t(matrix(1:4, 2, 2))
t(matrix(1:4, 2, 2))
關卡 59
我們可以用diag
快速建構對角化的矩陣。舉例來說:diag(1, 3)
會建立出3 乘3 的單位矩陣。請試試看。
diag(1, 3)
關卡 60
如果已知A %*% x = b
,給定A
和b
,我們就可以用solve
解出 x 。 舉例來說,若A
是matrix(1:4, 2, 2)
、b 是c(3, 8)
,solve(A, b)
即可以給出x
。 變數A
和b
已經存在了,所以請同學直接解出x
並且把它存到x
之中。
x <- solve(A, b)
關卡 61
我們來驗算一下,A %*% x
的結果是否真的是b
呢?
A %*% x
關卡 62
如果直接使用solve(A)
,則R 會算出A 的反矩陣。請同學試試看。
solve(A)
關卡 63
使用eigen(A)
則可以解出A 的特徵值(eigenvalues)和特徵向量(eigenvectors)。 我們可以試試看: A %*% eigen(A)$vectors[,1] / eigen(A)$vectors[,1]
是不是相除後,會拿到一模一樣的值呢? 這裡的$
用法,等到下一個課程,我們會有詳細的說明。
A %*% eigen(A)$vectors[,1] / eigen(A)$vectors[,1]
關卡 64
最後,我們請同學用所學到的技巧,做一個簡短的練習。 請同學在完成之後存檔,並輸入submit()
來檢查結果是否符合預期。 如果同學在檔案中看到亂碼,請使用Rstudio 左上角的File -> Reopen With Encoding… -> 選取:UTF-8
X <- cbind(x1 = 1, x2 = 1:10, x3 = sin(1:10))
beta <- c(0.5, -1, 4.3)
y <- X %*% beta
#' epsilon 是一個隨機產生的雜訊向量
epsilon <- c(-1.24462014500259, 0.146172987456978, 1.56426869006839, -0.856920339050681,
-1.15277300953772, 0.717919832604741, -0.270623615316431, -1.66281578024014,
-1.15557078461633, -0.730253254897595)
#' 我們讓y 參雜了雜訊
y <- y + epsilon
beta.hat <- solve(t(X)%*%X, t(X)%*%y)
#' 同學可以比較一下beta.hat和beta,體驗看看迴歸分析的方法,是不是真的有道理。