R Learning Notes: Vectors, Object, Factor, Arrays, Matrices.

— — — — — — — — — — — — — — — — — — — — —

我們通常給R 的指令分成兩種,一個expression,或是一個assignment:

? source 即為一個express的動作
`a <- 1`即是一個assignment的動作。
這些存放資料的東西都叫做object,如上述例子中的`a`。object可以是一個變數、一連串的數字、文字,甚至是函數或更複雜的東西。

在R 中,我們可以利用`objects()`或`ls()`來列出所有目前存在的object

我們可以刪除已經存在的物件。舉例來說,如果我們要刪除`a`,就只要輸入:`rm(a)`。
R 的object結構是針對資料分析所設計的。所以最簡單 的object,就是一連串的數字。這讓R 和其他的程式語言不同,因為一般的程式語言最簡單的object會是一個數字。

這樣設計的理由是因為在資料分析的應用中,一定是同時處理多筆資料,而不會只有單一筆資料。


在R 中,`c()`可以接受任意數量的向量參數,並依照順序將它們串接成一個單一向量。

舉例來說:`c(x, 1)`會在剛剛我們建立的x 後面再接一個1 。 而`c(x, 2, 3)`則會在x之後接上2 和3 。

在R 中,大部份的運算都是向量式的。舉例來說,加法`+`在R 中就屬於向量式。

除了加減乘除之外,許多常用的數學算式都是向量式的。例如:`log`、`exp`、`sin`、`cos`、`tan`和`sqrt`。

R 也具備有簡易的功能,可以產生一些附帶有規則的序列。

例如:`1:10`就會產生自1 至10的序列。 這樣的功能,在整理資料時十分實用。舉例來說,如果需要取出第5筆到第100筆的資料,就會用到類似的語法。

除了數值之外,邏輯值也是很常見的。

類似數值,R 最基礎的object之一,就是邏輯向量。

在R中,我們看到的一個值,其實只是一個長度為1 的向量。邏輯向量常常表示資料中如「是、否」、「男、女」之類等二分法的選項。 除此之外,也很常用在程式碼的流程控制。

邏輯值「真」常用`TRUE`或`T`來代表。「假」則用`FALSE`或`F`代表。 第三種在邏輯向量會出現的值,就是NA(Not Available)。

x > 5
[1] FALSE FALSE FALSE

從結果可以看到,R 會拿x (`c(10.4, 5.6, 3.1, 6.4)`)中的值一個個的和5 比較大小。比較大的就是TRUE,而比較小的即是FALSE。

此類推,可用於建立邏輯向量的「條件」分別有:大於`>`、大於等於`>=`、小於`<`、小於等於`<=`、相等`==`和不相等`!=`。

這類邏輯向量在整理資料做資料篩選時,是很常用到的。

另外,「且」`&`以及「或」`|`這兩個邏輯運算子也是很常用的。它們可以在兩個邏輯向量中做運算。

在R 之中,我們已經看過兩種特別的記號,分別為:NA和NaN。 NA代表的是缺失值,而NaN 大多來自於數學運算中沒有定義的行為,無限大就是`Inf`。

有時候,我們需要處理文字類型的object。這些object通常被用於指定繪圖的標題、或是處理類別形變數,如:國籍、行政區等等。

在R之中,這類的資料是透過單引號`’`或雙引號`”`來建立的。而這類的資料也常被人稱為:「字串」。

最後,介紹一個在整理資料時被廣泛運用的功能:如何在向量中挑選出一部份的資料。

第一種方法,使用坐標。 在R 之中,如果我們要挑選序列x中的第一個和第三個位置的值,只要使用即可:`x[c(1,3)]`。

第二種方法則是利用邏輯向量。 舉例來說,如果要挑選x 之中超過5 的值,即可透過`x[x >5]`取得。

第三種方法是`x[-2]`,抓取除了第二個數值以外的所有值。


在R 中,我們操作的所有變數,都是一種R 物件(Object)。 這一堂課程中,就是要簡介R的物件結構。

在所有物件中,最基礎的「原子」物件,就是各種向量。 其他的物件都是由這些原子物件組合而成。


R 也可以建立一種叫做`list`的向量,這是「R 物件」的向量。 在此向量中,每一個值都是R物件,都具有各自的`mode`、`length`等屬性。我們會在較為複雜的統計模型中,見到這樣的資料型態。

舉例來說,在R 中如果要建立一個迴歸模型,會使用:`g <- lm(dist ~ speed, cars)`這樣的程式碼會利用車速當解釋變數、煞車距離當應變數,建立一個迴歸模型。

g <- lm(formula = dist ~ speed, data = cars)

g[1:2]

