2017年12月28日 星期四

R 語言學習筆記 (三) : 陣列

測完矩陣接著測試陣列, 此前的測試紀錄如下 :

R 語言安裝
在樹莓派上安裝 R 語言
R 語言學習筆記 (一) : 基本語法與向量
R 語言學習筆記 (二) : 矩陣

R 語言的陣列是矩陣的維度擴展 (矩陣是陣列的一個特例, 它是二維的陣列), 因此其元素一樣也都是同質的 (即資料類型必須相同). 陣列也可視為多維度的向量 (注意, R 語言中向量並無維度), 使用多個索引如 A[i, j, k, ...] 來存取元素, 其中索引 i, j, k, ... 代表各維之位置. 最常用的是三維陣列, 在一些時間序列的應用中甚至會用到高維陣列.

與幾何類比, 向量相當於線; 矩陣相當於面; 而陣列則相當於多維空間. 不管是向量, 矩陣或陣列, 它們的元素都必須同質, 即由相同類型的資料組成.


一. 建立陣列的方法 :

1. 呼叫 array() 函數 : 

函數 array() API 如下 :

array(data=NA, dim=length(data), dimnames=NULL)

data : 向量或串列 (用來填滿陣列), 向量以外的資料會自動被 as.vector() 強制轉型.
dim : 整數向量, 用來依序定義各維度之長度.
dimnames : 字串列表 (list) 用來賦予各維度因次名稱 (例如列名, 行名, 表名)

三維陣列的第一列相當於矩陣之列, 第二維相當於行, 第三維通常稱為表 (table).  例如以下的三維陣列用 1:24 的向量來填滿 3*4*2 個元素位置, 會逐行 (by column) 填入元素, 即先填滿第一行, 再填第二行 :

> A <- array(1:24, c(3,4,2))    #建立一,二,三維長度各為 3,4,2 之陣列
> A
, , 1                          #顯示第三維第一個資料結構 (相當於 table 1)

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

, , 2                          #顯示第三維第二個資料結構 (相當於 table 2)

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

接著來看看陣列的資料結構是用甚麼組成的 :

> class(A)          #檢查資料結構是 array
[1] "array"
> is.array(A)
[1] TRUE
> is.vector(A)    #不是向量結構
[1] FALSE
> is.matrix(A)    #不是矩陣結構
[1] FALSE
> is.array(A[, 1 ,])   # A[ , 1, ] 是二維陣列  (降維)
[1] TRUE
> is.matrix(A[, 1, ])     # A[, 1, ] 也是矩陣 (降維)
[1] TRUE
> class(A[,1,])    # A[, 1, ] 的真實結構是矩陣
[1] "matrix"
> A[,1,]             
     [,1] [,2]
[1,]    1   13
[2,]    2   14
[3,]    3   15
> A[1,1,]     
[1]  1 13
> is.matrix(A[1,1,])      #A[1, 1, ] 則降維成向量
[1] FALSE
> is.vector(A[1,1,])
[1] TRUE

上面降維後的 A[ , 1, ] 用 is.array() 與 is.matrix() 檢查, 結果它似乎既是陣列 (二維) 也是矩陣, 用 class() 去檢驗即知事實上 A[ , 1, ] 結構是矩陣而非陣列, 可見陣列確實是用矩陣堆起來的, 而矩陣又是用向量堆起來的.

其實 R 語言中的二維陣列就是矩陣, 例如用 array() 建立一個二維陣列, 用 is.array() 與 is.matrix() 都回應 TRUE, 表示它既是陣列也是矩陣, 但用 class() 去檢查其結構類型卻歸類為是矩陣 :

> A <- array(1:12, c(4,3))     #建立一個二維陣列
> A
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> is.array(A)       #用 array() 建立當然是陣列
[1] TRUE
> is.matrix(A)     #也是矩陣
[1] TRUE
> class(A)           #結構上歸類為矩陣
[1] "matrix"

如果建立一個矩陣之後用 as.array() 強制轉成陣列會怎樣呢?

