您現在的位置是:首頁 > 武術

3.多維陣列和矩陣

  • 由 遊戲樂淘淘 發表于 武術
  • 2021-12-27
簡介比如,設x是一個維數向量為c(2,3,4,5)的陣列,則apply(x, c(1,3), sum)可以產生一個2行4 列的矩陣,其每一元素是x中固定第1維和第3維下標取出子陣列求和的結果

互逆矩陣相乘等於多少

多維陣列和矩陣 陣列(array)和矩陣(matrix)

陣列(array)可以看成是帶多個下標的型別相同的元素的集合,常用的是數值型的陣列如矩陣,也可以有其它型別(如字元型、邏輯型、復型陣列)。S可以很容易地生成和處理陣列,特別是矩陣(二維陣列)。

陣列有一個特徵屬性叫做維數向量(dim屬性),維數向量是一個元素取正整數值的向量,其長度是陣列的維數,比如維數向量有兩個元素時陣列為二維陣列(矩陣)。維數向量的每一個元素指定了該下標的上界,下標的下界總為1。

一組值只有定義了維數向量(dim屬性)後才能被看作是陣列。比如: > z dim(z) 這時z已經成為了一個維數向量為c(3,5,100)的三維陣列。也可以把向量定義為一維陣列,例如:

> dim(z)

陣列元素的排列次序預設情況下是採用FORTRAN的陣列元素次序(按列次序),即第一下標變化最快,最後下標變化最慢,對於矩陣(二維陣列)則是按列存放。例如,假設陣列a的元素為1:24,維數向量為c(2,3,4),則各元素次序為a[1,1,1], a[2,1,1], a[1,2,1], a[2,2,1], a[1,3,1], 。。。, a[2,3,4]。

用函式array()或matrix()可以更直觀地定義陣列。array()函式的完全使用為array(x, dim=length(x), dimnames=NULL),其中x是第一自變數,應該是一個向量,表示陣列的元素值組成的向量。dim引數可省,省略時作為一維陣列(但不同於向量)。dimnames屬性可以省略,不省略時是一個長度與維數相同的列表(list,見後面),列表的每個成員為一維的名字。例如上面的z可以這樣定義:

> z 其中第一自變數data為陣列的資料向量(預設值為缺失值NA),nrow為行數,ncol為列數,byrow表示資料填入矩陣時按行次序還是列次序,一定注意預設情況下按列次序,這與我們寫矩陣的習慣是不同的。dimnames預設是空值,否則是一個長度為2的列表,列表第一個成員是長度與行數相等的字元型向量,表示每行的標籤,列表第二個成員是長度與列數相同的字元型向量,表示每列的標籤。例如,定義一個3行4列,由1:12按行次序排列的矩陣,可以用:> b b [,1] [,2] [,3] [,4] [1,] 1 2 3 4 [2,] 5 6 7 8 [3,] 9 10 11 12

注意在有資料的情況下只需指定行數或列數之一。指定的資料個數允許少於所需的資料個數,這時迴圈使用提供的資料。例如:

> b 要訪問陣列的某個元素,只要象上面那樣寫出陣列名和方括號內用逗號分開的下標即可,如a[2,1,2]。

更進一步我們還可以在每一個下標位置寫一個下標向量,表示對這一維取出所有指定下標的元素,如a[1, 2:3, 2:3]取出所有第一下標為1,第二下標為2或3,第三下標為2或3的元素。注意因為第一維只有一個下標所以退化了,得到的是一個維數向量為c(2,2)的陣列。

另外,如果略寫某一維的下標,則表示該維全選。例如,a[1, , ]取出所有第一下標為1 的元素,得到一個形狀為c(3,4)的陣列。a[ , 2, ]取出所有第二下標為2的元素得到一個形狀為c(2,4)的陣列。a[1,1, ]則只能得到一個長度為4的向量,不再是陣列(dim(a[1,1, ]) 值為NULL)。a[ , , ]或a[]都表示整個陣列。比如

a[] 還有一種特殊下標是對於陣列只用一個下標向量(是向量,不是陣列),比如a[3:4] ,這時忽略陣列的維數資訊,把下標表達式看作是對陣列的資料向量取子集。不規則陣列下標

