首页 > 技术文章 > (2)apply函数及其源码

xuanlvshu 2016-03-20 13:37 原文


总结:
就是MARGIN决定了你的FUN调用几次,每次传递给你的是什么维度的内容,而...是传递给FUN的(每次调用的时候都会被传递给FUN)。apply的返回值结果可能是向量,数组(含矩阵)或列表(具体要根据条件分类讨论,但实际上我们没有必要,直接看一下返回的结果就知道是什么类型了)

apply {base}
Description
Returns a vector or array or list of values obtained by applying a function to margins of an array or matrix.
通过对数组或者矩阵的一个维度使用函数,并返回列表或者数组、向量。
Usage
apply(X, MARGIN, FUN, ...)
Arguments
X 数组,包括矩阵
MARGIN  
a vector giving the subscripts(下标 )which the function will be applied over. E.g., for a matrix 1 indicates rows, 2 indicates columns, c(1, 2) indicates rows and columns. Where X has named dimnames, it can be a character vector selecting dimension names.
1表示矩阵行,2表示矩阵列,也可以是c(1,2)(表示按行和按列,对每一个元素使用函数)
当X通过维度指定了名字,则可以是字符向量(用于选择维度)(这里是维度名而不是行名列名)
FUN   
the function to be applied: see ‘Details’. In the case of functions like +, %*%, etc., the function name must be backquoted(backquote是反引用的意思) or quoted
...   
optional arguments to FUN.
Details
If X is not an array but an object of a class with a non-null dim value (such as a data frame), apply attempts to coerce it to an array via as.matrix if it is two-dimensional (e.g., a data frame) or via as.array.
如果X不是数组,但是一个有非空的dim属性值的类对象(如数据框),apply函数将试图使用as.matrix()(当X是二维的时候)或使用as.array()将其转化为数组
FUN is found by a call to match.fun(这是一个函数) and typically is either a function or a symbol (e.g., a backquoted name) or a character string specifying a function to be searched for from the environment of the call to apply.
注:match.fun(FUN, descend = TRUE)(Value(返回值):A function matching FUN or an error is generated.)也就是返回一个function类型的与FUN匹配的函数
FUN通常是通过调用math.fun的函数来找到的,通常是一个函数或一个符号(如一个反引用变量)或者一个字符串指定一个函数(从环境中搜索到然后调用)
Arguments in ... cannot have the same name as any of the other arguments, and care may be needed to avoid partial matching to MARGIN or FUN. In general-purpose(通常) code it is good practice(习惯) to name the first three arguments if ... is passed through: this both avoids partial matching to MARGIN or FUN and ensures that a sensible(明显的) error message is given if arguments named X, MARGIN or FUN are passed through ....
可变参数...中的参数不能和任何其他的参数名一样,并且要注意要避免与MARGIN或FUN部分匹配(就是名字不要和MARGIN或FUN形似咯?)给前三个传递过去的变量命名是个好习惯。
Value
If each call to FUN returns a vector of length n, then apply returns an array of dimension c(n, dim(X)[MARGIN]) if n > 1. If n equals 1, apply returns a vector if MARGIN has length 1 and an array of dimension dim(X)[MARGIN] otherwise(否则). If n is 0, the result has length 0 but not necessarily the ‘correct’ dimension.
每次调用FUN会返回一个长度为n的向量
n>1,则apply返回一个维度为c(n,dim(X)[MARGIN])的数组
n=1且MARGIN的长度为1(说明传入的是一个二维的矩阵),则apply返回一个向量,如果n=1,而MARGIN的长度不为1,则返回一个维度为dim(X)[MARGIN]的数组
n=0,则返回0,但这未必是正确的维度。    
If the calls to FUN return vectors of different lengths, apply returns a list of length prod(dim(X)[MARGIN]) with dim set to MARGIN if this has length greater than one.
如果每次FUN返回的向量有不同的长度,则apply将返回一个长度为prod(dim(X)[MARGIN])的列表,如果其长度大于1,则将dim设置给MARGIN
In all cases the result is coerced by as.vector to one of the basic vector types before the dimensions are set, so that (for example) factor results will be coerced to a character array.
在被维度设定下来之前,这些结果都是被as.vector函数转换,所以因子的结果通常被转换为字符数组。
例:
  1. test<-matrix(1:20,ncol=4)
  2. #既然给定了列数,会自动计算行数

  3. apply(test,c(1,2),mean)

  4. # [,1] [,2] [,3] [,4]
  5. # [1,] 1 6 11 16
  6. # [2,] 2 7 12 17
  7. # [3,] 3 8 13 18
  8. # [4,] 4 9 14 19
  9. # [5,] 5 10 15 20

  10. apply(test,1,mean)

  11. # [1] 8.5 9.5 10.5 11.5 12.5
  12. # 返回的是一个向量


