R语言中的apply(),lapply(),sapply(),tapply()函数以及示例

  • apply()数据框或矩阵作为输入,并以矢量,列表或数组形式输出。apply()函数主要用于避免重复使用循环结构。它是所有可以在矩阵上使用的最基本的集合。

最简单的示例是对所有列求和。代码apply(m1,2,sum)将sum函数应用于矩阵5x6,并返回数据集中可访问的每一列的总和。

m1 <- matrix(C<-(1:10),nrow=5, ncol=6) 5行6列,默认按列排序
m1
a_m1 <- apply(m1, 2, sum) # 对m1矩阵的列(MARGIN=2)求sum
a_m1
  • lapply()函数可用于对列表对象执行操作,并返回与原始集合长度相同的列表对象。

lapply()中的l代表列表。lapply()和apply()之间的区别在于输出返回之间。lapply()的输出是一个列表。因此,lapply()函数不需要MARGIN。

movies <- c("SPYDERMAN","BATMAN","VERTIGO","CHINATOWN")
movies_lower <-lapply(movies, tolower) # tolower函数将所有的大写电影名改成小写
str(movies_lower)

我们可以使用unlist()将列表转换为向量。

films_lower <- unlist(lapply(movies,tolower)) # 使用unlist()将列表转换为向量
str(movies_lower)
  • sapply()函数将列表,向量或数据帧作为输入,并以向量或矩阵形式输出。sapply()函数执行的功能与lapply()函数相同,但返回一个向量

那和 unlist(lapply()) 有什么区别吗?结果显示:没有=。=

好吧肯定是有区别的,查阅了一下资料: https://stackoverflow.com/questions/18761541/why-is-unlistlapply-faster-than-sapply

资料告诉我们:

We don't need sapply. It exists purely for convenience. – Roland (我们不需要 sapply。它纯粹是为了方便而存在。)

除了运行以外lapply,还sapply可以运行simplify2array以尝试将输出拟合到数组中。为了弄清楚这是否可行,该函数需要检查所有单个输出的长度是否都相同:这是通过花费大量费用unique(lapply(..., length))来解决的,该费用占了您所看到的大部分时间差。 —— flodel 

正如droopy和Roland所指出的那样,sapplylapply的包装函数,旨在方便使用。sapply使用simplify2array,速度比unlist。 —— user1981275

跳过这些,直接看代码:

dt <- cars
lmn_cars <- lapply(dt, min) # 测量汽车的最小速度和最小停车距离
smn_cars <- sapply(dt, min)
lmn_cars
smn_cars
unlist_lmn_cars <- unlist( lmn_cars )
unlist_lmn_cars

> unlist_lmn_cars == smn_cars
speed  dist 
 TRUE  TRUE 

> identical(unlist_lmn_cars,smn_cars)
[1] TRUE

 得到这个结果后,我们应该如何分析呢?欢迎读者赐教!

  • tapply()计算向量中每个因子变量的度量函数(均值,中位数,最小值,最大值等)。
data(iris) # 使用虹膜数据集。该数据集的目的是预测三种花类中的每一种的类别。
tapply(iris$Sepal.Width, iris$Species, median) # 计算每个物种Species的宽度Width的中位数

声明:上文参考https://www.jianshu.com/p/59fb24ca2ea7 ,原作者你有康娜可爱吗,写的真好~简单做了些注释


  • Examples
## Compute row and column sums for a matrix: 分别计算矩阵的行列的和
x <- cbind(x1 = 3, x2 = c(4:1, 2:5)) # 向量,2列8行

# dimnames(x) 包含x的行列名, dimnames(x)[[1]] 是行名,dimnames(x)[[2]] 是列名
dimnames(x)[[1]] <- letters[1:8] # 将行名设置为a到h

# apply(X, MARGIN, FUN, ...) FUN后面的内容都是FUN的可选参数设置
# trim 会分别去除百分之多少的最大值和最小值
apply(x, 2, mean, trim = .2) # 去掉20%的最大值和最小值,对x按列求和
col.sums <- apply(x, 2, sum) # 列和
row.sums <- apply(x, 1, sum) # 行和

# cbind(x, Rtot = row.sums) 生成向量 列1=x1,列2=x2,列3=各行之和 共3列8行
# Ctot = c(col.sums, sum(col.sums)) 生成向量,由x1列1和,x2列和,总和 组成 3列1行
# 按行合并,生成3列(8+1)行的向量组
rbind(cbind(x, Rtot = row.sums), Ctot = c(col.sums, sum(col.sums)))



stopifnot( apply(x, 2, is.vector)) # stopifnot没有报错,说明x每列都是向量

## Sort the columns of a matrix 对矩阵按列排序
apply(x, 2, sort)