> A <- matrix(1:12, nrow=4)    #建立一個矩陣
> A
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> is.matrix(A)     #用 matrix() 建立當然是矩陣
[1] TRUE
> is.array(A)       #嘿! A 竟然也是陣列
[1] TRUE
> class(A)           #結構是矩陣
[1] "matrix"
> B <- as.array(A)      #用 as.array() 將 A 強制轉型為陣列 B
> B
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> is.matrix(B)     #還是矩陣
[1] TRUE
> is.array(B)       #當然是陣列
[1] TRUE
> class(B)           #結構仍歸類為矩陣
[1] "matrix"

我們可以用 identical() 函數來檢驗用 matrix() 與 array() 建立的二維物件是否雷同 :

> A <- matrix(1:12, nrow=4)    #建立一個矩陣 A
> A
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> B <- array(1:12, c(4,3))         #建立一個二維陣列 B, 內容與 A 矩陣相同
> B
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> class(A)         #矩陣 A 結構為 matrix
[1] "matrix"
> class(B)         #陣列 B 結構亦為 matrix
[1] "matrix"
> identical(A, B)    #呼叫 identical() 顯示兩者是同樣物件
[1] TRUE

總之, 在 R 語言中, 大於二維的資料結構是陣列, 二維陣列就被歸類為矩陣.

如果傳入的向量不夠填滿陣列, 則會套用循環規則從頭抓資料, 例如 :

> array(1:17, c(3,4,2))
, , 1

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

, , 2

     [,1] [,2] [,3] [,4]
[1,]   13   16    2    5
[2,]   14   17    3    6
[3,]   15    1    4    7

下面是用這 24 個元素來建立一個四維陣列 :

> A <- array(1:24, c(3,2,2,2))
> A
, , 1, 1

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

, , 2, 1

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

, , 1, 2

     [,1] [,2]
[1,]   13   16
[2,]   14   17
[3,]   15   18

, , 2, 2

     [,1] [,2]
[1,]   19   22
[2,]   20   23
[3,]   21   24

五維陣列範例如下 :

> A <- array(1:32, c(2,2,2,2,2))
> A
, , 1, 1, 1

     [,1] [,2]
[1,]    1    3
[2,]    2    4

, , 2, 1, 1

     [,1] [,2]
[1,]    5    7
[2,]    6    8

, , 1, 2, 1

     [,1] [,2]
[1,]    9   11
[2,]   10   12

, , 2, 2, 1

     [,1] [,2]
[1,]   13   15
[2,]   14   16

, , 1, 1, 2

     [,1] [,2]
[1,]   17   19
[2,]   18   20

, , 2, 1, 2

     [,1] [,2]
[1,]   21   23
[2,]   22   24

, , 1, 2, 2

     [,1] [,2]
[1,]   25   27
[2,]   26   28

, , 2, 2, 2

     [,1] [,2]
[1,]   29   31
[2,]   30   32

可見 R 語言在顯示高維陣列內容時, 是把它拆解到矩陣 (就是第一與第二維組成的二維陣列) 當作最小的單位, 然後從第三維起依序顯示 "每一張表".

2. 呼叫 dim() 函數設定維度將向量或列表變成陣列 :   

R 語言中向量 (vector) 是一群有序資料, 看起來像是一維, 但在 R 裡面是沒有維度的資料結構, 用 dim() 檢查會得到 NULL. 與建立矩陣一樣, 若呼叫 dim() 為向量指定大於 2 的維度, 則此無維度的向量將變成有維度的陣列結構, 例如 :

> v <- 1:24                 #建立 24 個元素的向量
> dim(v)                         #向量是無維度的資料結構 (NULL)
NULL 
> dim(v) <- c(4,3,2)   #指定維度給向量會使其變成矩陣 (2 維) 或向量 (大於 2 維)
> v
, , 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

> class(v)                       #變成陣列了
[1] "array"

> dim(v)                         #查詢陣列維度是 4*3*2
[1] 4 3 2


二. 存取陣列元素 :

存取陣列元素的方式與矩陣一樣, 也是用索引, 只是索引比較多而已.

> A <- array(1:24, c(4,3,2))
> A
, , 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

> A[1,1,1]
[1] 1
> A[1,3,1]
[1] 9
> A[1,3,2]
[1] 21
> A[1,1,]
[1]  1 13