$coefficients
(Intercept) speed 
 -17.579095 3.932409
$residuals
 1 2 3 4 
 3.849460 11.849460 -5.947766 12.052234

在最上面的`$coefficients`,表示`g[1:2]`這個向量的第一個值(同時也是`g`的第一個值),是有名字的。而它的名字是:`”coefficients”`。

由於`g[1:2]`的第一個值是一個有名字的numeric 向量,R就把這個向量所有的名字和值一起顯示在console之中。 而這個numeric向量的第一個值是-17.579095,名字是`”(Intercept)”`。第二個值是3.932409,名字則是`”speed”`。

接著,`$residuals`表示`g[1:2]`的第二個值也是有名字的,而且它的名字是`”residuals”`。

由於這個值也是一個有名字的numeric 向量,所以R 就把值和名字同時顯示到console上。所以我們就可以知道,這個numeric 向量的第一個值的名字是`”1"`,值是3.849460。以此類推。


> list(1,a=2)
[[1]]
[1] 1
$a
[1] 2

在輸出結果的一開始,R 顯示了`[[1]]`,接著顯示一個值為1 的numeric 向量。

開頭的`[[1]]`不只說明了這個物件是一個list,也說明接下來顯示的是第一個值的內容。

接著,R 顯示了`$a`,以及顯示一個值為2 的numeric 向量。

開頭的`$a`因為位置在上述的`[[1]]`之後,所以代表這是這個list物件的第二個值。同時,這個值的名字是`”a”`。

若想找出`g`的第一個值的物件本身,而非被包在一個list中,我們需要用到:`g[[1]]`


list向量最實用的特性,在於它可以裝不同型態的值。

以`g`為範例,雖然大部分值的型態都是numeric,但是也有些型態為call和list的物件。

list向量讓R 的開發者能更有彈性的建立較為複雜的模型。

> mode(g[[10]])
[1] “call”

這裡的`g[[10]]`其實是記載著產生g 的程式碼。在R裡面,這樣的程式碼是存成call型態的物件。

我們現在只要知道這是一種call就可以了。至於call是什麼東西,要等到同學需要開始深入的學習R的原始碼、運作機制時, 才需要弄懂。我們現在只要知道,list可以裝所有R 的物件就可以了。


上述例子中,我們除了用`g[[1]]`來取得第一個值之外,也可以用`g[[“coefficients”]]`來取得第一個值。

因為`g`這個向量是被命名的,而第一個名字就是`”coefficients”`。

適當的命名,可以讓程式碼更易讀。

舉例來說,若知道`g`是一個迴歸模型,也知道迴歸模型通常就是一個參數向量,那我們就可以預期到`g[[“coefficients”]]`就是這個迴歸模型的參數。

(在統計學之中,不同迴歸模型的參數通常稱作:”coefficients”)。


所有的R 物件,都有「屬性」(attributes)。我們可以用`attributes`這個函數來印出一個R物件的屬性。

attributes這樣的功能在探索一些複雜的R 模型物件時是非常好用的。

之後深入探討`matrix`、`data.frame`等進階物件的時候,也會需要了解attributes的相關知識。現在,同學只要知道所有的R 物件都具有attributes就可以了。

而名稱為”class”的屬性是非常重要的,因為它牽涉到R 的物件導向設計。

由於”names”和”class”這兩個屬性是如此的重要,所以R 中設計有`class`和`names`這兩個函數,讓使用者可以針對一個R 物件的names和class進行修改。


Factor是一個向量物件,用途是儲存「類別」的資料。有這樣的資料格式,我們可以將資料集依照類別分組。

屬於「類別」資料的例子如:「男、女」、「台北市、台中市、台東市、台南市」等。

R印出Factor向量和文字向量的方式不太一樣。在Factor向量的部分多出了levels這個屬性。

Factor向量中的levels屬性,代表向量中允許出現的類別。

要取出這些類別,可使用levels函數。請輸入`levels(blood_type_factor)`來取出所有允許的血型。

Factor向量本質上只是整數向量加上levels。而這樣設計的原因是儲存整數比儲存文字更省空間。

「類別」的資料有兩種。分為「無順序」與「有順序」的,血型的資料是無順序的例子。因為血型並無大小先後之分,你無法說O型比A型大或小。

Factor向量用來儲存類別的資料。level屬性限制能在向量中出現的類別種類。

Factor本質上是整數向量,只是帶有levels。
Factor可以是無順序或有順序的,可用在Factor函數中使用ordered=TRUE讓Factor變成有順序。


我們可以利用`matrix`這個函數來建立一個矩陣。

舉例來說,`matrix(1:18, 6, 3)`就可以建立一個6 乘3 的矩陣。

