R语言 Matrix的使用

注意:本篇文章是源自以下博客,为了方便查看特意做成一篇博客
参考博客:R语言初级教程(13): 矩阵(上篇)
R语言初级教程(15): 矩阵(下篇)
注:如有侵权,请告之,删之。

序言

R中有5种基本数据结构,分别是向量(vector)矩阵(matrix)数组(array)数据框(data frame)列表(list)。它们的结构如下图:
R语言 Matrix的使用_第1张图片

注意:其中向量、矩阵和数组中的数据类型必须是相同的;而数据框和列表中的数据类型可以是不一样的。

首先介绍矩阵,矩阵是一个二维数组。这篇博客将主要介绍矩阵的创建、元素的访问以及元素的修改…

1. 创建矩阵

在R中,使用matrix()函数来创建矩阵是最常用的方式。matrix()的原型为:matrix(data=NA, nrow=1, ncol = 1, byrow=FALSE, dimnames=NULL),其中参数的意义分别为:

data:包含了矩阵的元素,一般是个向量,默认情况下是NA
nrow和ncol:设定矩阵的行、列数目;一般这两个值只需设定一个,另外一个值可根据元素个数自动给出
byrow:设定矩阵是按行(byrow=TRUE)填充还是按 列(byrow=FALSE)填充,默认情况下按列填充
dimnames:包含了以字符型向量表示的行名和列名,是一个列表,默认情况下没有行列名

来看些例子:

c <- matrix(1:24, nrow = 3)#默认按列填充

结果:
Refused

c = matrix(1:24,byrow = TRUE, nrow = 3)#按行填充

结果:
Refused

rnames <- c('R1', 'R2')   ##行名
cnames <- c('C1', 'C2', 'C3')  ##列名
mat3 <- matrix(1:6, nrow=2, dimnames=list(rnames, cnames))   ##通过设定dimnames参数添加行列名

Refused

也可通过使用rownames()、colnames()函数来给矩阵添加行、列名

rownames(mat) <- c("R1", "R2", "R3")
colnames(mat) <- c("C1","C2")

结果:
R语言 Matrix的使用_第2张图片
此外,也可通过使用dim()函数来创建矩阵,其原理是通过改变维度使向量变为矩阵。比如:

mat4 <- 1:6   ##向量
> dim(mat4) <- c(3, 2)  ##变为3行2列的矩阵
> is.matrix(mat4)   ##判断是否为矩阵
[1] TRUE
> mat4

结果:
R语言 Matrix的使用_第3张图片

> mat4 <- 1:6
> dim(mat4) <- c(2, 3)   ##与上面不一样
> mat4 <- t(mat4)   ##矩阵转置
> mat4

结果:
R语言 Matrix的使用_第4张图片

2. 矩阵的属性

> mat <- matrix(1:6, nrow=2, dimnames=list(rnames, cnames)) 
> mat
   C1 C2 C3
R1  1  3  5
R2  2  4  6
> class(mat)  ##结构类型
[1] "matrix"
> typeof(mat)  ##元素数据类型
[1] "integer"
> dim(mat)  ##维度,2行3列
[1] 2 3
> length(mat)  ##元素个数
[1] 6
> rownames(mat)  ##获取行名
[1] "R1" "R2"
> colnames(mat)  ##获取列名
[1] "C1" "C2" "C3"

3. 访问矩阵中的元素

类似于向量元素的访问,只是增加了一个维度而已。来看一些例子:

> mat <- matrix(1:9, nrow=3, dimnames=list(c('r1', 'r2', 'r3'), c('c1', 'c2', 'c3'))) 
> mat
   c1 c2 c3
r1  1  4  7
r2  2  5  8
r3  3  6  9
> mat[2, 2]  ##访问第2行第2列元素
[1] 5
> mat[2, ]  ##访问第2行元素
c1 c2 c3 
 2  5  8 
> is.vector(mat[2, ])  ##返回为向量
[1] TRUE
> mat[, 2]  ##访问第2列元素
r1 r2 r3 
 4  5  6 
