R语言里面的apply()家族简述

我能想到的所有套路,毒液里面都有。

这个教程目的在于介绍apply()家族在R语言的用法,apply()函数算是R语言里面很基础的一个函数,同时还有sapply()、lapply()、tapply()函数精简了apply()的用法。

apply()函数是一个很R语言的函数,可以起到很好的替代冗余的for循环的作用,在一篇博客里面介绍过,R语言的循环操作for和while,都是基于R语言本身来实现的,而向量操作是基于底层的C语言函数实现的,所以使用apply()家族进行向量计算是高性价比的。apply()可以面向数据框、列表、向量等,同时任何函数都可以传递给apply()函数。

apply()函数

apply()函数的用法如下:

apply(X, MARGIN, FUN)
Here:
-x: 一个数组或者矩阵
-MARGIN: 两种数值1或者2决定对哪一个维度进行函数计算
-MARGIN=1`: 操作基于行
-MARGIN=2`: 操作基于列
-MARGIN=c(1,2)`: 对行和列都进行操作
-FUN: 使用哪种操作,内置的函数有mean(平均值)、medium(中位数)、sum(求和)、min(最小值)、max(最大值),当然还包括广大的用户自定义函数

一个最简单的例子就是使用apply()对一个matrix求和,以下代码是对列求和:

> m1 <- matrix(C<-(1:10),nrow=5, ncol=6)
> m1
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    6    1    6    1    6
[2,]    2    7    2    7    2    7
[3,]    3    8    3    8    3    8
[4,]    4    9    4    9    4    9
[5,]    5   10    5   10    5   10
> a_m1 <- apply(m1, 2, sum)
> a_m1
[1] 15 40 15 40 15 40

lapply()函数

lapply()函数中多出来的l代表的是list,所以lapply()和apply()的区别在于输出的格式,lapply()的输出是一个列表(list),所以lapply()函数不需要MARGIN参数:

lapply(X, FUN)
Arguments:
-X: 一个向量或者是一个对象
-FUN: 对X里面每个元素进行操作的函数

一个很简单的示例操作就是把一个字符向量里面的字符转成小写:

> movies <- c("SPYDERMAN","BATMAN","VERTIGO","CHINATOWN")
> class(movies)
[1] "character"
> movies_lower <-lapply(movies, tolower)
> str(movies_lower)
List of 4
 $ : chr "spyderman"
 $ : chr "batman"
 $ : chr "vertigo"
 $ : chr "chinatown"

我们可以看到,输出的内容是以list形式给出的,为了方便,我们可以使用unlist()函数进行整合:

> movies_lower <-unlist(lapply(movies,tolower))
> str(movies_lower)
 chr [1:4] "spyderman" "batman" "vertigo" "chinatown"

sapply()函数

sapply()函数做的事情和lapply()一样,可以理解为是一个简化的lapply,返回的是一个向量(vector)使得对解读更加友好,其使用方法和lapply一样,不过多了两个参数: simplify&use.NAMEs,simplify = T可以将输出结果数组化,如果设置为false,sapply()函数就和lapply()函数没有差别了,use.NAMEs = T可以设置字符串为字符名。

> dt <- cars
> lmn_cars <- lapply(dt, min)
> smn_cars <- sapply(dt, min)
> smn_cars_sim <- sapply(dt, min, simplify = F)
> lmn_cars
$`speed`
[1] 4

$dist
[1] 2

> smn_cars
speed  dist 
    4     2 
> smn_cars_sim
$`speed`
[1] 4

$dist
[1] 2

> class(lmn_cars)
[1] "list"
> class(smn_cars)
[1] "numeric"
> class(smn_cars_sim)
[1] "list"

那我们就稍微总结一下这三个函数的区别:

Function Second Header Objective Input Output
apply apply(x, MARGIN, FUN) Apply a function to the rows or columns or both Data frame or matrix vector, list, array
lapply lapply(X, FUN) Apply a function to all the elements of the input List, vector or data frame list
sapply sappy(X FUN) Apply a function to all the elements of the input List, vector or data frame vector or matrix

tapply()函数

这里拓展一个函数:tapply(),它可以对一个向量里面进行分组统计操作。

是不是想起了dplyr包里面的group_by函数 + summarize()函数。

其参数为:

tapply(X, INDEX, FUN = NULL)
Arguments:
-X: 一个对象,一般都是向量
-INDEX: 一个包含分类因子的列表(list)
-FUN: 对X里面每个元素进行操作的函数

数据分析的一部分工作就是分组进行统计,举例来说,根据一个特性来对一个群体进行分组计算平均值。拿鸢尾花数据(iris)举例,其有三个品种:Setosa, Versicolor, Virginica,以下代码可以计算三个品种平均宽度:

> data(iris)
> head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
> tapply(iris$Sepal.Width, iris$Species, median)
    setosa versicolor  virginica 
       3.4        2.8        3.0 

使用我之前说的dplyr包可以实现同样的目的:

> iris %>% group_by(Species) %>%
+   summarise(mean(Sepal.Width))
# A tibble: 3 x 2
  Species    `mean(Sepal.Width)`
  <fct>                    <dbl>
1 setosa                    3.43
2 versicolor                2.77
3 virginica                 2.97

Conclusion

其实apply()家族还有多个衍生函数,包括vapply、mapply、rapply等,但是具体应用其实并不很常用,摒弃了for循环和while循环,我们还是有很多方法可以高效而简洁得实现我们的目的得。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • R语言中的以apply()函数为首的apply()家族,提供了强大而方便的循环功能,这些函数说起来简单,用起来可能...
    大数据技术派阅读 1,314评论 0 1
  • 循环对于代码运行来说是非常消耗时间和资源的,在R中,要尽量少使用for while循环,用apply函数族的话对于...
    willnight阅读 3,445评论 0 2
  • 生物考完归来,只剩生物统计学待我手刃了。转眼着手于熟悉的环境,想想学习R也有几个月的时光了。谈得上入手,谈不上熟练...
    王诗翔阅读 16,296评论 9 65
  • 这次一起去香港,让我明白了。 人不需要活得太认真了…… 有哪份闲情去计较什么, 还不如把精力多花点在自己的身上。。...
    桔梗花蕾阅读 71评论 0 0
  • 一个人,呆在宿舍,嗅不到中秋的味道。 只是,在跟妈妈的聊天中,感觉到了没有回家过节的失落和心酸。 昨晚,彻夜难眠。...
    减肥的女孩阅读 284评论 0 1