Lesser known purrr tricks
purrr is package that extends R’s functional programming capabilities. It brings a lot of new stuff to the table and in this post I show you some of the most useful (at least to me) functions included in purrr.
Getting rid of loops with map()
library(purrr)
numbers <- list(11, 12, 13, 14)
map_dbl(numbers, sqrt)
## [1] 3.316625 3.464102 3.605551 3.741657
You might wonder why this might be preferred to a for loop? It’s a lot less verbose, and you do not need to initialise any kind of structure to hold the result. If you google “create empty list in R” you will see that this is very common. However, with themap() family of functions, there is no need for an initial structure. map_dbl() returns an atomic list of real numbers, but if you use map() you will get a list back. Try them all out!
Map conditionally
map_if()
# Create a helper function that returns TRUE if a number is even
is_even <- function(x){
!as.logical(x %% 2)
}
map_if(numbers, is_even, sqrt)
## [[1]]
## [1] 11
##
## [[2]]
## [1] 3.464102
##
## [[3]]
## [1] 13
##
## [[4]]
## [1] 3.741657
map_at()
map_at(numbers, c(1,3), sqrt)
## [[1]]
## [1] 3.316625
##
## [[2]]
## [1] 12
##
## [[3]]
## [1] 3.605551
##
## [[4]]
## [1] 14
map_if() and map_at() have a further argument than map(); in the case of map_if(), a predicate function ( a function that returnsTRUE or FALSE) and a vector of positions for map_at(). This allows you to map your function only when certain conditions are met, which is also something that a lot of people google for.
Map a function with multiple arguments
numbers2 <- list(1, 2, 3, 4)
map2(numbers, numbers2, `+`)
## [[1]]
## [1] 12
##
## [[2]]
## [1] 14
##
## [[3]]
## [1] 16
##
## [[4]]
## [1] 18
You can map two lists to a function which takes two arguments using map_2(). You can even map an arbitrary number of lists to any function using pmap().
By the way, try this in: `+`(1,3) and see what happens.
Don’t stop execution of your function if something goes wrong
possible_sqrt <- possibly(sqrt, otherwise = NA_real_)
numbers_with_error <- list(1, 2, 3, "spam", 4)
map(numbers_with_error, possible_sqrt)
## [[1]]
## [1] 1
##
## [[2]]
## [1] 1.414214
##
## [[3]]
## [1] 1.732051
##
## [[4]]
## [1] NA
##
## [[5]]
## [1] 2
Another very common issue is to keep running your loop even when something goes wrong. In most cases the loop simply stops at the error, but you would like it to continue and see where it failed. Try to google “skip error in a loop” or some variation of it and you’ll see that a lot of people really just want that. This is possible by combining map() and possibly(). Most solutions involve the use of tryCatch() which I personally do not find very easy to use.
Don’t stop execution of your function if something goes wrong and capture the error
safe_sqrt <- safely(sqrt, otherwise = NA_real_)
map(numbers_with_error, safe_sqrt)
## [[1]]
## [[1]]$result
## [1] 1
##
## [[1]]$error
## NULL
##
##
## [[2]]
## [[2]]$result
## [1] 1.414214
##
## [[2]]$error
## NULL
##
##
## [[3]]
## [[3]]$result
## [1] 1.732051
##
## [[3]]$error
## NULL
##
##
## [[4]]
## [[4]]$result
## [1] NA
##
## [[4]]$error
## <simpleError in .f(...): non-numeric argument to mathematical function>
##
##
## [[5]]
## [[5]]$result
## [1] 2
##
## [[5]]$error
## NULL
safely() is very similar to possibly() but it returns a list of lists. An element is thus a list of the result and the accompagnying error message. If there is no error, the error component is NULL if there is an error, it returns the error message.
Transpose a list
safe_result_list <- map(numbers_with_error, safe_sqrt)
transpose(safe_result_list)
## $result
## $result[[1]]
## [1] 1
##
## $result[[2]]
## [1] 1.414214
##
## $result[[3]]
## [1] 1.732051
##
## $result[[4]]
## [1] NA
##
## $result[[5]]
## [1] 2
##
##
## $error
## $error[[1]]
## NULL
##
## $error[[2]]
## NULL
##
## $error[[3]]
## NULL
##
## $error[[4]]
## <simpleError in .f(...): non-numeric argument to mathematical function>
##
## $error[[5]]
## NULL
Here we transposed the above list. This means that we still have a list of lists, but where the first list holds all the results (which you can then access with safe_result_list$result) and the second list holds all the errors (which you can access withsafe_result_list$error). This can be quite useful!
Apply a function to a lower depth of a list
transposed_list <- transpose(safe_result_list)
transposed_list %>%
at_depth(2, is_null)
## $result
## $result[[1]]
## [1] FALSE
##
## $result[[2]]
## [1] FALSE
##
## $result[[3]]
## [1] FALSE
##
## $result[[4]]
## [1] FALSE
##
## $result[[5]]
## [1] FALSE
##
##
## $error
## $error[[1]]
## [1] TRUE
##
## $error[[2]]
## [1] TRUE
##
## $error[[3]]
## [1] TRUE
##
## $error[[4]]
## [1] FALSE
##
## $error[[5]]
## [1] TRUE
Sometimes working with lists of lists can be tricky, especially when we want to apply a function to the sub-lists. This is easily done with at_depth()!
Set names of list elements
name_element <- c("sqrt()", "ok?")
set_names(transposed_list, name_element)
## $`sqrt()`
## $`sqrt()`[[1]]
## [1] 1
##
## $`sqrt()`[[2]]
## [1] 1.414214
##
## $`sqrt()`[[3]]
## [1] 1.732051
##
## $`sqrt()`[[4]]
## [1] NA
##
## $`sqrt()`[[5]]
## [1] 2
##
##
## $`ok?`
## $`ok?`[[1]]
## NULL
##
## $`ok?`[[2]]
## NULL
##
## $`ok?`[[3]]
## NULL
##
## $`ok?`[[4]]
## <simpleError in .f(...): non-numeric argument to mathematical function>
##
## $`ok?`[[5]]
## NULL
Reduce a list to a single value
reduce(numbers, `*`)
## [1] 24024
reduce() applies the function * iteratively to the list of numbers. There’s also accumulate():
accumulate(numbers, `*`)
## [1] 11 132 1716 24024
which keeps the intermediary results.
This function is very general, and you can reduce anything:
Matrices:
mat1 <- matrix(rnorm(10), nrow = 2)
mat2 <- matrix(rnorm(10), nrow = 2)
mat3 <- matrix(rnorm(10), nrow = 2)
list_mat <- list(mat1, mat2, mat3)
reduce(list_mat, `+`)
## [,1] [,2] [,3] [,4] [,5]
## [1,] -0.5228188 0.4813357 0.3808749 -1.1678164 0.3080001
## [2,] -3.8330509 -0.1061853 -3.8315768 0.3052248 0.3486929
even data frames:
df1 <- as.data.frame(mat1)
df2 <- as.data.frame(mat2)
df3 <- as.data.frame(mat3)
list_df <- list(df1, df2, df3)
reduce(list_df, dplyr::full_join)
## Joining, by = c("V1", "V2", "V3", "V4", "V5")
## Joining, by = c("V1", "V2", "V3", "V4", "V5")
## V1 V2 V3 V4 V5
## 1 0.01587062 0.8570925 1.04330594 -0.5354500 0.7557203
## 2 -0.46872345 0.3742191 -1.88322431 1.4983888 -1.2691007
## 3 -0.60675851 -0.7402364 -0.49269182 -0.4884616 -1.0127531
## 4 -1.49619518 1.0714251 0.06748534 0.6650679 1.1709317
## 5 0.06806907 0.3644795 -0.16973919 -0.1439047 0.5650329
## 6 -1.86813223 -1.5518295 -2.01583786 -1.8582319 0.4468619
Hope you enjoyed this list of useful functions! If you enjoy the content of my blog, you can follow me on twitter.
转自:https://www.r-bloggers.com/lesser-known-purrr-tricks/?utm_source=feedburner&utm_medium=email&utm_campaign=Feed%3A+RBloggers+%28R+bloggers%29
Lesser known purrr tricks的更多相关文章
- Lesser known dplyr tricks
In this blog post I share some lesser-known (at least I believe they are) tricks that use mainly fun ...
- testng 教程之使用参数的一些tricks配合使用reportng
前两次的总结:testng annotation生命周期 http://www.cnblogs.com/tobecrazy/p/4579414.html testng.xml的使用和基本配置http: ...
- (转) How to Train a GAN? Tips and tricks to make GANs work
How to Train a GAN? Tips and tricks to make GANs work 转自:https://github.com/soumith/ganhacks While r ...
- Matlab tips and tricks
matlab tips and tricks and ... page overview: I created this page as a vectorization helper but it g ...
- LoadRunner AJAX TruClient协议Tips and Tricks
LoadRunner AJAX TruClient协议Tips and Trickshttp://automationqa.com/forum.php?mod=viewthread&tid=2 ...
- 【翻译】C# Tips & Tricks: Weak References - When and How to Use Them
原文:C# Tips & Tricks: Weak References - When and How to Use Them Sometimes you have an object whi ...
- 神经网络训练中的Tricks之高效BP(反向传播算法)
神经网络训练中的Tricks之高效BP(反向传播算法) 神经网络训练中的Tricks之高效BP(反向传播算法) zouxy09@qq.com http://blog.csdn.net/zouxy09 ...
- Hex-Rays Decompiler Tips and tricks Volatile memory
https://www.hex-rays.com/products/decompiler/manual/tricks.shtml First of all, read the troubleshoot ...
- hdu 5276 YJC tricks time 数学
YJC tricks time Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...
随机推荐
- 脚本语言:Xmas(一)
很偶然的一个想法,在从北京回成都的高铁上:我想要一个计算器.于是在火车上花了十来个小时,完成了一个模型:能够处理+-*/的优先级,以及"()",比如:1+(3+2)*4.这已是一年 ...
- 关于苹果真机 getFullYear()返回值为NAN的问题
问题描述: 在html页面中获得后台传过来的一个时间并显示在页面上,我用getFullYear() ,getMonth(),getDate()分别获得了年月日在电脑上和三星手机上页面都能正确的显示时间 ...
- SqlDataReader生成动态Lambda表达式
上一扁使用动态lambda表达式来将DataTable转换成实体,比直接用反射快了不少.主要是首行转换的时候动态生成了委托. 后面的转换都是直接调用委托,省去了多次用反射带来的性能损失. 今天在对Sq ...
- Java 判断回文字符串有多少和其中的最大字符串
一.简介代码功能 该代码的功能可以实现对任意的一段字符串进行判断是否有回文,回文有哪些,和其中的最大回文. 二.代码部分 1.全局变量 static String hws = "" ...
- Felx布局(三)
flex网格布局 平均分布 最简单的网格布局,就是平均分布.在容器里面平均分配空间,跟上面的骰子布局很像,但是需要设置项目的自动缩放
- 非负矩阵分解(4):NMF算法和聚类算法的联系与区别
作者:桂. 时间:2017-04-14 06:22:26 链接:http://www.cnblogs.com/xingshansi/p/6685811.html 声明:欢迎被转载,不过记得注明出处 ...
- 简单的总结一下iOS面试中会遇到的问题
1.线程是什么?进程是什么?二者有什么区别和联系? 一个程序至少有一个进程,一个进程至少有一个线程: 进程:一个程序的一次运行,在执行过程中拥有独立的内存单元,而多个线程共享一块内存 线程:线程是指 ...
- zlog学习随笔
zlog1使用手册 Contents Chapter 1 zlog是什么? 1.1 兼容性说明 1.2 zlog 1.2 发布说明 Chapter 2 zlog不是什么? Chapter 3 ...
- 基于 Haproxy 构建负载均衡集群
1.HAPROXY简介 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种负载均衡解决方案.HAProxy特别适用于那些负载特大的web ...
- vue.js随笔记---初识Vue.js
1.基础要求: 1.1 HTML CSS JAVASCRIPT 1.2 模块化基础 1.3 Es6初步了解 2.vue.js 轻量级的MVVM模式框架,他同时吸收了recat和angular的优点,他 ...