R語言初級(jí)教程(15): 矩陣(下篇)

R中的數(shù)據(jù)結(jié)構(gòu)

這是最后一篇講解有關(guān)矩陣操作的博客,介紹有關(guān)矩陣的函數(shù),主要有rowSums(), colSums(), rowMeans(), colMeans(), apply(), rbind(), cbind(), row(), col(), rowsum(), aggregate(), sweep(), max.col()

下面通過例子來了解這些函數(shù)的用法:

1. 矩陣的行、列計(jì)算

我們知道,通過下標(biāo)索引[i, j]可以訪問矩陣的某一部分,索引如果沒有提供意味著“所有行”或“所有列”。來看個(gè)例子,比如:

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

> mean(x[,3])    ##求第三列的平均值,行索引i沒提供,意味著“所有行”
[1] 10.5
> var(x[2,])   ##求第二行的方差,列索引j沒提供,意味著“所有列”
[1] 16

在R中,可以用一些特殊的函數(shù)來進(jìn)行矩陣的行、列計(jì)算。來看些例子:

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

> rowSums(x)    ## 行和
[1] 15 18 21 24
> colSums(x)    ## 列和
[1] 10 26 42
> rowMeans(x)    ## 行平均
[1] 5 6 7 8
> colMeans(x)    ## 列平均
[1]  2.5  6.5 10.5

上面四個(gè)函數(shù)都是R內(nèi)建函數(shù),當(dāng)矩陣中沒有NANaN時(shí),計(jì)算效率非常高。

上述矩陣的行、列計(jì)算,還可以使用apply()函數(shù)來實(shí)現(xiàn)。apply()函數(shù)的原型為apply(X, MARGIN, FUN, ...),其中:X為矩陣或數(shù)組;MARGIN用來指定是對(duì)行運(yùn)算還是對(duì)列運(yùn)算,MARGIN=1表示對(duì)行運(yùn)算,MARGIN=2表示對(duì)列運(yùn)算;FUN用來指定運(yùn)算函數(shù);...用來指定FUN中需要的其它參數(shù)。來看些例子:

apply()函數(shù)來實(shí)現(xiàn)上面的例子

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

> apply(x, 1, sum)    ## 行和
[1] 15 18 21 24
> apply(x, 2, sum)    ## 列和
[1] 10 26 42
> apply(x, 1, mean)    ## 行平均
[1] 5 6 7 8
> apply(x, 2, mean)    ## 列平均
[1]  2.5  6.5 10.5

apply()函數(shù)功能很強(qiáng)大,我們可以對(duì)矩陣的行或列進(jìn)行其它運(yùn)算,例如:

> apply(x, 2, var)   ##每列方差
[1] 1.666667 1.666667 1.666667
> apply(x, 1, max)  ##每行最大值
[1]  9 10 11 12

如果矩陣存在NA值,可通過設(shè)置na.rm=TRUE來忽略NA值,然后再計(jì)算。比如:

> x <- matrix(c(1:5,NA, 7:12), ncol=3)
> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2   NA   10
[3,]    3    7   11
[4,]    4    8   12
> apply(x, 1, mean)
[1]  5 NA  7  8
> apply(x, 1, mean, na.rm=TRUE)
[1] 5 6 7 8

其中上面的na.rm參數(shù)來自mean()函數(shù)

甚至我們還可以自定義運(yùn)算函數(shù),來看個(gè)例子:

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

> apply(x, 2, function(x, a, b) x*a+b, a=2, b=1)   ##自定義函數(shù)
     [,1] [,2] [,3]
[1,]    3   11   19
[2,]    5   NA   21
[3,]    7   15   23
[4,]    9   17   25
> x*2+1
     [,1] [,2] [,3]
[1,]    3   11   19
[2,]    5   NA   21
[3,]    7   15   23
[4,]    9   17   25

注意:apply(x, 2, function(x, a, b) x*a+b, a=2, b=1)x*2+1效果相同,此處旨在說明如何應(yīng)用apply()函數(shù)

