R中主要的循环函数(loop functions)有 lapply( )、sapply( )、apply( )、tapply( ) 和 mapply( )。
lapply( )对列表中每个元素,包括各种类型的对象(向量、矩阵、数据框等),运用函数,返回一个新的列表。
lapplyfunction (X, FUN, ...) { FUN if (!is.vector(X) || is.object(X)) X as. .Internal(lapply(X, FUN))}0x7fde85867b90>namespace:
参数X是一个列表,X不是列表时会被as.list( )强制转化为列表,如果不能转化将报错
参数FUN,对列表里每个元素做运算的函数
其余的参数可用参数...传递给函数FUN
x 1:lapply(x, mean)$a[1] 2.5$b[1] 0.3474802$c[1] 0.937003$d[1] 4.957727#返回列表和原列表有相同的元素名a和b x<-1:4lapply(x, runif, min = 0, max = 10)[[1]][1] 1.621091[[2]][1] 4.75397920 0.01932835[[3]][1] 4.414591 2.609297 9.384137[[4]][1] 7.158333 1.630855 4.761880 6.902567#runif(x)函数生成x个服从均匀分布的随机变量组成的向量#对x调用lapply(),给runif()函数传递参数,指定生成介于0到10之间的随机数
lapply( ) 和相关循环函数可以传入匿名函数给参数FUN,不需要定义函数名称。
例:提取矩阵的第一列
x 1:x$a [,1] [,2][1,] 1 3[2,] 2 4$b [,1] [,2][1,] 1 4[2,] 2 5[3,] 3 6lapply(x, function(elt) elt[,1])$a[1] 1 2$b[1] 1 2 3
sapply( )可以简化lapply( )的结果。
如果结果列表中每个元素长度都为1,sapply( ) 返回一个包含所有元素的向量
如果结果列表中每个元素都是等长的向量, sapply( ) 返回矩阵
如果无法简化对象,sapply( ) 直接返回列表
x 1:lapply(x, mean)$a[1] 2.5$b[1] 0.2616772$c[1] 1.054757$d[1] 5.055208sapply(x, mean) a b c d 2.5000000 0.2616772 1.0547574 5.0552082 mean(x)[1] NAWarning message:In mean.default(x) : 参数不是数值也不是逻辑值:回覆NA#mean函数不适用于列表,对列表本身使用mean()函数将报错
apply( )对数组的各个维度(如行或列)进行运算。
str(apply)function (X, MARGIN, FUN, ...)
1. 参数x是一个数组;2. 参数MARGIN是整数向量,指明对数组的运用函数的维度 如MARGIN=1表示对二维数组的行运算,2表示对二维数组的列进行运算
x <- matrix(rnorm(200), 20, 10) #创建了一个20行10列的矩阵apply(x, 2, mean) #对矩阵中每列求平均值[1] 0.07982867 0.05471546 0.04272418 -0.07888251 -0.43758027 0.12137198 0.05869929[8] -0.24674699 0.21602219 -0.33674517#得到一个长度为10的向量,这个向量是矩阵中每个列的平均值apply(x, 1, sum) #对每行求和 [1] 1.3538445 -7.9108873 0.4657281 -2.2937298 -4.8767536 -5.6521484 2.1168591 -3.8917693 [9] -2.3622401 5.3025761 -4.2599949 2.3621288 -0.8809210 -2.6845400 4.9910454 -0.2658782[17] 5.4142552 -1.7345767 -1.2493809 5.5245197
可以直接使用经过优化的专用函数求和、求平均值:
rowSums = apply(x, 1, sum)
rowMeans = apply(x, 1, mean)
colSums = apply(x, 2, sum)
colMeans = apply(x, 2, mean)
例:对数组求平均值
a[,,1] [,1] [,2][1,] -1.138137 0.4264642[2,] 1.253815 -0.2950715apply(a, c(1, 2), mean) #保留数组的第1、2维求平均值 [,1] [,2][1,] -0.1066356 0.1550131[2,] -0.2499600 0.1434852rowMeans(a, dims = 2) [,1] [,2][1,] -0.1066356 0.1550131[2,] -0.2499600 0.1434852
mapply( ) 以一种并行的方式对多个列表的元素进行运算,是lapply( )的多变量版本。
str(mapply)function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
... 参数接收传递多个列表数据作为参数传递给FUN
MoreArgs::参数列表
SIMPLIFY:设置结果是否要被简化
USE.NAMES:如果X为字符串,TRUE设置字符串为数据名
list(rep(1, 4), rep(2, 3), rep(3, 2), rep(4, 1))[[1]][1] 1 1 1 1[[2]][1] 2 2 2[[3]][1] 3 3[[4]][1] 4#用rep()将1重复4次,将2重复3次,将3重复2次,将4重复1次输入#list()将所有结果以列表形式返回mapply(rep, 1:4, 4:1)
mapply( )函数依次将从1到4作为第一个参数,从4到1作为第二个参数传递给rep( )函数,返回相同的结果。
例:应用mapply( )生成一个均值为1的随机变量,两个均值为2的随机变量,三个均值为3的随机变量等等
#定义noise()函数生成一些正态随机噪音,有三个参数:观测数、均值以及标准差noise rnorm(n, mean, sd)} noise(5, 1, 2)[1] 0.6441040 0.1480373 2.9933176 2.4553214 -2.4532612#生成5个均值为1,标准差为2的正态随机变量noise(1:5, 1:5, 2)[1] 1.7067970 3.4536273 4.3365220 -0.8486346 4.5292851 #向noise()传递一个由参数组成的向量,会得到一个长度为5的向量,无法得到预期结果mapply(noise, 1:5, 1:5, 2)[[1]][1] 4.959267[[2]][1] 3.593589 -1.418552[[3]][1] -0.3273374 3.9822191 2.6518890 [[4]][1] 5.922581 4.587653 4.161999 4.367324[[5]][1] 5.332510 2.460802 9.698987 2.175989 4.966077
mapply( )函数依次将三个参数 1:5、1:5、2传递给noise( )函数运算得到预期结果。
tapply( ),table apply( ) 的缩写,将函数应用于向量的子集。
str(tapply)function (X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE)
X是一个数值或者其它类型的向量
INDEX是另一个长度与第一个向量相同的向量,用来表明第一个向量中的各元素分别属于哪一组
simplify设置结果是否要被简化
x 10), runif(#生成10个均值为0的正态随机变量、10个均匀随机变量以及10个均值为1的正态随机变量f3,f[1] 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3Levels: 1 2 3#gl()函数创建因子变量,因子变量有三个水平,每个水平会重复十次,表明观测值分别属于哪个组tapply(x, f, mean) #将x按分组子集求均值 1 2 3 0.3586938 0.6950377 0.7174120tapply(x, f, mean, simplify = FALSE)$`1`[1] 0.3586938$`2`[1] 0.6950377$`3`[1] 0.717412#不简化结果得到的是一个列表#可以计算一些更加复杂的统计量,计算观测值的范围tapply(x, f, range)$`1`[1] -1.042507 2.236323$`2`[1] 0.01919943 0.99887748$`3`[1] -1.371023 1.933389
split( )将对象分组,和lapply( )或sapply( )结合应用。
str(split)function (x, f, drop = FALSE, ...)
x为一个向量或列表、数据框
f为因子变量
drop指示空因子水平是否去掉
#加载airquality数据集library(datasets) head(airquality) Ozone Solar.R Wind Temp Month Day1 41 190 7.4 67 5 12 36 118 8.0 72 5 23 12 149 12.6 74 5 34 18 313 11.5 62 5 45 NA NA 14.3 56 5 56 28 NA 14.9 66 5 6#将数据框按因子变量Month分组s #联合lapply()按月计算平均值lapply(s, function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")]))$`5` Ozone Solar.R Wind NA NA 11.62258 $`6` Ozone Solar.R Wind NA 190.16667 10.26667 $`7` Ozone Solar.R Wind NA 216.483871 8.941935 $`8` Ozone Solar.R Wind NA NA 8.793548 $`9` Ozone Solar.R Wind NA 167.4333 10.1800 #Ozone和Solar.R变量有缺失值,导致无法计算平均值#调用sapply()简化返回的结果sapply(s, function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")])) 5 6 7 8 9Ozone NA NA NA NA NASolar.R NA 190.16667 216.483871 NA 167.4333Wind 11.62258 10.26667 8.941935 8.793548 10.1800#给colMeans()传递na.rm参数,在计算平均值之前移除每列的缺失值sapply(s, function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")], na.rm = TRUE)) 5 6 7 8 9Ozone 23.61538 29.44444 59.115385 59.961538 31.44828Solar.R 181.29630 190.16667 216.483871 171.857143 167.43333Wind 11.62258 10.26667 8.941935 8.793548 10.18000
观察不同因子组合产生的不同水平:
x 10) f12,f25,f1 [1] 1 1 1 1 1 2 2 2 2 2Levels: 1 2f2 [1] 1 1 2 2 3 3 4 4 5 5Levels: 1 2 3 4 5interaction(f1, f2) [1] 1.1 1.1 1.2 1.2 1.3 2.3 2.4 2.4 2.5 2.5Levels: 1.1 2.1 1.2 2.2 1.3 2.3 1.4 2.4 1.5 2.5#interaction()函数可以组合所有的因子水平,有10种不同水平的组合 #向split()函数直接传递一个包含两个因子变量的列表,会自动调用interaction()str(split(x, list(f1, f2)))List of 10 $ 1.1: num [1:2] 0.922 2.05 $ 2.1: num(0) $ 1.2: num [1:2] -0.491 -2.309 $ 2.2: num(0) $ 1.3: num 1.01 $ 2.3: num -0.709 $ 1.4: num(0) $ 2.4: num [1:2] -0.688 1.026 $ 1.5: num(0) $ 2.5: num [1:2] -0.285 -1.221#尽管有10种不同水平的组合,但不一定会在每个水平上都进行观测,某些水平会没有观测值#drop=TRUE去掉所有在分组过程中观测值为空的因子水平str(split(x, list(f1, f2), drop = TRUE))List of 6 $ 1.1: num [1:2] 0.922 2.05 $ 1.2: num [1:2] -0.491 -2.309 $ 1.3: num 1.01 $ 2.3: num -0.709 $ 2.4: num [1:2] -0.688 1.026 $ 2.5: num [1:2] -0.285 -1.221
编辑:李雪纯 冯文清 校审:张健 罗鹏