重複向量

在處理向量的運算時,如果遇到長度不同的向量,R 就會將長度較短的向量自動重複,直到其長度跟最長的向量相同為止,例如:

1:3 + 1:9
[1]  2  4  6  5  7  9  8 10 12

這裡的 1:3 向量長度為 3,而 1:9 向量長度為 9,所以 R 會將 1:3 重複 3 次,變成 c(1, 2, 3, 1, 2, 3, 1, 2, 3) 之後,再跟 1:9 進行運算。

當遇到向量與常數相加時,也是依據同樣的規則處理:

1:5 + 1
[1] 2 3 4 5 6

這裡的 1 在 R 中其實是一個長度為 1 的向量,而為了要跟 1:5 這個長度為 5 的向量進行運算,R 會將 1 自動重複 5 次,變成 c(1, 1, 1, 1, 1) 之後再進行運算。

如果遇到最長向量長度不是較短向量長度的整數倍時,最後一次的向量重複內容就會不完整(超過的部分會捨去),並且也會產生警告訊息:

1:2 + 1:5
[1] 2 4 4 6 6
Warning message:
In 1:2 + 1:5 : 較長的物件長度並非較短物件長度的倍數

以這個例子來說,1:2 會重複 2.5 次,變成 c(1, 2, 1, 2, 1) 之外再進行運算。

雖然 R 可以自動處理向量長度不同的問題,但是除了將向量加上一個常數之外,通常不建議過度運用這樣的特性,因為這會造成程式碼在閱讀上的混淆,也容易產生 bugs,最好的方式還是建立相同長度的向量後再進行運算。

如果要產生重複性的向量,可以使用 rep 這個函數,其第一個參數是要重複的向量,而第二個參數則是重複次數:

rep(1:4, 3)
[1] 1 2 3 4 1 2 3 4 1 2 3 4

如果要讓每一個元素個別重複之後再串接起來,可以使用 each 參數:

rep(1:4, each = 3)
[1] 1 1 1 2 2 2 3 3 3 4 4 4

也可以透過向量的方式指定重複次數,讓每一個元素重複不同的次數:

rep(1:4, 4:1)
[1] 1 1 1 1 2 2 2 3 3 4

另外也可以直接指定輸出的向量長度,讓 rep 自動計算重複的次數:

rep(1:4, length.out = 7)
[1] 1 2 3 4 1 2 3

rep.int 是一個執行效率較高的版本,大部分的狀況下可以代替 rep

rep.int(1:4, 3)
[1] 1 2 3 4 1 2 3 4 1 2 3 4

rep_len 是另一個高執行效率的版本:

rep_len(1:4, 7)
[1] 1 2 3 4 1 2 3

矩陣與陣列

R 中的向量(vectors)是用來儲存一維資料的變數類型,而如果需要儲存二維以上的資料,就要使用陣列(arrays)來處理,而二維的陣列就是我們所熟知的矩陣(matrices)。

建立矩陣與陣列

R 的矩陣可以使用 matrix 函數建立,例如:

matrix(1:6, nrow = 2, ncol = 3)

這樣就會建立一個 2 x 3 的矩陣:

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

byrow 參數可以調整資料排列的方向:

matrix(1:6, nrow = 2, ncol = 3, byrow = TRUE)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6

矩陣的行與列可以使用 dimnames 參數指定名稱:

matrix(1:6, nrow = 2, ncol = 3,
  dimnames = list(c("row1", "row2"),
  c("C.1", "C.2", "C.3")))
     C.1 C.2 C.3
row1   1   3   5
row2   2   4   6

多維度的陣列則是使用 array 函數來建立:

array(1:24, dim = c(4, 3, 2))
, , 1

     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

, , 2

     [,1] [,2] [,3]
[1,]   13   17   21
[2,]   14   18   22
[3,]   15   19   23
[4,]   16   20   24

多維度的陣列也可以使用 dimnames 參數指定每個維度的資料名稱:

array(1:24, dim = c(4, 3, 2), dimnames = list(
  X = c("A1","A2","A3","A4"),
  Y = c("B1", "B2", "B3"), Z = c("C1", "C2")))
, , Z = C1

    Y
X    B1 B2 B3
  A1  1  5  9
  A2  2  6 10
  A3  3  7 11
  A4  4  8 12

, , Z = C2

    Y
X    B1 B2 B3
  A1 13 17 21
  A2 14 18 22
  A3 15 19 23
  A4 16 20 24

事實上二維的陣列就是矩陣,不管使用 matrix 或是 array 來產生,結果都是一樣的:

x.matrix <- matrix(1:6, nrow = 2, ncol = 3)
x.array <- array(1:6, dim = c(2, 3))
identical(x.matrix, x.array)
[1] TRUE

如果我們檢查 x.array 的類型,會發現它實際上就是一個矩陣變數:

class(x.array)
[1] "matrix"

nrowncol 函數可以檢查矩陣的列數與行數:

nrow(x.matrix)
[1] 2
ncol(x.matrix)
[1] 3

nrowncol 函數若用於多維度的陣列,會傳回前兩個維度的長度。

x.array <- array(1:60, dim = c(3, 4, 5))
nrow(x.array)
[1] 3
ncol(x.array)
[1] 4

length 函數也可以用於矩陣或是陣列,他會計算矩陣或陣列中所有元素的個數(也就是所有維度長度的乘積):

length(x.matrix)
[1] 6
length(x.array)
[1] 60

若要改變矩陣或陣列的維度,可以使用 dim 指定新的維度:

x.matrix <- matrix(1:12, nrow = 4, ncol = 3)
dim(x.matrix) <- c(2, 6)
x.matrix
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    3    5    7    9   11
[2,]    2    4    6    8   10   12

甚至可以透過改變維度,將二維矩陣轉換為高維度的陣列:

dim(x.matrix) <- c(2, 3, 2)
x.matrix
, , 1

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

, , 2

     [,1] [,2] [,3]
[1,]    7    9   11
[2,]    8   10   12

nrowncoldim 這幾個函數如果用在一維的向量時,會傳回 NULL,如果想要避免這個問題,可以改用 NROWNCOL 函數,這兩個函數的作用跟 nrowncol 相同,但是當遇到一維的向量時也可以傳回有意義的值:

x.vector <- 1:5
nrow(x.vector)
NULL
NROW(x.vector)
[1] 5
ncol(x.vector)
NULL
NCOL(x.vector)
[1] 1