在S中甚至可以把陣列中的任意位置的元素作為一組訪問,其方法是用一個矩陣作為陣列的下標,矩陣的每一行是一個元素的下標,陣列有幾維下標矩陣的每一行就有幾列。例如,我們要把上面的形狀為c(2,3,4)的陣列a的第[1,1,1], [2,2,3], [1,3,4], [2,1,4]號共四個元素作為一個整體訪問,先定義一個包含這些下標作為行的二維陣列:

> b b [,1] [,2] [,3] [1,] 1 1 1 [2,] 2 2 3 [3,] 1 3 4 [4,] 2 1 4 > a[b] [1] 1 16 23 20注意取出的是一個向量。我們還可以對這幾個元素賦值,如:> a[b] a 或 > a[b] a 陣列四則運算

陣列可以進行四則運算(+,-, *, /,^),解釋為陣列對應元素的四則運算,參加運算的陣列一般應該是相同形狀的(dim屬性完全相同)。例如,假設A, B, C是三個形狀相同的陣列,則

> D

計算得到的結果是A的每一個元素除以B的對應元素加上C的對應元素乘以2得到相同形狀的陣列。四則運算遵循通常的優先順序規則。

形狀不一致的向量和陣列也可以進行四則運算,一般的規則是陣列的資料向量對應元素進行運算,把短的迴圈使用來與長的匹配,並儘可能保留共同的陣列屬性。例如:

> x1 x2 x1+x2 [1] 101 202 103 204 105 206 > x3 x3 [,1] [,2] [1,] 1 4 [2,] 2 5 [3,] 3 6 > x1+x3 [,1] [,2] [1,] 101 204 [2,] 202 105 [3,] 103 206除非你清楚地知道規則應避免使用這樣的辦法(標量與陣列或向量的四則運算除外)。矩陣運算

矩陣是二維陣列,但因為其應用廣泛所以對它定義了一些特殊的運算和操作。

函式t(A)返回矩陣A的轉置。nrow(A)為矩陣A的行數,ncol(A)為矩陣A的列數。

矩陣之間進行普通的加減乘除四則運算仍遵從一般的陣列四則運算規則,即陣列的對應元素之間進行運算,所以注意A*B不是矩陣乘法而是矩陣對應元素相乘。

要進行矩陣乘法,使用運算子%*%,A%*%B表示矩陣A乘以矩陣B(當然要求A的列數等於B的行數)。例如:

> A B A [,1] [,2] [,3] [1,] 1 2 3 [2,] 4 5 6 [3,] 7 8 9 [4,] 10 11 12 > B [,1] [,2] [1,] 1 0 [2,] 1 0 [3,] 1 0 > A %*% B [,1] [,2] [1,] 6 0 [2,] 15 0 [3,] 24 0 [4,] 33 0 >

另外,向量用在矩陣乘法中可以作為行向量看待也可以作為列向量看待,這要看哪一種觀點能夠進行矩陣乘法運算。例如,設x是一個長度為n的向量,A是一個

矩陣,則“x %*% A %*% x”表示二次型

。但是,有時向量在矩陣乘法中的地位並不清楚,比如“x %*% x”就既可能表示內積

也可能表示

。因為前者較常用,所以S選擇表示前者,但內積最好還是用crossprod(x)來計算。要表示

,可以用“cbind(x) %*% x”或“x %*% rbind(x) ”。

函式crossprod(X, Y)表示一般的交叉乘積(內積)

,即X的每一列與Y的每一列的內積組成的矩陣。如果X和Y都是向量則是一般的內積。只寫一個引數X的crossprod(X)計算X自身的內積

其它矩陣運算還有solve(A,b)解線性方程組,solve(A)求方陣A的逆矩陣,svd()計算奇異值分解,qr()計算QR分解,eigen()計算特徵向量和特徵值。詳見隨機幫助,例如:

> ?qr

函式diag()的作用依賴於其自變數。diag(vector)返回以自變數(向量)為主對角元素的對角矩陣。diag(matrix)返回由矩陣的主對角元素組成的向量。diag(k)(k為標量)返回k階單位陣。