apply函数的源码(直接F2即可)
为了方便理解源码,我们使用一个特例 
  1. x<-matrix(1:6,2)
源码:
  1. function (X, MARGIN, FUN, ...)
  2. {
  3.   FUN <- match.fun(FUN) #找到匹配的函数
  4.   dl <- length(dim(X)) #取到X中是几维 dl=2
  5.   if (!dl)
  6.     stop("dim(X) must have a positive length")

  7.   if (is.object(X)) #盘判断是否class属性
  8.     X <-if (dl == 2L) #维度为2,则转化为矩阵
  9.       as.matrix(X)
  10.     else 
  11. as.array(X) #否则转发转化为数组

  12.   d <- dim(X) #d是一个向量,里面存放着X的每一个维度 d=[1] 2 3
  13.   dn <- dimnames(X) #如果没有指定维度名,则dn=NULL,一般都是NULL
  14.   ds <- seq_len(dl) # 产生一个1到dl的向量 ds=[1] 1 2

  15.   if (is.character(MARGIN)) { #MARGIN是否为字符(我们没指定维度名,这个不考虑)
  16.     if (is.null(dnn <- names(dn)))
  17.       stop("'X' must have named dimnames")
  18.     MARGIN <- match(MARGIN, dnn)
  19.     if (anyNA(MARGIN))
  20.       stop("not all elements of 'MARGIN' are names of dimensions")
  21.   }

  22.   s.call <- ds[-MARGIN] #MARGIN是1或2,假设MARGIN=1 s.call=2
  23.   s.ans <- ds[MARGIN] #s.ans=1

  24.   d.call <- d[-MARGIN] #d.call=3
  25.   d.ans <- d[MARGIN] #第MARGIN个维度的位数 d.ans=2

  26.   dn.call <- dn[-MARGIN] #NULL 不考虑
  27.   dn.ans <- dn[MARGIN] #NULL 不考虑
  28.   d2 <- prod(d.ans) #连乘 d2=2

  29.   if (d2 == 0L) { #我们的一般情况不会出现该维度为0
  30.     newX <- array(vector(typeof(X), 1L), dim = c(prod(d.call),
  31. 1L))
  32.     ans <- forceAndCall(1, FUN, if (length(d.call) < 2L) newX[,
  33.       1] else array(newX[, 1L], d.call, dn.call), ...)
  34.     return(if (is.null(ans)) ans else if (length(d.ans) <
  35.       2L) ans[1L][-1L] else array(ans, d.ans, dn.ans))
  36.   }

  37.   newX <- aperm(X, c(s.call, s.ans)) #c(2,1)
  38. #理解aperm函数就知道,当X是一个矩阵的时候,其实这等价于一个转置
  39.  
  40. [,1] [,2] [1,] 1 2 [2,] 3 4 [3,] 5 6

  41.   dim(newX) <- c(prod(d.call), d2) # 3,2


  42.   ans <- vector("list", d2) #创建一个包含两个组件的列表
  43. [[1]] NULL [[2]] NULL

  44.   if (length(d.call) < 2L) { #d.call=3,不成立
  45.     if (length(dn.call))
  46.       dimnames(newX) <- c(dn.call, list(NULL))
  47.     for (i in 1L:d2) {
  48.       tmp <- forceAndCall(1, FUN, newX[, i], ...)
  49.       if (!is.null(tmp))
  50.         ans[[i]] <- tmp
  51.     }
  52.   }
  53.   else for (i in 1L:d2) { #d2=2 #执行
  54.     tmp <- forceAndCall(1, FUN, array(newX[, i], d.call,dn.call), ...)
  55. #传给apply的要被处理的数据是在这里才被传递给FUN的
  56.     if (!is.null(tmp)) #判断是否为空
  57.       ans[[i]] <- tmp
  58.   }
  59. #此时ans
  60. [[1]] [1] 3 #newX第一列的均值 [[2]] [1] 4


  61.   ans.list <- is.recursive(ans[[1L]]) #[1] FALSE

  62.   l.ans <- length(ans[[1L]]) # l.ans=1

  63.   ans.names <- names(ans[[1L]]) #ans.names=NULL

  64.   if (!ans.list) #成立
  65.     ans.list <- any(lengths(ans) != l.ans)
  66. #lengths(ans) [1] 1 1 即每个组件中的元素的个数
  67. #[1] FALSE FALSE ----> ans.list = FALSE
  68.   if (!ans.list && length(ans.names)) { #length(ans.names)=0 所以整个是F,不成立
  69.     all.same <- vapply(ans, function(x) identical(names(x),
  70.       ans.names), NA)
  71.     if (!all(all.same))
  72.       ans.names <- NULL
  73.   }
  74.   len.a <- if (ans.list) #不成立

  75.     d2
  76.   else length(ans <- unlist(ans, recursive = FALSE)) # len.a=2

  77.   if (length(MARGIN) == 1L && len.a == d2) { #满足
  78.     names(ans) <- if (length(dn.ans[[1L]])) #dn.ans是null
  79.       dn.ans[[1L]] #不会执行
  80.     ans # [1] 3 4 最终整个作为返回值
  81.   }
  82.   else if (len.a == d2)
  83.     array(ans, d.ans, dn.ans)
  84.   else if (len.a && len.a%%d2 == 0L) {
  85.     if (is.null(dn.ans))
  86.       dn.ans <- vector(mode = "list", length(d.ans))
  87.     dn1 <- list(ans.names)
  88.     if (length(dn.call) && !is.null(n1 <- names(dn <- dn.call[1])) &&
  89.       nzchar(n1) && length(ans.names) == length(dn[[1]]))
  90.       names(dn1) <- n1
  91.     dn.ans <- c(dn1, dn.ans)
  92.     array(ans, c(len.a%/%d2, d.ans), if (!is.null(names(dn.ans)) ||
  93.       !all(vapply(dn.ans, is.null, NA)))
  94.       dn.ans)
  95.   }
  96.   else ans
  97. }