> mat[c(2, 3), c(2, 3)]  ##访问第2、3行第2、3列元素,返回为矩阵
   c2 c3
r2  5  8
r3  6  9

### 也可通过行、列名来访问元素
> mat['r2', 'c2']
[1] 5
> mat['r2', ]
c1 c2 c3 
 2  5  8 
> mat[c('r2','r3'), c('c2','c3')]
   c2 c3
r2  5  8
r3  6  9

值得注意的是,当用上面的方式获取某个或某行或某列元素时,返回的是一个向量。如何使返回值也为矩阵呢?来看个例子:

> mat[2, 2, drop=FALSE]
   c2
r2  5
> mat[2, , drop=FALSE]
   c1 c2 c3
r2  2  5  8

> is.matrix(mat[2, 2, drop=FALSE])   ##返回的是个矩阵
[1] TRUE
> is.matrix(mat[2, , drop=FALSE])   ##返回的是个矩阵
[1] TRUE

通过将参数drop设定为FALSE,返回的将会是个矩阵

4. 修改矩阵中的元素

类似于向量,我们可以通过赋值运算来改变矩阵中的内容,比如:

> mat <- matrix(1:9, nrow=3) 
> mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

> mat[2, 2] <- 20   ##将第2行第2列元素改为20
> mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2   20    8
[3,]    3    6    9

> mat[ ,3] <- 10   ##将第3列元素都改为10
> mat
     [,1] [,2] [,3]
[1,]    1    4   10
[2,]    2   20   10
[3,]    3    6   10

> mat[mat<6] <- 7   ##将小于6的元素都改为7
> mat
     [,1] [,2] [,3]
[1,]    7    7   10
[2,]    7   20   10
[3,]    7    6   10

> mat <- mat[-2, ]   ##删掉第二行
> mat
     [,1] [,2] [,3]
[1,]    7    7   10
[2,]    7    6   10

另外,通过rbind()和cbind()函数可添加行和列,来看个例子:

> mat <- matrix(1:9, nrow=3) 
> mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

> rbind(mat, c(12, 13, 14))   ##在原矩阵mat后面添加一行
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
[4,]   12   13   14

> cbind(mat, c(12, 13, 14))   ##在原矩阵mat后面添加一列
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   12
[2,]    2    5    8   13
[3,]    3    6    9   14

5、矩阵的行、列计算

我们知道,通过下标索引[i, j]可以访问矩阵的某一部分,索引如果没有提供意味着“所有行”或“所有列”。来看个例子,比如:

x <- matrix(1:12, ncol=3)
![Refused](https://img-blog.csdnimg.cn/20200324220653370.png)
> mean(x[,3])    ##求第三列的平均值,行索引i没提供,意味着“所有行”
[1] 10.5

refused

> var(x[2,])   ##求第二行的方差,列索引j没提供,意味着“所有列”

在这里插入图片描述
在R中,可以用一些特殊的函数来进行矩阵的行、列计算。来看些例子:

> x <- matrix(1:12, ncol=3)

R语言 Matrix的使用_第5张图片

rowSums(x)    ## 行和

在这里插入图片描述
colSums(x) ## 列和
在这里插入图片描述

rowMeans(x)    ## 行平均
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200324221103564.png)
colMeans(x)    ## 列平均

在这里插入图片描述

注意:上面四个函数都是R内建函数,当矩阵中没有NA和NaN时,计算效率非常高。

上述矩阵的行、列计算,还可以使用apply()函数来实现。apply()函数的原型为apply(X, MARGIN, FUN, …),其中:X为矩阵或数组;MARGIN用来指定是对行运算还是对列运算,MARGIN=1表示对行运算,MARGIN=2表示对列运算;FUN用来指定运算函数;…用来指定FUN中需要的其它参数。来看些例子:

用apply()函数来实现上面的例子

> 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()函数功能很强大,我们可以对矩阵的行或列进行其它运算,例如:

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