矩陣合併與拉直

函式cbind()把其自變數橫向拼成一個大矩陣,rbind()把其自變數縱向拼成一個大矩陣。cbind()的自變數是矩陣或者看作列向量的向量,自變數的高度應該相等(對於向量,高度即長度,對於矩陣,高度即行數)。rbind的自變數是矩陣或看作行向量的向量,自變數的寬度應該相等(對於向量,寬度即長度,對於矩陣,寬度即列數)。如果參與合併的自變數比其它自變數短則迴圈補足後合併。例如:

> x1 x1 [,1] [,2] [1,] 1 2 [2,] 3 4 > x2 x3 x3 [,1] [,2] [,3] [,4] [1,] 1 2 11 12 [2,] 3 4 13 14 > x4 x4 [,1] [,2] [1,] 1 2 [2,] 3 4 [3,] 11 12 [4,] 13 14 > cbind(1, x1) [,1] [,2] [,3] [1,] 1 1 2 [2,] 1 3 4

因為cbind()和rbind()的結果總是矩陣型別(有dim屬性且為二維),所以可以用它們把向量表示為

矩陣(用cbind(x))或

矩陣(用rbind(x))。

設a是一個數組,要把它轉化為向量(去掉dim和dimnames屬性),只要用函式as。vector(a) 返回值就可以了(注意函式只能透過函式值返回結果而不允許修改它的自變數,比如t(X)返回X的轉置矩陣而X本身並未改變)。另一種由陣列得到其資料向量的簡單辦法是使用函式c() ,例如c(a)的結果是a的資料向量。這樣的另一個好處是c()允許多個自變數,它可以把多個自變數都看成資料向量連線起來。例如,設A和B是兩個矩陣,則c(A,B)表示把A按列次序拉直為向量並與把B按列次序拉直為向量的結果連線起來。一定注意拉直時是按列次序拉直的。

陣列的維名字

陣列可以有一個屬性dimnames儲存各維的各個下標的名字,預設時為NULL(即無此屬性)。我們以矩陣為例,它有兩個維:行維和列維。比如,設x為2行3列矩陣,它的行維可以定義一個長度為2的字元向量作為每行的名字,它的列維可以定義一個長度為3的向量作為每列的名字,屬性dimnames是一個列表,列表的每個成員是一個維名字的字元向量或NULL。例如:

> x x First Second one 1 2 two 3 4 three 5 6 我們也可以先定義矩陣x然後再為dimnames(x)賦值。 對於矩陣,我們還可以使用屬性rownames和colnames來訪問行名和列名。如: > x colnames(x) rownames(x) x[c(“one”,“three”),] First Second one 1 2 three 5 6 陣列的外積

兩個陣列a和b的外積是由a的每一個元素與b的每一個元素搭配在一起相乘得到一個新元素,這樣得到一個維數向量等於a的維數向量與b的維數向量連起來的陣列,即若d為a和b的外積,則dim(d)=c(dim(a), dim(b))。

a和b的外積記作 a %o% b。如> d d 注意outer(a, b, f)是一個一般性的外積函式,它可以把a的任一個元素與b的任意一個元素搭配起來作為f的自變數計算得到新的元素值,外積是兩個元素相乘的情況。函式當然也可以是加、減、除,或其它一般函式。當函式為乘積時可以省略不寫。

例如,我們希望計算函式在一個x和y的網格上的值用來繪製三維曲面圖,可以用如下方法生成網格及函式值:

> x y f z 下面考慮一個有意思的例子。我們考慮簡單的2×2矩陣,其元素均在0,1,。。。,9中取值。假設四個元素a,b,c,d都是相互獨立的服從離散均勻分佈的隨機變數,我們設法求矩陣行列式ad-bc的分佈。首先,隨機變數ad和bc同分布,它的取值由以下外積矩陣給出,每一個取值的機率均為1/100:

> d

這個語句產生一個的外積矩陣。為了計算ad的100個值(有重複)與bc的100個值相減得到的10000個結果,可以使用如下外積函式:

> d2