2. rbind()cbind()函數(shù)

在R中,rbind()cbind()函數(shù)可分別為矩陣添加行和列,來看一個(gè)例子:

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

> x <- rbind(x, apply(x, 2, mean))     ##添加一行,元素分別為每列平均值
> x
     [,1] [,2] [,3]
[1,]  1.0  5.0  9.0
[2,]  2.0  6.0 10.0
[3,]  3.0  7.0 11.0
[4,]  4.0  8.0 12.0
[5,]  2.5  6.5 10.5

> x <- cbind(x, apply(x, 1, sum))     ##添加一列,元素分別為每行求和值
> x
     [,1] [,2] [,3] [,4]
[1,]  1.0  5.0  9.0 15.0
[2,]  2.0  6.0 10.0 18.0
[3,]  3.0  7.0 11.0 21.0
[4,]  4.0  8.0 12.0 24.0
[5,]  2.5  6.5 10.5 19.5

> rownames(x) <- c(1:4, 'mean')   ## 添加行名
> colnames(x) <- c(1:3, 'sum')   ## 添加列名
> x
       1   2    3  sum
1    1.0 5.0  9.0 15.0
2    2.0 6.0 10.0 18.0
3    3.0 7.0 11.0 21.0
4    4.0 8.0 12.0 24.0
mean 2.5 6.5 10.5 19.5

3. row()col()函數(shù)

在R中,row()col()函數(shù)將分別返回元素的行和列下標(biāo)矩陣,來看個(gè)例子:

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

> row(x)     ##返回元素的行下標(biāo)矩陣
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    2    2
[3,]    3    3    3
[4,]    4    4    4
> col(x)     ##返回元素的列下標(biāo)矩陣
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    1    2    3
[3,]    1    2    3
[4,]    1    2    3

通過這兩個(gè)函數(shù),可以獲取矩陣的對(duì)角元素以及上下三角矩陣,例如:

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

> dx <- x[row(x)==col(x)]    ## 獲取對(duì)角元素
> dx
[1]  1  6 11
> diag(x)    ##也可通過diag()函數(shù)獲取對(duì)角元素,速度將更快、更簡(jiǎn)單
[1]  1  6 11

> x[row(x)>col(x)] <- 0   ##結(jié)果為上三角矩陣,通過賦值運(yùn)算將所有下三角元素變?yōu)?
> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    0    6   10
[3,]    0    0   11
[4,]    0    0    0

4. rowsum()aggregate()函數(shù)

有時(shí),你可能需要對(duì)每行進(jìn)行分組,然后組內(nèi)每列求和。在R中可以用rowsum()函數(shù)來解決,而且效率也非常高。先看個(gè)例子:

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

> group <- c('A', 'B', 'A', 'B')   ##分組向量
> rowsum(x, group)   ##組內(nèi)每列求和
  [,1] [,2] [,3]
A    4   12   20
B    6   14   22

上述代碼將第一行和第三行作為A組,把第二行和第四行作為B組,然后組內(nèi)每列求和。注意分組向量的長(zhǎng)度必須與矩陣行數(shù)相同

你也可以用aggregate()函數(shù)獲得類似結(jié)果:

> aggregate(x, list(group), sum)
  Group.1 V1 V2 V3
1       A  4 12 20
2       B  6 14 22

aggregate()函數(shù)的功能很強(qiáng)大,后面講“數(shù)據(jù)框”時(shí)再詳細(xì)講解。

有人就會(huì)問“為啥沒有列分組求和的操作?”,其實(shí)你可以先將矩陣轉(zhuǎn)置,然后行分組求和;這兩步就等同于列分組求和。

5. sweep()函數(shù)

