
這是最后一篇講解有關(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)矩陣中沒有
NA和NaN時(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)文章。