[,1] [,2] [,3]
[1,] 1 7 13
[2,] 2 8 14
[3,] 3 9 15
[4,] 4 10 16
[5,] 5 11 17
[6,] 6 12 18
matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE,
dimnames = NULL)

數學上來說,一個矩陣除了值之外,需要的就是維度的定義。而`matrix`這個函數中,`data`的參數代表該矩陣的值,
`nrow`的部份代表該矩陣的列數,而`ncol`的部份則代表該矩陣的行數。

根據上述的邏輯,`matrix(1:18, 6, 3)`會產生一個6 列3 行(簡稱6 乘3 )的矩陣。

重要的屬性,R 都會提供內建函數來方便存取。`dim`就是可以存取矩陣維度的函數,也可以利用`dim(x) <- c(3, 6)`來更改x 的維度。


R 的除了矩陣(matrix)之外,還有高維度的陣列。 我們可以直接更改x的維度到更高維。

`dim(x) <- c(3, 3, 2)`

, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 10 13 16
[2,] 11 14 17
[3,] 12 15 18

也可以利用`array(1:18, c(3, 3,2))`來建立一個高維矩陣。

我們可以利用中括號`[`來取出矩陣或陣列中部分的值。舉例來說,如果x是矩陣,`x[2,1]`會取出x 第二列第一行的值。 陣列的狀況也是類似的。

`x[1,2,3]`則會拿出第一個維度的第1 個方向,第二個維度的第2 個方向,第三個維度的第3個方向。 這就是以座標的方式做挑選。


在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[1,1,1]`的值更改為2, 我們可以使用`x[1,1,1] <- 2`

要更改一整排的資料也是類似的方法。 舉例來說,`x[,1,1] <- 3`可以把`, , 1`底下矩陣的`[,1]`該行改成`c(3,3,3)`向量。 這樣的運算也是向量式,R 會自動重複3直到把x[,1,1]填滿。


而當維度不相同的時候,R 會自動重複維度較低的那方。

舉例來說,當一邊是矩陣,一邊是單值的時候,運算相對簡單。

當陣列和向量相加的時候,R會一直重複向量,直到向量的長度和陣列需要的長度相符合。

舉例來說,一個3 乘2 乘2的陣列需要12個值。

接著,R會把這個向量轉換成和陣列一樣的維度,然後在對應的位置做相加。

> matrix(1:4,2,2) + 1:2
 [,1] [,2]
[1,] 2 4
[2,] 4 6

dim 屬性非常重要,所有的矩陣和陣列,都是一般的向量加上dim 這個屬性。 R 也提供了`dim`這個函數讓使用者可以存取dim 屬性。

舉例來說,`dim(x)`會印出x的維度。而我們可以透過`dim(x) <- NULL`來移除x 的dim 屬性。

dim(x) <- NULL

> x
 [1] 3 3 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18


R 中的陣列和向量的向量式運算,也可以回到兩個向量的運算。

差別在於它們多了維度的屬性,所以當維度差異太大的時候,R 會認為向量式運算無效。所以一般來說只會拿單值或向量去和陣列做運算,或是維度相同的矩陣或陣列進行運算。

基本上,`+`、`-`、`*`和`/`都會使用向量式運算。


在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))
 [,1] [,2] [,3] [,4]
[1,] 1 3 1 3
[2,] 2 4 2 4
> rbind(matrix(1:4,2,2),matrix(1:4,2,2))
 [,1] [,2]
[1,] 1 3
[2,] 2 4
[3,] 1 3
[4,] 2 4

最後,我們介紹一些和線性代數相關的運算子和函數。

在R 中兩個矩陣要作矩陣乘法,就是使用`%*%`這個運算符號。

> matrix(1:6,2,3) %*% matrix(3:8,3,2)
 [,1] [,2]
[1,] 40 67
[2,] 52 88


當矩陣乘向量的時候,單一向量會被視為行向量,最後會得到矩陣每個列和單一向量的內積,形成一個新的行向量。

在R 中,線性代數運算的底層是透過BLAS等函式庫做運算的,所以效能遠勝過自己用C寫的線性代數運算。

另外,R預設的BLAS庫為比較被廣泛驗證過正確性的版本,而非效能比較快版本。 這是因為,R core Team認為正確性比較重要,所以目前是採用比較舊,但是也比較可靠的BLAS庫。


如果已知` A %*% x = b `,給定`A` 和`b` ,我們就可以用`solve` 解出 x 。

舉例來說,若`A`是`matrix(1:4, 2, 2)`、b 是`c(3, 8)`,`solve(A, b)`即可以給出`x`。

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.