R语言初级教程(15): 矩阵(下篇)

作者: R语言和Python学堂 | 来源:发表于2018-11-06 17:04 被阅读3次
    R中的数据结构

    这是最后一篇讲解有关矩阵操作的博客,介绍有关矩阵的函数,主要有rowSums(), colSums(), rowMeans(), colMeans(), apply(), rbind(), cbind(), row(), col(), rowsum(), aggregate(), sweep(), max.col()

    下面通过例子来了解这些函数的用法:

    1. 矩阵的行、列计算

    我们知道,通过下标索引[i, 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
    
    > mean(x[,3])    ##求第三列的平均值,行索引i没提供,意味着“所有行”
    [1] 10.5
    > var(x[2,])   ##求第二行的方差,列索引j没提供,意味着“所有列”
    [1] 16
    

    在R中,可以用一些特殊的函数来进行矩阵的行、列计算。来看些例子:

    > 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
    

    上面四个函数都是R内建函数,当矩阵中没有NANaN时,计算效率非常高。

    上述矩阵的行、列计算,还可以使用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) x*a+b, a=2, b=1)x*2+1效果相同,此处旨在说明如何应用apply()函数

    2. 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
    

    3. 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
    

    4. 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
    

    上述代码将第一行和第三行作为A组,把第二行和第四行作为B组,然后组内每列求和。注意分组向量的长度必须与矩阵行数相同

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

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

    aggregate()函数的功能很强大,后面讲“数据框”时再详细讲解。

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

    5. 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()函数可以实现很多不同操作,这里就不细讲了。

    6. 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矩阵的最后一部分内容就讲到这。

    如若有遗漏,后期将会添加至本博客。


    感谢您的阅读!想了解更多有关R语言技巧,请关注我的微信公众号“R语言和Python学堂”,我将定期更新相关文章。

    相关文章

      网友评论

        本文标题:R语言初级教程(15): 矩阵(下篇)

        本文链接:https://www.haomeiwen.com/subject/poujtqtx.html