這樣得到一個維數向量為c(2,2,2,2)的四維陣列,每一個元素為行列式的一個可能取值,機率為萬分之一。因為這些取值中有很多重複,我們可以用一個table()函式來計算每一個值的出現次數(頻數):

> fr

得到的結果是一個帶有元素名的向量fr,fr的元素名為d2的一個取值,fr的元素值為d2該取值出現的頻數,比如fr[1]的元素名為-81,值為19,表示值-81在陣列d2中出現了19次。透過計算length(fr)可以知道共有163個不同值。還可以把這些值繪製一個頻數分佈圖(除以10000 則為實際機率):

> plot(as。numeric(names(fr)), fr, type=“h”, + xlab=“行列式”, ylab=“頻數”)

其中as。numeric()把向量fr中的元素名又轉換成了數值型,用來作為作圖的橫軸座標,fr 中的元素值即頻數作為縱軸,type=“h”表示是畫垂線型圖。

陣列的廣義轉置 可以用aperm(a, perm)函式把陣列a的各維按perm中指定的新次序重新排列。例如:> a b 結果a的第2維變成了b的第1維,a的第3維變成了b的第2維,a的第1維變成了b的第3維。這時有a[i1,i2,i3]≡b[i2,i3,i1]。注意c(i1,i2,i3)[2,3,1]=c(i2,i3,i1)。一般地,若b

對於矩陣a,aperm(a, c(2,1))恰好是矩陣轉置。對於矩陣轉置可以簡單地用t(a)表示。

apply函式

對於向量,我們有sum、mean等函式對其進行計算。對於陣列,如果我們想對其中一維(或若干維)進行某種計算,可以用apply函式。其一般形式為:

apply(X, MARGIN, FUN, 。。。)

其中X為一個數組,MARGIN是固定哪些維不變,FUN是用來計算的函式。例如,設a是矩陣,則apply(a, 1, sum)的意義是對a的各行求和(保留第一維即第一個下標不變),結果是一個長度為3的向量(與第一維長度相同),而apply(a, 2, sum)意義是對a的各列求和,結果是一個長度為4的向量(與第二維長度相同)。

如果函式FUN的結果是一個標量,MARGIN只有一個元素,則apply的結果是一個向量,其長度等於MARGIN指定維的長度,相當於固定MARGIN指定的那一維的每一個值而把其它維取出作為子陣列或向量送入FUN中進行運算。如果MARGIN指定了多個維,則結果是一個維數向量等於dim(X)[MARGIN]的陣列。如果函式FUN的結果是一個長度為N的向量,則結果是一個維數向量等於c(N, dim(X)[MARGIN])的陣列,注意這時不論是對哪一維計算,結果都放在了第一維。所以,比如我們要把4×3矩陣a的3列分別排序,只要用apply(a, 2, sort),這樣對每一列排序得到一個長度為4的向量,用第一維來引用,結果的維向量為c(N, dim(a)[2])=c(4,3) ,保留了列維,恰好得到所需結果,執行如下例:

> a a [,1] [,2] [1,] 4 3 [2,] 9 7 [3,] 1 2 > apply(a, 2, sort) [,1] [,2] [1,] 1 2 [2,] 4 3 [3,] 9 7 >

但是,如果要對行排序,則apply(a, 1, sort)把a的每一行3個元素排序後的結果用第一維來引用,結果的維向量為c(N, dim(a)[1])=c(3, 4),把原來的列變成了行,所以t(apply(a,1,sort)) 才是對a的每一行排序的結果。如:

> apply(a, 1, sort) [,1] [,2] [,3] [1,] 3 7 1 [2,] 4 9 2 > t(apply(a,1,sort)) [,1] [,2] [1,] 3 4 [2,] 7 9 [3,] 1 2

上面我們只用了矩陣(二維陣列)作為例子講解apply的用法。實際上,apply可以用於任意維數的陣列,函式FUN也可以是任意可以接收一個向量或陣列作為第一自變數的函式。比如,設x是一個維數向量為c(2,3,4,5)的陣列,則apply(x, c(1,3), sum)可以產生一個2行4 列的矩陣,其每一元素是x中固定第1維和第3維下標取出子陣列求和的結果。

Top