补充1
seq_len()函数是seq函数族中的一个,用法如下:
seq_len(length.out) 
length.out   
desired length of the sequence. A non-negative number, which for seq and seq.int will be rounded up if fractional.(想要生成的序列的个数)
其实就是seq_len(n)  产生n个数(从1到n)
补充2
aperm方法的用法详见笔记
aperm方法
补充3
vector函数
补充4 
forceAndCall函数
补充5
is.recursive returns TRUE if x has a recursive (list-like) structure(递归结构) and FALSE otherwise.



###################################################
关于...参数是如何传递给FUN的
事实上,上面的分析结合下面金的分析,我得出的结论是:
forceAndCall将X和...传递给了FUN,事实上,我们可以将...看做一个一组不确定个数和名字的变量(或者把他当做一个记号吧~)
  1. x <- cbind(x1 = 3, x2 = c(4:1, 2:5))
  2. dimnames(x)[[1]] <- letters[1:8]
  3. x
  4.   x1 x2
  5. 3  4
  6. 3  3
  7. 3  2
  8. 3  1
  9. 3  2
  10. 3  3
  11. 3  4
  12. 3  5
  13. apply(x, 2, mean, trim = .2)
  14. x1 x2
  15.  3  3 

  1. function (X, MARGIN, FUN, ...) 
  2. {
  3.   FUN <- match.fun(FUN)
  4.   dl <- length(dim(X))   #dl=2
  5.   if (!dl) 
  6.     stop("dim(X) must have a positive length")
  7.   if (is.object(X)) 
  8.     X <- if (dl == 2L) 
  9.       as.matrix(X)       #例子中x本就是matrix
  10.   else as.array(X)
  11.   d <- dim(X)            #d=[1] 8 2
  12.   dn <- dimnames(X)      
  13. # [[1]]
  14. # [1] "a" "b" "c" "d" "e" "f" "g" "h"
  15. # [[2]]
  16. # [1] "x1" "x2"
  17.   ds <- seq_len(dl)      #ds=1 2
  18.   if (is.character(MARGIN)) {      #MARGIN=2,不是字符
  19.     if (is.null(dnn <- names(dn))) 
  20.       stop("'X' must have named dimnames")
  21.     MARGIN <- match(MARGIN, dnn)
  22.     if (anyNA(MARGIN)) 
  23.       stop("not all elements of 'MARGIN' are names of dimensions")
  24.   }
  25.   s.call <- ds[-MARGIN]   #s.call=1
  26.   s.ans <- ds[MARGIN]     #s.ans=2
  27.   d.call <- d[-MARGIN]    #d.call=8
  28.   d.ans <- d[MARGIN]      #d.ans=2
  29.   dn.call <- dn[-MARGIN]
  30. # [[1]]
  31. # [1] "a" "b" "c" "d" "e" "f" "g" "h"
  32.   dn.ans <- dn[MARGIN]
  33. # [[1]]
  34. # [1] "x1" "x2"
  35.   d2 <- prod(d.ans)      #d2=2
  36.   if (d2 == 0L) {        #跳过
  37.     newX <- array(vector(typeof(X), 1L), dim = c(prod(d.call), 
  38.                                                  1L))
  39.     ans <- forceAndCall(1, FUN, if (length(d.call) < 2L) newX[, 
  40.                                                               1] else array(newX[, 1L], d.call, dn.call), ...)
  41.     return(if (is.null(ans)) ans else if (length(d.ans) < 
  42.                                           2L) ans[1L][-1L] else array(ans, d.ans, dn.ans))
  43.   }
  44.   newX <- aperm(X, c(s.call, s.ans))  #perm=c(1,2),所以相当于没变
  45. #   x1 x2
  46. # a  3  4
  47. # b  3  3
  48. # c  3  2
  49. # d  3  1
  50. # e  3  2
  51. # f  3  3
  52. # g  3  4
  53. # h  3  5
  54.   dim(newX) <- c(prod(d.call), d2)  #8,2
  55. #      [,1] [,2]
  56. # [1,]    3    4
  57. # [2,]    3    3
  58. # [3,]    3    2
  59. # [4,]    3    1
  60. # [5,]    3    2
  61. # [6,]    3    3
  62. # [7,]    3    4
  63. # [8,]    3    5
  64. #重定义了下维度就没有dimnames属性啦?
  65.   ans <- vector("list", d2)
  66. # [[1]]
  67. # NULL
  68. # [[2]]
  69. # NULL
  70.   if (length(d.call) < 2L) { #d.call=8
  71.     if (length(dn.call)) 
  72.       dimnames(newX) <- c(dn.call, list(NULL))
  73.     for (i in 1L:d2) {
  74.       tmp <- forceAndCall(1, FUN, newX[, i], ...)
  75.       if (!is.null(tmp)) 
  76.         ans[[i]] <- tmp
  77.     }
  78.   }
  79.   else for (i in 1L:d2) {    #执行
  80.     tmp <- forceAndCall(1, FUN, array(newX[, i], d.call, 
  81.                                       dn.call), ...)

  82. #我经过反复的测试,得到trim = .2这个参数其实是传递给了...

  83. #只不过这里不巧的是mean(newX)和mean(newX,.2)的结果都是3
  84.     if (!is.null(tmp)) 
  85.       ans[[i]] <- tmp
  86.   }
  87.   ans.list <- is.recursive(ans[[1L]])
  88.   l.ans <- length(ans[[1L]])
  89.   ans.names <- names(ans[[1L]])
  90.   if (!ans.list) 
  91.     ans.list <- any(lengths(ans) != l.ans)
  92.   if (!ans.list && length(ans.names)) {
  93.     all.same <- vapply(ans, function(x) identical(names(x), 
  94.                                                   ans.names), NA)
  95.     if (!all(all.same)) 
  96.       ans.names <- NULL
  97.   }
  98.   len.a <- if (ans.list) 
  99.     d2
  100.   else length(ans <- unlist(ans, recursive = FALSE))
  101.   if (length(MARGIN) == 1L && len.a == d2) {
  102.     names(ans) <- if (length(dn.ans[[1L]])) 
  103.       dn.ans[[1L]]
  104.     ans
  105.   }
  106.   else if (len.a == d2) 
  107.     array(ans, d.ans, dn.ans)
  108.   else if (len.a && len.a%%d2 == 0L) {
  109.     if (is.null(dn.ans)) 
  110.       dn.ans <- vector(mode = "list", length(d.ans))
  111.     dn1 <- list(ans.names)
  112.     if (length(dn.call) && !is.null(n1 <- names(dn <- dn.call[1])) && 
  113.         nzchar(n1) && length(ans.names) == length(dn[[1]])) 
  114.       names(dn1) <- n1
  115.     dn.ans <- c(dn1, dn.ans)
  116.     array(ans, c(len.a%/%d2, d.ans), if (!is.null(names(dn.ans)) || 
  117.                                          !all(vapply(dn.ans, is.null, NA))) 
  118.       dn.ans)
  119.   }
  120.   else ans
  121. }

