我们模拟6个学生10次考试成绩。
scores <- list(
s1 = round(runif(10, 50, 100)),
s2 = round(runif(10, 50, 100)),
s3 = round(runif(10, 50, 100)),
s4 = round(runif(10, 50, 100)),
s5 = round(runif(10, 50, 100)),
s6 = round(runif(10, 50, 100))
)
scores
我们用列表记录这些学生的成绩。
请问:如何计算每个学生的平均分数?
方案一:base-R的写法
list(
s1 = mean(scores$s1),
s2 = mean(scores$s2),
s3 = mean(scores$s3),
s4 = mean(scores$s4),
s5 = mean(scores$s5),
s6 = mean(scores$s6)
)
输出结果
方案一,不足之处,对scores列表的每个元素重写了mean函数,若是有更多的学生计算平均分数,这种方法费时费力,不精简,还容易出错。
方案二:使用apply的家族函数 lapply函数
lapply(scores, mean)
输出结果同上。
这个写法很简洁,也适合列表含有多个元素的场景
方案三:使用函数式编程,也就是把一个函数作用于列表的每个元素,成功处理完后,重组为一个新的列表。这个逻辑,我们可以使用purrr包的map函数族。可以理解为它们是base-R的apply函数族的升级版本
library(magrittr)
library(purrr)
map(scores, mean)
# 或者
# 管道操作和表示
scores %>% map(mean)
输出结果同上
为了准确地使用purrr包map函数做函数式编程和应用,我们先深入了解下这个函数的用法。
学习任何函数,三步曲。
第一步:函数输入
第二步:函数体做什么事情
第三步:函数输出
map函数,也不例外
map函数的理解,如下图所示:
map函数解读
1)输入部分,第一个参数是列表或者向量,第二个参数是函数(R自带或者自定义的)
2)函数体部分,函数会作用于列表或者向量中的每个元素,进行对应的函数处理
3)输出部分,函数作用于每个元素都会有个输出,所有输出组合成一个新的list。
map函数家族
map函数家族,可以让map返回我们需要的数据格式。如下图所示:
例如:
1)6个学生的平均分记为一个向量
scores %>% map_dbl(mean)
输出结果
2)6个学生的平均分保存在数据框里
scores %>% map_df(mean)
输出结果
map函数的使用拓展
1 支持添加额外参数
说明,这个额外参数,来自于map函数的第二个参数—函数f的参数。
例如:我们需要对6个学生的分数做降序排列
scores %>% map(sort, decreasing = FALSE)
输出结果
2支持自定义函数
有时候,根据需求,我们需要自定义函数来对列表的每个元素做处理。
例如:对每个学生的成绩做标准化处理
# 第一步:自定义函数
my_fun <- function(x){
(x - mean(x))/sd(x)
}
# 第二步:自定义函数作用于列表的每个元素
std_scores % map(my_fun)
std_scores
# 第三步:检验是否标准化成功
std_scores %>% map(mean)
std_scores %>% map(var)
3 支持匿名函数
匿名函数就是没有函数名的函数
第一种写法
scores %>% map(function(x) {(x-mean(x))/sd(x)})
第二种写法
scores %>% map(~ {(.x-mean(.x))/sd(.x)})
第三种写法
scores %>% map(~ {(.-mean(.))/sd(.)})
三种写法,输出结果都一样,你可以根据自己的喜好选择一种写法,同时,知道其它写法效果等同就好了。
4 与dplyr包结合使用
dplyr包方便数据处理,purrr包的map函数家族方便做函数式编程,两者结合,可以做更多有趣的事情。
例如,我们想知道列表中每个元素的长度
library(tidyverse)
df <- tibble(
x = list(1, 2:3, 4:6)
) %>%
mutate(l = purrr::map_int(x, length))
df
输出结果
例如,用于建模操作
mtcars %>%
group_by(cyl) %>%
nest() %>%
mutate(model = purrr::map(data, ~ lm(mpg ~ wt, data = .))) %>%
mutate(result = purrr::map(model, ~ broom::tidy(.))) %>%
unnest(result)
输出结果
总结
purrr包map函数家族,可以实现函数式编程,apply函数家族的升级版本,通过简介代码,实现迭代操作,提升工作效率。
进一步阅读
可以阅读《R数据科学》书籍的第三部分:编程
需要R数据科学书籍的朋友,可以加我微信,备注:R数据科学书籍
需要加入R语言群的朋友,可以加我微信,备注:R群
我的微信luqin360。
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777