## keeping named dimnames 保留行列名的命名
# dimnames(x) 包含x的行列名, dimnames(x)[[1]] 是行名,dimnames(x)[[2]] 是列名
# 给行列名取名
names(dimnames(x)) <- c("row", "col")

# dim(x) 表明有8行2列
# 创建数组,8行2列3组,将x重复3组,保留行列名,组名:cop.1 cop,2 cop,3
x3 <- array(x, dim = c(dim(x),3),
	    dimnames = c(dimnames(x), list(C = paste0("cop.",1:3))))

# identical 判断两个对象是否精确相等,比==好用
# identity(x) 输出x的值
# x 8行2列; apply( x,  2,  identity) 按列输出x 8行2列
identical(x,  apply( x,  2,  identity)) # 没区别
# x3 8行2列3组; apply(x3, 2:3, identity) 按列和组输出x3 8行2列3组
identical(x3, apply(x3, 2:3, identity)) # 没区别




##- function with extra args: 在apply中应用具有更多参数的复杂函数
# apply(X, MARGIN, FUN, ...) FUN后面的内容都是FUN的可选参数设置

# cave 函数 输出x的c1列的均值 和 c2列的均值
cave <- function(x, c1, c2) c(mean(x[c1]), mean(x[c2]))
# 按8个行输出两行计算结果: x1列的均值 和(x1列及x2列)的均值
# x1列的均值 就是x1列本身
apply(x, 1, cave,  c1 = "x1", c2 = c("x1","x2")) 
# 结果为 2行8列的向量组,第一行为x1列本身,第二行为(x1列及x2列)的均值




ma <- matrix(c(1:4, 1, 6:8), nrow = 2) # ma是按列排列的2行4列矩阵,byrow = FALSE
ma
apply(ma, 1, table)  #--> a list of length 2 结果为2组的列表,按行统计频率
# 结果为ma矩阵按行统计频率
apply(ma, 1, stats::quantile) # 5 x n matrix with rownames 结果为带行名的向量组(原文说是矩阵,看起来是矩阵,实际上是向量组)
# stats::quantile 默认给出seq(0, 1, 0.25)概率的5个常规分位数,分配到ma的每行计算中
# ma矩阵2行4列,按行统计,结果共有2列;5个分位数,结果共有5行
# apply(ma, 1, FUN) 函数有几个指标,按行计算,结果就有几行,按列计算,结果就有几列
# 有点绕,梳理一下,本子上画一画就发现,有点形似矩阵的乘法



stopifnot(dim(ma) == dim(apply(ma, 1:2, sum))) # stopifnot没有报错,说明这俩维数相等
# dim(ma) 2行4列
# apply(ma, 1:2, sum) 结果和ma一样,identical(ma,apply(ma, 1:2, sum))结果为TRUE,这是我很困惑的地方,难道矩阵分别按行按列相加之后,和原矩阵一致?算一算,不一致啊,谁来告诉我这是咋回事?




## Example with different lengths for each call 每次调用不同长度的
# 创建数组,共24个元素,2行3列4组(dim = c(2,3,4))
z <- array(1:24, dim = 2:4)

# 一边调用apply一边编写一个函数
# 这个函数计算最大值的序列长度
zseq <- apply(z, 1:2, function(x) seq_len(max(x))) # 分别按行列计算最大值的序列长度
zseq         ## a 2 x 3 matrix 结果是2行3列的矩阵,str显示其由6组整数序列组成的列表
# 结果表明最大值都出现在最后1组


typeof(zseq) ## list 与str的结果一致,确实是列表
dim(zseq) ## 2 3 但其维数是2行3列
zseq[1,] # 展示第一行!第一行是Integer,19 Integer,21 Integer,23 三组序列!

apply(z, 3, function(x) seq_len(max(x))) # 按组计算最大值的序列长度,z为2行3列4组的数组
# 结果是4组的列表
# a list without a dim attribute 结果没有维数属性,这是啥意思?我不是做出来4组了吗,但是结果如下:


==============================
[[1]]
[1] 1 2 3 4 5 6

[[2]]
 [1]  1  2  3  4  5  6  7  8  9 10 11 12

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

[[4]]
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

> str(apply(z, 3, function(x) seq_len(max(x))))
List of 4
 $ : int [1:6] 1 2 3 4 5 6
 $ : int [1:12] 1 2 3 4 5 6 7 8 9 10 ...
 $ : int [1:18] 1 2 3 4 5 6 7 8 9 10 ...
 $ : int [1:24] 1 2 3 4 5 6 7 8 9 10 ...
=====================================
#emmm,看不懂这个function(x) seq_len(max(x))到底算了个啥?谁能赐教吗?谢谢!

这部分代码翻译自R帮助文档

猜你喜欢

转载自blog.csdn.net/weixin_42683052/article/details/116224457