删掉了那些执行不到的代码和一些与我们的问题无关的代码
  1. function (X, MARGIN, FUN, ...) 
  2. {
  3.   FUN <- match.fun(FUN)
  4.   dl <- length(dim(X))   #dl=2
  5.   if (!dl) 
  6.     stop("dim(X) must have a positive length")
  7.   if (is.object(X)) 
  8.     X <- if (dl == 2L) 
  9.       as.matrix(X)       #例子中x本就是matrix
  10.   else as.array(X)
  11.   d <- dim(X)            #d=[1] 8 2
  12.   dn <- dimnames(X)      
  13. # [[1]]
  14. # [1] "a" "b" "c" "d" "e" "f" "g" "h"
  15. # [[2]]
  16. # [1] "x1" "x2"
  17.   ds <- seq_len(dl)      #ds=1 2
  18.   s.call <- ds[-MARGIN]   #s.call=1
  19.   s.ans <- ds[MARGIN]     #s.ans=2
  20.   d.call <- d[-MARGIN]    #d.call=8
  21.   d.ans <- d[MARGIN]      #d.ans=2
  22.   dn.call <- dn[-MARGIN]
  23. # [[1]]
  24. # [1] "a" "b" "c" "d" "e" "f" "g" "h"
  25.   dn.ans <- dn[MARGIN]
  26. # [[1]]
  27. # [1] "x1" "x2"
  28.   d2 <- prod(d.ans)      #d2=2
  29.   newX <- aperm(X, c(s.call, s.ans))  #perm=c(1,2),所以相当于没变
  30. #   x1 x2
  31. # a  3  4
  32. # b  3  3
  33. # c  3  2
  34. # d  3  1
  35. # e  3  2
  36. # f  3  3
  37. # g  3  4
  38. # h  3  5
  39.   dim(newX) <- c(prod(d.call), d2)  #8,2
  40. #      [,1] [,2]
  41. # [1,]    3    4
  42. # [2,]    3    3
  43. # [3,]    3    2
  44. # [4,]    3    1
  45. # [5,]    3    2
  46. # [6,]    3    3
  47. # [7,]    3    4
  48. # [8,]    3    5
  49. #重定义了下维度就没有dimnames属性啦?
  50.   ans <- vector("list", d2)
  51. # [[1]]
  52. # NULL
  53. # [[2]]
  54. # NULL
  55.   if (length(d.call) < 2L) { #d.call=8
  56.     if (length(dn.call)) 
  57.       dimnames(newX) <- c(dn.call, list(NULL))
  58.     for (i in 1L:d2) {
  59.       tmp <- forceAndCall(1, FUN, newX[, i], ...)
  60.       if (!is.null(tmp)) 
  61.         ans[[i]] <- tmp
  62.     }
  63.   }
  64.   else for (i in 1L:d2) {    #执行
  65.     tmp <- forceAndCall(1, FUN, array(newX[, i], d.call, 
  66.                                       dn.call), ...)


  67. #我经过反复的测试,得到trim = .2这个参数其实是传递给了...

  68. #只不过这里不巧的是mean(newX)和mean(newX,.2)的结果都是3
  69. }


###############################################
余下的例子:
  1. ## Compute row and column sums for a matrix:
  2. x <- cbind(x1 = 3, x2 = c(4:1, 2:5))
  3. dimnames(x)[[1]] <- letters[1:8]
  4. #求列均值
  5. apply(x, 2, mean, trim = .2)
  6. #求每一列的和
  7. col.sums <- apply(x, 2, sum)
  8. # x1 x2 
  9. # 24 24 
  10. #求每一行的和
  11. row.sums <- apply(x, 1, sum)
  12. # a b c d e f g h 
  13. # 7 6 5 4 5 6 7 8
  14. rbind(cbind(x, Rtot = row.sums), Ctot = c(col.sums, sum(col.sums)))
  15. #      x1 x2 Rtot
  16. # a     3  4    7
  17. # b     3  3    6
  18. # c     3  2    5
  19. # d     3  1    4
  20. # e     3  2    5
  21. # f     3  3    6
  22. # g     3  4    7
  23. # h     3  5    8
  24. # Ctot 24 24   48
  25. > apply(x, 2, is.vector)
  26.   x1   x2
  27. TRUE TRUE 
  28. ## Sort the columns of a matrix

  29. #按列排序,排序完了列名就木有啦?
  30. apply(x, 2, sort)
  31. #      x1 x2
  32. # [1,]  3  1
  33. # [2,]  3  2
  34. # [3,]  3  2
  35. # [4,]  3  3
  36. # [5,]  3  3
  37. # [6,]  3  4
  38. # [7,]  3  4
  39. # [8,]  3  5

为了自己探索上面的行名在排序后消失的困惑,我自己写了如下的代码测试
  1. > a<-c(2,11,7,13)
  2. > b<-c(3,5,9,2)
  3. > m<-cbind(a=a,b=b)
  4. > dimnames(m)<-list(paste(LETTERS[1:4],1:4,sep = "-"),c(letters[1:2]))
  5. > m
  6.      a b
  7. A-1  2 3
  8. B-2 11 5
  9. C-3  7 9
  10. D-4 13 2
  11. > apply(m,2,sort)
  12.       a b
  13. [1,]  2 2
  14. [2,]  7 3
  15. [3,] 11 5
  16. [4,] 13 9
  17. > apply(m,1,sort)
  18.      A-1 B-2 C-3 D-4
  19. [1,]   2   5   7   2
  20. [2,]   3  11   9  13
所以,你会发现,这种排序可能对于矩阵还有点用,对于数据框完全没有意义,因为他把行给拆开了,本来2对应3,现在变成了2对应2,所以说,他的行名自然也就消失了,因为这个行已经不是原来的那个行,自然也不能用原来的行名了(容易误导),同样的,按行排序也是。
注意, LETTERS是一个常量而不是函数
查看帮助文档会发现LETTERS是在Constants下的,Constants中存放的是R中的常量。只有四个(LETTERS,letters,month.abb,month.name,pi
LETTERS: the 26 upper-case letters of the Roman alphabet(拉丁字母/罗马字母);
26个大写英文字母
letters: the 26 lower-case letters of the Roman alphabet;
26个小写的英文字母
month.abb: the three-letter abbreviations for the English month names;
三个字母缩写的12月份名
month.name: the English names for the months of the year;
12月份名(全名)
pi: the ratio of the circumference of a circle to its diameter.


例子2:
其实我不太清楚例子2想说明什么,想说明维度名会保存么?不过我们这还少学会了如何设置维度名
  1. x <- cbind(x1 = 3, x2 = c(4:1, 2:5))
  2. x
  3. #      x1 x2
  4. # [1,]  3  4
  5. # [2,]  3  3
  6. # [3,]  3  2
  7. # [4,]  3  1
  8. # [5,]  3  2
  9. # [6,]  3  3
  10. # [7,]  3  4
  11. # [8,]  3  5

  12. ## keeping named dimnames
  13. #给维度命名
  14. names(dimnames(x)) <- c("row", "col")
  15. #给维度命名
  16. x
  17. #      col
  18. # row   x1 x2
  19. # [1,]  3  4
  20. # [2,]  3  3
  21. # [3,]  3  2
  22. # [4,]  3  1
  23. # [5,]  3  2
  24. # [6,]  3  3
  25. # [7,]  3  4
  26. # [8,]  3  5

  27. x3 <- array(x, dim = c(dim(x),3),

  28.             dimnames = c(dimnames(x), 
  29.             list(C = paste0("cop.",1:3))))
  30. x3
  31. # , , C = cop.1
  32. #       col
  33. # row   x1 x2
  34. # [1,]  3  4
  35. # [2,]  3  3
  36. # [3,]  3  2
  37. # [4,]  3  1
  38. # [5,]  3  2
  39. # [6,]  3  3
  40. # [7,]  3  4
  41. # [8,]  3  5
  42. # , , C = cop.2
  43. #       col
  44. # row   x1 x2
  45. # [1,]  3  4
  46. # [2,]  3  3
  47. # [3,]  3  2
  48. # [4,]  3  1
  49. # [5,]  3  2
  50. # [6,]  3  3
  51. # [7,]  3  4
  52. # [8,]  3  5
  53. # , , C = cop.3
  54. #       col
  55. # row   x1 x2
  56. # [1,]  3  4
  57. # [2,]  3  3
  58. # [3,]  3  2
  59. # [4,]  3  1
  60. # [5,]  3  2
  61. # [6,]  3  3
  62. # [7,]  3  4
  63. # [8,]  3  5

  64. identical(x,  apply( x,  2,  identity))
  65. # [1] TRUE
  66. identical(x3, apply(x3, 2:3, identity))
  67. # [1] TRUE

  68. > apply( x,  2,  identity)
  69.       col
  70. row    x1 x2
  71.   [1,]  3  4
  72.   [2,]  3  3
  73.   [3,]  3  2
  74.   [4,]  3  1
  75.   [5,]  3  2
  76.   [6,]  3  3
  77.   [7,]  3  4
  78.   [8,]  3  5
  79. > apply(x3, 2:3, identity) #对数组的列和层引用identity函数
  80. , , C = cop.1
  81.       col
  82. row    x1 x2
  83.   [1,]  3  4
  84.   [2,]  3  3
  85.   [3,]  3  2
  86.   [4,]  3  1
  87.   [5,]  3  2
  88.   [6,]  3  3
  89.   [7,]  3  4
  90.   [8,]  3  5
  91. , , C = cop.2
  92.       col
  93. row    x1 x2
  94.   [1,]  3  4
  95.   [2,]  3  3
  96.   [3,]  3  2
  97.   [4,]  3  1
  98.   [5,]  3  2
  99.   [6,]  3  3
  100.   [7,]  3  4
  101.   [8,]  3  5 ###下面这段输出结果第一次忘了插入了
    1. , , C = cop.3
    2. col
    3. row x1 x2
    4. [1,] 3 4
    5. [2,] 3 3
    6. [3,] 3 2
    7. [4,] 3 1
    8. [5,] 3 2
    9. [6,] 3 3
    10. [7,] 3 4
    11. [8,] 3 5

这里我比较奇怪的是,为什么输出的都是TRUE(先用了identity再用identical函数判断,当然是TRUE了)
查看了identity的说明:
A trivial(琐碎的微小的) identity(识别) function returning its argument.
这什么鬼?还不带例子
identical的描述是:
The safe and reliable way to test two objects for being exactly equal. It returns TRUE in this case, FALSE in every other case.
安全而可靠的测试两个变量是否完全相同。

例子3:
  1. x <- cbind(x1 = 3, x2 = c(4:1, 2:5))
  2. > x
  3.      x1 x2
  4. [1,]  3  4
  5. [2,]  3  3
  6. [3,]  3  2
  7. [4,]  3  1
  8. [5,]  3  2
  9. [6,]  3  3
  10. [7,]  3  4
  11. [8,]  3  5

  12. cave <- function(x, c1, c2) {
  13.   c(mean(x[c1]), mean(x[c2]))
  14. }
  15. apply(x, 1, cave,  c1 = "x1", c2 = c("x1","x2"))

  16.       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
  17. [1,]  3.0    3  3.0    3  3.0    3  3.0    3
  18. [2,]  3.5    3  2.5    2  2.5    3  3.5    4
  1. > class(apply(x, 1, cave,  c1 = "x1", c2 = c("x1","x2")))

  2. [1] "matrix"

我通过下面的例子,来说明MARGIN=1和x以及c1和c2的传递方式
  1. x <- cbind(x1 = 3, x2 = c(4:1, 2:5))
  2. ##- function with extra args:
  3. cave <- function(x, c1, c2) {
  4.   print("##q##")
  5.   print(x)
  6.   print("==b==")
  7.   c(mean(x[c1]), mean(x[c2]))
  8. }

  9. apply(x, 1, cave,  c1 = "x1", c2 = c("x1","x2"))
  10. [1] "##q##"
  11. x1 x2 
  12.  3  4 
  13. [1] "==b=="
  14. [1] "##q##"
  15. x1 x2 
  16.  3  3 
  17. [1] "==b=="
  18. [1] "##q##"
  19. x1 x2 
  20.  3  2 
  21. [1] "==b=="
  22. [1] "##q##"
  23. x1 x2 
  24.  3  1 
  25. [1] "==b=="
  26. [1] "##q##"
  27. x1 x2 
  28.  3  2 
  29. [1] "==b=="
  30. [1] "##q##"
  31. x1 x2 
  32.  3  3 
  33. [1] "==b=="
  34. [1] "##q##"
  35. x1 x2 
  36.  3  4 
  37. [1] "==b=="
  38. [1] "##q##"
  39. x1 x2 
  40.  3  5 
  41. [1] "==b=="
  42.      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
  43. [1,]  3.0    3  3.0    3  3.0    3  3.0    3
  44. [2,]  3.5    3  2.5    2  2.5    3  3.5    4
我们发现,其实MARGIN并不是传递给FUN的(当然我们查看源码也知道了),
我们发现,FUN被调用了8次(这个次数就是行数),而我们每次都传递了一行数据进去。
结合上面的源码,我们发现,apply接受MARGIN函数后,会通过一些列的转化,最终决定FUN被调用几次,每次传递哪个维度的数据给FUN,最后才是在apply中重新组合为一个合适的向量/数组(数组包含矩阵),而...才是每次真正的传递给FUN的参数。

例子4
  1. > ma <- matrix(c(1:4, 1, 6:8), nrow = 2)
  2. > ma
  3. [,1] [,2] [,3] [,4]
  4. [1,] 1 3 1 7
  5. [2,] 2 4 6 8

  6. > apply(ma, 1, table) #--> a list of length 2
  7. [[1]]
  8. 1 3 7
  9. 2 1 1
  10. [[2]]
  11. 2 4 6 8
  12. 1 1 1 1
  13. > apply(ma, 1, stats::quantile) # 5 x n matrix with rownames
  14. [,1] [,2]
  15. 0% 1 2.0
  16. 25% 1 3.5
  17. 50% 2 5.0
  18. 75% 4 6.5
  19. 100% 7 8.0
  20. > dim(ma) == dim(apply(ma, 1:2, sum)) #判断是否相等
  21. [1] TRUE TRUE
  22. > ma
  23. [,1] [,2] [,3] [,4]
  24. [1,] 1 3 1 7
  25. [2,] 2 4 6 8
apply(ma, 1:2, sum)其实1:2的意思相当于每次把一个元素传给sum了,我们可以自己编写个函数试验下是否是真的传递了8次。






null


推荐阅读