数据科学04 | R语言程序设计-循环函数
R中主要的循环函数(loop functions)有 lapply( )、sapply( )、apply( )、tapply( ) 和 mapply( )。
lapply( )
lapply( )对列表中每个元素,包括各种类型的对象(向量、矩阵、数据框等),运用函数,返回一个新的列表。
lapply
function (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.957727 ]
x<-1:4
lapply(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 6 ]
lapply(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.055208 ]
sapply(x, mean)
a b c d
2.5000000 0.2616772 1.0547574 5.0552082
mean(x)
[ ] NA
Warning 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.2950715 ]
apply(a, c(1, 2), mean)
[2] ] [,
[-0.1066356 0.1550131 ]
[-0.2499600 0.1434852 ]
rowMeans(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.4532612 ]
noise(1:5, 1:5, 2)
[1.7067970 3.4536273 4.3365220 -0.8486346 4.5292851 ]
mapply(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 3 ]
Levels: 1 2 3
tapply(x, f, mean)
1 2 3
0.3586938 0.6950377 0.7174120
tapply(x, f, mean, simplify = FALSE)
$`1`
[0.3586938 ]
$`2`
[0.6950377 ]
$`3`
[0.717412 ]
tapply(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 Day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
4 18 313 11.5 62 5 4
5 NA NA 14.3 56 5 5
6 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 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()简化返回的结果
function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")]))
5 6 7 8 9
Ozone NA NA NA NA NA
NA 190.16667 216.483871 NA 167.4333
Wind 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 9
Ozone 23.61538 29.44444 59.115385 59.961538 31.44828
181.29630 190.16667 216.483871 171.857143 167.43333
Wind 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 2
Levels: 1 2
f2
[1] 1 1 2 2 3 3 4 4 5 5
Levels: 1 2 3 4 5
interaction(f1, f2)
[1] 1.1 1.1 1.2 1.2 1.3 2.3 2.4 2.4 2.5 2.5
Levels: 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