3 向量化操作(apply)

3.1 循环迭代之 lapply/sapply

sapply,lapply 的简化版

第一参数是 X,官方解释说,可接收向量,list,或表达式对象,其他对象将被强制按 list,第二个参数则是函数,返回一个向量或矩阵。

func <- function(x){
  if (x %% 2 == 0){
    ret <- 'even'
  }
  else {
    ret <- 'odd'
  }
  return(ret)
}
vec <- round(runif(4)*100)
func(vec)
#> Warning in if (x%%2 == 0) {: the condition has length > 1 and only the
#> first element will be used
#> [1] "even"
vec
#> [1]  8 83 60 16
sapply(vec, func)
#> [1] "even" "odd"  "even" "even"

lapply

跟 sapply 的区别在于返回的是列表

lapply(vec, func)
#> [[1]]
#> [1] "even"
#> 
#> [[2]]
#> [1] "odd"
#> 
#> [[3]]
#> [1] "even"
#> 
#> [[4]]
#> [1] "even"
mylist <- as.list(iris[, 1:4]) # 不转list,也是强按
yourdata <- iris[, 1:4]

sapply(mylist, mean) # 还可以对列表进行计算
#> Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
#>         5.84         3.06         3.76         1.20
lapply(mylist, mean) # return a list
#> $Sepal.Length
#> [1] 5.84
#> 
#> $Sepal.Width
#> [1] 3.06
#> 
#> $Petal.Length
#> [1] 3.76
#> 
#> $Petal.Width
#> [1] 1.2

myfunc <- function(x) {
  ret <- c(mean(x),sd(x))
  return(ret)
}
result <- lapply(mylist, myfunc)
result
#> $Sepal.Length
#> [1] 5.843 0.828
#> 
#> $Sepal.Width
#> [1] 3.057 0.436
#> 
#> $Petal.Length
#> [1] 3.76 1.77
#> 
#> $Petal.Width
#> [1] 1.199 0.762

t(sapply(result, '[')) # list数据转 data.frame
#>              [,1]  [,2]
#> Sepal.Length 5.84 0.828
#> Sepal.Width  3.06 0.436
#> Petal.Length 3.76 1.765
#> Petal.Width  1.20 0.762

3.2 分组运算

apply

第一个参数接收数组或矩阵,MARGIN 参数按行或列计算

set.seed(1)
vec <- round(runif(12)*100)
mat <- matrix(vec, nrow = 3, ncol = 4)
apply(mat, MARGIN = 1, sum) # 1为行,2为列
#> [1] 218 144 228

tapply

tapply用于分组的循环计算,通过INDEX参数可以把数据集X进行分组,相当于group by的操作。

head(iris)
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1          5.1         3.5          1.4         0.2  setosa
#> 2          4.9         3.0          1.4         0.2  setosa
#> 3          4.7         3.2          1.3         0.2  setosa
#> 4          4.6         3.1          1.5         0.2  setosa
#> 5          5.0         3.6          1.4         0.2  setosa
#> 6          5.4         3.9          1.7         0.4  setosa
with(iris, tapply(Sepal.Length, list(Species), mean))
#>     setosa versicolor  virginica 
#>       5.01       5.94       6.59

aggregate

比较友好,返回的是数据框

aggregate(iris$Sepal.Length, list(iris$Species), mean)
#>      Group.1    x
#> 1     setosa 5.01
#> 2 versicolor 5.94
#> 3  virginica 6.59

3.3 多参数运算

mapply

这个函数目前理解的还不是很透彻,待补。

mapply(rep, times = 1:4, x = 4:1)
#> [[1]]
#> [1] 4
#> 
#> [[2]]
#> [1] 3 3
#> 
#> [[3]]
#> [1] 2 2 2
#> 
#> [[4]]
#> [1] 1 1 1 1