数据科学04 | R语言程序设计-循环函数
R中主要的循环函数(loop functions)有 lapply( )、sapply( )、apply( )、tapply( ) 和 mapply( )。
lapply( )
lapply( )对列表中每个元素,包括各种类型的对象(向量、矩阵、数据框等),运用函数,返回一个新的列表。
lapplyfunction (X, FUN, ...){FUN <- match.fun(FUN)if (!is.vector(X) || is.object(X))X <- as.list(X).Internal(lapply(X, FUN))}<bytecode: 0x7fde85867b90><environment: namespace:base>
参数X是一个列表,X不是列表时会被as.list( )强制转化为列表,如果不能转化将报错
参数FUN,对列表里每个元素做运算的函数
其余的参数可用参数...传递给函数FUN
x <- list(a = 1:4, b = rnorm(10), c = rnorm(20, 1), d = rnorm(100, 5))lapply(x, mean)$a[] 2.5$b[] 0.3474802$c[] 0.937003$d[] 4.957727x<-1:4lapply(x, runif, min = 0, max = 10)[]][] 1.621091[]][] 4.75397920 0.01932835[]][] 4.414591 2.609297 9.384137[]][] 7.158333 1.630855 4.761880 6.902567
lapply( ) 和相关循环函数可以传入匿名函数给参数FUN,不需要定义函数名称。
例:提取矩阵的第一列
x <- list(a = matrix(1:4, 2, 2), b = matrix(1:6, 3, 2))x$a[] [,2][] 1 3[] 2 4$b[] [,2][] 1 4[] 2 5[] 3 6lapply(x, function(elt) elt[,1])$a[] 1 2$b[] 1 2 3
sapply( )
sapply( )可以简化lapply( )的结果。
- 如果结果列表中每个元素长度都为1,sapply( ) 返回一个包含所有元素的向量 
- 如果结果列表中每个元素都是等长的向量, sapply( ) 返回矩阵 
- 如果无法简化对象,sapply( ) 直接返回列表 
x <- list(a = 1:4, b = rnorm(10), c = rnorm(20, 1), d = rnorm(100, 5))lapply(x, mean)$a[] 2.5$b[] 0.2616772$c[] 1.054757$d[] 5.055208sapply(x, mean)a b c d2.5000000 0.2616772 1.0547574 5.0552082mean(x)[] NAWarning message:In mean.default(x) : 参数不是数值也不是逻辑值:回覆NA
apply( )
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][] [,2][] -1.138137 0.4264642[] 1.253815 -0.2950715apply(a, c(1, 2), mean)[] [,2][] -0.1066356 0.1550131[] -0.2499600 0.1434852rowMeans(a, dims = 2)[] [,2][] -0.1066356 0.1550131[] -0.2499600 0.1434852
mapply( )
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 <- function(n, mean, sd) {rnorm(n, mean, sd)}noise(5, 1, 2)[] 0.6441040 0.1480373 2.9933176 2.4553214 -2.4532612noise(1:5, 1:5, 2)[] 1.7067970 3.4536273 4.3365220 -0.8486346 4.5292851mapply(noise, 1:5, 1:5, 2)[]][] 4.959267[]][] 3.593589 -1.418552[]][] -0.3273374 3.9822191 2.6518890[]][] 5.922581 4.587653 4.161999 4.367324[]][] 5.332510 2.460802 9.698987 2.175989 4.966077
mapply( )函数依次将三个参数 1:5、1:5、2传递给noise( )函数运算得到预期结果。
tapply( )
tapply( ),table apply( ) 的缩写,将函数应用于向量的子集。
str(tapply)function (X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE)
X是一个数值或者其它类型的向量
INDEX是另一个长度与第一个向量相同的向量,用来表明第一个向量中的各元素分别属于哪一组
simplify设置结果是否要被简化
x <- c(rnorm(10), runif(10), rnorm(10, 1))f<-gl(3,10)f[] 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 3tapply(x, f, mean)1 2 30.3586938 0.6950377 0.7174120tapply(x, f, mean, simplify = FALSE)$`1`[] 0.3586938$`2`[] 0.6950377$`3`[] 0.717412tapply(x, f, range)$`1`[] -1.042507 2.236323$`2`[] 0.01919943 0.99887748$`3`[] -1.371023 1.933389
split( )
split( )将对象分组,和lapply( )或sapply( )结合应用。
str(split)function (x, f, drop = FALSE, ...)
x为一个向量或列表、数据框
f为因子变量
drop指示空因子水平是否去掉
#加载airquality数据集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 <- split(airquality, airquality$Month)#联合lapply()按月计算平均值function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")]))$`5`Ozone Solar.R WindNA NA 11.62258$`6`Ozone Solar.R WindNA 190.16667 10.26667$`7`Ozone Solar.R WindNA 216.483871 8.941935$`8`Ozone Solar.R WindNA NA 8.793548$`9`Ozone Solar.R WindNA 167.4333 10.1800#Ozone和Solar.R变量有缺失值,导致无法计算平均值#调用sapply()简化返回的结果function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")]))5 6 7 8 9Ozone NA NA NA NA NANA 190.16667 216.483871 NA 167.4333Wind 11.62258 10.26667 8.941935 8.793548 10.1800#给colMeans()传递na.rm参数,在计算平均值之前移除每列的缺失值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.44828181.29630 190.16667 216.483871 171.857143 167.43333Wind 11.62258 10.26667 8.941935 8.793548 10.18000
观察不同因子组合产生的不同水平:
x <- rnorm(10)f1<-gl(2,5) #2个因子水平,重复5次f2<-gl(5,2) #5个因子水平,重复2次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