如果矩阵存在NA值,可通过设置na.rm=TRUE来忽略NA值,然后再计算。比如:

> 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参数来自mean()函数
甚至我们还可以自定义运算函数,来看个例子:

> 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)   ##自定义函数
     [,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) xa+b, a=2, b=1)与x2+1效果相同,此处旨在说明如何应用apply()函数

6.rbind()和cbind()函数

在R中,rbind()和cbind()函数可分别为矩阵添加行和列,来看一个例子:

> 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

7.row()和col()函数

在R中,row()和col()函数将分别返回元素的行和列下标矩阵,来看个例子:

> 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)     ##返回元素的行下标矩阵
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    2    2
[3,]    3    3    3
[4,]    4    4    4
> col(x)     ##返回元素的列下标矩阵
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    1    2    3
[3,]    1    2    3
[4,]    1    2    3

通过这两个函数,可以获取矩阵的对角元素以及上下三角矩阵,例如:

> 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)]    ## 获取对角元素
> dx
[1]  1  6 11
> diag(x)    ##也可通过diag()函数获取对角元素,速度将更快、更简单
[1]  1  6 11

> x[row(x)>col(x)] <- 0   ##结果为上三角矩阵,通过赋值运算将所有下三角元素变为0
> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    0    6   10
[3,]    0    0   11
[4,]    0    0    0

8.rowsum()和aggregate()函数

有时,你可能需要对每行进行分组,然后组内每列求和。在R中可以用rowsum()函数来解决,而且效率也非常高。先看个例子:

> 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)   ##组内每列求和
  [,1] [,2] [,3]
A    4   12   20
B    6   14   22

你也可以用aggregate()函数获得类似结果:

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

aggregate()函数的功能很强大。
有人就会问“为啥没有列分组求和的操作?”,其实你可以先将矩阵转置,然后行分组求和;这两步就等同于列分组求和。

9. sweep()函数

sweep()函数的原型为sweep(x, MARGIN, STATS, FUN = “-”, check.margin = TRUE, …),其中:x为矩阵或数组;MARGIN用来指定是对行运算还是对列运算,MARGIN=1表示对行运算,MARGIN=2表示对列运算;STATS表示想要清除的统计量;FUN用来指定运算函数,默认为减法-;check.margin用来核实x的维度是否与STATS的匹配,如果事先知道它们匹配的话,将其设为FALSE将提高运算速度; …用来指定FUN中需要的其它参数。来看些例子:

> 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)  ##每行减去对应值,比如第一行元素都减1,第二行减2,第三行减3,第四行减4
     [,1] [,2] [,3]
[1,]    0    4    8
[2,]    0    4    8
[3,]    0    4    8
[4,]    0    4    8

从上面的例子可以看出,sweep()函数的功能非常强,它可以对矩阵的行或列减去(默认情况)或加上不同的值
事实上,通过改变FUN参数的具体形式或自定义函数,sweep()函数可以实现很多不同操作,这里就不细讲了。

10. max.col()函数

max.col()函数返回矩阵每行最大值所在的列位置(即列下标),其原型为max.col(m, ties.method = c(“random”, “first”, “last”)),其中:m为矩阵;当存在多个最大值时,ties.method指定用哪种方式来处理这种情况,默认为"random"(随机),"first"指使用第一个最大值,"last"指使用最后一个最大值。来看个官网例子:

> set.seed(1)   ##通过设定随机数种子,使下面的结果可重复
> 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,跟上面的结果不一样
[1] 6 6 5
> max.col(mm, 'first')
[1] 4 6 5
> max.col(mm, 'last')
[1]  7  9 11

我们也可以结合apply()和which.max()函数来实现max.col(mm, ‘first’)。看个例子,

> apply(mm, 1, which.max)
x y z 
4 6 5 
> unname(apply(mm, 1, which.max))   ##通过unname函数去掉向量的名称
[1] 4 6 5

你可能感兴趣的:(R语言)