sweep()函數(shù)的原型為sweep(x, MARGIN, STATS, FUN = "-", check.margin = TRUE, ...),其中:x為矩陣或數(shù)組;MARGIN用來指定是對(duì)行運(yùn)算還是對(duì)列運(yùn)算,MARGIN=1表示對(duì)行運(yùn)算,MARGIN=2表示對(duì)列運(yùn)算;STATS表示想要清除的統(tǒng)計(jì)量;FUN用來指定運(yùn)算函數(shù),默認(rèn)為減法-;check.margin用來核實(shí)x的維度是否與STATS的匹配,如果事先知道它們匹配的話,將其設(shè)為FALSE將提高運(yùn)算速度; ...用來指定FUN中需要的其它參數(shù)。來看些例子:

> x <- matrix(1:12, ncol=3)
> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> cols <- apply(x, 2, mean)   ##列平均
> cols
[1]  2.5  6.5 10.5

> sweep(x, 2, cols)  ##每列減去其平均值
     [,1] [,2] [,3]
[1,] -1.5 -1.5 -1.5
[2,] -0.5 -0.5 -0.5
[3,]  0.5  0.5  0.5
[4,]  1.5  1.5  1.5

> sweep(x, 2, cols, '+')  ##每列加上其平均值
     [,1] [,2] [,3]
[1,]  3.5 11.5 19.5
[2,]  4.5 12.5 20.5
[3,]  5.5 13.5 21.5
[4,]  6.5 14.5 22.5

> sweep(x, 1, 1:4)  ##每行減去對(duì)應(yīng)值,比如第一行元素都減1,第二行減2,第三行減3,第四行減4
     [,1] [,2] [,3]
[1,]    0    4    8
[2,]    0    4    8
[3,]    0    4    8
[4,]    0    4    8

從上面的例子可以看出,sweep()函數(shù)的功能非常強(qiáng),它可以對(duì)矩陣的行或列減去(默認(rèn)情況)或加上不同的值

事實(shí)上,通過改變FUN參數(shù)的具體形式或自定義函數(shù),sweep()函數(shù)可以實(shí)現(xiàn)很多不同操作,這里就不細(xì)講了。

6. max.col()函數(shù)

max.col()函數(shù)返回矩陣每行最大值所在的列位置(即列下標(biāo)),其原型為max.col(m, ties.method = c("random", "first", "last")),其中:m為矩陣;當(dāng)存在多個(gè)最大值時(shí),ties.method指定用哪種方式來處理這種情況,默認(rèn)為"random"(隨機(jī)),"first"指使用第一個(gè)最大值,"last"指使用最后一個(gè)最大值。來看個(gè)官網(wǎng)例子:

> set.seed(1)   ##通過設(shè)定隨機(jī)數(shù)種子,使下面的結(jié)果可重復(fù)
> mm <- rbind(x = round(2*stats::runif(12)),
              y = round(5*stats::runif(12)),
              z = round(8*stats::runif(12)))
> mm
  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
x    1    1    1    2    0    2    2    1    1     0     0     0
y    3    2    4    2    4    5    2    4    5     1     3     1
z    2    3    0    3    7    3    4    5    4     1     7     5

> max.col(mm)   ##random
[1] 4 6 5
> max.col(mm)   ##random,跟上面的結(jié)果不一樣
[1] 6 6 5
> max.col(mm, 'first')
[1] 4 6 5
> max.col(mm, 'last')
[1]  7  9 11

我們也可以結(jié)合apply()which.max()函數(shù)來實(shí)現(xiàn)max.col(mm, 'first')。看個(gè)例子,

> apply(mm, 1, which.max)
x y z 
4 6 5 
> unname(apply(mm, 1, which.max))   ##通過unname函數(shù)去掉向量的名稱
[1] 4 6 5

R矩陣的最后一部分內(nèi)容就講到這。

如若有遺漏,后期將會(huì)添加至本博客。


感謝您的閱讀!想了解更多有關(guān)R語言技巧,請(qǐng)關(guān)注我的微信公眾號(hào)“R語言和Python學(xué)堂”,我將定期更新相關(guān)文章。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容