> A[1,,]
     [,1] [,2]
[1,]    1   13
[2,]    5   17
[3,]    9   21

> A[,1,]
     [,1] [,2]
[1,]    1   13
[2,]    2   14
[3,]    3   15
[4,]    4   16

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

注意, 這些取出來的物件都降階變成了二維的矩陣了, 可用 class() 檢驗. 如果取出來的元件想保留 array 架構, 不要降階成矩陣, 可以在索引最後面加上 drop=FALSE (預設是 TRUE), 例如 :

 > A <- array(1:24, c(4,3,2))
> A[1,,]               #只取第一維
     [,1] [,2]
[1,]    1   13
[2,]    5   17
[3,]    9   21
> class(A[1,,])     #降階為 matrix
[1] "matrix
> A[1,,,drop=FALSE]    #不降階 (保留陣列結構)
, , 1

     [,1] [,2] [,3]
[1,]    1    5    9

, , 2

     [,1] [,2] [,3]
[1,]   13   17   21

> class(A[1,,,drop=FALSE])    #仍為 array 結構
[1] "array"

> identical(A[1,,], A[1,,,drop=FALSE])  #兩個是不同物件 (內容相同, 但結構不同)
[1] FALSE 

上面是存取三維陣列內容時的降維情形, 如果取得的內容是二維, 則降階為矩陣; 若小於二維則為向量. 從多維陣列取得的內容如果大於二維, 則仍然是陣列結構, 例如 :

> A <- array(1:32, c(2,2,2,2,2))
> A
, , 1, 1, 1

     [,1] [,2]
[1,]    1    3
[2,]    2    4

, , 2, 1, 1

     [,1] [,2]
[1,]    5    7
[2,]    6    8

, , 1, 2, 1

     [,1] [,2]
[1,]    9   11
[2,]   10   12

, , 2, 2, 1

     [,1] [,2]
[1,]   13   15
[2,]   14   16

, , 1, 1, 2

     [,1] [,2]
[1,]   17   19
[2,]   18   20

, , 2, 1, 2

     [,1] [,2]
[1,]   21   23
[2,]   22   24

, , 1, 2, 2

     [,1] [,2]
[1,]   25   27
[2,]   26   28

, , 2, 2, 2

     [,1] [,2]
[1,]   29   31
[2,]   30   32

> A[,,,1,1]     #取得子陣列
, , 1

     [,1] [,2]
[1,]    1    3
[2,]    2    4

, , 2

     [,1] [,2]
[1,]    5    7
[2,]    6    8

> class(A[,,,1,1])   #結構是陣列 (因為是三維)
[1] "array"

取得陣列內容時也可以使用負索引來排除不要的部分, 例如 :

> A <- array(1:24, c(4,3,2))
> A
, , 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

> A[-3, c(1,3), 2]     #第一維不要第三列, 第二維取第一與第三行, 第三維取第二張
     [,1] [,2]
[1,]   13   21
[2,]   14   22
[3,]   16   24

修改陣列的內容只要直接將向量或矩陣指派給陣列的指定部分即可, 例如 :

> A <- array(1:24, c(4,3,2))   #建立陣列
> A
, , 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

> A[3:4,c(1,3),1]    #第一維之 3~4 列, 第二維的 1 與 3 行, 第三維的第一張表
     [,1] [,2]
[1,]    3   11
[2,]    4   12
> A[3:4,c(1,3),1] <- matrix(NA, nrow=2, ncol=2)   #將矩陣指派給陣列局部
> A
, , 1

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

, , 2

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


 三. 陣列常用函數 : 


 函數 說明
 array(data, dim, dimnames) 建立維度為 dim 向量之陣列
 str(x) 顯示物件結構與內容
 length(x) 顯示陣列元素個數
 dim(x) 顯示物件 (矩陣, 陣列, 資料框) 維度
 is.array(x) 檢查是否為鎮ㄌㄧ類型
 as.array(x) 將物件強制轉型為陣列陣類型
 identical(x, y) 檢查兩個物件 x, y 是否為相同物件


沒有留言 :