首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >R语言中的apply函数族

R语言中的apply函数族

作者头像
阿凡亮
发布2020-04-13 13:01:42
4.3K0
发布2020-04-13 13:01:42
举报

前言

apply函数族是R语言中数据处理的一组核心函数,通过使用apply函数,我们可以实现对数据的循环、分组、过滤、类型控制等操作。但是,由于在R语言中apply函数与其他语言循环体的处理思路是完全不一样的,所以apply函数族一直是初学者玩不转的一类核心函数。很多R语言新手,写了很多的for循环代码,也不愿意多花点时间把apply函数的使用方法了解清楚,最后把R代码写的跟C似得。

简介

由于R语言的apply家族函数是用C写的,所以使用apply进行遍历的执行效率远远高于自己编写的循环语句。为了面向不同的数据类型,不同的返回值,apply函数组成了一个函数族,包括了8个功能类似的函数,具体如下表所示。下面我们一个一个来介绍。

apply函数

apply函数是最常用的代替for循环的函数。apply函数可以对矩阵、数据框、数组(二维、多维),按行或列进行循环计算,对子元素进行迭代,并把子元素以参数传递的形式给自定义的FUN函数中,并返回计算结果。调用格式如下:

apply(X, MARGIN, FUN, ...)

X: 是一个数组(array),也就是说输入必须都是相同类型的数据,要么都是数值型,要么都是字符型。如果是一个混合数据类型的data.frame,那么就会尝试用as.matrix强制转换数据。 MARGIN:表示对行(1)或者是对列(2)应用函数。 FUN: 可是R自带函数,如mean,sum等。也可以是自己编写的函数。 ... :FUN中的额外参数。

现在假设我们需要对一个矩阵的每一行求和,那么用apply怎么实现呢?

x<-matrix(1:12, ncol=3)apply(x, 1, sum)[1] 15 18 21 24

一行代码搞定!当然你说可以使用 rowSums(x)也一样能得到结果,但是如果稍微复杂点,rowSums函数就不行了。比如说让数据框的x1列加1,并计算出x1,x2列的均值,这个时候就需要利用apply调用自定义函数了,可以说这才是apply强大的真正原因。

第一步,生成matrix

x <- cbind(x1 = 10, x2 = c(1:4, 2:5)); x     x1 x2[1,] 10  1[2,] 10  2[3,] 10  3[4,] 10  4[5,] 10  2[6,] 10  3[7,] 10  4[8,] 10  5

第二步,自定义函数myFUN,第一个参数x为数据, 第二、三个参数为自定义参数,可以通过apply的'...'进行传入。

myFUN <- function(x, c1, c2) {  c(sum(x[c1], 1), mean(x[c2])) }

第三步,通过apply调用上面自定义的函数

apply(x, 1, myFUN, c1='x1', c2=c('x1', 'x2'))     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8][1,] 11.0   11 11.0   11   11 11.0   11 11.0[2,]  5.5    6  6.5    7    6  6.5    7  7.5

是不是很简单,通过for循环的方式,也可以很容易的实现上面计算过程,但是需要一些额外的操作,比如构建循环体、定义结果数据集、合并每次循环的结果到结果数据集。

lapply函数

lapply函数是一个最基础循环操作函数之一,用来对list、data.frame数据集进行循环,并返回和X长度同样的list结构作为结果集,通过lapply的开头的第一个字母’l’就可以判断返回结果集的类型。

下面以计算list中的每个元素对应数据的分位数为例,展示该函数的特性。

# 构建一个list数据集x,分别包括a,b,c 三个KEY值。x <- list(a = 5:20, b = rnorm(6,10,5), c = c(FALSE,FALSE,TRUE,TRUE,TRUE,TRUE))# 分别计算每个KEY对应数据的分位数。lapply(x, fivenum)$`a`[1]  5.0  8.5 12.5 16.5 20.0
$b[1]  3.772836 11.750169 14.611470 17.395703 23.898115
$c[1] 0 0 1 1 1

可以看到,lapply很方便地把list数据集进行循环操作了,此外,它还可以对data.frame数据集按列进行循环,但如果传入的数据集是一个向量或矩阵对象,那么直接使用lapply就不能达到想要的效果了,lapply会分别循环矩阵中的每个值,而不是按行或按列进行分组计算。

x <- cbind(x=3, y=c(2:1, 4:5))lapply(data.frame(x), sum)$x[1] 12
$y[1] 12

sapply函数

sapply函数是一个简化版的lapply,sapply增加了2个参数simplify和USE.NAMES,主要就是让输出看起来更友好,返回值为向量,而不是list对象。

vapply函数

vapply类似于sapply,提供了FUN.VALUE参数,用来控制返回值的行名,这样可以让程序更健壮。

mapply函数

mapply是sapply的变形函数,类似多变量的sapply,但是参数定义有些变化。第一参数为自定义的FUN函数,第二个参数’…’可以接收多个数据,作为FUN函数的参数调用。比如,比较3个向量大小,按索引顺序取较大的值。

# 定义3个向量x <- 4:10y <- 10:4z <- round(runif(7, -5, 5))
# 按索引顺序取较大的值。mapply(max, x, y, z)[1] 10  9  8  7  8  9 10

又比如想生成4个符合正态分布的数据集,分别对应的均值和方差为c(1,10,100,1000)。

# m为均值,v为方差m <- v <- c(1, 10, 100, 1000)
# 生成4组数据,按列分组mapply(rnorm, rep(4,4), m, v)[,1]      [,2]      [,3]      [,4][1,] 1.1321892 11.119809 -12.65840  525.4851[2,] 3.3765492  8.032937 -44.84486  700.5648[3,] 0.1849429  6.717259 157.55199 1430.6167[4,] 1.8121539 15.392016  32.86186 1621.0613

tapply函数

tapply用于分组的循环计算,通过INDEX参数可以把数据集X进行分组,相当于group by的操作。例如,计算不同品种的鸢尾花的花瓣(iris)长度的均值。

# 通过iris$Species品种进行分组tapply(iris$Petal.Length, iris$Species, mean)    setosa versicolor  virginica      1.462      4.260      5.552

rapply函数

rapply是一个递归版本的lapply,它只处理list类型数据,对list的每个元素进行递归遍历,如果list包括子元素则继续遍历。例如,对一个list的数据进行过滤,把所有数字型的数据进行从小到大的排序。

x <- list(a=12, b=1:4, c=c('b', 'a'))y <- data.frame(a=rnorm(10), b=1:10)lst <- list(x=x, y=y)rapply(lst, sort, classes='numeric', how='replace')$`x`$`x`$`a`[1] 12
$`x`$b[1] 1 2 3 4
$`x`$c[1] "b" "a"

$ya  b1  -2.28818912  12  -1.11604471  23  -0.71061407  34  -0.47929464  45  -0.45064871  56  -0.32539516  67  -0.09147763  78   0.32032781  89   1.67678507  910  1.71896910 10

eapply函数

对一个环境空间中的所有变量进行遍历。eapply函数平时很难被用到,但对于R包开发来说,环境空间的使用是必须要掌握的。特别是当R要做为工业化的工具时,对变量的精确控制和管理是非常必要的。

总结

从上面这8个函数的参数定义,我们可以发现它们都接收一个函数作为它的参数,在编程的世界里,这种把函数作为参数传入的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。这种编程范式与面向对象的范式的差异如下图

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生物信息学 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档